This commit is contained in:
opfez 2021-11-14 14:05:24 +01:00
parent a539bf2b8f
commit f937f1cdbd
4 changed files with 318 additions and 206 deletions

View File

@ -1,46 +1,44 @@
# Blender v2.93.5 OBJ File: ''
# www.blender.org
mtllib cube.mtl
o Cube_Cube.002
v -50.000000 -50.000000 50.000000
v -50.000000 50.000000 50.000000
v -50.000000 -50.000000 -50.000000
v -50.000000 50.000000 -50.000000
v 50.000000 -50.000000 50.000000
v 50.000000 50.000000 50.000000
v 50.000000 -50.000000 -50.000000
v 50.000000 50.000000 -50.000000
o Cube
v 1.000000 1.000000 -1.000000
v 1.000000 -1.000000 -1.000000
v 1.000000 1.000000 1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 1.000000 -1.000000
v -1.000000 -1.000000 -1.000000
v -1.000000 1.000000 1.000000
v -1.000000 -1.000000 1.000000
vt 0.875000 0.500000
vt 0.625000 0.750000
vt 0.625000 0.500000
vt 0.375000 1.000000
vt 0.375000 0.750000
vt 0.625000 0.000000
vt 0.375000 0.250000
vt 0.375000 0.000000
vt 0.625000 0.250000
vt 0.375000 0.500000
vt 0.625000 0.500000
vt 0.375000 0.750000
vt 0.625000 0.750000
vt 0.375000 1.000000
vt 0.125000 0.750000
vt 0.125000 0.500000
vt 0.875000 0.500000
vt 0.625000 1.000000
vt 0.625000 0.250000
vt 0.875000 0.750000
vn -1.0000 0.0000 0.0000
vn 0.0000 0.0000 -1.0000
vn 1.0000 0.0000 0.0000
vn 0.0000 0.0000 1.0000
vn 0.0000 -1.0000 0.0000
vt 0.625000 1.000000
vn 0.0000 1.0000 0.0000
usemtl None
vn 0.0000 0.0000 1.0000
vn -1.0000 0.0000 0.0000
vn 0.0000 -1.0000 0.0000
vn 1.0000 0.0000 0.0000
vn 0.0000 0.0000 -1.0000
s off
f 2/1/1 3/2/1 1/3/1
f 4/4/2 7/5/2 3/2/2
f 8/6/3 5/7/3 7/5/3
f 6/8/4 1/9/4 5/7/4
f 7/5/5 1/10/5 3/11/5
f 4/12/6 6/8/6 8/6/6
f 2/1/1 4/4/1 3/2/1
f 4/4/2 8/6/2 7/5/2
f 8/6/3 6/8/3 5/7/3
f 6/8/4 2/13/4 1/9/4
f 7/5/5 5/7/5 1/10/5
f 4/12/6 2/14/6 6/8/6
f 5/1/1 3/2/1 1/3/1
f 3/2/2 8/4/2 4/5/2
f 7/6/3 6/7/3 8/8/3
f 2/9/4 8/10/4 6/11/4
f 1/3/5 4/5/5 2/9/5
f 5/12/6 2/9/6 6/7/6
f 5/1/1 7/13/1 3/2/1
f 3/2/2 7/14/2 8/4/2
f 7/6/3 5/12/3 6/7/3
f 2/9/4 4/5/4 8/10/4
f 1/3/5 3/2/5 4/5/5
f 5/12/6 1/3/6 2/9/6

86
iso.obj
View File

