#include "renderer_impl.h" #include "llr/light_impl.h" #include "llr/mesh_impl.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 "scene/scene_memory.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); }