Browse Source

Implement olivec_fill_triangle()

rexim 3 years ago
parent
commit
633c657dbe
4 changed files with 95 additions and 0 deletions
  1. 66 0
      olive.c
  2. 29 0
      test.c
  3. BIN
      test/test_draw_line.png
  4. BIN
      test/test_fill_triangle.png

+ 66 - 0
olive.c

@@ -105,6 +105,72 @@ void olivec_draw_line(uint32_t *pixels, size_t pixels_width, size_t pixels_heigh
     }
     }
 }
 }
 
 
+void olivec_sort_triangle_points_by_y(int *x1, int *y1,
+                                      int *x2, int *y2,
+                                      int *x3, int *y3)
+{
+
+    if (*y1 > *y2) {
+        OLIVEC_SWAP(int, *x1, *x2);
+        OLIVEC_SWAP(int, *y1, *y2);
+    }
+
+    if (*y2 > *y3) {
+        OLIVEC_SWAP(int, *x2, *x3);
+        OLIVEC_SWAP(int, *y2, *y3);
+    }
+
+    if (*y1 > *y2) {
+        OLIVEC_SWAP(int, *x1, *x2);
+        OLIVEC_SWAP(int, *y1, *y2);
+    }
+}
+
+void olivec_fill_triangle(uint32_t *pixels, size_t width, size_t height,
+                          int x1, int y1,
+                          int x2, int y2,
+                          int x3, int y3,
+                          uint32_t color)
+{
+    olivec_sort_triangle_points_by_y(&x1, &y1, &x2, &y2, &x3, &y3);
+
+    int dx12 = x2 - x1;
+    int dy12 = y2 - y1;
+    int dx13 = x3 - x1;
+    int dy13 = y3 - y1;
+
+    for (int y = y1; y <= y2; ++y) {
+        if (0 <= y && (size_t) y < height) {
+            int s1 = dy12 != 0 ? (y - y1)*dx12/dy12 + x1 : x1;
+            int s2 = dy13 != 0 ? (y - y1)*dx13/dy13 + x1 : x1;
+            if (s1 > s2) OLIVEC_SWAP(int, s1, s2);
+            for (int x = s1; x <= s2; ++x) {
+                if (0 <= x && (size_t) x < width) {
+                    pixels[y*width + x] = color;
+                }
+            }
+        }
+    }
+
+    int dx32 = x2 - x3;
+    int dy32 = y2 - y3;
+    int dx31 = x1 - x3;
+    int dy31 = y1 - y3;
+
+    for (int y = y2; y <= y3; ++y) {
+        if (0 <= y && (size_t) y < height) {
+            int s1 = dy32 != 0 ? (y - y3)*dx32/dy32 + x3 : x3;
+            int s2 = dy31 != 0 ? (y - y3)*dx31/dy31 + x3 : x3;
+            if (s1 > s2) OLIVEC_SWAP(int, s1, s2);
+            for (int x = s1; x <= s2; ++x) {
+                if (0 <= x && (size_t) x < width) {
+                    pixels[y*width + x] = color;
+                }
+            }
+        }
+    }
+}
+
 // TODO: supersampling for circles and lines
 // TODO: supersampling for circles and lines
 // TODO: olivec_fill_triangle
 // TODO: olivec_fill_triangle
 // TODO: olivec_draw_circle
 // TODO: olivec_draw_circle

+ 29 - 0
test.c

@@ -107,6 +107,7 @@ bool replay_test_case(const char *program_path, const char *file_path, const cha
             }
             }
         }
         }
 
 
+        // TODO: save the actual image along with the diff
         if (failed) {
         if (failed) {
             fprintf(stderr, "%s: TEST FAILURE: unexpected pixels in generated image\n", file_path);
             fprintf(stderr, "%s: TEST FAILURE: unexpected pixels in generated image\n", file_path);
             if (!stbi_write_png(failure_file_path, WIDTH, HEIGHT, 4, pixels, sizeof(uint32_t)*WIDTH)) {
             if (!stbi_write_png(failure_file_path, WIDTH, HEIGHT, 4, pixels, sizeof(uint32_t)*WIDTH)) {
@@ -160,12 +161,40 @@ void test_draw_line(void)
     olivec_fill(pixels, WIDTH, HEIGHT, BACKGROUND_COLOR);
     olivec_fill(pixels, WIDTH, HEIGHT, BACKGROUND_COLOR);
     olivec_draw_line(pixels, WIDTH, HEIGHT, 0, 0, WIDTH, HEIGHT, RED_COLOR);
     olivec_draw_line(pixels, WIDTH, HEIGHT, 0, 0, WIDTH, HEIGHT, RED_COLOR);
     olivec_draw_line(pixels, WIDTH, HEIGHT, WIDTH, 0, 0, HEIGHT, BLUE_COLOR);
     olivec_draw_line(pixels, WIDTH, HEIGHT, WIDTH, 0, 0, HEIGHT, BLUE_COLOR);
+    olivec_draw_line(pixels, WIDTH, HEIGHT, WIDTH/2, 0, WIDTH/2, HEIGHT, GREEN_COLOR);
+}
+
+void test_fill_triangle(void)
+{
+    olivec_fill(pixels, WIDTH, HEIGHT, BACKGROUND_COLOR);
+
+    {
+        int x1 = WIDTH/2, y1 = HEIGHT/8;
+        int x2 = WIDTH/8, y2 = HEIGHT/2;
+        int x3 = WIDTH*7/8, y3 = HEIGHT*7/8;
+        olivec_fill_triangle(pixels, WIDTH, HEIGHT, x1, y1, x2, y2, x3, y3, RED_COLOR);
+    }
+
+    {
+        int x1 = WIDTH/2, y1 = HEIGHT*2/8;
+        int x2 = WIDTH*2/8, y2 = HEIGHT/2;
+        int x3 = WIDTH*6/8, y3 = HEIGHT/2;
+        olivec_fill_triangle(pixels, WIDTH, HEIGHT, x1, y1, x2, y2, x3, y3, GREEN_COLOR);
+    }
+
+    {
+        int x1 = WIDTH/8, y1 = HEIGHT/8;
+        int x2 = WIDTH/8, y2 = HEIGHT*3/8;
+        int x3 = WIDTH*3/8, y3 = HEIGHT*3/8;
+        olivec_fill_triangle(pixels, WIDTH, HEIGHT, x1, y1, x2, y2, x3, y3, BLUE_COLOR);
+    }
 }
 }
 
 
 Test_Case test_cases[] = {
 Test_Case test_cases[] = {
     DEFINE_TEST_CASE(test_fill_rect),
     DEFINE_TEST_CASE(test_fill_rect),
     DEFINE_TEST_CASE(test_fill_circle),
     DEFINE_TEST_CASE(test_fill_circle),
     DEFINE_TEST_CASE(test_draw_line),
     DEFINE_TEST_CASE(test_draw_line),
+    DEFINE_TEST_CASE(test_fill_triangle),
 };
 };
 #define TEST_CASES_COUNT (sizeof(test_cases)/sizeof(test_cases[0]))
 #define TEST_CASES_COUNT (sizeof(test_cases)/sizeof(test_cases[0]))
 
 

BIN
test/test_draw_line.png


BIN
test/test_fill_triangle.png