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) {
{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(
{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(
{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,
{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
{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,
{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) {
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);
}
}
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]);
}