Simplify the code for gathering the vertices of a face
authorNick Downing <nick@ndcode.org>
Tue, 19 Apr 2022 12:37:35 +0000 (22:37 +1000)
committerNick Downing <nick@ndcode.org>
Tue, 19 Apr 2022 12:37:35 +0000 (22:37 +1000)
Makefile
render.c

index 050ce94..5611a82 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-CFLAGS=-g -Og -Wall -Wno-format-truncation -DCONF_NO_GL
+CFLAGS=-g -Og -Wall -Wno-format-overflow -Wno-format-truncation -DCONF_NO_GL
 
 render: render.o obj.o
        ${CC} -o $@ $^ -lSDL2 -lm
index 6af3569..e79d0bf 100644 (file)
--- a/render.c
+++ b/render.c
@@ -19,20 +19,20 @@ SDL_Surface *window_surface;
 
 void print_vec(const char *prefix, struct array *array, const char *suffix) {
   assert(array->n_dims == 2);
-  assert(array->stride[1] == sizeof(float));
+  assert(array->dim[1] == sizeof(float));
   printf("%s[", prefix);
-  for (int i = 0; i < array->dim[0]; ++i)
+  for (size_t i = 0; i < array->dim[0]; ++i)
     printf("%s%7.3f", i ? ", " : "", *(float *)array_index1(array, i));
   printf("]%s", suffix);
 }
 
 void print_mat(const char *prefix, struct array *array, const char *suffix) {
   assert(array->n_dims == 3);
-  assert(array->stride[2] == sizeof(float));
+  assert(array->dim[2] == sizeof(float));
   printf("%s[", prefix);
-  for (int i = 0; i < array->dim[0]; ++i) {
+  for (size_t i = 0; i < array->dim[0]; ++i) {
     printf("%s[", i ? " " : "");
-    for (int j = 0; j < array->dim[1]; ++j)
+    for (size_t 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" : "");
   }
@@ -43,18 +43,18 @@ void print_mat(const char *prefix, struct array *array, const char *suffix) {
 // compute C = A B
 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(A->dim[2] == sizeof(float));
   assert(B->n_dims == 3);
-  assert(B->stride[2] == sizeof(float));
+  assert(B->dim[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) {
+  for (size_t i = 0; i < I; ++i)
+    for (size_t j = 0; j < J; ++j) {
       float v = 0.f;
-      for (int k = 0; k < K; ++k)
+      for (size_t 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;
     }
@@ -64,16 +64,16 @@ struct array *mul_mat_mat(const struct array *A, const struct array *B) {
 // 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(A->dim[2] == sizeof(float));
   assert(b->n_dims == 2);
-  assert(b->stride[1] == sizeof(float));
+  assert(b->dim[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) {
+  for (size_t i = 0; i < I; ++i) {
     float v = 0.f;
-    for (int j = 0; j < J; ++j)
+    for (size_t j = 0; j < J; ++j)
       v += *(float *)array_index2(A, i, j) * *(float *)array_index1(b, j);
     *(float *)array_index1(c, i) = v;
   }
@@ -89,8 +89,8 @@ void vec_min_max(struct array *p, float *min, float *max) {
   *min = 1e30f;
   *max = -1e30f;
   assert(p->n_dims == 2);
-  assert(p->stride[1] == sizeof(float));
-  for (int i = 0; i < p->dim[0]; ++i) {
+  assert(p->dim[1] == sizeof(float));
+  for (size_t i = 0; i < p->dim[0]; ++i) {
     float v = *(float *)array_index1(p, i);
     if (v < *min)
       *min = v;
@@ -100,15 +100,81 @@ void vec_min_max(struct array *p, float *min, float *max) {
 }
 
 void mat_min_max(struct array *p) {
-  for (int i = 0; i < p->dim[0]; ++i) {
+  for (size_t i = 0; i < p->dim[0]; ++i) {
     struct array *q = array_dup1(p, i);
     float min, max;
     vec_min_max(q, &min, &max); 
-    printf("dim %d min %7.3f max %7.3f\n", i, min, max);
+    printf("dim %ld min %7.3f max %7.3f\n", i, min, max);
     array_free(q);
   }
 }
 
+float vec_dot(struct array *a, struct array *b) {
+  assert(a->n_dims == 2);
+  assert(a->dim[1] == sizeof(float));
+  assert(b->n_dims == 2);
+  assert(b->dim[1] == sizeof(float));
+  size_t I = a->dim[0];
+  assert(I == b->dim[0]);
+  float v = 0.f;
+  for (size_t i = 0; i < I; ++i)
+    v += *(float *)array_index1(a, i) * *(float *)array_index1(b, i);
+  return v;
+}
+
+struct array *vec_cross(struct array *a, struct array *b) {
+  assert(a->n_dims == 2);
+  assert(a->dim[0] == 3);
+  assert(a->dim[1] == sizeof(float));
+  assert(b->n_dims == 2);
+  assert(b->dim[0] == 3);
+  assert(b->dim[1] == sizeof(float));
+  struct array *c = array_new2(3, sizeof(float));
+  *(float *)array_index1(c, 0) =
+    *(float *)array_index1(a, 1) * *(float *)array_index1(b, 2) -
+    *(float *)array_index1(a, 2) * *(float *)array_index1(b, 1);
+  *(float *)array_index1(c, 1) =
+    *(float *)array_index1(a, 2) * *(float *)array_index1(b, 0) -
+    *(float *)array_index1(a, 0) * *(float *)array_index1(b, 2);
+  *(float *)array_index1(c, 2) =
+    *(float *)array_index1(a, 0) * *(float *)array_index1(b, 1) -
+    *(float *)array_index1(a, 1) * *(float *)array_index1(b, 0);
+  return c;
+}
+
+struct array *mat_unproject(struct array *A) {
+  assert(A->n_dims == 3);
+  assert(A->dim[2] == sizeof(float));
+  size_t I = A->dim[1];
+  size_t J = A->dim[0];
+  assert(J >= 1);
+  struct array *B = array_new3(--J, I, sizeof(float));
+  for (size_t i = 0; i < I; ++i) {
+    float d = *(float *)array_index2(A, J, i);
+    assert(d < -EPSILON || d >= EPSILON);
+    d = 1.f / d;
+    for (size_t j = 0; j < J; ++j)
+      *(float *)array_index2(B, j, i) = *(float *)array_index2(A, j, i) * d;
+  }
+  return B;
+}
+
+// special for column-wise vertex arrays
+// construct row-wise array for a given face
+struct array *gather(struct array *A, int n_cols, int *cols) {
+  assert(A->n_dims == 3);
+  assert(A->dim[2] == sizeof(float));
+  size_t J = A->dim[0];
+  struct array *B = array_new3(n_cols, J, sizeof(float));
+  for (int i = 0; i < n_cols; ++i) {
+    int col = cols[i];
+    assert(col >= 0 && col < A->dim[1]);
+    for (size_t j = 0; j < J; ++j)
+      *(float *)array_index2(B, i, j) = *(float *)array_index2(A, j, col);
+  }
+  return B; 
+}
+
 int main(void) {
   if (SDL_Init(SDL_INIT_VIDEO) < 0) {
     fprintf(stderr, "SDL_Init(): %s\n\n", SDL_GetError());
@@ -201,19 +267,19 @@ int main(void) {
   // model
 #if 1
   obj *o = obj_create("grey_bliss_set.obj"); //"Chest.obj");
-  struct array *model_vertices = array_new3(
-    4,
-    obj_num_vert(o),
-    sizeof(float)
-  );
-  for (int i = 0; i < model_vertices->dim[1]; ++i) {
-    float v[4];
-    obj_get_vert_v(o, i, v);
-    v[3] = 1.f;
-    array_set2(model_vertices, 0, i, v);
-    array_set2(model_vertices, 1, i, v + 1);
-    array_set2(model_vertices, 2, i, v + 2);
-    array_set2(model_vertices, 3, i, v + 3);
+  struct array *model_vertices;
+  {
+    int I = obj_num_vert(o);
+    model_vertices = array_new3(4, I, sizeof(float));
+    for (int i = 0; i < I; ++i) {
+      float v[4];
+      obj_get_vert_v(o, i, v);
+      v[3] = 1.f;
+      *(float *)array_index2(model_vertices, 0, i) = v[0];
+      *(float *)array_index2(model_vertices, 1, i) = v[1];
+      *(float *)array_index2(model_vertices, 2, i) = v[2];
+      *(float *)array_index2(model_vertices, 3, i) = v[3];
+    }
   }
 #else
   struct array *model_vertices = array_new3(4, 8, sizeof(float));
@@ -221,10 +287,11 @@ int main(void) {
     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_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);
+        int l = i * 4 + j * 2 + k;
+        *(float *)array_index2(model_vertices, 0, l) = v[0];
+        *(float *)array_index2(model_vertices, 1, l) = v[1];
+        *(float *)array_index2(model_vertices, 2, l) = v[2];
+        *(float *)array_index2(model_vertices, 3, l) = v[3];
       }
   int model_lines[12][2] = {
     {0, 1}, // 0, 0, 0 -> 0, 0, 1
@@ -412,27 +479,15 @@ int main(void) {
 
     // compose device, perspective, camera and model transforms for speed
     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);
+    struct array *t1 = mul_mat_mat(camera_rotate, camera_translate);
+    struct array *t2 = mul_mat_mat(t1, model_rotate);
+    struct array *t3 = mul_mat_mat(t2, model_translate);
 
     // transform model points
-    struct array *p = mul_mat_mat(t4, model_vertices);
-
-    // unproject
-    for (int i = 0; i < p->dim[1]; ++i) {
-      float v[3];
-      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_set2(p, 0, i, v);
-        array_set2(p, 1, i, v + 1);
-      }
-    }
+    struct array *p = mul_mat_mat(t3, model_vertices);
+    struct array *pu = mat_unproject(p);
+    struct array *q = mul_mat_mat(t0, p);
+    struct array *qu = mat_unproject(q);
 
     // draw
     SDL_SetRenderDrawColor(renderer, 0, 0xff, 0, 0xff);
@@ -444,59 +499,64 @@ int main(void) {
         for (int j = 0; j < J; ++j) {
           int v[3];
           obj_get_poly(o, i, j, v);
-          float p0[3];
-          array_get2(p, p0, 0, v[0]);
-          array_get2(p, p0 + 1, 1, v[0]);
-          array_get2(p, p0 + 2, 2, v[0]);
-          float p1[3];
-          array_get2(p, p1, 0, v[1]);
-          array_get2(p, p1 + 1, 1, v[1]);
-          array_get2(p, p1 + 2, 2, v[1]);
-          float p2[3];
-          array_get2(p, p2, 0, v[2]);
-          array_get2(p, p2 + 1, 1, v[2]);
-          array_get2(p, p2 + 2, 2, v[2]);
-          if (p0[2] >= EPSILON && p1[2] >= EPSILON)
-            SDL_RenderDrawLine(renderer, p0[0], p0[1], p1[0], p1[1]);
-          if (p0[2] >= EPSILON && p2[2] >= EPSILON)
-            SDL_RenderDrawLine(renderer, p0[0], p0[1], p2[0], p2[1]);
-          if (p1[2] >= EPSILON && p2[2] >= EPSILON)
-            SDL_RenderDrawLine(renderer, p1[0], p1[1], p2[0], p2[1]);
+          struct array *qug = gather(qu, 3, v);
+          SDL_RenderDrawLine(
+            renderer,
+            *(float *)array_index2(qug, 0, 0),
+            *(float *)array_index2(qug, 0, 1),
+            *(float *)array_index2(qug, 1, 0),
+            *(float *)array_index2(qug, 1, 1)
+          );
+          SDL_RenderDrawLine(
+            renderer,
+            *(float *)array_index2(qug, 1, 0),
+            *(float *)array_index2(qug, 1, 1),
+            *(float *)array_index2(qug, 2, 0),
+            *(float *)array_index2(qug, 2, 1)
+          );
+          SDL_RenderDrawLine(
+            renderer,
+            *(float *)array_index2(qug, 2, 0),
+            *(float *)array_index2(qug, 2, 1),
+            *(float *)array_index2(qug, 0, 0),
+            *(float *)array_index2(qug, 0, 1)
+          );
+          array_free(qug);
         }
         /*int*/ J = obj_num_line(o, i);
         for (int j = 0; j < J; ++j) {
           int v[2];
           obj_get_line(o, i, j, v);
-          float p0[3];
-          array_get2(p, p0, 0, v[0]);
-          array_get2(p, p0 + 1, 1, v[0]);
-          array_get2(p, p0 + 2, 2, v[0]);
-          float p1[3];
-          array_get2(p, p1, 0, v[1]);
-          array_get2(p, p1 + 1, 1, v[1]);
-          array_get2(p, p1 + 2, 2, v[1]);
-          if (p0[2] >= EPSILON && p1[2] >= EPSILON)
-            SDL_RenderDrawLine(renderer, p0[0], p0[1], p1[0], p1[1]);
+          struct array *qug = gather(qu, 2, v);
+          SDL_RenderDrawLine(
+            renderer,
+            *(float *)array_index2(qug, 0, 0),
+            *(float *)array_index2(qug, 0, 1),
+            *(float *)array_index2(qug, 1, 0),
+            *(float *)array_index2(qug, 1, 1)
+          );
+          array_free(qug);
         }
       }
     }
 #else
     for (int i = 0; i < 12; ++i) {
-      float p0[3];
-      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]);
-      float p1[3];
-      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]);
+      struct array *qug = gather(qu, 2, model_lines[i]);
+      SDL_RenderDrawLine(
+        renderer,
+        *(float *)array_index2(qug, 0, 0),
+        *(float *)array_index2(qug, 0, 1),
+        *(float *)array_index2(qug, 1, 0),
+        *(float *)array_index2(qug, 1, 1)
+      );
+      array_free(qug);
     }
 #endif
 
+    array_free(qu);
+    array_free(q);
+    array_free(pu);
     array_free(p);
-    array_free(t4);
     array_free(t3);
     array_free(t2);
     array_free(t1);