From 39aad7f9ca931342f58bf638b5aadd1923db0f50 Mon Sep 17 00:00:00 2001 From: Mitya Selivanov Date: Thu, 16 Jan 2025 19:09:09 +0100 Subject: Graphics fixes --- graphics.c | 165 ++++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 110 insertions(+), 55 deletions(-) (limited to 'graphics.c') diff --git a/graphics.c b/graphics.c index dc2a88e..62a6472 100644 --- a/graphics.c +++ b/graphics.c @@ -23,8 +23,8 @@ // // ================================================================ -vec4_f32 vec4_from_vec3_f32(vec3_f32 v, f32 w); vec3_f32 vec3_from_vec4_f32(vec4_f32 v); +vec4_f32 vec4_from_vec3_f32(vec3_f32 v, f32 w); vec3_f32 vec3_f32_lerp (vec3_f32 a, vec3_f32 b, f32 t); vec4_f32 vec4_f32_lerp (vec4_f32 a, vec4_f32 b, f32 t); @@ -149,15 +149,8 @@ static f64 gamma_re_(f64 x) { return x / 12.92; } -static void put_pixel_xor_(Brush brush, i64 x, i64 y) { - i64 n = y * brush.buffer.line_size + 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.buffer.pixels[n] = vec4_from_vec3_f32(c, 1.f);; +static void put_pixel_color_(Brush brush, i64 x, i64 y) { + brush.buffer.pixels[y * brush.buffer.line_size + x] = brush.color; } static void put_pixel_alpha_(Brush brush, i64 x, i64 y) { @@ -174,8 +167,20 @@ static void put_pixel_alpha_(Brush brush, i64 x, i64 y) { }; } -static void put_pixel_color_(Brush brush, i64 x, i64 y) { - brush.buffer.pixels[y * brush.buffer.line_size + x] = brush.color; +static void put_pixel_xor_(Brush brush, i64 x, i64 y) { + i64 n = y * brush.buffer.line_size + 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) { @@ -188,6 +193,9 @@ static void put_pixel_(Brush brush, i64 x, i64 y) { } void fill_rectangle_(Brush brush, f64 x, f64 y, f64 width, f64 height) { + if (width < EPSILON || height < EPSILON) + return; + f64 x0, y0, x1, y1; if (brush.scale.x < 0) { @@ -245,50 +253,50 @@ void fill_rectangle_(Brush brush, f64 x, f64 y, f64 width, f64 height) { brush.alpha = 1; if (i00 - 1 >= 0 && i00 - 1 < brush.buffer.width) { - brush.color.w = alpha * gamma_(kx0); + brush.color.w = gamma_(gamma_re_(alpha) * kx0); for (i64 j = j0; j < j1; ++j) put_pixel_(brush, i00 - 1, j); } if (i10 >= 0 && i10 < brush.buffer.width) { - brush.color.w = alpha * gamma_(kx1); + brush.color.w = gamma_(gamma_re_(alpha) * kx1); for (i64 j = j0; j < j1; ++j) put_pixel_(brush, i10, j); } if (j00 - 1 >= 0 && j00 - 1 < brush.buffer.height) { - brush.color.w = alpha * gamma_(ky0); + brush.color.w = gamma_(gamma_re_(alpha) * ky0); for (i64 i = i0; i < i1; ++i) put_pixel_(brush, i, j00 - 1); } if (j10 >= 0 && j10 < brush.buffer.height) { - brush.color.w = alpha * gamma_(ky1); + brush.color.w = gamma_(gamma_re_(alpha) * ky1); for (i64 i = i0; i < i1; ++i) put_pixel_(brush, i, j10); } if ( i00 - 1 >= 0 && i00 - 1 < brush.buffer.width && j00 - 1 >= 0 && j00 - 1 < brush.buffer.height) { - brush.color.w = alpha * gamma_(kx0 * ky0); + brush.color.w = gamma_(gamma_re_(alpha) * kx0 * ky0); put_pixel_(brush, i00 - 1, j00 - 1); } if ( i10 >= 0 && i10 < brush.buffer.width && j00 - 1 >= 0 && j00 - 1 < brush.buffer.height) { - brush.color.w = alpha * gamma_(kx1 * ky0); + brush.color.w = gamma_(gamma_re_(alpha) * kx1 * ky0); put_pixel_(brush, i10, j00 - 1); } if ( i00 - 1 >= 0 && i00 - 1 < brush.buffer.width && j10 >= 0 && j10 < brush.buffer.height) { - brush.color.w = alpha * gamma_(kx0 * ky1); + brush.color.w = gamma_(gamma_re_(alpha) * kx0 * ky1); put_pixel_(brush, i00 - 1, j10); } if ( i10 >= 0 && i10 < brush.buffer.width && j10 >= 0 && j10 < brush.buffer.height) { - brush.color.w = alpha * gamma_(kx1 * ky1); + brush.color.w = gamma_(gamma_re_(alpha) * kx1 * ky1); put_pixel_(brush, i10, j10); } } else { @@ -302,9 +310,18 @@ void fill_rectangle_(Brush brush, f64 x, f64 y, f64 width, f64 height) { if (j0 < 0) j0 = 0; if (j1 > brush.buffer.height) j1 = brush.buffer.height; - for (i64 j = j0; j < j1; ++j) - for (i64 i = i0; i < i1; ++i) - put_pixel_(brush, i, j); + 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); } } @@ -323,18 +340,34 @@ void fill_triangle_(Brush brush, 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)) + 1; - i64 j1 = (i64) ceil (max3_(y0, y1, y2)) + 1; + i64 i1 = (i64) ceil (max3_(x0, x1, x2)); + i64 j1 = (i64) ceil (max3_(y0, y1, y2)); + + if (j0 < 0) j0 = 0; + if (j1 >= brush.buffer.height) j1 = brush.buffer.height - 1; - 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; + for (i64 j = j0; j <= j1; ++j) { + i64 left = i1; + i64 right = i0; - for (i64 j = j0; j < j1; ++j) - for (i64 i = i0; i < i1; ++i) - if (triangle_contains(x0, y0, x1, y1, x2, y2, (f64) i, (f64) j)) - put_pixel_(brush, i, j); + for (i64 i = i0; i <= i1; ++i) + if (triangle_contains(x0, y0, x1, y1, x2, y2, (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)) { + right = i; + break; + } + + if (left < 0) left = 0; + if (right >= brush.buffer.width) right = brush.buffer.width - 1; + + for (i64 i = left; i <= right; ++i) + put_pixel_(brush, i, j); + } } static i64 char_column_offset_(c32 c, i64 column_index) { @@ -568,20 +601,20 @@ static Brush brush_defaults_(Brush b) { // ================================================================ -vec4_f32 vec4_from_vec3_f32(vec3_f32 v, f32 w) { - return (vec4_f32) { +vec3_f32 vec3_from_vec4_f32(vec4_f32 v) { + return (vec3_f32) { .x = v.x, .y = v.y, .z = v.z, - .w = w, }; } -vec3_f32 vec3_from_vec4_f32(vec4_f32 v) { - return (vec3_f32) { +vec4_f32 vec4_from_vec3_f32(vec3_f32 v, f32 w) { + return (vec4_f32) { .x = v.x, .y = v.y, .z = v.z, + .w = w, }; } @@ -807,13 +840,21 @@ b8 triangle_contains(f64 x0, f64 y0, f64 x1, f64 y1, f64 x2, f64 y2, f64 px, f64 // Z-components of cross-products // - f64 z0 = (x1 - x0) * (y2 - y0) - (x2 - x0) * (y1 - y0); - f64 z1 = (x2 - x1) * (y0 - y1) - (x0 - x1) * (y2 - y1); - f64 z2 = (x0 - x2) * (y1 - y2) - (x1 - x2) * (y0 - y2); + f64 x10 = x1 - x0; + f64 x21 = x2 - x1; + f64 x02 = x0 - x2; + + f64 y10 = y1 - y0; + f64 y21 = y2 - y1; + f64 y02 = y0 - y2; - f64 pz0 = (px - x0) * (y2 - y0) - (x2 - x0) * (py - y0); - f64 pz1 = (px - x1) * (y0 - y1) - (x0 - x1) * (py - y1); - f64 pz2 = (px - x2) * (y1 - y2) - (x1 - x2) * (py - y2); + f64 z0 = x02 * y10 - x10 * y02; + f64 z1 = x10 * y21 - x21 * y10; + f64 z2 = x21 * y02 - x02 * y21; + + f64 pz0 = x02 * (py - y0) - (px - x0) * y02; + f64 pz1 = x10 * (py - y1) - (px - x1) * y10; + f64 pz2 = x21 * (py - y2) - (px - x2) * y21; return same_sign_(z0, pz0) @@ -949,9 +990,6 @@ void draw_pixels(Brush brush, f64 x, f64 y, f64 width, f64 height, Pixel_Buffer } void fill_rectangle(Brush brush, f64 x, f64 y, f64 width, f64 height) { - if (width < EPSILON || height < EPSILON) - return; - fill_rectangle_(brush_defaults_(brush), x, y, width, height); } @@ -991,15 +1029,32 @@ void fill_ellipse(Brush brush, f64 x, f64 y, f64 width, f64 height) { 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 (j0 < 0) j0 = 0; + if (j1 >= brush.buffer.height) j1 = brush.buffer.height - 1; - for (i64 j = j0; j < j1; ++j) - for (i64 i = i0; i < i1; ++i) - if (ellipse_contains(x0, y0, x1 - x0, y1 - y0, (f64) i, (f64) j)) - put_pixel_(brush, i, j); + for (i64 j = j0; j <= j1; ++j) { + i64 left = i1; + i64 right = i0; + + for (i64 i = i0; i <= i1; ++i) + if (ellipse_contains(x0, y0, x1 - x0, y1 - y0, (f64) i, (f64) j)) { + left = i; + right = (i64) ceil(x0 + x1 - left); // symmetry + break; + } + + for (i64 i = right; i >= i0; --i) + if (ellipse_contains(x0, y0, x1 - x0, y1 - y0, (f64) i, (f64) j)) { + right = i; + break; + } + + if (left < 0) left = 0; + if (right >= brush.buffer.width) right = brush.buffer.width - 1; + + for (i64 i = left; i <= right; ++i) + put_pixel_(brush, i, j); + } } void fill_line(Brush brush, f64 x0, f64 y0, f64 x1, f64 y1, f64 width) { -- cgit v1.2.3