@ -1,49 +1,48 @@
# Blender v2.93.5 OBJ File: ''
# www.blender.org
mtllib iso.mtl
o Icosphere_Icosphere.001
v 0.000000 -100.000000 0.000000
v 72.360733 -44.721951 52.572529
v -27.638802 -44.721985 85.064926
v -89.442619 -44.721561 0.000000
v -27.638802 -44.721985 -85.064926
v 72.360733 -44.721951 -52.572529
v 27.638802 44.721985 85.064926
v -72.360733 44.721951 52.572529
v -72.360733 44.721951 -52.572529
v 27.638802 44.721985 -85.064926
v 89.442619 44.721561 0.000000
v 0.000000 100.000000 0.000000
v -16.245556 -85.065445 49.999527
v 42.532269 -85.065422 30.901140
v 26.286882 -52.573765 80.901161
v 85.064789 -52.573593 0.000000
v 42.532269 -85.065422 -30.901140
v -52.572979 -85.065170 0.000000
v -68.818939 -52.573620 49.999695
v -16.245556 -85.065445 -49.999527
v -68.818939 -52.573620 -49.999695
v 26.286882 -52.573765 -80.901161
v 95.105782 0.000000 30.901262
v 95.105782 0.000000 -30.901262
v 0.000000 0.000000 99.999992
v 58.778561 0.000000 80.901672
v -95.105782 0.000000 30.901262
v -58.778561 0.000000 80.901672
v -58.778561 0.000000 -80.901672
v -95.105782 0.000000 -30.901262
v 58.778561 0.000000 -80.901672
v 0.000000 0.000000 -99.999992
v 68.818939 52.573620 49.999695
v -26.286882 52.573765 80.901161
v -85.064789 52.573593 0.000000
v -26.286882 52.573765 -80.901161
v 68.818939 52.573620 -49.999695
v 16.245556 85.065437 49.999527
v 52.572979 85.065170 0.000000
v -42.532269 85.065422 30.901140
v -42.532269 85.065422 -30.901140
v 16.245556 85.065437 -49.999527
v 0.000000 -1.000000 0.000000
v 0.723607 -0.447220 0.525725
v -0.276388 -0.447220 0.850649
v -0.894426 -0.447216 0.000000
v -0.276388 -0.447220 -0.850649
v 0.723607 -0.447220 -0.525725
v 0.276388 0.447220 0.850649
v -0.723607 0.447220 0.525725
v -0.723607 0.447220 -0.525725
v 0.276388 0.447220 -0.850649
v 0.894426 0.447216 0.000000
v 0.000000 1.000000 0.000000
v -0.162456 -0.850654 0.499995
v 0.425323 -0.850654 0.309011
v 0.262869 -0.525738 0.809012
v 0.850648 -0.525736 0.000000
v 0.425323 -0.850654 -0.309011
v -0.525730 -0.850652 0.000000
v -0.688189 -0.525736 0.499997
v -0.162456 -0.850654 -0.499995
v -0.688189 -0.525736 -0.499997
v 0.262869 -0.525738 -0.809012
v 0.951058 0.000000 0.309013
v 0.951058 0.000000 -0.309013
v 0.000000 0.000000 1.000000
v 0.587786 0.000000 0.809017
v -0.951058 0.000000 0.309013
v -0.587786 0.000000 0.809017
v -0.587786 0.000000 -0.809017
v -0.951058 0.000000 -0.309013
v 0.587786 0.000000 -0.809017
v 0.000000 0.000000 -1.000000
v 0.688189 0.525736 0.499997
v -0.262869 0.525738 0.809012
v -0.850648 0.525736 0.000000
v -0.262869 0.525738 -0.809012
v 0.688189 0.525736 -0.499997
v 0.162456 0.850654 0.499995
v 0.525730 0.850652 0.000000
v -0.425323 0.850654 0.309011
v -0.425323 0.850654 -0.309011
v 0.162456 0.850654 -0.499995
vt 0.181819 0.000000
vt 0.227273 0.078731
vt 0.136365 0.078731
@ -187,7 +186,6 @@ vn 0.3313 -0.9435 0.0000
vn -0.0385 -0.6617 0.7488
vn 0.1876 -0.7947 0.5773
vn 0.4713 -0.6617 0.5831
usemtl None
s off
f 1/1/1 14/2/1 13/3/1
f 2/4/2 14/5/2 16/6/2

262
main.c
View File

