From 65d448aad0e6c792b1adba1272efef73b31c4885 Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Fri, 24 Oct 2025 18:33:36 -0700 Subject: Consolidate renderers --- src/render/renderer.c | 246 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 246 insertions(+) create mode 100644 src/render/renderer.c (limited to 'src/render/renderer.c') diff --git a/src/render/renderer.c b/src/render/renderer.c new file mode 100644 index 0000000..eca7551 --- /dev/null +++ b/src/render/renderer.c @@ -0,0 +1,246 @@ +#include "renderer_impl.h" + +#include "llr_impl.h" +#include "memory.h" +#include "scene/animation_impl.h" +#include "scene/camera_impl.h" +#include "scene/model_impl.h" +#include "scene/node_impl.h" +#include "scene/object_impl.h" +#include "scene/scene_impl.h" + +#include +#include +#include + +#include + +#include + +bool gfx_renderer_make(Renderer* renderer, LLR* llr, GfxCore* gfxcore) { + assert(renderer); + assert(llr); + assert(gfxcore); + + renderer->gfxcore = gfxcore; + renderer->llr = llr; + + return true; +} + +void gfx_renderer_destroy(Renderer* renderer) { + if (!renderer) { + return; + } + assert(renderer->gfxcore); + GfxCore* gfxcore = renderer->gfxcore; + if (renderer->shaders.debug) { + gfx_destroy_shader_program(gfxcore, &renderer->shaders.debug); + } + if (renderer->shaders.normals) { + gfx_destroy_shader_program(gfxcore, &renderer->shaders.normals); + } + if (renderer->shaders.normal_mapped_normals) { + gfx_destroy_shader_program( + gfxcore, &renderer->shaders.normal_mapped_normals); + } + if (renderer->shaders.tangents) { + gfx_destroy_shader_program(gfxcore, &renderer->shaders.tangents); + } +} + +static ShaderProgram* load_shader(Renderer* renderer, RenderSceneMode mode) { + assert(renderer); + +#define LOAD_AND_RETURN(pShader, constructor) \ + { \ + if (!pShader) { \ + pShader = constructor(renderer->gfxcore); \ + } \ + assert(pShader); \ + return pShader; \ + } + + switch (mode) { + case RenderDefault: + return 0; + case RenderDebug: + LOAD_AND_RETURN(renderer->shaders.debug, gfx_make_debug3d_shader); + case RenderNormals: + LOAD_AND_RETURN(renderer->shaders.normals, gfx_make_view_normals_shader); + case RenderNormalMappedNormals: + LOAD_AND_RETURN( + renderer->shaders.normal_mapped_normals, + gfx_make_view_normal_mapped_normals_shader); + case RenderTangents: + LOAD_AND_RETURN(renderer->shaders.tangents, gfx_make_view_tangents_shader); + } + assert(false); + return 0; +} + +// static void log_matrix(const mat4* m) { +// for (int row = 0; row < 4; ++row) { +// LOGI("[ %5.2f, %5.2f, %5.2f, %5.2f ]", m->val[0][row], m->val[1][row], +// m->val[2][row], m->val[3][row]); +// } +// } + +typedef struct RenderState { + GfxCore* gfxcore; + LLR* llr; + Renderer* renderer; + ShaderProgram* shader; // Null to use scene shaders. + const Scene* scene; + const Anima* anima; +} RenderState; + +static void draw_children( + RenderState* state, const mat4* node_transform, const SceneNode* node); + +/// Draw the scene recursively. +static void draw_recursively( + RenderState* state, mat4 parent_transform, const SceneNode* node) { + assert(state); + const mat4 node_transform = mat4_mul(parent_transform, node->transform); + + // Anima. + if (node->type == AnimaNode) { + // Save the anima so that we can animate objects. + state->anima = gfx_get_node_anima(node); + + draw_children(state, &node_transform, node); + } + // Activate light. + else if (node->type == LightNode) { + Light* light = mem_get_light(node->light); + assert(light); + gfx_llr_push_light(state->llr, light); + { + draw_children(state, &node_transform, node); + } + gfx_llr_pop_light(state->llr); + } + // Model. + else if (node->type == ModelNode) { + const Model* model = gfx_get_node_model(node); + const SceneNode* root = mem_get_node(model->root); + draw_recursively(state, parent_transform, root); + draw_children(state, &node_transform, node); + } + // Render object. + else if (node->type == ObjectNode) { + const SceneObject* object = mem_get_object(node->object); + assert(object); + + // TODO: Here we would frustum-cull the object. + + // A model/anima can have many skeletons. We need to animate the given + // object using its skeleton, not just any skeleton of the anima. + if (object->skeleton.val) { + const Skeleton* skeleton = mem_get_skeleton(object->skeleton); + gfx_llr_set_skeleton(state->llr, state->anima, skeleton); + } + + const mat4 model_matrix = node_transform; + + for (mesh_link_idx mesh_link_index = object->mesh_link; + mesh_link_index.val;) { + const MeshLink* mesh_link = mem_get_mesh_link(mesh_link_index); + mesh_link_index = mesh_link->next; + + const Mesh* mesh = mem_get_mesh(mesh_link->mesh); + if (!mesh) { + continue; + } + + // TODO: Here we would frustum-cull the mesh. The AABB would have to be + // transformed by the model matrix. Rotation would make the AABB + // relatively large, but still, the culling would be conservative. + + ShaderProgram* shader = state->shader ? state->shader : mesh->shader; + gfx_llr_set_shader(state->llr, shader); + gfx_llr_set_model_matrix(state->llr, &model_matrix); + gfx_llr_render_mesh(state->llr, mesh); + } + + if (object->skeleton.val) { + gfx_llr_clear_skeleton(state->llr); + } + + draw_children(state, &node_transform, node); + } else { + draw_children(state, &node_transform, node); + } +} + +/// Draw the node's children. +static void draw_children( + RenderState* state, const mat4* node_transform, const SceneNode* node) { + // Render children recursively. + for (node_idx child_index = node->child; child_index.val;) { + const SceneNode* child = mem_get_node(child_index); + draw_recursively(state, *node_transform, child); + child_index = child->next; + } +} + +void gfx_render_scene(Renderer* renderer, const RenderSceneParams* params) { + assert(renderer); + assert(params); + assert(params->scene); + + ShaderProgram* const shader = load_shader(renderer, params->mode); + + const Scene* scene = params->scene; + const SceneCamera* camera = params->camera; + GfxCore* const gfxcore = renderer->gfxcore; + + int x, y, width, height; + gfx_get_viewport(gfxcore, &x, &y, &width, &height); + const R aspect = (R)width / (R)height; + + RenderState state = { + .gfxcore = gfxcore, + .llr = renderer->llr, + .renderer = renderer, + .shader = shader, + .scene = scene}; + + gfx_llr_set_camera(renderer->llr, &camera->camera); + gfx_llr_set_aspect(renderer->llr, aspect); + draw_recursively(&state, mat4_id(), scene->root); +} + +static void update_rec(SceneNode* node, const SceneCamera* camera, R t) { + assert(node); + assert(camera); + + const NodeType node_type = gfx_get_node_type(node); + + // TODO: Models do not need to be animated if they are not visible to the + // camera. + if (node_type == AnimaNode) { + Anima* anima = gfx_get_node_anima_mut(node); + gfx_update_animation(anima, (R)t); + } else if (node_type == ModelNode) { + Model* model = gfx_get_node_model_mut(node); + SceneNode* root = gfx_get_model_root_mut(model); + update_rec(root, camera, t); + } + + // Children. + SceneNode* child = gfx_get_node_child_mut(node); + while (child) { + update_rec(child, camera, t); + child = gfx_get_node_sibling_mut(child); + } +} + +void gfx_update(Scene* scene, const SceneCamera* camera, R t) { + assert(scene); + assert(camera); + + SceneNode* node = gfx_get_scene_root(scene); + update_rec(node, camera, t); +} -- cgit v1.2.3