Browse Source

Move boundary checks outside of the loops in rect and circle functions

rexim 3 years ago
parent
commit
dd0d49f20f
1 changed files with 55 additions and 31 deletions
  1. 55 31
      olive.c

+ 55 - 31
olive.c

@@ -3,6 +3,7 @@
 
 #include <stddef.h>
 #include <stdint.h>
+#include <stdbool.h>
 
 #define OLIVEC_SWAP(T, a, b) do { T t = a; a = b; b = t; } while (0)
 #define OLIVEC_SIGN(T, x) ((T)((x) > 0) - (T)((x) < 0))
@@ -15,23 +16,55 @@ void olivec_fill(uint32_t *pixels, size_t width, size_t height, uint32_t color)
     }
 }
 
+// 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 (itn y = y1; y <= y2; ++y) {
+//             pixels[y*pixels_width + x] = 0x69696969;
+//         }
+//     }
+// } else {
+//     // Rectangle is invisible cause it's completely out-of-bounds
+// }
+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)
+{
+    *x1 = x;
+    *y1 = y;
+
+    // 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);
+
+    // 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;
+
+    // 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;
+
+    return true;
+}
+
 void olivec_fill_rect(uint32_t *pixels, size_t pixels_width, size_t pixels_height,
-                      int x1, int y1, int w, int h,
+                      int x, int y, int w, int h,
                       uint32_t color)
 {
-    int x2 = x1 + OLIVEC_SIGN(int, w)*(OLIVEC_ABS(int, w) - 1);
-    if (x1 > x2) OLIVEC_SWAP(int, x1, x2);
-    int y2 = y1 + OLIVEC_SIGN(int, h)*(OLIVEC_ABS(int, h) - 1);
-    if (y1 > y2) OLIVEC_SWAP(int, y1, y2);
+    int x1, y1, x2, y2;
+    if (!olivec_normalize_rect(x, y, w, h, pixels_width, pixels_height, &x1, &x2, &y1, &y2)) return;
 
     for (int y = y1; y <= y2; ++y) {
-        // TODO: move boundary checks out of the loops in olivec_fill_rect
-        if (0 <= y && y < (int) pixels_height) {
-            for (int x = x1; x <= x2; ++x) {
-                if (0 <= x && x < (int) pixels_width) {
-                    pixels[y*pixels_width + x] = color;
-                }
-            }
+        for (int x = x1; x <= x2; ++x) {
+            pixels[y*pixels_width + x] = color;
         }
     }
 }
@@ -40,27 +73,16 @@ void olivec_fill_circle(uint32_t *pixels, size_t pixels_width, size_t pixels_hei
                         int cx, int cy, int r,
                         uint32_t color)
 {
-    if (r == 0) return;
-
-    int x1 = cx - r;
-    int x2 = cx + r;
-    if (x1 > x2) OLIVEC_SWAP(int, x1, x2);
-
-    int y1 = cy - r;
-    int y2 = cy + r;
-    if (y1 > y2) OLIVEC_SWAP(int, y1, y2);
+    int x1, y1, x2, y2;
+    int r1 = r + OLIVEC_SIGN(int, r);
+    if (!olivec_normalize_rect(cx - r1, cy - r1, 2*r1, 2*r1, pixels_width, pixels_height, &x1, &x2, &y1, &y2)) return;
 
     for (int y = y1; y <= y2; ++y) {
-        // TODO: move boundary checks out of the loops in olivec_fill_circle
-        if (0 <= y && y < (int) pixels_height) {
-            for (int x = x1; x <= x2; ++x) {
-                if (0 <= x && x < (int) pixels_width) {
-                    int dx = x - cx;
-                    int dy = y - cy;
-                    if (dx*dx + dy*dy <= r*r) {
-                        pixels[y*pixels_width + x] = color;
-                    }
-                }
+        for (int x = x1; x <= x2; ++x) {
+            int dx = x - cx;
+            int dy = y - cy;
+            if (dx*dx + dy*dy <= r*r) {
+                pixels[y*pixels_width + x] = color;
             }
         }
     }
@@ -80,6 +102,7 @@ void olivec_draw_line(uint32_t *pixels, size_t pixels_width, size_t pixels_heigh
 
         if (x1 > x2) OLIVEC_SWAP(int, x1, x2);
         for (int x = x1; x <= x2; ++x) {
+            // TODO: move boundary checks out side of the loops in olivec_draw_line
             if (0 <= x && x < (int) pixels_width) {
                 int sy1 = dy*x/dx + c;
                 int sy2 = dy*(x + 1)/dx + c;
@@ -131,6 +154,7 @@ void olivec_fill_triangle(uint32_t *pixels, size_t width, size_t height,
     int dy13 = y3 - y1;
 
     for (int y = y1; y <= y2; ++y) {
+        // TODO: move boundary checks outside of loops in olivec_fill_triangle
         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;