From bd57f345ed9dbed1d81683e48199626de2ea9044 Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Fri, 27 Jun 2025 10:18:39 -0700 Subject: Restructure project --- src/renderer/imm_renderer.c | 260 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 260 insertions(+) create mode 100644 src/renderer/imm_renderer.c (limited to 'src/renderer/imm_renderer.c') diff --git a/src/renderer/imm_renderer.c b/src/renderer/imm_renderer.c new file mode 100644 index 0000000..8cf3a10 --- /dev/null +++ b/src/renderer/imm_renderer.c @@ -0,0 +1,260 @@ +#include "imm_renderer_impl.h" + +#include +#include + +#include + +#include +#include // memcpy + +bool imm_renderer_make(ImmRenderer* renderer, GfxCore* gfxcore) { + assert(renderer); + assert(gfxcore); + + const size_t num_triangle_verts = IMM_MAX_NUM_TRIANGLES * 3; + + renderer->gfxcore = gfxcore; + + renderer->triangles = gfx_make_geometry( + gfxcore, &(GeometryDesc){ + .type = Triangles, + .buffer_usage = BufferDynamic, + .num_verts = num_triangle_verts, + .positions3d = (BufferView3d){ + .size_bytes = num_triangle_verts * sizeof(vec3)}}); + if (!renderer->triangles) { + goto cleanup; + } + + renderer->shader = gfx_make_immediate_mode_shader(gfxcore); + if (!renderer->shader) { + goto cleanup; + } + + renderer->matrix_stack[0] = mat4_id(); + renderer->stack_pointer = 0; + + gfx_imm_set_colour(renderer, vec4_make(0.0, 0.0, 0.0, 1.0)); + + return true; + +cleanup: + imm_renderer_destroy(renderer); + return false; +} + +void imm_renderer_destroy(ImmRenderer* renderer) { + assert(renderer); + assert(renderer->gfxcore); + + if (renderer->triangles) { + gfx_destroy_geometry(renderer->gfxcore, &renderer->triangles); + // TODO: Could also destroy the geometry's buffers here. + } + + if (renderer->shader) { + gfx_destroy_shader_program(renderer->gfxcore, &renderer->shader); + } +} + +void imm_renderer_flush(ImmRenderer* renderer) { + assert(renderer); + + if (renderer->num_triangle_verts > 0) { + gfx_update_geometry( + renderer->triangles, + &(GeometryDesc){ + .num_verts = renderer->num_triangle_verts, + .positions3d = (BufferView3d){ + .data = renderer->triangle_verts, + .size_bytes = renderer->num_triangle_verts * sizeof(vec3)} + }); + + gfx_apply_uniforms(renderer->shader); + gfx_render_geometry(renderer->triangles); + + renderer->num_triangle_verts = 0; + } +} + +void gfx_imm_start(ImmRenderer* renderer) { + assert(renderer); + // Shader uniforms are applied lazily. + // TODO: In the event that gfx_activate_shader_program() activates uniforms + // automatically for convenience, call an overload here that doesn't do so. + ShaderProgram* shader = renderer->shader; + gfx_activate_shader_program(shader); +} + +void gfx_imm_end(ImmRenderer* renderer) { + assert(renderer); + imm_renderer_flush(renderer); + gfx_deactivate_shader_program(renderer->shader); +} + +void gfx_imm_draw_triangles( + ImmRenderer* renderer, const vec3 verts[], size_t num_triangles) { + assert(renderer); + assert(verts); + const size_t new_verts = num_triangles * 3; + assert( + renderer->num_triangle_verts + new_verts < (IMM_MAX_NUM_TRIANGLES * 3)); + + memcpy( + renderer->triangle_verts + renderer->num_triangle_verts, verts, + new_verts * sizeof(vec3)); + + renderer->num_triangle_verts += new_verts; +} + +void gfx_imm_draw_triangle(ImmRenderer* renderer, const vec3 verts[3]) { + gfx_imm_draw_triangles(renderer, verts, 1); +} + +void gfx_imm_draw_aabb2(ImmRenderer* renderer, aabb2 box) { + assert(renderer); + + // clang-format off + const vec3 verts[4] = { + vec3_make(box.min.x, box.min.y, 0), // 3 ---- 2 + vec3_make(box.max.x, box.min.y, 0), // | | + vec3_make(box.max.x, box.max.y, 0), // | | + vec3_make(box.min.x, box.max.y, 0)}; // 0 ---- 1 + // clang-format on + +#define tri(i0, i1, i2) verts[i0], verts[i1], verts[i2] + const vec3 tris[6] = {tri(0, 1, 2), tri(0, 2, 3)}; +#undef tri + + gfx_imm_draw_triangles(renderer, tris, 2); +} + +void gfx_imm_draw_aabb3(ImmRenderer* renderer, aabb3 box) { + assert(renderer); + + // clang-format off + const vec3 vertices[8] = { + vec3_make(box.min.x, box.min.y, box.max.z), // 7 ----- 6 + vec3_make(box.max.x, box.min.y, box.max.z), // / /| + vec3_make(box.max.x, box.max.y, box.max.z), // 3 ----- 2 | + vec3_make(box.min.x, box.max.y, box.max.z), // | | | + vec3_make(box.min.x, box.min.y, box.min.z), // | 4 ----- 5 + vec3_make(box.max.x, box.min.y, box.min.z), // |/ |/ + vec3_make(box.max.x, box.max.y, box.min.z), // 0 ----- 1 + vec3_make(box.min.x, box.max.y, box.min.z)}; + // clang-format on + + gfx_imm_draw_box3(renderer, vertices); +} + +void gfx_imm_draw_box3(ImmRenderer* renderer, const vec3 vertices[8]) { + assert(renderer); + assert(vertices); + + // 7 ----- 6 + // / /| + // 3 ----- 2 | + // | | | + // | 4 ----- 5 + // |/ |/ + // 0 ----- 1 + +#define tri(i0, i1, i2) vertices[i0], vertices[i1], vertices[i2] + const vec3 tris[36] = {// Front. + tri(0, 1, 2), tri(0, 2, 3), + // Right. + tri(1, 5, 6), tri(1, 6, 2), + // Back. + tri(5, 4, 7), tri(5, 7, 6), + // Left. + tri(4, 0, 03), tri(4, 3, 7), + // Top. + tri(3, 2, 6), tri(3, 6, 7), + // Bottom. + tri(0, 4, 5), tri(0, 5, 1)}; + + gfx_imm_draw_triangles(renderer, tris, 12); +} + +// Load the top of the matrix stack into the shader. +static void update_shader_model_matrix(ImmRenderer* renderer) { + assert(renderer); + imm_renderer_flush(renderer); + gfx_set_mat4_uniform( + renderer->shader, "Model", + &renderer->matrix_stack[renderer->stack_pointer]); +} + +void gfx_imm_load_identity(ImmRenderer* renderer) { + assert(renderer); + renderer->matrix_stack[0] = mat4_id(); + renderer->stack_pointer = 0; + update_shader_model_matrix(renderer); +} + +void gfx_imm_push_matrix(ImmRenderer* renderer, const mat4* matrix) { + assert(renderer); + assert(matrix); + assert(renderer->stack_pointer >= 0); + assert(renderer->stack_pointer < IMM_MAX_NUM_MATRICES); // TODO: hard assert. + + renderer->matrix_stack[renderer->stack_pointer + 1] = + mat4_mul(*matrix, renderer->matrix_stack[renderer->stack_pointer]); + renderer->stack_pointer += 1; + + update_shader_model_matrix(renderer); +} + +void gfx_imm_pop_matrix(ImmRenderer* renderer) { + assert(renderer); + assert(renderer->stack_pointer > 0); // TODO: hard assert. + + // For debugging, zero out the matrix stack as matrices are popped out. + memset( + &renderer->matrix_stack[renderer->stack_pointer], 0, + sizeof(renderer->matrix_stack[0])); + + renderer->stack_pointer -= 1; + + update_shader_model_matrix(renderer); +} + +void gfx_imm_translate(ImmRenderer* renderer, vec3 offset) { + assert(renderer); + const mat4 mat = mat4_translate(offset); + gfx_imm_push_matrix(renderer, &mat); +} + +void gfx_imm_set_camera(ImmRenderer* renderer, const Camera* camera) { + assert(renderer); + assert(renderer->shader); + imm_renderer_flush(renderer); + const mat4 view = spatial3_inverse_transform(&camera->spatial); + const mat4 view_proj = mat4_mul(camera->projection, view); + gfx_imm_set_view_projection_matrix(renderer, &view_proj); +} + +void gfx_imm_set_model_matrix(ImmRenderer* renderer, const mat4* model) { + assert(renderer); + assert(model); + imm_renderer_flush(renderer); + renderer->matrix_stack[0] = *model; + renderer->stack_pointer = 0; + update_shader_model_matrix(renderer); +} + +void gfx_imm_set_view_projection_matrix( + ImmRenderer* renderer, const mat4* view_proj) { + assert(renderer); + assert(renderer->shader); + imm_renderer_flush(renderer); + gfx_set_mat4_uniform(renderer->shader, "ViewProjection", view_proj); +} + +void gfx_imm_set_colour(ImmRenderer* renderer, vec4 colour) { + assert(renderer); + assert(renderer->shader); + imm_renderer_flush(renderer); + gfx_set_vec4_uniform(renderer->shader, "Colour", colour); +} -- cgit v1.2.3