@ -57,42 +57,30 @@ typedef struct {
uint32_t *indices;
} mesh;
vec3
vec3_matrix3x3_multiply(vec3 v, matrix3x3 r)
{
return (vec3) {
.x = (v.x * r.nums[0][0]) + (v.y * r.nums[0][1]) + (v.z * r.nums[0][2]),
.y = (v.x * r.nums[1][0]) + (v.y * r.nums[1][1]) + (v.z * r.nums[1][2]),
.z = (v.x * r.nums[2][0]) + (v.y * r.nums[2][1]) + (v.z * r.nums[2][2])
};
}
camera
new_camera(double znear, vec3 pos, vec3 target, vec3 up)
new_camera(double znear, vec3 pos, vec3 up, double yaw, double pitch)
{
if (pos.x == target.x &&
pos.y == target.y &&
pos.z == target.z)
die("cannot create camera with same target and position");
camera ret = {
.znear = znear,
.pos = pos,
.target = target,
.up = up,
.yaw = yaw,
.pitch = pitch
};
ret.dir = vec3_normalize(vec3_sub(pos, target));
ret.right = vec3_normalize(vec3_cross(up, ret.dir));
update_camera(&ret);
return ret;
}
mesh
new_mesh(uint32_t vertex_num,
uint32_t tri_num,
uint32_t index_num,
vec3 vertices[],
uint32_t indices[])
new_mesh(
uint32_t vertex_num,
uint32_t tri_num,
uint32_t index_num,
vec3 vertices[],
uint32_t indices[]
)
{
mesh ret;
@ -147,11 +135,13 @@ load_mesh(char *path)
mesh
copy_mesh(mesh orig)
{
return new_mesh(orig.vertex_num,
orig.tri_num,
orig.index_num,
orig.vertices,
orig.indices);
return new_mesh(
orig.vertex_num,
orig.tri_num,
orig.index_num,
orig.vertices,
orig.indices
);
}
void free_mesh(mesh mesh) { free(mesh.vertices); free(mesh.indices); }
@ -188,15 +178,17 @@ init_sdl(void)
sdl_state ret;
ret.window = SDL_CreateWindow("Game",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
W,
H,
// TODO: when we have a proper event loop, we can
// add resizing windows.
/* SDL_WINDOW_RESIZABLE | SDL_WINDOW_SHOWN); */
SDL_WINDOW_MOUSE_CAPTURE | SDL_WINDOW_SHOWN);
ret.window = SDL_CreateWindow(
"Game",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
W,
H,
// TODO: when we have a proper event loop, we can
// add resizing windows.
/* SDL_WINDOW_RESIZABLE | SDL_WINDOW_SHOWN); */
SDL_WINDOW_MOUSE_CAPTURE | SDL_WINDOW_SHOWN
);
ret.renderer = SDL_CreateRenderer(ret.window, -1, SDL_RENDERER_SOFTWARE);
SDL_SetRenderDrawColor(ret.renderer, 0, 0, 0, 255);
SDL_RenderClear(ret.renderer);
@ -502,13 +494,20 @@ midpoint(vec2 a, vec2 b)
};
}
vec2
project(camera c, vec3 v)
vec3
view_matricize(camera c, vec3 v)
{
vec3 u = vec3_sub(v, c.pos);
// TODO rotation
double r = c.znear / u.z;
return (vec2){W / 2 + r * u.x, H / 2 + r * u.y};
mat4x4 view = lookat(c);
vec4 tmp = vec4_mat4x4_mul(vec3_to_vec4(v), view);
return (vec3) {.x = tmp.x, .y = tmp.y, .z = tmp.z};
}
vec2
project(camera c, vec3 u)
{
double r = c.znear / (u.z);
return (vec2){(W / 2) * (u.x * r + 1), (H / 2) * (r * (-u.y) + 1) * (800.0 / 600.0)};
}
triangle2
@ -548,76 +547,66 @@ draw_mesh(rgb canvas[], rgb col, camera c, mesh mesh)
v1 = mesh.vertices[mesh.indices[3*i+1]],
v2 = mesh.vertices[mesh.indices[3*i+2]];
if (v0.z > c.znear && v1.z > c.znear && v2.z > c.znear) continue;
vec3 norm = vec3_normalize(vec3_cross(vec3_sub(v1, v0), vec3_sub(v2, v0)));
vec3 norm = vec3_normalize(
vec3_cross(vec3_sub(v1, v0), vec3_sub(v2, v0))
);
double x = vec3_dot(vec3_sub(v0, c.pos), norm);
if (wireframe) {
if (x < 0)
draw_triangle(canvas, col, project_triangle(c, (triangle3) {
v0, v1, v2
}));
/* else */
/* draw_triangle(canvas, */
/* (rgb) { */
/* .r = col.r * 0.2, */
/* .g = col.g * 0.2, */
/* .b = col.b * 0.2, */
/* .a = col.a */
/* }, */
/* project_triangle(c, (triangle3) { */
/* v0, v1, v2 */
/* })); */
vec3 us[3] = {view_matricize(c, v0), view_matricize(c, v1), view_matricize(c, v2)};
int skip_triangle = 0;
for (int i = 0; i < 3; i++) {
if (us[i].z > 0.0)
skip_triangle = 1;
}
else {
if (x < 0) {
double col_mod = clamp(vec3_dot(norm, vec3_normalize(c.pos)), 0.0, 1.0);
fill_triangle(canvas,
(rgb) {
.r = col.r * col_mod,
.g = col.g * col_mod,
.b = col.b * col_mod
},
project_triangle(c, (triangle3) {
v0, v1, v2
}));
if (!skip_triangle) {
if (wireframe) {
if (x < 0)
draw_triangle(canvas, col, project_triangle(c, (triangle3) {
us[0], us[1], us[2]
}));
/* else */
/* draw_triangle(canvas, */
/* (rgb) { */
/* .r = col.r * 0.2, */
/* .g = col.g * 0.2, */
/* .b = col.b * 0.2, */
/* .a = col.a */
/* }, */
/* project_triangle(c, (triangle3) { */
/* v0, v1, v2 */
/* })); */
}
else {
if (x < 0) {
double col_mod = clamp(
vec3_dot(norm, vec3_normalize((vec3){2,2,2})),
0.0, 1.0);
fill_triangle(canvas,
(rgb) {
.r = col.r * col_mod,
.g = col.g * col_mod,
.b = col.b * col_mod
},
project_triangle(c, (triangle3) {
us[0], us[1], us[2]
}));
}
}
}
}
}
matrix3x3
matrix3x3_multiply(matrix3x3 r, matrix3x3 s)
{
#define a r.nums
#define b s.nums
return (matrix3x3) {
.nums =
{{a[0][0] * b[0][0] + a[0][1] * b[1][0] + a[0][2] * b[2][0],
a[0][0] * b[0][1] + a[0][1] * b[1][1] + a[0][2] * b[2][1],
a[0][0] * b[0][2] + a[0][1] * b[1][2] + a[0][2] * b[2][2]},
{a[1][0] * b[0][0] + a[1][1] * b[1][0] + a[1][2] * b[2][0],
a[1][0] * b[0][1] + a[1][1] * b[1][1] + a[1][2] * b[2][1],
a[1][0] * b[0][2] + a[1][1] * b[1][2] + a[1][2] * b[2][2]},
{a[2][0] * b[0][0] + a[2][1] * b[1][0] + a[2][2] * b[2][0],
a[2][0] * b[0][1] + a[2][1] * b[1][1] + a[2][2] * b[2][1],
a[2][0] * b[0][2] + a[2][1] * b[1][2] + a[2][2] * b[2][2]}}
};
#undef a
#undef b
}
double
to_deg(double deg)
{
return deg * 2 * PI / 360.0;
}
matrix3x3
mat3x3
x_rotation(double deg)
{
return (matrix3x3) {
return (mat3x3) {
.nums =
{{1, 0, 0},
{0, cos(to_deg(deg)), -sin(to_deg(deg))},
@ -625,10 +614,10 @@ x_rotation(double deg)
};
}
matrix3x3
mat3x3
y_rotation(double deg)
{
return (matrix3x3) {
return (mat3x3) {
.nums =
{{ cos(to_deg(deg)), 0, sin(to_deg(deg))},
{ 0, 1, 0},
@ -636,10 +625,10 @@ y_rotation(double deg)
};
}
matrix3x3
mat3x3
z_rotation(double deg)
{
return (matrix3x3) {
return (mat3x3) {
.nums =
{{cos(to_deg(deg)), -sin(to_deg(deg)), 0},
{sin(to_deg(deg)), cos(to_deg(deg)), 0},
@ -653,14 +642,15 @@ int
main(void)
{
sdl_state state = init_sdl();
camera cam = new_camera(180, (vec3){0, 0, 200}, (vec3){0, 0, 0}, UP);
/* print_camera(cam); */
camera cam = new_camera(-1.0, (vec3){0, 1, 30}, UP, PI/2, 0.0);
print_camera(cam);
SDL_Event event;
const mesh obj = load_mesh("iso.mod");
mesh obj_copy = copy_mesh(obj);
const mesh iso = load_mesh("iso.mod");
mesh iso_copy = copy_mesh(iso);
const mesh plane = load_mesh("plane.mod");
mesh plane_copy = copy_mesh(plane);
uint64_t t = 0;
@ -668,41 +658,65 @@ main(void)
for (;;) {
double elapsed, start = SDL_GetPerformanceCounter();
matrix3x3 rotation = matrix3x3_multiply(
matrix3x3_multiply(
z_rotation(1.2 * t * rot_speed),
y_rotation(1.1 * t * rot_speed)),
x_rotation(1.0 * t * rot_speed));
mat3x3 rotation = mat3x3_mul(
mat3x3_mul(
z_rotation(1.0 * t * rot_speed),
y_rotation(1.2 * t * rot_speed)),
x_rotation(1.3 * t * rot_speed));
int x, y;
uint32_t buttons = SDL_GetMouseState(&x, &y);
clear_canvas(state.canvas, (rgb){7, 7, 7, 255});
for (size_t i = 0; i < obj.vertex_num; i++) {
obj_copy.vertices[i] = vec3_matrix3x3_multiply(obj.vertices[i], rotation);
for (size_t i = 0; i < iso.vertex_num; i++) {
iso_copy.vertices[i] = vec3_mat3x3_mul(iso.vertices[i], rotation);
}
draw_mesh(state.canvas, WHITE, cam, obj_copy);
draw_mesh(state.canvas, WHITE, cam, plane_copy);
draw_mesh(state.canvas, WHITE, cam, iso_copy);
render(state);
/* continuous keyboard events */
const uint8_t *keyboard = SDL_GetKeyboardState(NULL);
double velocity = 0.1;
if (keyboard[SDL_SCANCODE_W]) {
cam.pos = vec3_sub(cam.pos, vec3_scalar_mul(cam.front, velocity));
}
if (keyboard[SDL_SCANCODE_S]) {
cam.pos = vec3_add(cam.pos, vec3_scalar_mul(cam.front, velocity));
}
if (keyboard[SDL_SCANCODE_E]) {
cam.pos = vec3_add(cam.pos, vec3_scalar_mul(cam.right, velocity));
}
if (keyboard[SDL_SCANCODE_Q]) {
cam.pos = vec3_sub(cam.pos, vec3_scalar_mul(cam.right, velocity));
}
if (keyboard[SDL_SCANCODE_D]) {
cam.yaw -= 0.05;
}
if (keyboard[SDL_SCANCODE_A]) {
cam.yaw += 0.05;
}
update_camera(&cam);
/* other events */
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_KEYDOWN: {
case SDL_KEYDOWN:
switch (event.key.keysym.scancode) {
case SDL_SCANCODE_F3: {
case SDL_SCANCODE_F3:
if (!event.key.repeat) wireframe = !wireframe;
break;
}
case SDL_SCANCODE_F6: {
case SDL_SCANCODE_F6:
if (!event.key.repeat) screenshot(state.canvas);
break;
}
default:
break;
}
break;
}
case SDL_QUIT:
goto quit;
}
@ -715,7 +729,9 @@ main(void)
}
quit:
free_mesh(obj);
free_mesh(obj_copy);
free_mesh(iso);
free_mesh(iso_copy);
free_mesh(plane);
free_mesh(plane_copy);
free_sdl(state);
}

108
types.h
View File

@ -35,21 +35,22 @@ STRUCT(vec4)
FIELD(w, double)
END_STRUCT
STRUCT(matrix3x3)
STRUCT(mat3x3)
FIELD(nums, grid3x3)
END_STRUCT
STRUCT(matrix4x4)
STRUCT(mat4x4)
FIELD(nums, grid4x4)
END_STRUCT
STRUCT(camera)
FIELD(znear, double)
FIELD(pos, vec3)
FIELD(target, vec3)
FIELD(front, vec3)
FIELD(up, vec3)
FIELD(dir, vec3)
FIELD(right, vec3)
FIELD(yaw, double)
FIELD(pitch, double)
END_STRUCT
#else
@ -120,6 +121,16 @@ vec3_sub(vec3 u, vec3 v)
};
}
vec3
vec3_scalar_mul(vec3 v, double s)
{
return (vec3) {
.x = v.x * s,
.y = v.y * s,
.z = v.z * s,
};
}
vec3
vec3_cross(vec3 u, vec3 v)
{
@ -147,6 +158,12 @@ vec3_normalize(vec3 u)
};
}
vec4
vec3_to_vec4(vec3 v)
{
return (vec4){v.x, v.y, v.z, 1.0};
}
vec4
vec4_add(vec4 u, vec4 v)
{
@ -169,6 +186,89 @@ vec4_sub(vec4 u, vec4 v)
};
}
void
mat_mul(size_t dim, double m1[dim][dim], double m2[dim][dim], double out[dim][dim])
{
for (size_t i = 0; i < dim; i++) {
for (size_t j = 0; j < dim; j++) {
for (size_t k = 0; k < dim; k++) {
out[i][j] += m1[i][k] * m2[k][j];
}
}
}
}
mat3x3
mat3x3_mul(mat3x3 r, mat3x3 s)
{
mat3x3 ret = { .nums = {{0}} };
mat_mul(3, r.nums, s.nums, ret.nums);
return ret;
}
mat4x4
mat4x4_mul(mat4x4 r, mat4x4 s)
{
mat4x4 ret = { .nums = {{0}} };
mat_mul(4, r.nums, s.nums, ret.nums);
return ret;
}
vec3
vec3_mat3x3_mul(vec3 v, mat3x3 r)
{
return (vec3) {
.x = (v.x * r.nums[0][0]) + (v.y * r.nums[0][1]) + (v.z * r.nums[0][2]),
.y = (v.x * r.nums[1][0]) + (v.y * r.nums[1][1]) + (v.z * r.nums[1][2]),
.z = (v.x * r.nums[2][0]) + (v.y * r.nums[2][1]) + (v.z * r.nums[2][2])
};
}
vec4
vec4_mat4x4_mul(vec4 v, mat4x4 r)
{
return (vec4) {
.x = (v.x * r.nums[0][0]) + (v.y * r.nums[0][1]) + (v.z * r.nums[0][2]) + (v.w * r.nums[0][3]),
.y = (v.x * r.nums[1][0]) + (v.y * r.nums[1][1]) + (v.z * r.nums[1][2]) + (v.w * r.nums[1][3]),
.z = (v.x * r.nums[2][0]) + (v.y * r.nums[2][1]) + (v.z * r.nums[2][2]) + (v.w * r.nums[2][3]),
.w = (v.x * r.nums[3][0]) + (v.y * r.nums[3][1]) + (v.z * r.nums[3][2]) + (v.w * r.nums[3][3])
};
}
mat4x4
lookat(camera cam)
{
/* vec3 dir = vec3_add(cam.pos, cam.front); */
return mat4x4_mul(
(mat4x4) {
.nums = {{cam.right.x, cam.right.y, cam.right.z, 0},
{cam.up.x, cam.up.y, cam.up.z, 0},
{cam.front.x, cam.front.y, cam.front.z, 0},
{0, 0, 0, 1}}
},
(mat4x4) {
.nums = {{1, 0, 0, -cam.pos.x},
{0, 1, 0, -cam.pos.y},
{0, 0, 1, -cam.pos.z},
{0, 0, 0, 1}}
}
);
}
void
update_camera(camera *cam)
{
vec3 front = {
.x = cos(cam->yaw) * cos(cam->pitch),
.y = sin(cam->pitch),
.z = sin(cam->yaw) * cos(cam->pitch)
};
cam->front = vec3_normalize(front);
cam->right = vec3_normalize(vec3_cross(cam->front, cam->up));
/* cam->up = vec3_normalize(vec3_cross(cam->right, cam->front)); */
}
#endif
#endif /* SUB_INCLUDE_TYPES */