diff --git a/include/rasteriser/rasteriser.h b/include/rasteriser/rasteriser.h index 6735864..20a70b9 100644 --- a/include/rasteriser/rasteriser.h +++ b/include/rasteriser/rasteriser.h @@ -8,10 +8,12 @@ #include "vector/vec.h" #include "window/window.h" +#define INVALID_VERTEX -1 + typedef struct { - u64 idx0; - u64 idx1; - u64 idx2; + i64 idx0; + i64 idx1; + i64 idx2; colour_t colour; } scene_triangle_t; @@ -41,8 +43,6 @@ typedef struct { list_scene_triangle_t *triangles; } model_t; #define NULL_MODEL ((model_t){0}) -#define IS_NULL_MODEL(MODEL_PTR) \ - (MODEL_PTR->vertices == NULL && MODEL_PTR->triangles == NULL) typedef struct { f32 scale; @@ -79,5 +79,6 @@ void draw_wireframe_triangle(window_t *wnd, Arena *arena, triangle_t triangle); void draw_filled_triangle(window_t *wnd, Arena *arena, triangle_t triangle); void draw_shaded_triangle(window_t *wnd, Arena *arena, triangle_t triangle); void draw_line(window_t *wnd, Arena *arena, line_t line, colour_t colour); +bool is_null_model(const model_t *model); #endif // !RASTERISER_H diff --git a/src/rasteriser/rasteriser.c b/src/rasteriser/rasteriser.c index 1eda9c8..60a6041 100644 --- a/src/rasteriser/rasteriser.c +++ b/src/rasteriser/rasteriser.c @@ -15,18 +15,24 @@ internal void render_instance(window_t *wnd, const rasteriser_scene_t *scene, Arena *arena, mat4x4f_t camera_matrix, mat3x4f_t projection_matrix, const instance_t *instance); -internal void clip_instance(model_t *model, const rasteriser_scene_t *scene); -internal void clip_instance_against_plane(model_t *model, +internal void clip_instance(Arena *arena, model_t *model, + const rasteriser_scene_t *scene); +internal void clip_instance_against_plane(Arena *arena, model_t *model, const bounding_sphere_t *sphere, const clipping_plane_t *plane); -internal void clip_triangles_against_plane(model_t *model, +internal void clip_triangles_against_plane(Arena *arena, model_t *model, const clipping_plane_t *plane); -internal void clip_triangle_against_plane(vec3f_t *v0, vec3f_t *v1, vec3f_t *v2, +internal void clip_triangle_against_plane(Arena *arena, model_t *model, + i64 triangle_index, const clipping_plane_t *plane); internal list_float *interpolate(Arena *arena, i32 i0, f32 d0, i32 i1, f32 d1); internal inline void order_triangle_points(triangle_t *triangle); internal inline bounding_sphere_t get_bounding_sphere(const list_vec3f_t *vertices); +internal inline vec3f_t segment_intersection(const vec3f_t *a, const vec3f_t *b, + const clipping_plane_t *plane); +internal inline void copy_triangles(Arena *arena, list_scene_triangle_t *dst, + const list_scene_triangle_t *src); internal inline f32 signed_distance(const vec3f_t *vertex, const clipping_plane_t *plane); @@ -50,11 +56,17 @@ internal void render_instance(window_t *wnd, const rasteriser_scene_t *scene, mat3x4f_t projection_matrix, const instance_t *instance) { list_vec3f_t *transformed = list_create_with_capacity( - vec3f_t, arena, instance->model->vertices->count * sizeof(vec3f_t)); - if (!transformed) { + vec3f_t, arena, + (instance->model->vertices->count + 10) * sizeof(vec3f_t)); + list_scene_triangle_t *triangles = list_create_with_capacity( + scene_triangle_t, arena, + (instance->model->triangles->count + 10) * sizeof(scene_triangle_t)); + if (!transformed || !triangles) { return; } + copy_triangles(arena, triangles, instance->model->triangles); + 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, @@ -79,10 +91,9 @@ internal void render_instance(window_t *wnd, const rasteriser_scene_t *scene, list_append(vec3f_t, arena, transformed, vertex); } - model_t model = {transformed, instance->model->triangles}; - clip_instance(&model, scene); - model_t *mdl = &model; - if (IS_NULL_MODEL(mdl)) { + model_t model = {transformed, triangles}; + clip_instance(arena, &model, scene); + if (is_null_model(&model)) { return; } @@ -101,8 +112,9 @@ internal void render_instance(window_t *wnd, const rasteriser_scene_t *scene, 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); + for (u64 i = 0; i < triangles->count; ++i) { + scene_triangle_t triangle = list_get(triangles, i); + triangle_t tri = { .p0 = list_get(projected, triangle.idx0), .p1 = list_get(projected, triangle.idx1), @@ -112,6 +124,12 @@ internal void render_instance(window_t *wnd, const rasteriser_scene_t *scene, .h2 = 1.0f, .colour = triangle.colour, }; + + if ((tri.p0.x == tri.p1.x && tri.p0.x == tri.p2.x) && + (tri.p0.y == tri.p1.y && tri.p0.y == tri.p2.y)) { + continue; + } + draw_wireframe_triangle(wnd, arena, tri); } } @@ -269,20 +287,25 @@ void draw_line(window_t *wnd, Arena *arena, line_t line, colour_t colour) { } } -internal void clip_instance(model_t *model, const rasteriser_scene_t *scene) { +bool is_null_model(const model_t *model) { + return model->vertices == NULL && model->triangles == NULL; +} + +internal void clip_instance(Arena *arena, model_t *model, + const rasteriser_scene_t *scene) { bounding_sphere_t sphere = get_bounding_sphere(model->vertices); const clipping_plane_t *plane = NULL; for (u64 i = 0; i < CLIPPING_PLANE_COUNT; ++i) { plane = &(scene->planes[i]); - clip_instance_against_plane(model, &sphere, plane); - if (IS_NULL_MODEL(model)) { + clip_instance_against_plane(arena, model, &sphere, plane); + if (is_null_model(model)) { return; } } } -internal void clip_instance_against_plane(model_t *model, +internal void clip_instance_against_plane(Arena *arena, model_t *model, const bounding_sphere_t *sphere, const clipping_plane_t *plane) { f32 distance = signed_distance(&(sphere->centre), plane); @@ -293,28 +316,111 @@ internal void clip_instance_against_plane(model_t *model, } else if (distance < neg_radius) { *model = NULL_MODEL; } else { - clip_triangles_against_plane(model, plane); + clip_triangles_against_plane(arena, model, plane); } } -internal void clip_triangles_against_plane(model_t *model, +internal void clip_triangles_against_plane(Arena *arena, model_t *model, const clipping_plane_t *plane) { - for (u64 i = 0; i < model->triangles->count; ++i) { - scene_triangle_t triangle = list_get(model->triangles, i); - vec3f_t *v0 = &(list_get(model->vertices, triangle.idx0)); - vec3f_t *v1 = &(list_get(model->vertices, triangle.idx1)); - vec3f_t *v2 = &(list_get(model->vertices, triangle.idx2)); - clip_triangle_against_plane(v0, v1, v2, plane); + u64 count = model->triangles->count; + for (u64 i = 0; i < count; ++i) { + clip_triangle_against_plane(arena, model, i, plane); } } -internal void clip_triangle_against_plane(vec3f_t *v0, vec3f_t *v1, vec3f_t *v2, +internal void clip_triangle_against_plane(Arena *arena, model_t *model, + i64 triangle_index, const clipping_plane_t *plane) { + scene_triangle_t *triangle = &(list_get(model->triangles, triangle_index)); + vec3f_t *v0 = &(list_get(model->vertices, triangle->idx0)); + vec3f_t *v1 = &(list_get(model->vertices, triangle->idx1)); + vec3f_t *v2 = &(list_get(model->vertices, triangle->idx2)); + f32 d0 = signed_distance(v0, plane); f32 d1 = signed_distance(v1, plane); f32 d2 = signed_distance(v2, plane); - if (d0 > 0.0f && d1 > 0.0f && d2 > 0.0f) { + if (d0 >= 0.0f && d1 >= 0.0f && d2 >= 0.0f) { + return; + } else if (d0 < 0.0f && d1 < 0.0f && d2 < 0.0f) { + triangle->idx0 = INVALID_VERTEX; + triangle->idx1 = INVALID_VERTEX; + triangle->idx2 = INVALID_VERTEX; + } else if ((d0 < 0.0f && d1 < 0.0f) || (d0 < 0.0f && d2 < 0.0f) || + (d1 < 0.0f && d2 < 0.0f)) { + vec3f_t *vp; + vec3f_t *vn0; + vec3f_t *vn1; + i64 *in0; + i64 *in1; + if (d0 > 0.0f) { + vp = v0; + vn0 = v1; + vn1 = v2; + in0 = &(triangle->idx1); + in1 = &(triangle->idx2); + } else if (d1 > 0.0f) { + vp = v1; + vn0 = v0; + vn1 = v2; + in0 = &(triangle->idx0); + in1 = &(triangle->idx2); + } else { + vp = v2; + vn0 = v0; + vn1 = v1; + in0 = &(triangle->idx0); + in1 = &(triangle->idx1); + } + + list_append(vec3f_t, arena, model->vertices, + segment_intersection(vp, vn0, plane)); + list_append(vec3f_t, arena, model->vertices, + segment_intersection(vp, vn1, plane)); + + *in0 = model->vertices->count - 2; + *in1 = model->vertices->count - 1; + } else { + vec3f_t *vn; + vec3f_t *vp0; + vec3f_t *vp1; + i64 *in; + i64 *ip; + if (d0 < 0.0f) { + vn = v0; + vp0 = v1; + vp1 = v2; + in = &(triangle->idx0); + ip = &(triangle->idx2); + } else if (d1 < 0.0f) { + vn = v1; + vp0 = v0; + vp1 = v2; + in = &(triangle->idx1); + ip = &(triangle->idx2); + } else { + vn = v2; + vp0 = v0; + vp1 = v1; + in = &(triangle->idx2); + ip = &(triangle->idx1); + } + + list_append(vec3f_t, arena, model->vertices, + segment_intersection(vp0, vn, plane)); + list_append(vec3f_t, arena, model->vertices, + segment_intersection(vp1, vn, plane)); + + *in = model->vertices->count - 2; + + scene_triangle_t tri = { + .idx0 = *in, + .idx1 = *ip, + .idx2 = model->vertices->count - 1, + .colour = triangle->colour, + }; + + list_append(scene_triangle_t, arena, model->triangles, tri); } } @@ -383,8 +489,28 @@ get_bounding_sphere(const list_vec3f_t *vertices) { }; } +internal inline vec3f_t segment_intersection(const vec3f_t *a, const vec3f_t *b, + const clipping_plane_t *plane) { + f32 neg_d = plane->distance * -1.0f; + f32 na_dot = vec_dot(vec3f_t, plane->normal, *a); + vec3f_t ba = vec_sub(vec3f_t, *b, *a); + f32 nba_dot = vec_dot(vec3f_t, plane->normal, ba); + + f32 t = (neg_d - na_dot) / nba_dot; + + return vec_add(vec3f_t, *a, vec_mul_num(vec3f_t, ba, t)); +} + +internal inline void copy_triangles(Arena *arena, list_scene_triangle_t *dst, + const list_scene_triangle_t *src) { + for (u64 i = 0; i < src->count; ++i) { + scene_triangle_t tri = list_get(src, i); + list_append(scene_triangle_t, arena, dst, tri); + } +} + internal inline f32 signed_distance(const vec3f_t *vertex, const clipping_plane_t *plane) { - return (vertex->x * plane->normal.x) + (vertex->y + plane->normal.y) + - (vertex->z + plane->normal.z) + plane->distance; + return (vertex->x * plane->normal.x) + (vertex->y * plane->normal.y) + + (vertex->z * plane->normal.z) + plane->distance; }