Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
MorsGames
GitHub Repository: MorsGames/sm64plus
Path: blob/master/src/engine/graph_node.c
7857 views
1
#include <ultra64.h>
2
#include "sm64.h"
3
4
#include "game/level_update.h"
5
#include "math_util.h"
6
#include "game/memory.h"
7
#include "graph_node.h"
8
#include "game/rendering_graph_node.h"
9
#include "game/area.h"
10
#include "geo_layout.h"
11
12
// unused Mtx(s)
13
s16 identityMtx[4][4] = { { 1, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } };
14
s16 zeroMtx[4][4] = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } };
15
16
Vec3f gVec3fZero = { 0.0f, 0.0f, 0.0f };
17
Vec3s gVec3sZero = { 0, 0, 0 };
18
Vec3f gVec3fOne = { 1.0f, 1.0f, 1.0f };
19
UNUSED Vec3s gVec3sOne = { 1, 1, 1 };
20
21
/**
22
* Initialize a geo node with a given type. Sets all links such that there
23
* are no siblings, parent or children for this node.
24
*/
25
void init_scene_graph_node_links(struct GraphNode *graphNode, s32 type) {
26
graphNode->type = type;
27
graphNode->flags = GRAPH_RENDER_ACTIVE;
28
graphNode->prev = graphNode;
29
graphNode->next = graphNode;
30
graphNode->parent = NULL;
31
graphNode->children = NULL;
32
}
33
34
/**
35
* Allocated and returns a newly created root node
36
*/
37
struct GraphNodeRoot *init_graph_node_root(struct AllocOnlyPool *pool, struct GraphNodeRoot *graphNode,
38
s16 areaIndex, s16 x, s16 y, s16 width, s16 height) {
39
if (pool != NULL) {
40
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeRoot));
41
}
42
43
if (graphNode != NULL) {
44
init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_ROOT);
45
46
graphNode->areaIndex = areaIndex;
47
graphNode->unk15 = 0;
48
graphNode->x = x;
49
graphNode->y = y;
50
graphNode->width = width;
51
graphNode->height = height;
52
graphNode->views = NULL;
53
graphNode->numViews = 0;
54
}
55
56
return graphNode;
57
}
58
59
/**
60
* Allocates and returns a newly created otrhographic projection node
61
*/
62
struct GraphNodeOrthoProjection *
63
init_graph_node_ortho_projection(struct AllocOnlyPool *pool, struct GraphNodeOrthoProjection *graphNode,
64
f32 scale) {
65
if (pool != NULL) {
66
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeOrthoProjection));
67
}
68
69
if (graphNode != NULL) {
70
init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_ORTHO_PROJECTION);
71
graphNode->scale = scale;
72
}
73
74
return graphNode;
75
}
76
77
/**
78
* Allocates and returns a newly created perspective node
79
*/
80
struct GraphNodePerspective *init_graph_node_perspective(struct AllocOnlyPool *pool,
81
struct GraphNodePerspective *graphNode,
82
f32 fov, s16 near, s16 far,
83
GraphNodeFunc nodeFunc, s32 unused) {
84
if (pool != NULL) {
85
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodePerspective));
86
}
87
88
if (graphNode != NULL) {
89
init_scene_graph_node_links(&graphNode->fnNode.node, GRAPH_NODE_TYPE_PERSPECTIVE);
90
91
graphNode->fov = fov;
92
graphNode->near = near;
93
graphNode->far = far;
94
graphNode->fnNode.func = nodeFunc;
95
graphNode->unused = unused;
96
97
if (nodeFunc != NULL) {
98
nodeFunc(GEO_CONTEXT_CREATE, &graphNode->fnNode.node, pool);
99
}
100
}
101
102
return graphNode;
103
}
104
105
/**
106
* Allocates and returns a newly created start node
107
*/
108
struct GraphNodeStart *init_graph_node_start(struct AllocOnlyPool *pool,
109
struct GraphNodeStart *graphNode) {
110
if (pool != NULL) {
111
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeStart));
112
}
113
114
if (graphNode != NULL) {
115
init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_START);
116
}
117
118
return graphNode;
119
}
120
121
/**
122
* Allocates and returns a newly created master list node
123
*/
124
struct GraphNodeMasterList *init_graph_node_master_list(struct AllocOnlyPool *pool,
125
struct GraphNodeMasterList *graphNode, s16 on) {
126
if (pool != NULL) {
127
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeMasterList));
128
}
129
130
if (graphNode != NULL) {
131
init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_MASTER_LIST);
132
133
if (on) {
134
graphNode->node.flags |= GRAPH_RENDER_Z_BUFFER;
135
}
136
}
137
138
return graphNode;
139
}
140
141
/**
142
* Allocates and returns a newly created render range node
143
*/
144
struct GraphNodeLevelOfDetail *init_graph_node_render_range(struct AllocOnlyPool *pool,
145
struct GraphNodeLevelOfDetail *graphNode,
146
s16 minDistance, s16 maxDistance) {
147
if (pool != NULL) {
148
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeLevelOfDetail));
149
}
150
151
if (graphNode != NULL) {
152
init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_LEVEL_OF_DETAIL);
153
graphNode->minDistance = minDistance;
154
graphNode->maxDistance = maxDistance;
155
}
156
157
return graphNode;
158
}
159
160
/**
161
* Allocates and returns a newly created switch case node
162
*/
163
struct GraphNodeSwitchCase *init_graph_node_switch_case(struct AllocOnlyPool *pool,
164
struct GraphNodeSwitchCase *graphNode,
165
s16 numCases, s16 selectedCase,
166
GraphNodeFunc nodeFunc, s32 unused) {
167
if (pool != NULL) {
168
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeSwitchCase));
169
}
170
171
if (graphNode != NULL) {
172
init_scene_graph_node_links(&graphNode->fnNode.node, GRAPH_NODE_TYPE_SWITCH_CASE);
173
graphNode->numCases = numCases;
174
graphNode->selectedCase = selectedCase;
175
graphNode->fnNode.func = nodeFunc;
176
graphNode->unused = unused;
177
178
if (nodeFunc != NULL) {
179
nodeFunc(GEO_CONTEXT_CREATE, &graphNode->fnNode.node, pool);
180
}
181
}
182
183
return graphNode;
184
}
185
186
/**
187
* Allocates and returns a newly created camera node
188
*/
189
struct GraphNodeCamera *init_graph_node_camera(struct AllocOnlyPool *pool,
190
struct GraphNodeCamera *graphNode, f32 *pos,
191
f32 *focus, GraphNodeFunc func, s32 mode) {
192
if (pool != NULL) {
193
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeCamera));
194
}
195
196
if (graphNode != NULL) {
197
init_scene_graph_node_links(&graphNode->fnNode.node, GRAPH_NODE_TYPE_CAMERA);
198
vec3f_copy(graphNode->pos, pos);
199
vec3f_copy(graphNode->focus, focus);
200
graphNode->fnNode.func = func;
201
graphNode->config.mode = mode;
202
graphNode->roll = 0;
203
graphNode->rollScreen = 0;
204
205
if (func != NULL) {
206
func(GEO_CONTEXT_CREATE, &graphNode->fnNode.node, pool);
207
}
208
}
209
210
return graphNode;
211
}
212
213
/**
214
* Allocates and returns a newly created translation rotation node
215
*/
216
struct GraphNodeTranslationRotation *
217
init_graph_node_translation_rotation(struct AllocOnlyPool *pool,
218
struct GraphNodeTranslationRotation *graphNode, s32 drawingLayer,
219
void *displayList, Vec3s translation, Vec3s rotation) {
220
if (pool != NULL) {
221
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeTranslationRotation));
222
}
223
224
if (graphNode != NULL) {
225
init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_TRANSLATION_ROTATION);
226
227
vec3s_copy(graphNode->translation, translation);
228
vec3s_copy(graphNode->rotation, rotation);
229
graphNode->node.flags = (drawingLayer << 8) | (graphNode->node.flags & 0xFF);
230
graphNode->displayList = displayList;
231
}
232
233
return graphNode;
234
}
235
236
/**
237
* Allocates and returns a newly created translation node
238
*/
239
struct GraphNodeTranslation *init_graph_node_translation(struct AllocOnlyPool *pool,
240
struct GraphNodeTranslation *graphNode,
241
s32 drawingLayer, void *displayList,
242
Vec3s translation) {
243
if (pool != NULL) {
244
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeTranslation));
245
}
246
247
if (graphNode != NULL) {
248
init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_TRANSLATION);
249
250
vec3s_copy(graphNode->translation, translation);
251
graphNode->node.flags = (drawingLayer << 8) | (graphNode->node.flags & 0xFF);
252
graphNode->displayList = displayList;
253
}
254
255
return graphNode;
256
}
257
258
/**
259
* Allocates and returns a newly created rotation node
260
*/
261
struct GraphNodeRotation *init_graph_node_rotation(struct AllocOnlyPool *pool,
262
struct GraphNodeRotation *graphNode,
263
s32 drawingLayer, void *displayList,
264
Vec3s rotation) {
265
if (pool != NULL) {
266
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeRotation));
267
}
268
269
if (graphNode != NULL) {
270
init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_ROTATION);
271
vec3s_copy(graphNode->rotation, rotation);
272
graphNode->node.flags = (drawingLayer << 8) | (graphNode->node.flags & 0xFF);
273
graphNode->displayList = displayList;
274
}
275
276
return graphNode;
277
}
278
279
/**
280
* Allocates and returns a newly created scaling node
281
*/
282
struct GraphNodeScale *init_graph_node_scale(struct AllocOnlyPool *pool,
283
struct GraphNodeScale *graphNode, s32 drawingLayer,
284
void *displayList, f32 scale) {
285
if (pool != NULL) {
286
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeScale));
287
}
288
289
if (graphNode != NULL) {
290
init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_SCALE);
291
graphNode->node.flags = (drawingLayer << 8) | (graphNode->node.flags & 0xFF);
292
graphNode->scale = scale;
293
graphNode->displayList = displayList;
294
}
295
296
return graphNode;
297
}
298
299
/**
300
* Allocates and returns a newly created object node
301
*/
302
struct GraphNodeObject *init_graph_node_object(struct AllocOnlyPool *pool,
303
struct GraphNodeObject *graphNode,
304
struct GraphNode *sharedChild, Vec3f pos, Vec3s angle,
305
Vec3f scale) {
306
if (pool != NULL) {
307
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeObject));
308
}
309
310
if (graphNode != NULL) {
311
init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_OBJECT);
312
vec3f_copy(graphNode->pos, pos);
313
vec3f_copy(graphNode->scale, scale);
314
vec3s_copy(graphNode->angle, angle);
315
#ifdef USE_SYSTEM_MALLOC
316
// To avoid uninitialised memory usage in audio code
317
vec3f_copy(graphNode->cameraToObject, gVec3fZero);
318
#endif
319
graphNode->sharedChild = sharedChild;
320
graphNode->throwMatrix = NULL;
321
graphNode->animInfo.animID = 0;
322
graphNode->animInfo.curAnim = NULL;
323
graphNode->animInfo.animFrame = 0;
324
graphNode->animInfo.animFrameAccelAssist = 0;
325
graphNode->animInfo.animAccel = 0x10000;
326
graphNode->animInfo.animTimer = 0;
327
graphNode->node.flags |= GRAPH_RENDER_HAS_ANIMATION;
328
}
329
330
return graphNode;
331
}
332
333
/**
334
* Allocates and returns a newly created frustum culling radius node
335
*/
336
struct GraphNodeCullingRadius *init_graph_node_culling_radius(struct AllocOnlyPool *pool,
337
struct GraphNodeCullingRadius *graphNode,
338
s16 radius) {
339
if (pool != NULL) {
340
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeCullingRadius));
341
}
342
343
if (graphNode != NULL) {
344
init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_CULLING_RADIUS);
345
graphNode->cullingRadius = radius;
346
}
347
348
return graphNode;
349
}
350
351
/**
352
* Allocates and returns a newly created animated part node
353
*/
354
struct GraphNodeAnimatedPart *init_graph_node_animated_part(struct AllocOnlyPool *pool,
355
struct GraphNodeAnimatedPart *graphNode,
356
s32 drawingLayer, void *displayList,
357
Vec3s translation) {
358
if (pool != NULL) {
359
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeAnimatedPart));
360
}
361
362
if (graphNode != NULL) {
363
init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_ANIMATED_PART);
364
vec3s_copy(graphNode->translation, translation);
365
graphNode->node.flags = (drawingLayer << 8) | (graphNode->node.flags & 0xFF);
366
graphNode->displayList = displayList;
367
}
368
369
return graphNode;
370
}
371
372
/**
373
* Allocates and returns a newly created billboard node
374
*/
375
struct GraphNodeBillboard *init_graph_node_billboard(struct AllocOnlyPool *pool,
376
struct GraphNodeBillboard *graphNode,
377
s32 drawingLayer, void *displayList,
378
Vec3s translation) {
379
if (pool != NULL) {
380
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeBillboard));
381
}
382
383
if (graphNode != NULL) {
384
init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_BILLBOARD);
385
vec3s_copy(graphNode->translation, translation);
386
graphNode->node.flags = (drawingLayer << 8) | (graphNode->node.flags & 0xFF);
387
graphNode->displayList = displayList;
388
}
389
390
return graphNode;
391
}
392
393
/**
394
* Allocates and returns a newly created displaylist node
395
*/
396
struct GraphNodeDisplayList *init_graph_node_display_list(struct AllocOnlyPool *pool,
397
struct GraphNodeDisplayList *graphNode,
398
s32 drawingLayer, void *displayList) {
399
if (pool != NULL) {
400
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeDisplayList));
401
}
402
403
if (graphNode != NULL) {
404
init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_DISPLAY_LIST);
405
graphNode->node.flags = (drawingLayer << 8) | (graphNode->node.flags & 0xFF);
406
graphNode->displayList = displayList;
407
}
408
409
return graphNode;
410
}
411
412
/**
413
* Allocates and returns a newly created shadow node
414
*/
415
struct GraphNodeShadow *init_graph_node_shadow(struct AllocOnlyPool *pool,
416
struct GraphNodeShadow *graphNode, s16 shadowScale,
417
u8 shadowSolidity, u8 shadowType) {
418
if (pool != NULL) {
419
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeShadow));
420
}
421
422
if (graphNode != NULL) {
423
init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_SHADOW);
424
graphNode->shadowScale = shadowScale;
425
graphNode->shadowSolidity = shadowSolidity;
426
graphNode->shadowType = shadowType;
427
}
428
429
return graphNode;
430
}
431
432
/**
433
* Allocates and returns a newly created object parent node
434
*/
435
struct GraphNodeObjectParent *init_graph_node_object_parent(struct AllocOnlyPool *pool,
436
struct GraphNodeObjectParent *graphNode,
437
struct GraphNode *sharedChild) {
438
if (pool != NULL) {
439
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeObjectParent));
440
}
441
442
if (graphNode != NULL) {
443
init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_OBJECT_PARENT);
444
graphNode->sharedChild = sharedChild;
445
}
446
447
return graphNode;
448
}
449
450
/**
451
* Allocates and returns a newly created generated node
452
*/
453
struct GraphNodeGenerated *init_graph_node_generated(struct AllocOnlyPool *pool,
454
struct GraphNodeGenerated *graphNode,
455
GraphNodeFunc gfxFunc, s32 parameter) {
456
if (pool != NULL) {
457
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeGenerated));
458
}
459
460
if (graphNode != NULL) {
461
init_scene_graph_node_links(&graphNode->fnNode.node, GRAPH_NODE_TYPE_GENERATED_LIST);
462
graphNode->fnNode.func = gfxFunc;
463
graphNode->parameter = parameter;
464
465
if (gfxFunc != NULL) {
466
gfxFunc(GEO_CONTEXT_CREATE, &graphNode->fnNode.node, pool);
467
}
468
}
469
470
return graphNode;
471
}
472
473
/**
474
* Allocates and returns a newly created background node
475
*/
476
struct GraphNodeBackground *init_graph_node_background(struct AllocOnlyPool *pool,
477
struct GraphNodeBackground *graphNode,
478
u16 background, GraphNodeFunc backgroundFunc,
479
s32 zero) {
480
if (pool != NULL) {
481
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeBackground));
482
}
483
484
if (graphNode != NULL) {
485
init_scene_graph_node_links(&graphNode->fnNode.node, GRAPH_NODE_TYPE_BACKGROUND);
486
487
graphNode->background = (background << 16) | background;
488
graphNode->fnNode.func = backgroundFunc;
489
graphNode->unused = zero; // always 0, unused
490
491
if (backgroundFunc != NULL) {
492
backgroundFunc(GEO_CONTEXT_CREATE, &graphNode->fnNode.node, pool);
493
}
494
}
495
496
return graphNode;
497
}
498
499
/**
500
* Allocates and returns a newly created held object node
501
*/
502
struct GraphNodeHeldObject *init_graph_node_held_object(struct AllocOnlyPool *pool,
503
struct GraphNodeHeldObject *graphNode,
504
struct Object *objNode,
505
Vec3s translation,
506
GraphNodeFunc nodeFunc, s32 playerIndex) {
507
if (pool != NULL) {
508
graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeHeldObject));
509
}
510
511
if (graphNode != NULL) {
512
init_scene_graph_node_links(&graphNode->fnNode.node, GRAPH_NODE_TYPE_HELD_OBJ);
513
vec3s_copy(graphNode->translation, translation);
514
graphNode->objNode = objNode;
515
graphNode->fnNode.func = nodeFunc;
516
graphNode->playerIndex = playerIndex;
517
518
if (nodeFunc != NULL) {
519
nodeFunc(GEO_CONTEXT_CREATE, &graphNode->fnNode.node, pool);
520
}
521
}
522
523
return graphNode;
524
}
525
526
/**
527
* Adds 'childNode' to the end of the list children from 'parent'
528
*/
529
struct GraphNode *geo_add_child(struct GraphNode *parent, struct GraphNode *childNode) {
530
struct GraphNode *parentFirstChild;
531
struct GraphNode *parentLastChild;
532
533
if (childNode != NULL) {
534
childNode->parent = parent;
535
parentFirstChild = parent->children;
536
537
if (parentFirstChild == NULL) {
538
parent->children = childNode;
539
childNode->prev = childNode;
540
childNode->next = childNode;
541
} else {
542
parentLastChild = parentFirstChild->prev;
543
childNode->prev = parentLastChild;
544
childNode->next = parentFirstChild;
545
parentFirstChild->prev = childNode;
546
parentLastChild->next = childNode;
547
}
548
}
549
550
return childNode;
551
}
552
553
/**
554
* Remove a node from the scene graph. It changes the links with its
555
* siblings and with its parent, it doesn't deallocate the memory
556
* since geo nodes are allocated in a pointer-bumping pool that
557
* gets thrown out when changing areas.
558
*/
559
struct GraphNode *geo_remove_child(struct GraphNode *graphNode) {
560
struct GraphNode *parent;
561
struct GraphNode **firstChild;
562
563
parent = graphNode->parent;
564
firstChild = &parent->children;
565
566
// Remove link with siblings
567
graphNode->prev->next = graphNode->next;
568
graphNode->next->prev = graphNode->prev;
569
570
// If this node was the first child, a new first child must be chosen
571
if (*firstChild == graphNode) {
572
// The list is circular, so this checks whether it was the only child
573
if (graphNode->next == graphNode) {
574
*firstChild = NULL; // Parent has no children anymore
575
} else {
576
*firstChild = graphNode->next; // Choose a new first child
577
}
578
}
579
580
return parent;
581
}
582
583
/**
584
* Reorders the given node so it's the first child of its parent.
585
* This is called on the Mario object when he is spawned. That's why Mario's
586
* object is always drawn before any other objects. (Note that the geo order
587
* is independent from processing group order, where Mario is not first.)
588
*/
589
struct GraphNode *geo_make_first_child(struct GraphNode *newFirstChild) {
590
struct GraphNode *lastSibling;
591
struct GraphNode *parent;
592
struct GraphNode **firstChild;
593
594
parent = newFirstChild->parent;
595
firstChild = &parent->children;
596
597
if (*firstChild != newFirstChild) {
598
if ((*firstChild)->prev != newFirstChild) {
599
newFirstChild->prev->next = newFirstChild->next;
600
newFirstChild->next->prev = newFirstChild->prev;
601
lastSibling = (*firstChild)->prev;
602
newFirstChild->prev = lastSibling;
603
newFirstChild->next = *firstChild;
604
(*firstChild)->prev = newFirstChild;
605
lastSibling->next = newFirstChild;
606
}
607
*firstChild = newFirstChild;
608
}
609
610
return parent;
611
}
612
613
/**
614
* Helper function for geo_call_global_function_nodes that recursively
615
* traverses the scene graph and calls the functions of global nodes.
616
*/
617
void geo_call_global_function_nodes_helper(struct GraphNode *graphNode, s32 callContext) {
618
struct GraphNode **globalPtr;
619
struct GraphNode *curNode;
620
struct FnGraphNode *asFnNode;
621
622
curNode = graphNode;
623
624
do {
625
asFnNode = (struct FnGraphNode *) curNode;
626
627
if (curNode->type & GRAPH_NODE_TYPE_FUNCTIONAL) {
628
if (asFnNode->func != NULL) {
629
asFnNode->func(callContext, curNode, NULL);
630
}
631
}
632
633
if (curNode->children != NULL) {
634
switch (curNode->type) {
635
case GRAPH_NODE_TYPE_MASTER_LIST:
636
globalPtr = (struct GraphNode **) &gCurGraphNodeMasterList;
637
break;
638
case GRAPH_NODE_TYPE_PERSPECTIVE:
639
globalPtr = (struct GraphNode **) &gCurGraphNodeCamFrustum;
640
break;
641
case GRAPH_NODE_TYPE_CAMERA:
642
globalPtr = (struct GraphNode **) &gCurGraphNodeCamera;
643
break;
644
case GRAPH_NODE_TYPE_OBJECT:
645
globalPtr = (struct GraphNode **) &gCurGraphNodeObject;
646
break;
647
default:
648
globalPtr = NULL;
649
break;
650
}
651
652
if (globalPtr != NULL) {
653
*globalPtr = curNode;
654
}
655
656
geo_call_global_function_nodes_helper(curNode->children, callContext);
657
658
if (globalPtr != NULL) {
659
*globalPtr = NULL;
660
}
661
}
662
} while ((curNode = curNode->next) != graphNode);
663
}
664
665
/**
666
* Call the update functions of geo nodes that are stored in global variables.
667
* These variables include gCurGraphNodeMasterList, gCurGraphNodeCamFrustum,
668
* gCurGraphNodeCamera and gCurGraphNodeObject.
669
* callContext is one of the GEO_CONTEXT_ defines.
670
* The graphNode argument should be of type GraphNodeRoot.
671
*/
672
void geo_call_global_function_nodes(struct GraphNode *graphNode, s32 callContext) {
673
if (graphNode->flags & GRAPH_RENDER_ACTIVE) {
674
gCurGraphNodeRoot = (struct GraphNodeRoot *) graphNode;
675
676
if (graphNode->children != NULL) {
677
geo_call_global_function_nodes_helper(graphNode->children, callContext);
678
}
679
680
gCurGraphNodeRoot = 0;
681
}
682
}
683
684
/**
685
* When objects are cleared, this is called on all object nodes (loaded or unloaded).
686
*/
687
void geo_reset_object_node(struct GraphNodeObject *graphNode) {
688
init_graph_node_object(NULL, graphNode, 0, gVec3fZero, gVec3sZero, gVec3fOne);
689
690
geo_add_child(&gObjParentGraphNode, &graphNode->node);
691
graphNode->node.flags &= ~GRAPH_RENDER_ACTIVE;
692
}
693
694
/**
695
* Initialize an object node using the given parameters
696
*/
697
void geo_obj_init(struct GraphNodeObject *graphNode, void *sharedChild, Vec3f pos, Vec3s angle) {
698
vec3f_set(graphNode->scale, 1.0f, 1.0f, 1.0f);
699
vec3f_copy(graphNode->pos, pos);
700
vec3s_copy(graphNode->angle, angle);
701
702
graphNode->sharedChild = sharedChild;
703
graphNode->unk4C = 0;
704
graphNode->throwMatrix = NULL;
705
graphNode->animInfo.curAnim = NULL;
706
707
graphNode->node.flags |= GRAPH_RENDER_ACTIVE;
708
graphNode->node.flags &= ~GRAPH_RENDER_INVISIBLE;
709
graphNode->node.flags |= GRAPH_RENDER_HAS_ANIMATION;
710
graphNode->node.flags &= ~GRAPH_RENDER_BILLBOARD;
711
}
712
713
/**
714
* Initialize and object node using the given SpawnInfo struct
715
*/
716
void geo_obj_init_spawninfo(struct GraphNodeObject *graphNode, struct SpawnInfo *spawn) {
717
vec3f_set(graphNode->scale, 1.0f, 1.0f, 1.0f);
718
vec3s_copy(graphNode->angle, spawn->startAngle);
719
720
graphNode->pos[0] = (f32) spawn->startPos[0];
721
graphNode->pos[1] = (f32) spawn->startPos[1];
722
graphNode->pos[2] = (f32) spawn->startPos[2];
723
724
graphNode->areaIndex = spawn->areaIndex;
725
graphNode->activeAreaIndex = spawn->activeAreaIndex;
726
graphNode->sharedChild = spawn->unk18;
727
graphNode->unk4C = spawn;
728
graphNode->throwMatrix = NULL;
729
graphNode->animInfo.curAnim = 0;
730
731
graphNode->node.flags |= GRAPH_RENDER_ACTIVE;
732
graphNode->node.flags &= ~GRAPH_RENDER_INVISIBLE;
733
graphNode->node.flags |= GRAPH_RENDER_HAS_ANIMATION;
734
graphNode->node.flags &= ~GRAPH_RENDER_BILLBOARD;
735
}
736
737
/**
738
* Initialize the animation of an object node
739
*/
740
void geo_obj_init_animation(struct GraphNodeObject *graphNode, struct Animation **animPtrAddr) {
741
struct Animation **animSegmented = segmented_to_virtual(animPtrAddr);
742
struct Animation *anim = segmented_to_virtual(*animSegmented);
743
744
if (graphNode->animInfo.curAnim != anim) {
745
graphNode->animInfo.curAnim = anim;
746
graphNode->animInfo.animFrame = anim->startFrame + ((anim->flags & ANIM_FLAG_FORWARD) ? 1 : -1);
747
graphNode->animInfo.animAccel = 0;
748
graphNode->animInfo.animYTrans = 0;
749
}
750
}
751
752
/**
753
* Initialize the animation of an object node
754
*/
755
void geo_obj_init_animation_accel(struct GraphNodeObject *graphNode, struct Animation **animPtrAddr, u32 animAccel) {
756
struct Animation **animSegmented = segmented_to_virtual(animPtrAddr);
757
struct Animation *anim = segmented_to_virtual(*animSegmented);
758
759
if (graphNode->animInfo.curAnim != anim) {
760
graphNode->animInfo.curAnim = anim;
761
graphNode->animInfo.animYTrans = 0;
762
graphNode->animInfo.animFrameAccelAssist =
763
(anim->startFrame << 16) + ((anim->flags & ANIM_FLAG_FORWARD) ? animAccel : -animAccel);
764
graphNode->animInfo.animFrame = graphNode->animInfo.animFrameAccelAssist >> 16;
765
}
766
767
graphNode->animInfo.animAccel = animAccel;
768
}
769
770
/**
771
* Retrieves an index into animation data based on the attribute pointer
772
* An attribute is an x-, y- or z-component of the translation / rotation for a part
773
* Each attribute is a pair of s16's, where the first s16 represents the maximum frame
774
* and the second s16 the actual index. This index can be used to index in the array
775
* with actual animation values.
776
*/
777
s32 retrieve_animation_index(s32 frame, u16 **attributes) {
778
s32 result;
779
780
if (frame < (*attributes)[0]) {
781
result = (*attributes)[1] + frame;
782
} else {
783
result = (*attributes)[1] + (*attributes)[0] - 1;
784
}
785
786
*attributes += 2;
787
788
return result;
789
}
790
791
/**
792
* Update the animation frame of an object. The animation flags determine
793
* whether it plays forwards or backwards, and whether it stops or loops at
794
* the end etc.
795
*/
796
s16 geo_update_animation_frame(struct AnimInfo *obj, s32 *accelAssist) {
797
s32 result;
798
struct Animation *anim;
799
800
anim = obj->curAnim;
801
802
if (obj->animTimer == gAreaUpdateCounter || anim->flags & ANIM_FLAG_2) {
803
if (accelAssist != NULL) {
804
accelAssist[0] = obj->animFrameAccelAssist;
805
}
806
807
return obj->animFrame;
808
}
809
810
if (anim->flags & ANIM_FLAG_FORWARD) {
811
if (obj->animAccel) {
812
result = obj->animFrameAccelAssist - obj->animAccel;
813
} else {
814
result = (obj->animFrame - 1) << 16;
815
}
816
817
if (GET_HIGH_S16_OF_32(result) < anim->loopStart) {
818
if (anim->flags & ANIM_FLAG_NOLOOP) {
819
SET_HIGH_S16_OF_32(result, anim->loopStart);
820
} else {
821
SET_HIGH_S16_OF_32(result, anim->loopEnd - 1);
822
}
823
}
824
} else {
825
if (obj->animAccel != 0) {
826
result = obj->animFrameAccelAssist + obj->animAccel;
827
} else {
828
result = (obj->animFrame + 1) << 16;
829
}
830
831
if (GET_HIGH_S16_OF_32(result) >= anim->loopEnd) {
832
if (anim->flags & ANIM_FLAG_NOLOOP) {
833
SET_HIGH_S16_OF_32(result, anim->loopEnd - 1);
834
} else {
835
SET_HIGH_S16_OF_32(result, anim->loopStart);
836
}
837
}
838
}
839
840
if (accelAssist != 0) {
841
accelAssist[0] = result;
842
}
843
844
return GET_HIGH_S16_OF_32(result);
845
}
846
847
/**
848
* Unused function to retrieve an object's current animation translation
849
* Assumes that it has x, y and z data in animations, which isn't always the
850
* case since some animation types only have vertical or lateral translation.
851
* This might have been used for positioning the shadow under an object, which
852
* currently happens in-line in geo_process_shadow where it also accounts for
853
* animations without lateral translation.
854
*/
855
void geo_retreive_animation_translation(struct GraphNodeObject *obj, Vec3f position) {
856
struct Animation *animation = obj->animInfo.curAnim;
857
858
if (animation != NULL) {
859
u16 *attribute = segmented_to_virtual((void *) animation->index);
860
s16 *values = segmented_to_virtual((void *) animation->values);
861
862
s16 frame = obj->animInfo.animFrame;
863
864
if (frame < 0) {
865
frame = 0;
866
}
867
868
position[0] = (f32) values[retrieve_animation_index(frame, &attribute)];
869
position[1] = (f32) values[retrieve_animation_index(frame, &attribute)];
870
position[2] = (f32) values[retrieve_animation_index(frame, &attribute)];
871
} else {
872
vec3f_set(position, 0, 0, 0);
873
}
874
}
875
876
/**
877
* Unused function to find the root of the geo node tree, which should be a
878
* GraphNodeRoot. If it is not for some reason, null is returned.
879
*/
880
struct GraphNodeRoot *geo_find_root(struct GraphNode *graphNode) {
881
struct GraphNodeRoot *resGraphNode = NULL;
882
883
while (graphNode->parent != NULL) {
884
graphNode = graphNode->parent;
885
}
886
887
if (graphNode->type == GRAPH_NODE_TYPE_ROOT) {
888
resGraphNode = (struct GraphNodeRoot *) graphNode;
889
}
890
891
return resGraphNode;
892
}
893
894