traza/main.c

722 lines
18 KiB
C
Raw Normal View History

2021-11-05 21:12:14 +00:00
#define DEBUG
2021-09-26 17:10:41 +00:00
#include <assert.h>
2021-09-25 22:09:49 +00:00
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <time.h>
2021-10-24 09:20:10 +00:00
#include <math.h>
2021-09-25 22:09:49 +00:00
#include <SDL2/SDL.h>
2021-11-05 21:12:14 +00:00
/* cursed struct definitions, thanks bx */
2021-11-13 14:49:42 +00:00
#define TYPES_IMPL
2021-11-05 21:12:14 +00:00
#include "types.h"
2021-09-25 22:09:49 +00:00
#define W 800
#define H 600
2021-09-28 15:34:53 +00:00
#define PI 3.14159265358979323844
2021-09-25 22:09:49 +00:00
2021-11-12 16:04:23 +00:00
int wireframe = 1;
2021-11-05 21:12:14 +00:00
void
die(char *msg)
{
fprintf(stderr, "%s\n", msg);
exit(1);
}
const rgb WHITE = {255, 255, 255, 255};
const rgb BLACK = {0, 0, 0, 255};
2021-11-13 22:39:49 +00:00
const rgb RED = {255, 60, 40, 255};
const rgb GREEN = {40, 255, 70, 255};
const rgb BLUE = {50, 70, 255, 255};
2021-09-25 22:09:49 +00:00
2021-11-12 16:04:23 +00:00
const vec3 UP = {0, 1, 0};
2021-09-25 22:09:49 +00:00
typedef struct {
SDL_Renderer *renderer;
SDL_Window *window;
SDL_Texture *tex;
2021-11-05 21:12:14 +00:00
rgb *canvas;
} sdl_state;
2021-09-25 22:09:49 +00:00
typedef struct {
2021-11-05 21:12:14 +00:00
vec2 a, b, c;
} triangle2;
2021-09-25 22:09:49 +00:00
2021-10-23 08:51:41 +00:00
typedef struct {
2021-11-05 21:12:14 +00:00
vec3 a, b, c;
} triangle3;
2021-10-24 09:20:10 +00:00
typedef struct {
2021-10-27 19:51:30 +00:00
uint32_t vertex_num;
uint32_t tri_num; /* for loops */
uint32_t index_num;
2021-11-05 21:12:14 +00:00
vec3 *vertices;
2021-10-27 19:51:30 +00:00
uint32_t *indices;
2021-11-05 21:12:14 +00:00
} mesh;
2021-10-24 09:20:10 +00:00
2021-11-05 21:12:14 +00:00
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)
2021-11-05 21:12:14 +00:00
{
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,
2021-11-05 21:12:14 +00:00
.pos = pos,
.target = target,
.up = up,
};
ret.dir = vec3_normalize(vec3_sub(pos, target));
ret.right = vec3_normalize(vec3_cross(up, ret.dir));
return ret;
}
2021-10-27 19:51:30 +00:00
2021-11-05 21:12:14 +00:00
mesh
2021-11-13 14:49:42 +00:00
new_mesh(uint32_t vertex_num,
uint32_t tri_num,
uint32_t index_num,
vec3 vertices[],
uint32_t indices[])
2021-10-24 09:20:10 +00:00
{
2021-11-05 21:12:14 +00:00
mesh ret;
2021-10-24 09:20:10 +00:00
2021-10-27 19:51:30 +00:00
ret.vertex_num = vertex_num;
ret.tri_num = tri_num;
ret.index_num = index_num;
2021-11-05 21:12:14 +00:00
ret.vertices = malloc(sizeof(vec3) * vertex_num);
2021-10-27 19:51:30 +00:00
for (uint32_t i = 0; i < vertex_num; i++)
ret.vertices[i] = vertices[i];
ret.indices = malloc(sizeof(uint32_t) * index_num);
for (uint32_t i = 0; i < index_num; i++)
ret.indices[i] = indices[i];
2021-10-24 09:20:10 +00:00
return ret;
}
2021-11-13 14:49:42 +00:00
mesh
load_mesh(char *path)
{
mesh ret;
FILE *f = fopen(path, "r");
2021-11-13 14:53:26 +00:00
if (f == NULL)
die("load_mesh: couldn't open model");
2021-11-13 14:49:42 +00:00
/* Vertices */
fread(&ret.vertex_num, 4, 1, f);
ret.vertices = malloc(sizeof(vec3) * ret.vertex_num);
for (uint32_t i = 0; i < ret.vertex_num; i++) {
fread(&ret.vertices[i].x, 8, 1, f);
fread(&ret.vertices[i].y, 8, 1, f);
fread(&ret.vertices[i].z, 8, 1, f);
}
/* Indices */
fread(&ret.index_num, 4, 1, f);
if (ret.index_num % 3 != 0) {
free(ret.vertices);
die("load_mesh: invalid number of indices, should be a multiple of 3");
}
ret.tri_num = ret.index_num / 3;
ret.indices = malloc(sizeof(uint32_t) * ret.index_num);
for (uint32_t i = 0; i < ret.index_num; i++)
fread(&ret.indices[i], 4, 1, f);
return ret;
}
mesh
copy_mesh(mesh orig)
{
return new_mesh(orig.vertex_num,
orig.tri_num,
orig.index_num,
orig.vertices,
orig.indices);
}
2021-11-05 21:12:14 +00:00
void free_mesh(mesh mesh) { free(mesh.vertices); free(mesh.indices); }
2021-09-25 22:09:49 +00:00
#define max(x, y) ((x) > (y) ? (x) : (y))
#define min(x, y) ((x) < (y) ? (x) : (y))
#define swap(x, y) do { \
2021-10-23 08:51:41 +00:00
(x) ^= (y); \
(y) ^= (x); \
(x) ^= (y); \
2021-09-25 22:09:49 +00:00
} while (0)
2021-11-05 21:12:14 +00:00
#define clamp(x, min, max) (((x) >= (min)) ? ((x) <= (max)) ? (x) : (max) : (min))
2021-09-25 22:09:49 +00:00
2021-10-23 08:51:41 +00:00
void
swapd(double *a, double *b)
{
double tmp = *a;
*a = *b;
*b = tmp;
}
2021-11-05 21:12:14 +00:00
void clear_canvas(rgb canvas[], rgb colour);
sdl_state init_sdl(void);
void free_sdl(sdl_state state);
void render(sdl_state state);
void plot_rgb(rgb canvas[], int32_t x, int32_t y, rgb colour);
void draw_line(rgb canvas[], rgb c, vec2 p0, vec2 p1);
vec2 project(camera c, vec3 v);
2021-09-25 22:09:49 +00:00
2021-11-05 21:12:14 +00:00
sdl_state
2021-09-25 22:09:49 +00:00
init_sdl(void)
{
SDL_Init(SDL_INIT_VIDEO);
2021-11-05 21:12:14 +00:00
sdl_state ret;
2021-09-25 22:09:49 +00:00
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);
SDL_RenderPresent(ret.renderer);
ret.tex = SDL_CreateTexture(ret.renderer,
SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STATIC,
W, H);
2021-11-05 21:12:14 +00:00
ret.canvas = malloc(sizeof(rgb) * W * H);
clear_canvas(ret.canvas, (rgb){0, 0, 0, 255});
2021-09-25 22:09:49 +00:00
return ret;
}
void
2021-11-05 21:12:14 +00:00
free_sdl(sdl_state state)
2021-09-25 22:09:49 +00:00
{
SDL_DestroyRenderer(state.renderer);
SDL_DestroyWindow(state.window);
SDL_DestroyTexture(state.tex);
2021-09-25 22:09:49 +00:00
free(state.canvas);
SDL_Quit();
}
uint32_t
2021-11-05 21:12:14 +00:00
rgb_to_int(rgb c)
{
return (((uint32_t)c.a << 24)
| ((uint32_t)c.r << 16)
| ((uint32_t)c.g << 8)
| ((uint32_t)c.b));
}
2021-09-27 08:00:13 +00:00
/* display the contents of the canvas */
2021-10-23 08:51:41 +00:00
void
2021-11-05 21:12:14 +00:00
render(sdl_state state)
2021-09-25 22:09:49 +00:00
{
uint32_t pixels[H*W];
2021-09-25 22:09:49 +00:00
for (size_t y = 0; y < H; y++) {
for (size_t x = 0; x < W; x++) {
pixels[x + y * W] = rgb_to_int(state.canvas[x + y * W]);
2021-09-25 22:09:49 +00:00
}
}
SDL_UpdateTexture(state.tex, NULL, pixels, W * sizeof(uint32_t));
2021-09-25 22:09:49 +00:00
/* present the texture */
SDL_RenderCopy(state.renderer, state.tex, NULL, NULL);
2021-09-25 22:09:49 +00:00
SDL_RenderPresent(state.renderer);
}
2021-11-12 16:04:23 +00:00
2021-09-25 22:09:49 +00:00
void
2021-11-05 21:12:14 +00:00
plot_rgb(rgb canvas[], int32_t x, int32_t y, rgb colour)
2021-09-25 22:09:49 +00:00
{
2021-10-27 19:51:30 +00:00
if (x < W && y < H && x >= 0 && y >= 0)
2021-09-25 22:09:49 +00:00
canvas[x + y * W] = colour;
}
void
2021-11-05 21:12:14 +00:00
clear_canvas_trailing(rgb canvas[], rgb colour)
2021-09-25 22:09:49 +00:00
{
2021-09-28 15:34:53 +00:00
for (size_t i = 0; i < W * H; i++)
2021-10-27 19:51:30 +00:00
if ((rand()&31)==0) canvas[i] = colour;
}
void
2021-11-05 21:12:14 +00:00
clear_canvas(rgb canvas[], rgb colour)
2021-10-27 19:51:30 +00:00
{
for (size_t i = 0; i < W * H; i += 2) {
2021-09-28 15:34:53 +00:00
canvas[i] = colour;
2021-10-27 19:51:30 +00:00
canvas[i+1] = colour;
}
2021-09-25 22:09:49 +00:00
}
void
2021-11-05 21:12:14 +00:00
draw_line(rgb canvas[], rgb c, vec2 p0, vec2 p1)
2021-09-25 22:09:49 +00:00
{
2021-10-27 19:51:30 +00:00
int32_t x0 = (int32_t)p0.x,
x1 = (int32_t)p1.x,
y0 = (int32_t)p0.y,
y1 = (int32_t)p1.y;
2021-10-23 08:51:41 +00:00
2021-09-25 22:09:49 +00:00
if (x0 > x1) {
swap(x0, x1);
swap(y0, y1);
}
2021-11-12 16:04:23 +00:00
int dx = abs(x1 - x0);
int dy = abs(y1 - y0);
int s = y1 > y0 ? 1 : -1;
int eps = 0;
2021-11-06 11:07:50 +00:00
if (dy < dx) {
2021-11-12 16:04:23 +00:00
int y = y0;
for (int x = x0; x <= x1; x++) {
2021-11-06 11:07:50 +00:00
plot_rgb(canvas, x, y, c);
eps += dy;
if ((eps * 2) >= dx) {
y += s;
eps -= dx;
2021-09-25 22:09:49 +00:00
}
}
}
else {
2021-11-12 16:04:23 +00:00
if (y0 >= y1) {
swap(y0, y1);
swap(x0, x1);
}
int x = x0;
for (int y = y0; y <= y1; y++) {
2021-11-06 11:07:50 +00:00
plot_rgb(canvas, x, y, c);
eps += dx;
if ((eps * 2) >= dy) {
x += s;
eps -= dy;
2021-09-25 22:09:49 +00:00
}
}
}
}
2021-09-26 17:10:41 +00:00
void
2021-11-05 21:12:14 +00:00
draw_horizontal_line(rgb canvas[], rgb c, int32_t x0, int32_t x1, int32_t y)
2021-09-26 17:10:41 +00:00
{
2021-11-12 16:04:23 +00:00
if (y < 0) return;
2021-11-05 21:12:14 +00:00
if (x0 < 0) x0 = 0;
if (x1 >= W) x1 = W - 1;
2021-11-12 16:04:23 +00:00
if (y >= H) return;
2021-11-05 21:12:14 +00:00
for (int32_t x = x0; x <= x1; x++)
canvas[x + y * W] = c;
2021-09-26 17:10:41 +00:00
}
2021-09-25 22:09:49 +00:00
void
2021-11-05 21:12:14 +00:00
draw_triangle(rgb canvas[], rgb col, triangle2 tri)
2021-09-25 22:09:49 +00:00
{
2021-10-24 09:20:10 +00:00
draw_line(canvas, col, tri.a, tri.b);
draw_line(canvas, col, tri.b, tri.c);
draw_line(canvas, col, tri.c, tri.a);
2021-09-25 22:09:49 +00:00
}
2021-09-26 17:10:41 +00:00
void
2021-11-05 21:12:14 +00:00
fill_bottom_flat_triangle(rgb canvas[], rgb c, triangle2 tri)
2021-09-26 17:10:41 +00:00
{
2021-11-05 21:12:14 +00:00
if (tri.b.x > tri.c.x)
2021-10-23 08:51:41 +00:00
swapd(&tri.b.x, &tri.c.x);
2021-09-26 17:10:41 +00:00
2021-11-05 21:12:14 +00:00
/* tri.a x
* / \
* / \
* tri.b x_____x tri.c
*/
2021-09-26 17:10:41 +00:00
2021-11-05 21:12:14 +00:00
int32_t ax = (int32_t)tri.a.x,
bx = (int32_t)tri.b.x,
cx = (int32_t)tri.c.x,
ay = (int32_t)tri.a.y,
by = (int32_t)tri.b.y,
cy = (int32_t)tri.c.y;
assert(ay <= cy);
assert(ay <= by);
assert(bx <= cx);
int32_t dx_right = abs(cx - ax);
int32_t dy_right = abs(cy - ay);
int32_t dx_left = abs(bx - ax);
int32_t dy_left = abs(by - ay);
int32_t eps_r = 0;
int32_t eps_l = 0;
int32_t xr = ax;
int32_t xl = ax;
int32_t xr_change = ax < cx ? 1 : -1;
int32_t xl_change = ax < bx ? 1 : -1;
for (int32_t y = ay; y < by; y++) {
eps_r += dx_right;
eps_l += dx_left;
while (eps_r > 0) {
eps_r -= dy_right;
xr += xr_change;
}
while (eps_l > 0) {
eps_l -= dy_left;
xl += xl_change;
}
draw_horizontal_line(canvas, c, xl, xr, y);
2021-09-26 17:10:41 +00:00
}
}
void
2021-11-05 21:12:14 +00:00
fill_top_flat_triangle(rgb canvas[], rgb c, triangle2 tri)
2021-09-26 17:10:41 +00:00
{
2021-11-05 21:12:14 +00:00
if (tri.a.x > tri.b.x)
2021-10-23 08:51:41 +00:00
swapd(&tri.a.x, &tri.b.x);
2021-09-26 17:10:41 +00:00
2021-11-05 21:12:14 +00:00
/* tri.a x_____x tri.b
* \ /
* \ /
* tri.c x
*/
2021-09-26 17:10:41 +00:00
2021-11-05 21:12:14 +00:00
int32_t ax = (int32_t)tri.a.x,
bx = (int32_t)tri.b.x,
cx = (int32_t)tri.c.x,
ay = (int32_t)tri.a.y,
by = (int32_t)tri.b.y,
cy = (int32_t)tri.c.y;
assert(cy >= ay);
assert(cy >= by);
assert(ax <= bx);
int32_t dx_right = abs(cx - bx);
int32_t dy_right = abs(cy - by);
int32_t dx_left = abs(cx - ax);
int32_t dy_left = abs(cy - ay);
int32_t eps_r = 0;
int32_t eps_l = 0;
int32_t xr = cx;
int32_t xl = cx;
int32_t xr_change = cx < bx ? 1 : -1;
int32_t xl_change = cx < ax ? 1 : -1;
int32_t y;
2021-11-13 18:01:37 +00:00
for (y = cy-1; y > by; y--) {
2021-11-05 21:12:14 +00:00
eps_r += dx_right;
eps_l += dx_left;
while (eps_r > 0) {
eps_r -= dy_right;
xr += xr_change;
}
while (eps_l > 0) {
eps_l -= dy_left;
xl += xl_change;
}
draw_horizontal_line(canvas, c, xl, xr, y);
}
2021-09-26 17:10:41 +00:00
2021-11-05 21:12:14 +00:00
/* We're missing one line, but setting the loop conditional to be y >= by
* messes up the drawing.
2021-10-27 19:51:30 +00:00
*/
2021-11-05 21:12:14 +00:00
draw_horizontal_line(canvas, c, xl, xr, y);
2021-09-26 17:10:41 +00:00
}
/* http://www.sunshine2k.de/coding/java/TriangleRasterization/TriangleRasterization.html */
void
2021-11-05 21:12:14 +00:00
fill_triangle(rgb canvas[], rgb c, triangle2 tri)
2021-09-26 17:10:41 +00:00
{
/* tri.a <= tri.b <= tri.c */
if (tri.b.y < tri.a.y) {
2021-10-23 08:51:41 +00:00
swapd(&tri.b.y, &tri.a.y);
swapd(&tri.b.x, &tri.a.x);
2021-09-26 17:10:41 +00:00
}
if (tri.c.y < tri.a.y) {
2021-10-23 08:51:41 +00:00
swapd(&tri.c.y, &tri.a.y);
swapd(&tri.c.x, &tri.a.x);
2021-10-27 19:51:30 +00:00
}
2021-09-26 17:10:41 +00:00
if (tri.c.y < tri.b.y) {
2021-10-23 08:51:41 +00:00
swapd(&tri.c.y, &tri.b.y);
swapd(&tri.c.x, &tri.b.x);
2021-09-26 17:10:41 +00:00
}
/* simple solutions */
2021-11-05 21:12:14 +00:00
if ((int32_t)tri.b.y == (int32_t)tri.c.y) {
2021-09-26 17:10:41 +00:00
fill_bottom_flat_triangle(canvas, c, tri);
}
2021-11-05 21:12:14 +00:00
else if ((int32_t)tri.a.y == (int32_t)tri.b.y) {
2021-09-26 17:10:41 +00:00
fill_top_flat_triangle(canvas, c, tri);
}
else {
2021-11-05 21:12:14 +00:00
vec2 trid = {
2021-11-12 16:04:23 +00:00
(tri.a.x + (tri.b.y - tri.a.y) / (tri.c.y - tri.a.y) * (tri.c.x - tri.a.x)),
2021-09-26 17:10:41 +00:00
tri.b.y};
if (tri.a.y > tri.b.y) {
2021-10-23 08:51:41 +00:00
swapd(&tri.a.y, &tri.b.y);
swapd(&tri.a.x, &tri.b.x);
2021-09-26 17:10:41 +00:00
}
2021-11-05 21:12:14 +00:00
fill_top_flat_triangle(canvas, c, (triangle2) {
2021-09-26 17:10:41 +00:00
tri.b, trid, tri.c
});
2021-11-05 21:12:14 +00:00
fill_bottom_flat_triangle(canvas, c, (triangle2) {
tri.a, tri.b, trid
});
2021-09-26 17:10:41 +00:00
}
}
2021-11-05 21:12:14 +00:00
vec2
midpoint(vec2 a, vec2 b)
2021-09-25 22:09:49 +00:00
{
2021-11-05 21:12:14 +00:00
return (vec2) {
2021-09-25 22:09:49 +00:00
(a.x + b.x) / 2,
(a.y + b.y) / 2
};
}
2021-11-05 21:12:14 +00:00
vec2
project(camera c, vec3 v)
2021-10-23 08:51:41 +00:00
{
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};
2021-10-23 08:51:41 +00:00
}
2021-11-05 21:12:14 +00:00
triangle2
project_triangle(camera c, triangle3 tri)
2021-10-24 09:20:10 +00:00
{
2021-11-05 21:12:14 +00:00
return (triangle2) {
2021-10-24 09:20:10 +00:00
.a = project(c, tri.a),
.b = project(c, tri.b),
.c = project(c, tri.c),
};
}
2021-09-25 22:09:49 +00:00
/* saves canvas as a P6 image */
void
2021-11-05 21:12:14 +00:00
screenshot(rgb canvas[])
2021-09-25 22:09:49 +00:00
{
time_t t = time(NULL);
char output[64];
2021-11-12 16:04:23 +00:00
strftime(output, sizeof(output), "screenshot-%Y%m%d-%H%M%S.ppm", localtime(&t));
2021-09-25 22:09:49 +00:00
FILE *out = fopen(output, "w");
fprintf(out, "P6\n%d %d\n255\n", W, H);
for (int y = 0; y < H; y++) {
for (int x = 0; x < W; x++) {
2021-11-05 21:12:14 +00:00
rgb cur = canvas[x + y * W];
2021-09-25 22:09:49 +00:00
fprintf(out, "%c%c%c", cur.r, cur.g, cur.b);
}
}
fclose(out);
fprintf(stderr, "Saved %s\n", output);
}
2021-09-26 17:10:41 +00:00
void
2021-11-05 21:12:14 +00:00
draw_mesh(rgb canvas[], rgb col, camera c, mesh mesh)
2021-10-23 08:51:41 +00:00
{
2021-10-27 19:51:30 +00:00
for (uint32_t i = 0; i < mesh.tri_num; i++) {
vec3 v0 = mesh.vertices[mesh.indices[3*i ]],
v1 = mesh.vertices[mesh.indices[3*i+1]],
v2 = mesh.vertices[mesh.indices[3*i+2]];
2021-11-13 18:01:37 +00:00
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)));
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 */
/* })); */
}
else {
if (x < 0) {
2021-11-13 22:39:49 +00:00
double col_mod = clamp(vec3_dot(norm, vec3_normalize(c.pos)), 0.0, 1.0);
fill_triangle(canvas,
(rgb) {
2021-11-13 22:39:49 +00:00
.r = col.r * col_mod,
.g = col.g * col_mod,
.b = col.b * col_mod
},
project_triangle(c, (triangle3) {
v0, v1, v2
}));
}
}
2021-10-23 08:51:41 +00:00
}
}
2021-11-05 21:12:14 +00:00
matrix3x3
matrix3x3_multiply(matrix3x3 r, matrix3x3 s)
2021-10-27 19:51:30 +00:00
{
#define a r.nums
#define b s.nums
2021-11-05 21:12:14 +00:00
return (matrix3x3) {
2021-10-27 19:51:30 +00:00
.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
}
2021-11-05 21:12:14 +00:00
double
to_deg(double deg)
{
return deg * 2 * PI / 360.0;
}
matrix3x3
2021-10-27 19:51:30 +00:00
x_rotation(double deg)
{
2021-11-05 21:12:14 +00:00
return (matrix3x3) {
2021-10-27 19:51:30 +00:00
.nums =
2021-11-05 21:12:14 +00:00
{{1, 0, 0},
{0, cos(to_deg(deg)), -sin(to_deg(deg))},
{0, sin(to_deg(deg)), cos(to_deg(deg))}}
2021-10-27 19:51:30 +00:00
};
}
2021-11-05 21:12:14 +00:00
matrix3x3
2021-10-27 19:51:30 +00:00
y_rotation(double deg)
{
2021-11-05 21:12:14 +00:00
return (matrix3x3) {
2021-10-27 19:51:30 +00:00
.nums =
2021-11-05 21:12:14 +00:00
{{ cos(to_deg(deg)), 0, sin(to_deg(deg))},
{ 0, 1, 0},
{-sin(to_deg(deg)), 0, cos(to_deg(deg))}}
2021-10-27 19:51:30 +00:00
};
}
2021-11-05 21:12:14 +00:00
matrix3x3
2021-10-27 19:51:30 +00:00
z_rotation(double deg)
{
2021-11-05 21:12:14 +00:00
return (matrix3x3) {
2021-10-27 19:51:30 +00:00
.nums =
2021-11-05 21:12:14 +00:00
{{cos(to_deg(deg)), -sin(to_deg(deg)), 0},
{sin(to_deg(deg)), cos(to_deg(deg)), 0},
{0, 0, 1}}
2021-10-27 19:51:30 +00:00
};
}
2021-11-05 21:12:14 +00:00
#include "other.h"
2021-10-27 19:51:30 +00:00
2021-09-25 22:09:49 +00:00
int
main(void)
{
2021-11-05 21:12:14 +00:00
sdl_state state = init_sdl();
camera cam = new_camera(180, (vec3){0, 0, 200}, (vec3){0, 0, 0}, UP);
2021-11-13 22:39:49 +00:00
2021-11-13 14:49:42 +00:00
/* print_camera(cam); */
2021-09-25 22:09:49 +00:00
SDL_Event event;
2021-10-24 09:20:10 +00:00
2021-11-13 14:49:42 +00:00
const mesh obj = load_mesh("iso.mod");
mesh obj_copy = copy_mesh(obj);
2021-10-24 09:20:10 +00:00
2021-10-27 19:51:30 +00:00
uint64_t t = 0;
2021-10-24 09:20:10 +00:00
2021-11-13 22:39:49 +00:00
double rot_speed = 0.6;
2021-09-25 22:09:49 +00:00
for (;;) {
2021-11-05 21:12:14 +00:00
double elapsed, start = SDL_GetPerformanceCounter();
2021-11-12 16:04:23 +00:00
matrix3x3 rotation = matrix3x3_multiply(
2021-10-27 19:51:30 +00:00
matrix3x3_multiply(
z_rotation(1.2 * t * rot_speed),
y_rotation(1.1 * t * rot_speed)),
x_rotation(1.0 * t * rot_speed));
2021-10-23 08:51:41 +00:00
2021-10-27 19:51:30 +00:00
int x, y;
uint32_t buttons = SDL_GetMouseState(&x, &y);
2021-10-23 08:51:41 +00:00
2021-11-13 22:39:49 +00:00
clear_canvas(state.canvas, (rgb){7, 7, 7, 255});
2021-10-24 09:20:10 +00:00
2021-11-13 14:49:42 +00:00
for (size_t i = 0; i < obj.vertex_num; i++) {
obj_copy.vertices[i] = vec3_matrix3x3_multiply(obj.vertices[i], rotation);
2021-10-24 09:20:10 +00:00
}
2021-11-13 14:49:42 +00:00
draw_mesh(state.canvas, WHITE, cam, obj_copy);
2021-09-25 22:09:49 +00:00
render(state);
2021-11-13 22:39:49 +00:00
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_KEYDOWN: {
switch (event.key.keysym.scancode) {
case SDL_SCANCODE_F3: {
if (!event.key.repeat) wireframe = !wireframe;
break;
}
case SDL_SCANCODE_F6: {
if (!event.key.repeat) screenshot(state.canvas);
break;
}
default:
break;
}
break;
}
case SDL_QUIT:
goto quit;
}
}
2021-10-24 09:20:10 +00:00
2021-11-12 16:04:23 +00:00
elapsed = (SDL_GetPerformanceCounter() - start) / (double)SDL_GetPerformanceFrequency() * 1000.0;
2021-11-05 21:12:14 +00:00
SDL_Delay(clamp(16.666f - elapsed, 0, 1000));
2021-10-27 19:51:30 +00:00
t++;
2021-09-25 22:09:49 +00:00
}
2021-11-13 22:39:49 +00:00
quit:
2021-11-13 14:49:42 +00:00
free_mesh(obj);
free_mesh(obj_copy);
2021-09-25 22:09:49 +00:00
free_sdl(state);
}