Browse Source

Make olivec_normalize_rect() preserve the original uncut range

rexim 3 years ago
parent
commit
8576120add
6 changed files with 72 additions and 72 deletions
  1. 57 62
      olive.c
  2. 15 10
      test.c
  3. BIN
      wasm/3d.wasm
  4. BIN
      wasm/squish.wasm
  5. BIN
      wasm/triangle.wasm
  6. BIN
      wasm/triangle3d.wasm

+ 57 - 62
olive.c

@@ -303,18 +303,31 @@ OLIVECDEF void olivec_triangle3(Olivec_Canvas oc, int x1, int y1, int x2, int y2
 OLIVECDEF void olivec_text(Olivec_Canvas oc, const char *text, int x, int y, Olivec_Font font, size_t size, uint32_t color);
 OLIVECDEF void olivec_text(Olivec_Canvas oc, const char *text, int x, int y, Olivec_Font font, size_t size, uint32_t color);
 OLIVECDEF void olivec_copy(Olivec_Canvas src, Olivec_Canvas dst, int x, int y, int w, int h);
 OLIVECDEF void olivec_copy(Olivec_Canvas src, Olivec_Canvas dst, int x, int y, int w, int h);
 
 
+typedef struct {
+    // Safe ranges to iterate over.
+    int x1, x2;
+    int y1, y2;
+
+    // Original uncut ranges some parts of which may be outside of the canvas boundaries.
+    int ox1, ox2;
+    int oy1, oy2;
+} Olivec_Normalized_Rect;
+
 // The point of this function is to produce two ranges x1..x2 and y1..y2 that are guaranteed to be safe to iterate over the canvas of size pixels_width by pixels_height without any boundary checks.
 // The point of this function is to produce two ranges x1..x2 and y1..y2 that are guaranteed to be safe to iterate over the canvas of size pixels_width by pixels_height without any boundary checks.
 //
 //
-// if (olivec_normalize_rect(x, y, w, h, WIDTH, HEIGHT, &x1, &y1, &x2, &y2)) {
-//     for (int x = x1; x <= x2; ++x) {
-//         for (int y = y1; y <= y2; ++y) {
+// Olivec_Normalized_Rect nr = {0};
+// if (olivec_normalize_rect(x, y, w, h, WIDTH, HEIGHT, &nr)) {
+//     for (int x = nr.x1; x <= nr.x2; ++x) {
+//         for (int y = nr.y1; y <= nr.y2; ++y) {
 //             OLIVEC_PIXEL(oc, x, y) = 0x69696969;
 //             OLIVEC_PIXEL(oc, x, y) = 0x69696969;
 //         }
 //         }
 //     }
 //     }
 // } else {
 // } else {
 //     // Rectangle is invisible cause it's completely out-of-bounds
 //     // Rectangle is invisible cause it's completely out-of-bounds
 // }
 // }
-OLIVECDEF bool olivec_normalize_rect(int x, int y, int w, int h, size_t pixels_width, size_t pixels_height, int *x1, int *x2, int *y1, int *y2);
+OLIVECDEF bool olivec_normalize_rect(int x, int y, int w, int h,
+                                     size_t canvas_width, size_t canvas_height,
+                                     Olivec_Normalized_Rect *nr);
 
 
 #endif // OLIVE_C_
 #endif // OLIVE_C_
 
 
@@ -332,44 +345,49 @@ OLIVECDEF Olivec_Canvas olivec_canvas(uint32_t *pixels, size_t width, size_t hei
 }
 }
 
 
 OLIVECDEF bool olivec_normalize_rect(int x, int y, int w, int h,
 OLIVECDEF bool olivec_normalize_rect(int x, int y, int w, int h,
-                                     size_t pixels_width, size_t pixels_height,
-                                     int *x1, int *x2, int *y1, int *y2)
+                                     size_t canvas_width, size_t canvas_height,
+                                     Olivec_Normalized_Rect *nr)
 {
 {
     // No need to render empty rectangle
     // No need to render empty rectangle
     if (w == 0) return false;
     if (w == 0) return false;
     if (h == 0) return false;
     if (h == 0) return false;
 
 
-    *x1 = x;
-    *y1 = y;
+    nr->ox1 = x;
+    nr->oy1 = y;
 
 
     // Convert the rectangle to 2-points representation
     // Convert the rectangle to 2-points representation
-    *x2 = *x1 + OLIVEC_SIGN(int, w)*(OLIVEC_ABS(int, w) - 1);
-    if (*x1 > *x2) OLIVEC_SWAP(int, *x1, *x2);
-    *y2 = *y1 + OLIVEC_SIGN(int, h)*(OLIVEC_ABS(int, h) - 1);
-    if (*y1 > *y2) OLIVEC_SWAP(int, *y1, *y2);
+    nr->ox2 = nr->ox1 + OLIVEC_SIGN(int, w)*(OLIVEC_ABS(int, w) - 1);
+    if (nr->ox1 > nr->ox2) OLIVEC_SWAP(int, nr->ox1, nr->ox2);
+    nr->oy2 = nr->oy1 + OLIVEC_SIGN(int, h)*(OLIVEC_ABS(int, h) - 1);
+    if (nr->oy1 > nr->oy2) OLIVEC_SWAP(int, nr->oy1, nr->oy2);
 
 
     // Cull out invisible rectangle
     // Cull out invisible rectangle
-    if (*x1 >= (int) pixels_width) return false;
-    if (*x2 < 0) return false;
-    if (*y1 >= (int) pixels_height) return false;
-    if (*y2 < 0) return false;
+    if (nr->ox1 >= (int) canvas_width) return false;
+    if (nr->ox2 < 0) return false;
+    if (nr->oy1 >= (int) canvas_height) return false;
+    if (nr->oy2 < 0) return false;
+
+    nr->x1 = nr->ox1;
+    nr->y1 = nr->oy1;
+    nr->x2 = nr->ox2;
+    nr->y2 = nr->oy2;
 
 
     // Clamp the rectangle to the boundaries
     // Clamp the rectangle to the boundaries
-    if (*x1 < 0) *x1 = 0;
-    if (*x2 >= (int) pixels_width) *x2 = (int) pixels_width - 1;
-    if (*y1 < 0) *y1 = 0;
-    if (*y2 >= (int) pixels_height) *y2 = (int) pixels_height - 1;
+    if (nr->x1 < 0) nr->x1 = 0;
+    if (nr->x2 >= (int) canvas_width) nr->x2 = (int) canvas_width - 1;
+    if (nr->y1 < 0) nr->y1 = 0;
+    if (nr->y2 >= (int) canvas_height) nr->y2 = (int) canvas_height - 1;
 
 
     return true;
     return true;
 }
 }
 
 
 OLIVECDEF Olivec_Canvas olivec_subcanvas(Olivec_Canvas oc, int x, int y, int w, int h)
 OLIVECDEF Olivec_Canvas olivec_subcanvas(Olivec_Canvas oc, int x, int y, int w, int h)
 {
 {
-    int x1, x2, y1, y2;
-    if (!olivec_normalize_rect(x, y, w, h, oc.width, oc.height, &x1, &x2, &y1, &y2)) return OLIVEC_CANVAS_NULL;
-    oc.pixels = &OLIVEC_PIXEL(oc, x1, y1);
-    oc.width = x2 - x1 + 1;
-    oc.height = y2 - y1 + 1;
+    Olivec_Normalized_Rect nr = {0};
+    if (!olivec_normalize_rect(x, y, w, h, oc.width, oc.height, &nr)) return OLIVEC_CANVAS_NULL;
+    oc.pixels = &OLIVEC_PIXEL(oc, nr.x1, nr.y1);
+    oc.width = nr.x2 - nr.x1 + 1;
+    oc.height = nr.y2 - nr.y1 + 1;
     return oc;
     return oc;
 }
 }
 
 
