diff --git a/main.c b/main.c new file mode 100644 index 0000000..65c4932 --- /dev/null +++ b/main.c @@ -0,0 +1,223 @@ +/** + * Playing around with matrices while studying + * https://github.com/ssloy/tinyrenderer/wiki/Lesson-4:-Perspective-projection + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define u64 uint64_t +#define f32 float + +#define RADIANS(DEGREES) (DEGREES * M_PI / 180.0f) + +typedef struct vec2u V2u; +struct vec2u { + u64 x; + u64 y; +}; + +typedef struct vec3f V3f; +struct vec3f { + union { + f32 x; + f32 col0; + }; + union { + f32 y; + f32 col1; + }; + union { + f32 z; + f32 col2; + }; +}; + +typedef struct mat3x3 Mat3x3; +struct mat3x3 { + V3f row0; + V3f row1; + V3f row2; +}; + +#define vec_add(v1, v2) ((V2u){.x = v1.x + v2.x, .y = v1.y + v2.y}) +#define vec_sub(v1, v2) ((V2u){.x = v1.x - v2.x, .y = v1.y - v2.y}) +#define vec_div_num(v, n) ((V2u){.x = v.x / n, .y = v.y / 2}) +#define mat_mul_vec(mat, vec) \ + ((V3f){.x = mat.row0.col0 * vec.x + mat.row0.col1 * vec.y + \ + mat.row0.col2 * vec.z, \ + .y = mat.row1.col0 * vec.x + mat.row1.col1 * vec.y + \ + mat.row1.col2 * vec.z, \ + .z = mat.row2.col0 * vec.x + mat.row2.col1 * vec.y + \ + mat.row2.col2 * vec.z}) +#define project_v3f(v) ((V2u){.x = (u64)(v.x / v.z), .y = (u64)(v.y / v.z)}) + +// clang-format off +#define mat_mul(mat1, mat2) \ + ((Mat3x3){ \ + .row0 = {.col0 = mat1.row0.col0 * mat2.row0.col0 + mat1.row0.col1 * mat2.row1.col0 + mat1.row0.col2 * mat2.row2.col0, \ + .col1 = mat1.row0.col0 * mat2.row0.col1 + mat1.row0.col1 * mat2.row1.col1 + mat1.row0.col2 * mat2.row2.col1, \ + .col2 = mat1.row0.col0 * mat2.row0.col2 + mat1.row0.col1 * mat2.row1.col2 + mat1.row0.col2 * mat2.row2.col2}, \ + .row1 = {.col0 = mat1.row1.col0 * mat2.row0.col0 + mat1.row1.col1 * mat2.row1.col0 + mat1.row1.col2 * mat2.row2.col0, \ + .col1 = mat1.row1.col0 * mat2.row0.col1 + mat1.row1.col1 * mat2.row1.col1 + mat1.row1.col2 * mat2.row2.col1, \ + .col2 = mat1.row1.col0 * mat2.row0.col2 + mat1.row1.col1 * mat2.row1.col2 + mat1.row1.col2 * mat2.row2.col2}, \ + .row2 = {.col0 = mat1.row2.col0 * mat2.row0.col0 + mat1.row2.col1 * mat2.row1.col0 + mat1.row2.col2 * mat2.row2.col0, \ + .col1 = mat1.row2.col0 * mat2.row0.col1 + mat1.row2.col1 * mat2.row1.col1 + mat1.row2.col2 * mat2.row2.col1, \ + .col2 = mat1.row2.col0 * mat2.row0.col2 + mat1.row2.col1 * mat2.row1.col2 + mat1.row2.col2 * mat2.row2.col2}, \ + }) +// clang-format on + +#define MAT3x3(r0c0, r0c1, r0c2, r1c0, r1c1, r1c2, r2c0, r2c1, r2c2) \ + ((Mat3x3){{r0c0, r0c1, r0c2}, {r1c0, r1c1, r1c2}, {r2c0, r2c1, r2c2}}) + +void draw_line(SDL_Renderer *renderer, const V2u *start, const V2u *end); + +int main(void) { + SDL_Init(0); + SDL_Window *wnd = + SDL_CreateWindow("Matrices", SDL_WINDOWPOS_CENTERED, + SDL_WINDOWPOS_CENTERED, 1200, 800, SDL_WINDOW_SHOWN); + SDL_Renderer *renderer = SDL_CreateRenderer(wnd, -1, 0); + + f32 rotation = 0.0f; + f32 radians = RADIANS(rotation); + + // clang-format off + Mat3x3 pos_rot_mat, neg_rot_mat; + + Mat3x3 mat0 = MAT3x3(2.0f, -0.5f, 0.0f, + 0.0f, 2.0f, 0.0f, + 0.0f, 0.0f, 1.0f); + Mat3x3 mat1 = MAT3x3( 0.5f, 0.0f, 0.0f, + 0.25f, 0.5f, 0.0f, + 0.0f, 0.0f, 1.0f); + // clang-format on + + V3f v0p0 = {400.0f, 150.0f, 1.0f}; + V3f v0p1 = {800.0f, 150.0f, 1.0f}; + V3f v0p2 = {400.0f, 400.0f, 1.0f}; + V3f v0p3 = {800.0f, 400.0f, 1.0f}; + + // clang-format off + Mat3x3 mid_mat = MAT3x3(0.5f, 0.0f, 0.0f, + 0.0f, 0.5f, 0.0f, + 0.0f, 0.0f, 1.0f); + Mat3x3 neg_v0p0_xf = MAT3x3(1.0f, 0.0f, -(v0p0.x), + 0.0f, 1.0f, -(v0p0.y), + 0.0f, 0.0f, 1.0f); + Mat3x3 pos_v0p0_xf = MAT3x3(1.0f, 0.0f, v0p0.x, + 0.0f, 1.0f, v0p0.y, + 0.0f, 0.0f, 1.0f); + // clang-format on + + Mat3x3 v0_mid_mat = mat_mul(mat_mul(pos_v0p0_xf, mid_mat), neg_v0p0_xf); + V3f v0_mid = mat_mul_vec(v0_mid_mat, v0p3); + + // clang-format off + Mat3x3 neg_v0_mid_xf = MAT3x3(1.0f, 0.0f, -(v0_mid.x), + 0.0f, 1.0f, -(v0_mid.y), + 0.0f, 0.0f, 1.0f); + Mat3x3 pos_v0_mid_xf = MAT3x3(1.0f, 0.0f, v0_mid.x, + 0.0f, 1.0f, v0_mid.y, + 0.0f, 0.0f, 1.0f); + // clang-format on + + Mat3x3 v1_mat; + V3f v1p0, v1p1, v1p2, v1p3; + + Mat3x3 v2_mat; + V3f v2p0, v2p1, v2p2, v2p3; + + // Projection + V2u v0_p0 = project_v3f(v0p0); + V2u v0_p1 = project_v3f(v0p1); + V2u v0_p2 = project_v3f(v0p2); + V2u v0_p3 = project_v3f(v0p3); + + V2u v1_p0, v1_p1, v1_p2, v1_p3; + V2u v2_p0, v2_p1, v2_p2, v2_p3; + + SDL_Event event; + bool running = true; + + while (running) { + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_QUIT: + running = false; + break; + } + } + + rotation += 0.001f; + radians = RADIANS(rotation); + + // clang-format off + pos_rot_mat = MAT3x3( cosf(radians), -sinf(radians), 0.0f, + sinf(radians), cosf(radians), 0.0f, + 0.0f, 0.0f, 1.0f); + neg_rot_mat = MAT3x3(cosf(-radians), -sinf(-radians), 0.0f, + sinf(-radians), cosf(-radians), 0.0f, + 0.0f, 0.0f, 1.0f); + // clang-format on + + v1_mat = mat_mul(mat_mul(pos_v0_mid_xf, mat_mul(pos_rot_mat, mat0)), + neg_v0_mid_xf); + v1p0 = mat_mul_vec(v1_mat, v0p0); + v1p1 = mat_mul_vec(v1_mat, v0p1); + v1p2 = mat_mul_vec(v1_mat, v0p2); + v1p3 = mat_mul_vec(v1_mat, v0p3); + + v2_mat = mat_mul(mat_mul(pos_v0_mid_xf, mat_mul(neg_rot_mat, mat1)), + neg_v0_mid_xf); + v2p0 = mat_mul_vec(v2_mat, v0p0); + v2p1 = mat_mul_vec(v2_mat, v0p1); + v2p2 = mat_mul_vec(v2_mat, v0p2); + v2p3 = mat_mul_vec(v2_mat, v0p3); + + v1_p0 = project_v3f(v1p0); + v1_p1 = project_v3f(v1p1); + v1_p2 = project_v3f(v1p2); + v1_p3 = project_v3f(v1p3); + + v2_p0 = project_v3f(v2p0); + v2_p1 = project_v3f(v2p1); + v2_p2 = project_v3f(v2p2); + v2_p3 = project_v3f(v2p3); + + SDL_SetRenderDrawColor(renderer, 128, 128, 128, 255); + SDL_RenderClear(renderer); + + SDL_SetRenderDrawColor(renderer, 255, 64, 128, 255); + draw_line(renderer, &v0_p0, &v0_p1); + draw_line(renderer, &v0_p1, &v0_p3); + draw_line(renderer, &v0_p3, &v0_p2); + draw_line(renderer, &v0_p2, &v0_p0); + + SDL_SetRenderDrawColor(renderer, 64, 255, 128, 255); + draw_line(renderer, &v1_p0, &v1_p1); + draw_line(renderer, &v1_p1, &v1_p3); + draw_line(renderer, &v1_p3, &v1_p2); + draw_line(renderer, &v1_p2, &v1_p0); + + SDL_SetRenderDrawColor(renderer, 64, 128, 255, 255); + draw_line(renderer, &v2_p0, &v2_p1); + draw_line(renderer, &v2_p1, &v2_p3); + draw_line(renderer, &v2_p3, &v2_p2); + draw_line(renderer, &v2_p2, &v2_p0); + + SDL_RenderPresent(renderer); + } + + return 0; +} + +void draw_line(SDL_Renderer *renderer, const V2u *start, const V2u *end) { + SDL_RenderDrawLine(renderer, start->x, start->y, end->x, end->y); +}