dynlist_proc.c (108540B)
1 #include <PR/ultratypes.h> 2 #include <stdio.h> 3 4 #include "bad_declarations.h" 5 #include "debug_utils.h" 6 #include "draw_objects.h" 7 #include "dynlist_proc.h" 8 #include "gd_main.h" 9 #include "gd_math.h" 10 #include "gd_types.h" 11 #include "joints.h" 12 #include "macros.h" 13 #include "objects.h" 14 #include "old_menu.h" 15 #include "particles.h" 16 #include "renderer.h" 17 #include "shape_helper.h" 18 #include "skin.h" 19 20 /** 21 * @file dynlist_proc.c 22 * 23 * Functions for parsing and processing Goddard's DynList object format. 24 * It also has utility functions for abstracting at runtime over the various 25 * flavors of `GdObj`s. 26 */ 27 28 // constants 29 /// Size of the dynamic object name buffer 30 #define DYNOBJ_NAME_SIZE 8 31 /// Total number of dynamic `GdObj`s that can be created 32 #define DYNOBJ_LIST_SIZE 3000 33 /// Maximum number of verticies supported when adding vertices node to an `ObjShape` 34 #define VTX_BUF_SIZE 3000 35 36 // types 37 /// Information about a dynamically created `GdObj` 38 struct DynObjInfo { 39 char name[DYNOBJ_NAME_SIZE]; 40 struct GdObj *obj; 41 s32 num; 42 s32 unk; 43 }; 44 /// @name DynList Accessors 45 /// Accessor marcos for easy interpretation of data in a `DynList` packet 46 ///@{ 47 #define Dyn1AsInt(dyn) ((dyn)->w1.word) 48 #define Dyn1AsPtr(dyn) ((dyn)->w1.ptr) 49 #define Dyn1AsStr(dyn) ((dyn)->w1.str) 50 #define Dyn1AsName(dyn) ((DynObjName)((dyn)->w1.ptr)) 51 52 #define Dyn2AsInt(dyn) ((dyn)->w2.word) 53 #define Dyn2AsPtr(dyn) ((dyn)->w2.ptr) 54 #define Dyn2AsStr(dyn) ((dyn)->w2.str) 55 #define Dyn2AsName(dyn) ((DynObjName)((dyn)->w2.ptr)) 56 57 #define DynVec(dyn) (&(dyn)->vec) 58 #define DynVecX(dyn) ((dyn)->vec.x) 59 #define DynVecY(dyn) ((dyn)->vec.y) 60 #define DynVecZ(dyn) ((dyn)->vec.z) 61 ///@} 62 63 // data 64 static struct DynObjInfo *sGdDynObjList = NULL; // @ 801A8250; info for all loaded/made dynobjs 65 static struct GdObj *sDynListCurObj = NULL; // @ 801A8254 66 static struct GdBoundingBox sNullBoundingBox = { // @ 801A8258 67 0.0, 0.0, 0.0, 68 0.0, 0.0, 0.0 69 }; 70 static s32 sUseIntegerNames = FALSE; // if TRUE, then all DynNames are specified as integers 71 72 // bss 73 static char sIntToStringBuf[DYNOBJ_NAME_SIZE]; ///< buffer for returning formated string from 74 ///< `integer_name_to_string()` 75 static struct DynObjInfo sNullDynObjInfo; // @ 801B9F08 76 static char sDynNameSuffix[DYNOBJ_NAME_SIZE]; // @ 801B9F20; small buf for printing dynid to? 77 static s32 78 sUnnamedObjCount; // @ 801B9F28; used to print empty string ids (not NULL char *) to sDynNameSuffix 79 static s32 sLoadedDynObjs; // @ 801B9F2C; total loaded dynobjs 80 static struct DynObjInfo *sDynListCurInfo; // @ 801B9F30; info for most recently added object 81 static struct DynObjInfo *sParentObjInfo; ///< Information for `ObjNet` made by `d_add_net_with_subgroup()` or `ObjJoint` made by `d_attach_joint_to_net()` 82 static struct DynObjInfo *sStashedDynObjInfo; // @ 801B9F38 83 static struct GdObj *sStashedDynObj; // @ 801B9F3C 84 static s32 sDynNetCount; // @ 801B9F40 85 static char sDynNetNameSuffix[0x20]; // @ 801B9F48 86 static char sStashedDynNameSuffix[0x100]; // @ 801B9F68 87 88 // necessary foreward declarations 89 void d_add_net_with_subgroup(s32, DynObjName); 90 void d_end_net_with_subgroup(DynObjName); 91 void d_attach_joint_to_net(s32, DynObjName); 92 void d_addto_group(DynObjName); 93 void d_link_with(DynObjName); 94 void d_link_with_ptr(void *); 95 void d_set_normal(f32, f32, f32); 96 void d_make_vertex(struct GdVec3f *); 97 void d_set_rotation(f32, f32, f32); 98 void d_center_of_gravity(f32, f32, f32); 99 void d_set_shape_offset(f32, f32, f32); 100 void d_clear_flags(s32); 101 void d_attach(DynObjName); 102 void d_attach_to(s32, struct GdObj *); 103 void d_attachto_dynid(s32, DynObjName); 104 void d_set_att_offset(const struct GdVec3f *); 105 void d_set_nodegroup(DynObjName); 106 void d_set_matgroup(DynObjName); 107 void d_set_skinshape(DynObjName); 108 void d_set_planegroup(DynObjName); 109 void d_set_shapeptr(DynObjName); 110 void d_friction(f32, f32, f32); 111 void d_set_spring(f32); 112 void d_set_ambient(f32, f32, f32); 113 void d_set_control_type(s32); 114 void d_set_skin_weight(s32, f32); 115 void d_set_id(s32); 116 void d_set_material(void *, s32); 117 void d_map_materials(DynObjName); 118 void d_map_vertices(DynObjName); 119 void d_set_texture_st(f32, f32); 120 void d_use_texture(void *); 121 void d_make_netfromshapeid(DynObjName); 122 void d_make_netfromshape_ptrptr(struct ObjShape **); 123 void add_to_dynobj_list(struct GdObj *, DynObjName); 124 125 /** 126 * Store the active dynamic `GdObj` into a one object stash. 127 */ 128 void d_stash_dynobj(void) { 129 sStashedDynObjInfo = sDynListCurInfo; 130 sStashedDynObj = sDynListCurObj; 131 } 132 133 /** 134 * Set the stashed `GdObj` as the active dynamic `GdObj`. 135 */ 136 void d_unstash_dynobj(void) { 137 sDynListCurObj = sStashedDynObj; 138 sDynListCurInfo = sStashedDynObjInfo; 139 } 140 141 /** 142 * Reset dynlist related variables to a starting state 143 */ 144 void reset_dynlist(void) { 145 sUnnamedObjCount = 0; 146 sLoadedDynObjs = 0; 147 sDynNameSuffix[0] = '\0'; 148 sGdDynObjList = NULL; 149 sDynListCurObj = NULL; 150 sDynNetCount = 0; 151 sUseIntegerNames = FALSE; 152 gd_strcpy(sNullDynObjInfo.name, "NullObj"); 153 } 154 155 /** 156 * Parse a `DynList` array into active `GdObj`s. 157 * 158 * @returns Pointer to current dynamically created dynamic `GdObj`. 159 * Normally the dynlist specifically sets an object for return. 160 */ 161 struct GdObj *proc_dynlist(struct DynList *dylist) { 162 UNUSED u8 filler[8]; 163 164 if (dylist++->cmd != 0xD1D4) { 165 fatal_printf("proc_dynlist() not a valid dyn list"); 166 } 167 168 while (dylist->cmd != 58) { 169 switch (dylist->cmd) { 170 case 43: 171 d_set_name_suffix(Dyn1AsStr(dylist)); 172 break; 173 case 15: 174 d_makeobj(Dyn2AsInt(dylist), Dyn1AsName(dylist)); 175 break; 176 case 46: 177 d_add_net_with_subgroup(Dyn2AsInt(dylist), Dyn1AsName(dylist)); 178 break; 179 case 48: 180 d_end_net_with_subgroup(Dyn1AsName(dylist)); 181 break; 182 case 47: 183 d_attach_joint_to_net(Dyn2AsInt(dylist), Dyn1AsName(dylist)); 184 break; 185 case 16: 186 d_start_group(Dyn1AsName(dylist)); 187 break; 188 case 17: 189 d_end_group(Dyn1AsName(dylist)); 190 break; 191 case 18: 192 d_addto_group(Dyn1AsName(dylist)); 193 break; 194 case 30: 195 d_use_obj(Dyn1AsName(dylist)); 196 break; 197 case 28: 198 d_link_with(Dyn1AsName(dylist)); 199 break; 200 case 50: 201 d_add_valptr(Dyn1AsName(dylist), (u32) DynVecY(dylist), Dyn2AsInt(dylist), 202 (size_t) DynVecX(dylist)); 203 break; 204 case 29: 205 d_link_with_ptr(Dyn1AsPtr(dylist)); 206 break; 207 case 12: 208 proc_dynlist(Dyn1AsPtr(dylist)); 209 break; 210 case 0: 211 d_use_integer_names(Dyn2AsInt(dylist)); 212 break; 213 case 1: 214 d_set_init_pos(DynVecX(dylist), DynVecY(dylist), DynVecZ(dylist)); 215 break; 216 case 2: 217 d_set_rel_pos(DynVecX(dylist), DynVecY(dylist), DynVecZ(dylist)); 218 break; 219 case 3: 220 d_set_world_pos(DynVecX(dylist), DynVecY(dylist), DynVecZ(dylist)); 221 break; 222 case 4: 223 d_set_normal(DynVecX(dylist), DynVecY(dylist), DynVecZ(dylist)); 224 break; 225 case 5: 226 d_set_scale(DynVecX(dylist), DynVecY(dylist), DynVecZ(dylist)); 227 break; 228 case 49: 229 d_make_vertex(DynVec(dylist)); 230 break; 231 case 6: 232 d_set_rotation(DynVecX(dylist), DynVecY(dylist), DynVecZ(dylist)); 233 break; 234 case 27: 235 d_center_of_gravity(DynVecX(dylist), DynVecY(dylist), DynVecZ(dylist)); 236 break; 237 case 26: 238 d_set_shape_offset(DynVecX(dylist), DynVecY(dylist), DynVecZ(dylist)); 239 break; 240 case 44: 241 d_set_parm_f(Dyn2AsInt(dylist), DynVecX(dylist)); 242 break; 243 case 45: 244 d_set_parm_ptr(Dyn2AsInt(dylist), Dyn1AsPtr(dylist)); 245 break; 246 case 8: 247 d_set_flags(Dyn2AsInt(dylist)); 248 break; 249 case 9: 250 d_clear_flags(Dyn2AsInt(dylist)); 251 break; 252 case 7: 253 d_set_obj_draw_flag(Dyn2AsInt(dylist)); 254 break; 255 case 39: 256 d_attach(Dyn1AsName(dylist)); 257 break; 258 case 40: 259 d_attachto_dynid(Dyn2AsInt(dylist), Dyn1AsName(dylist)); 260 break; 261 case 41: 262 d_set_att_offset(DynVec(dylist)); 263 break; 264 case 21: 265 d_set_nodegroup(Dyn1AsName(dylist)); 266 break; 267 case 20: 268 d_set_matgroup(Dyn1AsName(dylist)); 269 break; 270 case 22: 271 d_set_skinshape(Dyn1AsName(dylist)); 272 break; 273 case 23: 274 d_set_planegroup(Dyn1AsName(dylist)); 275 break; 276 case 24: 277 d_set_shapeptrptr(Dyn1AsPtr(dylist)); 278 break; 279 case 25: 280 d_set_shapeptr(Dyn1AsName(dylist)); 281 break; 282 case 19: 283 d_set_type(Dyn2AsInt(dylist)); 284 break; 285 case 13: 286 d_set_colour_num(Dyn2AsInt(dylist)); 287 break; 288 case 10: 289 d_friction(DynVecX(dylist), DynVecY(dylist), DynVecZ(dylist)); 290 break; 291 case 11: 292 d_set_spring(DynVecX(dylist)); 293 break; 294 case 33: 295 d_set_ambient(DynVecX(dylist), DynVecY(dylist), DynVecZ(dylist)); 296 break; 297 case 34: 298 d_set_diffuse(DynVecX(dylist), DynVecY(dylist), DynVecZ(dylist)); 299 break; 300 case 31: 301 d_set_control_type(Dyn2AsInt(dylist)); 302 break; 303 case 32: 304 d_set_skin_weight(Dyn2AsInt(dylist), DynVecX(dylist)); 305 break; 306 case 35: 307 d_set_id(Dyn2AsInt(dylist)); 308 break; 309 case 36: 310 d_set_material(Dyn1AsPtr(dylist), Dyn2AsInt(dylist)); 311 break; 312 case 37: 313 d_map_materials(Dyn1AsName(dylist)); 314 break; 315 case 38: 316 d_map_vertices(Dyn1AsName(dylist)); 317 break; 318 case 53: 319 d_set_texture_st(DynVecX(dylist), DynVecY(dylist)); 320 break; 321 case 52: 322 d_use_texture(Dyn2AsPtr(dylist)); 323 break; 324 case 54: 325 d_make_netfromshapeid(Dyn1AsName(dylist)); 326 break; 327 case 55: 328 d_make_netfromshape_ptrptr(Dyn1AsPtr(dylist)); 329 break; 330 default: 331 fatal_printf("proc_dynlist(): unkown command"); 332 } 333 dylist++; 334 } 335 336 return sDynListCurObj; 337 } 338 339 /** 340 * Copy input `str` into a buffer that will be concatenated to a dynamic 341 * `GdObj`'s name string when creating a new dynamic object. If input 342 * is `NULL`, then a generic string is created based on the number of 343 * unnamed objects. 344 */ 345 void d_set_name_suffix(char *str) { 346 if (str != NULL) { 347 if (str[0] == '\0') { 348 sprintf(sDynNameSuffix, "__%d", ++sUnnamedObjCount); 349 } else { 350 gd_strcpy(sDynNameSuffix, str); 351 } 352 } else { 353 sDynNameSuffix[0] = '\0'; 354 } 355 } 356 357 /** 358 * Concatenate input `str` into a buffer that will be concatenated to a dynamic 359 * `GdObj`'s name string when creating a new dynamic object. If input 360 * is `NULL`, then a generic string is created based on the number of 361 * unnamed objects. 362 * 363 * @note Not called 364 */ 365 void d_append_to_name_suffix(char *str) { 366 char buf[0xff + 1]; 367 368 if (str != NULL) { 369 if (str[0] == '\0') { 370 sprintf(buf, "__%d", ++sUnnamedObjCount); 371 } else { 372 gd_strcpy(buf, str); 373 } 374 } else { 375 buf[0] = '\0'; 376 } 377 378 gd_strcat(sDynNameSuffix, buf); 379 } 380 381 /** 382 * Stash the current string that is appended to a created dynamic `GdObj` name. 383 */ 384 static void stash_name_suffix(void) { 385 gd_strcpy(sStashedDynNameSuffix, sDynNameSuffix); 386 } 387 388 /** 389 * Pop the stash for the string that is appended to a created dynamic `GdObj` name. 390 */ 391 static void unstash_name_suffix(void) { 392 gd_strcpy(sDynNameSuffix, sStashedDynNameSuffix); 393 } 394 395 /** 396 * Get the `DynObjInfo` struct for object `name` 397 * 398 * @param name Either a string or integer id for a dynamic `GdObj` 399 * @returns pointer to that object's information 400 */ 401 static struct DynObjInfo *get_dynobj_info(DynObjName name) { 402 struct DynObjInfo *foundDynobj; 403 char buf[0x100]; 404 s32 i; 405 406 if (sLoadedDynObjs == 0) { 407 return NULL; 408 } 409 410 if (sUseIntegerNames) { 411 sprintf(buf, "N%d", DynNameAsInt(name)); 412 } else { 413 gd_strcpy(buf, DynNameAsStr(name)); 414 } 415 416 gd_strcat(buf, sDynNameSuffix); 417 foundDynobj = NULL; 418 for (i = 0; i < sLoadedDynObjs; i++) { 419 if (gd_str_not_equal(sGdDynObjList[i].name, buf) == 0) { 420 foundDynobj = &sGdDynObjList[i]; 421 break; 422 } 423 } 424 425 return foundDynobj; 426 } 427 428 /** 429 * Reset the number of created dynamic objects and 430 * free the dynamic object information list (`sGdDynObjList`). 431 * The objects themselves still exist, though. 432 * 433 * @note Not called 434 */ 435 void reset_dynamic_objs(void) { 436 UNUSED u8 filler[4]; 437 438 if (sLoadedDynObjs == 0) { 439 return; 440 } 441 442 gd_free(sGdDynObjList); 443 sLoadedDynObjs = 0; 444 sGdDynObjList = NULL; 445 } 446 447 /** 448 * Create an `ObjNet` and an associated node `ObjGroup`. This function creates 449 * its own naming string to append to later created dynamic objects. 450 */ 451 void d_add_net_with_subgroup(UNUSED s32 a0, DynObjName name) { 452 d_makeobj(D_NET, name); 453 d_set_obj_draw_flag(OBJ_INVISIBLE); 454 // this creates a string to append to the names of the objs created after this 455 sprintf(sDynNetNameSuffix, "c%d", ++sDynNetCount); 456 d_set_type(4); 457 stash_name_suffix(); 458 d_set_name_suffix(sDynNetNameSuffix); 459 d_start_group(name); 460 unstash_name_suffix(); 461 d_use_obj(name); 462 sParentObjInfo = sDynListCurInfo; 463 } 464 465 /** 466 * End the `ObjNet`+`ObjGroup` set created by `d_add_net_with_subgroup()`. 467 */ 468 void d_end_net_with_subgroup(DynObjName name) { 469 d_use_obj(name); 470 stash_name_suffix(); 471 d_set_name_suffix(sDynNetNameSuffix); 472 d_end_group(name); 473 d_set_nodegroup(name); 474 unstash_name_suffix(); 475 sParentObjInfo = NULL; 476 } 477 478 /** 479 * Create an `ObjJoint` and attach that to the `ObjNet` created by 480 * `d_add_net_with_subgroup()` or the most recent `ObjJoint` created 481 * by `d_attach_joint_to_net()`. 482 * 483 * @param arg0 Not used 484 * @param name Name for created `ObjJoint` 485 */ 486 void d_attach_joint_to_net(UNUSED s32 arg0, DynObjName name) { 487 UNUSED struct DynObjInfo *curInfo = sDynListCurInfo; 488 UNUSED u8 filler[8]; 489 490 d_makeobj(D_JOINT, name); 491 d_set_type(3); 492 d_set_shapeptrptr(NULL); 493 d_attach_to(0xD, sParentObjInfo->obj); 494 sParentObjInfo = sDynListCurInfo; 495 } 496 497 /** 498 * Create a new `ObjNet` linked with the dynamic `ObjShape` `name`. 499 * The newly made net is added to the dynamic object list. 500 */ 501 void d_make_netfromshapeid(DynObjName name) { 502 struct DynObjInfo *dyninfo = get_dynobj_info(name); 503 struct ObjNet *net; 504 505 if (dyninfo == NULL) { 506 fatal_printf("dMakeNetFromShape(\"%s\"): Undefined object", DynNameAsStr(name)); 507 } 508 509 net = make_netfromshape((struct ObjShape *) dyninfo->obj); 510 add_to_dynobj_list(&net->header, NULL); 511 } 512 513 /** 514 * Create a new `ObjNet` linked with the doubly indirected `ObjShape`. 515 * The newly made net is added to the dynamic object list, but 516 * the shape is not moved into the dynamic list. 517 */ 518 void d_make_netfromshape_ptrptr(struct ObjShape **shapePtr) { 519 UNUSED u8 filler[4]; 520 struct ObjNet *net = make_netfromshape(*shapePtr); 521 522 printf("dMakeNetFromShapePtrPtr\n"); 523 524 add_to_dynobj_list(&net->header, NULL); 525 } 526 527 /** 528 * Add `newobj` identified by `name` to the dynamic `GdObj` list. Once a `GdObj` 529 * is in the dynamic list, it can referred to by its `name` when that object is 530 * needed later. 531 */ 532 void add_to_dynobj_list(struct GdObj *newobj, DynObjName name) { 533 UNUSED u8 filler[4]; 534 char idbuf[0x100]; 535 536 start_memtracker("dynlist"); 537 538 if (sGdDynObjList == NULL) { 539 sGdDynObjList = gd_malloc_temp(DYNOBJ_LIST_SIZE * sizeof(struct DynObjInfo)); 540 if (sGdDynObjList == NULL) { 541 fatal_printf("dMakeObj(): Cant allocate dynlist memory"); 542 } 543 } 544 545 stop_memtracker("dynlist"); 546 547 if (sUseIntegerNames) { 548 sprintf(idbuf, "N%d", DynNameAsInt(name)); 549 name = NULL; 550 } else { 551 sprintf(idbuf, "U%d", ((u32) sLoadedDynObjs) + 1); 552 } 553 554 if (DynNameAsStr(name) != NULL) { 555 if (get_dynobj_info(name) != NULL) { 556 fatal_printf("dMakeObj(\"%s\"): Object with same name already exists", DynNameAsStr(name)); 557 } 558 gd_strcpy(sGdDynObjList[sLoadedDynObjs].name, DynNameAsStr(name)); 559 } else { 560 gd_strcpy(sGdDynObjList[sLoadedDynObjs].name, idbuf); 561 } 562 563 gd_strcat(sGdDynObjList[sLoadedDynObjs].name, sDynNameSuffix); 564 565 if (gd_strlen(sGdDynObjList[sLoadedDynObjs].name) > (DYNOBJ_NAME_SIZE - 1)) { 566 fatal_printf("dyn list obj name too long '%s'", sGdDynObjList[sLoadedDynObjs].name); 567 } 568 569 sGdDynObjList[sLoadedDynObjs].num = sLoadedDynObjs; 570 sDynListCurInfo = &sGdDynObjList[sLoadedDynObjs]; 571 sGdDynObjList[sLoadedDynObjs++].obj = newobj; 572 573 // A good place to bounds-check your array is 574 // after you finish writing a new member to it. 575 if (sLoadedDynObjs >= DYNOBJ_LIST_SIZE) { 576 fatal_printf("dMakeObj(): Too many dynlist objects"); 577 } 578 579 sDynListCurObj = newobj; 580 } 581 582 /** 583 * Format `name` into string, if `DynObjName`s are currently being interpreted 584 * as numbers. 585 * 586 * @returns pointer to global buffer for id 587 * @retval NULL if `name` is `NULL` or if `DynObjName`s are interpreted as strings 588 */ 589 static char *integer_name_to_string(DynObjName name) { 590 if (DynNameAsInt(name) != 0 && sUseIntegerNames) { 591 sprintf(sIntToStringBuf, "N%d", DynNameAsInt(name)); 592 return sIntToStringBuf; 593 } 594 595 return NULL; 596 } 597 598 /** 599 * Create a new `GdObj` of `type` and add that object to the 600 * dynamic object list with `name`. Created objects have default 601 * parameters, which are usually 0 or NULL. 602 * 603 * @returns pointer to created object 604 */ 605 struct GdObj *d_makeobj(enum DObjTypes type, DynObjName name) { 606 struct GdObj *dobj; 607 UNUSED struct ObjGroup *dgroup; 608 609 switch (type) { 610 case D_CAR_DYNAMICS: 611 fatal_printf("dmakeobj() Car dynamics are missing!"); 612 break; 613 case D_JOINT: 614 dobj = &make_joint(0, 0.0f, 0.0f, 0.0f)->header; 615 break; 616 case D_ANOTHER_JOINT: 617 dobj = &make_joint(0, 0.0f, 0.0f, 0.0f)->header; 618 break; 619 case D_NET: 620 dobj = &make_net(0, NULL, NULL, NULL, NULL)->header; 621 break; 622 case D_GROUP: 623 dobj = &make_group(0)->header; 624 dgroup = (struct ObjGroup *) dobj; 625 break; 626 case D_DATA_GRP: 627 d_makeobj(D_GROUP, name); 628 ((struct ObjGroup *) sDynListCurObj)->linkType = 1; 629 //! @bug Returns garbage when making `D_DATA_GRP` object 630 #ifdef AVOID_UB 631 return NULL; 632 #else 633 return; 634 #endif 635 case D_CAMERA: 636 dobj = &make_camera(0, NULL)->header; 637 break; 638 case D_BONE: 639 dobj = &make_bone(0, NULL, NULL, 0)->header; 640 break; 641 case D_PARTICLE: 642 dobj = &make_particle(0, 0, 0.0f, 0.0f, 0.0f)->header; 643 break; 644 case D_VERTEX: 645 dobj = &gd_make_vertex(0.0f, 0.0f, 0.0f)->header; 646 break; 647 case D_FACE: 648 dobj = &make_face_with_colour(1.0, 1.0, 1.0)->header; 649 break; 650 case D_PLANE: 651 dobj = &make_plane(FALSE, NULL)->header; 652 break; 653 case D_MATERIAL: 654 dobj = &make_material(0, NULL, 0)->header; 655 break; 656 case D_SHAPE: 657 dobj = &make_shape(0, integer_name_to_string(name))->header; 658 break; 659 case D_GADGET: 660 dobj = &make_gadget(0, 0)->header; 661 break; 662 case D_LABEL: 663 //! @bug When making a `D_LABEL`, the call to `make_label()` 664 //! compiles incorrectly due to Goddard only declaring 665 //! the functions, not prototyping the functions 666 dobj = &make_label(NULL, NULL, 8, 0, 0, 0)->header; 667 break; 668 case D_VIEW: 669 dobj = &make_view(NULL, 670 (VIEW_2_COL_BUF | VIEW_ALLOC_ZBUF | VIEW_UNK_2000 | VIEW_UNK_4000 671 | VIEW_1_CYCLE | VIEW_MOVEMENT | VIEW_DRAW), 672 2, 0, 0, 0, 0, NULL) 673 ->header; 674 break; 675 case D_ANIMATOR: 676 dobj = &make_animator()->header; 677 break; 678 case D_LIGHT: 679 dobj = &make_light(0, NULL, 0)->header; 680 addto_group(gGdLightGroup, dobj); 681 break; 682 default: 683 fatal_printf("dMakeObj(): Unkown object type"); 684 } 685 686 add_to_dynobj_list(dobj, name); 687 return dobj; 688 } 689 690 /** 691 * Attach dynamic object `name` to the current active `ObjJoint` object. 692 * 693 * @note This function doesn't actually do anything. 694 */ 695 void d_attach(DynObjName name) { 696 struct DynObjInfo *info; 697 698 if (sDynListCurObj == NULL) { 699 fatal_printf("proc_dynlist(): No current object"); 700 } 701 702 info = get_dynobj_info(name); 703 if (info == NULL) { 704 fatal_printf("dAttach(\"%s\"): Undefined object", DynNameAsStr(name)); 705 } 706 707 switch (sDynListCurObj->type) { 708 case OBJ_TYPE_JOINTS: 709 break; 710 default: 711 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dAttach()", 712 sDynListCurInfo->name, sDynListCurObj->type); 713 } 714 } 715 716 /** 717 * Attach the current dynamic `GdObj` into the proper subgroup of `obj` and set 718 * the "attach flags" of the current dynamic object to `flag` 719 */ 720 void d_attach_to(s32 flag, struct GdObj *obj) { 721 UNUSED u8 filler1[4]; 722 struct ObjGroup *attgrp; 723 UNUSED u8 filler2[8]; 724 UNUSED struct DynObjInfo *curInfo = sDynListCurInfo; 725 struct GdVec3f currObjPos; // transformed into attach offset 726 struct GdVec3f objPos; 727 728 d_stash_dynobj(); 729 730 if (sDynListCurObj == NULL) { 731 fatal_printf("proc_dynlist(): No current object"); 732 } 733 734 // find or generate attachment groups 735 switch (obj->type) { 736 case OBJ_TYPE_JOINTS: 737 if ((attgrp = ((struct ObjJoint *) obj)->attachedObjsGrp) == NULL) { 738 attgrp = ((struct ObjJoint *) obj)->attachedObjsGrp = make_group(0); 739 } 740 break; 741 case OBJ_TYPE_NETS: 742 if ((attgrp = ((struct ObjNet *) obj)->attachedObjsGrp) == NULL) { 743 attgrp = ((struct ObjNet *) obj)->attachedObjsGrp = make_group(0); 744 } 745 break; 746 case OBJ_TYPE_PARTICLES: 747 if ((attgrp = ((struct ObjParticle *) obj)->attachedObjsGrp) == NULL) { 748 attgrp = ((struct ObjParticle *) obj)->attachedObjsGrp = make_group(0); 749 } 750 break; 751 case OBJ_TYPE_ANIMATORS: 752 if ((attgrp = ((struct ObjAnimator *) obj)->attachedObjsGrp) == NULL) { 753 attgrp = ((struct ObjAnimator *) obj)->attachedObjsGrp = make_group(0); 754 } 755 break; 756 default: 757 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dAttachTo()", 758 sDynListCurInfo->name, sDynListCurObj->type); 759 } 760 761 if (group_contains_obj(attgrp, sDynListCurObj)) { 762 return; 763 } 764 765 addto_group(attgrp, sDynListCurObj); 766 767 if (flag & 9) { 768 d_get_world_pos(&currObjPos); 769 set_cur_dynobj(obj); 770 d_get_world_pos(&objPos); 771 772 currObjPos.x -= objPos.x; 773 currObjPos.y -= objPos.y; 774 currObjPos.z -= objPos.z; 775 } 776 777 d_unstash_dynobj(); 778 switch (sDynListCurObj->type) { 779 case OBJ_TYPE_JOINTS: 780 ((struct ObjJoint *) sDynListCurObj)->attachFlags = flag; 781 ((struct ObjJoint *) sDynListCurObj)->attachedToObj = obj; 782 break; 783 case OBJ_TYPE_NETS: 784 ((struct ObjNet *) sDynListCurObj)->attachFlags = flag; 785 ((struct ObjNet *) sDynListCurObj)->attachedToObj = obj; 786 break; 787 case OBJ_TYPE_PARTICLES: 788 ((struct ObjParticle *) sDynListCurObj)->attachFlags = flag; 789 ((struct ObjParticle *) sDynListCurObj)->attachedToObj = obj; 790 break; 791 case OBJ_TYPE_ANIMATORS: 792 ((struct ObjAnimator *) sDynListCurObj)->attachFlags = flag; 793 ((struct ObjAnimator *) sDynListCurObj)->attachedToObj = obj; 794 break; 795 default: 796 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dAttachTo()", 797 sDynListCurInfo->name, sDynListCurObj->type); 798 } 799 800 if (flag & 9) { 801 d_set_att_offset(&currObjPos); 802 } 803 } 804 805 /** 806 * Attach the current dynamic object to dynamic object `name`. This function 807 * is a wrapper around `d_attach_to()` 808 */ 809 void d_attachto_dynid(s32 flag, DynObjName name) { 810 struct DynObjInfo *info; 811 812 if (name == NULL) { 813 return; 814 } 815 if (sDynListCurObj == NULL) { 816 fatal_printf("proc_dynlist(): No current object"); 817 } 818 819 info = get_dynobj_info(name); 820 if (info == NULL) { 821 fatal_printf("dAttachTo(\"%s\"): Undefined object", DynNameAsStr(name)); 822 } 823 824 d_attach_to(flag, info->obj); 825 } 826 827 /** 828 * Helper function to copy bytes. Where's memcpy when you need it? 829 */ 830 void copy_bytes(u8 *src, u8 *dst, s32 num) { 831 if (num == 0) { 832 return; 833 } 834 while (num--) { 835 *dst++ = *src++; 836 } 837 } 838 839 /** 840 * Allocate the animation data for `animator` onto the goddard heap. 841 * Animation data of type `::GD_ANIM_SCALE3S_POS3S_ROT3S` is converted to a `AnimMtxVec` struct, 842 * rather than solely byted copied like the other types. 843 */ 844 void alloc_animdata(struct ObjAnimator *animator) { 845 UNUSED u8 filler1[4]; 846 // probably should be three GdVec3fs, not triangle... 847 // vec0 = position; vec1 = scale? rotation?; vec2 = translation 848 struct GdTriangleF tri; //+58; temp float for converting half to f32? 849 s16(*halfarr)[9]; //+54; data to convert into a AnimMtxVec 850 struct AnimDataInfo *curAnimSrc; //+50; source animation data... 851 struct AnimDataInfo *animDst; //+4c; destination anim data II 852 struct AnimDataInfo *animDataArr; //+48; start of allocated anim data memory 853 struct ObjGroup *animgrp; //+44 854 s32 datasize; //+40; anim data allocation size? 855 s32 dataIdx; //+3C; byte count? 856 s32 animCnt; //+38; count of animdata "info" structs 857 s32 i; //+34 858 void *allocSpace; //+30; allocated animdata space 859 f32 allocMtxScale = 0.1f; //+2C; scale postion/rotation of GD_ANIM_SCALE3S_POS3S_ROT3S data 860 struct AnimMtxVec *curMtxVec; //+28 861 UNUSED u8 filler2[4]; 862 863 start_memtracker("animdata"); 864 865 if ((animgrp = animator->animdataGrp) == NULL) { 866 fatal_printf("no anim group"); 867 } 868 869 if ((curAnimSrc = (struct AnimDataInfo *) animgrp->firstMember->obj) == NULL) { 870 fatal_printf("no animation data"); 871 } 872 873 // count number of array-ed animation data structs 874 animDst = curAnimSrc; 875 animCnt = 0; 876 while (animDst++->count >= 0) { 877 animCnt++; 878 } 879 880 animDst = gd_malloc_perm(animCnt * sizeof(struct AnimDataInfo)); // gd_alloc_perm 881 if ((animDataArr = animDst) == NULL) { 882 fatal_printf("cant allocate animation data"); 883 } 884 885 for (i = 0; i < animCnt; i++) { 886 allocSpace = NULL; 887 if (curAnimSrc->type != 0) { 888 switch (curAnimSrc->type) { 889 case GD_ANIM_CAMERA_EYE3S_LOOKAT3S: 890 datasize = sizeof(s16[6]); 891 break; 892 case GD_ANIM_ROT3S: 893 datasize = sizeof(s16[3]); 894 break; 895 case GD_ANIM_POS3S: 896 datasize = sizeof(s16[3]); 897 break; 898 case GD_ANIM_ROT3S_POS3S: 899 datasize = sizeof(s16[6]); 900 break; 901 case GD_ANIM_SCALE3F_ROT3F_POS3F: 902 datasize = sizeof(f32[3][3]); 903 break; 904 /* This function will convert the s16[9] array into a struct AnimMtxVec */ 905 case GD_ANIM_SCALE3S_POS3S_ROT3S: 906 datasize = sizeof(struct AnimMtxVec); 907 break; 908 case GD_ANIM_MTX4x4: 909 datasize = sizeof(Mat4f); 910 break; 911 default: 912 fatal_printf("unknown anim type for allocation"); 913 break; 914 } 915 916 allocSpace = gd_malloc_perm(curAnimSrc->count * datasize); // gd_alloc_perm 917 if (allocSpace == NULL) { 918 fatal_printf("cant allocate animation data"); 919 } 920 921 if (curAnimSrc->type == GD_ANIM_SCALE3S_POS3S_ROT3S) { 922 for (dataIdx = 0; dataIdx < curAnimSrc->count; dataIdx++) { 923 halfarr = &((s16(*)[9]) curAnimSrc->data)[dataIdx]; 924 curMtxVec = &((struct AnimMtxVec *) allocSpace)[dataIdx]; 925 926 tri.p0.x = (f32)(*halfarr)[0] * allocMtxScale; 927 tri.p0.y = (f32)(*halfarr)[1] * allocMtxScale; 928 tri.p0.z = (f32)(*halfarr)[2] * allocMtxScale; 929 tri.p1.x = (f32)(*halfarr)[3] * allocMtxScale; 930 tri.p1.y = (f32)(*halfarr)[4] * allocMtxScale; 931 tri.p1.z = (f32)(*halfarr)[5] * allocMtxScale; 932 tri.p2.x = (f32)(*halfarr)[6]; 933 tri.p2.y = (f32)(*halfarr)[7]; 934 tri.p2.z = (f32)(*halfarr)[8]; 935 936 gd_set_identity_mat4(&curMtxVec->matrix); 937 gd_rot_mat_about_vec(&curMtxVec->matrix, &tri.p1); 938 gd_add_vec3f_to_mat4f_offset(&curMtxVec->matrix, &tri.p2); 939 940 ((struct AnimMtxVec *) allocSpace)[dataIdx].vec.x = tri.p0.x; 941 ((struct AnimMtxVec *) allocSpace)[dataIdx].vec.y = tri.p0.y; 942 ((struct AnimMtxVec *) allocSpace)[dataIdx].vec.z = tri.p0.z; 943 } 944 curAnimSrc->type = GD_ANIM_MTX4x4F_SCALE3F; 945 } else { 946 copy_bytes(curAnimSrc->data, allocSpace, curAnimSrc->count * datasize); 947 } 948 } 949 950 animDst[i].type = curAnimSrc->type; 951 animDst[i].count = curAnimSrc->count; 952 animDst[i].data = allocSpace; 953 954 curAnimSrc++; // next anim data struct 955 } 956 957 animgrp->firstMember->obj = (void *) animDataArr; 958 stop_memtracker("animdata"); 959 } 960 961 /** 962 * Generate or create the various `ObjVertex`, `ObjFace`, and/or 963 * `ObjMaterial` when groups of those structures are attached to 964 * `shape`. This function is called when `d_set_nodegroup()`, 965 * `d_set_planegroup()`, or `d_set_matgroup()` are called 966 * when an `ObjShape` is the active dynamic object. 967 * 968 * @note Face/vertices need to be set before materials 969 */ 970 void chk_shapegen(struct ObjShape *shape) { 971 struct ObjFace *face; // sp5C; made face 972 struct ObjVertex *vtx; // sp58; made gdvtx 973 struct ObjVertex **vtxbuf; // sp54; heap storage for made gd vtx 974 struct ObjGroup *shapeMtls; // sp50 975 struct ObjGroup *shapeFaces; // sp4C 976 struct ObjGroup *shapeVtx; // sp48 977 UNUSED u8 filler[4]; 978 struct ObjGroup *madeFaces; // sp40 979 struct ObjGroup *madeVtx; // sp3C 980 u32 i; // sp38 981 struct GdVtxData *vtxdata; // sp34 982 struct GdFaceData *facedata; // sp30 983 struct GdObj *oldObjHead; // sp2C 984 985 start_memtracker("chk_shapegen"); 986 imin("chk_shapegen"); 987 shapeMtls = shape->mtlGroup; 988 shapeFaces = shape->faceGroup; 989 shapeVtx = shape->vtxGroup; 990 991 if (shapeVtx != NULL && shapeFaces != NULL) { 992 if ((shapeVtx->linkType & 1) && (shapeFaces->linkType & 1)) { //? needs the double if 993 // These ListNodes point to special, compressed data structures 994 vtxdata = (struct GdVtxData *) shapeVtx->firstMember->obj; 995 facedata = (struct GdFaceData *) shapeFaces->firstMember->obj; 996 if (facedata->type != 1) { 997 fatal_printf("unsupported poly type"); 998 } 999 1000 if (vtxdata->type != 1) { 1001 fatal_printf("unsupported vertex type"); 1002 } 1003 1004 if (vtxdata->count >= VTX_BUF_SIZE) { 1005 fatal_printf("shapegen() too many vertices"); 1006 } 1007 1008 vtxbuf = gd_malloc_temp(VTX_BUF_SIZE * sizeof(struct ObjVertex *)); 1009 oldObjHead = gGdObjectList; 1010 1011 for (i = 0; i < vtxdata->count; i++) { 1012 vtx = gd_make_vertex(vtxdata->data[i][0], vtxdata->data[i][1], vtxdata->data[i][2]); 1013 vtx->normal.x = vtx->normal.y = vtx->normal.z = 0.0f; 1014 vtxbuf[i] = vtx; 1015 } 1016 1017 madeVtx = make_group_of_type(OBJ_TYPE_VERTICES, oldObjHead, NULL); 1018 1019 oldObjHead = gGdObjectList; 1020 for (i = 0; i < facedata->count; i++) { 1021 //! @bug Call to `make_face_with_colour()` compiles incorrectly 1022 //! due to Goddard only declaring the functions, 1023 //! not prototyping the functions 1024 face = make_face_with_colour(1.0, 1.0, 1.0); 1025 face->mtlId = (s32) facedata->data[i][0]; 1026 add_3_vtx_to_face(face, vtxbuf[facedata->data[i][1]], vtxbuf[facedata->data[i][2]], 1027 vtxbuf[facedata->data[i][3]]); 1028 vtxbuf[facedata->data[i][1]]->normal.x += face->normal.x; 1029 vtxbuf[facedata->data[i][1]]->normal.y += face->normal.y; 1030 vtxbuf[facedata->data[i][1]]->normal.z += face->normal.z; 1031 1032 vtxbuf[facedata->data[i][2]]->normal.x += face->normal.x; 1033 vtxbuf[facedata->data[i][2]]->normal.y += face->normal.y; 1034 vtxbuf[facedata->data[i][2]]->normal.z += face->normal.z; 1035 1036 vtxbuf[facedata->data[i][3]]->normal.x += face->normal.x; 1037 vtxbuf[facedata->data[i][3]]->normal.y += face->normal.y; 1038 vtxbuf[facedata->data[i][3]]->normal.z += face->normal.z; 1039 } 1040 1041 if (shape->flag & 0x10) { 1042 for (i = 0; i < vtxdata->count; i++) { 1043 vtxbuf[i]->normal.x = vtxbuf[i]->pos.x; 1044 vtxbuf[i]->normal.y = vtxbuf[i]->pos.y; 1045 vtxbuf[i]->normal.z = vtxbuf[i]->pos.z; 1046 gd_normalize_vec3f(&vtxbuf[i]->normal); 1047 } 1048 } else { 1049 for (i = 0; i < vtxdata->count; i++) { 1050 gd_normalize_vec3f(&vtxbuf[i]->normal); 1051 } 1052 } 1053 1054 gd_free(vtxbuf); 1055 madeFaces = make_group_of_type(OBJ_TYPE_FACES, oldObjHead, NULL); 1056 shape->faceGroup = madeFaces; 1057 shape->vtxGroup = madeVtx; 1058 } 1059 } 1060 1061 if (shapeMtls != NULL) { 1062 if (shape->faceGroup) { 1063 map_face_materials(shape->faceGroup, shapeMtls); 1064 } else { 1065 fatal_printf("chk_shapegen() please set face group before mats"); 1066 } 1067 } 1068 1069 imout(); 1070 stop_memtracker("chk_shapegen"); 1071 } 1072 1073 /** 1074 * Set the "node group" of the current dynamic object to dynamic object `name`. 1075 * The node group depends on the type of the current dynamic object: 1076 * * the vertex group is set for `ObjShape` 1077 * * the joints/weight group is set for `ObjNet` 1078 * * data is set for `ObjAnimator` 1079 * * something is set for `ObjGadget` 1080 */ 1081 void d_set_nodegroup(DynObjName name) { 1082 struct DynObjInfo *info; // sp2C 1083 UNUSED u8 filler[8]; 1084 1085 if (sDynListCurObj == NULL) { 1086 fatal_printf("proc_dynlist(): No current object"); 1087 } 1088 1089 info = get_dynobj_info(name); 1090 if (info == NULL) { 1091 fatal_printf("dSetNodeGroup(\"%s\"): Undefined group", DynNameAsStr(name)); 1092 } 1093 1094 switch (sDynListCurObj->type) { 1095 case OBJ_TYPE_NETS: 1096 ((struct ObjNet *) sDynListCurObj)->unk1C8 = (struct ObjGroup *) info->obj; 1097 ((struct ObjNet *) sDynListCurObj)->unk1D0 = (struct ObjGroup *) info->obj; 1098 break; 1099 case OBJ_TYPE_SHAPES: 1100 ((struct ObjShape *) sDynListCurObj)->vtxGroup = (struct ObjGroup *) info->obj; 1101 chk_shapegen((struct ObjShape *) sDynListCurObj); 1102 break; 1103 case OBJ_TYPE_GADGETS: 1104 ((struct ObjGadget *) sDynListCurObj)->unk54 = (struct ObjGroup *) info->obj; 1105 break; 1106 case OBJ_TYPE_ANIMATORS: 1107 ((struct ObjAnimator *) sDynListCurObj)->animdataGrp = (struct ObjGroup *) info->obj; 1108 alloc_animdata((struct ObjAnimator *) sDynListCurObj); 1109 break; 1110 default: 1111 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetNodeGroup()", 1112 sDynListCurInfo->name, sDynListCurObj->type); 1113 } 1114 } 1115 1116 /** 1117 * Set the material group of the current dynamic `ObjShape` to `name`. 1118 */ 1119 void d_set_matgroup(DynObjName name) { 1120 struct DynObjInfo *info; 1121 1122 if (sDynListCurObj == NULL) { 1123 fatal_printf("proc_dynlist(): No current object"); 1124 } 1125 1126 info = get_dynobj_info(name); 1127 if (info == NULL) { 1128 fatal_printf("dSetMatGroup(\"%s\"): Undefined group", DynNameAsStr(name)); 1129 } 1130 1131 switch (sDynListCurObj->type) { 1132 case OBJ_TYPE_SHAPES: 1133 ((struct ObjShape *) sDynListCurObj)->mtlGroup = (struct ObjGroup *) info->obj; 1134 chk_shapegen((struct ObjShape *) sDynListCurObj); 1135 break; 1136 default: 1137 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetMatGroup()", 1138 sDynListCurInfo->name, sDynListCurObj->type); 1139 } 1140 } 1141 1142 /** 1143 * At one time in the past, this set the s and t value of the current 1144 * dynamic `ObjVertex`. However, this function does nothing now. 1145 * See `BetaVtx` for a possible remnant of vertex code that had 1146 * ST coordinates. 1147 */ 1148 void d_set_texture_st(UNUSED f32 s, UNUSED f32 t) { 1149 UNUSED u8 filler[8]; 1150 1151 if (sDynListCurObj == NULL) { 1152 fatal_printf("proc_dynlist(): No current object"); 1153 } 1154 1155 switch (sDynListCurObj->type) { 1156 case OBJ_TYPE_VERTICES: 1157 break; // ifdef-ed out? 1158 default: 1159 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetTextureST()", 1160 sDynListCurInfo->name, sDynListCurObj->type); 1161 } 1162 } 1163 1164 /** 1165 * Set the texture pointer of the current dynamic `ObjMaterial`. 1166 */ 1167 void d_use_texture(void *texture) { 1168 if (sDynListCurObj == NULL) { 1169 fatal_printf("proc_dynlist(): No current object"); 1170 } 1171 1172 switch (sDynListCurObj->type) { 1173 case OBJ_TYPE_MATERIALS: 1174 ((struct ObjMaterial *) sDynListCurObj)->texture = texture; 1175 break; 1176 default: 1177 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dUseTexture()", 1178 sDynListCurInfo->name, sDynListCurObj->type); 1179 } 1180 } 1181 1182 /** 1183 * Set the current dynamic `ObjNet`'s skin group with the vertex group from 1184 * the dynamic `ObjShape` with `name`. 1185 */ 1186 void d_set_skinshape(DynObjName name) { 1187 struct DynObjInfo *info; 1188 1189 if (sDynListCurObj == NULL) { 1190 fatal_printf("proc_dynlist(): No current object"); 1191 } 1192 1193 info = get_dynobj_info(name); 1194 if (info == NULL) { 1195 fatal_printf("dSetSkinShape(\"%s\"): Undefined object", DynNameAsStr(name)); 1196 } 1197 1198 switch (sDynListCurObj->type) { 1199 case OBJ_TYPE_NETS: 1200 ((struct ObjNet *) sDynListCurObj)->skinGrp = ((struct ObjShape *) info->obj)->vtxGroup; 1201 break; 1202 default: 1203 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetSkinShape()", 1204 sDynListCurInfo->name, sDynListCurObj->type); 1205 } 1206 } 1207 1208 /** 1209 * Map the material ids for the `ObjFace`s in the current dynamic `ObjGroup` 1210 * to pointer to `ObjMaterial`s in the `ObjGroup` `name`. 1211 * 1212 * See `map_face_materials()` for more info. 1213 */ 1214 void d_map_materials(DynObjName name) { 1215 struct DynObjInfo *info; 1216 1217 if (sDynListCurObj == NULL) { 1218 fatal_printf("proc_dynlist(): No current object"); 1219 } 1220 1221 info = get_dynobj_info(name); 1222 if (info == NULL) { 1223 fatal_printf("dMapMaterials(\"%s\"): Undefined group", DynNameAsStr(name)); 1224 } 1225 1226 map_face_materials((struct ObjGroup *) sDynListCurObj, (struct ObjGroup *) info->obj); 1227 } 1228 1229 /** 1230 * For all faces in the current `ObjGroup`, resolve their vertex indices to 1231 * `ObjVertex` pointers that point to vertices in the specified vertex group. 1232 * Also compute normals for all faces in the current `ObjGroup` and all vertices 1233 * in the specified vertex group. 1234 * See `map_vertices()` for more info. 1235 * @param name name of a vertex group dynobj 1236 */ 1237 void d_map_vertices(DynObjName name) { 1238 struct DynObjInfo *info; 1239 1240 if (sDynListCurObj == NULL) { 1241 fatal_printf("proc_dynlist(): No current object"); 1242 } 1243 1244 info = get_dynobj_info(name); 1245 if (info == NULL) { 1246 fatal_printf("dMapVertices(\"%s\"): Undefined group", DynNameAsStr(name)); 1247 } 1248 1249 map_vertices((struct ObjGroup *) sDynListCurObj, (struct ObjGroup *) info->obj); 1250 } 1251 1252 /** 1253 * In practice, this is used to set the faces of the current 1254 * active dynamic `ObjShape` to the dynamic group `name` of `ObjFace`s. 1255 * It also has interactions with `ObjNet`s, but there are no examples 1256 * of that usage in existing code. 1257 */ 1258 void d_set_planegroup(DynObjName name) { 1259 struct DynObjInfo *info; 1260 UNUSED u8 filler[8]; 1261 1262 if (sDynListCurObj == NULL) { 1263 fatal_printf("proc_dynlist(): No current object"); 1264 } 1265 1266 info = get_dynobj_info(name); 1267 if (info == NULL) { 1268 fatal_printf("dSetPlaneGroup(\"%s\"): Undefined group", DynNameAsStr(name)); 1269 } 1270 1271 switch (sDynListCurObj->type) { 1272 case OBJ_TYPE_NETS: 1273 ((struct ObjNet *) sDynListCurObj)->unk1CC = (struct ObjGroup *) info->obj; 1274 break; 1275 case OBJ_TYPE_SHAPES: 1276 ((struct ObjShape *) sDynListCurObj)->faceGroup = (struct ObjGroup *) info->obj; 1277 chk_shapegen((struct ObjShape *) sDynListCurObj); 1278 break; 1279 default: 1280 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetPlaneGroup()", 1281 sDynListCurInfo->name, sDynListCurObj->type); 1282 } 1283 } 1284 1285 /** 1286 * Set the shape pointer of the current active dynamic object to the 1287 * pointer pointed to by `shpPtrptr`. 1288 */ 1289 void d_set_shapeptrptr(struct ObjShape **shpPtrptr) { 1290 struct ObjShape *defaultptr = NULL; 1291 1292 if (sDynListCurObj == NULL) { 1293 fatal_printf("proc_dynlist(): No current object"); 1294 } 1295 1296 if (shpPtrptr == NULL) { 1297 shpPtrptr = &defaultptr; 1298 } 1299 1300 switch (sDynListCurObj->type) { 1301 case OBJ_TYPE_JOINTS: 1302 ((struct ObjJoint *) sDynListCurObj)->shapePtr = *shpPtrptr; 1303 ((struct ObjJoint *) sDynListCurObj)->colourNum = 0; 1304 break; 1305 case OBJ_TYPE_NETS: 1306 ((struct ObjNet *) sDynListCurObj)->shapePtr = *shpPtrptr; 1307 break; 1308 case OBJ_TYPE_BONES: 1309 ((struct ObjBone *) sDynListCurObj)->shapePtr = *shpPtrptr; 1310 break; 1311 case OBJ_TYPE_GADGETS: 1312 ((struct ObjGadget *) sDynListCurObj)->shapePtr = *shpPtrptr; 1313 break; 1314 case OBJ_TYPE_PARTICLES: 1315 ((struct ObjParticle *) sDynListCurObj)->shapePtr = *shpPtrptr; 1316 break; 1317 case OBJ_TYPE_LIGHTS: 1318 ((struct ObjLight *) sDynListCurObj)->unk9C = *shpPtrptr; 1319 break; 1320 default: 1321 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetShapePtrPtr()", 1322 sDynListCurInfo->name, sDynListCurObj->type); 1323 } 1324 } 1325 1326 /** 1327 * Set the shape pointer of the current active dynamic object to dynamic 1328 * `ObjShape` `name`. 1329 */ 1330 void d_set_shapeptr(DynObjName name) { 1331 struct DynObjInfo *info; 1332 if (name == NULL) { 1333 return; 1334 } 1335 1336 info = get_dynobj_info(name); 1337 if (info == NULL) { 1338 fatal_printf("dSetShapePtr(\"%s\"): Undefined object", DynNameAsStr(name)); 1339 } 1340 1341 switch (sDynListCurObj->type) { 1342 case OBJ_TYPE_JOINTS: 1343 ((struct ObjJoint *) sDynListCurObj)->shapePtr = (struct ObjShape *) info->obj; 1344 ((struct ObjJoint *) sDynListCurObj)->colourNum = 0; 1345 break; 1346 case OBJ_TYPE_NETS: 1347 ((struct ObjNet *) sDynListCurObj)->shapePtr = (struct ObjShape *) info->obj; 1348 break; 1349 case OBJ_TYPE_BONES: 1350 ((struct ObjBone *) sDynListCurObj)->shapePtr = (struct ObjShape *) info->obj; 1351 break; 1352 case OBJ_TYPE_GADGETS: 1353 ((struct ObjGadget *) sDynListCurObj)->shapePtr = (struct ObjShape *) info->obj; 1354 break; 1355 case OBJ_TYPE_PARTICLES: 1356 ((struct ObjParticle *) sDynListCurObj)->shapePtr = (struct ObjShape *) info->obj; 1357 break; 1358 default: 1359 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetShapePtr()", 1360 sDynListCurInfo->name, sDynListCurObj->type); 1361 } 1362 } 1363 1364 /** 1365 * Set the current active dynamic object to object `name`. 1366 */ 1367 struct GdObj *d_use_obj(DynObjName name) { 1368 struct DynObjInfo *info = get_dynobj_info(name); 1369 if (info == NULL) { 1370 fatal_printf("dUseObj(\"%s\"): Undefined object", DynNameAsStr(name)); 1371 } 1372 1373 sDynListCurObj = info->obj; 1374 sDynListCurInfo = info; 1375 1376 return info->obj; 1377 } 1378 1379 /** 1380 * Set the current active dynamic object to `obj`. This object can 1381 * any type of `GdObj`, not just an object created through the 1382 * dynmaic object system. 1383 */ 1384 void set_cur_dynobj(struct GdObj *obj) { 1385 sDynListCurObj = obj; 1386 sDynListCurInfo = &sNullDynObjInfo; 1387 } 1388 1389 /** 1390 * Start a dynamic `ObjGroup` identified with `name`. 1391 */ 1392 void d_start_group(DynObjName name) { 1393 d_makeobj(D_GROUP, name); 1394 } 1395 1396 /** 1397 * Add all dynamic objects created between the start of dynamic `ObjGroup` `name` 1398 * and this call. 1399 */ 1400 void d_end_group(DynObjName name) { 1401 UNUSED u8 filler[4]; 1402 struct DynObjInfo *info = get_dynobj_info(name); 1403 struct ObjGroup *dynGrp; 1404 s32 i; 1405 1406 if (info == NULL) { 1407 fatal_printf("dEndGroup(\"%s\"): Undefined group", DynNameAsStr(name)); 1408 } 1409 1410 dynGrp = (struct ObjGroup *) info->obj; 1411 for (i = info->num + 1; i < sLoadedDynObjs; i++) { 1412 if (sGdDynObjList[i].obj->type != OBJ_TYPE_GROUPS) { 1413 addto_group(dynGrp, sGdDynObjList[i].obj); 1414 } 1415 } 1416 } 1417 1418 /** 1419 * Add the current dynamic object to the dynamic `ObjGroup` `name`. 1420 */ 1421 void d_addto_group(DynObjName name) { 1422 UNUSED u8 filler[4]; 1423 struct DynObjInfo *info = get_dynobj_info(name); 1424 struct ObjGroup *targetGrp; 1425 1426 if (info == NULL) { 1427 fatal_printf("dAddToGroup(\"%s\"): Undefined group", DynNameAsStr(name)); 1428 } 1429 1430 targetGrp = (struct ObjGroup *) info->obj; 1431 addto_group(targetGrp, sDynListCurObj); 1432 } 1433 1434 /** 1435 * Set if `DynObjName` should be treated as integer values, 1436 * or as `char *` string pointers. 1437 * 1438 * @param isIntBool `TRUE` to interpret ids as integers 1439 */ 1440 void d_use_integer_names(s32 isIntBool) { 1441 sUseIntegerNames = isIntBool; 1442 } 1443 1444 /** 1445 * Set the initial position of the current dynamic object 1446 * to `(x, y, z)`. 1447 */ 1448 void d_set_init_pos(f32 x, f32 y, f32 z) { 1449 UNUSED u8 filler1[12]; 1450 struct GdObj *dynobj = sDynListCurObj; // sp28 1451 UNUSED u8 filler2[4]; 1452 1453 if (sDynListCurObj == NULL) { 1454 fatal_printf("proc_dynlist(): No current object"); 1455 } 1456 1457 switch (sDynListCurObj->type) { 1458 case OBJ_TYPE_JOINTS: 1459 ((struct ObjJoint *) dynobj)->worldPos.x = x; 1460 ((struct ObjJoint *) dynobj)->worldPos.y = y; 1461 ((struct ObjJoint *) dynobj)->worldPos.z = z; 1462 1463 ((struct ObjJoint *) dynobj)->unk3C.x = x; 1464 ((struct ObjJoint *) dynobj)->unk3C.y = y; 1465 ((struct ObjJoint *) dynobj)->unk3C.z = z; 1466 1467 ((struct ObjJoint *) dynobj)->initPos.x = x; 1468 ((struct ObjJoint *) dynobj)->initPos.y = y; 1469 ((struct ObjJoint *) dynobj)->initPos.z = z; 1470 break; 1471 case OBJ_TYPE_NETS: 1472 ((struct ObjNet *) dynobj)->worldPos.x = x; 1473 ((struct ObjNet *) dynobj)->worldPos.y = y; 1474 ((struct ObjNet *) dynobj)->worldPos.z = z; 1475 1476 ((struct ObjNet *) dynobj)->initPos.x = x; 1477 ((struct ObjNet *) dynobj)->initPos.y = y; 1478 ((struct ObjNet *) dynobj)->initPos.z = z; 1479 break; 1480 case OBJ_TYPE_PARTICLES: 1481 ((struct ObjParticle *) dynobj)->pos.x = x; 1482 ((struct ObjParticle *) dynobj)->pos.y = y; 1483 ((struct ObjParticle *) dynobj)->pos.z = z; 1484 break; 1485 case OBJ_TYPE_CAMERAS: 1486 ((struct ObjCamera *) dynobj)->worldPos.x = x; 1487 ((struct ObjCamera *) dynobj)->worldPos.y = y; 1488 ((struct ObjCamera *) dynobj)->worldPos.z = z; 1489 break; 1490 case OBJ_TYPE_VERTICES: 1491 d_set_rel_pos(x, y, z); 1492 1493 ((struct ObjVertex *) dynobj)->initPos.x = x; 1494 ((struct ObjVertex *) dynobj)->initPos.y = y; 1495 ((struct ObjVertex *) dynobj)->initPos.z = z; 1496 break; 1497 default: 1498 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetInitPos()", 1499 sDynListCurInfo->name, sDynListCurObj->type); 1500 } 1501 } 1502 1503 /** 1504 * Set the velocity of the current active dynamic object. The 1505 * values of the input `GdVec3f` are copied into the object. 1506 */ 1507 void d_set_velocity(const struct GdVec3f *vel) { 1508 struct GdObj *dynobj = sDynListCurObj; 1509 1510 if (sDynListCurObj == NULL) { 1511 fatal_printf("proc_dynlist(): No current object"); 1512 } 1513 1514 switch (sDynListCurObj->type) { 1515 case OBJ_TYPE_JOINTS: 1516 ((struct ObjJoint *) dynobj)->velocity.x = vel->x; 1517 ((struct ObjJoint *) dynobj)->velocity.y = vel->y; 1518 ((struct ObjJoint *) dynobj)->velocity.z = vel->z; 1519 break; 1520 case OBJ_TYPE_NETS: 1521 ((struct ObjNet *) dynobj)->velocity.x = vel->x; 1522 ((struct ObjNet *) dynobj)->velocity.y = vel->y; 1523 ((struct ObjNet *) dynobj)->velocity.z = vel->z; 1524 break; 1525 default: 1526 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetVelocity()", 1527 sDynListCurInfo->name, sDynListCurObj->type); 1528 } 1529 } 1530 1531 /** 1532 * Read the velocity value of the current dynamic object into `dst` 1533 * 1534 * @param[out] dst values are copied to this `GdVec3f` 1535 */ 1536 void d_get_velocity(struct GdVec3f *dst) { 1537 struct GdObj *dynobj = sDynListCurObj; 1538 1539 if (sDynListCurObj == NULL) { 1540 fatal_printf("proc_dynlist(): No current object"); 1541 } 1542 1543 switch (sDynListCurObj->type) { 1544 case OBJ_TYPE_JOINTS: 1545 dst->x = ((struct ObjJoint *) dynobj)->velocity.x; 1546 dst->y = ((struct ObjJoint *) dynobj)->velocity.y; 1547 dst->z = ((struct ObjJoint *) dynobj)->velocity.z; 1548 break; 1549 case OBJ_TYPE_NETS: 1550 dst->x = ((struct ObjNet *) dynobj)->velocity.x; 1551 dst->y = ((struct ObjNet *) dynobj)->velocity.y; 1552 dst->z = ((struct ObjNet *) dynobj)->velocity.z; 1553 break; 1554 default: 1555 dst->x = dst->y = dst->z = 0.0f; 1556 break; 1557 } 1558 } 1559 1560 /** 1561 * Set the torque vectore for the current dynamic object. 1562 * Values from input `GdVec3f` are copied into the object. 1563 * 1564 * @note Not called 1565 */ 1566 void d_set_torque(const struct GdVec3f *src) { 1567 struct GdObj *dynobj = sDynListCurObj; 1568 1569 if (sDynListCurObj == NULL) { 1570 fatal_printf("proc_dynlist(): No current object"); 1571 } 1572 1573 switch (sDynListCurObj->type) { 1574 case OBJ_TYPE_NETS: 1575 ((struct ObjNet *) dynobj)->torque.x = src->x; 1576 ((struct ObjNet *) dynobj)->torque.y = src->y; 1577 ((struct ObjNet *) dynobj)->torque.z = src->z; 1578 break; 1579 default: 1580 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetTorque()", 1581 sDynListCurInfo->name, sDynListCurObj->type); 1582 } 1583 } 1584 1585 /** 1586 * Get the initial position of the current dynamic object and 1587 * store in `dst`. 1588 */ 1589 void d_get_init_pos(struct GdVec3f *dst) { 1590 struct GdObj *dynobj = sDynListCurObj; 1591 1592 if (sDynListCurObj == NULL) { 1593 fatal_printf("proc_dynlist(): No current object"); 1594 } 1595 1596 switch (sDynListCurObj->type) { 1597 case OBJ_TYPE_JOINTS: 1598 dst->x = ((struct ObjJoint *) dynobj)->initPos.x; 1599 dst->y = ((struct ObjJoint *) dynobj)->initPos.y; 1600 dst->z = ((struct ObjJoint *) dynobj)->initPos.z; 1601 break; 1602 case OBJ_TYPE_NETS: 1603 dst->x = ((struct ObjNet *) dynobj)->initPos.x; 1604 dst->y = ((struct ObjNet *) dynobj)->initPos.y; 1605 dst->z = ((struct ObjNet *) dynobj)->initPos.z; 1606 break; 1607 case OBJ_TYPE_VERTICES: 1608 dst->x = ((struct ObjVertex *) dynobj)->initPos.x; 1609 dst->y = ((struct ObjVertex *) dynobj)->initPos.y; 1610 dst->z = ((struct ObjVertex *) dynobj)->initPos.z; 1611 break; 1612 default: 1613 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dGetInitPos()", 1614 sDynListCurInfo->name, sDynListCurObj->type); 1615 } 1616 } 1617 1618 /** 1619 * Get the initial rotation of the current dynamic object and 1620 * store in `dst`. 1621 */ 1622 void d_get_init_rot(struct GdVec3f *dst) { 1623 struct GdObj *dynobj = sDynListCurObj; 1624 1625 if (sDynListCurObj == NULL) { 1626 fatal_printf("proc_dynlist(): No current object"); 1627 } 1628 1629 switch (sDynListCurObj->type) { 1630 case OBJ_TYPE_JOINTS: 1631 dst->x = ((struct ObjJoint *) dynobj)->unk6C.x; 1632 dst->y = ((struct ObjJoint *) dynobj)->unk6C.y; 1633 dst->z = ((struct ObjJoint *) dynobj)->unk6C.z; 1634 break; 1635 case OBJ_TYPE_NETS: 1636 dst->x = ((struct ObjNet *) dynobj)->unk68.x; 1637 dst->y = ((struct ObjNet *) dynobj)->unk68.y; 1638 dst->z = ((struct ObjNet *) dynobj)->unk68.z; 1639 break; 1640 case OBJ_TYPE_LIGHTS: 1641 dst->x = dst->y = dst->z = 0.0f; 1642 break; 1643 default: 1644 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dGetInitRot()", 1645 sDynListCurInfo->name, sDynListCurObj->type); 1646 } 1647 } 1648 1649 /** 1650 * Set the position of the current dynamic object. 1651 * 1652 * @note This function automatically adjusts the three zoom levels 1653 * for an `ObjCamera`. 1654 */ 1655 void d_set_rel_pos(f32 x, f32 y, f32 z) { 1656 struct GdObj *dynobj = sDynListCurObj; // sp34 1657 UNUSED struct GdVec3f unusedVec; // sp28 1658 1659 if (sDynListCurObj == NULL) { 1660 fatal_printf("proc_dynlist(): No current object"); 1661 } 1662 1663 switch (sDynListCurObj->type) { 1664 case OBJ_TYPE_JOINTS: 1665 ((struct ObjJoint *) dynobj)->unk3C.x = x; 1666 ((struct ObjJoint *) dynobj)->unk3C.y = y; 1667 ((struct ObjJoint *) dynobj)->unk3C.z = z; 1668 break; 1669 case OBJ_TYPE_CAMERAS: 1670 unusedVec.x = x; 1671 unusedVec.y = y; 1672 unusedVec.z = z; 1673 1674 ((struct ObjCamera *) dynobj)->unk40.x = x; 1675 ((struct ObjCamera *) dynobj)->unk40.y = y; 1676 ((struct ObjCamera *) dynobj)->unk40.z = z; 1677 1678 ((struct ObjCamera *) dynobj)->zoomPositions[0].x = x; 1679 ((struct ObjCamera *) dynobj)->zoomPositions[0].y = y; 1680 ((struct ObjCamera *) dynobj)->zoomPositions[0].z = z; 1681 1682 ((struct ObjCamera *) dynobj)->zoomPositions[1].x = x * 1.5; //? 1.5f 1683 ((struct ObjCamera *) dynobj)->zoomPositions[1].y = y * 1.5; //? 1.5f 1684 ((struct ObjCamera *) dynobj)->zoomPositions[1].z = z * 1.5; //? 1.5f 1685 1686 ((struct ObjCamera *) dynobj)->zoomPositions[2].x = x * 2.0f; 1687 ((struct ObjCamera *) dynobj)->zoomPositions[2].y = y * 2.0f; 1688 ((struct ObjCamera *) dynobj)->zoomPositions[2].z = z * 2.0f; 1689 1690 ((struct ObjCamera *) dynobj)->maxZoomLevel = 2; 1691 break; 1692 case OBJ_TYPE_VERTICES: 1693 ((struct ObjVertex *) dynobj)->pos.x = x; 1694 ((struct ObjVertex *) dynobj)->pos.y = y; 1695 ((struct ObjVertex *) dynobj)->pos.z = z; 1696 break; 1697 case OBJ_TYPE_LABELS: 1698 ((struct ObjLabel *) dynobj)->position.x = x; 1699 ((struct ObjLabel *) dynobj)->position.y = y; 1700 ((struct ObjLabel *) dynobj)->position.z = z; 1701 break; 1702 case OBJ_TYPE_PARTICLES: 1703 ((struct ObjParticle *) dynobj)->pos.x = x; 1704 ((struct ObjParticle *) dynobj)->pos.y = y; 1705 ((struct ObjParticle *) dynobj)->pos.z = z; 1706 break; 1707 case OBJ_TYPE_NETS: 1708 break; 1709 default: 1710 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetRelPos()", 1711 sDynListCurInfo->name, sDynListCurObj->type); 1712 } 1713 } 1714 1715 /** 1716 * Offset the current position of the current dynamic object. 1717 */ 1718 void d_addto_rel_pos(struct GdVec3f *src) { 1719 struct GdObj *dynobj = sDynListCurObj; // sp24 1720 1721 if (sDynListCurObj == NULL) { 1722 fatal_printf("proc_dynlist(): No current object"); 1723 } 1724 1725 switch (sDynListCurObj->type) { 1726 case OBJ_TYPE_VERTICES: 1727 ((struct ObjVertex *) dynobj)->pos.x += src->x; 1728 ((struct ObjVertex *) dynobj)->pos.y += src->y; 1729 ((struct ObjVertex *) dynobj)->pos.z += src->z; 1730 break; 1731 case OBJ_TYPE_JOINTS: 1732 ((struct ObjJoint *) dynobj)->unk3C.x += src->x; 1733 ((struct ObjJoint *) dynobj)->unk3C.y += src->y; 1734 ((struct ObjJoint *) dynobj)->unk3C.z += src->z; 1735 break; 1736 case OBJ_TYPE_PARTICLES: 1737 ((struct ObjParticle *) dynobj)->pos.x += src->x; 1738 ((struct ObjParticle *) dynobj)->pos.y += src->y; 1739 ((struct ObjParticle *) dynobj)->pos.z += src->z; 1740 break; 1741 default: 1742 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dAddToRelPos()", 1743 sDynListCurInfo->name, sDynListCurObj->type); 1744 } 1745 } 1746 1747 /** 1748 * Store the current dynamic object's position into `dst`. 1749 */ 1750 void d_get_rel_pos(struct GdVec3f *dst) { 1751 if (sDynListCurObj == NULL) { 1752 fatal_printf("proc_dynlist(): No current object"); 1753 } 1754 1755 switch (sDynListCurObj->type) { 1756 case OBJ_TYPE_VERTICES: 1757 dst->x = ((struct ObjVertex *) sDynListCurObj)->pos.x; 1758 dst->y = ((struct ObjVertex *) sDynListCurObj)->pos.y; 1759 dst->z = ((struct ObjVertex *) sDynListCurObj)->pos.z; 1760 break; 1761 case OBJ_TYPE_JOINTS: 1762 dst->x = ((struct ObjJoint *) sDynListCurObj)->unk3C.x; 1763 dst->y = ((struct ObjJoint *) sDynListCurObj)->unk3C.y; 1764 dst->z = ((struct ObjJoint *) sDynListCurObj)->unk3C.z; 1765 break; 1766 case OBJ_TYPE_CAMERAS: 1767 dst->x = ((struct ObjCamera *) sDynListCurObj)->unk40.x; 1768 dst->y = ((struct ObjCamera *) sDynListCurObj)->unk40.y; 1769 dst->z = ((struct ObjCamera *) sDynListCurObj)->unk40.z; 1770 break; 1771 case OBJ_TYPE_PARTICLES: 1772 dst->x = ((struct ObjParticle *) sDynListCurObj)->pos.x; 1773 dst->y = ((struct ObjParticle *) sDynListCurObj)->pos.y; 1774 dst->z = ((struct ObjParticle *) sDynListCurObj)->pos.z; 1775 break; 1776 default: 1777 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dGetRelPos()", 1778 sDynListCurInfo->name, sDynListCurObj->type); 1779 } 1780 } 1781 1782 /** 1783 * Return a pointer to the attached object group of the current 1784 * dynamic object. 1785 */ 1786 struct ObjGroup *d_get_att_objgroup(void) { 1787 if (sDynListCurObj == NULL) { 1788 fatal_printf("proc_dynlist(): No current object"); 1789 } 1790 1791 switch (sDynListCurObj->type) { 1792 case OBJ_TYPE_JOINTS: 1793 return ((struct ObjJoint *) sDynListCurObj)->attachedObjsGrp; 1794 break; // lol 1795 case OBJ_TYPE_NETS: 1796 return ((struct ObjNet *) sDynListCurObj)->attachedObjsGrp; 1797 break; // lol 1798 default: 1799 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dGetAttObjGroup()", 1800 sDynListCurInfo->name, sDynListCurObj->type); 1801 } 1802 // No null return due to `fatal_printf()` being a non-returning function? 1803 } 1804 1805 /** 1806 * Return a pointer to the object that the current dynamic object is attached to. 1807 */ 1808 struct GdObj *d_get_att_to_obj(void) { 1809 if (sDynListCurObj == NULL) { 1810 fatal_printf("proc_dynlist(): No current object"); 1811 } 1812 1813 switch (sDynListCurObj->type) { 1814 case OBJ_TYPE_JOINTS: 1815 return ((struct ObjJoint *) sDynListCurObj)->attachedToObj; 1816 break; // lol 1817 case OBJ_TYPE_NETS: 1818 return ((struct ObjNet *) sDynListCurObj)->attachedToObj; 1819 break; // lol 1820 default: 1821 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dGetAttToObj()", 1822 sDynListCurInfo->name, sDynListCurObj->type); 1823 } 1824 // No null return due to `fatal_printf()` being a non-returning function? 1825 } 1826 1827 /** 1828 * Store the current dynamic object's scale into `dst`. 1829 */ 1830 void d_get_scale(struct GdVec3f *dst) { 1831 struct GdObj *dynobj; // sp24 1832 1833 if (sDynListCurObj == NULL) { 1834 fatal_printf("proc_dynlist(): No current object"); 1835 } 1836 1837 dynobj = sDynListCurObj; 1838 switch (sDynListCurObj->type) { 1839 case OBJ_TYPE_JOINTS: 1840 dst->x = ((struct ObjJoint *) dynobj)->scale.x; 1841 dst->y = ((struct ObjJoint *) dynobj)->scale.y; 1842 dst->z = ((struct ObjJoint *) dynobj)->scale.z; 1843 break; 1844 case OBJ_TYPE_NETS: 1845 dst->x = ((struct ObjNet *) dynobj)->scale.x; 1846 dst->y = ((struct ObjNet *) dynobj)->scale.y; 1847 dst->z = ((struct ObjNet *) dynobj)->scale.z; 1848 break; 1849 case OBJ_TYPE_LIGHTS: 1850 dst->x = 1.0f; 1851 dst->y = 1.0f; 1852 dst->z = 1.0f; 1853 break; 1854 default: 1855 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dGetScale()", 1856 sDynListCurInfo->name, sDynListCurObj->type); 1857 } 1858 } 1859 1860 /** 1861 * Set the offset of the attached object on the current dynamic object. 1862 */ 1863 void d_set_att_offset(const struct GdVec3f *off) { 1864 struct GdObj *dynobj; // sp24 1865 1866 if (sDynListCurObj == NULL) { 1867 fatal_printf("proc_dynlist(): No current object"); 1868 } 1869 1870 dynobj = sDynListCurObj; 1871 switch (sDynListCurObj->type) { 1872 case OBJ_TYPE_JOINTS: 1873 ((struct ObjJoint *) dynobj)->attachOffset.x = off->x; 1874 ((struct ObjJoint *) dynobj)->attachOffset.y = off->y; 1875 ((struct ObjJoint *) dynobj)->attachOffset.z = off->z; 1876 1877 ((struct ObjJoint *) dynobj)->initPos.x = off->x; 1878 ((struct ObjJoint *) dynobj)->initPos.y = off->y; 1879 ((struct ObjJoint *) dynobj)->initPos.z = off->z; 1880 break; 1881 case OBJ_TYPE_NETS: 1882 ((struct ObjNet *) dynobj)->attachOffset.x = off->x; 1883 ((struct ObjNet *) dynobj)->attachOffset.y = off->y; 1884 ((struct ObjNet *) dynobj)->attachOffset.z = off->z; 1885 1886 ((struct ObjNet *) dynobj)->initPos.x = off->x; 1887 ((struct ObjNet *) dynobj)->initPos.y = off->y; 1888 ((struct ObjNet *) dynobj)->initPos.z = off->z; 1889 break; 1890 case OBJ_TYPE_PARTICLES: 1891 break; 1892 default: 1893 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetAttOffset()", 1894 sDynListCurInfo->name, sDynListCurObj->type); 1895 } 1896 } 1897 1898 /** 1899 * An incorrectly-coded recursive function that was presumably supposed to 1900 * set the offset of an attached object. Now, it will only call itself 1901 * until it encounters a NULL pointer, which will trigger a `fatal_printf()` 1902 * call. 1903 * 1904 * @note Not called 1905 */ 1906 void d_set_att_to_offset(UNUSED u32 a) { 1907 struct GdObj *dynobj; // sp3c 1908 UNUSED u8 filler[24]; 1909 1910 if (sDynListCurObj == NULL) { 1911 fatal_printf("proc_dynlist(): No current object"); 1912 } 1913 1914 dynobj = sDynListCurObj; 1915 d_stash_dynobj(); 1916 switch (sDynListCurObj->type) { 1917 case OBJ_TYPE_JOINTS: 1918 set_cur_dynobj(((struct ObjJoint *) dynobj)->attachedToObj); 1919 break; 1920 case OBJ_TYPE_NETS: 1921 set_cur_dynobj(((struct ObjNet *) dynobj)->attachedToObj); 1922 break; 1923 case OBJ_TYPE_PARTICLES: 1924 set_cur_dynobj(((struct ObjParticle *) dynobj)->attachedToObj); 1925 break; 1926 default: 1927 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetAttToOffset()", 1928 sDynListCurInfo->name, sDynListCurObj->type); 1929 } 1930 1931 if (sDynListCurObj == NULL) { 1932 fatal_printf("dSetAttOffset(): Object '%s' isnt attached to anything", 1933 sStashedDynObjInfo->name); 1934 } 1935 d_set_att_to_offset(a); 1936 d_unstash_dynobj(); 1937 } 1938 1939 /** 1940 * Store the offset of the attached object into `dst`. 1941 * 1942 * @note Not called 1943 */ 1944 void d_get_att_offset(struct GdVec3f *dst) { 1945 if (sDynListCurObj == NULL) { 1946 fatal_printf("proc_dynlist(): No current object"); 1947 } 1948 1949 switch (sDynListCurObj->type) { 1950 case OBJ_TYPE_JOINTS: 1951 dst->x = ((struct ObjJoint *) sDynListCurObj)->attachOffset.x; 1952 dst->y = ((struct ObjJoint *) sDynListCurObj)->attachOffset.y; 1953 dst->z = ((struct ObjJoint *) sDynListCurObj)->attachOffset.z; 1954 break; 1955 case OBJ_TYPE_NETS: 1956 dst->x = ((struct ObjNet *) sDynListCurObj)->attachOffset.x; 1957 dst->y = ((struct ObjNet *) sDynListCurObj)->attachOffset.y; 1958 dst->z = ((struct ObjNet *) sDynListCurObj)->attachOffset.z; 1959 break; 1960 case OBJ_TYPE_PARTICLES: 1961 break; 1962 default: 1963 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dGetAttOffset()", 1964 sDynListCurInfo->name, sDynListCurObj->type); 1965 } 1966 } 1967 1968 /** 1969 * Get the attached object flags for the current dynamic object. 1970 */ 1971 s32 d_get_att_flags(void) { 1972 s32 attflag; // sp24 1973 1974 if (sDynListCurObj == NULL) { 1975 fatal_printf("proc_dynlist(): No current object"); 1976 } 1977 1978 switch (sDynListCurObj->type) { 1979 case OBJ_TYPE_JOINTS: 1980 attflag = ((struct ObjJoint *) sDynListCurObj)->attachFlags; 1981 break; 1982 case OBJ_TYPE_NETS: 1983 attflag = ((struct ObjNet *) sDynListCurObj)->attachFlags; 1984 break; 1985 case OBJ_TYPE_PARTICLES: 1986 attflag = ((struct ObjParticle *) sDynListCurObj)->attachFlags; 1987 break; 1988 default: 1989 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dGetAttFlags()", 1990 sDynListCurInfo->name, sDynListCurObj->type); 1991 } 1992 1993 return attflag; 1994 } 1995 1996 /** 1997 * Set the world position of the current dynamic object. 1998 * 1999 * @note Sets the upper left coordinates of an `ObjView` 2000 */ 2001 void d_set_world_pos(f32 x, f32 y, f32 z) { 2002 if (sDynListCurObj == NULL) { 2003 fatal_printf("proc_dynlist(): No current object"); 2004 } 2005 2006 switch (sDynListCurObj->type) { 2007 case OBJ_TYPE_CAMERAS: 2008 ((struct ObjCamera *) sDynListCurObj)->worldPos.x = x; 2009 ((struct ObjCamera *) sDynListCurObj)->worldPos.y = y; 2010 ((struct ObjCamera *) sDynListCurObj)->worldPos.z = z; 2011 break; 2012 case OBJ_TYPE_JOINTS: 2013 ((struct ObjJoint *) sDynListCurObj)->worldPos.x = x; 2014 ((struct ObjJoint *) sDynListCurObj)->worldPos.y = y; 2015 ((struct ObjJoint *) sDynListCurObj)->worldPos.z = z; 2016 break; 2017 case OBJ_TYPE_NETS: 2018 ((struct ObjNet *) sDynListCurObj)->worldPos.x = x; 2019 ((struct ObjNet *) sDynListCurObj)->worldPos.y = y; 2020 ((struct ObjNet *) sDynListCurObj)->worldPos.z = z; 2021 break; 2022 case OBJ_TYPE_GADGETS: 2023 ((struct ObjGadget *) sDynListCurObj)->worldPos.x = x; 2024 ((struct ObjGadget *) sDynListCurObj)->worldPos.y = y; 2025 ((struct ObjGadget *) sDynListCurObj)->worldPos.z = z; 2026 break; 2027 case OBJ_TYPE_VIEWS: 2028 ((struct ObjView *) sDynListCurObj)->upperLeft.x = x; 2029 ((struct ObjView *) sDynListCurObj)->upperLeft.y = y; 2030 ((struct ObjView *) sDynListCurObj)->upperLeft.z = z; 2031 break; 2032 case OBJ_TYPE_VERTICES: 2033 ((struct ObjVertex *) sDynListCurObj)->pos.x = x; 2034 ((struct ObjVertex *) sDynListCurObj)->pos.y = y; 2035 ((struct ObjVertex *) sDynListCurObj)->pos.z = z; 2036 break; 2037 default: 2038 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetWorldPos()", 2039 sDynListCurInfo->name, sDynListCurObj->type); 2040 } 2041 } 2042 2043 /** 2044 * Set the normal of the current dynamic `ObjVertex`. The input `x, y, z` values 2045 * are normalized into a unit vector before setting the vertex normal. 2046 */ 2047 void d_set_normal(f32 x, f32 y, f32 z) { 2048 struct GdVec3f normal; // sp1C 2049 2050 if (sDynListCurObj == NULL) { 2051 fatal_printf("proc_dynlist(): No current object"); 2052 } 2053 2054 normal.x = x; 2055 normal.y = y; 2056 normal.z = z; 2057 gd_normalize_vec3f(&normal); 2058 2059 switch (sDynListCurObj->type) { 2060 case OBJ_TYPE_VERTICES: 2061 ((struct ObjVertex *) sDynListCurObj)->normal.x = normal.x; 2062 ((struct ObjVertex *) sDynListCurObj)->normal.y = normal.y; 2063 ((struct ObjVertex *) sDynListCurObj)->normal.z = normal.z; 2064 break; 2065 default: 2066 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetNormal()", 2067 sDynListCurInfo->name, sDynListCurObj->type); 2068 } 2069 } 2070 2071 /** 2072 * Get a pointer to the world position vector of the active 2073 * dynamic object. This is a pointer inside the actual object. 2074 * 2075 * @note Not called. 2076 */ 2077 struct GdVec3f *d_get_world_pos_ptr(void) { 2078 if (sDynListCurObj == NULL) { 2079 fatal_printf("proc_dynlist(): No current object"); 2080 } 2081 2082 switch (sDynListCurObj->type) { 2083 case OBJ_TYPE_VERTICES: 2084 return &((struct ObjVertex *) sDynListCurObj)->pos; 2085 break; 2086 case OBJ_TYPE_PARTICLES: 2087 return &((struct ObjParticle *) sDynListCurObj)->pos; 2088 break; 2089 default: 2090 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dGetWorldPosPtr()", 2091 sDynListCurInfo->name, sDynListCurObj->type); 2092 } 2093 // No null return due to `fatal_printf()` being a non-returning function? 2094 } 2095 2096 /** 2097 * Copy the world position of the current dynamic object into `dst`. 2098 */ 2099 void d_get_world_pos(struct GdVec3f *dst) { 2100 if (sDynListCurObj == NULL) { 2101 fatal_printf("proc_dynlist(): No current object"); 2102 } 2103 2104 switch (sDynListCurObj->type) { 2105 case OBJ_TYPE_VERTICES: 2106 dst->x = ((struct ObjVertex *) sDynListCurObj)->pos.x; 2107 dst->y = ((struct ObjVertex *) sDynListCurObj)->pos.y; 2108 dst->z = ((struct ObjVertex *) sDynListCurObj)->pos.z; 2109 break; 2110 case OBJ_TYPE_JOINTS: 2111 dst->x = ((struct ObjJoint *) sDynListCurObj)->worldPos.x; 2112 dst->y = ((struct ObjJoint *) sDynListCurObj)->worldPos.y; 2113 dst->z = ((struct ObjJoint *) sDynListCurObj)->worldPos.z; 2114 break; 2115 case OBJ_TYPE_NETS: 2116 dst->x = ((struct ObjNet *) sDynListCurObj)->worldPos.x; 2117 dst->y = ((struct ObjNet *) sDynListCurObj)->worldPos.y; 2118 dst->z = ((struct ObjNet *) sDynListCurObj)->worldPos.z; 2119 break; 2120 case OBJ_TYPE_PARTICLES: 2121 dst->x = ((struct ObjParticle *) sDynListCurObj)->pos.x; 2122 dst->y = ((struct ObjParticle *) sDynListCurObj)->pos.y; 2123 dst->z = ((struct ObjParticle *) sDynListCurObj)->pos.z; 2124 break; 2125 case OBJ_TYPE_CAMERAS: 2126 dst->x = ((struct ObjCamera *) sDynListCurObj)->worldPos.x; 2127 dst->y = ((struct ObjCamera *) sDynListCurObj)->worldPos.y; 2128 dst->z = ((struct ObjCamera *) sDynListCurObj)->worldPos.z; 2129 break; 2130 case OBJ_TYPE_BONES: 2131 dst->x = ((struct ObjBone *) sDynListCurObj)->worldPos.x; 2132 dst->y = ((struct ObjBone *) sDynListCurObj)->worldPos.y; 2133 dst->z = ((struct ObjBone *) sDynListCurObj)->worldPos.z; 2134 break; 2135 case OBJ_TYPE_SHAPES: 2136 dst->x = dst->y = dst->z = 0.0f; 2137 break; 2138 case OBJ_TYPE_LABELS: 2139 dst->x = dst->y = dst->z = 0.0f; 2140 break; 2141 case OBJ_TYPE_GADGETS: 2142 dst->x = ((struct ObjGadget *) sDynListCurObj)->worldPos.x; 2143 dst->y = ((struct ObjGadget *) sDynListCurObj)->worldPos.y; 2144 dst->z = ((struct ObjGadget *) sDynListCurObj)->worldPos.z; 2145 break; 2146 case OBJ_TYPE_PLANES: 2147 dst->x = ((struct ObjPlane *) sDynListCurObj)->boundingBox.minX; 2148 dst->y = ((struct ObjPlane *) sDynListCurObj)->boundingBox.minY; 2149 dst->z = ((struct ObjPlane *) sDynListCurObj)->boundingBox.minZ; 2150 2151 dst->x += ((struct ObjPlane *) sDynListCurObj)->boundingBox.maxX; 2152 dst->y += ((struct ObjPlane *) sDynListCurObj)->boundingBox.maxY; 2153 dst->z += ((struct ObjPlane *) sDynListCurObj)->boundingBox.maxZ; 2154 2155 dst->x *= 0.5; //? 0.5f 2156 dst->y *= 0.5; //? 0.5f 2157 dst->z *= 0.5; //? 0.5f 2158 break; 2159 case OBJ_TYPE_ZONES: 2160 dst->x = ((struct ObjZone *) sDynListCurObj)->boundingBox.minX; 2161 dst->y = ((struct ObjZone *) sDynListCurObj)->boundingBox.minY; 2162 dst->z = ((struct ObjZone *) sDynListCurObj)->boundingBox.minZ; 2163 2164 dst->x += ((struct ObjZone *) sDynListCurObj)->boundingBox.maxX; 2165 dst->y += ((struct ObjZone *) sDynListCurObj)->boundingBox.maxY; 2166 dst->z += ((struct ObjZone *) sDynListCurObj)->boundingBox.maxZ; 2167 2168 dst->x *= 0.5; //? 0.5f 2169 dst->y *= 0.5; //? 0.5f 2170 dst->z *= 0.5; //? 0.5f 2171 break; 2172 case OBJ_TYPE_LIGHTS: 2173 dst->x = ((struct ObjLight *) sDynListCurObj)->position.x; 2174 dst->y = ((struct ObjLight *) sDynListCurObj)->position.y; 2175 dst->z = ((struct ObjLight *) sDynListCurObj)->position.z; 2176 break; 2177 default: 2178 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dGetWorldPos()", 2179 sDynListCurInfo->name, sDynListCurObj->type); 2180 } 2181 } 2182 2183 /** 2184 * Create a new dynamic `ObjVertex` at point `pos`. 2185 * 2186 * @param[in] pos values are copied to set vertex position 2187 */ 2188 void d_make_vertex(struct GdVec3f *pos) { 2189 d_makeobj(D_VERTEX, AsDynName(NULL)); 2190 d_set_init_pos(pos->x, pos->y, pos->z); 2191 } 2192 2193 /** 2194 * Scale the current dynamic object by factor `(x, y, z)`. 2195 * 2196 * @note Sets the lower right coordinates of an `ObjView` 2197 */ 2198 void d_set_scale(f32 x, f32 y, f32 z) { 2199 struct GdObj *initDynobj; 2200 2201 if (sDynListCurObj == NULL) { 2202 fatal_printf("proc_dynlist(): No current object"); 2203 } 2204 2205 initDynobj = sDynListCurObj; 2206 d_stash_dynobj(); 2207 switch (sDynListCurObj->type) { 2208 case OBJ_TYPE_JOINTS: 2209 ((struct ObjJoint *) initDynobj)->scale.x = x; 2210 ((struct ObjJoint *) initDynobj)->scale.y = y; 2211 ((struct ObjJoint *) initDynobj)->scale.z = z; 2212 break; 2213 case OBJ_TYPE_NETS: 2214 ((struct ObjNet *) initDynobj)->scale.x = x; 2215 ((struct ObjNet *) initDynobj)->scale.y = y; 2216 ((struct ObjNet *) initDynobj)->scale.z = z; 2217 break; 2218 case OBJ_TYPE_VIEWS: 2219 ((struct ObjView *) initDynobj)->lowerRight.x = x; 2220 ((struct ObjView *) initDynobj)->lowerRight.y = y; 2221 ((struct ObjView *) initDynobj)->lowerRight.z = z; 2222 break; 2223 case OBJ_TYPE_PARTICLES: 2224 break; 2225 case OBJ_TYPE_GADGETS: 2226 if (((struct ObjGadget *) initDynobj)->shapePtr != NULL) { 2227 scale_verts_in_shape(((struct ObjGadget *) initDynobj)->shapePtr, x, y, z); 2228 } 2229 ((struct ObjGadget *) initDynobj)->size.x = x; 2230 ((struct ObjGadget *) initDynobj)->size.y = y; 2231 ((struct ObjGadget *) initDynobj)->size.z = z; 2232 break; 2233 case OBJ_TYPE_LIGHTS: 2234 break; 2235 default: 2236 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetScale()", 2237 sDynListCurInfo->name, sDynListCurObj->type); 2238 } 2239 d_unstash_dynobj(); 2240 } 2241 2242 /** 2243 * Set the rotation value of the current active dynamic object. 2244 */ 2245 void d_set_rotation(f32 x, f32 y, f32 z) { 2246 struct GdObj *dynobj; // sp2C 2247 UNUSED u8 filler[4]; 2248 2249 if (sDynListCurObj == NULL) { 2250 fatal_printf("proc_dynlist(): No current object"); 2251 } 2252 2253 dynobj = sDynListCurObj; 2254 switch (sDynListCurObj->type) { 2255 case OBJ_TYPE_JOINTS: 2256 ((struct ObjJoint *) dynobj)->unk6C.x = x; 2257 ((struct ObjJoint *) dynobj)->unk6C.y = y; 2258 ((struct ObjJoint *) dynobj)->unk6C.z = z; 2259 break; 2260 case OBJ_TYPE_NETS: 2261 ((struct ObjNet *) dynobj)->unk68.x = x; 2262 ((struct ObjNet *) dynobj)->unk68.y = y; 2263 ((struct ObjNet *) dynobj)->unk68.z = z; 2264 break; 2265 default: 2266 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetRotation()", 2267 sDynListCurInfo->name, sDynListCurObj->type); 2268 } 2269 } 2270 2271 /** 2272 * Set the center of gravity of the current dynamic `ObjNet`. 2273 */ 2274 void d_center_of_gravity(f32 x, f32 y, f32 z) { 2275 if (sDynListCurObj == NULL) { 2276 fatal_printf("proc_dynlist(): No current object"); 2277 } 2278 2279 switch (sDynListCurObj->type) { 2280 case OBJ_TYPE_NETS: 2281 ((struct ObjNet *) sDynListCurObj)->centerOfGravity.x = x; 2282 ((struct ObjNet *) sDynListCurObj)->centerOfGravity.y = y; 2283 ((struct ObjNet *) sDynListCurObj)->centerOfGravity.z = z; 2284 break; 2285 default: 2286 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dCofG()", 2287 sDynListCurInfo->name, sDynListCurObj->type); 2288 } 2289 } 2290 2291 /** 2292 * Set the shape offset of the current dynamic `ObjJoint`. 2293 */ 2294 void d_set_shape_offset(f32 x, f32 y, f32 z) { 2295 if (sDynListCurObj == NULL) { 2296 fatal_printf("proc_dynlist(): No current object"); 2297 } 2298 2299 switch (sDynListCurObj->type) { 2300 case OBJ_TYPE_JOINTS: 2301 ((struct ObjJoint *) sDynListCurObj)->shapeOffset.x = x; 2302 ((struct ObjJoint *) sDynListCurObj)->shapeOffset.y = y; 2303 ((struct ObjJoint *) sDynListCurObj)->shapeOffset.z = z; 2304 break; 2305 default: 2306 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dShapeOffset()", 2307 sDynListCurInfo->name, sDynListCurObj->type); 2308 } 2309 } 2310 2311 /** 2312 * Creates a new `ObjValPtr`. 2313 * If `vflags` is 0x40000, then `name` is the name of an object, and `offset` 2314 * is an offset to a field in that object. Otherwise, `offset` specifies a 2315 * the address of a standalone variable. 2316 */ 2317 void d_add_valptr(DynObjName name, u32 vflags, enum ValPtrType type, size_t offset) { 2318 struct GdObj *dynobj; 2319 struct ObjValPtr *valptr; 2320 struct DynObjInfo *info; 2321 2322 if (sDynListCurObj == NULL) { 2323 fatal_printf("proc_dynlist(): No current object"); 2324 } 2325 2326 dynobj = sDynListCurObj; 2327 2328 if (vflags == 0x40000) { 2329 // value is an object field, and objId is the name of the object 2330 info = get_dynobj_info(name); 2331 if (info == NULL) { 2332 fatal_printf("dAddValPtr(\"%s\"): Undefined object", DynNameAsStr(name)); 2333 } 2334 2335 valptr = make_valptr(info->obj, vflags, type, offset); 2336 } else { 2337 // value is a standalone variable 2338 valptr = make_valptr(name, vflags, type, offset); 2339 } 2340 2341 switch (sDynListCurObj->type) { 2342 case OBJ_TYPE_GADGETS: 2343 if (((struct ObjGadget *) dynobj)->valueGrp == NULL) { 2344 ((struct ObjGadget *) dynobj)->valueGrp = make_group(0); 2345 } 2346 addto_group(((struct ObjGadget *) dynobj)->valueGrp, &valptr->header); 2347 break; 2348 case OBJ_TYPE_LABELS: 2349 ((struct ObjLabel *) dynobj)->valptr = valptr; 2350 break; 2351 default: 2352 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dAddValPtr()", 2353 sDynListCurInfo->name, sDynListCurObj->type); 2354 } 2355 } 2356 2357 /** 2358 * Add a value processing function (`valptrproc_t`) to the current 2359 * dynamic `ObjLabel`. 2360 */ 2361 void d_add_valproc(valptrproc_t proc) { 2362 struct GdObj *dynobj; 2363 2364 if (sDynListCurObj == NULL) { 2365 fatal_printf("proc_dynlist(): No current object"); 2366 } 2367 2368 dynobj = sDynListCurObj; 2369 switch (sDynListCurObj->type) { 2370 case OBJ_TYPE_LABELS: 2371 ((struct ObjLabel *) dynobj)->valfn = proc; 2372 break; 2373 default: 2374 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dAddValProc()", 2375 sDynListCurInfo->name, sDynListCurObj->type); 2376 } 2377 } 2378 2379 /** 2380 * Link a variable pointer to the current active dynamic object. 2381 * In the final game, this is used to link arrays of raw vertex, face, 2382 * or animation data to `ObjGroup`s, or to link joints to `ObjAnimator`s. 2383 */ 2384 void d_link_with_ptr(void *ptr) { 2385 struct GdObj *dynobj; // sp34 2386 struct ObjValPtr *valptr; // sp30 2387 struct ListNode *link; // sp2C 2388 2389 if (sDynListCurObj == NULL) { 2390 fatal_printf("proc_dynlist(): No current object"); 2391 } 2392 2393 dynobj = sDynListCurObj; 2394 imin("dLinkWithPtr"); 2395 switch (sDynListCurObj->type) { 2396 case OBJ_TYPE_CAMERAS: 2397 ((struct ObjCamera *) dynobj)->unk30 = ptr; 2398 break; 2399 case OBJ_TYPE_GROUPS: 2400 link = make_link_to_obj(NULL, ptr); 2401 ((struct ObjGroup *) dynobj)->firstMember = link; 2402 break; 2403 case OBJ_TYPE_BONES: 2404 add_joint2bone((struct ObjBone *) dynobj, ptr); 2405 break; 2406 case OBJ_TYPE_VIEWS: 2407 ((struct ObjView *) dynobj)->components = ptr; 2408 ((struct ObjView *) dynobj)->unk1C = 2409 setup_view_buffers(((struct ObjView *) dynobj)->namePtr, ((struct ObjView *) dynobj), 2410 (s32)((struct ObjView *) dynobj)->upperLeft.x, 2411 (s32)((struct ObjView *) dynobj)->upperLeft.y, 2412 (s32)((struct ObjView *) dynobj)->lowerRight.x, 2413 (s32)((struct ObjView *) dynobj)->lowerRight.y); 2414 reset_nets_and_gadgets(((struct ObjView *) dynobj)->components); 2415 break; 2416 case OBJ_TYPE_FACES: 2417 if (((struct ObjFace *) dynobj)->vtxCount >= 4) { 2418 fatal_printf("too many points"); 2419 } 2420 2421 ((struct ObjFace *) dynobj)->vertices[((struct ObjFace *) dynobj)->vtxCount] = ptr; 2422 ((struct ObjFace *) dynobj)->vtxCount++; 2423 2424 if (((struct ObjFace *) dynobj)->vtxCount >= 3) { 2425 calc_face_normal((struct ObjFace *) dynobj); 2426 } 2427 2428 break; 2429 case OBJ_TYPE_ANIMATORS: 2430 if (((struct ObjAnimator *) dynobj)->animatedPartsGrp == NULL) { 2431 ((struct ObjAnimator *) dynobj)->animatedPartsGrp = make_group(0); 2432 } 2433 2434 addto_group(((struct ObjAnimator *) dynobj)->animatedPartsGrp, ptr); 2435 break; 2436 case OBJ_TYPE_LABELS: 2437 valptr = make_valptr(ptr, OBJ_TYPE_ALL, 0, 0); 2438 ((struct ObjLabel *) dynobj)->valptr = valptr; 2439 break; 2440 default: 2441 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dLinkWithPtr()", 2442 sDynListCurInfo->name, sDynListCurObj->type); 2443 } 2444 imout(); 2445 } 2446 2447 /** 2448 * Link the dynamic object `name` to the current dynamic object by wrapping 2449 * `d_link_with_ptr()`. 2450 */ 2451 void d_link_with(DynObjName name) { 2452 struct DynObjInfo *info; // sp1C 2453 struct DynObjInfo *origInfo = sDynListCurInfo; // sp18 2454 2455 if (sDynListCurObj == NULL) { 2456 fatal_printf("proc_dynlist(): No current object"); 2457 } 2458 2459 if (name == NULL) { 2460 return; 2461 } 2462 2463 info = get_dynobj_info(name); 2464 if (info == NULL) { 2465 fatal_printf("dLinkWith(\"%s\"): Undefined object", DynNameAsStr(name)); 2466 } 2467 2468 d_link_with_ptr(info->obj); 2469 set_cur_dynobj(origInfo->obj); 2470 sDynListCurInfo = origInfo; 2471 } 2472 2473 /** 2474 * Set the object specific flags of the current dynamic object. 2475 */ 2476 void d_set_flags(s32 flags) { 2477 struct GdObj *dynobj; // sp24 2478 2479 if (sDynListCurObj == NULL) { 2480 fatal_printf("proc_dynlist(): No current object"); 2481 } 2482 2483 dynobj = sDynListCurObj; 2484 switch (sDynListCurObj->type) { 2485 case OBJ_TYPE_JOINTS: 2486 ((struct ObjJoint *) dynobj)->flags |= flags; 2487 break; 2488 case OBJ_TYPE_BONES: 2489 ((struct ObjBone *) dynobj)->unk104 |= flags; 2490 break; 2491 case OBJ_TYPE_NETS: 2492 ((struct ObjNet *) dynobj)->flags |= flags; 2493 break; 2494 case OBJ_TYPE_CAMERAS: 2495 ((struct ObjCamera *) dynobj)->flags |= flags; 2496 break; 2497 case OBJ_TYPE_VIEWS: 2498 ((struct ObjView *) dynobj)->flags |= flags; 2499 break; 2500 case OBJ_TYPE_SHAPES: 2501 ((struct ObjShape *) dynobj)->flag |= flags; 2502 break; 2503 case OBJ_TYPE_PARTICLES: 2504 ((struct ObjParticle *) dynobj)->flags |= flags; 2505 break; 2506 case OBJ_TYPE_LIGHTS: 2507 ((struct ObjLight *) dynobj)->flags |= flags; 2508 break; 2509 default: 2510 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetFlags()", 2511 sDynListCurInfo->name, sDynListCurObj->type); 2512 } 2513 } 2514 2515 /** 2516 * Clear object specific flags from the current dynamic object. 2517 */ 2518 void d_clear_flags(s32 flags) { 2519 if (sDynListCurObj == NULL) { 2520 fatal_printf("proc_dynlist(): No current object"); 2521 } 2522 2523 switch (sDynListCurObj->type) { 2524 case OBJ_TYPE_JOINTS: 2525 ((struct ObjJoint *) sDynListCurObj)->flags &= ~flags; 2526 break; 2527 case OBJ_TYPE_BONES: 2528 ((struct ObjBone *) sDynListCurObj)->unk104 &= ~flags; 2529 break; 2530 case OBJ_TYPE_NETS: 2531 ((struct ObjNet *) sDynListCurObj)->flags &= ~flags; 2532 break; 2533 case OBJ_TYPE_CAMERAS: 2534 ((struct ObjCamera *) sDynListCurObj)->flags &= ~flags; 2535 break; 2536 case OBJ_TYPE_PARTICLES: 2537 ((struct ObjParticle *) sDynListCurObj)->flags &= ~flags; 2538 break; 2539 default: 2540 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dClrFlags()", 2541 sDynListCurInfo->name, sDynListCurObj->type); 2542 } 2543 } 2544 2545 /** 2546 * Set variable float parameters on the current dynamic object. 2547 * These are mainly used for `ObjGadget`s to set the drawing size 2548 * range. 2549 */ 2550 void d_set_parm_f(enum DParmF param, f32 val) { 2551 if (sDynListCurObj == NULL) { 2552 fatal_printf("proc_dynlist(): No current object"); 2553 } 2554 2555 switch (sDynListCurObj->type) { 2556 case OBJ_TYPE_SHAPES: 2557 switch (param) { 2558 case PARM_F_ALPHA: 2559 ((struct ObjShape *) sDynListCurObj)->alpha = val; 2560 break; 2561 default: 2562 fatal_printf("%s: Object '%s'(%x) does not support this function.", 2563 "dSetParmf() - unsupported parm.", sDynListCurInfo->name, 2564 sDynListCurObj->type); 2565 } 2566 break; 2567 case OBJ_TYPE_GADGETS: 2568 switch (param) { 2569 case PARM_F_RANGE_MIN: 2570 ((struct ObjGadget *) sDynListCurObj)->rangeMin = val; 2571 break; 2572 case PARM_F_RANGE_MAX: 2573 ((struct ObjGadget *) sDynListCurObj)->rangeMax = val; 2574 break; 2575 case PARM_F_VARVAL: 2576 ((struct ObjGadget *) sDynListCurObj)->varval.f = val; 2577 break; 2578 default: 2579 fatal_printf("%s: Object '%s'(%x) does not support this function.", 2580 "dSetParmf() - unsupported parm.", sDynListCurInfo->name, 2581 sDynListCurObj->type); 2582 } 2583 break; 2584 case OBJ_TYPE_VERTICES: 2585 switch (param) { 2586 case PARM_F_ALPHA: 2587 ((struct ObjVertex *) sDynListCurObj)->alpha = val; 2588 break; 2589 default: 2590 fatal_printf("%s: Object '%s'(%x) does not support this function.", 2591 "dSetParmf() - unsupported parm.", sDynListCurInfo->name, 2592 sDynListCurObj->type); 2593 } 2594 break; 2595 default: 2596 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetParmf()", 2597 sDynListCurInfo->name, sDynListCurObj->type); 2598 } 2599 } 2600 2601 /** 2602 * Set various pointer parameters for the current dynamic object. 2603 * Normally, this is used to set `char *` pointer for various objects, 2604 * but it can also set the vertices for an `ObjFace`. 2605 */ 2606 void d_set_parm_ptr(enum DParmPtr param, void *ptr) { 2607 if (sDynListCurObj == NULL) { 2608 fatal_printf("proc_dynlist(): No current object"); 2609 } 2610 2611 switch (sDynListCurObj->type) { 2612 case OBJ_TYPE_LABELS: 2613 switch (param) { 2614 case PARM_PTR_CHAR: 2615 ((struct ObjLabel *) sDynListCurObj)->fmtstr = ptr; 2616 break; 2617 default: 2618 fatal_printf("Bad parm"); 2619 } 2620 break; 2621 case OBJ_TYPE_VIEWS: 2622 switch (param) { 2623 case PARM_PTR_CHAR: 2624 ((struct ObjView *) sDynListCurObj)->namePtr = ptr; 2625 break; 2626 default: 2627 fatal_printf("Bad parm"); 2628 } 2629 break; 2630 case OBJ_TYPE_FACES: 2631 switch (param) { 2632 case PARM_PTR_OBJ_VTX: 2633 // Don't allow more than 4 vertices in a face 2634 if (((struct ObjFace *) sDynListCurObj)->vtxCount >= 4) { 2635 fatal_printf("dsetparmp() too many points"); 2636 } 2637 // `ptr` here is a vertex index, not an actual pointer. 2638 // These vertex indices later get converted to `ObjVertex` pointers when `find_thisface_verts` is called. 2639 ((struct ObjFace *) sDynListCurObj)->vertices[((struct ObjFace *) sDynListCurObj)->vtxCount++] = ptr; 2640 break; 2641 default: 2642 fatal_printf("Bad parm"); 2643 } 2644 break; 2645 default: 2646 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetParmp()", 2647 sDynListCurInfo->name, sDynListCurObj->type); 2648 } 2649 } 2650 2651 /** 2652 * Set the generic drawing flags for the current dynamic object. 2653 */ 2654 void d_set_obj_draw_flag(enum ObjDrawingFlags flag) { 2655 if (sDynListCurObj == NULL) { 2656 fatal_printf("proc_dynlist(): No current object"); 2657 } 2658 2659 sDynListCurObj->drawFlags |= flag; 2660 } 2661 2662 /** 2663 * Set an object specific type field for the current dynamic object. 2664 */ 2665 void d_set_type(s32 type) { 2666 struct GdObj *dynobj = sDynListCurObj; // sp24 2667 2668 if (sDynListCurObj == NULL) { 2669 fatal_printf("proc_dynlist(): No current object"); 2670 } 2671 2672 switch (sDynListCurObj->type) { 2673 case OBJ_TYPE_NETS: 2674 ((struct ObjNet *) dynobj)->netType = type; 2675 break; 2676 case OBJ_TYPE_GADGETS: 2677 ((struct ObjGadget *) dynobj)->type = type; 2678 break; 2679 case OBJ_TYPE_GROUPS: 2680 ((struct ObjGroup *) dynobj)->debugPrint = type; 2681 break; 2682 case OBJ_TYPE_JOINTS: 2683 ((struct ObjJoint *) dynobj)->type = type; 2684 break; 2685 case OBJ_TYPE_PARTICLES: 2686 ((struct ObjParticle *) dynobj)->unk60 = type; 2687 break; 2688 case OBJ_TYPE_MATERIALS: 2689 ((struct ObjMaterial *) dynobj)->type = type; 2690 break; 2691 default: 2692 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetType()", 2693 sDynListCurInfo->name, sDynListCurObj->type); 2694 } 2695 } 2696 2697 /** 2698 * Set the specific object ID field for the current dynamic object. 2699 */ 2700 void d_set_id(s32 id) { 2701 struct GdObj *dynobj = sDynListCurObj; // sp24 2702 2703 if (sDynListCurObj == NULL) { 2704 fatal_printf("proc_dynlist(): No current object"); 2705 } 2706 2707 switch (sDynListCurObj->type) { 2708 case OBJ_TYPE_MATERIALS: 2709 ((struct ObjMaterial *) dynobj)->id = id; 2710 break; 2711 case OBJ_TYPE_JOINTS: 2712 ((struct ObjJoint *) dynobj)->id = id; 2713 break; 2714 case OBJ_TYPE_VERTICES: 2715 ((struct ObjVertex *) dynobj)->id = id; 2716 break; 2717 case OBJ_TYPE_LIGHTS: 2718 ((struct ObjLight *) dynobj)->id = id; 2719 break; 2720 default: 2721 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetID()", 2722 sDynListCurInfo->name, sDynListCurObj->type); 2723 } 2724 } 2725 2726 // TODO: enumerate colors? 2727 /** 2728 * Set the colour of the current dynamic object. The input color is an index 2729 * for `gd_get_colour()` 2730 */ 2731 void d_set_colour_num(s32 colornum) { 2732 struct GdColour *rgbcolor; 2733 2734 if (sDynListCurObj == NULL) { 2735 fatal_printf("proc_dynlist(): No current object"); 2736 } 2737 2738 switch (sDynListCurObj->type) { 2739 case OBJ_TYPE_JOINTS: 2740 ((struct ObjJoint *) sDynListCurObj)->colourNum = colornum; 2741 break; 2742 case OBJ_TYPE_PARTICLES: 2743 ((struct ObjParticle *) sDynListCurObj)->colourNum = colornum; 2744 break; 2745 case OBJ_TYPE_NETS: 2746 ((struct ObjNet *) sDynListCurObj)->colourNum = colornum; 2747 break; 2748 case OBJ_TYPE_GADGETS: 2749 ((struct ObjGadget *) sDynListCurObj)->colourNum = colornum; 2750 break; 2751 case OBJ_TYPE_FACES: 2752 rgbcolor = gd_get_colour(colornum); 2753 if (rgbcolor != NULL) { 2754 ((struct ObjFace *) sDynListCurObj)->colour.r = rgbcolor->r; 2755 ((struct ObjFace *) sDynListCurObj)->colour.g = rgbcolor->g; 2756 ((struct ObjFace *) sDynListCurObj)->colour.b = rgbcolor->b; 2757 ((struct ObjFace *) sDynListCurObj)->colourNum = colornum; 2758 } else { 2759 fatal_printf("dSetColNum: Unkown colour number"); 2760 } 2761 break; 2762 default: 2763 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dColourNum()", 2764 sDynListCurInfo->name, sDynListCurObj->type); 2765 } 2766 } 2767 2768 /** 2769 * Set the material ID of the current dynamic `ObjFace`. 2770 */ 2771 void d_set_material(UNUSED void *a0, s32 mtlId) { 2772 if (sDynListCurObj == NULL) { 2773 fatal_printf("proc_dynlist(): No current object"); 2774 } 2775 2776 switch (sDynListCurObj->type) { 2777 case OBJ_TYPE_FACES: 2778 ((struct ObjFace *) sDynListCurObj)->mtlId = mtlId; 2779 break; 2780 default: 2781 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetMaterial()", 2782 sDynListCurInfo->name, sDynListCurObj->type); 2783 } 2784 } 2785 2786 /** 2787 * Set the friction vec of the current dynamic `ObjJoint`. 2788 */ 2789 void d_friction(f32 x, f32 y, f32 z) { 2790 if (sDynListCurObj == NULL) { 2791 fatal_printf("proc_dynlist(): No current object"); 2792 } 2793 2794 switch (sDynListCurObj->type) { 2795 case OBJ_TYPE_JOINTS: 2796 ((struct ObjJoint *) sDynListCurObj)->friction.x = x; 2797 ((struct ObjJoint *) sDynListCurObj)->friction.y = y; 2798 ((struct ObjJoint *) sDynListCurObj)->friction.z = z; 2799 break; 2800 default: 2801 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dFriction()", 2802 sDynListCurInfo->name, sDynListCurObj->type); 2803 } 2804 } 2805 2806 /** 2807 * Set the spring constant of the current dynamic `ObjBone`. 2808 */ 2809 void d_set_spring(f32 spring) { 2810 if (sDynListCurObj == NULL) { 2811 fatal_printf("proc_dynlist(): No current object"); 2812 } 2813 2814 switch (sDynListCurObj->type) { 2815 case OBJ_TYPE_BONES: 2816 ((struct ObjBone *) sDynListCurObj)->spring = spring; 2817 break; 2818 default: 2819 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetSpring()", 2820 sDynListCurInfo->name, sDynListCurObj->type); 2821 } 2822 } 2823 2824 /** 2825 * Set the ambient color of the current dynamic `ObjMaterial`. 2826 */ 2827 void d_set_ambient(f32 r, f32 g, f32 b) { 2828 if (sDynListCurObj == NULL) { 2829 fatal_printf("proc_dynlist(): No current object"); 2830 } 2831 2832 switch (sDynListCurObj->type) { 2833 case OBJ_TYPE_MATERIALS: 2834 ((struct ObjMaterial *) sDynListCurObj)->Ka.r = r; 2835 ((struct ObjMaterial *) sDynListCurObj)->Ka.g = g; 2836 ((struct ObjMaterial *) sDynListCurObj)->Ka.b = b; 2837 break; 2838 default: 2839 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetAmbient()", 2840 sDynListCurInfo->name, sDynListCurObj->type); 2841 } 2842 } 2843 2844 /** 2845 * Set the diffuse color of the current dynamic `ObjMaterial` or `ObjLight`. 2846 */ 2847 void d_set_diffuse(f32 r, f32 g, f32 b) { 2848 if (sDynListCurObj == NULL) { 2849 fatal_printf("proc_dynlist(): No current object"); 2850 } 2851 2852 switch (sDynListCurObj->type) { 2853 case OBJ_TYPE_MATERIALS: 2854 ((struct ObjMaterial *) sDynListCurObj)->Kd.r = r; 2855 ((struct ObjMaterial *) sDynListCurObj)->Kd.g = g; 2856 ((struct ObjMaterial *) sDynListCurObj)->Kd.b = b; 2857 break; 2858 case OBJ_TYPE_LIGHTS: 2859 ((struct ObjLight *) sDynListCurObj)->diffuse.r = r; 2860 ((struct ObjLight *) sDynListCurObj)->diffuse.g = g; 2861 ((struct ObjLight *) sDynListCurObj)->diffuse.b = b; 2862 break; 2863 default: 2864 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetDiffuse()", 2865 sDynListCurInfo->name, sDynListCurObj->type); 2866 } 2867 } 2868 2869 /** 2870 * Set the control type of the current dynamic `ObjNet`. 2871 */ 2872 void d_set_control_type(s32 ctrltype) { 2873 if (sDynListCurObj == NULL) { 2874 fatal_printf("proc_dynlist(): No current object"); 2875 } 2876 2877 switch (sDynListCurObj->type) { 2878 case OBJ_TYPE_NETS: 2879 ((struct ObjNet *) sDynListCurObj)->ctrlType = ctrltype; 2880 break; 2881 default: 2882 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dControlType()", 2883 sDynListCurInfo->name, sDynListCurObj->type); 2884 } 2885 } 2886 2887 /** 2888 * Get a pointer to a `GdBoundingBox` in the current dynamic object. 2889 * If the current object does not have a bounding box, a pointer to 2890 * a global bounding box at (0,0) is returned. 2891 */ 2892 struct GdBoundingBox *d_get_bounding_box(void) { 2893 if (sDynListCurObj == NULL) { 2894 fatal_printf("proc_dynlist(): No current object"); 2895 } 2896 2897 switch (sDynListCurObj->type) { 2898 case OBJ_TYPE_NETS: 2899 return &((struct ObjNet *) sDynListCurObj)->boundingBox; 2900 break; 2901 case OBJ_TYPE_PLANES: 2902 return &((struct ObjPlane *) sDynListCurObj)->boundingBox; 2903 break; 2904 case OBJ_TYPE_ZONES: 2905 return &((struct ObjZone *) sDynListCurObj)->boundingBox; 2906 break; 2907 default: 2908 return &sNullBoundingBox; 2909 } 2910 } 2911 2912 /** 2913 * Copy the matrix from the current dynamic object into `dst`. 2914 */ 2915 void d_get_matrix(Mat4f *dst) { 2916 struct GdObj *dynobj; // sp24 2917 2918 if (sDynListCurObj == NULL) { 2919 fatal_printf("proc_dynlist(): No current object"); 2920 } 2921 2922 dynobj = sDynListCurObj; 2923 switch (sDynListCurObj->type) { 2924 case OBJ_TYPE_NETS: 2925 gd_copy_mat4f(&((struct ObjNet *) dynobj)->mat128, dst); 2926 break; 2927 break; // lol 2928 case OBJ_TYPE_JOINTS: 2929 gd_copy_mat4f(&((struct ObjJoint *) dynobj)->matE8, dst); 2930 break; 2931 case OBJ_TYPE_CAMERAS: 2932 gd_copy_mat4f(&((struct ObjCamera *) dynobj)->unkE8, dst); 2933 break; 2934 case OBJ_TYPE_PARTICLES: 2935 gd_set_identity_mat4(dst); 2936 break; 2937 case OBJ_TYPE_SHAPES: 2938 gd_set_identity_mat4(dst); 2939 break; 2940 default: 2941 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dGetMatrix()", 2942 sDynListCurInfo->name, sDynListCurObj->type); 2943 } 2944 } 2945 2946 /** 2947 * Set the matrix of the current dynamic object by copying `src` into the object. 2948 */ 2949 void d_set_matrix(Mat4f *src) { 2950 if (sDynListCurObj == NULL) { 2951 fatal_printf("proc_dynlist(): No current object"); 2952 } 2953 2954 switch (sDynListCurObj->type) { 2955 case OBJ_TYPE_NETS: 2956 gd_copy_mat4f(src, &((struct ObjNet *) sDynListCurObj)->mat128); 2957 //! @bug When setting an `ObjNet` matrix, the source is copied twice 2958 //! due to a probable copy-paste line repeat error 2959 gd_copy_mat4f(src, &((struct ObjNet *) sDynListCurObj)->mat128); 2960 break; 2961 case OBJ_TYPE_JOINTS: 2962 gd_copy_mat4f(src, &((struct ObjJoint *) sDynListCurObj)->matE8); 2963 break; 2964 case OBJ_TYPE_CAMERAS: 2965 gd_copy_mat4f(src, &((struct ObjCamera *) sDynListCurObj)->unk64); 2966 break; 2967 default: 2968 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetMatrix()", 2969 sDynListCurInfo->name, sDynListCurObj->type); 2970 } 2971 } 2972 2973 /** 2974 * Set the rotation matrix of the current dynamic object by copying 2975 * the input matrix `src`. 2976 */ 2977 void d_set_rot_mtx(Mat4f *src) { 2978 if (sDynListCurObj == NULL) { 2979 fatal_printf("proc_dynlist(): No current object"); 2980 } 2981 2982 switch (sDynListCurObj->type) { 2983 case OBJ_TYPE_JOINTS: 2984 gd_copy_mat4f(src, &((struct ObjJoint *) sDynListCurObj)->mat128); 2985 break; 2986 case OBJ_TYPE_NETS: 2987 gd_copy_mat4f(src, &((struct ObjNet *) sDynListCurObj)->mat168); 2988 break; 2989 default: 2990 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetRMatrix()", 2991 sDynListCurInfo->name, sDynListCurObj->type); 2992 } 2993 } 2994 2995 /** 2996 * Get a pointer to the current dynamic object's rotation matrix. 2997 */ 2998 Mat4f *d_get_rot_mtx_ptr(void) { 2999 if (sDynListCurObj == NULL) { 3000 fatal_printf("proc_dynlist(): No current object"); 3001 } 3002 3003 switch (sDynListCurObj->type) { 3004 case OBJ_TYPE_JOINTS: 3005 return &((struct ObjJoint *) sDynListCurObj)->mat128; 3006 case OBJ_TYPE_NETS: 3007 return &((struct ObjNet *) sDynListCurObj)->mat168; 3008 default: 3009 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dGetRMatrixPtr()", 3010 sDynListCurInfo->name, sDynListCurObj->type); 3011 } 3012 // No null return due to `fatal_printf()` being a non-returning function? 3013 } 3014 3015 /** 3016 * Copy `src` into the matrix of the current dynamic object. 3017 * TODO: What is an IMatrix? 3018 */ 3019 void d_set_i_matrix(Mat4f *src) { 3020 struct GdObj *dynobj; 3021 3022 if (sDynListCurObj == NULL) { 3023 fatal_printf("proc_dynlist(): No current object"); 3024 } 3025 3026 dynobj = sDynListCurObj; 3027 switch (sDynListCurObj->type) { 3028 case OBJ_TYPE_NETS: 3029 gd_copy_mat4f(src, &((struct ObjNet *) dynobj)->matE8); 3030 break; 3031 case OBJ_TYPE_JOINTS: 3032 gd_copy_mat4f(src, &((struct ObjJoint *) dynobj)->mat168); 3033 break; 3034 case OBJ_TYPE_LIGHTS: 3035 ((struct ObjLight *) dynobj)->position.x = (*src)[3][0]; 3036 ((struct ObjLight *) dynobj)->position.y = (*src)[3][1]; 3037 ((struct ObjLight *) dynobj)->position.z = (*src)[3][2]; 3038 break; 3039 default: 3040 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetIMatrix()", 3041 sDynListCurInfo->name, sDynListCurObj->type); 3042 } 3043 } 3044 3045 /** 3046 * Get a pointer to the current dynamic object's matrix. 3047 */ 3048 Mat4f *d_get_matrix_ptr(void) { 3049 if (sDynListCurObj == NULL) { 3050 fatal_printf("proc_dynlist(): No current object"); 3051 } 3052 3053 switch (sDynListCurObj->type) { 3054 case OBJ_TYPE_NETS: 3055 return &((struct ObjNet *) sDynListCurObj)->mat128; 3056 break; 3057 case OBJ_TYPE_CAMERAS: 3058 return &((struct ObjCamera *) sDynListCurObj)->unk64; 3059 break; 3060 case OBJ_TYPE_BONES: 3061 return &((struct ObjBone *) sDynListCurObj)->mat70; 3062 break; 3063 case OBJ_TYPE_JOINTS: 3064 return &((struct ObjJoint *) sDynListCurObj)->matE8; 3065 break; 3066 default: 3067 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dGetMatrixPtr()", 3068 sDynListCurInfo->name, sDynListCurObj->type); 3069 } 3070 // No null return due to `fatal_printf()` being a non-returning function? 3071 } 3072 3073 /** 3074 * Get a pointer to the current dynamic object's matrix. 3075 * TODO: What is an IMatrix? 3076 */ 3077 Mat4f *d_get_i_mtx_ptr(void) { 3078 struct GdObj *dynobj; // sp24 3079 3080 if (sDynListCurObj == NULL) { 3081 fatal_printf("proc_dynlist(): No current object"); 3082 } 3083 3084 dynobj = sDynListCurObj; 3085 switch (sDynListCurObj->type) { 3086 case OBJ_TYPE_NETS: 3087 return &((struct ObjNet *) dynobj)->matE8; 3088 break; 3089 case OBJ_TYPE_JOINTS: 3090 return &((struct ObjJoint *) dynobj)->mat168; 3091 break; 3092 default: 3093 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dGetIMatrixPtr()", 3094 sDynListCurInfo->name, sDynListCurObj->type); 3095 } 3096 // No null return due to `fatal_printf()` being a non-returning function? 3097 } 3098 3099 /** 3100 * Use the dynamic object system to calculate the distance between 3101 * two `GdObj`s. The objects don't have to be dynamic objects. 3102 */ 3103 f32 d_calc_world_dist_btwn(struct GdObj *obj1, struct GdObj *obj2) { 3104 struct GdVec3f obj1pos; // sp34 3105 struct GdVec3f obj2pos; // sp28 3106 struct GdVec3f posdiff; // sp1C 3107 3108 set_cur_dynobj(obj1); 3109 d_get_world_pos(&obj1pos); 3110 set_cur_dynobj(obj2); 3111 d_get_world_pos(&obj2pos); 3112 3113 posdiff.x = obj2pos.x - obj1pos.x; 3114 posdiff.y = obj2pos.y - obj1pos.y; 3115 posdiff.z = obj2pos.z - obj1pos.z; 3116 3117 return gd_vec3f_magnitude(&posdiff); 3118 } 3119 3120 /** 3121 * Create a new weight for the vertex `vtxId` in the current dynamic `ObjJoint`. 3122 * The input weight value is out of 100. 3123 */ 3124 void d_set_skin_weight(s32 vtxId, f32 percentWeight) { 3125 if (sDynListCurObj == NULL) { 3126 fatal_printf("proc_dynlist(): No current object"); 3127 } 3128 3129 switch (sDynListCurObj->type) { 3130 case OBJ_TYPE_JOINTS: 3131 set_skin_weight((struct ObjJoint *) sDynListCurObj, vtxId, NULL, 3132 percentWeight / 100.0); 3133 break; 3134 default: 3135 fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetSkinWeight()", 3136 sDynListCurInfo->name, sDynListCurObj->type); 3137 } 3138 }