@@ -411,10 +429,10 @@ OLIVECDEF void olivec_fill(Olivec_Canvas oc, uint32_t color)
 
 
 OLIVECDEF void olivec_rect(Olivec_Canvas oc, int x, int y, int w, int h, uint32_t color)
 OLIVECDEF void olivec_rect(Olivec_Canvas oc, int x, int y, int w, int h, uint32_t color)
 {
 {
-    int x1, x2, y1, y2;
-    if (!olivec_normalize_rect(x, y, w, h, oc.width, oc.height, &x1, &x2, &y1, &y2)) return;
-    for (int x = x1; x <= x2; ++x) {
-        for (int y = y1; y <= y2; ++y) {
+    Olivec_Normalized_Rect nr = {0};
+    if (!olivec_normalize_rect(x, y, w, h, oc.width, oc.height, &nr)) return;
+    for (int x = nr.x1; x <= nr.x2; ++x) {
+        for (int y = nr.y1; y <= nr.y2; ++y) {
             olivec_blend_color(&OLIVEC_PIXEL(oc, x, y), color);
             olivec_blend_color(&OLIVEC_PIXEL(oc, x, y), color);
         }
         }
     }
     }
@@ -440,12 +458,12 @@ OLIVECDEF void olivec_frame(Olivec_Canvas oc, int x, int y, int w, int h, size_t
 
 
 OLIVECDEF void olivec_circle(Olivec_Canvas oc, int cx, int cy, int r, uint32_t color)
 OLIVECDEF void olivec_circle(Olivec_Canvas oc, int cx, int cy, int r, uint32_t color)
 {
 {
-    int x1, y1, x2, y2;
+    Olivec_Normalized_Rect nr = {0};
     int r1 = r + OLIVEC_SIGN(int, r);
     int r1 = r + OLIVEC_SIGN(int, r);
-    if (!olivec_normalize_rect(cx - r1, cy - r1, 2*r1, 2*r1, oc.width, oc.height, &x1, &x2, &y1, &y2)) return;
+    if (!olivec_normalize_rect(cx - r1, cy - r1, 2*r1, 2*r1, oc.width, oc.height, &nr)) return;
 
 
-    for (int y = y1; y <= y2; ++y) {
-        for (int x = x1; x <= x2; ++x) {
+    for (int y = nr.y1; y <= nr.y2; ++y) {
+        for (int x = nr.x1; x <= nr.x2; ++x) {
             int count = 0;
             int count = 0;
             for (int sox = 0; sox < OLIVEC_AA_RES; ++sox) {
             for (int sox = 0; sox < OLIVEC_AA_RES; ++sox) {
                 for (int soy = 0; soy < OLIVEC_AA_RES; ++soy) {
                 for (int soy = 0; soy < OLIVEC_AA_RES; ++soy) {
@@ -711,36 +729,13 @@ OLIVECDEF void olivec_copy(Olivec_Canvas src, Olivec_Canvas dst, int x, int y, i
     if (src.width == 0) return;
     if (src.width == 0) return;
     if (src.height == 0) return;
     if (src.height == 0) return;
 
 
-    // No need to render empty rectangle
-    if (w == 0) return;
-    if (h == 0) return;
+    Olivec_Normalized_Rect nr = {0};
+    if (!olivec_normalize_rect(x, y, w, h, dst.width, dst.height, &nr)) return;
 
 
-    int ox1 = x;
-    int oy1 = y;
-
-    // Convert the rectangle to 2-points representation
-    int ox2 = ox1 + OLIVEC_SIGN(int, w)*(OLIVEC_ABS(int, w) - 1);
-    if (ox1 > ox2) OLIVEC_SWAP(int, ox1, ox2);
-    int oy2 = oy1 + OLIVEC_SIGN(int, h)*(OLIVEC_ABS(int, h) - 1);
-    if (oy1 > oy2) OLIVEC_SWAP(int, oy1, oy2);
-
-    // Cull out invisible rectangle
-    if (ox1 >= (int) dst.width) return;
-    if (ox2 < 0) return;
-    if (oy1 >= (int) dst.height) return;
-    if (oy2 < 0) return;
-
-    // Clamp the rectangle to the boundaries
-    int x1 = ox1, x2 = ox2, y1 = oy1, y2 = oy2;
-    if (x1 < 0) x1 = 0;
-    if (x2 >= (int) dst.width) x2 = (int) dst.width - 1;
-    if (y1 < 0) y1 = 0;
-    if (y2 >= (int) dst.height) y2 = (int) dst.height - 1;
-
-    int xa = ox1; if (w < 0) xa = ox2;
-    int ya = oy1; if (h < 0) ya = oy2;
-    for (int y = y1; y <= y2; ++y) {
-        for (int x = x1; x <= x2; ++x) {
+    int xa = nr.ox1; if (w < 0) xa = nr.ox2;
+    int ya = nr.oy1; if (h < 0) ya = nr.oy2;
+    for (int y = nr.y1; y <= nr.y2; ++y) {
+        for (int x = nr.x1; x <= nr.x2; ++x) {
             size_t nx = (x - xa)*((int) src.width)/w;
             size_t nx = (x - xa)*((int) src.width)/w;
             size_t ny = (y - ya)*((int) src.height)/h;
             size_t ny = (y - ya)*((int) src.height)/h;
             olivec_blend_color(&OLIVEC_PIXEL(dst, x, y), OLIVEC_PIXEL(src, nx, ny));
             olivec_blend_color(&OLIVEC_PIXEL(dst, x, y), OLIVEC_PIXEL(src, nx, ny));

+ 15 - 10
test.c

@@ -133,6 +133,9 @@ static inline size_t max_size(size_t a, size_t b)
 
 
 Replay_Result run_test_case(const char *program_path, const Test_Case *tc)
 Replay_Result run_test_case(const char *program_path, const Test_Case *tc)
 {
 {
+    printf("%s:", tc->id);
+    fflush(stdout);
+
     const char *expected_file_path = tc->expected_file_path;
     const char *expected_file_path = tc->expected_file_path;
     const char *actual_file_path = tc->actual_file_path;
     const char *actual_file_path = tc->actual_file_path;
     const char *diff_file_path = tc->diff_file_path;
     const char *diff_file_path = tc->diff_file_path;
@@ -141,9 +144,10 @@ Replay_Result run_test_case(const char *program_path, const Test_Case *tc)
 
 
     Olivec_Canvas expected_canvas;
     Olivec_Canvas expected_canvas;
     if (!canvas_stbi_load(expected_file_path, &expected_canvas)) {
     if (!canvas_stbi_load(expected_file_path, &expected_canvas)) {
-        fprintf(stderr, "%s: ERROR: could not read %s: %s\n", tc->id, expected_file_path, stbi_failure_reason());
+        fprintf(stderr, "\n");
+        fprintf(stderr, "  ERROR: could not read %s: %s\n", expected_file_path, stbi_failure_reason());
         if (errno == ENOENT) {
         if (errno == ENOENT) {
-            fprintf(stderr, "%s: HINT: Consider running `$ %s update %s` to create it\n", tc->id, program_path, tc->id);
+            fprintf(stderr, "  HINT: Consider running `$ %s update %s` to create it\n", program_path, tc->id);
         }
         }
         return(REPLAY_ERRORED);
         return(REPLAY_ERRORED);
     }
     }
@@ -174,26 +178,27 @@ Replay_Result run_test_case(const char *program_path, const Test_Case *tc)
     }
     }
 
 
     if (failed) {
     if (failed) {
+        fprintf(stderr, "\n");
 
 
         if (!canvas_stbi_save(actual_canvas, actual_file_path)) {
         if (!canvas_stbi_save(actual_canvas, actual_file_path)) {
-            fprintf(stderr, "ERROR: could not write image file with actual pixels %s: %s\n", actual_file_path, strerror(errno));
+            fprintf(stderr, "  ERROR: could not write image file with actual pixels %s: %s\n", actual_file_path, strerror(errno));
             return(REPLAY_ERRORED);
             return(REPLAY_ERRORED);
         }
         }
 
 
         if (!canvas_stbi_save(diff_canvas, diff_file_path)) {
         if (!canvas_stbi_save(diff_canvas, diff_file_path)) {
-            fprintf(stderr, "ERROR: could not wrilte diff image file %s: %s\n", diff_file_path, strerror(errno));
+            fprintf(stderr, "  ERROR: could not wrilte diff image file %s: %s\n", diff_file_path, strerror(errno));
             return(REPLAY_ERRORED);
             return(REPLAY_ERRORED);
         }
         }
 
 
-        fprintf(stderr, "%s: TEST FAILURE: unexpected pixels in generated image\n", tc->id);
-        fprintf(stderr, "%s:   Expected: %s\n", tc->id, expected_file_path);
-        fprintf(stderr, "%s:   Actual:   %s\n", tc->id, actual_file_path);
-        fprintf(stderr, "%s:   Diff:     %s\n", tc->id, diff_file_path);
-        fprintf(stderr, "%s: HINT: If this behaviour is intentional confirm that by updating the image with `$ %s update`\n", tc->id, program_path);
+        fprintf(stderr, "  TEST FAILURE: unexpected pixels in generated image\n");
+        fprintf(stderr, "    Expected: %s\n", expected_file_path);
+        fprintf(stderr, "    Actual:   %s\n", actual_file_path);
+        fprintf(stderr, "    Diff:     %s\n", diff_file_path);
+        fprintf(stderr, "  HINT: If this behaviour is intentional confirm that by updating the image with `$ %s update`\n", program_path);
         return(REPLAY_FAILED);
         return(REPLAY_FAILED);
     }
     }
 
 
-    printf("%s: OK\n", tc->id);
+    printf(" OK\n");
 
 
     return(REPLAY_PASSED);
     return(REPLAY_PASSED);
 }
 }

BIN
wasm/3d.wasm


BIN
wasm/squish.wasm


BIN
wasm/triangle.wasm


BIN
wasm/triangle3d.wasm