diff options
Diffstat (limited to 'graphics.c')
-rwxr-xr-x | graphics.c | 319 |
1 files changed, 282 insertions, 37 deletions
@@ -97,6 +97,7 @@ enum { GRAPHICS_DRAW_PIXELS, GRAPHICS_FILL_RECTANGLE, GRAPHICS_FILL_TRIANGLE, + GRAPHICS_FILL_TRIANGLES, GRAPHICS_FILL_QUAD, GRAPHICS_FILL_ELLIPSE, GRAPHICS_FILL_LINE, @@ -121,6 +122,12 @@ typedef struct graphics_request_ { } triangle; struct { vec4_f32 color; + Box area; + i64 num_triangles; + vec2 * vertices; + } triangles; + struct { + vec4_f32 color; vec2 vertices[4]; } quad; struct { @@ -152,11 +159,23 @@ typedef struct graphics_request_ { } Graphics_Request; typedef struct { - b8 disable_antialiasing; + b8 disable_cache; vec2 scale; Pixel_Buffer dst; } Graphics_Context; +// ================================================================ +// +// User program interface +// +// ================================================================ + +Box external_font_text_area(i32 font, vec2 scale, i64 num_chars, c32 *text); + +void external_font_render_to_buffer(Pixel_Buffer dst, i32 font, vec4_f32 color, vec2 position, vec2 scale, i64 num_chars, c32 *text); + +// ================================================================ + vec3_f32 lab_from_rgb(vec3_f32 rgb); vec3_f32 rgb_from_lab(vec3_f32 lab); vec3_f32 lab_from_lch(vec3_f32 lch); @@ -194,24 +213,33 @@ b8 hit_line (vec2 vertices[2], f64 width, vec2 point); void draw_pixels_to_buffer (Pixel_Buffer dst, Box area, Pixel_Buffer src); void fill_rectangle_to_buffer (Pixel_Buffer dst, vec4_f32 color, Box area); void fill_triangle_to_buffer (Pixel_Buffer dst, vec4_f32 color, vec2 vertices[3]); +void fill_triangles_to_buffer (Pixel_Buffer dst, vec4_f32 color, Box area, i64 num_triangles, vec2 *vertices); void fill_quad_to_buffer (Pixel_Buffer dst, vec4_f32 color, vec2 vertices[4]); void fill_ellipse_to_buffer (Pixel_Buffer dst, vec4_f32 color, Box area); void fill_line_to_buffer (Pixel_Buffer dst, vec4_f32 color, vec2 vertices[2], f64 width); void draw_text_area_to_buffer (Pixel_Buffer dst, vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text); void draw_text_cursor_to_buffer(Pixel_Buffer dst, vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text, i64 cursor, i64 selection); +void draw_pixels_cached (Box area, Pixel_Buffer src); +void fill_rectangle_cached (vec4_f32 color, Box area); +void fill_triangle_cached (vec4_f32 color, vec2 vertices[3]); +void fill_triangles_cached (vec4_f32 color, Box area, i64 num_triangles, vec2 *vertices); +void fill_quad_cached (vec4_f32 color, vec2 vertices[4]); +void fill_ellipse_cached (vec4_f32 color, Box area); +void fill_line_cached (vec4_f32 color, vec2 vertices[2], f64 width); +void draw_text_area_cached (vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text); +void draw_text_cursor_cached(vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text, i64 cursor, i64 selection); + void draw_pixels (Box area, Pixel_Buffer src); void fill_rectangle (vec4_f32 color, Box area); void fill_triangle (vec4_f32 color, vec2 vertices[3]); +void fill_triangles (vec4_f32 color, Box area, i64 num_triangles, vec2 *vertices); void fill_quad (vec4_f32 color, vec2 vertices[4]); void fill_ellipse (vec4_f32 color, Box area); void fill_line (vec4_f32 color, vec2 vertices[2], f64 width); void draw_text_area (vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text); void draw_text_cursor(vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text, i64 cursor, i64 selection); -void draw_pixels_quick (Box area, Pixel_Buffer src); -void fill_rectangle_quick(vec4_f32 color, Box area); - void perform_graphics_request(Graphics_Context context, Graphics_Request req); #endif // GRAPHICS_HEADER_GUARD_ @@ -332,11 +360,6 @@ void fill_rectangle_to_buffer(Pixel_Buffer dst, vec4_f32 color, Box area) { i64 j0 = (i64) floor(area.y); i64 j1 = (i64) floor(area.y + area.height); - i64 i00 = i0; - i64 j00 = j0; - i64 i10 = i1; - i64 j10 = j1; - if (i0 < 0) i0 = 0; if (i1 > dst.width) i1 = dst.width; if (j0 < 0) j0 = 0; @@ -393,6 +416,43 @@ void fill_triangle_to_buffer(Pixel_Buffer dst, vec4_f32 color, vec2 vertices[3]) } } +static void triangles_area_(f64 *x0, f64 *y0, f64 *x1, f64 *y1, i64 num, vec2 *v) { + if (num <= 0) + return; + + *x0 = min3_(v[0].x, v[1].x, v[2].x); + *y0 = min3_(v[0].y, v[1].y, v[2].y); + *x1 = max3_(v[0].x, v[1].x, v[2].x); + *y1 = max3_(v[0].y, v[1].y, v[2].y); + + for (i64 i = 1; i < num; ++i) { + *x0 = min4_(*x0, v[i * 3].x, v[i * 3 + 1].x, v[i * 3 + 2].x); + *y0 = min4_(*y0, v[i * 3].y, v[i * 3 + 1].y, v[i * 3 + 2].y); + *x1 = max4_(*x1, v[i * 3].x, v[i * 3 + 1].x, v[i * 3 + 2].x); + *y1 = max4_(*y1, v[i * 3].y, v[i * 3 + 1].y, v[i * 3 + 2].y); + } +} + +void fill_triangles_to_buffer(Pixel_Buffer dst, vec4_f32 color, Box area, i64 num_triangles, vec2 *vertices) { + f64 x0, y0, x1, y1; + triangles_area_(&x0, &y0, &x1, &y1, num_triangles, vertices); + + i64 i0 = (i64) x0; + i64 j0 = (i64) y0; + i64 i1 = (i64) x1; + i64 j1 = (i64) y1; + + // FIXME, PERF + + for (i64 j = j0; j <= j1; ++j) + for (i64 i = i0; i <= i1; ++i) + for (i64 k = 0; k < num_triangles; ++k) + if (hit_triangle(vertices + 3 * k, (vec2) { (f64) i, (f64) j, })) { + put_pixel_(dst.pixels + j * dst.stride + i, color); + break; + } +} + void fill_quad_to_buffer(Pixel_Buffer dst, vec4_f32 color, vec2 vertices[4]) { f64 x0 = vertices[0].x; f64 y0 = vertices[0].y; @@ -403,10 +463,10 @@ void fill_quad_to_buffer(Pixel_Buffer dst, vec4_f32 color, vec2 vertices[4]) { f64 x3 = vertices[3].x; f64 y3 = vertices[3].y; - 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)); + i64 i0 = (i64) floor(min4_(x0, x1, x2, x3)); + i64 j0 = (i64) floor(min4_(y0, y1, y2, y3)); + i64 i1 = (i64) ceil (max4_(x0, x1, x2, x3)); + i64 j1 = (i64) ceil (max4_(y0, y1, y2, y3)); if (i0 < 0) i0 = 0; if (i1 >= dst.width) i1 = dst.width - 1; @@ -477,7 +537,7 @@ void fill_ellipse_to_buffer(Pixel_Buffer dst, vec4_f32 color, Box area) { } } -b8 quad_from_line_(vec2 *dst, vec2 vertices[2], f64 width) { +static b8 quad_from_line_(vec2 *dst, vec2 vertices[2], f64 width) { f64 x0 = vertices[0].x; f64 y0 = vertices[0].y; f64 x1 = vertices[1].x; @@ -511,6 +571,8 @@ void fill_line_to_buffer(Pixel_Buffer dst, vec4_f32 color, vec2 vertices[2], f64 vec2 quad[4]; if (!quad_from_line_(quad, vertices, width)) return; fill_quad_to_buffer(dst, color, quad); + + // TODO: Also render line ends as circles. } static i64 char_column_offset_(c32 c, i64 column_index) { @@ -721,6 +783,17 @@ static void draw_text_(Pixel_Buffer dst, vec4_f32 color, f64 x0, f64 y0, f64 sca } } +#if !defined(GRAPHICS_ENABLE_EXTERNAL_FONT) +Box external_font_text_area(i32 font, vec2 scale, i64 num_chars, c32 *text) { + // TODO + return (Box) {0}; +} + +void external_font_render_to_buffer(Pixel_Buffer dst, i32 font, vec4_f32 color, vec2 position, vec2 scale, i64 num_chars, c32 *text) { + // TODO +} +#endif // !defined(GRAPHICS_ENABLE_EXTERNAL_FONT) + void draw_text_area_to_buffer(Pixel_Buffer dst, vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text) { if (text == NULL || num_chars <= 0 || max_size.x < EPSILON || max_size.y < EPSILON) return; @@ -743,7 +816,7 @@ void draw_text_area_to_buffer(Pixel_Buffer dst, vec4_f32 color, Box area, vec2 m } void draw_text_cursor_to_buffer(Pixel_Buffer dst, vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text, i64 cursor, i64 selection) { - if (max_size.x< EPSILON || max_size.y < EPSILON) + if (max_size.x < EPSILON || max_size.y < EPSILON) return; i64 num_columns = enum_text_columns_(num_chars, text); @@ -1070,9 +1143,6 @@ b8 hit_rectangle(Box area, vec2 point) { } b8 hit_triangle(vec2 vertices[3], vec2 point) { - // Z-components of cross-products - // - f64 x0 = vertices[0].x; f64 y0 = vertices[0].y; f64 x1 = vertices[1].x; @@ -1082,6 +1152,12 @@ b8 hit_triangle(vec2 vertices[3], vec2 point) { f64 px = point.x; f64 py = point.y; + if ( (px < x0 && px < x1 && px < x2) + || (px > x0 && px > x1 && px > x2) + || (py < y0 && py < y1 && py < y2) + || (py > y0 && py > y1 && py > y2) ) + return 0; + f64 x10 = x1 - x0; f64 x21 = x2 - x1; f64 x02 = x0 - x2; @@ -1090,6 +1166,8 @@ b8 hit_triangle(vec2 vertices[3], vec2 point) { f64 y21 = y2 - y1; f64 y02 = y0 - y2; + // Z-components of cross-products + f64 z0 = x02 * y10 - x10 * y02; f64 z1 = x10 * y21 - x21 * y10; f64 z2 = x21 * y02 - x02 * y21; @@ -1164,7 +1242,7 @@ b8 hit_line(vec2 vertices[2], f64 width, vec2 point) { }, point); } -void draw_pixels(Box area, Pixel_Buffer src) { +void draw_pixels_cached(Box area, Pixel_Buffer src) { perform_graphics_request( (Graphics_Context) {0}, (Graphics_Request) { @@ -1177,7 +1255,7 @@ void draw_pixels(Box area, Pixel_Buffer src) { ); } -void fill_rectangle(vec4_f32 color, Box area) { +void fill_rectangle_cached(vec4_f32 color, Box area) { perform_graphics_request( (Graphics_Context) {0}, (Graphics_Request) { @@ -1190,7 +1268,7 @@ void fill_rectangle(vec4_f32 color, Box area) { ); } -void fill_triangle(vec4_f32 color, vec2 vertices[3]) { +void fill_triangle_cached(vec4_f32 color, vec2 vertices[3]) { perform_graphics_request( (Graphics_Context) {0}, (Graphics_Request) { @@ -1207,7 +1285,22 @@ void fill_triangle(vec4_f32 color, vec2 vertices[3]) { ); } -void fill_quad(vec4_f32 color, vec2 vertices[4]) { +void fill_triangles_cached(vec4_f32 color, Box area, i64 num_triangles, vec2 *vertices) { + perform_graphics_request( + (Graphics_Context) {0}, + (Graphics_Request) { + .op = GRAPHICS_FILL_TRIANGLES, + .triangles = { + .color = color, + .area = area, + .num_triangles = num_triangles, + .vertices = vertices, + }, + } + ); +} + +void fill_quad_cached(vec4_f32 color, vec2 vertices[4]) { perform_graphics_request( (Graphics_Context) {0}, (Graphics_Request) { @@ -1225,7 +1318,7 @@ void fill_quad(vec4_f32 color, vec2 vertices[4]) { ); } -void fill_ellipse(vec4_f32 color, Box area) { +void fill_ellipse_cached(vec4_f32 color, Box area) { perform_graphics_request( (Graphics_Context) {0}, (Graphics_Request) { @@ -1238,7 +1331,7 @@ void fill_ellipse(vec4_f32 color, Box area) { ); } -void fill_line(vec4_f32 color, vec2 vertices[2], f64 width) { +void fill_line_cached(vec4_f32 color, vec2 vertices[2], f64 width) { perform_graphics_request( (Graphics_Context) {0}, (Graphics_Request) { @@ -1252,7 +1345,7 @@ void fill_line(vec4_f32 color, vec2 vertices[2], f64 width) { ); } -void draw_text_area(vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text) { +void draw_text_area_cached(vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text) { perform_graphics_request( (Graphics_Context) {0}, (Graphics_Request) { @@ -1268,7 +1361,7 @@ void draw_text_area(vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 ); } -void draw_text_cursor(vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text, i64 cursor, i64 selection) { +void draw_text_cursor_cached(vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text, i64 cursor, i64 selection) { perform_graphics_request( (Graphics_Context) {0}, (Graphics_Request) { @@ -1286,9 +1379,9 @@ void draw_text_cursor(vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c3 ); } -void draw_pixels_quick(Box area, Pixel_Buffer src) { +void draw_pixels(Box area, Pixel_Buffer src) { perform_graphics_request( - (Graphics_Context) { .disable_antialiasing = 1, }, + (Graphics_Context) { .disable_cache = 1, }, (Graphics_Request) { .op = GRAPHICS_DRAW_PIXELS, .pixels = { @@ -1299,9 +1392,9 @@ void draw_pixels_quick(Box area, Pixel_Buffer src) { ); } -void fill_rectangle_quick(vec4_f32 color, Box area) { +void fill_rectangle(vec4_f32 color, Box area) { perform_graphics_request( - (Graphics_Context) { .disable_antialiasing = 1, }, + (Graphics_Context) { .disable_cache = 1, }, (Graphics_Request) { .op = GRAPHICS_FILL_RECTANGLE, .rectangle = { @@ -1312,6 +1405,117 @@ void fill_rectangle_quick(vec4_f32 color, Box area) { ); } +void fill_triangle(vec4_f32 color, vec2 vertices[3]) { + perform_graphics_request( + (Graphics_Context) { .disable_cache = 1, }, + (Graphics_Request) { + .op = GRAPHICS_FILL_TRIANGLE, + .triangle = { + .color = color, + .vertices = { + vertices[0], + vertices[1], + vertices[2], + }, + }, + } + ); +} + +void fill_triangles(vec4_f32 color, Box area, i64 num_triangles, vec2 *vertices) { + perform_graphics_request( + (Graphics_Context) { .disable_cache = 1, }, + (Graphics_Request) { + .op = GRAPHICS_FILL_TRIANGLES, + .triangles = { + .color = color, + .area = area, + .num_triangles = num_triangles, + .vertices = vertices, + }, + } + ); +} + +void fill_quad(vec4_f32 color, vec2 vertices[4]) { + perform_graphics_request( + (Graphics_Context) { .disable_cache = 1, }, + (Graphics_Request) { + .op = GRAPHICS_FILL_QUAD, + .quad = { + .color = color, + .vertices = { + vertices[0], + vertices[1], + vertices[2], + vertices[3], + }, + }, + } + ); +} + +void fill_ellipse(vec4_f32 color, Box area) { + perform_graphics_request( + (Graphics_Context) { .disable_cache = 1, }, + (Graphics_Request) { + .op = GRAPHICS_FILL_ELLIPSE, + .ellipse = { + .color = color, + .area = area, + }, + } + ); +} + +void fill_line(vec4_f32 color, vec2 vertices[2], f64 width) { + perform_graphics_request( + (Graphics_Context) { .disable_cache = 1, }, + (Graphics_Request) { + .op = GRAPHICS_FILL_LINE, + .line = { + .color = color, + .vertices = { vertices[0], vertices[1], }, + .width = width, + }, + } + ); +} + +void draw_text_area(vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text) { + perform_graphics_request( + (Graphics_Context) { .disable_cache = 1, }, + (Graphics_Request) { + .op = GRAPHICS_DRAW_TEXT_AREA, + .text_area = { + .color = color, + .area = area, + .max_size = max_size, + .num_chars = num_chars, + .text = text, + }, + } + ); +} + +void draw_text_cursor(vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text, i64 cursor, i64 selection) { + perform_graphics_request( + (Graphics_Context) { .disable_cache = 1, }, + (Graphics_Request) { + .op = GRAPHICS_DRAW_TEXT_CURSOR, + .text_cursor = { + .color = color, + .area = area, + .max_size = max_size, + .num_chars = num_chars, + .text = text, + .cursor = cursor, + .selection = selection, + }, + } + ); +} + // ================================================================ typedef struct { @@ -1343,6 +1547,13 @@ static i64 _graphics_cache_gc_index = 0; static void graphics_request_hash_(Blake2b_State *S, Graphics_Request req) { switch (req.op) { + case GRAPHICS_FILL_TRIANGLES: + blake2b_update(S, (u8 *) &req.triangles.color, sizeof req.triangles.color); + blake2b_update(S, (u8 *) &req.triangles.area, sizeof req.triangles.area); + blake2b_update(S, (u8 *) &req.triangles.num_triangles, sizeof req.triangles.num_triangles); + blake2b_update(S, (u8 *) req.triangles.vertices, req.triangles.num_triangles * 3 * sizeof *req.triangles.vertices); + break; + case GRAPHICS_DRAW_PIXELS: blake2b_update(S, (u8 *) &req.pixels.area, sizeof req.pixels.area); blake2b_update(S, (u8 *) &req.pixels.src.width, sizeof req.pixels.src.width); @@ -1423,6 +1634,13 @@ static Graphics_Request graphics_request_scaled_(Graphics_Request req, vec2 scal scaled.triangle.vertices[2].y *= scale.y; break; + case GRAPHICS_FILL_TRIANGLES: + scaled.triangles.area.x *= scale.x; + scaled.triangles.area.y *= scale.y; + scaled.triangles.area.width *= scale.x; + scaled.triangles.area.height *= scale.y; + break; + case GRAPHICS_FILL_QUAD: scaled.quad.vertices[0].x *= scale.x; scaled.quad.vertices[0].y *= scale.y; @@ -1511,6 +1729,11 @@ static Graphics_Request graphics_request_moved_(Graphics_Request req, vec2 offse moved.triangle.vertices[2].y += offset.y; break; + case GRAPHICS_FILL_TRIANGLES: + moved.triangles.area.x += offset.x; + moved.triangles.area.y += offset.y; + break; + case GRAPHICS_FILL_QUAD: moved.quad.vertices[0].x += offset.x; moved.quad.vertices[0].y += offset.y; @@ -1568,6 +1791,18 @@ static Box graphics_request_area_(Graphics_Request req) { area.height = max3_(v[0].y, v[1].y, v[2].y) - area.y; } break; + case GRAPHICS_FILL_TRIANGLES: + if (req.triangles.num_triangles > 0) { + f64 x0, y0, x1, y1; + triangles_area_(&x0, &y0, &x1, &y1, req.triangles.num_triangles, req.triangles.vertices); + + area.x = x0; + area.y = y0; + area.width = x1 - x0; + area.height = y1 - y0; + } + break; + case GRAPHICS_FILL_QUAD: case GRAPHICS_FILL_LINE: { vec2 quad[4] = {0}; @@ -1635,6 +1870,16 @@ static void perform_graphics_request_to_buffer_(Pixel_Buffer dst, Graphics_Reque ); break; + case GRAPHICS_FILL_TRIANGLES: + fill_triangles_to_buffer( + dst, + req.triangles.color, + req.triangles.area, + req.triangles.num_triangles, + req.triangles.vertices + ); + break; + case GRAPHICS_FILL_QUAD: fill_quad_to_buffer( dst, @@ -1738,7 +1983,7 @@ static void perform_graphics_request_cached_(Pixel_Buffer dst, Graphics_Request } if (slot == -1) { - LOG_ERROR("Graphics cache collision."); + LOG_ERROR("Graphics cache overflow."); slot = n; } @@ -1747,11 +1992,11 @@ static void perform_graphics_request_cached_(Pixel_Buffer dst, Graphics_Request i64 num_pixels = norm.width * norm.height; if (reset_slot) { - s->occupied = 1; - s->id = id; - s->req = norm.req; - s->width = norm.width; - s->height = norm.height; + s->occupied = 1; + s->id = id; + s->req = norm.req; + s->width = norm.width; + s->height = norm.height; if (num_pixels > s->buffer_len) resize_dynamic_array_exact(&s->buffer_len, (void **) &s->buffer, sizeof *s->buffer, num_pixels); @@ -1784,7 +2029,7 @@ static void perform_graphics_request_cached_(Pixel_Buffer dst, Graphics_Request static void scale_and_perform_graphics_request_(Graphics_Context context, Graphics_Request req) { Graphics_Request scaled = graphics_request_scaled_(req, context.scale); - if (context.disable_antialiasing) + if (context.disable_cache) perform_graphics_request_to_buffer_(context.dst, scaled); else perform_graphics_request_cached_(context.dst, scaled); |