summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitya Selivanov <automainint@guattari.tech>2025-04-25 10:12:37 +0200
committerMitya Selivanov <automainint@guattari.tech>2025-04-25 10:12:37 +0200
commit67e3cb4f67692491be35899414f099d43bc975d6 (patch)
tree15c77a48d2a8db63a31b816a5c51a76dbb6d7337
parent3f37db0647cb31955c8ad271f747c8e1ee5d2124 (diff)
downloadreduced_system_layer-67e3cb4f67692491be35899414f099d43bc975d6.zip
Add graphics tests; Fix triangles rendering
-rw-r--r--graphics.c238
1 files changed, 233 insertions, 5 deletions
diff --git a/graphics.c b/graphics.c
index a962ba6..5e9790e 100644
--- a/graphics.c
+++ b/graphics.c
@@ -413,11 +413,23 @@ void fill_triangles_to_buffer(Pixel_Buffer dst, vec4_f32 color, vec2 position, v
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, })) {
+ for (i64 k = 0; k < num_triangles; ++k) {
+ vec2 triangle[3] = {
+ vertices[3 * k],
+ vertices[3 * k + 1],
+ vertices[3 * k + 2],
+ };
+
+ for (i64 r = 0; r < 3; ++r) {
+ triangle[r].x = position.x + triangle[r].x * scale. x;
+ triangle[r].y = position.y + triangle[r].y * scale.y;
+ }
+
+ if (hit_triangle(triangle, (vec2) { (f64) i, (f64) j, })) {
put_pixel_(dst.pixels + j * dst.stride + i, color);
break;
}
+ }
PROFILER_end(PROFILE_FILL_TRIANGLES);
}
@@ -493,14 +505,14 @@ void fill_ellipse_to_buffer(Pixel_Buffer dst, vec4_f32 color, Box area) {
f64 cy = area.y + half_h;
for (i64 j = j0; j <= j1; ++j) {
- f64 ry = (j - cy) * inv_half_h;
+ f64 ry = (j - cy + 0.5) * inv_half_h;
if (ry > 1.0 - EPSILON || ry < -1.0 + EPSILON)
continue;
f64 dx = half_w * sqrt(1.0 - ry * ry);
- i64 left = (i64) ceil (cx - dx - EPSILON);
- i64 right = (i64) floor(cx + dx + EPSILON);
+ i64 left = (i64) floor(cx - dx + 0.5);
+ i64 right = (i64) floor(cx + dx - 0.5);
if (left < 0) left = 0;
if (right >= dst.width) right = dst.width - 1;
@@ -2359,6 +2371,222 @@ TEST("rectangle aliasing") {
REQUIRE(ok);
}
+TEST("triangle") {
+ i64 w = 10;
+ i64 h = 10;
+
+ vec4_f32 pixels[100] = {0};
+
+ fill_triangle_to_buffer(
+ (Pixel_Buffer) { .width = w, .height = h, .stride = w, .pixels = pixels, },
+ (vec4_f32) { 1.0f, 1.0f, 1.0f, 1.0f },
+ (vec2[3]) {
+ { 1.0, 1.0 },
+ { 5.9, 1.0 },
+ { 1.0, 5.9 },
+ }
+ );
+
+ b8 expect_bits[100] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 1, 1, 0, 0, 0, 0,
+ 0, 1, 1, 1, 1, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+
+ b8 ok = 1;
+
+ for (i64 i = 0; i < w * h; ++i) {
+ if (expect_bits[i] != (pixels[i].x > 0.5) ||
+ expect_bits[i] != (pixels[i].y > 0.5) ||
+ expect_bits[i] != (pixels[i].z > 0.5) ||
+ expect_bits[i] != (pixels[i].w > 0.5)) {
+ ok = 0;
+ break;
+ }
+ }
+
+ REQUIRE(ok);
+}
+
+TEST("triangles") {
+ i64 w = 10;
+ i64 h = 10;
+
+ vec4_f32 pixels[100] = {0};
+
+ fill_triangles_to_buffer(
+ (Pixel_Buffer) { .width = w, .height = h, .stride = w, .pixels = pixels, },
+ (vec4_f32) { 1.0f, 1.0f, 1.0f, 1.0f },
+ (vec2) { 1.0, 1.0 },
+ (vec2) { 1.0, 1.0 },
+ 2,
+ (vec2[6]) {
+ { 0.0, 0.0 }, { 3.1, 0.0 }, { 0.0, 3.1 },
+ { 4.1, 0.9 }, { 0.9, 4.1 }, { 4.1, 4.1 },
+ }
+ );
+
+ b8 expect_bits[100] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 1, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 1, 0, 0, 0, 0,
+ 0, 1, 1, 0, 1, 1, 0, 0, 0, 0,
+ 0, 1, 0, 1, 1, 1, 0, 0, 0, 0,
+ 0, 0, 1, 1, 1, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+
+ b8 ok = 1;
+
+ for (i64 i = 0; i < w * h; ++i) {
+ if (expect_bits[i] != (pixels[i].x > 0.5) ||
+ expect_bits[i] != (pixels[i].y > 0.5) ||
+ expect_bits[i] != (pixels[i].z > 0.5) ||
+ expect_bits[i] != (pixels[i].w > 0.5)) {
+ ok = 0;
+ break;
+ }
+ }
+
+ REQUIRE(ok);
+}
+
+TEST("quad") {
+ i64 w = 10;
+ i64 h = 10;
+
+ vec4_f32 pixels[100] = {0};
+
+ fill_quad_to_buffer(
+ (Pixel_Buffer) { .width = w, .height = h, .stride = w, .pixels = pixels, },
+ (vec4_f32) { 1.0f, 1.0f, 1.0f, 1.0f },
+ (vec2[4]) {
+ { 4.0, 0.9 },
+ { 7.1, 4.0 },
+ { 4.0, 7.1 },
+ { 0.9, 4.0 },
+ }
+ );
+
+ b8 expect_bits[100] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 1, 0, 0, 0, 0,
+ 0, 0, 1, 1, 1, 1, 1, 0, 0, 0,
+ 0, 1, 1, 1, 1, 1, 1, 1, 0, 0,
+ 0, 0, 1, 1, 1, 1, 1, 0, 0, 0,
+ 0, 0, 0, 1, 1, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+
+ b8 ok = 1;
+
+ for (i64 i = 0; i < w * h; ++i) {
+ if (expect_bits[i] != (pixels[i].x > 0.5) ||
+ expect_bits[i] != (pixels[i].y > 0.5) ||
+ expect_bits[i] != (pixels[i].z > 0.5) ||
+ expect_bits[i] != (pixels[i].w > 0.5)) {
+ ok = 0;
+ break;
+ }
+ }
+
+ REQUIRE(ok);
+}
+
+TEST("ellipse") {
+ i64 w = 10;
+ i64 h = 10;
+
+ vec4_f32 pixels[100] = {0};
+
+ fill_ellipse_to_buffer(
+ (Pixel_Buffer) { .width = w, .height = h, .stride = w, .pixels = pixels, },
+ (vec4_f32) { 1.0f, 1.0f, 1.0f, 1.0f },
+ (Box) { 0.9, 0.9, 9.2, 9.2 }
+ );
+
+ b8 expect_bits[100] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
+ 0, 0, 1, 1, 1, 1, 1, 1, 1, 0,
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 0, 1, 1, 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
+ };
+
+ b8 ok = 1;
+
+ for (i64 i = 0; i < w * h; ++i) {
+ if (expect_bits[i] != (pixels[i].x > 0.5) ||
+ expect_bits[i] != (pixels[i].y > 0.5) ||
+ expect_bits[i] != (pixels[i].z > 0.5) ||
+ expect_bits[i] != (pixels[i].w > 0.5)) {
+ ok = 0;
+ break;
+ }
+ }
+
+ REQUIRE(ok);
+}
+
+TEST("line") {
+ i64 w = 10;
+ i64 h = 10;
+
+ vec4_f32 pixels[100] = {0};
+
+ fill_line_to_buffer(
+ (Pixel_Buffer) { .width = w, .height = h, .stride = w, .pixels = pixels, },
+ (vec4_f32) { 1.0f, 1.0f, 1.0f, 1.0f },
+ (vec2[2]) { { 1.0, 1.0 }, { 8.0, 3.0 }, },
+ 1.0
+ );
+
+ b8 expect_bits[100] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+
+ b8 ok = 1;
+
+ for (i64 i = 0; i < w * h; ++i) {
+ if (expect_bits[i] != (pixels[i].x > 0.5) ||
+ expect_bits[i] != (pixels[i].y > 0.5) ||
+ expect_bits[i] != (pixels[i].z > 0.5) ||
+ expect_bits[i] != (pixels[i].w > 0.5)) {
+ ok = 0;
+ break;
+ }
+ }
+
+ REQUIRE(ok);
+}
+
TEST("text letter A") {
i64 w = 10;
i64 h = 10;