254 lines
7.2 KiB
C
254 lines
7.2 KiB
C
#include "rasteriser/rasteriser.h"
|
|
#include "aliases.h"
|
|
#include "list/typed_list.h"
|
|
#include "math/math_utils.h"
|
|
#include "mem_arena.h"
|
|
#include "vector/vec.h"
|
|
#include "window/window.h"
|
|
#include <assert.h>
|
|
#include <math.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/mman.h>
|
|
|
|
internal list_float *interpolate(Arena *arena, i32 i0, f32 d0, i32 i1, f32 d1);
|
|
internal inline void order_triangle_points(triangle_t *triangle);
|
|
|
|
void render_instance(window_t *wnd, Arena *arena, mat3x4f_t proj_cam_mat,
|
|
const instance_t *instance) {
|
|
list_vec2i_t *projected = list_create_with_capacity(
|
|
vec2i_t, arena, instance->model->vertices->count * sizeof(vec3f_t));
|
|
if (!projected) {
|
|
return;
|
|
}
|
|
|
|
mat4x4f_t t_mat = get_translation_matrix(instance->transform.position);
|
|
mat4x4f_t r_mat = get_rotation_matrix(instance->transform.rotation);
|
|
mat4x4f_t s_mat = get_scaling_matrix((vec3f_t){instance->transform.scale,
|
|
instance->transform.scale,
|
|
instance->transform.scale});
|
|
mat4x4f_t tr_mat = mul_mat4x4f(t_mat, r_mat);
|
|
mat4x4f_t trs_mat = mul_mat4x4f(tr_mat, s_mat);
|
|
|
|
mat3x4f_t xf_proj_mat = mul_mat3x4f_by_mat4x4f(proj_cam_mat, trs_mat);
|
|
|
|
vec3f_t vertex = {0};
|
|
vec2i_t point = {0};
|
|
for (u64 i = 0; i < instance->model->vertices->count; ++i) {
|
|
vertex = list_get(instance->model->vertices, i);
|
|
vertex = mul_mat3x4f_by_vec4f(
|
|
xf_proj_mat, (vec4f_t){vertex.x, vertex.y, vertex.z, 1.0f});
|
|
point = (vec2i_t){(i32)(vertex.x / vertex.z), (i32)(vertex.y / vertex.z)};
|
|
list_append(vec2i_t, arena, projected, point);
|
|
}
|
|
|
|
for (u64 i = 0; i < instance->model->triangles->count; ++i) {
|
|
scene_triangle_t triangle = list_get(instance->model->triangles, i);
|
|
triangle_t tri = {
|
|
.p0 = list_get(projected, triangle.idx0),
|
|
.p1 = list_get(projected, triangle.idx1),
|
|
.p2 = list_get(projected, triangle.idx2),
|
|
.h0 = 1.0f,
|
|
.h1 = 1.0f,
|
|
.h2 = 1.0f,
|
|
.colour = triangle.colour,
|
|
};
|
|
draw_wireframe_triangle(wnd, arena, tri);
|
|
}
|
|
}
|
|
|
|
void draw_wireframe_triangle(window_t *wnd, Arena *arena, triangle_t triangle) {
|
|
order_triangle_points(&triangle);
|
|
|
|
draw_line(wnd, arena, (line_t){triangle.p0, triangle.p1}, triangle.colour);
|
|
draw_line(wnd, arena, (line_t){triangle.p1, triangle.p2}, triangle.colour);
|
|
draw_line(wnd, arena, (line_t){triangle.p2, triangle.p0}, triangle.colour);
|
|
}
|
|
|
|
void draw_filled_triangle(window_t *wnd, Arena *arena, triangle_t triangle) {
|
|
order_triangle_points(&triangle);
|
|
|
|
i32 x0 = triangle.p0.x;
|
|
i32 y0 = triangle.p0.y;
|
|
i32 x1 = triangle.p1.x;
|
|
i32 y1 = triangle.p1.y;
|
|
i32 x2 = triangle.p2.x;
|
|
i32 y2 = triangle.p2.y;
|
|
|
|
list_float *x01 = interpolate(arena, y0, x0, y1, x1);
|
|
list_float *x12 = interpolate(arena, y1, x1, y2, x2);
|
|
list_float *x02 = interpolate(arena, y0, x0, y2, x2);
|
|
list_float *x012 = NULL;
|
|
|
|
list_pop(x01); // Last element of x01 is a duplicate of first element in x12
|
|
list_merge(f32, arena, x012, x01, x12);
|
|
|
|
list_float *x_left;
|
|
list_float *x_right;
|
|
u64 middle = (u64)(floorf((f32)(x02->count) / 2.0f));
|
|
if (list_get(x02, middle) < list_get(x012, middle)) {
|
|
x_left = x02;
|
|
x_right = x012;
|
|
} else {
|
|
x_left = x012;
|
|
x_right = x02;
|
|
}
|
|
|
|
for (i64 y = y0; y <= y2; ++y) {
|
|
i32 index = y - y0;
|
|
for (i64 x = (i64)list_get(x_left, index); x < list_get(x_right, index);
|
|
++x) {
|
|
set_pixel(wnd, x, y, triangle.colour);
|
|
}
|
|
}
|
|
}
|
|
|
|
void draw_shaded_triangle(window_t *wnd, Arena *arena, triangle_t triangle) {
|
|
order_triangle_points(&triangle);
|
|
|
|
i32 x0 = triangle.p0.x;
|
|
i32 y0 = triangle.p0.y;
|
|
i32 x1 = triangle.p1.x;
|
|
i32 y1 = triangle.p1.y;
|
|
i32 x2 = triangle.p2.x;
|
|
i32 y2 = triangle.p2.y;
|
|
|
|
list_float *x01 = interpolate(arena, y0, x0, y1, x1);
|
|
list_float *x12 = interpolate(arena, y1, x1, y2, x2);
|
|
list_float *x02 = interpolate(arena, y0, x0, y2, x2);
|
|
list_float *x012 = NULL;
|
|
|
|
list_pop(x01); // Last element of x01 is a duplicate of first element in x12
|
|
list_merge(f32, arena, x012, x01, x12);
|
|
|
|
f32 h0 = triangle.h0;
|
|
f32 h1 = triangle.h1;
|
|
f32 h2 = triangle.h2;
|
|
list_float *h01 = interpolate(arena, y0, h0, y1, h1);
|
|
list_float *h12 = interpolate(arena, y1, h1, y2, h2);
|
|
list_float *h02 = interpolate(arena, y0, h0, y2, h2);
|
|
list_float *h012 = NULL;
|
|
|
|
list_pop(h01); // Last element of h01 is a duplicate of first element in h12
|
|
list_merge(f32, arena, h012, h01, h12);
|
|
|
|
list_float *x_left;
|
|
list_float *x_right;
|
|
list_float *h_left;
|
|
list_float *h_right;
|
|
u64 middle = (u64)(floorf((f32)(x02->count) / 2.0f));
|
|
if (list_get(x02, middle) < list_get(x012, middle)) {
|
|
x_left = x02;
|
|
h_left = h02;
|
|
x_right = x012;
|
|
h_right = h012;
|
|
} else {
|
|
x_left = x012;
|
|
h_left = h012;
|
|
x_right = x02;
|
|
h_right = h02;
|
|
}
|
|
|
|
list_float *h_segment = NULL;
|
|
i32 index = -1;
|
|
i64 xl = -1;
|
|
i64 xr = -1;
|
|
colour_t shaded_colour = (colour_t){0};
|
|
|
|
for (i64 y = y0; y <= y2; ++y) {
|
|
index = y - y0;
|
|
xl = (i64)list_get(x_left, index);
|
|
xr = (i64)list_get(x_right, index);
|
|
for (i64 x = xl; x < xr; ++x) {
|
|
h_segment = interpolate(arena, xl, list_get(h_left, index), xr,
|
|
list_get(h_right, index));
|
|
shaded_colour = colour_mul(triangle.colour, list_get(h_segment, x - xl));
|
|
set_pixel(wnd, x, y, shaded_colour);
|
|
}
|
|
}
|
|
}
|
|
|
|
void draw_line(window_t *wnd, Arena *arena, line_t line, colour_t colour) {
|
|
list_float *values = NULL;
|
|
|
|
if (abs(line.p1.x - line.p0.x) > abs(line.p1.y - line.p0.y)) {
|
|
if (line.p1.x < line.p0.x) {
|
|
swap(vec2i_t, line.p0, line.p1);
|
|
}
|
|
|
|
i32 x0 = line.p0.x;
|
|
i32 y0 = line.p0.y;
|
|
i32 x1 = line.p1.x;
|
|
i32 y1 = line.p1.y;
|
|
|
|
values = interpolate(arena, x0, y0, x1, y1);
|
|
if (!values) {
|
|
return;
|
|
}
|
|
|
|
for (i32 x = x0; x <= x1; ++x) {
|
|
set_pixel(wnd, x, (i32)(list_get(values, x - x0)), colour);
|
|
}
|
|
} else {
|
|
if (line.p1.y < line.p0.y) {
|
|
swap(vec2i_t, line.p0, line.p1);
|
|
}
|
|
|
|
i32 x0 = line.p0.x;
|
|
i32 y0 = line.p0.y;
|
|
i32 x1 = line.p1.x;
|
|
i32 y1 = line.p1.y;
|
|
|
|
values = interpolate(arena, y0, x0, y1, x1);
|
|
if (!values) {
|
|
return;
|
|
}
|
|
|
|
for (i32 y = y0; y <= y1; ++y) {
|
|
set_pixel(wnd, (i32)(list_get(values, y - y0)), y, colour);
|
|
}
|
|
}
|
|
}
|
|
|
|
internal list_float *interpolate(Arena *arena, i32 i0, f32 d0, i32 i1, f32 d1) {
|
|
list_float *values;
|
|
if (i0 == i1) {
|
|
values = list_create_with_capacity(f32, arena, 20);
|
|
if (values) {
|
|
list_append(f32, arena, values, d0);
|
|
}
|
|
|
|
return values;
|
|
}
|
|
|
|
values = list_create(f32, arena);
|
|
if (!values) {
|
|
return NULL;
|
|
}
|
|
|
|
f32 a = (d1 - d0) / ((f32)i1 - i0);
|
|
f32 d = d0;
|
|
|
|
for (i32 i = i0; i <= i1; ++i) {
|
|
list_append(f32, arena, values, d);
|
|
d += a;
|
|
}
|
|
|
|
return values;
|
|
}
|
|
|
|
internal inline void order_triangle_points(triangle_t *triangle) {
|
|
if (triangle->p1.y < triangle->p0.y) {
|
|
swap(vec2i_t, triangle->p0, triangle->p1);
|
|
swap(f32, triangle->h0, triangle->h1);
|
|
}
|
|
if (triangle->p2.y < triangle->p0.y) {
|
|
swap(vec2i_t, triangle->p0, triangle->p2);
|
|
swap(f32, triangle->h0, triangle->h2);
|
|
}
|
|
if (triangle->p2.y < triangle->p1.y) {
|
|
swap(vec2i_t, triangle->p1, triangle->p2);
|
|
swap(f32, triangle->h1, triangle->h2);
|
|
}
|
|
}
|