7 #define WINDOW_WIDTH 1024
8 #define WINDOW_HEIGHT 768
9 #define CAMERA_DISTANCE 5.f
13 #define COS_5DEG .99619470f // math.cos(5 * math.pi / 180.)
14 #define SIN_5DEG .087155743f // math.sin(5 * math.pi / 180.)
17 SDL_Renderer *renderer;
21 void print_vec(const char *prefix, struct array *array, const char *suffix) {
22 assert(array->n_dims == 2);
23 assert(array->dim[1] == sizeof(float));
24 printf("%s[", prefix);
25 for (size_t i = 0; i < array->dim[0]; ++i)
26 printf("%s%7.3f", i ? ", " : "", *(float *)array_index1(array, i));
27 printf("]%s", suffix);
30 void print_mat(const char *prefix, struct array *array, const char *suffix) {
31 assert(array->n_dims == 3);
32 assert(array->dim[2] == sizeof(float));
33 printf("%s[", prefix);
34 for (size_t i = 0; i < array->dim[0]; ++i) {
35 printf("%s[", i ? " " : "");
36 for (size_t j = 0; j < array->dim[1]; ++j)
37 printf("%s%7.3f", j ? ", " : "", *(float *)array_index2(array, i, j));
38 printf("]%s", i < array->dim[0] - 1 ? "\n" : "");
40 printf("]%s", suffix);
45 struct array *mul_mat_mat(const struct array *A, const struct array *B) {
46 assert(A->n_dims == 3);
47 assert(A->dim[2] == sizeof(float));
48 assert(B->n_dims == 3);
49 assert(B->dim[2] == sizeof(float));
53 assert(K == B->dim[0]);
54 struct array *C = array_new3(I, J, sizeof(float));
55 for (size_t i = 0; i < I; ++i)
56 for (size_t j = 0; j < J; ++j) {
58 for (size_t k = 0; k < K; ++k)
59 v += *(float *)array_index2(A, i, k) * *(float *)array_index2(B, k, j);
60 *(float *)array_index2(C, i, j) = v;
66 struct array *mul_mat_vec(const struct array *A, const struct array *b) {
67 assert(A->n_dims == 3);
68 assert(A->dim[2] == sizeof(float));
69 assert(b->n_dims == 2);
70 assert(b->dim[1] == sizeof(float));
73 assert(J == b->dim[0]);
74 struct array *c = array_new2(I, sizeof(float));
75 for (size_t i = 0; i < I; ++i) {
77 for (size_t j = 0; j < J; ++j)
78 v += *(float *)array_index2(A, i, j) * *(float *)array_index1(b, j);
79 *(float *)array_index1(c, i) = v;
84 void replace_array(struct array **p, struct array *q) {
89 void vec_min_max(struct array *p, float *min, float *max) {
92 assert(p->n_dims == 2);
93 assert(p->dim[1] == sizeof(float));
94 for (size_t i = 0; i < p->dim[0]; ++i) {
95 float v = *(float *)array_index1(p, i);
103 void mat_min_max(struct array *p) {
104 for (size_t i = 0; i < p->dim[0]; ++i) {
105 struct array *q = array_dup1(p, i);
107 vec_min_max(q, &min, &max);
108 printf("dim %ld min %7.3f max %7.3f\n", i, min, max);
113 float vec_dot(struct array *a, struct array *b) {
114 assert(a->n_dims == 2);
115 assert(a->dim[1] == sizeof(float));
116 assert(b->n_dims == 2);
117 assert(b->dim[1] == sizeof(float));
118 size_t I = a->dim[0];
119 assert(I == b->dim[0]);
121 for (size_t i = 0; i < I; ++i)
122 v += *(float *)array_index1(a, i) * *(float *)array_index1(b, i);
126 struct array *vec_cross(struct array *a, struct array *b) {
127 assert(a->n_dims == 2);
128 assert(a->dim[0] == 3);
129 assert(a->dim[1] == sizeof(float));
130 assert(b->n_dims == 2);
131 assert(b->dim[0] == 3);
132 assert(b->dim[1] == sizeof(float));
133 struct array *c = array_new2(3, sizeof(float));
134 *(float *)array_index1(c, 0) =
135 *(float *)array_index1(a, 1) * *(float *)array_index1(b, 2) -
136 *(float *)array_index1(a, 2) * *(float *)array_index1(b, 1);
137 *(float *)array_index1(c, 1) =
138 *(float *)array_index1(a, 2) * *(float *)array_index1(b, 0) -
139 *(float *)array_index1(a, 0) * *(float *)array_index1(b, 2);
140 *(float *)array_index1(c, 2) =
141 *(float *)array_index1(a, 0) * *(float *)array_index1(b, 1) -
142 *(float *)array_index1(a, 1) * *(float *)array_index1(b, 0);
146 struct array *mat_unproject(struct array *A) {
147 assert(A->n_dims == 3);
148 assert(A->dim[2] == sizeof(float));
149 size_t I = A->dim[1];
150 size_t J = A->dim[0];
152 struct array *B = array_new3(--J, I, sizeof(float));
153 for (size_t i = 0; i < I; ++i) {
154 float d = *(float *)array_index2(A, J, i);
155 assert(d < -EPSILON || d >= EPSILON);
157 for (size_t j = 0; j < J; ++j)
158 *(float *)array_index2(B, j, i) = *(float *)array_index2(A, j, i) * d;
163 struct array *mat_column(struct array *A, size_t col) {
164 assert(A->n_dims == 3);
165 assert(A->dim[2] == sizeof(float));
166 size_t I = A->dim[0];
167 struct array *B = array_new2(I, sizeof(float));
168 for (size_t i = 0; i < I; ++i)
169 *(float *)array_index1(B, i) = *(float *)array_index2(A, i, col);
173 struct array *mat_columns(struct array *A, size_t n_cols, size_t *cols) {
174 assert(A->n_dims == 3);
175 assert(A->dim[2] == sizeof(float));
176 size_t I = A->dim[0];
177 struct array *B = array_new3(I, n_cols, sizeof(float));
178 for (size_t i = 0; i < I; ++i)
179 for (size_t j = 0; j < n_cols; ++j)
180 *(float *)array_index2(B, i, j) = *(float *)array_index2(A, i, cols[j]);
184 struct array *vec_add(struct array *a, struct array *b) {
185 assert(a->n_dims == 2);
186 assert(a->dim[1] == sizeof(float));
187 assert(b->n_dims == 2);
188 assert(b->dim[1] == sizeof(float));
189 size_t I = a->dim[0];
190 assert(I == b->dim[0]);
191 struct array *c = array_new2(I, sizeof(float));
192 for (size_t i = 0; i < I; ++i)
193 *(float *)array_index1(c, i) =
194 *(float *)array_index1(a, i) + *(float *)array_index1(b, i);
198 struct array *vec_sub(struct array *a, struct array *b) {
199 assert(a->n_dims == 2);
200 assert(a->dim[1] == sizeof(float));
201 assert(b->n_dims == 2);
202 assert(b->dim[1] == sizeof(float));
203 size_t I = a->dim[0];
204 assert(I == b->dim[0]);
205 struct array *c = array_new2(I, sizeof(float));
206 for (size_t i = 0; i < I; ++i)
207 *(float *)array_index1(c, i) =
208 *(float *)array_index1(a, i) - *(float *)array_index1(b, i);
213 if (SDL_Init(SDL_INIT_VIDEO) < 0) {
214 fprintf(stderr, "SDL_Init(): %s\n\n", SDL_GetError());
218 if (!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1")) {
219 fprintf(stderr, "SDL_SetHint(): %s\n", SDL_GetError());
223 window = SDL_CreateWindow(
225 SDL_WINDOWPOS_UNDEFINED,
226 SDL_WINDOWPOS_UNDEFINED,
231 if (window == NULL) {
232 fprintf(stderr, "SDL_CreateWindow(): %s\n", SDL_GetError());
236 renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
237 if (renderer == NULL) {
238 fprintf(stderr, "SDL_CreateRenderer(): %s\n", SDL_GetError());
242 texture = SDL_CreateTexture(
244 SDL_PIXELFORMAT_ARGB8888,
245 SDL_TEXTUREACCESS_STREAMING,
249 if (texture == NULL) {
250 fprintf(stderr, "SDL_CreateTexture(): %s\n", SDL_GetError());
255 struct array *device_transform = array_new3_init(
260 {WINDOW_WIDTH, 0.f, .5f * WINDOW_WIDTH},
261 {0.f, WINDOW_WIDTH, .5f * WINDOW_HEIGHT},
265 print_mat("device_transform\n", device_transform, "\n");
268 struct array *perspective_transform = array_new3_init(
273 {1.f, 0.f, 0.f, 0.f},
274 {0.f, 0.f, 1.f, 0.f},
275 {0.f, 1.f, 0.f, 0.f},
278 print_mat("perspective_transform\n", perspective_transform, "\n");
281 struct array *camera_rotate = array_new3_init(
286 {1.f, 0.f, 0.f, 0.f},
287 {0.f, 1.f, 0.f, 0.f},
288 {0.f, 0.f, 1.f, 0.f},
292 print_mat("camera_rotate\n", camera_rotate, "\n");
294 struct array *camera_translate = array_new3_init(
299 {1.f, 0.f, 0.f, 0.f},
300 {0.f, 1.f, 0.f, CAMERA_DISTANCE},
301 {0.f, 0.f, 1.f, 0.f},
305 print_mat("camera_translate\n", camera_translate, "\n");
309 struct obj *obj = obj_create("Chest.obj"); //"grey_bliss_set.obj");
310 struct array *model_vertices;
311 struct array *model_vertices_t;
314 model_vertices = array_new3(4, I, sizeof(float));
315 model_vertices_t = array_new3(2, I, sizeof(float));
316 for (int i = 0; i < I; ++i) {
317 *(float *)array_index2(model_vertices, 0, i) = obj->vv[i].v[0];
318 *(float *)array_index2(model_vertices, 1, i) = obj->vv[i].v[1];
319 *(float *)array_index2(model_vertices, 2, i) = obj->vv[i].v[2];
320 *(float *)array_index2(model_vertices, 3, i) = 1.f;
322 *(float *)array_index2(model_vertices_t, 0, i) = obj->vv[i].t[0];
323 *(float *)array_index2(model_vertices_t, 1, i) = obj->vv[i].t[1];
327 struct array *model_vertices = array_new3(4, 8, sizeof(float));
328 for (int i = 0; i < 2; ++i)
329 for (int j = 0; j < 2; ++j)
330 for (int k = 0; k < 2; ++k) {
331 float v[4] = {i * 2 - 1, j * 2 - 1, k * 2 - 1, 1.f};
332 int l = i * 4 + j * 2 + k;
333 *(float *)array_index2(model_vertices, 0, l) = v[0];
334 *(float *)array_index2(model_vertices, 1, l) = v[1];
335 *(float *)array_index2(model_vertices, 2, l) = v[2];
336 *(float *)array_index2(model_vertices, 3, l) = v[3];
338 size_t model_lines[12][2] = {
339 {0, 1}, // 0, 0, 0 -> 0, 0, 1
340 {0, 2}, // 0, 0, 0 -> 0, 1, 0
341 {0, 4}, // 0, 0, 0 -> 1, 0, 0
343 //{1, 0}, // 0, 0, 1 -> 0, 0, 0
344 {1, 3}, // 0, 0, 1 -> 0, 1, 1
345 {1, 5}, // 0, 0, 1 -> 1, 0, 1
347 {2, 3}, // 0, 1, 0 -> 0, 1, 1
348 //{2, 0}, // 0, 1, 0 -> 0, 0, 0
349 {2, 6}, // 0, 1, 0 -> 1, 1, 0
351 //{3, 2}, // 0, 1, 1 -> 0, 1, 0
352 //{3, 1}, // 0, 1, 1 -> 0, 0, 1
353 {3, 7}, // 0, 1, 1 -> 1, 1, 1
355 {4, 5}, // 1, 0, 0 -> 1, 0, 1
356 {4, 6}, // 1, 0, 0 -> 1, 1, 0
357 //{4, 0}, // 1, 0, 0 -> 0, 0, 0
359 //{5, 4}, // 1, 0, 1 -> 1, 0, 0
360 {5, 7}, // 1, 0, 1 -> 1, 1, 1
361 //{5, 1}, // 1, 0, 1 -> 0, 0, 1
363 {6, 7}, // 1, 1, 0 -> 1, 1, 1
364 //{6, 4}, // 1, 1, 0 -> 1, 0, 0
365 //{6, 2}, // 1, 1, 0 -> 0, 1, 0
367 //{7, 6}, // 1, 1, 1 -> 1, 1, 0
368 //{7, 5}, // 1, 1, 1 -> 1, 0, 1
369 //{7, 3}, // 1, 1, 1 -> 0, 1, 1
373 struct array *model_rotate = array_new3_init(
378 {1.f, 0.f, 0.f, 0.f},
379 {0.f, 1.f, 0.f, 0.f},
380 {0.f, 0.f, 1.f, 0.f},
384 print_mat("model_rotate\n", model_rotate, "\n");
386 struct array *model_translate = array_new3_init(
391 {1.f, 0.f, 0.f, 0.f},
392 {0.f, 1.f, 0.f, 0.f},
393 {0.f, 0.f, 1.f, 0.f},
397 print_mat("model_translate\n", model_translate, "\n");
399 // rotation matrices for navigation
400 struct array *rotate_xy_5deg = array_new3_init(
405 {COS_5DEG, SIN_5DEG, 0.f, 0.f},
406 {-SIN_5DEG, COS_5DEG, 0.f, 0.f},
407 {0.f, 0.f, 1.f, 0.f},
411 struct array *rotate_xy_m5deg = array_new3_init(
416 {COS_5DEG, -SIN_5DEG, 0.f, 0.f},
417 {SIN_5DEG, COS_5DEG, 0.f, 0.f},
418 {0.f, 0.f, 1.f, 0.f},
422 struct array *rotate_xz_5deg = array_new3_init(
427 {COS_5DEG, 0.f, SIN_5DEG, 0.f},
428 {0.f, 1.f, 0.f, 0.f},
429 {-SIN_5DEG, 0.f, COS_5DEG, 0.f},
433 struct array *rotate_xz_m5deg = array_new3_init(
438 {COS_5DEG, 0.f, -SIN_5DEG, 0.f},
439 {0.f, 1.f, 0.f, 0.f},
440 {SIN_5DEG, 0.f, COS_5DEG, 0.f},
444 struct array *rotate_yz_5deg = array_new3_init(
449 {1.f, 0.f, 0.f, 0.f},
450 {0.f, COS_5DEG, -SIN_5DEG, 0.f},
451 {0.f, SIN_5DEG, COS_5DEG, 0.f},
455 struct array *rotate_yz_m5deg = array_new3_init(
460 {1.f, 0.f, 0.f, 0.f},
461 {0.f, COS_5DEG, SIN_5DEG, 0.f},
462 {0.f, -SIN_5DEG, COS_5DEG, 0.f},
469 struct array *to_barycentric = array_new3_init(
481 struct array *barycentric = array_new3(
488 for (int i = 0; i <= 100; ++i)
489 for (int j = 0; i + j <= 100; ++j) {
490 *(float *)array_index2(barycentric, 0, k) = i * .01f;
491 *(float *)array_index2(barycentric, 1, k) = j * .01f;
492 *(float *)array_index2(barycentric, 2, k) = (100 - i - j) * .01f;
495 assert(k == 101 * 102 / 2);
499 struct array *frame =
500 array_new3(WINDOW_HEIGHT, WINDOW_WIDTH, sizeof(uint32_t));
501 struct array *frame_z =
502 array_new3(WINDOW_HEIGHT, WINDOW_WIDTH, sizeof(float));
505 while (SDL_PollEvent(&event))
506 switch (event.type) {
511 SDL_KeyboardEvent *e = (SDL_KeyboardEvent *)&event;
512 switch (e->keysym.sym) {
516 mul_mat_mat(rotate_xz_5deg, model_rotate)
522 mul_mat_mat(rotate_yz_5deg, model_rotate)
528 mul_mat_mat(rotate_xz_m5deg, model_rotate)
534 mul_mat_mat(rotate_xy_5deg, model_rotate)
540 mul_mat_mat(rotate_yz_m5deg, model_rotate)
546 mul_mat_mat(rotate_xy_m5deg, model_rotate)
554 SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0xff);
555 SDL_RenderClear(renderer);
557 // compose device, perspective, camera and model transforms for speed
558 struct array *t0 = mul_mat_mat(device_transform, perspective_transform);
559 struct array *t1 = mul_mat_mat(camera_rotate, camera_translate);
560 struct array *t2 = mul_mat_mat(t1, model_rotate);
561 struct array *t3 = mul_mat_mat(t2, model_translate);
563 // transform model points
564 struct array *p = mul_mat_mat(t3, model_vertices);
565 struct array *pu = mat_unproject(p);
566 struct array *q = mul_mat_mat(t0, p);
567 struct array *qu = mat_unproject(q);
571 for (int i = 0; i < WINDOW_HEIGHT; ++i)
572 for (int j = 0; j < WINDOW_WIDTH; ++j)
573 *(float *)array_index2(frame_z, i, j) = 1e30f;
577 for (int i = 0; i < I; ++i) {
578 int J = obj->sv[i].pc;
579 for (int j = 0; j < J; ++j) {
581 obj->sv[i].pv[j].vi[0],
582 obj->sv[i].pv[j].vi[1],
583 obj->sv[i].pv[j].vi[2]
587 // check face visibility
588 struct array *pu0 = mat_column(pu, v[0]);
589 struct array *pu1 = mat_column(pu, v[1]);
590 struct array *pu2 = mat_column(pu, v[2]);
591 struct array *dir1 = vec_sub(pu1, pu0);
592 struct array *dir2 = vec_sub(pu2, pu0);
593 struct array *norm = vec_cross(dir1, dir2); // outward pointing
595 /*vec_dot(norm, norm) < EPSILON ||*/ // degenerate face
596 vec_dot(norm, pu0) >= -EPSILON // origin is on underside of face
614 #if 1 // roughly texturize
615 int mi = obj->sv[i].mi;
616 if (mi >= 0 && mi < obj->mc) {
617 struct array *map = obj->mv[mi].kv[OBJ_KD].map;
618 assert(map->dim[2] == 3);
619 struct array *tc = mat_columns(model_vertices_t, 3, v);
620 for (int i = 0; i < 3; ++i) {
621 *(float *)array_index2(tc, 0, i) *= map->dim[1];
622 *(float *)array_index2(tc, 1, i) *= map->dim[0];
624 struct array *tcb = mul_mat_mat(tc, barycentric);
625 struct array *qc = mat_columns(q, 3, v);
626 struct array *qcb = mul_mat_mat(qc, barycentric);
627 struct array *qcbu = mat_unproject(qcb);
628 size_t K = barycentric->dim[1];
629 for (size_t k = 0; k < K; ++k) {
630 float u = floorf(*(float *)array_index2(tcb, 0, k));
631 float v = floorf(*(float *)array_index2(tcb, 1, k));
632 float x = roundf(*(float *)array_index2(qcbu, 0, k));
633 float y = roundf(*(float *)array_index2(qcbu, 1, k));
644 size_t xi = (size_t)x;
645 size_t yi = (size_t)y;
646 float z = *(float *)array_index2(qcb, 2, k);
647 float *fz = (float *)array_index2(frame_z, yi, xi);
649 size_t ui = (size_t)u;
650 size_t vi = (size_t)v;
651 uint8_t *m = array_index2(map, vi, ui);
652 uint8_t *f = array_index2(frame, yi, xi);
667 #else // wireframe only
668 struct array *quc = mat_columns(qu, 3, v);
669 SDL_SetRenderDrawColor(renderer, 0, 0xff, 0, 0xff);
672 *(float *)array_index2(quc, 0, 0),
673 *(float *)array_index2(quc, 1, 0),
674 *(float *)array_index2(quc, 0, 1),
675 *(float *)array_index2(quc, 1, 1)
679 *(float *)array_index2(quc, 0, 1),
680 *(float *)array_index2(quc, 1, 1),
681 *(float *)array_index2(quc, 0, 2),
682 *(float *)array_index2(quc, 1, 2)
686 *(float *)array_index2(quc, 0, 2),
687 *(float *)array_index2(quc, 1, 2),
688 *(float *)array_index2(quc, 0, 0),
689 *(float *)array_index2(quc, 1, 0)
694 /*int*/ J = obj->sv[i].lc;
695 for (int j = 0; j < J; ++j) {
697 obj->sv[i].lv[j].vi[0],
698 obj->sv[i].lv[j].vi[1]
700 struct array *quc = mat_columns(qu, 2, v);
701 SDL_SetRenderDrawColor(renderer, 0, 0xff, 0, 0xff);
704 *(float *)array_index2(quc, 0, 0),
705 *(float *)array_index2(quc, 1, 0),
706 *(float *)array_index2(quc, 0, 1),
707 *(float *)array_index2(quc, 1, 1)
714 for (int i = 0; i < 12; ++i) {
715 struct array *quc = mat_columns(qu, 2, model_lines[i]);
716 SDL_SetRenderDrawColor(renderer, 0, 0xff, 0, 0xff);
719 *(float *)array_index2(quc, 0, 0),
720 *(float *)array_index2(quc, 1, 0),
721 *(float *)array_index2(quc, 0, 1),
722 *(float *)array_index2(quc, 1, 1)
737 SDL_UpdateTexture(texture, NULL, array_index0(frame), frame->stride[1]);
738 SDL_RenderCopy(renderer, texture, NULL, NULL);
739 SDL_RenderPresent(renderer);
744 SDL_DestroyRenderer(renderer);
745 SDL_DestroyWindow(window);