aboutsummaryrefslogtreecommitdiff
path: root/src/scene/node.c
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2025-06-27 10:18:39 -0700
committer3gg <3gg@shellblade.net>2025-06-27 10:18:39 -0700
commitbd57f345ed9dbed1d81683e48199626de2ea9044 (patch)
tree4221f2f2a7ad2244d2e93052bd68187ec91b8ea9 /src/scene/node.c
parent9a82ce0083437a4f9f58108b2c23b957d2249ad8 (diff)
Restructure projectHEADmain
Diffstat (limited to 'src/scene/node.c')
-rw-r--r--src/scene/node.c409
1 files changed, 409 insertions, 0 deletions
diff --git a/src/scene/node.c b/src/scene/node.c
new file mode 100644
index 0000000..67ce93c
--- /dev/null
+++ b/src/scene/node.c
@@ -0,0 +1,409 @@
1#include "node_impl.h"
2
3#include "animation_impl.h"
4#include "camera_impl.h"
5#include "light_impl.h"
6#include "model_impl.h"
7#include "object_impl.h"
8#include "scene_graph.h"
9#include "scene_memory.h"
10
11#include "gfx_assert.h"
12
13#include <cstring.h>
14#include <log/log.h>
15
16static void scene_node_make(SceneNode* node) {
17 assert(node);
18 node->type = LogicalNode;
19 node->transform = mat4_id();
20}
21
22SceneNode* gfx_make_node() {
23 SceneNode* node = mem_alloc_node();
24 scene_node_make(node);
25 return node;
26}
27
28SceneNode* gfx_make_anima_node(Anima* anima) {
29 assert(anima);
30 SceneNode* node = gfx_make_node();
31 node->type = AnimaNode;
32 node->anima = mem_get_anima_index(anima);
33 anima->parent = mem_get_node_index(node);
34 return node;
35}
36
37SceneNode* gfx_make_camera_node(SceneCamera* camera) {
38 assert(camera);
39 SceneNode* node = gfx_make_node();
40 node->type = CameraNode;
41 node->camera = mem_get_camera_index(camera);
42 camera->parent = mem_get_node_index(node);
43 return node;
44}
45
46SceneNode* gfx_make_light_node(Light* light) {
47 assert(light);
48 SceneNode* node = gfx_make_node();
49 node->type = LightNode;
50 node->light = mem_get_light_index(light);
51 light->parent = mem_get_node_index(node);
52 return node;
53}
54
55SceneNode* gfx_make_model_node(Model* model) {
56 assert(model);
57 SceneNode* node = gfx_make_node();
58 node->type = ModelNode;
59 node->model = mem_get_model_index(model);
60 model->parent = mem_get_node_index(node);
61 return node;
62}
63
64SceneNode* gfx_make_object_node(SceneObject* object) {
65 assert(object);
66 SceneNode* node = gfx_make_node();
67 node->type = ObjectNode;
68 node->object = mem_get_object_index(object);
69 object->parent = mem_get_node_index(node);
70 return node;
71}
72
73/// Frees the node's resource.
74static void free_node_resource(SceneNode* node) {
75 assert(node);
76
77 // Set the resource's parent node back to 0 to avoid a recursive call into
78 // gfx_del_node().
79 switch (node->type) {
80 case AnimaNode: {
81 Anima* anima = mem_get_anima(node->anima);
82 anima->parent.val = 0;
83 gfx_destroy_anima(&anima);
84 return;
85 }
86 case CameraNode: {
87 SceneCamera* camera = mem_get_camera(node->camera);
88 camera->parent.val = 0;
89 gfx_destroy_camera(&camera);
90 return;
91 }
92 case LightNode: {
93 Light* light = mem_get_light(node->light);
94 light->parent.val = 0;
95 gfx_destroy_light(&light);
96 return;
97 }
98 case ModelNode: {
99 return; // Model data is owned by the asset cache.
100 }
101 case ObjectNode: {
102 SceneObject* object = mem_get_object(node->object);
103 object->parent.val = 0;
104 gfx_destroy_object(&object);
105 return;
106 }
107 case LogicalNode:
108 return; // Logical nodes have no resource.
109 }
110 FAIL("unhandled node type");
111}
112
113void gfx_construct_anima_node(SceneNode* node, Anima* anima) {
114 assert(node);
115 assert(anima);
116 free_node_resource(node);
117 node->type = AnimaNode;
118 node->anima = mem_get_anima_index(anima);
119 anima->parent = mem_get_node_index(node);
120}
121
122void gfx_construct_camera_node(SceneNode* node, SceneCamera* camera) {
123 assert(node);
124 assert(camera);
125 free_node_resource(node);
126 node->type = CameraNode;
127 node->camera = mem_get_camera_index(camera);
128 camera->parent = mem_get_node_index(node);
129}
130
131// TODO: Add a common helper function between each gfx_make_xyz_node() and
132// gfx_construct_xyz_node() pair.
133void gfx_construct_light_node(SceneNode* node, Light* light) {
134 assert(node);
135 assert(light);
136 free_node_resource(node);
137 node->type = LightNode;
138 node->light = mem_get_light_index(light);
139 light->parent = mem_get_node_index(node);
140}
141
142void gfx_construct_model_node(SceneNode* node, Model* model) {
143 assert(node);
144 assert(model);
145 free_node_resource(node);
146 node->type = ModelNode;
147 node->model = mem_get_model_index(model);
148 model->parent = mem_get_node_index(node);
149}
150
151void gfx_construct_object_node(SceneNode* node, SceneObject* object) {
152 assert(node);
153 assert(object);
154 free_node_resource(node);
155 node->type = ObjectNode;
156 node->object = mem_get_object_index(object);
157 object->parent = mem_get_node_index(node);
158}
159
160static void destroy_node_rec(SceneNode* node) {
161 assert(node);
162
163 // First child.
164 if (node->child.val) {
165 destroy_node_rec(mem_get_node(node->child));
166 }
167
168 // Right sibling.
169 if (node->next.val) {
170 destroy_node_rec(mem_get_node(node->next));
171 }
172
173 free_node_resource(node);
174 mem_free_node(&node);
175}
176
177void gfx_destroy_node(SceneNode** node) {
178 assert(node);
179 if (*node) {
180 // Since the node and the whole hierarchy under it gets destroyed, there is
181 // no need to individually detach every node from its hierarchy. We can
182 // simply detach the given node and then destroy it and its sub-hierarchy.
183 TREE_REMOVE(*node);
184 destroy_node_rec(*node);
185 *node = 0;
186 }
187}
188
189// TODO: Think more about ownership of nodes and resources. Should this function
190// even exist?
191void gfx_del_node(node_idx index) {
192 assert(index.val);
193 SceneNode* node = mem_get_node(index);
194 assert(node);
195 // TODO: Should destroy children recursively?
196 TREE_REMOVE(node);
197 mem_free_node(&node);
198}
199
200NodeType gfx_get_node_type(const SceneNode* node) {
201 assert(node);
202 return node->type;
203}
204
205#define NODE_GET(node, field, expected_type) \
206 { \
207 assert(node); \
208 assert(node->type == expected_type); \
209 return mem_get_##field(node->field); \
210 }
211
212const Anima* gfx_get_node_anima(const SceneNode* node) {
213 NODE_GET(node, anima, AnimaNode);
214}
215
216Anima* gfx_get_node_anima_mut(SceneNode* node) {
217 NODE_GET(node, anima, AnimaNode);
218}
219
220const SceneCamera* gfx_get_node_camera(const SceneNode* node) {
221 NODE_GET(node, camera, CameraNode);
222}
223
224SceneCamera* gfx_get_node_camera_mut(SceneNode* node) {
225 NODE_GET(node, camera, CameraNode);
226}
227
228const Light* gfx_get_node_light(const SceneNode* node) {
229 NODE_GET(node, light, LightNode);
230}
231
232Light* gfx_get_node_light_mut(SceneNode* node) {
233 NODE_GET(node, light, LightNode);
234}
235
236const Model* gfx_get_node_model(const SceneNode* node) {
237 NODE_GET(node, model, ModelNode);
238}
239
240Model* gfx_get_node_model_mut(SceneNode* node) {
241 NODE_GET(node, model, ModelNode);
242}
243
244const SceneObject* gfx_get_node_object(const SceneNode* node) {
245 NODE_GET(node, object, ObjectNode);
246}
247
248SceneObject* gfx_get_node_object_mut(SceneNode* node) {
249 NODE_GET(node, object, ObjectNode);
250}
251
252const SceneNode* gfx_get_node_parent(const SceneNode* node) {
253 assert(node);
254 return mem_get_node(node->parent);
255}
256
257SceneNode* gfx_get_node_parent_mut(SceneNode* node) {
258 assert(node);
259 return mem_get_node(node->parent);
260}
261
262const SceneNode* gfx_get_node_child(const SceneNode* node) {
263 assert(node);
264 if (node->child.val) {
265 return mem_get_node(node->child);
266 } else {
267 return 0;
268 }
269}
270
271SceneNode* gfx_get_node_child_mut(SceneNode* node) {
272 return (SceneNode*)gfx_get_node_child(node);
273}
274
275const SceneNode* gfx_get_node_sibling(const SceneNode* node) {
276 assert(node);
277 if (node->next.val) {
278 return mem_get_node(node->next);
279 } else {
280 return 0;
281 }
282}
283
284SceneNode* gfx_get_node_sibling_mut(SceneNode* node) {
285 return (SceneNode*)gfx_get_node_sibling(node);
286}
287
288mat4 gfx_get_node_transform(const SceneNode* node) {
289 assert(node);
290 return node->transform;
291}
292
293mat4 gfx_get_node_global_transform(const SceneNode* node) {
294 assert(node);
295 mat4 transform = node->transform;
296 node_idx parent_index = node->parent;
297 while (parent_index.val != 0) {
298 const SceneNode* parent = mem_get_node(parent_index);
299 transform = mat4_mul(parent->transform, transform);
300 parent_index = parent->parent;
301 }
302 return transform;
303}
304
305void gfx_set_node_parent(SceneNode* child, SceneNode* parent_node) {
306 assert(child);
307 // Parent can be null.
308 SET_PARENT(child, parent_node);
309}
310
311void gfx_set_node_transform(SceneNode* node, const mat4* transform) {
312 assert(node);
313 assert(transform);
314 node->transform = *transform;
315}
316
317void gfx_set_node_position(SceneNode* node, const vec3* position) {
318 assert(node);
319 assert(position);
320 mat4_set_v3(&node->transform, *position);
321}
322
323void gfx_set_node_rotation(SceneNode* node, const quat* rotation) {
324 assert(node);
325 assert(rotation);
326 mat4_set_3x3(&node->transform, mat4_from_quat(*rotation));
327}
328
329void gfx_set_node_rotation_mat(SceneNode* node, const mat4* rotation) {
330 assert(node);
331 assert(rotation);
332 mat4_set_3x3(&node->transform, *rotation);
333}
334
335static const char* get_node_type_str(NodeType type) {
336 switch (type) {
337 case LogicalNode:
338 return "LogicalNode";
339 case AnimaNode:
340 return "AnimaNode";
341 case CameraNode:
342 return "CameraNode";
343 case LightNode:
344 return "LightNode";
345 case ModelNode:
346 return "ModelNode";
347 case ObjectNode:
348 return "ObjectNode";
349 }
350 FAIL("Unhandled node type");
351 return "";
352}
353
354static void log_node_hierarchy_rec(const SceneNode* node, const sstring* pad) {
355 assert(node);
356 assert(pad);
357
358 LOGI(
359 "%s%s (%u)", sstring_cstr(pad), get_node_type_str(node->type),
360 mem_get_node_index(node).val);
361
362 // Log the children.
363 if (node->child.val) {
364 const sstring new_pad = sstring_concat_cstr(*pad, " ");
365 log_node_hierarchy_rec(mem_get_node(node->child), &new_pad);
366 }
367
368 // Then log the siblings.
369 if (node->next.val) {
370 log_node_hierarchy_rec(mem_get_node(node->next), pad);
371 }
372}
373
374void gfx_log_node_hierarchy(const SceneNode* node) {
375 const sstring pad = sstring_make("");
376 log_node_hierarchy_rec(node, &pad);
377}
378
379static SceneNode* clone_scene_rec(const SceneNode* node) {
380 assert(node);
381
382 SceneNode* copy = mem_alloc_node();
383 *copy = *node; // Shallow clone of the node's resource.
384
385 if (node->child.val) {
386 SceneNode* child = mem_get_node(node->child);
387 SceneNode* child_copy = clone_scene_rec(child);
388 copy->child = mem_get_node_index(child_copy);
389 child_copy->parent = mem_get_node_index(copy);
390 }
391
392 if (node->next.val) {
393 SceneNode* next = mem_get_node(node->next);
394 SceneNode* next_copy = clone_scene_rec(next);
395 copy->next = mem_get_node_index(next_copy);
396 next_copy->prev = mem_get_node_index(copy);
397 }
398
399 return copy;
400}
401
402SceneNode* gfx_clone_scene_shallow(const SceneNode* node) {
403 assert(node);
404 // Must be a root node; not allowed to have siblings.
405 assert(!node->prev.val);
406 assert(!node->next.val);
407
408 return clone_scene_rec(node);
409}