diff options
author | Mitya Selivanov <automainint@guattari.tech> | 2025-01-23 12:19:08 +0100 |
---|---|---|
committer | Mitya Selivanov <automainint@guattari.tech> | 2025-01-23 12:19:08 +0100 |
commit | 6ec822ee73734aafa598c642e91fb2194792397b (patch) | |
tree | 04d98433fe01049bc20ec3c5651d7f1dd182e389 /graphics.c | |
parent | 53feef5a47b6093ac4b518da96368870bb530bce (diff) | |
download | reduced_system_layer-6ec822ee73734aafa598c642e91fb2194792397b.zip |
Graphics requests - in progress
Diffstat (limited to 'graphics.c')
-rwxr-xr-x | graphics.c | 1334 |
1 files changed, 594 insertions, 740 deletions
@@ -78,18 +78,6 @@ typedef struct { vec4_f32 *pixels; } Pixel_Buffer; -typedef struct { - Pixel_Buffer buffer; - i64 sketch_size; - vec4_f32 *sketch; - vec2 position; - vec2 scale; - b8 quick : 1; // If set, anti-aliasing is skipped. - b8 alpha : 1; // If set, the resulting color is: dst * (1 - alpha) + src * alpha. - b8 xor_color : 1; // If set, the source color is XORed with the destination color. - vec4_f32 color; -} Brush; - vec3_f32 lab_from_rgb(vec3_f32 rgb); vec3_f32 rgb_from_lab(vec3_f32 lab); vec3_f32 lab_from_lch(vec3_f32 lch); @@ -118,29 +106,98 @@ vec3_f32 rgb_f32_from_u32(u32 color); u32 rgba_u32_from_f32(vec4_f32 color); vec4_f32 rgba_f32_from_u32(u32 color); -#define RGB(...) ((Brush) { .color = { __VA_ARGS__, 1.f } }) -#define RGBA(...) ((Brush) { .color = { __VA_ARGS__ } }) -#define LCH(...) ((Brush) { .color = vec4_from_vec3_f32(rgb_from_lch((vec3_f32) { __VA_ARGS__ }), 1.f) } }) -#define LCHA(...) ((Brush) { .color = vec4_from_vec3_f32(rgb_from_lch(vec3_from_vec4_f32((vec4_f32) { __VA_ARGS__ })), ((vec4_f32) { __VA_ARGS__ }).w) } }) - b8 rectangle_contains(f64 x0, f64 y0, f64 width, f64 height, f64 px, f64 py); b8 triangle_contains (f64 x0, f64 y0, f64 x1, f64 y1, f64 x2, f64 y2, f64 px, f64 py); b8 quad_contains (f64 x0, f64 y0, f64 x1, f64 y1, f64 x2, f64 y2, f64 x3, f64 y3, f64 px, f64 py); b8 ellipse_contains (f64 x0, f64 y0, f64 width, f64 height, f64 px, f64 py); b8 line_contains (f64 x0, f64 y0, f64 x1, f64 y1, f64 width, f64 px, f64 py); -Pixel_Buffer frame_pixels (void); -Pixel_Buffer subimage (Pixel_Buffer image, i64 x, i64 y, i64 width, i64 height); +// ================================================================ + +enum { + OP_NONE = 0, + OP_REQUESTS, + OP_PIXELS, + OP_RECTANGLE, + OP_TRIANGLE, + OP_QUAD, + OP_ELLIPSE, + OP_LINE, + OP_TEXT_AREA, + OP_TEXT_CURSOR, +}; -void put_pixel (Brush brush, i64 x, i64 y); -void draw_pixels (Brush brush, f64 x, f64 y, f64 width, f64 height, Pixel_Buffer src); -void fill_rectangle (Brush brush, f64 x, f64 y, f64 width, f64 height); -void fill_triangle (Brush brush, f64 x0, f64 y0, f64 x1, f64 y1, f64 x2, f64 y2); -void fill_quad (Brush brush, f64 x0, f64 y0, f64 x1, f64 y1, f64 x2, f64 y2, f64 x3, f64 y3); -void fill_ellipse (Brush brush, f64 x, f64 y, f64 width, f64 height); -void fill_line (Brush brush, f64 x0, f64 y0, f64 x1, f64 y1, f64 width); -void draw_text_area (Brush brush, f64 x, f64 y, f64 width, f64 height, f64 max_scale_x, f64 max_scale_y, i64 num_chars, c32 *text); -void draw_text_cursor(Brush brush, f64 x, f64 y, f64 width, f64 height, f64 max_scale_x, f64 max_scale_y, i64 cursor, i64 selection, i64 num_chars, c32 *text); +typedef struct { + f64 x; + f64 y; + f64 width; + f64 height; +} Box; + +typedef struct gx_request { + u16 op; + union { + struct { + i64 num; + struct gx_request *values; + } requests; + struct { + Box area; + Pixel_Buffer src; + } pixels; + struct { + vec4_f32 color; + Box area; + } rectangle; + struct { + vec4_f32 color; + vec2 vertices[3]; + } triangle; + struct { + vec4_f32 color; + vec2 vertices[4]; + } quad; + struct { + vec4_f32 color; + Box area; + } ellipse; + struct { + vec4_f32 color; + vec2 vertices[2]; + f64 width; + } line; + struct { + vec4_f32 color; + Box area; + vec2 max_size; + i64 num_chars; + c32 * text; + } text_area; + struct { + vec4_f32 color; + Box area; + vec2 max_size; + i64 cursor; + i64 selection; + i64 num_chars; + c32 * text; + } text_cursor; + }; +} Gx_Request; + +typedef struct { + i64 x; + i64 y; + Pixel_Buffer buffer; +} Gx_Baked; + +typedef struct { + i64 sketch_size; + vec4_f32 *sketch; + vec2 scale; +} Gx_Context; + +void gx_render(Gx_Context context, Pixel_Buffer dst, Gx_Request req); #endif // GRAPHICS_HEADER_GUARD_ @@ -214,139 +271,23 @@ static f64 gamma_re_(f64 x) { return x / 12.92; } -static void put_pixel_color_(Brush brush, i64 x, i64 y) { - brush.buffer.pixels[y * brush.buffer.stride + x] = brush.color; -} - -static void put_pixel_alpha_(Brush brush, i64 x, i64 y) { - i64 n = y * brush.buffer.stride + x; +static void put_pixel_alpha_(Pixel_Buffer dst, vec4_f32 color, i64 x, i64 y) { + i64 n = y * dst.stride + x; - vec4_f32 dst = brush.buffer.pixels[n]; - f64 a = brush.color.w; + vec4_f32 dst_color = dst.pixels[n]; + f64 a = color.w; - brush.buffer.pixels[n] = (vec4_f32) { - .x = (f32) (dst.x * (1. - a) + brush.color.x * a), - .y = (f32) (dst.y * (1. - a) + brush.color.y * a), - .z = (f32) (dst.z * (1. - a) + brush.color.z * a), + dst.pixels[n] = (vec4_f32) { + .x = (f32) (dst_color.x * (1. - a) + color.x * a), + .y = (f32) (dst_color.y * (1. - a) + color.y * a), + .z = (f32) (dst_color.z * (1. - a) + color.z * a), .w = 1., }; } -static void put_pixel_xor_(Brush brush, i64 x, i64 y) { - i64 n = y * brush.buffer.stride + x; - - vec3_f32 c = rgb_f32_from_u32( - rgb_u32_from_f32(vec3_from_vec4_f32(brush.buffer.pixels[n])) - ^ rgb_u32_from_f32(vec3_from_vec4_f32(brush.color)) - ); - - brush.color = vec4_from_vec3_f32(c, brush.color.w); - - if (brush.alpha) - put_pixel_alpha_(brush, x, y); - else - brush.buffer.pixels[n] = brush.color; -} - -static void put_pixel_(Brush brush, i64 x, i64 y) { - if (brush.xor_color) put_pixel_xor_ (brush, x, y); - else if (brush.alpha) put_pixel_alpha_(brush, x, y); - else put_pixel_color_(brush, x, y); -} - -f64 transform_x_(Brush brush, f64 x) { - return (brush.position.x + x) * brush.scale.x; -} - -f64 transform_y_(Brush brush, f64 y) { - return (brush.position.y + y) * brush.scale.y; -} - -void transform_box_(Brush brush, f64 x, f64 y, f64 width, f64 height, f64 *x0, f64 *y0, f64 *x1, f64 *y1) { - if (brush.scale.x < 0) { - *x1 = transform_x_(brush, x); - *x0 = *x1 + width * brush.scale.x; - } else { - *x0 = transform_x_(brush, x); - *x1 = *x0 + width * brush.scale.x; - } - - if (brush.scale.y < 0) { - *y1 = transform_y_(brush, y); - *y0 = *y1 + height * brush.scale.y; - } else { - *y0 = transform_y_(brush, y); - *y1 = *y0 + height * brush.scale.y; - } -} - -Pixel_Buffer sketch_pixels_(Brush brush, i64 width, i64 height) { - vec4_f32 *buffer_end = brush.buffer.pixels + brush.buffer.stride * (brush.buffer.height - 1) + brush.buffer.width; - vec4_f32 *sketch_end = brush.sketch + brush.sketch_size; - - b8 is_inside_sketch_area = buffer_end > brush.sketch && brush.buffer.pixels < sketch_end; - - b8 offset = is_inside_sketch_area - ? buffer_end - brush.sketch - : 0; - - if (brush.sketch_size - offset < width * height) - return (Pixel_Buffer) { - .width = 0, - .height = 0, - .stride = 0, - .pixels = brush.sketch, - }; - - return (Pixel_Buffer) { - .width = width, - .height = height, - .stride = width, - .pixels = brush.sketch + offset, - }; -} - -Brush antialiasing_brush_(Brush brush) { - return (Brush) { - .buffer = sketch_pixels_( - brush, - brush.buffer.width * ANTIALIASING_SCALE, - brush.buffer.height * ANTIALIASING_SCALE - ), - .sketch_size = brush.sketch_size, - .sketch = brush.sketch, - .position = brush.position, - .scale = { - .x = brush.scale.x * ANTIALIASING_SCALE, - .y = brush.scale.y * ANTIALIASING_SCALE, - }, - .quick = 1, - .alpha = 0, - .xor_color = 0, - .color = brush.alpha - ? brush.color - : vec4_from_vec3_f32(vec3_from_vec4_f32(brush.color), 1.f), - }; -} - -Brush copy_brush_(Brush brush) { - return (Brush) { - .buffer = brush.buffer, - .position = brush.position, - .scale = brush.scale, - .alpha = 1, - .xor_color = brush.xor_color, - }; -} - -void draw_pixels_(Brush brush, f64 x, f64 y, f64 width, f64 height, Pixel_Buffer src) { - // FIXME PERF - - f64 x0, y0, x1, y1; - transform_box_(brush, x, y, width, height, &x0, &y0, &x1, &y1); - - f64 w = x1 - x0; - f64 h = y1 - y0; +void draw_pixels_raw(Pixel_Buffer dst, f64 x0, f64 y0, f64 w, f64 h, Pixel_Buffer src) { + f64 x1 = x0 + w; + f64 y1 = y0 + h; if (w < EPSILON || h < EPSILON) return; @@ -356,318 +297,214 @@ void draw_pixels_(Brush brush, f64 x, f64 y, f64 width, f64 height, Pixel_Buffer i64 j0 = (i64) floor(y0); i64 j1 = (i64) floor(y1); - if (i0 < 0) i0 = 0; - if (i1 >= brush.buffer.width) i1 = brush.buffer.width - 1; - if (j0 < 0) j0 = 0; - if (j1 >= brush.buffer.height) j1 = brush.buffer.height - 1; + if (i0 < 0) i0 = 0; + if (i1 >= dst.width) i1 = dst.width - 1; + if (j0 < 0) j0 = 0; + if (j1 >= dst.height) j1 = dst.height - 1; f64 w_inv = 1. / w; f64 h_inv = 1. / h; - if (!brush.quick) - for (i64 j = j0; j <= j1; ++j) { - i64 src_j0 = (i64) floor(((j - y0) * src.height) * h_inv + .5); - i64 src_j1 = (i64) floor(((j + 1 - y0) * src.height) * h_inv + .5); - if (src_j0 == src_j1) src_j1 = src_j0 + 1; - if (src_j1 <= 0 || src_j0 >= src.height) continue; - if (src_j0 < 0) src_j0 = 0; - if (src_j1 > src.height) src_j1 = src.height; - for (i64 i = i0; i <= i1; ++i) { - i64 src_i0 = (i64) floor(((i - x0) * src.width) * w_inv + .5); - i64 src_i1 = (i64) floor(((i + 1 - x0) * src.width) * w_inv + .5); - if (src_i0 == src_i1) src_i1 = src_i0 + 1; - if (src_i1 <= 0 || src_i0 >= src.width) continue; - if (src_i0 < 0) src_i0 = 0; - if (src_i1 > src.width) src_i1 = src.width; - brush.color = (vec4_f32) {0}; - i64 n = 0; - for (i64 jj = src_j0; jj < src_j1; ++jj) - for (i64 ii = src_i0; ii < src_i1; ++ii) { - brush.color.x += gamma_re_(src.pixels[jj * src.stride + ii].x); - brush.color.y += gamma_re_(src.pixels[jj * src.stride + ii].y); - brush.color.z += gamma_re_(src.pixels[jj * src.stride + ii].z); - brush.color.w += gamma_re_(src.pixels[jj * src.stride + ii].w); - ++n; - } - if (n == 0) - continue; - f32 n_inv = 1.f / n; - brush.color.x = gamma_(brush.color.x * n_inv); - brush.color.y = gamma_(brush.color.y * n_inv); - brush.color.z = gamma_(brush.color.z * n_inv); - brush.color.w = gamma_(brush.color.w * n_inv); - put_pixel_(brush, i, j); - } - } - else if (!brush.alpha && !brush.xor_color) { - i32 iw = (i32) floor(w + .5); - i32 ih = (i32) floor(h + .5); - i32 ix0 = (i32) floor(x0 + .5); - i32 iy0 = (i32) floor(y0 + .5); - for (i32 j = j0; j <= j1; ++j) { - i32 src_j = ((j - iy0) * src.height) / ih; - i32 dst_j = j * brush.buffer.stride; - if (src_j < 0 || src_j >= src.height) continue; - src_j *= src.stride; - for (i32 i = i0; i <= i1; ++i) { - i32 src_i = ((i - ix0) * src.width) / iw; - if (src_i < 0 || src_i >= src.width) continue; - brush.buffer.pixels[dst_j + i] = src.pixels[src_j + src_i]; - } - } - } else - for (i64 j = j0; j <= j1; ++j) { - i64 src_j = (i64) floor(((j - y0) * src.height) * h_inv + .5); - if (src_j < 0 || src_j >= src.height) continue; - src_j *= src.stride; - for (i64 i = i0; i <= i1; ++i) { - i64 src_i = (i64) floor(((i - x0) * src.width) * w_inv + .5); - if (src_i < 0 || src_i >= src.width) continue; - brush.color = src.pixels[src_j + src_i]; - put_pixel_(brush, i, j); - } + for (i64 j = j0; j <= j1; ++j) { + i64 src_j0 = (i64) floor(((j - y0) * src.height) * h_inv + .5); + i64 src_j1 = (i64) floor(((j + 1 - y0) * src.height) * h_inv + .5); + if (src_j0 == src_j1) src_j1 = src_j0 + 1; + if (src_j1 <= 0 || src_j0 >= src.height) continue; + if (src_j0 < 0) src_j0 = 0; + if (src_j1 > src.height) src_j1 = src.height; + for (i64 i = i0; i <= i1; ++i) { + i64 src_i0 = (i64) floor(((i - x0) * src.width) * w_inv + .5); + i64 src_i1 = (i64) floor(((i + 1 - x0) * src.width) * w_inv + .5); + if (src_i0 == src_i1) src_i1 = src_i0 + 1; + if (src_i1 <= 0 || src_i0 >= src.width) continue; + if (src_i0 < 0) src_i0 = 0; + if (src_i1 > src.width) src_i1 = src.width; + vec4_f32 color = {0}; + i64 n = 0; + for (i64 jj = src_j0; jj < src_j1; ++jj) + for (i64 ii = src_i0; ii < src_i1; ++ii) { + color.x += gamma_re_(src.pixels[jj * src.stride + ii].x); + color.y += gamma_re_(src.pixels[jj * src.stride + ii].y); + color.z += gamma_re_(src.pixels[jj * src.stride + ii].z); + color.w += gamma_re_(src.pixels[jj * src.stride + ii].w); + ++n; + } + if (n == 0) + continue; + f32 n_inv = 1.f / n; + color.x = gamma_(color.x * n_inv); + color.y = gamma_(color.y * n_inv); + color.z = gamma_(color.z * n_inv); + color.w = gamma_(color.w * n_inv); + put_pixel_alpha_(dst, color, i, j); } + } } -void draw_pixels_from_(Brush brush, f64 x, f64 y, f64 width, f64 height, Pixel_Buffer src, i64 src_x, i64 src_y, i64 src_width, i64 src_height) { - // NOTE: In the future we may need to implement - // pixel buffers with bounding boxes. +void fill_rectangle_raw(Pixel_Buffer dst, vec4_f32 color, f64 x0, f64 y0, f64 w, f64 h) { + f64 x1 = x0 + w; + f64 y1 = y0 + h; - f64 bx = 0; - f64 by = 0; - f64 bw = 0; - f64 bh = 0; + i64 i0 = (i64) ceil (x0); + i64 i1 = (i64) floor(x1); + i64 j0 = (i64) ceil (y0); + i64 j1 = (i64) floor(y1); - if (src_width > src.width - src_x) { - bw += src_width - src.width + src_x; - src_width = src.width - src_x; - } + i64 i00 = i0; + i64 j00 = j0; + i64 i10 = i1; + i64 j10 = j1; - if (src_height > src.height - src_y) { - bh += src_height - src.height + src_y; - src_height = src.height - src_y; - } + if (i0 < 0) i0 = 0; + if (i1 > dst.width) i1 = dst.width; + if (j0 < 0) j0 = 0; + if (j1 > dst.height) j1 = dst.height; - if (src_x < 0) { - bx -= src_x; - bw -= src_x; - src_x = 0; - } + f64 kx0 = i00 - x0; + f64 kx1 = x1 - i10; + f64 ky0 = j00 - y0; + f64 ky1 = y1 - j10; + + for (i64 j = j0; j < j1; ++j) + for (i64 i = i0; i < i1; ++i) + put_pixel_alpha_(dst, color, i, j); - if (src_y < 0) { - by -= src_y; - bh -= src_y; - src_y = 0; + if (i00 > i10) { + kx0 *= kx1; + kx1 = 0.; } - if (src_x + src_width > src.width || src_y + src_height > src.height || src_width <= 0 || src_height <= 0) - return; + if (j00 > j10) { + ky0 *= ky1; + ky1 = 0.; + } - f64 w_inv = 1. / src_width; - f64 h_inv = 1. / src_height; + f64 alpha = color.w; - bx *= width * w_inv; - by *= height * h_inv; - bw *= width * w_inv; - bh *= height * h_inv; + if (i00 - 1 >= 0 && i00 - 1 < dst.width) { + color.w = gamma_(gamma_re_(alpha) * kx0); + for (i64 j = j0; j < j1; ++j) + put_pixel_alpha_(dst, color, i00 - 1, j); + } - draw_pixels_(brush, x + bx, y + by, width - bw, height - bh, subimage(src, src_x, src_y, src_width, src_height)); -} + if (i10 >= 0 && i10 < dst.width) { + color.w = gamma_(gamma_re_(alpha) * kx1); + for (i64 j = j0; j < j1; ++j) + put_pixel_alpha_(dst, color, i10, j); + } -void fill_rectangle_(Brush brush, f64 x, f64 y, f64 width, f64 height) { - if (width < EPSILON || height < EPSILON) - return; + if (j00 - 1 >= 0 && j00 - 1 < dst.height) { + color.w = gamma_(gamma_re_(alpha) * ky0); + for (i64 i = i0; i < i1; ++i) + put_pixel_alpha_(dst, color, i, j00 - 1); + } - f64 x0, y0, x1, y1; - transform_box_(brush, x, y, width, height, &x0, &y0, &x1, &y1); - - if (!brush.quick) { - i64 i0 = (i64) ceil (x0); - i64 i1 = (i64) floor(x1); - i64 j0 = (i64) ceil (y0); - i64 j1 = (i64) floor(y1); - - i64 i00 = i0; - i64 j00 = j0; - i64 i10 = i1; - i64 j10 = j1; - - if (i0 < 0) i0 = 0; - if (i1 > brush.buffer.width) i1 = brush.buffer.width; - if (j0 < 0) j0 = 0; - if (j1 > brush.buffer.height) j1 = brush.buffer.height; - - f64 kx0 = i00 - x0; - f64 kx1 = x1 - i10; - f64 ky0 = j00 - y0; - f64 ky1 = y1 - j10; - - if (brush.xor_color) - for (i64 j = j0; j < j1; ++j) - for (i64 i = i0; i < i1; ++i) - put_pixel_xor_(brush, i, j); - else if (brush.alpha) - for (i64 j = j0; j < j1; ++j) - for (i64 i = i0; i < i1; ++i) - put_pixel_alpha_(brush, i, j); - else - for (i64 j = j0; j < j1; ++j) - for (i64 i = i0; i < i1; ++i) - put_pixel_color_(brush, i, j); - - if (i00 > i10) { - kx0 *= kx1; - kx1 = 0.; - } + if (j10 >= 0 && j10 < dst.height) { + color.w = gamma_(gamma_re_(alpha) * ky1); + for (i64 i = i0; i < i1; ++i) + put_pixel_alpha_(dst, color, i, j10); + } - if (j00 > j10) { - ky0 *= ky1; - ky1 = 0.; - } + if ( i00 - 1 >= 0 && i00 - 1 < dst.width + && j00 - 1 >= 0 && j00 - 1 < dst.height) { + color.w = gamma_(gamma_re_(alpha) * kx0 * ky0); + put_pixel_alpha_(dst, color, i00 - 1, j00 - 1); + } - f64 alpha = brush.alpha ? brush.color.w : 1.; - brush.alpha = 1; + if ( i10 >= 0 && i10 < dst.width + && j00 - 1 >= 0 && j00 - 1 < dst.height) { + color.w = gamma_(gamma_re_(alpha) * kx1 * ky0); + put_pixel_alpha_(dst, color, i10, j00 - 1); + } - if (i00 - 1 >= 0 && i00 - 1 < brush.buffer.width) { - brush.color.w = gamma_(gamma_re_(alpha) * kx0); - for (i64 j = j0; j < j1; ++j) - put_pixel_(brush, i00 - 1, j); - } + if ( i00 - 1 >= 0 && i00 - 1 < dst.width + && j10 >= 0 && j10 < dst.height) { + color.w = gamma_(gamma_re_(alpha) * kx0 * ky1); + put_pixel_alpha_(dst, color, i00 - 1, j10); + } - if (i10 >= 0 && i10 < brush.buffer.width) { - brush.color.w = gamma_(gamma_re_(alpha) * kx1); - for (i64 j = j0; j < j1; ++j) - put_pixel_(brush, i10, j); - } + if ( i10 >= 0 && i10 < dst.width + && j10 >= 0 && j10 < dst.height) { + color.w = gamma_(gamma_re_(alpha) * kx1 * ky1); + put_pixel_alpha_(dst, color, i10, j10); + } +} - if (j00 - 1 >= 0 && j00 - 1 < brush.buffer.height) { - brush.color.w = gamma_(gamma_re_(alpha) * ky0); - for (i64 i = i0; i < i1; ++i) - put_pixel_(brush, i, j00 - 1); - } +void fill_triangle_raw(Pixel_Buffer dst, vec4_f32 color, f64 x0, f64 y0, f64 x1, f64 y1, f64 x2, f64 y2) { + i64 i0 = (i64) floor(min3_(x0, x1, x2)); + i64 j0 = (i64) floor(min3_(y0, y1, y2)); + i64 i1 = (i64) ceil (max3_(x0, x1, x2)); + i64 j1 = (i64) ceil (max3_(y0, y1, y2)); - if (j10 >= 0 && j10 < brush.buffer.height) { - brush.color.w = gamma_(gamma_re_(alpha) * ky1); - for (i64 i = i0; i < i1; ++i) - put_pixel_(brush, i, j10); - } + if (i0 < 0) i0 = 0; + if (i1 >= dst.width) i1 = dst.width - 1; + if (j0 < 0) j0 = 0; + if (j1 >= dst.height) j1 = dst.height - 1; - if ( i00 - 1 >= 0 && i00 - 1 < brush.buffer.width - && j00 - 1 >= 0 && j00 - 1 < brush.buffer.height) { - brush.color.w = gamma_(gamma_re_(alpha) * kx0 * ky0); - put_pixel_(brush, i00 - 1, j00 - 1); - } + for (i64 j = j0; j <= j1; ++j) { + i64 left = i1; + i64 right = i0; - if ( i10 >= 0 && i10 < brush.buffer.width - && j00 - 1 >= 0 && j00 - 1 < brush.buffer.height) { - brush.color.w = gamma_(gamma_re_(alpha) * kx1 * ky0); - put_pixel_(brush, i10, j00 - 1); - } + for (i64 i = i0; i <= i1; ++i) + if (triangle_contains(x0, y0, x1, y1, x2, y2, (f64) i, (f64) j)) { + left = i; + break; + } - if ( i00 - 1 >= 0 && i00 - 1 < brush.buffer.width - && j10 >= 0 && j10 < brush.buffer.height) { - brush.color.w = gamma_(gamma_re_(alpha) * kx0 * ky1); - put_pixel_(brush, i00 - 1, j10); - } + for (i64 i = i1; i >= i0; --i) + if (triangle_contains(x0, y0, x1, y1, x2, y2, (f64) i, (f64) j)) { + right = i; + break; + } - if ( i10 >= 0 && i10 < brush.buffer.width - && j10 >= 0 && j10 < brush.buffer.height) { - brush.color.w = gamma_(gamma_re_(alpha) * kx1 * ky1); - put_pixel_(brush, i10, j10); - } - } else { - i64 i0 = (i64) floor(x0); - i64 i1 = (i64) ceil (x1); - i64 j0 = (i64) floor(y0); - i64 j1 = (i64) ceil (y1); - - if (i0 < 0) i0 = 0; - if (i1 > brush.buffer.width) i1 = brush.buffer.width; - if (j0 < 0) j0 = 0; - if (j1 > brush.buffer.height) j1 = brush.buffer.height; - - if (brush.xor_color) - for (i64 j = j0; j < j1; ++j) - for (i64 i = i0; i < i1; ++i) - put_pixel_xor_(brush, i, j); - else if (brush.alpha) - for (i64 j = j0; j < j1; ++j) - for (i64 i = i0; i < i1; ++i) - put_pixel_alpha_(brush, i, j); - else - for (i64 j = j0; j < j1; ++j) - for (i64 i = i0; i < i1; ++i) - put_pixel_color_(brush, i, j); + for (i64 i = left; i <= right; ++i) + put_pixel_alpha_(dst, color, i, j); } } -void fill_triangle_(Brush brush, f64 x0, f64 y0, f64 x1, f64 y1, f64 x2, f64 y2) { - // FIXME PERF: - // Implement better algorithm. - - x0 = transform_x_(brush, x0); - y0 = transform_y_(brush, y0); - - x1 = transform_x_(brush, x1); - y1 = transform_y_(brush, y1); - - x2 = transform_x_(brush, x2); - y2 = transform_y_(brush, y2); - +void fill_quad_raw(Pixel_Buffer dst, vec4_f32 color, f64 x0, f64 y0, f64 x1, f64 y1, f64 x2, f64 y2, f64 x3, f64 y3) { i64 i0 = (i64) floor(min3_(x0, x1, x2)); i64 j0 = (i64) floor(min3_(y0, y1, y2)); i64 i1 = (i64) ceil (max3_(x0, x1, x2)); i64 j1 = (i64) ceil (max3_(y0, y1, y2)); - if (i0 < 0) i0 = 0; - if (i1 >= brush.buffer.width) i1 = brush.buffer.width - 1; - if (j0 < 0) j0 = 0; - if (j1 >= brush.buffer.height) j1 = brush.buffer.height - 1; + if (i0 < 0) i0 = 0; + if (i1 >= dst.width) i1 = dst.width - 1; + if (j0 < 0) j0 = 0; + if (j1 >= dst.height) j1 = dst.height - 1; for (i64 j = j0; j <= j1; ++j) { i64 left = i1; i64 right = i0; for (i64 i = i0; i <= i1; ++i) - if (triangle_contains(x0, y0, x1, y1, x2, y2, (f64) i, (f64) j)) { + if (quad_contains(x0, y0, x1, y1, x2, y2, x3, y3, (f64) i, (f64) j)) { left = i; break; } for (i64 i = i1; i >= i0; --i) - if (triangle_contains(x0, y0, x1, y1, x2, y2, (f64) i, (f64) j)) { + if (quad_contains(x0, y0, x1, y1, x2, y2, x3, y3, (f64) i, (f64) j)) { right = i; break; } - if (brush.xor_color) - for (i64 i = left; i <= right; ++i) - put_pixel_xor_(brush, i, j); - else if (brush.alpha) - for (i64 i = left; i <= right; ++i) - put_pixel_alpha_(brush, i, j); - else - for (i64 i = left; i <= right; ++i) - put_pixel_color_(brush, i, j); + for (i64 i = left; i <= right; ++i) + put_pixel_alpha_(dst, color, i, j); } } -void fill_quad_(Brush brush, f64 x0, f64 y0, f64 x1, f64 y1, f64 x2, f64 y2, f64 x3, f64 y3) { - fill_triangle_(brush, x0, y0, x1, y1, x2, y2); - fill_triangle_(brush, x0, y0, x2, y2, x3, y3); -} - -void fill_ellipse_(Brush brush, f64 x, f64 y, f64 width, f64 height) { - f64 x0, y0, x1, y1; - transform_box_(brush, x, y, width, height, &x0, &y0, &x1, &y1); +void fill_ellipse_raw(Pixel_Buffer dst, vec4_f32 color, f64 x0, f64 y0, f64 w, f64 h) { + f64 x1 = x0 + w; + f64 y1 = y0 + h; i64 i0 = (i64) floor(x0); i64 i1 = (i64) ceil (x1); i64 j0 = (i64) floor(y0); i64 j1 = (i64) ceil (y1); - if (j0 < 0) j0 = 0; - if (j1 >= brush.buffer.height) j1 = brush.buffer.height - 1; + if (j0 < 0) j0 = 0; + if (j1 >= dst.height) j1 = dst.height - 1; for (i64 j = j0; j <= j1; ++j) { i64 left = i1; @@ -686,21 +523,37 @@ void fill_ellipse_(Brush brush, f64 x, f64 y, f64 width, f64 height) { break; } - if (left < 0) left = 0; - if (right >= brush.buffer.width) right = brush.buffer.width - 1; - - if (brush.xor_color) - for (i64 i = left; i <= right; ++i) - put_pixel_xor_(brush, i, j); - else if (brush.alpha) - for (i64 i = left; i <= right; ++i) - put_pixel_alpha_(brush, i, j); - else - for (i64 i = left; i <= right; ++i) - put_pixel_color_(brush, i, j); + if (left < 0) left = 0; + if (right >= dst.width) right = dst.width - 1; + + for (i64 i = left; i <= right; ++i) + put_pixel_alpha_(dst, color, i, j); } } +void fill_line_raw(Pixel_Buffer dst, vec4_f32 color, f64 x0, f64 y0, f64 x1, f64 y1, f64 width) { + if (width < EPSILON) + return; + + f64 dx = x1 - x0; + f64 dy = y1 - y0; + + // Tangent + // + f64 tx = -dy; + f64 ty = dx; + f64 tl = sqrt(tx * tx + ty * ty); + + if (tl < EPSILON) + return; + + f64 k = .5 / tl; + tx *= width * k; + ty *= width * k; + + fill_quad_raw(dst, color, x0 - tx, y0 - ty, x0 + tx, y0 + ty, x1 + tx, y1 + ty, x1 - tx, y1 - ty); +} + static i64 char_column_offset_(c32 c, i64 column_index) { if (column_index < 0 || column_index >= CHAR_NUM_BITS_X_) return -1; @@ -851,15 +704,7 @@ static i64 enum_text_rows_(i64 num_chars, c32 *text) { return rows; } -static void draw_text_(Brush brush, f64 x0, f64 y0, f64 scale_x, f64 scale_y, i64 num_chars, c32 *text) { - x0 = transform_x_(brush, x0); - y0 = transform_y_(brush, y0); - - if (brush.scale.x < 0) scale_x *= -brush.scale.x; - else scale_x *= brush.scale.x; - if (brush.scale.y < 0) scale_y *= -brush.scale.y; - else scale_y *= brush.scale.y; - +static void draw_text_(Pixel_Buffer dst, vec4_f32 color, f64 x0, f64 y0, f64 scale_x, f64 scale_y, i64 num_chars, c32 *text) { f64 kx = scale_x; f64 h = scale_y * CHAR_NUM_BITS_Y_; @@ -893,10 +738,10 @@ static void draw_text_(Brush brush, f64 x0, f64 y0, f64 scale_x, f64 scale_y, i6 i64 j0 = (i64) floor(y); i64 j1 = (i64) ceil (y + h); - if (i0 < 0) i0 = 0; - if (i1 >= brush.buffer.width) i1 = brush.buffer.width - 1; - if (j0 < 0) j0 = 0; - if (j1 >= brush.buffer.height) j1 = brush.buffer.height - 1; + if (i0 < 0) i0 = 0; + if (i1 >= dst.width) i1 = dst.width - 1; + if (j0 < 0) j0 = 0; + if (j1 >= dst.height) j1 = dst.height - 1; f64 w_inv = 1. / w; f64 h_inv = 1. / h; @@ -905,24 +750,11 @@ static void draw_text_(Brush brush, f64 x0, f64 y0, f64 scale_x, f64 scale_y, i6 i64 column = (i64) floor(((i - x) * num_cols) * w_inv + .5); i64 offset = char_column_offset_(text[n], column); - if (brush.xor_color) - for (i64 j = j0; j <= j1; ++j) { - i64 row = (i64) floor(((j - y) * CHAR_NUM_BITS_Y_) * h_inv + .5); - if (char_bit_(offset, row)) - put_pixel_xor_(brush, i, j); - } - else if (brush.alpha) - for (i64 j = j0; j <= j1; ++j) { - i64 row = (i64) floor(((j - y) * CHAR_NUM_BITS_Y_) * h_inv + .5); - if (char_bit_(offset, row)) - put_pixel_alpha_(brush, i, j); - } - else - for (i64 j = j0; j <= j1; ++j) { - i64 row = (i64) floor(((j - y) * CHAR_NUM_BITS_Y_) * h_inv + .5); - if (char_bit_(offset, row)) - put_pixel_color_(brush, i, j); - } + for (i64 j = j0; j <= j1; ++j) { + i64 row = (i64) floor(((j - y) * CHAR_NUM_BITS_Y_) * h_inv + .5); + if (char_bit_(offset, row)) + put_pixel_alpha_(dst, color, i, j); + } } } @@ -930,24 +762,105 @@ static void draw_text_(Brush brush, f64 x0, f64 y0, f64 scale_x, f64 scale_y, i6 } } -static Brush brush_defaults_(Brush b) { - if (g_platform.frame_width > 0) { - if (b.scale.x == 0.) b.scale.x = ((f64) g_platform.frame_width) / g_platform.real_width; - if (b.scale.y == 0.) b.scale.y = ((f64) g_platform.frame_height) / g_platform.real_height; - } +void draw_text_area_raw(Pixel_Buffer dst, vec4_f32 color, f64 x, f64 y, f64 width, f64 height, f64 max_width, f64 max_height, i64 num_chars, c32 *text) { + if (text == NULL || num_chars <= 0 || max_width < EPSILON || max_height < EPSILON) + return; + + i64 num_columns = enum_text_columns_(num_chars, text); + i64 num_rows = enum_text_rows_(num_chars, text); + + f64 scale_x = width / num_columns; + f64 scale_y = height / num_rows; - if (b.buffer.pixels == NULL) - b.buffer = frame_pixels(); + f64 kx = scale_x / max_width; + f64 ky = scale_y / max_height; - if (b.buffer.stride == 0) - b.buffer.stride = b.buffer.width; + f64 k = kx < ky ? kx : ky; - if (b.sketch_size == 0 && b.sketch == NULL) { - b.sketch_size = MAX_NUM_PIXELS; - b.sketch = g_platform.sketch; - } + kx = k * max_width; + ky = k * max_height; - return b; + draw_text_(dst, color, x, y, kx, ky, num_chars, text); +} + +void draw_text_cursor_raw(Pixel_Buffer dst, vec4_f32 color, f64 x, f64 y, f64 width, f64 height, f64 max_width, f64 max_height, i64 cursor, i64 selection, i64 num_chars, c32 *text) { + if (max_width < EPSILON || max_height < EPSILON) + return; + + i64 num_columns = enum_text_columns_(num_chars, text); + i64 num_rows = enum_text_rows_(num_chars, text); + i64 cursor_x = text_cursor_(cursor, text); + i64 cursor_y = enum_text_rows_(cursor, text); + + f64 scale_x = width / num_columns; + f64 scale_y = height / num_rows; + + f64 kx = scale_x / max_width; + f64 ky = scale_y / max_height; + + f64 k = kx < ky ? kx : ky; + + kx = k * max_width; + ky = k * max_height; + + if (selection != 0) { + i64 selection_x, selection_y; + + if (selection > 0) { + selection_x = text_cursor_(cursor + selection, text); + selection_y = enum_text_rows_(cursor + selection, text); + } else { + selection_x = cursor_x; + selection_y = cursor_y; + cursor_x = text_cursor_(cursor + selection, text); + cursor_y = enum_text_rows_(cursor + selection, text); + } + + if (cursor_y == selection_y) + fill_rectangle_raw( + dst, + color, + x + kx * cursor_x, + y + ky * cursor_y - ky * (CHAR_NUM_BITS_Y_ + 1), + kx * (selection_x - cursor_x), + ky * (CHAR_NUM_BITS_Y_ + 1) + ); + else { + fill_rectangle_raw( + dst, + color, + x + kx * cursor_x, + y + ky * cursor_y - ky * (CHAR_NUM_BITS_Y_ + 1), + kx * (num_columns - cursor_x), + ky * (CHAR_NUM_BITS_Y_ + 1) + ); + for (i64 j = cursor_y + CHAR_NUM_BITS_Y_ + 1; j < selection_y; j += CHAR_NUM_BITS_Y_ + 1) + fill_rectangle_raw( + dst, + color, + x, + y + ky * j - ky * (CHAR_NUM_BITS_Y_ + 1), + kx * num_columns, + ky * (CHAR_NUM_BITS_Y_ + 1) + ); + fill_rectangle_raw( + dst, + color, + x, + y + ky * selection_y - ky * (CHAR_NUM_BITS_Y_ + 1), + kx * selection_x, + ky * (CHAR_NUM_BITS_Y_ + 1) + ); + } + } else + fill_rectangle_raw( + dst, + color, + x + kx * cursor_x, + y + ky * cursor_y - ky * CHAR_NUM_BITS_Y_, + kx * .5, + ky * (CHAR_NUM_BITS_Y_ - 1) + ); } // ================================================================ @@ -1256,301 +1169,245 @@ b8 line_contains(f64 x0, f64 y0, f64 x1, f64 y1, f64 width, f64 px, f64 py) { || triangle_contains(x0 - tx, y0 - ty, x1 + tx, y1 + ty, x1 - tx, y1 - ty, px, py); } -Pixel_Buffer frame_pixels(void) { - return (Pixel_Buffer) { - .width = g_platform.frame_width, - .height = g_platform.frame_height, - .stride = g_platform.frame_width, - .pixels = g_platform.pixels, - }; -} - -Pixel_Buffer subimage(Pixel_Buffer image, i64 x, i64 y, i64 width, i64 height) { - if (x < 0 || y < 0 || width <= 0 || height <= 0 || x + width > image.width || y + height > image.height || image.pixels == NULL) - return (Pixel_Buffer) { - .width = 0, - .height = 0, - .stride = 0, - - // Set pixels pointer to prevent default initialization. - .pixels = g_platform.sketch, - }; - - return (Pixel_Buffer) { - .width = width, - .height = height, - .stride = image.stride, - .pixels = image.pixels + (y * image.stride + x), - }; -} - -void put_pixel(Brush brush, i64 x, i64 y) { - brush = brush_defaults_(brush); - - if (x < 0 || x >= brush.buffer.width || y < 0 || y >= brush.buffer.height) - return; - - put_pixel_(brush, x, y); -} - -void draw_pixels(Brush brush, f64 x, f64 y, f64 width, f64 height, Pixel_Buffer src) { - if (width < EPSILON || height < EPSILON || src.width <= 0 || src.height <= 0 || src.stride <= 0 || src.pixels == NULL) - return; +// ================================================================ - draw_pixels_(brush_defaults_(brush), x, y, width, height, src); -} +void gx_render_raw_(Gx_Context context, Pixel_Buffer dst, Gx_Request req) { + switch (req.op) { + case OP_REQUESTS: + for (i64 i = 0; i < req.requests.num; ++i) + gx_render_raw_(context, dst, req.requests.values[i]); + break; -void fill_rectangle(Brush brush, f64 x, f64 y, f64 width, f64 height) { - fill_rectangle_(brush_defaults_(brush), x, y, width, height); -} + case OP_PIXELS: + draw_pixels_raw( + dst, + req.pixels.area.x, + req.pixels.area.y, + req.pixels.area.width, + req.pixels.area.height, + req.pixels.src + ); + break; -void fill_triangle(Brush brush, f64 x0, f64 y0, f64 x1, f64 y1, f64 x2, f64 y2) { - brush = brush_defaults_(brush); + case OP_RECTANGLE: + fill_rectangle_raw( + dst, + req.rectangle.color, + req.rectangle.area.x, + req.rectangle.area.y, + req.rectangle.area.width, + req.rectangle.area.height + ); + break; - if (!brush.quick) { - Brush aa = antialiasing_brush_(brush); + case OP_TRIANGLE: + fill_triangle_raw( + dst, + req.triangle.color, + req.triangle.vertices[0].x, + req.triangle.vertices[0].y, + req.triangle.vertices[1].x, + req.triangle.vertices[1].y, + req.triangle.vertices[2].x, + req.triangle.vertices[2].y + ); + break; - f64 x = min3_(x0, x1, x2); - f64 y = min3_(y0, y1, y2); - f64 width = max3_(x0, x1, x2) - x; - f64 height = max3_(y0, y1, y2) - y; + case OP_QUAD: + fill_quad_raw( + dst, + req.quad.color, + req.quad.vertices[0].x, + req.quad.vertices[0].y, + req.quad.vertices[1].x, + req.quad.vertices[1].y, + req.quad.vertices[2].x, + req.quad.vertices[2].y, + req.quad.vertices[3].x, + req.quad.vertices[3].y + ); + break; - Brush clear = aa; - clear.color = vec4_from_vec3_f32(vec3_from_vec4_f32(brush.color), 0.f); - fill_rectangle_(clear, 0, 0, width, height); + case OP_ELLIPSE: + fill_ellipse_raw( + dst, + req.ellipse.color, + req.ellipse.area.x, + req.ellipse.area.y, + req.ellipse.area.width, + req.ellipse.area.height + ); + break; - fill_triangle_(aa, x0 - x, y0 - y, x1 - x, y1 - y, x2 - x, y2 - y); + case OP_LINE: + fill_line_raw( + dst, + req.line.color, + req.line.vertices[0].x, + req.line.vertices[0].y, + req.line.vertices[1].x, + req.line.vertices[1].y, + req.line.width + ); + break; - f64 x0, y0, x1, y1; - transform_box_(aa, 0, 0, width, height, &x0, &y0, &x1, &y1); + case OP_TEXT_AREA: + draw_text_area_raw( + dst, + req.text_area.color, + req.text_area.area.x, + req.text_area.area.y, + req.text_area.area.width, + req.text_area.area.height, + req.text_area.max_size.x, + req.text_area.max_size.y, + req.text_area.num_chars, + req.text_area.text + ); + break; - i64 i0 = (i64) floor(x0); - i64 i1 = (i64) ceil (x1); - i64 j0 = (i64) floor(y0); - i64 j1 = (i64) ceil (y1); + case OP_TEXT_CURSOR: + draw_text_cursor_raw( + dst, + req.text_cursor.color, + req.text_cursor.area.x, + req.text_cursor.area.y, + req.text_cursor.area.width, + req.text_cursor.area.height, + req.text_cursor.max_size.x, + req.text_cursor.max_size.y, + req.text_cursor.cursor, + req.text_cursor.selection, + req.text_cursor.num_chars, + req.text_cursor.text + ); + break; - draw_pixels_from_( - copy_brush_(brush), - x, y, width, height, - aa.buffer, i0, j0, i1 - i0, j1 - j0 - ); - } else - fill_triangle_(brush, x0, y0, x1, y1, x2, y2); + default:; + } } -void fill_quad(Brush brush, f64 x0, f64 y0, f64 x1, f64 y1, f64 x2, f64 y2, f64 x3, f64 y3) { - brush = brush_defaults_(brush); - - if (!brush.quick) { - Brush aa = antialiasing_brush_(brush); - - f64 x = min4_(x0, x1, x2, x3); - f64 y = min4_(y0, y1, y2, y3); - f64 width = max4_(x0, x1, x2, x3) - x; - f64 height = max4_(y0, y1, y2, y3) - y; - - Brush clear = aa; - clear.color = vec4_from_vec3_f32(vec3_from_vec4_f32(brush.color), 0.f); - fill_rectangle_(clear, 0, 0, width, height); - - fill_quad_(aa, x0 - x, y0 - y, x1 - x, y1 - y, x2 - x, y2 - y, x3 - x, y3 - y); - - f64 x0, y0, x1, y1; - transform_box_(aa, 0, 0, width, height, &x0, &y0, &x1, &y1); +Gx_Request gx_scaled_(Gx_Request req, vec2 scale) { + Gx_Request scaled = req; - i64 i0 = (i64) floor(x0); - i64 i1 = (i64) ceil (x1); - i64 j0 = (i64) floor(y0); - i64 j1 = (i64) ceil (y1); - - draw_pixels_from_( - copy_brush_(brush), - x, y, width, height, - aa.buffer, i0, j0, i1 - i0, j1 - j0 - ); - } else - fill_quad_(brush, x0, y0, x1, y1, x2, y2, x3, y3); -} + switch (req.op) { + case OP_REQUESTS: + for (i64 i = 0; i < req.requests.num; ++i) + scaled.requests.values[i] = gx_scaled_(req.requests.values[i], scale); + break; -void fill_ellipse(Brush brush, f64 x, f64 y, f64 width, f64 height) { - // FIXME PERF: - // Implement better algorithm. + case OP_PIXELS: + scaled.pixels.area.x *= scale.x; + scaled.pixels.area.y *= scale.y; + scaled.pixels.area.width *= scale.x; + scaled.pixels.area.height *= scale.y; + break; - if (width < EPSILON || height < EPSILON) - return; + case OP_RECTANGLE: + scaled.rectangle.area.x *= scale.x; + scaled.rectangle.area.y *= scale.y; + scaled.rectangle.area.width *= scale.x; + scaled.rectangle.area.height *= scale.y; + break; - brush = brush_defaults_(brush); + case OP_TRIANGLE: + scaled.triangle.vertices[0].x *= scale.x; + scaled.triangle.vertices[0].y *= scale.y; + scaled.triangle.vertices[1].x *= scale.x; + scaled.triangle.vertices[1].y *= scale.y; + scaled.triangle.vertices[2].x *= scale.x; + scaled.triangle.vertices[2].y *= scale.y; + break; - if (!brush.quick) { - Brush aa = antialiasing_brush_(brush); + case OP_QUAD: + scaled.quad.vertices[0].x *= scale.x; + scaled.quad.vertices[0].y *= scale.y; + scaled.quad.vertices[1].x *= scale.x; + scaled.quad.vertices[1].y *= scale.y; + scaled.quad.vertices[2].x *= scale.x; + scaled.quad.vertices[2].y *= scale.y; + scaled.quad.vertices[4].x *= scale.x; + scaled.quad.vertices[4].y *= scale.y; + break; - Brush clear = aa; - clear.color = vec4_from_vec3_f32(vec3_from_vec4_f32(brush.color), 0.f); - fill_rectangle_(clear, 0, 0, width, height); + case OP_ELLIPSE: + scaled.ellipse.area.x *= scale.x; + scaled.ellipse.area.y *= scale.y; + scaled.ellipse.area.width *= scale.x; + scaled.ellipse.area.height *= scale.y; + break; - fill_ellipse_(aa, 0, 0, width, height); + case OP_LINE: + scaled.line.vertices[0].x *= scale.x; + scaled.line.vertices[0].y *= scale.y; + scaled.line.vertices[1].x *= scale.x; + scaled.line.vertices[1].y *= scale.y; - f64 x0, y0, x1, y1; - transform_box_(aa, 0, 0, width, height, &x0, &y0, &x1, &y1); + f64 dx = req.line.vertices[1].x - req.line.vertices[0].x; + f64 dy = req.line.vertices[1].y - req.line.vertices[0].y; - i64 i0 = (i64) floor(x0); - i64 i1 = (i64) ceil (x1); - i64 j0 = (i64) floor(y0); - i64 j1 = (i64) ceil (y1); + f64 l = sqrt(dx * dx + dy * dy); + if (l > EPSILON) { + dx /= l; + dy /= l; - draw_pixels_from_( - copy_brush_(brush), - x, y, width, height, - aa.buffer, i0, j0, i1 - i0, j1 - j0 - ); - } else - fill_ellipse_(brush, x, y, width, height); -} + f64 tx = dy * scale.x; + f64 ty = -dx * scale.y; -void fill_line(Brush brush, f64 x0, f64 y0, f64 x1, f64 y1, f64 width) { - if (width < EPSILON) - return; + scaled.line.width *= sqrt(tx * tx + ty * ty); + } else + scaled.line.width *= (scale.x + scale.y) / 2.0; - f64 dx = x1 - x0; - f64 dy = y1 - y0; + break; - // Tangent - // - f64 tx = -dy; - f64 ty = dx; - f64 tl = sqrt(tx * tx + ty * ty); + case OP_TEXT_AREA: + scaled.text_area.area.x *= scale.x; + scaled.text_area.area.y *= scale.y; + scaled.text_area.area.width *= scale.x; + scaled.text_area.area.height *= scale.y; + scaled.text_area.max_size.x *= scale.x; + scaled.text_area.max_size.y *= scale.y; + break; - if (tl < EPSILON) - return; + case OP_TEXT_CURSOR: + scaled.text_cursor.area.x *= scale.x; + scaled.text_cursor.area.y *= scale.y; + scaled.text_cursor.area.width *= scale.x; + scaled.text_cursor.area.height *= scale.y; + scaled.text_cursor.max_size.x *= scale.x; + scaled.text_cursor.max_size.y *= scale.y; + break; - f64 k = .5 / tl; - tx *= width * k; - ty *= width * k; + default:; + } - fill_quad(brush, x0 - tx, y0 - ty, x0 + tx, y0 + ty, x1 + tx, y1 + ty, x1 - tx, y1 - ty); + return scaled; } -void draw_text_area(Brush brush, f64 x, f64 y, f64 width, f64 height, f64 max_scale_x, f64 max_scale_y, i64 num_chars, c32 *text) { - if (text == NULL || num_chars <= 0 || max_scale_x < EPSILON || max_scale_y < EPSILON) - return; - - i64 num_columns = enum_text_columns_(num_chars, text); - i64 num_rows = enum_text_rows_(num_chars, text); - - f64 scale_x = width / num_columns; - f64 scale_y = height / num_rows; - - f64 kx = scale_x / max_scale_x; - f64 ky = scale_y / max_scale_y; - - f64 k = kx < ky ? kx : ky; - - kx = k * max_scale_x; - ky = k * max_scale_y; - - brush = brush_defaults_(brush); - - if (!brush.quick) { - Brush aa = antialiasing_brush_(brush); - - Brush clear = aa; - clear.color = vec4_from_vec3_f32(vec3_from_vec4_f32(brush.color), 0.f); - fill_rectangle_(clear, 0, 0, width, height); - - draw_text_(aa, 0, 0, kx, ky, num_chars, text); - - f64 x0, y0, x1, y1; - transform_box_(aa, 0, 0, width, height, &x0, &y0, &x1, &y1); - - i64 i0 = (i64) floor(x0); - i64 i1 = (i64) ceil (x1); - i64 j0 = (i64) floor(y0); - i64 j1 = (i64) ceil (y1); - - draw_pixels_from_( - copy_brush_(brush), - x, y, width, height, - aa.buffer, i0, j0, i1 - i0, j1 - j0 - ); - } else - draw_text_(brush, x, y, kx, ky, num_chars, text); +void gx_render_(Gx_Context context, Pixel_Buffer dst, Gx_Request req) { + gx_render_raw_(context, dst, gx_scaled_(req, context.scale)); } -void draw_text_cursor(Brush brush, f64 x, f64 y, f64 width, f64 height, f64 max_scale_x, f64 max_scale_y, i64 cursor, i64 selection, i64 num_chars, c32 *text) { - if (max_scale_x < EPSILON || max_scale_y < EPSILON) - return; - - i64 num_columns = enum_text_columns_(num_chars, text); - i64 num_rows = enum_text_rows_(num_chars, text); - i64 cursor_x = text_cursor_(cursor, text); - i64 cursor_y = enum_text_rows_(cursor, text); - - f64 scale_x = width / num_columns; - f64 scale_y = height / num_rows; - - f64 kx = scale_x / max_scale_x; - f64 ky = scale_y / max_scale_y; - - f64 k = kx < ky ? kx : ky; - - kx = k * max_scale_x; - ky = k * max_scale_y; - - brush = brush_defaults_(brush); - - if (selection != 0) { - i64 selection_x, selection_y; +void gx_render(Gx_Context context, Pixel_Buffer dst, Gx_Request req) { + if (context.sketch == NULL) { + context.sketch_size = MAX_NUM_PIXELS; + context.sketch = g_platform.sketch; + } - if (selection > 0) { - selection_x = text_cursor_(cursor + selection, text); - selection_y = enum_text_rows_(cursor + selection, text); - } else { - selection_x = cursor_x; - selection_y = cursor_y; - cursor_x = text_cursor_(cursor + selection, text); - cursor_y = enum_text_rows_(cursor + selection, text); - } + if (dst.pixels == NULL) { + dst.width = g_platform.frame_width; + dst.height = g_platform.frame_height; + dst.stride = g_platform.frame_width; + dst.pixels = g_platform.pixels; + + if (context.scale.x == 0. && context.scale.y == 0.) + context.scale = (vec2) { + .x = ((f64) g_platform.frame_width) / g_platform.real_width, + .y = ((f64) g_platform.frame_height) / g_platform.real_height, + }; + } - if (cursor_y == selection_y) - fill_rectangle_( - brush, - x + kx * cursor_x, - y + ky * cursor_y - ky * (CHAR_NUM_BITS_Y_ + 1), - kx * (selection_x - cursor_x), - ky * (CHAR_NUM_BITS_Y_ + 1) - ); - else { - fill_rectangle_( - brush, - x + kx * cursor_x, - y + ky * cursor_y - ky * (CHAR_NUM_BITS_Y_ + 1), - kx * (num_columns - cursor_x), - ky * (CHAR_NUM_BITS_Y_ + 1) - ); - for (i64 j = cursor_y + CHAR_NUM_BITS_Y_ + 1; j < selection_y; j += CHAR_NUM_BITS_Y_ + 1) - fill_rectangle_( - brush, - x, - y + ky * j - ky * (CHAR_NUM_BITS_Y_ + 1), - kx * num_columns, - ky * (CHAR_NUM_BITS_Y_ + 1) - ); - fill_rectangle_( - brush, - x, - y + ky * selection_y - ky * (CHAR_NUM_BITS_Y_ + 1), - kx * selection_x, - ky * (CHAR_NUM_BITS_Y_ + 1) - ); - } - } else - fill_rectangle_( - brush, - x + kx * cursor_x, - y + ky * cursor_y - ky * CHAR_NUM_BITS_Y_, - kx * .5, - ky * (CHAR_NUM_BITS_Y_ - 1) - ); + gx_render_(context, dst, req); } // ================================================================ @@ -1644,22 +1501,19 @@ TEST("colors") { REQUIRE_EQ((purple.z + 2e-7) * 100, 100); } -Brush brush = { - .buffer = { - .width = 1280, - .height = 720, - .stride = 1280, - .pixels = g_platform.pixels, - }, - .position = { 0.f, 0.f, }, - .scale = { 1.f, 1.f, }, - .color = { 1.f, 1.f, 1.f, 1.f }, +Pixel_Buffer pixels = { + .width = 1280, + .height = 720, + .stride = 1280, + .pixels = g_platform.sketch, }; +vec4_f32 color = { 1., 1., 1., 1., }; + BENCHMARK("fill rectangle") { BENCHMARK_BEGIN; { - fill_rectangle(brush, 100, 100, 300, 200); + fill_rectangle_raw(pixels, color, 100, 100, 300, 200); } BENCHMARK_END; } @@ -1667,7 +1521,7 @@ BENCHMARK("fill rectangle") { BENCHMARK("fill triangle") { BENCHMARK_BEGIN; { - fill_triangle(brush, 100, 100, 300, 100, 200, 250); + fill_triangle_raw(pixels, color, 100, 100, 300, 100, 200, 250); } BENCHMARK_END; } @@ -1675,7 +1529,7 @@ BENCHMARK("fill triangle") { BENCHMARK("fill quad") { BENCHMARK_BEGIN; { - fill_quad(brush, 100, 100, 300, 100, 300, 200, 100, 200); + fill_quad_raw(pixels, color, 100, 100, 300, 100, 300, 200, 100, 200); } BENCHMARK_END; } @@ -1683,7 +1537,7 @@ BENCHMARK("fill quad") { BENCHMARK("fill ellipse") { BENCHMARK_BEGIN; { - fill_ellipse(brush, 80, 80, 340, 240); + fill_ellipse_raw(pixels, color, 80, 80, 340, 240); } BENCHMARK_END; } @@ -1691,7 +1545,7 @@ BENCHMARK("fill ellipse") { BENCHMARK("fill line") { BENCHMARK_BEGIN; { - fill_line(brush, 100, 100, 300, 200, 40); + fill_line_raw(pixels, color, 100, 100, 300, 200, 40); } BENCHMARK_END; } @@ -1700,7 +1554,7 @@ BENCHMARK("draw text area") { BENCHMARK_BEGIN; { c32 text[] = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'S', 'a', 'i', 'l', 'o', 'r', '!', }; - draw_text_area(brush, 100, 100, 300, 200, 100, 200, sizeof text / sizeof *text, text); + draw_text_area_raw(pixels, color, 100, 100, 300, 200, 100, 200, sizeof text / sizeof *text, text); } BENCHMARK_END; } |