Playing with shear, scale, rotation and translation matrices

This commit is contained in:
Abdelrahman Said 2024-08-11 03:15:05 +01:00
parent 3e2fbf2c58
commit a05083061b

223
main.c Normal file
View File

@ -0,0 +1,223 @@
/**
* Playing around with matrices while studying
* https://github.com/ssloy/tinyrenderer/wiki/Lesson-4:-Perspective-projection
*/
#include <SDL2/SDL.h>
#include <SDL2/SDL_events.h>
#include <SDL2/SDL_rect.h>
#include <SDL2/SDL_render.h>
#include <SDL2/SDL_video.h>
#include <math.h>
#include <stdbool.h>
#include <stdint.h>
#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);
}