graph_node.c (31305B)
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 graphNode->sharedChild = sharedChild; 316 graphNode->throwMatrix = NULL; 317 graphNode->animInfo.animID = 0; 318 graphNode->animInfo.curAnim = NULL; 319 graphNode->animInfo.animFrame = 0; 320 graphNode->animInfo.animFrameAccelAssist = 0; 321 graphNode->animInfo.animAccel = 0x10000; 322 graphNode->animInfo.animTimer = 0; 323 graphNode->node.flags |= GRAPH_RENDER_HAS_ANIMATION; 324 } 325 326 return graphNode; 327 } 328 329 /** 330 * Allocates and returns a newly created frustum culling radius node 331 */ 332 struct GraphNodeCullingRadius *init_graph_node_culling_radius(struct AllocOnlyPool *pool, 333 struct GraphNodeCullingRadius *graphNode, 334 s16 radius) { 335 if (pool != NULL) { 336 graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeCullingRadius)); 337 } 338 339 if (graphNode != NULL) { 340 init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_CULLING_RADIUS); 341 graphNode->cullingRadius = radius; 342 } 343 344 return graphNode; 345 } 346 347 /** 348 * Allocates and returns a newly created animated part node 349 */ 350 struct GraphNodeAnimatedPart *init_graph_node_animated_part(struct AllocOnlyPool *pool, 351 struct GraphNodeAnimatedPart *graphNode, 352 s32 drawingLayer, void *displayList, 353 Vec3s translation) { 354 if (pool != NULL) { 355 graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeAnimatedPart)); 356 } 357 358 if (graphNode != NULL) { 359 init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_ANIMATED_PART); 360 vec3s_copy(graphNode->translation, translation); 361 graphNode->node.flags = (drawingLayer << 8) | (graphNode->node.flags & 0xFF); 362 graphNode->displayList = displayList; 363 } 364 365 return graphNode; 366 } 367 368 /** 369 * Allocates and returns a newly created billboard node 370 */ 371 struct GraphNodeBillboard *init_graph_node_billboard(struct AllocOnlyPool *pool, 372 struct GraphNodeBillboard *graphNode, 373 s32 drawingLayer, void *displayList, 374 Vec3s translation) { 375 if (pool != NULL) { 376 graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeBillboard)); 377 } 378 379 if (graphNode != NULL) { 380 init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_BILLBOARD); 381 vec3s_copy(graphNode->translation, translation); 382 graphNode->node.flags = (drawingLayer << 8) | (graphNode->node.flags & 0xFF); 383 graphNode->displayList = displayList; 384 } 385 386 return graphNode; 387 } 388 389 /** 390 * Allocates and returns a newly created displaylist node 391 */ 392 struct GraphNodeDisplayList *init_graph_node_display_list(struct AllocOnlyPool *pool, 393 struct GraphNodeDisplayList *graphNode, 394 s32 drawingLayer, void *displayList) { 395 if (pool != NULL) { 396 graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeDisplayList)); 397 } 398 399 if (graphNode != NULL) { 400 init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_DISPLAY_LIST); 401 graphNode->node.flags = (drawingLayer << 8) | (graphNode->node.flags & 0xFF); 402 graphNode->displayList = displayList; 403 } 404 405 return graphNode; 406 } 407 408 /** 409 * Allocates and returns a newly created shadow node 410 */ 411 struct GraphNodeShadow *init_graph_node_shadow(struct AllocOnlyPool *pool, 412 struct GraphNodeShadow *graphNode, s16 shadowScale, 413 u8 shadowSolidity, u8 shadowType) { 414 if (pool != NULL) { 415 graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeShadow)); 416 } 417 418 if (graphNode != NULL) { 419 init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_SHADOW); 420 graphNode->shadowScale = shadowScale; 421 graphNode->shadowSolidity = shadowSolidity; 422 graphNode->shadowType = shadowType; 423 } 424 425 return graphNode; 426 } 427 428 /** 429 * Allocates and returns a newly created object parent node 430 */ 431 struct GraphNodeObjectParent *init_graph_node_object_parent(struct AllocOnlyPool *pool, 432 struct GraphNodeObjectParent *graphNode, 433 struct GraphNode *sharedChild) { 434 if (pool != NULL) { 435 graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeObjectParent)); 436 } 437 438 if (graphNode != NULL) { 439 init_scene_graph_node_links(&graphNode->node, GRAPH_NODE_TYPE_OBJECT_PARENT); 440 graphNode->sharedChild = sharedChild; 441 } 442 443 return graphNode; 444 } 445 446 /** 447 * Allocates and returns a newly created generated node 448 */ 449 struct GraphNodeGenerated *init_graph_node_generated(struct AllocOnlyPool *pool, 450 struct GraphNodeGenerated *graphNode, 451 GraphNodeFunc gfxFunc, s32 parameter) { 452 if (pool != NULL) { 453 graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeGenerated)); 454 } 455 456 if (graphNode != NULL) { 457 init_scene_graph_node_links(&graphNode->fnNode.node, GRAPH_NODE_TYPE_GENERATED_LIST); 458 graphNode->fnNode.func = gfxFunc; 459 graphNode->parameter = parameter; 460 461 if (gfxFunc != NULL) { 462 gfxFunc(GEO_CONTEXT_CREATE, &graphNode->fnNode.node, pool); 463 } 464 } 465 466 return graphNode; 467 } 468 469 /** 470 * Allocates and returns a newly created background node 471 */ 472 struct GraphNodeBackground *init_graph_node_background(struct AllocOnlyPool *pool, 473 struct GraphNodeBackground *graphNode, 474 u16 background, GraphNodeFunc backgroundFunc, 475 s32 zero) { 476 if (pool != NULL) { 477 graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeBackground)); 478 } 479 480 if (graphNode != NULL) { 481 init_scene_graph_node_links(&graphNode->fnNode.node, GRAPH_NODE_TYPE_BACKGROUND); 482 483 graphNode->background = (background << 16) | background; 484 graphNode->fnNode.func = backgroundFunc; 485 graphNode->unused = zero; // always 0, unused 486 487 if (backgroundFunc != NULL) { 488 backgroundFunc(GEO_CONTEXT_CREATE, &graphNode->fnNode.node, pool); 489 } 490 } 491 492 return graphNode; 493 } 494 495 /** 496 * Allocates and returns a newly created held object node 497 */ 498 struct GraphNodeHeldObject *init_graph_node_held_object(struct AllocOnlyPool *pool, 499 struct GraphNodeHeldObject *graphNode, 500 struct Object *objNode, 501 Vec3s translation, 502 GraphNodeFunc nodeFunc, s32 playerIndex) { 503 if (pool != NULL) { 504 graphNode = alloc_only_pool_alloc(pool, sizeof(struct GraphNodeHeldObject)); 505 } 506 507 if (graphNode != NULL) { 508 init_scene_graph_node_links(&graphNode->fnNode.node, GRAPH_NODE_TYPE_HELD_OBJ); 509 vec3s_copy(graphNode->translation, translation); 510 graphNode->objNode = objNode; 511 graphNode->fnNode.func = nodeFunc; 512 graphNode->playerIndex = playerIndex; 513 514 if (nodeFunc != NULL) { 515 nodeFunc(GEO_CONTEXT_CREATE, &graphNode->fnNode.node, pool); 516 } 517 } 518 519 return graphNode; 520 } 521 522 /** 523 * Adds 'childNode' to the end of the list children from 'parent' 524 */ 525 struct GraphNode *geo_add_child(struct GraphNode *parent, struct GraphNode *childNode) { 526 struct GraphNode *parentFirstChild; 527 struct GraphNode *parentLastChild; 528 529 if (childNode != NULL) { 530 childNode->parent = parent; 531 parentFirstChild = parent->children; 532 533 if (parentFirstChild == NULL) { 534 parent->children = childNode; 535 childNode->prev = childNode; 536 childNode->next = childNode; 537 } else { 538 parentLastChild = parentFirstChild->prev; 539 childNode->prev = parentLastChild; 540 childNode->next = parentFirstChild; 541 parentFirstChild->prev = childNode; 542 parentLastChild->next = childNode; 543 } 544 } 545 546 return childNode; 547 } 548 549 /** 550 * Remove a node from the scene graph. It changes the links with its 551 * siblings and with its parent, it doesn't deallocate the memory 552 * since geo nodes are allocated in a pointer-bumping pool that 553 * gets thrown out when changing areas. 554 */ 555 struct GraphNode *geo_remove_child(struct GraphNode *graphNode) { 556 struct GraphNode *parent; 557 struct GraphNode **firstChild; 558 559 parent = graphNode->parent; 560 firstChild = &parent->children; 561 562 // Remove link with siblings 563 graphNode->prev->next = graphNode->next; 564 graphNode->next->prev = graphNode->prev; 565 566 // If this node was the first child, a new first child must be chosen 567 if (*firstChild == graphNode) { 568 // The list is circular, so this checks whether it was the only child 569 if (graphNode->next == graphNode) { 570 *firstChild = NULL; // Parent has no children anymore 571 } else { 572 *firstChild = graphNode->next; // Choose a new first child 573 } 574 } 575 576 return parent; 577 } 578 579 /** 580 * Reorders the given node so it's the first child of its parent. 581 * This is called on the Mario object when he is spawned. That's why Mario's 582 * object is always drawn before any other objects. (Note that the geo order 583 * is independent from processing group order, where Mario is not first.) 584 */ 585 struct GraphNode *geo_make_first_child(struct GraphNode *newFirstChild) { 586 struct GraphNode *lastSibling; 587 struct GraphNode *parent; 588 struct GraphNode **firstChild; 589 590 parent = newFirstChild->parent; 591 firstChild = &parent->children; 592 593 if (*firstChild != newFirstChild) { 594 if ((*firstChild)->prev != newFirstChild) { 595 newFirstChild->prev->next = newFirstChild->next; 596 newFirstChild->next->prev = newFirstChild->prev; 597 lastSibling = (*firstChild)->prev; 598 newFirstChild->prev = lastSibling; 599 newFirstChild->next = *firstChild; 600 (*firstChild)->prev = newFirstChild; 601 lastSibling->next = newFirstChild; 602 } 603 *firstChild = newFirstChild; 604 } 605 606 return parent; 607 } 608 609 /** 610 * Helper function for geo_call_global_function_nodes that recursively 611 * traverses the scene graph and calls the functions of global nodes. 612 */ 613 void geo_call_global_function_nodes_helper(struct GraphNode *graphNode, s32 callContext) { 614 struct GraphNode **globalPtr; 615 struct GraphNode *curNode; 616 struct FnGraphNode *asFnNode; 617 618 curNode = graphNode; 619 620 do { 621 asFnNode = (struct FnGraphNode *) curNode; 622 623 if (curNode->type & GRAPH_NODE_TYPE_FUNCTIONAL) { 624 if (asFnNode->func != NULL) { 625 asFnNode->func(callContext, curNode, NULL); 626 } 627 } 628 629 if (curNode->children != NULL) { 630 switch (curNode->type) { 631 case GRAPH_NODE_TYPE_MASTER_LIST: 632 globalPtr = (struct GraphNode **) &gCurGraphNodeMasterList; 633 break; 634 case GRAPH_NODE_TYPE_PERSPECTIVE: 635 globalPtr = (struct GraphNode **) &gCurGraphNodeCamFrustum; 636 break; 637 case GRAPH_NODE_TYPE_CAMERA: 638 globalPtr = (struct GraphNode **) &gCurGraphNodeCamera; 639 break; 640 case GRAPH_NODE_TYPE_OBJECT: 641 globalPtr = (struct GraphNode **) &gCurGraphNodeObject; 642 break; 643 default: 644 globalPtr = NULL; 645 break; 646 } 647 648 if (globalPtr != NULL) { 649 *globalPtr = curNode; 650 } 651 652 geo_call_global_function_nodes_helper(curNode->children, callContext); 653 654 if (globalPtr != NULL) { 655 *globalPtr = NULL; 656 } 657 } 658 } while ((curNode = curNode->next) != graphNode); 659 } 660 661 /** 662 * Call the update functions of geo nodes that are stored in global variables. 663 * These variables include gCurGraphNodeMasterList, gCurGraphNodeCamFrustum, 664 * gCurGraphNodeCamera and gCurGraphNodeObject. 665 * callContext is one of the GEO_CONTEXT_ defines. 666 * The graphNode argument should be of type GraphNodeRoot. 667 */ 668 void geo_call_global_function_nodes(struct GraphNode *graphNode, s32 callContext) { 669 if (graphNode->flags & GRAPH_RENDER_ACTIVE) { 670 gCurGraphNodeRoot = (struct GraphNodeRoot *) graphNode; 671 672 if (graphNode->children != NULL) { 673 geo_call_global_function_nodes_helper(graphNode->children, callContext); 674 } 675 676 gCurGraphNodeRoot = 0; 677 } 678 } 679 680 /** 681 * When objects are cleared, this is called on all object nodes (loaded or unloaded). 682 */ 683 void geo_reset_object_node(struct GraphNodeObject *graphNode) { 684 init_graph_node_object(NULL, graphNode, 0, gVec3fZero, gVec3sZero, gVec3fOne); 685 686 geo_add_child(&gObjParentGraphNode, &graphNode->node); 687 graphNode->node.flags &= ~GRAPH_RENDER_ACTIVE; 688 } 689 690 /** 691 * Initialize an object node using the given parameters 692 */ 693 void geo_obj_init(struct GraphNodeObject *graphNode, void *sharedChild, Vec3f pos, Vec3s angle) { 694 vec3f_set(graphNode->scale, 1.0f, 1.0f, 1.0f); 695 vec3f_copy(graphNode->pos, pos); 696 vec3s_copy(graphNode->angle, angle); 697 698 graphNode->sharedChild = sharedChild; 699 graphNode->unk4C = 0; 700 graphNode->throwMatrix = NULL; 701 graphNode->animInfo.curAnim = NULL; 702 703 graphNode->node.flags |= GRAPH_RENDER_ACTIVE; 704 graphNode->node.flags &= ~GRAPH_RENDER_INVISIBLE; 705 graphNode->node.flags |= GRAPH_RENDER_HAS_ANIMATION; 706 graphNode->node.flags &= ~GRAPH_RENDER_BILLBOARD; 707 } 708 709 /** 710 * Initialize and object node using the given SpawnInfo struct 711 */ 712 void geo_obj_init_spawninfo(struct GraphNodeObject *graphNode, struct SpawnInfo *spawn) { 713 vec3f_set(graphNode->scale, 1.0f, 1.0f, 1.0f); 714 vec3s_copy(graphNode->angle, spawn->startAngle); 715 716 graphNode->pos[0] = (f32) spawn->startPos[0]; 717 graphNode->pos[1] = (f32) spawn->startPos[1]; 718 graphNode->pos[2] = (f32) spawn->startPos[2]; 719 720 graphNode->areaIndex = spawn->areaIndex; 721 graphNode->activeAreaIndex = spawn->activeAreaIndex; 722 graphNode->sharedChild = spawn->model; 723 graphNode->unk4C = spawn; 724 graphNode->throwMatrix = NULL; 725 graphNode->animInfo.curAnim = 0; 726 727 graphNode->node.flags |= GRAPH_RENDER_ACTIVE; 728 graphNode->node.flags &= ~GRAPH_RENDER_INVISIBLE; 729 graphNode->node.flags |= GRAPH_RENDER_HAS_ANIMATION; 730 graphNode->node.flags &= ~GRAPH_RENDER_BILLBOARD; 731 } 732 733 /** 734 * Initialize the animation of an object node 735 */ 736 void geo_obj_init_animation(struct GraphNodeObject *graphNode, struct Animation **animPtrAddr) { 737 struct Animation **animSegmented = segmented_to_virtual(animPtrAddr); 738 struct Animation *anim = segmented_to_virtual(*animSegmented); 739 740 if (graphNode->animInfo.curAnim != anim) { 741 graphNode->animInfo.curAnim = anim; 742 graphNode->animInfo.animFrame = anim->startFrame + ((anim->flags & ANIM_FLAG_BACKWARD) ? 1 : -1); 743 graphNode->animInfo.animAccel = 0; 744 graphNode->animInfo.animYTrans = 0; 745 } 746 } 747 748 /** 749 * Initialize the animation of an object node 750 */ 751 void geo_obj_init_animation_accel(struct GraphNodeObject *graphNode, struct Animation **animPtrAddr, u32 animAccel) { 752 struct Animation **animSegmented = segmented_to_virtual(animPtrAddr); 753 struct Animation *anim = segmented_to_virtual(*animSegmented); 754 755 if (graphNode->animInfo.curAnim != anim) { 756 graphNode->animInfo.curAnim = anim; 757 graphNode->animInfo.animYTrans = 0; 758 graphNode->animInfo.animFrameAccelAssist = 759 (anim->startFrame << 16) + ((anim->flags & ANIM_FLAG_BACKWARD) ? animAccel : -animAccel); 760 graphNode->animInfo.animFrame = graphNode->animInfo.animFrameAccelAssist >> 16; 761 } 762 763 graphNode->animInfo.animAccel = animAccel; 764 } 765 766 /** 767 * Retrieves an index into animation data based on the attribute pointer 768 * An attribute is an x-, y- or z-component of the translation / rotation for a part 769 * Each attribute is a pair of s16's, where the first s16 represents the maximum frame 770 * and the second s16 the actual index. This index can be used to index in the array 771 * with actual animation values. 772 */ 773 s32 retrieve_animation_index(s32 frame, u16 **attributes) { 774 s32 result; 775 776 if (frame < (*attributes)[0]) { 777 result = (*attributes)[1] + frame; 778 } else { 779 result = (*attributes)[1] + (*attributes)[0] - 1; 780 } 781 782 *attributes += 2; 783 784 return result; 785 } 786 787 /** 788 * Update the animation frame of an object. The animation flags determine 789 * whether it plays forwards or backwards, and whether it stops or loops at 790 * the end etc. 791 */ 792 s16 geo_update_animation_frame(struct AnimInfo *obj, s32 *accelAssist) { 793 s32 result; 794 struct Animation *anim = obj->curAnim; 795 796 if (obj->animTimer == gAreaUpdateCounter || anim->flags & ANIM_FLAG_2) { 797 if (accelAssist != NULL) { 798 accelAssist[0] = obj->animFrameAccelAssist; 799 } 800 801 return obj->animFrame; 802 } 803 804 if (anim->flags & ANIM_FLAG_BACKWARD) { 805 if (obj->animAccel != 0) { 806 result = obj->animFrameAccelAssist - obj->animAccel; 807 } else { 808 result = (obj->animFrame - 1) << 16; 809 } 810 811 if (GET_HIGH_S16_OF_32(result) < anim->loopStart) { 812 if (anim->flags & ANIM_FLAG_NOLOOP) { 813 SET_HIGH_S16_OF_32(result, anim->loopStart); 814 } else { 815 SET_HIGH_S16_OF_32(result, anim->loopEnd - 1); 816 } 817 } 818 } else { 819 if (obj->animAccel != 0) { 820 result = obj->animFrameAccelAssist + obj->animAccel; 821 } else { 822 result = (obj->animFrame + 1) << 16; 823 } 824 825 if (GET_HIGH_S16_OF_32(result) >= anim->loopEnd) { 826 if (anim->flags & ANIM_FLAG_NOLOOP) { 827 SET_HIGH_S16_OF_32(result, anim->loopEnd - 1); 828 } else { 829 SET_HIGH_S16_OF_32(result, anim->loopStart); 830 } 831 } 832 } 833 834 if (accelAssist != 0) { 835 accelAssist[0] = result; 836 } 837 838 return GET_HIGH_S16_OF_32(result); 839 } 840 841 /** 842 * Unused function to retrieve an object's current animation translation 843 * Assumes that it has x, y and z data in animations, which isn't always the 844 * case since some animation types only have vertical or lateral translation. 845 * This might have been used for positioning the shadow under an object, which 846 * currently happens in-line in geo_process_shadow where it also accounts for 847 * animations without lateral translation. 848 */ 849 void geo_retreive_animation_translation(struct GraphNodeObject *obj, Vec3f position) { 850 struct Animation *animation = obj->animInfo.curAnim; 851 852 if (animation != NULL) { 853 u16 *attribute = segmented_to_virtual((void *) animation->index); 854 s16 *values = segmented_to_virtual((void *) animation->values); 855 856 s16 frame = obj->animInfo.animFrame; 857 858 if (frame < 0) { 859 frame = 0; 860 } 861 862 position[0] = (f32) values[retrieve_animation_index(frame, &attribute)]; 863 position[1] = (f32) values[retrieve_animation_index(frame, &attribute)]; 864 position[2] = (f32) values[retrieve_animation_index(frame, &attribute)]; 865 } else { 866 vec3f_set(position, 0, 0, 0); 867 } 868 } 869 870 /** 871 * Unused function to find the root of the geo node tree, which should be a 872 * GraphNodeRoot. If it is not for some reason, null is returned. 873 */ 874 struct GraphNodeRoot *geo_find_root(struct GraphNode *graphNode) { 875 struct GraphNodeRoot *resGraphNode = NULL; 876 877 while (graphNode->parent != NULL) { 878 graphNode = graphNode->parent; 879 } 880 881 if (graphNode->type == GRAPH_NODE_TYPE_ROOT) { 882 resGraphNode = (struct GraphNodeRoot *) graphNode; 883 } 884 885 return resGraphNode; 886 }