#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); }