summaryrefslogtreecommitdiff
path: root/graphics.c
diff options
context:
space:
mode:
authorMitya Selivanov <automainint@guattari.tech>2025-01-23 12:19:08 +0100
committerMitya Selivanov <automainint@guattari.tech>2025-01-23 12:19:08 +0100
commit6ec822ee73734aafa598c642e91fb2194792397b (patch)
tree04d98433fe01049bc20ec3c5651d7f1dd182e389 /graphics.c
parent53feef5a47b6093ac4b518da96368870bb530bce (diff)
downloadreduced_system_layer-6ec822ee73734aafa598c642e91fb2194792397b.zip
Graphics requests - in progress
Diffstat (limited to 'graphics.c')
-rwxr-xr-xgraphics.c1334
1 files changed, 594 insertions, 740 deletions
diff --git a/graphics.c b/graphics.c
index eb0db72..ec1e243 100755
--- a/graphics.c
+++ b/graphics.c
@@ -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;
}