aboutsummaryrefslogtreecommitdiff
path: root/src/render/renderer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/render/renderer.c')
-rw-r--r--src/render/renderer.c246
1 files changed, 246 insertions, 0 deletions
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 @@
1#include "renderer_impl.h"
2
3#include "llr_impl.h"
4#include "memory.h"
5#include "scene/animation_impl.h"
6#include "scene/camera_impl.h"
7#include "scene/model_impl.h"
8#include "scene/node_impl.h"
9#include "scene/object_impl.h"
10#include "scene/scene_impl.h"
11
12#include <gfx/core.h>
13#include <gfx/render/llr.h>
14#include <gfx/util/shader.h>
15
16#include <math/mat4.h>
17
18#include <assert.h>
19
20bool gfx_renderer_make(Renderer* renderer, LLR* llr, GfxCore* gfxcore) {
21 assert(renderer);
22 assert(llr);
23 assert(gfxcore);
24
25 renderer->gfxcore = gfxcore;
26 renderer->llr = llr;
27
28 return true;
29}
30
31void gfx_renderer_destroy(Renderer* renderer) {
32 if (!renderer) {
33 return;
34 }
35 assert(renderer->gfxcore);
36 GfxCore* gfxcore = renderer->gfxcore;
37 if (renderer->shaders.debug) {
38 gfx_destroy_shader_program(gfxcore, &renderer->shaders.debug);
39 }
40 if (renderer->shaders.normals) {
41 gfx_destroy_shader_program(gfxcore, &renderer->shaders.normals);
42 }
43 if (renderer->shaders.normal_mapped_normals) {
44 gfx_destroy_shader_program(
45 gfxcore, &renderer->shaders.normal_mapped_normals);
46 }
47 if (renderer->shaders.tangents) {
48 gfx_destroy_shader_program(gfxcore, &renderer->shaders.tangents);
49 }
50}
51
52static ShaderProgram* load_shader(Renderer* renderer, RenderSceneMode mode) {
53 assert(renderer);
54
55#define LOAD_AND_RETURN(pShader, constructor) \
56 { \
57 if (!pShader) { \
58 pShader = constructor(renderer->gfxcore); \
59 } \
60 assert(pShader); \
61 return pShader; \
62 }
63
64 switch (mode) {
65 case RenderDefault:
66 return 0;
67 case RenderDebug:
68 LOAD_AND_RETURN(renderer->shaders.debug, gfx_make_debug3d_shader);
69 case RenderNormals:
70 LOAD_AND_RETURN(renderer->shaders.normals, gfx_make_view_normals_shader);
71 case RenderNormalMappedNormals:
72 LOAD_AND_RETURN(
73 renderer->shaders.normal_mapped_normals,
74 gfx_make_view_normal_mapped_normals_shader);
75 case RenderTangents:
76 LOAD_AND_RETURN(renderer->shaders.tangents, gfx_make_view_tangents_shader);
77 }
78 assert(false);
79 return 0;
80}
81
82// static void log_matrix(const mat4* m) {
83// for (int row = 0; row < 4; ++row) {
84// LOGI("[ %5.2f, %5.2f, %5.2f, %5.2f ]", m->val[0][row], m->val[1][row],
85// m->val[2][row], m->val[3][row]);
86// }
87// }
88
89typedef struct RenderState {
90 GfxCore* gfxcore;
91 LLR* llr;
92 Renderer* renderer;
93 ShaderProgram* shader; // Null to use scene shaders.
94 const Scene* scene;
95 const Anima* anima;
96} RenderState;
97
98static void draw_children(
99 RenderState* state, const mat4* node_transform, const SceneNode* node);
100
101/// Draw the scene recursively.
102static void draw_recursively(
103 RenderState* state, mat4 parent_transform, const SceneNode* node) {
104 assert(state);
105 const mat4 node_transform = mat4_mul(parent_transform, node->transform);
106
107 // Anima.
108 if (node->type == AnimaNode) {
109 // Save the anima so that we can animate objects.
110 state->anima = gfx_get_node_anima(node);
111
112 draw_children(state, &node_transform, node);
113 }
114 // Activate light.
115 else if (node->type == LightNode) {
116 Light* light = mem_get_light(node->light);
117 assert(light);
118 gfx_llr_push_light(state->llr, light);
119 {
120 draw_children(state, &node_transform, node);
121 }
122 gfx_llr_pop_light(state->llr);
123 }
124 // Model.
125 else if (node->type == ModelNode) {
126 const Model* model = gfx_get_node_model(node);
127 const SceneNode* root = mem_get_node(model->root);
128 draw_recursively(state, parent_transform, root);
129 draw_children(state, &node_transform, node);
130 }
131 // Render object.
132 else if (node->type == ObjectNode) {
133 const SceneObject* object = mem_get_object(node->object);
134 assert(object);
135
136 // TODO: Here we would frustum-cull the object.
137
138 // A model/anima can have many skeletons. We need to animate the given
139 // object using its skeleton, not just any skeleton of the anima.
140 if (object->skeleton.val) {
141 const Skeleton* skeleton = mem_get_skeleton(object->skeleton);
142 gfx_llr_set_skeleton(state->llr, state->anima, skeleton);
143 }
144
145 const mat4 model_matrix = node_transform;
146
147 for (mesh_link_idx mesh_link_index = object->mesh_link;
148 mesh_link_index.val;) {
149 const MeshLink* mesh_link = mem_get_mesh_link(mesh_link_index);
150 mesh_link_index = mesh_link->next;
151
152 const Mesh* mesh = mem_get_mesh(mesh_link->mesh);
153 if (!mesh) {
154 continue;
155 }
156
157 // TODO: Here we would frustum-cull the mesh. The AABB would have to be
158 // transformed by the model matrix. Rotation would make the AABB
159 // relatively large, but still, the culling would be conservative.
160
161 ShaderProgram* shader = state->shader ? state->shader : mesh->shader;
162 gfx_llr_set_shader(state->llr, shader);
163 gfx_llr_set_model_matrix(state->llr, &model_matrix);
164 gfx_llr_render_mesh(state->llr, mesh);
165 }
166
167 if (object->skeleton.val) {
168 gfx_llr_clear_skeleton(state->llr);
169 }
170
171 draw_children(state, &node_transform, node);
172 } else {
173 draw_children(state, &node_transform, node);
174 }
175}
176
177/// Draw the node's children.
178static void draw_children(
179 RenderState* state, const mat4* node_transform, const SceneNode* node) {
180 // Render children recursively.
181 for (node_idx child_index = node->child; child_index.val;) {
182 const SceneNode* child = mem_get_node(child_index);
183 draw_recursively(state, *node_transform, child);
184 child_index = child->next;
185 }
186}
187
188void gfx_render_scene(Renderer* renderer, const RenderSceneParams* params) {
189 assert(renderer);
190 assert(params);
191 assert(params->scene);
192
193 ShaderProgram* const shader = load_shader(renderer, params->mode);
194
195 const Scene* scene = params->scene;
196 const SceneCamera* camera = params->camera;
197 GfxCore* const gfxcore = renderer->gfxcore;
198
199 int x, y, width, height;
200 gfx_get_viewport(gfxcore, &x, &y, &width, &height);
201 const R aspect = (R)width / (R)height;
202
203 RenderState state = {
204 .gfxcore = gfxcore,
205 .llr = renderer->llr,
206 .renderer = renderer,
207 .shader = shader,
208 .scene = scene};
209
210 gfx_llr_set_camera(renderer->llr, &camera->camera);
211 gfx_llr_set_aspect(renderer->llr, aspect);
212 draw_recursively(&state, mat4_id(), scene->root);
213}
214
215static void update_rec(SceneNode* node, const SceneCamera* camera, R t) {
216 assert(node);
217 assert(camera);
218
219 const NodeType node_type = gfx_get_node_type(node);
220
221 // TODO: Models do not need to be animated if they are not visible to the
222 // camera.
223 if (node_type == AnimaNode) {
224 Anima* anima = gfx_get_node_anima_mut(node);
225 gfx_update_animation(anima, (R)t);
226 } else if (node_type == ModelNode) {
227 Model* model = gfx_get_node_model_mut(node);
228 SceneNode* root = gfx_get_model_root_mut(model);
229 update_rec(root, camera, t);
230 }
231
232 // Children.
233 SceneNode* child = gfx_get_node_child_mut(node);
234 while (child) {
235 update_rec(child, camera, t);
236 child = gfx_get_node_sibling_mut(child);
237 }
238}
239
240void gfx_update(Scene* scene, const SceneCamera* camera, R t) {
241 assert(scene);
242 assert(camera);
243
244 SceneNode* node = gfx_get_scene_root(scene);
245 update_rec(node, camera, t);
246}