Implement generic printing and matrix/vector routines using new array->dim[]
authorNick Downing <nick@ndcode.org>
Tue, 19 Apr 2022 06:17:03 +0000 (16:17 +1000)
committerNick Downing <nick@ndcode.org>
Tue, 19 Apr 2022 06:17:03 +0000 (16:17 +1000)
array.h
render.c

diff --git a/array.h b/array.h
index 73493a4..54602b8 100644 (file)
--- a/array.h
+++ b/array.h
@@ -22,8 +22,8 @@ struct array {
 // which already has the strides available, so it doesn't calculate them
 static inline __attribute__((always_inline)) struct array *array_new(
   int n_dims,
-  size_t *dim,
-  size_t *stride
+  const size_t *dim,
+  const size_t *stride
 ) {
 #ifndef NDEBUG
   {
@@ -300,14 +300,14 @@ static inline __attribute__((always_inline)) struct array *array_new4_zero(
 }
 
 static inline __attribute__((always_inline)) void *array_index0(
-  struct array *self
+  const struct array *self
 ) {
   assert(self->n_dims >= 0);
   return self->data;
 }
 
 static inline __attribute__((always_inline)) void *array_index1(
-  struct array *self,
+  const struct array *self,
   size_t i0
 ) {
   assert(self->n_dims >= 1);
@@ -318,7 +318,7 @@ static inline __attribute__((always_inline)) void *array_index1(
 }
 
 static inline __attribute__((always_inline)) void *array_index2(
-  struct array *self,
+  const struct array *self,
   size_t i0,
   size_t i1
 ) {
@@ -332,7 +332,7 @@ static inline __attribute__((always_inline)) void *array_index2(
 }
 
 static inline __attribute__((always_inline)) void *array_index3(
-  struct array *self,
+  const struct array *self,
   size_t i0,
   size_t i1,
   size_t i2
@@ -349,7 +349,7 @@ static inline __attribute__((always_inline)) void *array_index3(
 }
 
 static inline __attribute__((always_inline)) void *array_index4(
-  struct array *self,
+  const struct array *self,
   size_t i0,
   size_t i1,
   size_t i2,
@@ -369,14 +369,14 @@ static inline __attribute__((always_inline)) void *array_index4(
 }
 
 static inline __attribute__((always_inline)) void array_get0(
-  struct array *self,
+  const struct array *self,
   void *dest
 ) {
   memcpy(dest, array_index0(self), self->stride[0]);
 }
 
 static inline __attribute__((always_inline)) void array_get1(
-  struct array *self,
+  const struct array *self,
   void *dest,
   size_t i0
 ) {
@@ -384,7 +384,7 @@ static inline __attribute__((always_inline)) void array_get1(
 }
 
 static inline __attribute__((always_inline)) void array_get2(
-  struct array *self,
+  const struct array *self,
   void *dest,
   size_t i0,
   size_t i1
@@ -393,7 +393,7 @@ static inline __attribute__((always_inline)) void array_get2(
 }
 
 static inline __attribute__((always_inline)) void array_get3(
-  struct array *self,
+  const struct array *self,
   void *dest,
   size_t i0,
   size_t i1,
@@ -403,7 +403,7 @@ static inline __attribute__((always_inline)) void array_get3(
 }
 
 static inline __attribute__((always_inline)) void array_get4(
-  struct array *self,
+  const struct array *self,
   void *dest,
   size_t i0,
   size_t i1,
@@ -499,7 +499,7 @@ static inline __attribute__((always_inline)) void array_clear4(
 }
 
 static inline __attribute__((always_inline)) struct array *array_dup0(
-  struct array *self
+  const struct array *self
 ) {
   assert(self->n_dims >= 0);
   struct array *p = array_new(
@@ -512,7 +512,7 @@ static inline __attribute__((always_inline)) struct array *array_dup0(
 }
 
 static inline __attribute__((always_inline)) struct array *array_dup1(
-  struct array *self,
+  const struct array *self,
   size_t i0
 ) {
   assert(self->n_dims >= 1);
@@ -526,7 +526,7 @@ static inline __attribute__((always_inline)) struct array *array_dup1(
 }
 
 static inline __attribute__((always_inline)) struct array *array_dup2(
-  struct array *self,
+  const struct array *self,
   size_t i0,
   size_t i1
 ) {
@@ -541,7 +541,7 @@ static inline __attribute__((always_inline)) struct array *array_dup2(
 }
 
 static inline __attribute__((always_inline)) struct array *array_dup3(
-  struct array *self,
+  const struct array *self,
   size_t i0,
   size_t i1,
   size_t i2
@@ -557,7 +557,7 @@ static inline __attribute__((always_inline)) struct array *array_dup3(
 }
 
 static inline __attribute__((always_inline)) struct array *array_dup4(
-  struct array *self,
+  const struct array *self,
   size_t i0,
   size_t i1,
   size_t i2,
index 3521303..260bec0 100644 (file)
--- a/render.c
+++ b/render.c
@@ -15,124 +15,74 @@ SDL_Window *window;
 SDL_Renderer *renderer;
 SDL_Surface *window_surface;
 
-void print_vec30(struct array *array) {
-  for (int i = 0; i < 3; ++i) {
-    float v;
-    array_get1(array, &v, i);
-    printf("%s%7.3f", i ? ", " : "[", v);
-  }
-  printf("]");
-}
-
-void print_vec31(struct array *array, size_t i0) {
-  for (int i = 0; i < 3; ++i) {
-    float v;
-    array_get2(array, &v, i0, i);
-    printf("%s%7.3f", i ? ", " : "[", v);
-  }
-  printf("]");
-}
-
-void print_vec40(struct array *array) {
-  for (int i = 0; i < 4; ++i) {
-    float v;
-    array_get1(array, &v, i);
-    printf("%s%7.3f", i ? ", " : "[", v);
-  }
-  printf("]");
-}
-
-void print_vec41(struct array *array, size_t i0) {
-  for (int i = 0; i < 4; ++i) {
-    float v;
-    array_get2(array, &v, i0, i);
-    printf("%s%7.3f", i ? ", " : "[", v);
-  }
-  printf("]");
-}
-
-void print_mat330(struct array *array) {
-  for (int i = 0; i < 3; ++i) {
-    printf("%s", i ? " " : "[");
-    print_vec31(array, i);
-    printf("%s", i < 2 ? "\n" : "]");
-  }
-}
-
-void print_mat340(struct array *array) {
-  for (int i = 0; i < 3; ++i) {
-    printf("%s", i ? " " : "[");
-    print_vec41(array, i);
-    printf("%s", i < 2 ? "\n" : "]");
-  }
+void print_vec(const char *prefix, struct array *array, const char *suffix) {
+  assert(array->n_dims == 2);
+  assert(array->stride[1] == sizeof(float));
+  printf("%s[", prefix);
+  for (int i = 0; i < array->dim[0]; ++i)
+    printf("%s%7.3f", i ? ", " : "", *(float *)array_index1(array, i));
+  printf("]%s", suffix);
 }
 
-void print_mat440(struct array *array) {
-  for (int i = 0; i < 4; ++i) {
-    printf("%s", i ? " " : "[");
-    print_vec41(array, i);
-    printf("%s", i < 3 ? "\n" : "]");
+void print_mat(const char *prefix, struct array *array, const char *suffix) {
+  assert(array->n_dims == 3);
+  assert(array->stride[2] == sizeof(float));
+  printf("%s[", prefix);
+  for (int i = 0; i < array->dim[0]; ++i) {
+    printf("%s[", i ? " " : "");
+    for (int j = 0; j < array->dim[1]; ++j)
+      printf("%s%7.3f", j ? ", " : "", *(float *)array_index2(array, i, j));
+    printf("]%s", i < array->dim[0] - 1 ? "\n" : "");
   }
+  printf("]%s", suffix);
 }
 
 // compute C = A B
-void mul_mat33_mat34(struct array *A, struct array *B, struct array *C) {
-  for (int i = 0; i < 3; ++i)
-    for (int j = 0; j < 4; ++j) {
-      float c = 0.f;
-      for (int k = 0; k < 3; ++k) {
-        float a, b;
-        array_get2(A, &a, i, k);
-        array_get2(B, &b, k, j);
-        c += a * b;
-      }
-      array_set2(C, i, j, &c);
-    }
-}
-void mul_mat34_mat44(struct array *A, struct array *B, struct array *C) {
-  for (int i = 0; i < 3; ++i)
-    for (int j = 0; j < 4; ++j) {
-      float c = 0.f;
-      for (int k = 0; k < 4; ++k) {
-        float a, b;
-        array_get2(A, &a, i, k);
-        array_get2(B, &b, k, j);
-        c += a * b;
-      }
-      array_set2(C, i, j, &c);
-    }
-}
-void mul_mat44_mat44(struct array *A, struct array *B, struct array *C) {
-  for (int i = 0; i < 4; ++i)
-    for (int j = 0; j < 4; ++j) {
-      float c = 0.f;
-      for (int k = 0; k < 4; ++k) {
-        float a, b;
-        array_get2(A, &a, i, k);
-        array_get2(B, &b, k, j);
-        c += a * b;
-      }
-      array_set2(C, i, j, &c);
+struct array *mul_mat_mat(const struct array *A, const struct array *B) {
+  assert(A->n_dims == 3);
+  assert(A->stride[2] == sizeof(float));
+  assert(B->n_dims == 3);
+  assert(B->stride[2] == sizeof(float));
+  size_t I = A->dim[0];
+  size_t J = B->dim[1];
+  size_t K = A->dim[1];
+  assert(K == B->dim[0]);
+  struct array *C = array_new3(I, J, sizeof(float));
+  for (int i = 0; i < I; ++i)
+    for (int j = 0; j < J; ++j) {
+      float v = 0.f;
+      for (int k = 0; k < K; ++k)
+        v += *(float *)array_index2(A, i, k) * *(float *)array_index2(B, k, j);
+      *(float *)array_index2(C, i, j) = v;
     }
+  return C;
 }
-void mul_mat34_vec4(struct array *A, struct array *B, struct array *C) {
-  for (int i = 0; i < 3; ++i) {
-    float c = 0.f;
-    for (int j = 0; j < 4; ++j) {
-      float a, b;
-      array_get2(A, &a, i, j);
-      array_get1(B, &b, j);
-      c += a * b;
-    }
-    array_set1(C, i, &c);
+
+// compute c = A b
+struct array *mul_mat_vec(const struct array *A, const struct array *b) {
+  assert(A->n_dims == 3);
+  assert(A->stride[2] == sizeof(float));
+  assert(b->n_dims == 2);
+  assert(b->stride[1] == sizeof(float));
+  size_t I = A->dim[0];
+  size_t J = A->dim[1];
+  assert(J == b->dim[0]);
+  struct array *c = array_new2(I, sizeof(float));
+  for (int i = 0; i < I; ++i) {
+    float v = 0.f;
+    for (int j = 0; j < J; ++j)
+      v += *(float *)array_index2(A, i, j) * *(float *)array_index1(b, j);
+    *(float *)array_index1(c, i) = v;
   }
+  return c;
 }
 
 void rotate(const float (*v)[4], struct array *transform) {
   struct array *t0 = array_new3_init(4, 4, sizeof(float), v);
-  struct array *t1 = array_new3(4, 4, sizeof(float));
-  mul_mat44_mat44(t0, transform, t1);
+  struct array *t1 = mul_mat_mat(t0, transform);
   array_set0(transform, array_index0(t1));
+  array_free(t1);
+  array_free(t0);
 }
 
 int main(void) {
@@ -182,9 +132,7 @@ int main(void) {
       {0.f, 0.f, 1.f},
     }
   );
-  printf("device_transform\n");
-  print_mat330(device_transform);
-  printf("\n");
+  print_mat("device_transform\n", device_transform, "\n");
 
   // perspective
   struct array *perspective_transform = array_new3_init(
@@ -197,9 +145,7 @@ int main(void) {
       {0.f, 1.f, 0.f, 0.f},
     }
   );
-  printf("perspective_transform\n");
-  print_mat340(perspective_transform);
-  printf("\n");
+  print_mat("perspective_transform\n", perspective_transform, "\n");
 
   // camera
   struct array *camera_rotate = array_new3_init(
@@ -213,9 +159,7 @@ int main(void) {
       {0.f, 0.f, 0.f, 1.f}
     }
   );
-  printf("camera_rotate\n");
-  print_mat440(camera_rotate);
-  printf("\n");
+  print_mat("camera_rotate\n", camera_rotate, "\n");
 
   struct array *camera_translate = array_new3_init(
     4,
@@ -228,23 +172,19 @@ int main(void) {
       {0.f, 0.f, 0.f, 1.f}
     }
   );
-  printf("camera_translate\n");
-  print_mat440(camera_translate);
-  printf("\n");
+  print_mat("camera_translate\n", camera_translate, "\n");
 
   // model
-  struct array *model_vertices = array_new3(8, 4, sizeof(float));
+  struct array *model_vertices = array_new3(4, 8, sizeof(float));
   for (int i = 0; i < 2; ++i)
     for (int j = 0; j < 2; ++j)
       for (int k = 0; k < 2; ++k) {
         float v[4] = {i * 2 - 1, j * 2 - 1, k * 2 - 1, 1.f};
-        array_set1(model_vertices, i * 4 + j * 2 + k, v);
+        array_set2(model_vertices, 0, i * 4 + j * 2 + k, v);
+        array_set2(model_vertices, 1, i * 4 + j * 2 + k, v + 1);
+        array_set2(model_vertices, 2, i * 4 + j * 2 + k, v + 2);
+        array_set2(model_vertices, 3, i * 4 + j * 2 + k, v + 3);
       }
-  printf("model_vertices\n");
-  for (int i = 0; i < 8; ++i) {
-    print_vec41(model_vertices, i);
-    printf("\n");
-  }
   int model_lines[12][2] = {
     {0, 1}, // 0, 0, 0 -> 0, 0, 1
     {0, 2}, // 0, 0, 0 -> 0, 1, 0
@@ -290,9 +230,7 @@ int main(void) {
       {0.f, 0.f, 0.f, 1.f}
     }
   );
-  printf("model_rotate\n");
-  print_mat440(model_rotate);
-  printf("\n");
+  print_mat("model_rotate\n", model_rotate, "\n");
 
   struct array *model_translate = array_new3_init(
     4,
@@ -305,9 +243,7 @@ int main(void) {
       {0.f, 0.f, 0.f, 1.f}
     }
   );
-  printf("model_translate\n");
-  print_mat440(model_translate);
-  printf("\n");
+  print_mat("model_translate\n", model_translate, "\n");
 
   // main loop
   while (true) {
@@ -395,40 +331,26 @@ int main(void) {
     SDL_RenderClear(renderer);
 
     // compose device, perspective, camera and model transforms for speed
-    struct array *t0 = array_new3(3, 4, sizeof(float));
-    mul_mat33_mat34(device_transform, perspective_transform, t0);
-    struct array *t1 = array_new3(3, 4, sizeof(float));
-    mul_mat34_mat44(t0, camera_rotate, t1);
-    struct array *t2 = array_new3(3, 4, sizeof(float));
-    mul_mat34_mat44(t1, camera_translate, t2);
-    struct array *t3 = array_new3(3, 4, sizeof(float));
-    mul_mat34_mat44(t2, model_rotate, t3);
-    struct array *t4 = array_new3(3, 4, sizeof(float));
-    mul_mat34_mat44(t3, model_translate, t4);
+    struct array *t0 = mul_mat_mat(device_transform, perspective_transform);
+    struct array *t1 = mul_mat_mat(t0, camera_rotate);
+    struct array *t2 = mul_mat_mat(t1, camera_translate);
+    struct array *t3 = mul_mat_mat(t2, model_rotate);
+    struct array *t4 = mul_mat_mat(t3, model_translate);
 
     // transform model points
-    struct array *p = array_new3(8, 3, sizeof(float));
-    for (int i = 0; i < 8; ++i)
-      // taken from mul_mat34_vec4():
-      for (int j = 0; j < 3; ++j) {
-        float c = 0.f;
-        for (int k = 0; k < 4; ++k) {
-          float a, b;
-          array_get2(t4, &a, j, k);
-          array_get2(model_vertices, &b, i, k);
-          c += a * b;
-        }
-        array_set2(p, i, j, &c);
-      }
+    struct array *p = mul_mat_mat(t4, model_vertices);
 
     // unproject
     for (int i = 0; i < 8; ++i) {
       float v[3];
-      array_get1(p, v, i);
+      array_get2(p, v, 0, i);
+      array_get2(p, v + 1, 1, i);
+      array_get2(p, v + 2, 2, i);
       if (v[2] >= EPSILON) {
         v[0] /= v[2];
         v[1] /= v[2];
-        array_set1(p, i, v);
+        array_set2(p, 0, i, v);
+        array_set2(p, 1, i, v + 1);
       }
     }
 
@@ -437,8 +359,12 @@ int main(void) {
     for (int i = 0; i < 12; ++i) {
        float p0[3];
        float p1[3];
-       array_get1(p, p0, model_lines[i][0]);
-       array_get1(p, p1, model_lines[i][1]);
+       array_get2(p, p0, 0, model_lines[i][0]);
+       array_get2(p, p0 + 1, 1, model_lines[i][0]);
+       array_get2(p, p0 + 2, 2, model_lines[i][0]);
+       array_get2(p, p1, 0, model_lines[i][1]);
+       array_get2(p, p1 + 1, 1, model_lines[i][1]);
+       array_get2(p, p1 + 2, 2, model_lines[i][1]);
        if (p0[2] >= EPSILON && p1[2] >= EPSILON)
          SDL_RenderDrawLine(renderer, p0[0], p0[1], p1[0], p1[1]);
     }