Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
MorsGames
GitHub Repository: MorsGames/sm64plus
Path: blob/master/src/engine/geo_layout.c
7857 views
1
#include <ultra64.h>
2
#include "sm64.h"
3
4
#include "geo_layout.h"
5
#include "math_util.h"
6
#include "game/memory.h"
7
#include "graph_node.h"
8
9
typedef void (*GeoLayoutCommandProc)(void);
10
11
GeoLayoutCommandProc GeoLayoutJumpTable[] = {
12
geo_layout_cmd_branch_and_link,
13
geo_layout_cmd_end,
14
geo_layout_cmd_branch,
15
geo_layout_cmd_return,
16
geo_layout_cmd_open_node,
17
geo_layout_cmd_close_node,
18
geo_layout_cmd_assign_as_view,
19
geo_layout_cmd_update_node_flags,
20
geo_layout_cmd_node_root,
21
geo_layout_cmd_node_ortho_projection,
22
geo_layout_cmd_node_perspective,
23
geo_layout_cmd_node_start,
24
geo_layout_cmd_node_master_list,
25
geo_layout_cmd_node_level_of_detail,
26
geo_layout_cmd_node_switch_case,
27
geo_layout_cmd_node_camera,
28
geo_layout_cmd_node_translation_rotation,
29
geo_layout_cmd_node_translation,
30
geo_layout_cmd_node_rotation,
31
geo_layout_cmd_node_animated_part,
32
geo_layout_cmd_node_billboard,
33
geo_layout_cmd_node_display_list,
34
geo_layout_cmd_node_shadow,
35
geo_layout_cmd_node_object_parent,
36
geo_layout_cmd_node_generated,
37
geo_layout_cmd_node_background,
38
geo_layout_cmd_nop,
39
geo_layout_cmd_copy_view,
40
geo_layout_cmd_node_held_obj,
41
geo_layout_cmd_node_scale,
42
geo_layout_cmd_nop2,
43
geo_layout_cmd_nop3,
44
geo_layout_cmd_node_culling_radius,
45
};
46
47
struct GraphNode gObjParentGraphNode;
48
struct AllocOnlyPool *gGraphNodePool;
49
struct GraphNode *gCurRootGraphNode;
50
51
UNUSED s32 D_8038BCA8;
52
53
/* The gGeoViews array is a mysterious one. Some background:
54
*
55
* If there are e.g. multiple Goombas, the multiple Goomba objects share one
56
* Geo node tree describing the goomba 3D model. Since every node has a single
57
* parent field and not a parent array, the parent is dynamically rebinded to
58
* each goomba instance just before rendering and set to null afterwards.
59
* The same happens for ObjectParentNode, which has as his sharedChild a group
60
* of all 240 object nodes. Why does the ObjectParentNode exist at all, if its
61
* only purpose is to temporarily bind the actual group with objects? This might
62
* be another remnant to Luigi.
63
*
64
* When creating a root node, room for (2 + cmd+0x02) pointers is allocated in
65
* gGeoViews. Except for the title screen, cmd+0x02 is 10. The 2 default ones
66
* might be for Mario and Luigi, and the other 10 could be different cameras for
67
* different rooms / boss fights. An area might be structured like this:
68
*
69
* geo_camera mode_player //Mario cam
70
* geo_open_node
71
* geo_render_obj
72
* geo_assign_as_view 1 // currently unused geo command
73
* geo_close_node
74
*
75
* geo_camera mode_player //Luigi cam
76
* geo_open_node
77
* geo_render_obj
78
* geo_copy_view 1 // currently unused geo command
79
* geo_assign_as_view 2
80
* geo_close_node
81
*
82
* geo_camera mode_boss //boss fight cam
83
* geo_assign_as_view 3
84
* ...
85
*
86
* There might also be specific geo nodes for Mario or Luigi only. Or a fixed camera
87
* might not have display list nodes of parts of the level that are out of view.
88
* In the end Luigi got scrapped and the multiple-camera design did not pan out,
89
* so everything was reduced to a single ObjectParent with a single group, and
90
* camera switching was all done in one node. End of speculation.
91
*/
92
struct GraphNode **gGeoViews;
93
u16 gGeoNumViews; // length of gGeoViews array
94
95
uintptr_t gGeoLayoutStack[16];
96
struct GraphNode *gCurGraphNodeList[32];
97
s16 gCurGraphNodeIndex;
98
s16 gGeoLayoutStackIndex; // similar to SP register in MIPS
99
UNUSED s16 D_8038BD7C;
100
s16 gGeoLayoutReturnIndex; // similar to RA register in MIPS
101
u8 *gGeoLayoutCommand;
102
103
u32 unused_8038B894[3] = { 0 };
104
105
/*
106
0x00: Branch and store return address
107
cmd+0x04: void *branchTarget
108
*/
109
void geo_layout_cmd_branch_and_link(void) {
110
gGeoLayoutStack[gGeoLayoutStackIndex++] = (uintptr_t) (gGeoLayoutCommand + CMD_PROCESS_OFFSET(8));
111
gGeoLayoutStack[gGeoLayoutStackIndex++] = (gCurGraphNodeIndex << 16) + gGeoLayoutReturnIndex;
112
gGeoLayoutReturnIndex = gGeoLayoutStackIndex;
113
gGeoLayoutCommand = segmented_to_virtual(cur_geo_cmd_ptr(0x04));
114
}
115
116
// 0x01: Terminate geo layout
117
void geo_layout_cmd_end(void) {
118
gGeoLayoutStackIndex = gGeoLayoutReturnIndex;
119
gGeoLayoutReturnIndex = gGeoLayoutStack[--gGeoLayoutStackIndex] & 0xFFFF;
120
gCurGraphNodeIndex = gGeoLayoutStack[gGeoLayoutStackIndex] >> 16;
121
gGeoLayoutCommand = (u8 *) gGeoLayoutStack[--gGeoLayoutStackIndex];
122
}
123
124
/*
125
0x02: Branch
126
cmd+0x04: void *branchTarget
127
*/
128
void geo_layout_cmd_branch(void) {
129
if (cur_geo_cmd_u8(0x01) == 1) {
130
gGeoLayoutStack[gGeoLayoutStackIndex++] = (uintptr_t) (gGeoLayoutCommand + CMD_PROCESS_OFFSET(8));
131
}
132
133
gGeoLayoutCommand = segmented_to_virtual(cur_geo_cmd_ptr(0x04));
134
}
135
136
// 0x03: Return from branch
137
void geo_layout_cmd_return(void) {
138
gGeoLayoutCommand = (u8 *) gGeoLayoutStack[--gGeoLayoutStackIndex];
139
}
140
141
// 0x04: Open node
142
void geo_layout_cmd_open_node(void) {
143
gCurGraphNodeList[gCurGraphNodeIndex + 1] = gCurGraphNodeList[gCurGraphNodeIndex];
144
gCurGraphNodeIndex++;
145
gGeoLayoutCommand += 0x04 << CMD_SIZE_SHIFT;
146
}
147
148
// 0x05: Close node
149
void geo_layout_cmd_close_node(void) {
150
gCurGraphNodeIndex--;
151
gGeoLayoutCommand += 0x04 << CMD_SIZE_SHIFT;
152
}
153
154
/*
155
0x06: Register the current node as a view
156
cmd+0x02: index
157
158
Register the current node in the gGeoViews array at the given index
159
*/
160
void geo_layout_cmd_assign_as_view(void) {
161
u16 index = cur_geo_cmd_s16(0x02);
162
163
if (index < gGeoNumViews) {
164
gGeoViews[index] = gCurGraphNodeList[gCurGraphNodeIndex];
165
}
166
167
gGeoLayoutCommand += 0x04 << CMD_SIZE_SHIFT;
168
}
169
170
/*
171
0x07: Update current scene graph node flags
172
cmd+0x01: u8 operation (0 = reset, 1 = set, 2 = clear)
173
cmd+0x02: s16 bits
174
*/
175
void geo_layout_cmd_update_node_flags(void) {
176
u16 operation = cur_geo_cmd_u8(0x01);
177
u16 flagBits = cur_geo_cmd_s16(0x02);
178
179
switch (operation) {
180
case GEO_CMD_FLAGS_RESET:
181
gCurGraphNodeList[gCurGraphNodeIndex]->flags = flagBits;
182
break;
183
case GEO_CMD_FLAGS_SET:
184
gCurGraphNodeList[gCurGraphNodeIndex]->flags |= flagBits;
185
break;
186
case GEO_CMD_FLAGS_CLEAR:
187
gCurGraphNodeList[gCurGraphNodeIndex]->flags &= ~flagBits;
188
break;
189
}
190
191
gGeoLayoutCommand += 0x04 << CMD_SIZE_SHIFT;
192
}
193
194
/*
195
0x08: Create a scene graph root node that specifies the viewport
196
cmd+0x02: s16 num entries (+2) to allocate for gGeoViews
197
cmd+0x04: s16 x
198
cmd+0x06: s16 y
199
cmd+0x08: s16 width
200
cmd+0x0A: s16 height
201
*/
202
void geo_layout_cmd_node_root(void) {
203
s32 i;
204
struct GraphNodeRoot *graphNode;
205
206
s16 x = cur_geo_cmd_s16(0x04);
207
s16 y = cur_geo_cmd_s16(0x06);
208
s16 width = cur_geo_cmd_s16(0x08);
209
s16 height = cur_geo_cmd_s16(0x0A);
210
211
// number of entries to allocate for gGeoViews array
212
// at least 2 are allocated by default
213
// cmd+0x02 = 0x00: Mario face, 0x0A: all other levels
214
gGeoNumViews = cur_geo_cmd_s16(0x02) + 2;
215
216
graphNode = init_graph_node_root(gGraphNodePool, NULL, 0, x, y, width, height);
217
218
// TODO: check type
219
gGeoViews = alloc_only_pool_alloc(gGraphNodePool, gGeoNumViews * sizeof(struct GraphNode *));
220
221
graphNode->views = gGeoViews;
222
graphNode->numViews = gGeoNumViews;
223
224
for (i = 0; i < gGeoNumViews; i++) {
225
gGeoViews[i] = NULL;
226
}
227
228
register_scene_graph_node(&graphNode->node);
229
230
gGeoLayoutCommand += 0x0C << CMD_SIZE_SHIFT;
231
}
232
233
/*
234
0x09: Create orthographic projection scene graph node
235
cmd+0x02: s16 scale as a percentage (usually it's 100)
236
*/
237
void geo_layout_cmd_node_ortho_projection(void) {
238
struct GraphNodeOrthoProjection *graphNode;
239
f32 scale = (f32) cur_geo_cmd_s16(0x02) / 100.0f;
240
241
graphNode = init_graph_node_ortho_projection(gGraphNodePool, NULL, scale);
242
243
register_scene_graph_node(&graphNode->node);
244
245
gGeoLayoutCommand += 0x04 << CMD_SIZE_SHIFT;
246
}
247
248
/*
249
0x0A: Create camera frustum scene graph node
250
cmd+0x01: u8 if nonzero, enable frustumFunc field
251
cmd+0x02: s16 field of view
252
cmd+0x04: s16 near
253
cmd+0x06: s16 far
254
[cmd+0x08: GraphNodeFunc frustumFunc]
255
*/
256
void geo_layout_cmd_node_perspective(void) {
257
struct GraphNodePerspective *graphNode;
258
GraphNodeFunc frustumFunc = NULL;
259
s16 fov = cur_geo_cmd_s16(0x02);
260
s16 near = cur_geo_cmd_s16(0x04);
261
s16 far = cur_geo_cmd_s16(0x06);
262
263
if (cur_geo_cmd_u8(0x01) != 0) {
264
// optional asm function
265
frustumFunc = (GraphNodeFunc) cur_geo_cmd_ptr(0x08);
266
gGeoLayoutCommand += 4 << CMD_SIZE_SHIFT;
267
}
268
269
graphNode = init_graph_node_perspective(gGraphNodePool, NULL, (f32) fov, near, far, frustumFunc, 0);
270
271
register_scene_graph_node(&graphNode->fnNode.node);
272
273
gGeoLayoutCommand += 0x08 << CMD_SIZE_SHIFT;
274
}
275
276
/*
277
0x0B: Create a scene graph node that groups other nodes without any
278
additional functionality
279
*/
280
void geo_layout_cmd_node_start(void) {
281
struct GraphNodeStart *graphNode;
282
283
graphNode = init_graph_node_start(gGraphNodePool, NULL);
284
285
register_scene_graph_node(&graphNode->node);
286
287
gGeoLayoutCommand += 0x04 << CMD_SIZE_SHIFT;
288
}
289
290
// 0x1F: No operation
291
void geo_layout_cmd_nop3(void) {
292
gGeoLayoutCommand += 0x10 << CMD_SIZE_SHIFT;
293
}
294
295
/*
296
0x0C: Create zbuffer-toggling scene graph node
297
cmd+0x01: u8 enableZBuffer (1 = on, 0 = off)
298
*/
299
void geo_layout_cmd_node_master_list(void) {
300
struct GraphNodeMasterList *graphNode;
301
302
graphNode = init_graph_node_master_list(gGraphNodePool, NULL, cur_geo_cmd_u8(0x01));
303
304
register_scene_graph_node(&graphNode->node);
305
306
gGeoLayoutCommand += 0x04 << CMD_SIZE_SHIFT;
307
}
308
309
/*
310
0x0D: Create a level of detail graph node, which only renders at a certain
311
distance interval from the camera.
312
cmd+0x04: s16 minDistance
313
cmd+0x06: s16 maxDistance
314
*/
315
void geo_layout_cmd_node_level_of_detail(void) {
316
struct GraphNodeLevelOfDetail *graphNode;
317
s16 minDistance = cur_geo_cmd_s16(0x04);
318
s16 maxDistance = cur_geo_cmd_s16(0x06);
319
320
graphNode = init_graph_node_render_range(gGraphNodePool, NULL, minDistance, maxDistance);
321
322
register_scene_graph_node(&graphNode->node);
323
324
gGeoLayoutCommand += 0x08 << CMD_SIZE_SHIFT;
325
}
326
327
/*
328
0x0E: Create switch-case scene graph node
329
cmd+0x02: s16 initialSelectedCase
330
cmd+0x04: GraphNodeFunc caseSelectorFunc
331
332
caseSelectorFunc returns an index which is used to select the child node to render.
333
Used for animating coins, blinking, color selection, etc.
334
*/
335
void geo_layout_cmd_node_switch_case(void) {
336
struct GraphNodeSwitchCase *graphNode;
337
338
graphNode =
339
init_graph_node_switch_case(gGraphNodePool, NULL,
340
cur_geo_cmd_s16(0x02), // case which is initially selected
341
0,
342
(GraphNodeFunc) cur_geo_cmd_ptr(0x04), // case update function
343
0);
344
345
register_scene_graph_node(&graphNode->fnNode.node);
346
347
gGeoLayoutCommand += 0x08 << CMD_SIZE_SHIFT;
348
}
349
350
/*
351
0x0F: Create a camera scene graph node (GraphNodeCamera). The focus sets the Camera's areaCen position.
352
cmd+0x02: s16 camera type (changes from course to course)
353
cmd+0x04: s16 posX
354
cmd+0x06: s16 posY
355
cmd+0x08: s16 posZ
356
cmd+0x0A: s16 focusX
357
cmd+0x0C: s16 focusY
358
cmd+0x0E: s16 focusZ
359
cmd+0x10: GraphNodeFunc func
360
*/
361
void geo_layout_cmd_node_camera(void) {
362
struct GraphNodeCamera *graphNode;
363
s16 *cmdPos = (s16 *) &gGeoLayoutCommand[4];
364
365
Vec3f pos, focus;
366
367
cmdPos = read_vec3s_to_vec3f(pos, cmdPos);
368
cmdPos = read_vec3s_to_vec3f(focus, cmdPos);
369
370
graphNode = init_graph_node_camera(gGraphNodePool, NULL, pos, focus,
371
(GraphNodeFunc) cur_geo_cmd_ptr(0x10), cur_geo_cmd_s16(0x02));
372
373
register_scene_graph_node(&graphNode->fnNode.node);
374
375
gGeoViews[0] = &graphNode->fnNode.node;
376
377
gGeoLayoutCommand += 0x14 << CMD_SIZE_SHIFT;
378
}
379
380
/*
381
0x10: Create translation & rotation scene graph node with optional display list
382
cmd+0x01: u8 params
383
(params & 0x80): if set, enable displayList field and drawingLayer
384
((params & 0x70)>>4): fieldLayout
385
(params & 0x0F): drawingLayer
386
387
fieldLayout == 0:
388
cmd+0x04: s16 xTranslation
389
cmd+0x06: s16 yTranslation
390
cmd+0x08: s16 zTranslation
391
cmd+0x0A: s16 xRotation
392
cmd+0x0C: s16 yRotation
393
cmd+0x0E: s16 zRotation
394
395
fieldLayout == 1:
396
cmd+0x02: s16 xTranslation
397
cmd+0x04: s16 yTranslation
398
cmd+0x06: s16 zTranslation
399
(rotation gets copied from gVec3sZero)
400
401
fieldLayout == 2:
402
cmd+0x02: s16 xRotation
403
cmd+0x04: s16 yRotation
404
cmd+0x06: s16 zRotation
405
(translation gets copied from gVec3sZero)
406
407
fieldLayout == 3:
408
cmd+0x02: s16 yRotation
409
(translation gets copied from gVec3sZero)
410
(x and z translation are set to 0)
411
412
[cmd+var: void *displayList]
413
*/
414
void geo_layout_cmd_node_translation_rotation(void) {
415
struct GraphNodeTranslationRotation *graphNode;
416
417
Vec3s translation, rotation;
418
419
void *displayList = NULL;
420
s16 drawingLayer = 0;
421
422
s16 params = cur_geo_cmd_u8(0x01);
423
s16 *cmdPos = (s16 *) gGeoLayoutCommand;
424
425
switch ((params & 0x70) >> 4) {
426
case 0:
427
cmdPos = read_vec3s(translation, &cmdPos[2]);
428
cmdPos = read_vec3s_angle(rotation, cmdPos);
429
break;
430
case 1:
431
cmdPos = read_vec3s(translation, &cmdPos[1]);
432
vec3s_copy(rotation, gVec3sZero);
433
break;
434
case 2:
435
cmdPos = read_vec3s_angle(rotation, &cmdPos[1]);
436
vec3s_copy(translation, gVec3sZero);
437
break;
438
case 3:
439
vec3s_copy(translation, gVec3sZero);
440
vec3s_set(rotation, 0, (cmdPos[1] << 15) / 180, 0);
441
cmdPos += 2 << CMD_SIZE_SHIFT;
442
break;
443
}
444
445
if (params & 0x80) {
446
displayList = *(void **) &cmdPos[0];
447
drawingLayer = params & 0x0F;
448
cmdPos += 2 << CMD_SIZE_SHIFT;
449
}
450
451
graphNode = init_graph_node_translation_rotation(gGraphNodePool, NULL, drawingLayer, displayList,
452
translation, rotation);
453
register_scene_graph_node(&graphNode->node);
454
455
gGeoLayoutCommand = (u8 *) cmdPos;
456
}
457
458
/*
459
0x11: Create translation scene graph node with optional display list
460
cmd+0x01: u8 params
461
(params & 0x80): if set, enable displayList field and drawingLayer
462
(params & 0x0F): drawingLayer
463
cmd+0x02: s16 xTranslation
464
cmd+0x04: s16 yTranslation
465
cmd+0x06: s16 zTranslation
466
[cmd+0x08: void *displayList]
467
*/
468
void geo_layout_cmd_node_translation(void) {
469
struct GraphNodeTranslation *graphNode;
470
471
Vec3s translation;
472
473
s16 drawingLayer = 0;
474
s16 params = cur_geo_cmd_u8(0x01);
475
s16 *cmdPos = (s16 *) gGeoLayoutCommand;
476
void *displayList = NULL;
477
478
cmdPos = read_vec3s(translation, &cmdPos[1]);
479
480
if (params & 0x80) {
481
displayList = *(void **) &cmdPos[0];
482
drawingLayer = params & 0x0F;
483
cmdPos += 2 << CMD_SIZE_SHIFT;
484
}
485
486
graphNode =
487
init_graph_node_translation(gGraphNodePool, NULL, drawingLayer, displayList, translation);
488
489
register_scene_graph_node(&graphNode->node);
490
491
gGeoLayoutCommand = (u8 *) cmdPos;
492
}
493
494
/*
495
0x12: Create ? scene graph node
496
cmd+0x01: u8 params
497
(params & 0x80): if set, enable displayList field and drawingLayer
498
(params & 0x0F): drawingLayer
499
cmd+0x02: s16 unkX
500
cmd+0x04: s16 unkY
501
cmd+0x06: s16 unkZ
502
[cmd+0x08: void *displayList]
503
*/
504
void geo_layout_cmd_node_rotation(void) {
505
struct GraphNodeRotation *graphNode;
506
507
Vec3s sp2c;
508
509
s16 drawingLayer = 0;
510
s16 params = cur_geo_cmd_u8(0x01);
511
s16 *cmdPos = (s16 *) gGeoLayoutCommand;
512
void *displayList = NULL;
513
514
cmdPos = read_vec3s_angle(sp2c, &cmdPos[1]);
515
516
if (params & 0x80) {
517
displayList = *(void **) &cmdPos[0];
518
drawingLayer = params & 0x0F;
519
cmdPos += 2 << CMD_SIZE_SHIFT;
520
}
521
522
graphNode = init_graph_node_rotation(gGraphNodePool, NULL, drawingLayer, displayList, sp2c);
523
524
register_scene_graph_node(&graphNode->node);
525
526
gGeoLayoutCommand = (u8 *) cmdPos;
527
}
528
529
/*
530
0x1D: Create scale scene graph node with optional display list
531
cmd+0x01: u8 params
532
(params & 0x80): if set, enable displayList field and drawingLayer
533
(params & 0x0F): drawingLayer
534
cmd+0x04: u32 scale (0x10000 = 1.0)
535
[cmd+0x08: void *displayList]
536
*/
537
void geo_layout_cmd_node_scale(void) {
538
struct GraphNodeScale *graphNode;
539
540
s16 drawingLayer = 0;
541
s16 params = cur_geo_cmd_u8(0x01);
542
f32 scale = cur_geo_cmd_u32(0x04) / 65536.0f;
543
void *displayList = NULL;
544
545
if (params & 0x80) {
546
displayList = cur_geo_cmd_ptr(0x08);
547
drawingLayer = params & 0x0F;
548
gGeoLayoutCommand += 4 << CMD_SIZE_SHIFT;
549
}
550
551
graphNode = init_graph_node_scale(gGraphNodePool, NULL, drawingLayer, displayList, scale);
552
553
register_scene_graph_node(&graphNode->node);
554
555
gGeoLayoutCommand += 0x08 << CMD_SIZE_SHIFT;
556
}
557
558
// 0x1E: No operation
559
void geo_layout_cmd_nop2(void) {
560
gGeoLayoutCommand += 0x08 << CMD_SIZE_SHIFT;
561
}
562
563
/*
564
0x13: Create a scene graph node that is rotated by the object's animation.
565
cmd+0x01: u8 drawingLayer
566
cmd+0x02: s16 xTranslation
567
cmd+0x04: s16 yTranslation
568
cmd+0x06: s16 zTranslation
569
cmd+0x08: void *displayList
570
*/
571
void geo_layout_cmd_node_animated_part(void) {
572
struct GraphNodeAnimatedPart *graphNode;
573
Vec3s translation;
574
s32 drawingLayer = cur_geo_cmd_u8(0x01);
575
void *displayList = cur_geo_cmd_ptr(0x08);
576
s16 *cmdPos = (s16 *) gGeoLayoutCommand;
577
578
read_vec3s(translation, &cmdPos[1]);
579
580
graphNode =
581
init_graph_node_animated_part(gGraphNodePool, NULL, drawingLayer, displayList, translation);
582
583
register_scene_graph_node(&graphNode->node);
584
585
gGeoLayoutCommand += 0x0C << CMD_SIZE_SHIFT;
586
}
587
588
/*
589
0x14: Create billboarding node with optional display list
590
cmd+0x01: u8 params
591
(params & 0x80): if set, enable displayList field and drawingLayer
592
(params & 0x0F): drawingLayer
593
cmd+0x02: s16 xTranslation
594
cmd+0x04: s16 yTranslation
595
cmd+0x06: s16 zTranslation
596
[cmd+0x08: void *displayList]
597
*/
598
void geo_layout_cmd_node_billboard(void) {
599
struct GraphNodeBillboard *graphNode;
600
Vec3s translation;
601
s16 drawingLayer = 0;
602
s16 params = cur_geo_cmd_u8(0x01);
603
s16 *cmdPos = (s16 *) gGeoLayoutCommand;
604
void *displayList = NULL;
605
606
cmdPos = read_vec3s(translation, &cmdPos[1]);
607
608
if (params & 0x80) {
609
displayList = *(void **) &cmdPos[0];
610
drawingLayer = params & 0x0F;
611
cmdPos += 2 << CMD_SIZE_SHIFT;
612
}
613
614
graphNode = init_graph_node_billboard(gGraphNodePool, NULL, drawingLayer, displayList, translation);
615
616
register_scene_graph_node(&graphNode->node);
617
618
gGeoLayoutCommand = (u8 *) cmdPos;
619
}
620
621
/*
622
0x15: Create plain display list scene graph node
623
cmd+0x01: u8 drawingLayer
624
cmd+0x04: void *displayList
625
*/
626
void geo_layout_cmd_node_display_list(void) {
627
struct GraphNodeDisplayList *graphNode;
628
s32 drawingLayer = cur_geo_cmd_u8(0x01);
629
void *displayList = cur_geo_cmd_ptr(0x04);
630
631
graphNode = init_graph_node_display_list(gGraphNodePool, NULL, drawingLayer, displayList);
632
633
register_scene_graph_node(&graphNode->node);
634
635
gGeoLayoutCommand += 0x08 << CMD_SIZE_SHIFT;
636
}
637
638
/*
639
0x16: Create shadow scene graph node
640
cmd+0x02: s16 shadowType
641
cmd+0x04: s16 shadowSolidity
642
cmd+0x06: s16 shadowScale
643
*/
644
void geo_layout_cmd_node_shadow(void) {
645
struct GraphNodeShadow *graphNode;
646
u8 shadowType = cur_geo_cmd_s16(0x02);
647
u8 shadowSolidity = cur_geo_cmd_s16(0x04);
648
s16 shadowScale = cur_geo_cmd_s16(0x06);
649
650
graphNode = init_graph_node_shadow(gGraphNodePool, NULL, shadowScale, shadowSolidity, shadowType);
651
652
register_scene_graph_node(&graphNode->node);
653
654
gGeoLayoutCommand += 0x08 << CMD_SIZE_SHIFT;
655
}
656
657
// 0x17: Create scene graph node that manages the group of all object nodes
658
void geo_layout_cmd_node_object_parent(void) {
659
struct GraphNodeObjectParent *graphNode;
660
661
graphNode = init_graph_node_object_parent(gGraphNodePool, NULL, &gObjParentGraphNode);
662
663
register_scene_graph_node(&graphNode->node);
664
665
gGeoLayoutCommand += 0x04 << CMD_SIZE_SHIFT;
666
}
667
668
/*
669
0x18: Create dynamically generated displaylist scene graph node
670
cmd+0x02: s16 parameter
671
cmd+0x04: GraphNodeFunc func
672
*/
673
void geo_layout_cmd_node_generated(void) {
674
struct GraphNodeGenerated *graphNode;
675
676
graphNode = init_graph_node_generated(gGraphNodePool, NULL,
677
(GraphNodeFunc) cur_geo_cmd_ptr(0x04), // asm function
678
cur_geo_cmd_s16(0x02)); // parameter
679
680
register_scene_graph_node(&graphNode->fnNode.node);
681
682
gGeoLayoutCommand += 0x08 << CMD_SIZE_SHIFT;
683
}
684
685
/*
686
0x19: Create background scene graph node
687
cmd+0x02: s16 background // background ID, or RGBA5551 color if backgroundFunc is null
688
cmd+0x04: GraphNodeFunc backgroundFunc
689
*/
690
void geo_layout_cmd_node_background(void) {
691
struct GraphNodeBackground *graphNode;
692
693
graphNode = init_graph_node_background(
694
gGraphNodePool, NULL,
695
cur_geo_cmd_s16(0x02), // background ID, or RGBA5551 color if asm function is null
696
(GraphNodeFunc) cur_geo_cmd_ptr(0x04), // asm function
697
0);
698
699
register_scene_graph_node(&graphNode->fnNode.node);
700
701
gGeoLayoutCommand += 0x08 << CMD_SIZE_SHIFT;
702
}
703
704
// 0x1A: No operation
705
void geo_layout_cmd_nop(void) {
706
gGeoLayoutCommand += 0x08 << CMD_SIZE_SHIFT;
707
}
708
709
/*
710
0x1B: Copy the shared children from the object parent from a specific view
711
to a newly created object parent node.
712
cmd+0x02: s16 index (of gGeoViews)
713
*/
714
void geo_layout_cmd_copy_view(void) {
715
struct GraphNodeObjectParent *graphNode;
716
struct GraphNode *node = NULL;
717
s16 index = cur_geo_cmd_s16(0x02);
718
719
if (index >= 0) {
720
node = gGeoViews[index];
721
722
if (node->type == GRAPH_NODE_TYPE_OBJECT_PARENT) {
723
node = ((struct GraphNodeObjectParent *) node)->sharedChild;
724
} else {
725
node = NULL;
726
}
727
}
728
729
graphNode = init_graph_node_object_parent(gGraphNodePool, NULL, node);
730
731
register_scene_graph_node(&graphNode->node);
732
733
gGeoLayoutCommand += 0x04 << CMD_SIZE_SHIFT;
734
}
735
736
/*
737
0x1C: Create a held object scene graph node
738
cmd+0x01: u8 unused
739
cmd+0x02: s16 offsetX
740
cmd+0x04: s16 offsetY
741
cmd+0x06: s16 offsetZ
742
cmd+0x08: GraphNodeFunc nodeFunc
743
*/
744
void geo_layout_cmd_node_held_obj(void) {
745
struct GraphNodeHeldObject *graphNode;
746
Vec3s offset;
747
748
read_vec3s(offset, (s16 *) &gGeoLayoutCommand[0x02]);
749
750
graphNode = init_graph_node_held_object(
751
gGraphNodePool, NULL, NULL, offset, (GraphNodeFunc) cur_geo_cmd_ptr(0x08), cur_geo_cmd_u8(0x01));
752
753
register_scene_graph_node(&graphNode->fnNode.node);
754
755
gGeoLayoutCommand += 0x0C << CMD_SIZE_SHIFT;
756
}
757
758
/*
759
0x20: Create a scene graph node that specifies for an object the radius that
760
is used for frustum culling.
761
cmd+0x02: s16 cullingRadius
762
*/
763
void geo_layout_cmd_node_culling_radius(void) {
764
struct GraphNodeCullingRadius *graphNode;
765
graphNode = init_graph_node_culling_radius(gGraphNodePool, NULL, cur_geo_cmd_s16(0x02));
766
register_scene_graph_node(&graphNode->node);
767
gGeoLayoutCommand += 0x04 << CMD_SIZE_SHIFT;
768
}
769
770
struct GraphNode *process_geo_layout(struct AllocOnlyPool *pool, void *segptr) {
771
// set by register_scene_graph_node when gCurGraphNodeIndex is 0
772
// and gCurRootGraphNode is NULL
773
gCurRootGraphNode = NULL;
774
775
gGeoNumViews = 0; // number of entries in gGeoViews
776
777
gCurGraphNodeList[0] = 0;
778
gCurGraphNodeIndex = 0; // incremented by cmd_open_node, decremented by cmd_close_node
779
780
gGeoLayoutStackIndex = 2;
781
gGeoLayoutReturnIndex = 2; // stack index is often copied here?
782
783
gGeoLayoutCommand = segmented_to_virtual(segptr);
784
785
gGraphNodePool = pool;
786
787
gGeoLayoutStack[0] = 0;
788
gGeoLayoutStack[1] = 0;
789
790
while (gGeoLayoutCommand != NULL) {
791
GeoLayoutJumpTable[gGeoLayoutCommand[0x00]]();
792
}
793
794
return gCurRootGraphNode;
795
}
796
797