sm64

A Super Mario 64 decompilation
Log | Files | Refs | README | LICENSE

objects.c (62581B)


      1 #include <PR/ultratypes.h>
      2 #include <stdarg.h>
      3 #include <stdio.h>
      4 
      5 #include "objects.h"
      6 
      7 #include "debug_utils.h"
      8 #include "draw_objects.h"
      9 #include "dynlist_proc.h"
     10 #include "gd_macros.h"
     11 #include "gd_main.h"
     12 #include "gd_math.h"
     13 #include "gd_types.h"
     14 #include "joints.h"
     15 #include "macros.h"
     16 #include "old_menu.h"
     17 #include "particles.h"
     18 #include "renderer.h"
     19 #include "sfx.h"
     20 #include "shape_helper.h"
     21 #include "skin.h"
     22 
     23 // structs
     24 struct Unk801B9E68 {
     25     /* 0x00 */ s32 count;
     26     /* 0x04 */ u8 filler[20];
     27 }; /* sizeof() = 0x18 */
     28 
     29 struct Unk8017F3CC {
     30     /*0x00*/ u8 filler[32];
     31     /*0x20*/ struct GdVec3f unk20;
     32 };
     33 
     34 // data
     35 f32 D_801A81C0 = 0.0f;
     36 f32 D_801A81C4 = 0.0f;
     37 
     38 // bss
     39 struct GdBoundingBox gSomeBoundingBox;
     40 struct ObjCamera *sCurrentMoveCamera; // @ 801B9DB8
     41 struct ObjView *sCurrentMoveView;     // @ 801B9DBC
     42 struct DebugCounters gGdCounter;      // @ 801B9DC0
     43 Mat4f D_801B9DC8;
     44 struct GdVec3f D_801B9E08;
     45 struct ObjGroup *sCurrentMoveGrp; // @ 801B9E14
     46 struct GdVec3f D_801B9E18;
     47 struct GdVec3f D_801B9E28;
     48 f32 D_801B9E34;
     49 Mat4f *D_801B9E38;
     50 struct ObjParticle *D_801B9E3C;
     51 s32 D_801B9E40;
     52 s32 D_801B9E44;
     53 Mat4f *D_801B9E48;
     54 struct ObjCamera *gGdCameraList; // @ 801B9E4C
     55 void *D_801B9E50;
     56 struct ObjGroup *gGdGroupList;  // @ 801B9E54
     57 s32 gGdObjCount;                // @ 801B9E58
     58 s32 gGdGroupCount;              // @ 801B9E5C
     59 s32 gGdPlaneCount;              // @ 801B9E60
     60 s32 gGdCameraCount;             // @ 801B9E64
     61 struct Unk801B9E68 sGdViewInfo; // @ 801B9E68
     62 void *D_801B9E80;
     63 struct ObjJoint *gGdJointList;  // @ 801B9E84
     64 struct ObjBone *gGdBoneList;    // @ 801B9E88
     65 struct GdObj *gGdObjectList;    // head of linked list containing every single GdObj that was created
     66 struct ObjGroup *gGdViewsGroup; // @ 801B9E90
     67 
     68 /* @ 22A480 for 0x70 */
     69 void reset_bounding_box(void) { /* Initialize Plane? */
     70     gSomeBoundingBox.minX = 10000000.0f;
     71     gSomeBoundingBox.minY = 10000000.0f;
     72     gSomeBoundingBox.minZ = 10000000.0f;
     73 
     74     gSomeBoundingBox.maxX = -10000000.0f;
     75     gSomeBoundingBox.maxY = -10000000.0f;
     76     gSomeBoundingBox.maxZ = -10000000.0f;
     77 }
     78 
     79 void add_obj_pos_to_bounding_box(struct GdObj *obj) {
     80     struct GdVec3f pos;
     81 
     82     set_cur_dynobj(obj);
     83     d_get_world_pos(&pos);
     84 
     85     if (pos.x < gSomeBoundingBox.minX) {
     86         gSomeBoundingBox.minX = pos.x;
     87     }
     88 
     89     if (pos.y < gSomeBoundingBox.minY) {
     90         gSomeBoundingBox.minY = pos.y;
     91     }
     92 
     93     if (pos.z < gSomeBoundingBox.minZ) {
     94         gSomeBoundingBox.minZ = pos.z;
     95     }
     96 
     97     if (pos.x > gSomeBoundingBox.maxX) {
     98         gSomeBoundingBox.maxX = pos.x;
     99     }
    100 
    101     if (pos.y > gSomeBoundingBox.maxY) {
    102         gSomeBoundingBox.maxY = pos.y;
    103     }
    104 
    105     if (pos.z > gSomeBoundingBox.maxZ) {
    106         gSomeBoundingBox.maxZ = pos.z;
    107     }
    108 }
    109 
    110 /* @ 22A630 for 0x70 */
    111 void get_some_bounding_box(struct GdBoundingBox *a0) {
    112     a0->minX = gSomeBoundingBox.minX;
    113     a0->minY = gSomeBoundingBox.minY;
    114     a0->minZ = gSomeBoundingBox.minZ;
    115 
    116     a0->maxX = gSomeBoundingBox.maxX;
    117     a0->maxY = gSomeBoundingBox.maxY;
    118     a0->maxZ = gSomeBoundingBox.maxZ;
    119 }
    120 
    121 /* @ 22A6A0 for 0x24 */
    122 void stub_objects_1(UNUSED struct ObjGroup *a0, UNUSED struct GdObj *a1) {
    123     UNUSED u8 filler[8];
    124     /* Debug stub? */
    125     return;
    126 }
    127 
    128 /**
    129  * Returns a string containing the name of the the object type
    130  */
    131 static const char *get_obj_name_str(enum ObjTypeFlag objFlag) {
    132     const char *objName;
    133     switch (objFlag) {
    134         case OBJ_TYPE_JOINTS:
    135             objName = "joints";
    136             break;
    137         case OBJ_TYPE_BONES:
    138             objName = "bones";
    139             break;
    140         case OBJ_TYPE_GROUPS:
    141             objName = "groups";
    142             break;
    143         case OBJ_TYPE_PARTICLES:
    144             objName = "particles";
    145             break;
    146         case OBJ_TYPE_SHAPES:
    147             objName = "shapes";
    148             break;
    149         case OBJ_TYPE_NETS:
    150             objName = "nets";
    151             break;
    152         case OBJ_TYPE_PLANES:
    153             objName = "planes";
    154             break;
    155         case OBJ_TYPE_VERTICES:
    156             objName = "vertices";
    157             break;
    158         case OBJ_TYPE_CAMERAS:
    159             objName = "cameras";
    160             break;
    161         case OBJ_TYPE_FACES:
    162             objName = "faces";
    163             break;
    164         case OBJ_TYPE_MATERIALS:
    165             objName = "materials";
    166             break;
    167         case OBJ_TYPE_LIGHTS:
    168             objName = "lights";
    169             break;
    170         case OBJ_TYPE_WEIGHTS:
    171             objName = "weights";
    172             break;
    173         case OBJ_TYPE_GADGETS:
    174             objName = "gadgets";
    175             break;
    176         case OBJ_TYPE_VIEWS:
    177             objName = "views";
    178             break;
    179         case OBJ_TYPE_LABELS:
    180             objName = "labels";
    181             break;
    182         case OBJ_TYPE_ANIMATORS:
    183             objName = "animators";
    184             break;
    185         case OBJ_TYPE_VALPTRS:
    186             objName = "valptrs";
    187             break;
    188         case OBJ_TYPE_ZONES:
    189             objName = "zones";
    190             break;
    191         default:
    192             objName = "unkown";
    193             break;
    194     }
    195     return objName;
    196 }
    197 
    198 /**
    199  * Creates an object of the specified type
    200  */
    201 struct GdObj *make_object(enum ObjTypeFlag objType) {
    202     struct GdObj *newObj;
    203     struct GdObj *objListOldHead;
    204     s32 objSize;
    205     s32 i;
    206     drawmethod_t objDrawFn;
    207     const char *typeName;
    208     u8 *newObjBytes;
    209     s32 objPermanence = 0x10;
    210 
    211     imin("make_object");
    212 
    213     switch (objType) {
    214         case OBJ_TYPE_JOINTS:
    215             objSize = sizeof(struct ObjJoint);
    216             objDrawFn = (drawmethod_t) draw_joint;
    217             break;
    218         case OBJ_TYPE_BONES:
    219             objSize = sizeof(struct ObjBone);
    220             objDrawFn = (drawmethod_t) draw_bone;
    221             break;
    222         case OBJ_TYPE_GROUPS:
    223             objSize = sizeof(struct ObjGroup);
    224             objDrawFn = (drawmethod_t) draw_group;
    225             break;
    226         case OBJ_TYPE_PARTICLES:
    227             objSize = sizeof(struct ObjParticle);
    228             objDrawFn = (drawmethod_t) draw_particle;
    229             break;
    230         case OBJ_TYPE_SHAPES:
    231             objSize = sizeof(struct ObjShape);
    232             // Shapes get drawn by their parent object instead of automatically.
    233             objDrawFn = (drawmethod_t) draw_nothing;
    234             break;
    235         case OBJ_TYPE_UNK200000:
    236             objSize = sizeof(struct ObjUnk200000);
    237             objDrawFn = (drawmethod_t) draw_nothing;
    238             break;
    239         case OBJ_TYPE_NETS:
    240             objSize = sizeof(struct ObjNet);
    241             objDrawFn = (drawmethod_t) draw_net;
    242             break;
    243         case OBJ_TYPE_PLANES:
    244             objSize = sizeof(struct ObjPlane);
    245             objDrawFn = (drawmethod_t) draw_plane;
    246             break;
    247         case OBJ_TYPE_VERTICES:
    248             objSize = sizeof(struct ObjVertex);
    249             objDrawFn = (drawmethod_t) draw_nothing;
    250             break;
    251         case OBJ_TYPE_CAMERAS:
    252             objSize = sizeof(struct ObjCamera);
    253             objDrawFn = (drawmethod_t) draw_camera;
    254             break;
    255         case OBJ_TYPE_FACES:
    256             objSize = sizeof(struct ObjFace);
    257             objDrawFn = (drawmethod_t) draw_face;
    258             objPermanence = 1;
    259             break;
    260         case OBJ_TYPE_MATERIALS:
    261             objSize = sizeof(struct ObjMaterial);
    262             objDrawFn = (drawmethod_t) draw_material;
    263             break;
    264         case OBJ_TYPE_LIGHTS:
    265             objSize = sizeof(struct ObjLight);
    266             objDrawFn = (drawmethod_t) draw_light;
    267             break;
    268         case OBJ_TYPE_WEIGHTS:
    269             objSize = sizeof(struct ObjWeight);
    270             objDrawFn = (drawmethod_t) draw_nothing;
    271             break;
    272         case OBJ_TYPE_GADGETS:
    273             objSize = sizeof(struct ObjGadget);
    274             objDrawFn = (drawmethod_t) draw_gadget;
    275             break;
    276         case OBJ_TYPE_VIEWS:
    277             objSize = sizeof(struct ObjView);
    278             objDrawFn = (drawmethod_t) draw_nothing;
    279             break;
    280         case OBJ_TYPE_LABELS:
    281             objSize = sizeof(struct ObjLabel);
    282             objDrawFn = (drawmethod_t) draw_label;
    283             break;
    284         case OBJ_TYPE_ANIMATORS:
    285             objSize = sizeof(struct ObjAnimator);
    286             objDrawFn = (drawmethod_t) draw_nothing;
    287             break;
    288         case OBJ_TYPE_VALPTRS:
    289             objSize = sizeof(struct ObjValPtr);
    290             objDrawFn = (drawmethod_t) draw_nothing;
    291             break;
    292         case OBJ_TYPE_ZONES:
    293             objSize = sizeof(struct ObjZone);
    294             objDrawFn = (drawmethod_t) draw_nothing;
    295             break;
    296         default:
    297             fatal_print("make_object() : Unkown object!");
    298     }
    299 
    300     typeName = get_obj_name_str(objType);
    301 
    302     // Allocate memory for the object
    303     start_memtracker(typeName);
    304     newObj = gd_malloc(objSize, objPermanence);
    305     if (newObj == NULL) {
    306         fatal_printf("Cant allocate object '%s' memory!", typeName);
    307     }
    308     stop_memtracker(typeName);
    309 
    310     // Zero out the object
    311     newObjBytes = (u8 *) newObj;
    312     for (i = 0; i < objSize; i++) {
    313         newObjBytes[i] = 0;
    314     }
    315 
    316     // Add the new object to the beginning of gGdObjectList
    317     gGdObjCount++;
    318     objListOldHead = gGdObjectList;
    319     gGdObjectList = newObj;
    320     newObj->prev = NULL;
    321     if (objListOldHead != NULL) {
    322         newObj->next = objListOldHead;
    323         objListOldHead->prev = newObj;
    324     }
    325 
    326     // Fill in required fields
    327     newObj->index = gGdObjCount;
    328     newObj->type = objType;
    329     newObj->objDrawFn = objDrawFn;
    330     newObj->drawFlags = 0;
    331 
    332     imout();
    333     return newObj;
    334 }
    335 
    336 /* @ 22AEA0 for 0xD0; orig name: func_8017C6D0 */
    337 struct ObjZone *make_zone(struct ObjGroup *a0, struct GdBoundingBox *bbox, struct ObjGroup *a2) {
    338     struct ObjZone *newZone = (struct ObjZone *) make_object(OBJ_TYPE_ZONES);
    339 
    340     newZone->boundingBox.minX = bbox->minX;
    341     newZone->boundingBox.minY = bbox->minY;
    342     newZone->boundingBox.minZ = bbox->minZ;
    343     newZone->boundingBox.maxX = bbox->maxX;
    344     newZone->boundingBox.maxY = bbox->maxY;
    345     newZone->boundingBox.maxZ = bbox->maxZ;
    346     // pointers? prev, next?
    347     newZone->unk2C = a2;
    348     newZone->unk30 = a0;
    349 
    350 //! @bug Created `ObjZone` is not returned
    351 #ifdef AVOID_UB
    352     return newZone;
    353 #endif
    354 }
    355 
    356 /* @ 22AF70 for 0x60 */
    357 struct ObjUnk200000 *func_8017C7A0(struct ObjVertex *a0, struct ObjFace *a1) {
    358     struct ObjUnk200000 *unk = (struct ObjUnk200000 *) make_object(OBJ_TYPE_UNK200000);
    359 
    360     unk->unk30 = a0;
    361     unk->unk34 = a1;
    362 
    363     return unk;
    364 }
    365 
    366 /**
    367  * Creates a ListNode for the object. Adds the new node after `prevNode` if `prevNode` is not NULL.
    368  */
    369 struct ListNode *make_link_to_obj(struct ListNode *prevNode, struct GdObj *obj) {
    370     struct ListNode *newNode;
    371 
    372     // Allocate link node
    373     start_memtracker("links");
    374     newNode = gd_malloc_perm(sizeof(struct ListNode));
    375     if (newNode == NULL) {
    376         fatal_print("Cant allocate link memory!");
    377     }
    378     stop_memtracker("links");
    379 
    380     // Append to `prevNode` if not NULL
    381     if (prevNode != NULL) {
    382         prevNode->next = newNode;
    383     }
    384 
    385     newNode->prev = prevNode;
    386     newNode->next = NULL;
    387     newNode->obj = obj;
    388 
    389     return newNode;
    390 }
    391 
    392 /*
    393  * Creates a VtxLink for the vertex. Adds the new node after `prevNode` if `prevNode` is not NULL.
    394  */
    395 struct VtxLink *make_vtx_link(struct VtxLink *prevNode, Vtx *data) {
    396     struct VtxLink *newNode;
    397 
    398     newNode = gd_malloc_perm(sizeof(struct VtxLink));
    399     if (newNode == NULL) {
    400         fatal_print("Cant allocate link memory!");
    401     }
    402 
    403     // Append to `prevNode` if not NULL
    404     if (prevNode != NULL) {
    405         prevNode->next = newNode;
    406     }
    407 
    408     newNode->prev = prevNode;
    409     newNode->next = NULL;
    410     newNode->data = data;
    411 
    412     // WTF? Not sure what this is supposed to check
    413     if (((uintptr_t)(newNode)) == 0x3F800000) {
    414         fatal_printf("bad3\n");
    415     }
    416 
    417     return newNode;
    418 }
    419 
    420 /* @ 22B154 for 0x88; orig name: func8017C984 */
    421 struct ObjValPtr *make_valptr(struct GdObj *obj, s32 flag, enum ValPtrType type, size_t offset) {
    422     struct ObjValPtr *sp1C = (struct ObjValPtr *) make_object(OBJ_TYPE_VALPTRS);
    423 
    424     sp1C->obj = obj;
    425     sp1C->flag = flag;
    426     sp1C->offset = offset;
    427     sp1C->datatype = type;
    428 
    429     return sp1C;
    430 }
    431 
    432 /* @ 22B1DC for 0x430 */
    433 void reset_plane(struct ObjPlane *plane) {
    434     struct ObjFace *sp4C;
    435     f32 sp48;
    436     f32 sp44;
    437     UNUSED u8 filler[12];
    438     s32 i;
    439     s32 sp30;
    440     register f32 sp28;
    441 
    442     imin("reset_plane");
    443 
    444     sp4C = plane->unk40;
    445     calc_face_normal(sp4C);
    446     plane->unk1C = gd_dot_vec3f(&sp4C->vertices[0]->pos, &sp4C->normal);
    447     sp48 = 0.0f;
    448 
    449     sp28 = sp4C->normal.x < 0.0f ? -sp4C->normal.x : sp4C->normal.x;
    450     sp44 = sp28;
    451     if (sp44 > sp48) {
    452         sp30 = 0;
    453         sp48 = sp44;
    454     }
    455 
    456     sp28 = sp4C->normal.y < 0.0f ? -sp4C->normal.y : sp4C->normal.y;
    457     sp44 = sp28;
    458     if (sp44 > sp48) {
    459         sp30 = 1;
    460         sp48 = sp44;
    461     }
    462 
    463     sp28 = sp4C->normal.z < 0.0f ? -sp4C->normal.z : sp4C->normal.z;
    464     sp44 = sp28;
    465     if (sp44 > sp48) {
    466         sp30 = 2;
    467     }
    468 
    469     switch (sp30) {
    470         case 0:
    471             plane->unk20 = 1;
    472             plane->unk24 = 2;
    473             break;
    474         case 1:
    475             plane->unk20 = 0;
    476             plane->unk24 = 2;
    477             break;
    478         case 2:
    479             plane->unk20 = 0;
    480             plane->unk24 = 1;
    481             break;
    482     }
    483 
    484     reset_bounding_box();
    485 
    486     for (i = 0; i < sp4C->vtxCount; i++) {
    487         add_obj_pos_to_bounding_box(&sp4C->vertices[i]->header);
    488     }
    489 
    490     plane->boundingBox.minX = gSomeBoundingBox.minX;
    491     plane->boundingBox.minY = gSomeBoundingBox.minY;
    492     plane->boundingBox.minZ = gSomeBoundingBox.minZ;
    493     plane->boundingBox.maxX = gSomeBoundingBox.maxX;
    494     plane->boundingBox.maxY = gSomeBoundingBox.maxY;
    495     plane->boundingBox.maxZ = gSomeBoundingBox.maxZ;
    496 
    497     if (plane->boundingBox.maxX - plane->boundingBox.minX < 100.0f) {
    498         plane->boundingBox.maxX += 50.0f;
    499         plane->boundingBox.minX -= 50.0f;
    500     }
    501 
    502     plane->boundingBox.maxY += 200.0f;
    503     plane->boundingBox.minY -= 200.0f;
    504 
    505     if (plane->boundingBox.maxZ - plane->boundingBox.minZ < 100.0f) {
    506         plane->boundingBox.maxZ += 50.0f;
    507         plane->boundingBox.minZ -= 50.0f;
    508     }
    509     imout();
    510 }
    511 
    512 /* @ 22B60C for 0x94; orig name: func_8017CE3C */
    513 struct ObjPlane *make_plane(s32 inZone, struct ObjFace *a1) {
    514     UNUSED u8 filler[4];
    515     struct ObjPlane *newPlane = (struct ObjPlane *) make_object(OBJ_TYPE_PLANES);
    516 
    517     gGdPlaneCount++;
    518     newPlane->id = gGdPlaneCount;
    519     newPlane->unk18 = inZone;
    520     newPlane->unk40 = a1;
    521     reset_plane(newPlane);
    522 
    523     return newPlane;
    524 }
    525 
    526 /* @ 22B6A0 for 0x21C; orig name: func_8017CED0 */
    527 struct ObjCamera *make_camera(s32 flags, struct GdObj *a1) {
    528     struct ObjCamera *newCam;
    529     struct ObjCamera *oldCameraHead;
    530 
    531     newCam = (struct ObjCamera *) make_object(OBJ_TYPE_CAMERAS);
    532 
    533     gGdCameraCount++;
    534     newCam->id = gGdCameraCount;
    535 
    536     oldCameraHead = gGdCameraList;
    537     gGdCameraList = newCam;
    538 
    539     if (oldCameraHead != NULL) {
    540         newCam->next = oldCameraHead;
    541         oldCameraHead->prev = newCam;
    542     }
    543 
    544     newCam->flags = flags | 0x10;
    545     newCam->unk30 = a1;
    546     gd_set_identity_mat4(&newCam->unk64);
    547     gd_set_identity_mat4(&newCam->unkA8);
    548 
    549     newCam->unk180.x = 1.0f;
    550     newCam->unk180.y = 0.1f;
    551     newCam->unk180.z = 1.0f;
    552 
    553     newCam->unk134.x = 4.0f;
    554     newCam->unk134.y = 4.0f;
    555     newCam->unk134.z = 4.0f;
    556 
    557     newCam->unk178 = 0.0f;
    558     newCam->unk17C = 0.25f;
    559 
    560     newCam->zoomLevel = 0;
    561     newCam->maxZoomLevel = -1;
    562 
    563     newCam->unkA4 = 0.0f;
    564 
    565     newCam->lookAt.x = newCam->lookAt.y = newCam->lookAt.z = 0.0f;
    566     newCam->worldPos.x = newCam->worldPos.y = newCam->worldPos.z = 0.0f;
    567 
    568     return newCam;
    569 }
    570 
    571 /* @ 22B8BC for 0xA8; orig. name: func_8017D0EC */
    572 struct ObjMaterial *make_material(UNUSED s32 a0, char *name, s32 id) {
    573     struct ObjMaterial *newMtl;
    574 
    575     newMtl = (struct ObjMaterial *) make_object(OBJ_TYPE_MATERIALS);
    576 
    577     if (name != NULL) {
    578         gd_strcpy(newMtl->name, name);
    579     } else {
    580         gd_strcpy(newMtl->name, "NoName");
    581     }
    582 
    583     newMtl->id = id;
    584     newMtl->gddlNumber = 0;
    585     newMtl->type = 16;
    586 
    587     return newMtl;
    588 }
    589 
    590 /* @ 22B964 for 0x114; orig name: func_8017D194 */
    591 struct ObjLight *make_light(s32 flags, char *name, s32 id) {
    592     struct ObjLight *newLight;
    593 
    594     newLight = (struct ObjLight *) make_object(OBJ_TYPE_LIGHTS);
    595 
    596     if (name != NULL) {
    597         gd_strcpy(newLight->name, name);
    598     } else {
    599         gd_strcpy(newLight->name, "NoName");
    600     }
    601 
    602     newLight->id = id;
    603     newLight->unk30 = 1.0f;
    604     newLight->unk4C = 0;
    605     newLight->flags = flags | LIGHT_NEW_UNCOUNTED;
    606     newLight->unk98 = 0;
    607     newLight->unk40 = 0;
    608 
    609     newLight->unk68.x = newLight->unk68.y = newLight->unk68.z = 0;
    610 
    611     return newLight;
    612 }
    613 
    614 /* @ 22BA78 for 0x294; orig name: func_8017D2A8*/
    615 struct ObjView *make_view(const char *name, s32 flags, s32 projectionType, s32 ulx, s32 uly, s32 lrx, s32 lry,
    616                           struct ObjGroup *parts) {
    617     struct ObjView *newView = (struct ObjView *) make_object(OBJ_TYPE_VIEWS);
    618 
    619     if (gGdViewsGroup == NULL) {
    620         gGdViewsGroup = make_group(0);
    621     }
    622 
    623     addto_group(gGdViewsGroup, &newView->header);
    624 
    625     newView->flags = flags | VIEW_UPDATE | VIEW_LIGHT;
    626     newView->id = sGdViewInfo.count++;
    627 
    628     if ((newView->components = parts) != NULL) {
    629         reset_nets_and_gadgets(parts);
    630     }
    631 
    632     newView->unk78 = 0;
    633     newView->projectionType = projectionType;
    634 
    635     newView->clipping.x = 30.0f;
    636     newView->clipping.y = 5000.0f;
    637     newView->clipping.z = 45.0f;
    638 
    639     newView->upperLeft.x = (f32) ulx;
    640     newView->upperLeft.y = (f32) uly;
    641 
    642     newView->lowerRight.x = (f32) lrx;
    643     newView->lowerRight.y = (f32) lry;
    644 
    645     newView->unk48 = 1.0f;
    646     newView->unk4C = 1.0f;
    647 
    648     newView->colour.r = newView->id * 0.1; //? 0.1f, unless the extra precision was wanted for the tenth
    649     newView->colour.g = 0.06f;
    650     newView->colour.b = 1.0f;
    651 
    652     newView->proc = NULL;
    653     newView->unk9C = 0;
    654 
    655     if (name != NULL) {
    656         newView->unk1C = setup_view_buffers(name, newView, ulx, uly, lrx, lry);
    657     }
    658 
    659     newView->namePtr = name;
    660     newView->lights = NULL;
    661 
    662     return newView;
    663 }
    664 
    665 /* @ 22BD0C for 0x78; orig name: func_8017D53C */
    666 struct ObjAnimator *make_animator(void) {
    667     struct ObjAnimator *newAnim = (struct ObjAnimator *) make_object(OBJ_TYPE_ANIMATORS);
    668     newAnim->unk24 = 1.0f;
    669     newAnim->frame = 1.0f;
    670 
    671     newAnim->controlFunc = NULL;
    672     newAnim->state = 0;
    673 
    674     return newAnim;
    675 }
    676 
    677 /* @ 22BD84 for 0x78; orig name: func_8017D5B4 */
    678 struct ObjWeight *make_weight(UNUSED s32 a0, s32 vtxId, struct ObjVertex *vtx /* always NULL */, f32 weight) {
    679     struct ObjWeight *newWeight = (struct ObjWeight *) make_object(OBJ_TYPE_WEIGHTS);
    680 
    681     newWeight->vtxId = vtxId;
    682     newWeight->weightVal = weight;
    683     newWeight->vtx = vtx;  // is always NULL here. This vtx field actually gets set in reset_weight_vtx.
    684 
    685     return newWeight;
    686 }
    687 
    688 /**
    689  * Makes a group, adding all objects from `fromObj` to `toObj` with type `type`
    690  * as members.
    691  */
    692 struct ObjGroup *make_group_of_type(enum ObjTypeFlag type, struct GdObj *fromObj, struct GdObj *toObj) {
    693     struct ObjGroup *newGroup;
    694     struct GdObj *curObj;
    695 
    696     newGroup = make_group(0);
    697     curObj = fromObj;
    698 
    699     while (curObj != NULL) {
    700         if (curObj->type & type) {
    701             addto_group(newGroup, curObj);
    702         }
    703 
    704         if (curObj == toObj) {
    705             break;
    706         }
    707 
    708         curObj = curObj->prev;
    709     }
    710 
    711     return newGroup;
    712 }
    713 
    714 /**
    715  * Converts the object's ID to a string and places it in the buffer pointed to by `str`.
    716  */
    717 void format_object_id(char *str, struct GdObj *obj) {
    718     enum ObjTypeFlag type = obj->type;
    719 
    720     switch (type) {
    721         case OBJ_TYPE_BONES:
    722             sprintf(str, "b%d ", ((struct ObjBone *) obj)->id);
    723             break;
    724         case OBJ_TYPE_JOINTS:
    725             sprintf(str, "j%d ", ((struct ObjJoint *) obj)->id);
    726             break;
    727         case OBJ_TYPE_GROUPS:
    728             sprintf(str, "g%d ", ((struct ObjGroup *) obj)->id);
    729             break;
    730         case OBJ_TYPE_PARTICLES:
    731             sprintf(str, "p%d ", ((struct ObjParticle *) obj)->id);
    732             break;
    733         case OBJ_TYPE_NETS:
    734             sprintf(str, "net(no id) ");
    735             break;
    736         case OBJ_TYPE_CAMERAS:
    737             sprintf(str, "c%d ", ((struct ObjCamera *) obj)->id);
    738             break;
    739         case OBJ_TYPE_VERTICES:
    740             sprintf(str, "v(no id) ");
    741             break;
    742         case OBJ_TYPE_PLANES:
    743             sprintf(str, "pl%d ", ((struct ObjPlane *) obj)->id);
    744             break;
    745         default:
    746             sprintf(str, "?%x ", type);
    747             break;
    748     }
    749 }
    750 
    751 /* @ 22C094 for 0x210 */
    752 struct ObjGroup *make_group(s32 count, ...) {
    753     va_list args;
    754     s32 i;
    755     UNUSED u8 filler1[4];
    756     struct GdObj *curObj;
    757     UNUSED u8 filler2[12];
    758     struct ObjGroup *newGroup;
    759     struct ObjGroup *oldGroupListHead;
    760     struct GdObj *vargObj;
    761     char idStrBuf[0x20];
    762     struct ListNode *curLink;
    763 
    764     newGroup = (struct ObjGroup *) make_object(OBJ_TYPE_GROUPS);
    765     newGroup->id = ++gGdGroupCount;
    766     newGroup->memberCount = 0;
    767     newGroup->firstMember = newGroup->lastMember = NULL;
    768 
    769     printf("Made group no.%d\n", newGroup->id);
    770 
    771     oldGroupListHead = gGdGroupList;
    772     gGdGroupList = newGroup;
    773     if (oldGroupListHead != NULL) {
    774         newGroup->next = oldGroupListHead;
    775         oldGroupListHead->prev = newGroup;
    776     }
    777 
    778     if (count == 0) {
    779         return newGroup;
    780     }
    781 
    782     va_start(args, count);
    783     curLink = NULL;
    784 
    785     for (i = 0; i < count; i++) {
    786         // get the next pointer in the struct.
    787         vargObj = va_arg(args, struct GdObj *);
    788 
    789         if (vargObj == NULL) { // one of our pointers was NULL. raise an error.
    790             fatal_printf("make_group() NULL group ptr");
    791         }
    792 
    793         curObj = vargObj;
    794         newGroup->memberTypes |= curObj->type;
    795         addto_group(newGroup, vargObj);
    796     }
    797     va_end(args);
    798 
    799     curLink = newGroup->firstMember;
    800     printf("Made group no.%d from: ", newGroup->id);
    801     while (curLink != NULL) {
    802         curObj = curLink->obj;
    803         format_object_id(idStrBuf, curObj);
    804         printf("%s", idStrBuf);
    805         printf("\n");
    806         curLink = curLink->next;
    807     }
    808 
    809     return newGroup;
    810 }
    811 
    812 /**
    813  * Adds the object as a member of the group, placing it at the end of the group's list.
    814  */
    815 void addto_group(struct ObjGroup *group, struct GdObj *obj) {
    816     char strbuf[0x20];
    817     UNUSED u8 filler[8];
    818 
    819     imin("addto_group");
    820 
    821     // Add object to the end of group's member list
    822     if (group->firstMember == NULL) {
    823         group->firstMember = make_link_to_obj(NULL, obj);
    824         group->lastMember = group->firstMember;
    825     } else {
    826         group->lastMember = make_link_to_obj(group->lastMember, obj);
    827     }
    828 
    829     group->memberTypes |= obj->type;
    830     group->memberCount++;
    831 
    832     printf("Added ");
    833     format_object_id(strbuf, obj);
    834     printf("%s", strbuf);
    835     printf(" to ");
    836     format_object_id(strbuf, &group->header);
    837     printf("%s", strbuf);
    838     printf("\n");
    839 
    840     imout();
    841 }
    842 
    843 /**
    844  * Adds the object as a member of the group, placing it at the beginning of the group's list.
    845  */
    846 void addto_groupfirst(struct ObjGroup *group, struct GdObj *obj) {
    847     imin("addto_groupfirst");
    848 
    849     // Add object to the beginning of group's member list
    850     if (group->firstMember == NULL) {
    851         group->firstMember = make_link_to_obj(NULL, obj);
    852         group->lastMember = group->firstMember;
    853     } else {
    854         struct ListNode *newNode = make_link_to_obj(NULL, obj);
    855         group->firstMember->prev = newNode;
    856         newNode->next = group->firstMember;
    857         group->firstMember = newNode;
    858     }
    859 
    860     group->memberTypes |= obj->type;
    861     group->memberCount++;
    862 
    863     imout();
    864 }
    865 
    866 /**
    867  * Returns TRUE if `obj` is a member of `group`, or FALSE otherwise
    868  */
    869 s32 group_contains_obj(struct ObjGroup *group, struct GdObj *obj) {
    870     struct ListNode *node = group->firstMember;
    871 
    872     while (node != NULL) {
    873         if (node->obj->index == obj->index) {
    874             return TRUE;
    875         }
    876         node = node->next;
    877     }
    878 
    879     return FALSE;
    880 }
    881 
    882 /**
    883  * Unused (not called) - this shows details about all objects in the main object linked list
    884  */
    885 void show_details(enum ObjTypeFlag type) {
    886     enum ObjTypeFlag curObjType;
    887     struct ListNode *curGroupLink;
    888     struct ObjGroup *curSubGroup;
    889     struct GdObj *curObj;
    890     char idStrBuf[0x24];
    891     s32 curGroupTypes;
    892 
    893     gd_printf("\nDetails about: ");
    894     switch (type) {
    895         case OBJ_TYPE_GROUPS:
    896             gd_printf("Groups\n");
    897             break;
    898         case OBJ_TYPE_BONES:
    899             gd_printf("Bones\n");
    900             break;
    901         case OBJ_TYPE_JOINTS:
    902             gd_printf("Joints\n");
    903             break;
    904         case OBJ_TYPE_PARTICLES:
    905             gd_printf("Particles\n");
    906             break;
    907         default:
    908             gd_printf("Everything?\n");
    909             break;
    910     }
    911 
    912     curObj = gGdObjectList;
    913     while (curObj != NULL) {
    914         curObjType = curObj->type;
    915         if (curObjType == type) {
    916             format_object_id(idStrBuf, curObj);
    917             switch (curObjType) {
    918                 case OBJ_TYPE_GROUPS:
    919                     gd_printf("Group %s: ", idStrBuf);
    920                     curGroupTypes = ((struct ObjGroup *) curObj)->memberTypes;
    921 
    922                     if (curGroupTypes & OBJ_TYPE_GROUPS) {
    923                         gd_printf("groups ");
    924                     }
    925                     if (curGroupTypes & OBJ_TYPE_BONES) {
    926                         gd_printf("bones ");
    927                     }
    928                     if (curGroupTypes & OBJ_TYPE_JOINTS) {
    929                         gd_printf("joints ");
    930                     }
    931                     if (curGroupTypes & OBJ_TYPE_PARTICLES) {
    932                         gd_printf("particles ");
    933                     }
    934                     if (curGroupTypes & OBJ_TYPE_CAMERAS) {
    935                         gd_printf("cameras ");
    936                     }
    937                     if (curGroupTypes & OBJ_TYPE_NETS) {
    938                         gd_printf("nets ");
    939                     }
    940                     if (curGroupTypes & OBJ_TYPE_GADGETS) {
    941                         gd_printf("gadgets ");
    942                     }
    943                     if (curGroupTypes & OBJ_TYPE_LABELS) {
    944                         gd_printf("labels ");
    945                     }
    946                     if (curGroupTypes & OBJ_TYPE_FACES) {
    947                         gd_printf("face ");
    948                     }
    949                     if (curGroupTypes & OBJ_TYPE_VERTICES) {
    950                         gd_printf("vertex ");
    951                     }
    952 
    953                     curGroupLink = ((struct ObjGroup *) curObj)->firstMember;
    954                     while (curGroupLink != NULL) {
    955                         format_object_id(idStrBuf, curGroupLink->obj);
    956                         gd_printf("%s", idStrBuf);
    957                         curGroupLink = curGroupLink->next;
    958                     }
    959                     gd_printf("\n");
    960                     break;
    961                 case OBJ_TYPE_BONES:
    962                     gd_printf("Bone %s: ", idStrBuf);
    963                     curSubGroup = ((struct ObjBone *) curObj)->unk10C;
    964                     curGroupLink = curSubGroup->firstMember;
    965                     while (curGroupLink != NULL) {
    966                         format_object_id(idStrBuf, curGroupLink->obj);
    967                         gd_printf("%s", idStrBuf);
    968                         curGroupLink = curGroupLink->next;
    969                     }
    970                     gd_printf("\n");
    971                     break;
    972                 case OBJ_TYPE_JOINTS:
    973                     gd_printf("Joint %s: ", idStrBuf);
    974                     curSubGroup = ((struct ObjJoint *) curObj)->unk1C4;
    975                     curGroupLink = curSubGroup->firstMember;
    976                     while (curGroupLink != NULL) {
    977                         format_object_id(idStrBuf, curGroupLink->obj);
    978                         gd_printf("%s", idStrBuf);
    979                         curGroupLink = curGroupLink->next;
    980                     }
    981                     gd_printf("\n");
    982                     break;
    983                 default:;
    984             }
    985         }
    986         curObj = curObj->next;
    987     }
    988 }
    989 
    990 /* @ 22C9B8 for 0x24 */
    991 s32 stub_objects_2(void) {
    992     s32 sp4 = 0;
    993     return sp4;
    994 }
    995 
    996 /**
    997  * Unused - called by __main__
    998  */
    999 s32 make_scene(void) {
   1000     s32 sp4 = 0;
   1001     return sp4;
   1002 }
   1003 
   1004 /* @ 22CA00 for 0x88 */
   1005 static void reset_joint_or_net(struct GdObj *obj) {
   1006     struct GdObj *localObjPtr = obj;
   1007 
   1008     switch (obj->type) {
   1009         case OBJ_TYPE_JOINTS:
   1010             reset_joint((struct ObjJoint *) localObjPtr);
   1011             break;
   1012         case OBJ_TYPE_NETS:
   1013             reset_net((struct ObjNet *) localObjPtr);
   1014             break;
   1015         default:;
   1016     }
   1017 }
   1018 
   1019 /**
   1020  * called when the user clicks the "Reset Positions" item from the
   1021  * "Dynamics" menu.
   1022  */
   1023 void menu_cb_reset_positions(void) {
   1024     apply_to_obj_types_in_group(OBJ_TYPE_NETS, (applyproc_t) reset_joint_or_net, sCurrentMoveGrp);
   1025 }
   1026 
   1027 /**
   1028  * Unused (not called) - does nothing useful
   1029  */
   1030 struct GdObj *func_8017E2F0(struct GdObj *obj, enum ObjTypeFlag type) {
   1031     UNUSED u8 filler[4];
   1032     enum ObjTypeFlag curObjType;
   1033     struct ListNode *node;
   1034 
   1035     curObjType = obj->type;
   1036 
   1037     switch (curObjType) {
   1038         case OBJ_TYPE_GROUPS:
   1039             node = ((struct ObjGroup *) obj)->firstMember;
   1040             while (node != NULL) {
   1041                 func_8017E2F0(node->obj, type);
   1042                 node = node->next;
   1043             }
   1044             break;
   1045         case OBJ_TYPE_BONES:
   1046             break;
   1047         default:;
   1048     }
   1049 
   1050     if (curObjType == type) {
   1051         return obj;
   1052     }
   1053 
   1054 //! @bug Nothing is returned if a GdObj of `type` is not found
   1055 #ifdef AVOID_UB
   1056     return NULL;
   1057 #endif
   1058 }
   1059 
   1060 /**
   1061  * Recursively calls `func` on all members of `group` whose type is in the
   1062  * `types` bitmask.
   1063  * Returns the number of objects this function was called on.
   1064  */
   1065 s32 apply_to_obj_types_in_group(s32 types, applyproc_t func, struct ObjGroup *group) {
   1066     struct ListNode *curLink;
   1067     struct ListNode *nextLink;
   1068     struct GdObj *linkedObj;
   1069     enum ObjTypeFlag linkedObjType;
   1070     applyproc_t objFn;
   1071     UNUSED u8 filler[32];
   1072     s32 fnAppliedCount;
   1073 
   1074     fnAppliedCount = 0;
   1075 
   1076     //! @bug When `group` pointer is NULL, garbage is returned, not the
   1077     //!      count of `fn` calls
   1078     if (group == NULL) {
   1079 #ifdef AVOID_UB
   1080         return fnAppliedCount;
   1081 #else
   1082         return;
   1083 #endif
   1084     }
   1085 
   1086     if (group->linkType & 1) { // compressed data, not an Obj
   1087         return fnAppliedCount;
   1088     }
   1089 
   1090     if (!((group->memberTypes & OBJ_TYPE_GROUPS) | (group->memberTypes & types))) {
   1091         return fnAppliedCount;
   1092     }
   1093 
   1094     objFn = func;
   1095     curLink = group->firstMember;
   1096 
   1097     while (curLink != NULL) {
   1098         linkedObj = curLink->obj;
   1099         linkedObjType = linkedObj->type;
   1100         nextLink = curLink->next;
   1101 
   1102         if (linkedObjType == OBJ_TYPE_GROUPS) {
   1103             fnAppliedCount += apply_to_obj_types_in_group(types, func, (struct ObjGroup *) linkedObj);
   1104         }
   1105 
   1106         if (linkedObjType & types) {
   1107             (*objFn)(linkedObj);
   1108             fnAppliedCount++;
   1109         }
   1110 
   1111         curLink = nextLink;
   1112     }
   1113     return fnAppliedCount;
   1114 }
   1115 
   1116 /* @ 22CD54 for 0x2B4 */
   1117 void func_8017E584(struct ObjNet *a0, struct GdVec3f *a1, struct GdVec3f *a2) {
   1118     struct GdVec3f sp94;
   1119     struct GdVec3f sp88;
   1120     struct GdVec3f sp7C;
   1121     struct GdVec3f sp70;
   1122     UNUSED u8 filler1[64]; // unused MyMatrix4x4? f32[4][4]
   1123     f32 sp2C;
   1124     UNUSED u8 filler2[4];
   1125     struct GdVec3f sp1C;
   1126 
   1127     sp70.x = a2->x;
   1128     sp70.y = a2->y;
   1129     sp70.z = a2->z;
   1130 
   1131     gd_normalize_vec3f(&sp70);
   1132 
   1133     sp7C.x = a1->x;
   1134     sp7C.y = a1->y;
   1135     sp7C.z = a1->z;
   1136 
   1137     sp1C.x = a0->centerOfGravity.x;
   1138     sp1C.y = a0->centerOfGravity.y;
   1139     sp1C.z = a0->centerOfGravity.z;
   1140 
   1141     gd_rotate_and_translate_vec3f(&sp1C, &a0->mat128);
   1142 
   1143     sp7C.x -= sp1C.x;
   1144     sp7C.y -= sp1C.y;
   1145     sp7C.z -= sp1C.z;
   1146 
   1147     if (gd_normalize_vec3f(&sp7C) == FALSE) {
   1148         sp7C.x = -sp70.x;
   1149         sp7C.y = -sp70.y;
   1150         sp7C.z = -sp70.z;
   1151     }
   1152 
   1153     gd_cross_vec3f(&sp70, a1, &sp94);
   1154     sp2C = (f32) gd_sqrt_d((sp94.x * sp94.x) + (sp94.z * sp94.z));
   1155 
   1156     if (sp2C > 1000.0) { //? 1000.0f
   1157         sp2C = 1000.0f;
   1158     }
   1159 
   1160     sp2C /= 1000.0;    //? 1000.0f
   1161     sp2C = 1.0 - sp2C; //? 1.0f - sp2C
   1162 
   1163     sp88.x = a2->x * sp2C;
   1164     sp88.y = a2->y * sp2C;
   1165     sp88.z = a2->z * sp2C;
   1166 
   1167     a0->collDisp.x += sp88.x;
   1168     a0->collDisp.y += sp88.y;
   1169     a0->collDisp.z += sp88.z;
   1170 }
   1171 
   1172 /* @ 22D008 for 0x1B4 */
   1173 void func_8017E838(struct ObjNet *a0, struct GdVec3f *a1, struct GdVec3f *a2) {
   1174     UNUSED u8 filler1[12];
   1175     struct GdVec3f sp70;
   1176     struct GdVec3f sp64;
   1177     UNUSED u8 filler2[64];
   1178     struct GdVec3f sp18;
   1179 
   1180     sp64.x = a1->x;
   1181     sp64.y = a1->y;
   1182     sp64.z = a1->z;
   1183 
   1184     sp18.x = a0->centerOfGravity.x;
   1185     sp18.y = a0->centerOfGravity.y;
   1186     sp18.z = a0->centerOfGravity.z;
   1187 
   1188     gd_rotate_and_translate_vec3f(&sp18, &a0->mat128);
   1189 
   1190     sp64.x -= sp18.x;
   1191     sp64.y -= sp18.y;
   1192     sp64.z -= sp18.z;
   1193 
   1194     sp64.x *= 0.01; //? 0.01f;
   1195     sp64.y *= 0.01; //? 0.01f;
   1196     sp64.z *= 0.01; //? 0.01f;
   1197 
   1198     gd_cross_vec3f(a2, &sp64, &sp70);
   1199     gd_clamp_vec3f(&sp70, 5.0f);
   1200 
   1201     a0->collTorque.x += sp70.x;
   1202     a0->collTorque.y += sp70.y;
   1203     a0->collTorque.z += sp70.z;
   1204 }
   1205 
   1206 /* @ 22D1BC for 0xA8 */
   1207 void func_8017E9EC(struct ObjNet *net) {
   1208     struct GdVec3f sp5C;
   1209     Mat4f sp1C;
   1210     f32 sp18;
   1211 
   1212     sp5C.x = net->torque.x;
   1213     sp5C.y = net->torque.y;
   1214     sp5C.z = net->torque.z;
   1215 
   1216     gd_normalize_vec3f(&sp5C);
   1217     sp18 = gd_vec3f_magnitude(&net->torque);
   1218     gd_create_rot_mat_angular(&sp1C, &sp5C, -sp18);
   1219     gd_mult_mat4f(&D_801B9DC8, &sp1C, &D_801B9DC8);
   1220 }
   1221 
   1222 /**
   1223  * Unused (not called)
   1224  */
   1225 s32 func_8017EA94(struct GdVec3f *vec, Mat4f matrix) {
   1226     if (vec->x >= matrix[2][2] && vec->x <= matrix[3][1] && vec->z >= matrix[3][0]
   1227         && vec->z <= matrix[3][3]) {
   1228         return 1;
   1229     }
   1230 
   1231     return 0;
   1232 }
   1233 
   1234 /**
   1235  * Unused (not called)
   1236  */
   1237 s32 func_8017EB24(struct GdObj *obj1, struct GdObj *obj2) {
   1238     struct GdVec3f pos1;
   1239     struct GdVec3f pos2;
   1240     struct GdBoundingBox *bbox1;
   1241     struct GdBoundingBox *bbox2;
   1242     struct GdBoundingBox sp18;
   1243 
   1244     set_cur_dynobj(obj1);
   1245     d_get_world_pos(&pos1);
   1246     bbox1 = d_get_bounding_box();
   1247 
   1248     set_cur_dynobj(obj2);
   1249     d_get_world_pos(&pos2);
   1250     bbox2 = d_get_bounding_box();
   1251 
   1252     // bbox2 is an offset for bbox1?
   1253     sp18.minX = bbox1->minX + bbox2->minX;
   1254     sp18.minY = bbox1->minY + bbox2->minY;
   1255     sp18.minZ = bbox1->minZ + bbox2->minZ;
   1256     sp18.maxX = bbox1->maxX + bbox2->maxX;
   1257     sp18.maxY = bbox1->maxY + bbox2->maxY;
   1258     sp18.maxZ = bbox1->maxZ + bbox2->maxZ;
   1259 
   1260     D_801B9E08.x = pos2.x - pos1.x;
   1261     D_801B9E08.y = pos2.y - pos1.y;
   1262     D_801B9E08.z = pos2.z - pos1.z;
   1263 
   1264     if (D_801B9E08.x >= sp18.minX) {
   1265         if (D_801B9E08.x <= sp18.maxX) {
   1266             if (D_801B9E08.z >= sp18.minZ) {
   1267                 if (D_801B9E08.z <= sp18.maxZ) {
   1268                     return TRUE;
   1269                 }
   1270             }
   1271         }
   1272     }
   1273 
   1274     return FALSE;
   1275 }
   1276 
   1277 /**
   1278  * Unused (not called)
   1279  */
   1280 s32 is_obj_xz_in_bounding_box(struct GdObj *obj, struct GdBoundingBox *bbox) {
   1281     struct GdVec3f pos;
   1282 
   1283     set_cur_dynobj(obj);
   1284     d_get_world_pos(&pos);
   1285 
   1286     if (pos.x >= bbox->minX) {
   1287         if (pos.x <= bbox->maxX) {
   1288             if (pos.z >= bbox->minZ) {
   1289                 if (pos.z <= bbox->maxZ) {
   1290                     return TRUE;
   1291                 }
   1292             }
   1293         }
   1294     }
   1295 
   1296     return FALSE;
   1297 }
   1298 
   1299 /**
   1300  * Unused (not called)
   1301  */
   1302 s32 is_point_xz_in_bounding_box(struct GdVec3f *point, struct GdBoundingBox *bbox) {
   1303     if (point->x >= bbox->minX) {
   1304         if (point->x <= bbox->maxX) {
   1305             if (point->z >= bbox->minZ) {
   1306                 if (point->z <= bbox->maxZ) {
   1307                     return TRUE;
   1308                 }
   1309             }
   1310         }
   1311     }
   1312 
   1313     return FALSE;
   1314 }
   1315 
   1316 /**
   1317  * Unused (called by func_801A71CC) - returns TRUE if any of the four corners of
   1318  * box1's X-Z plane lie within box2's X-Z plane
   1319  */
   1320 s32 gd_plane_point_within(struct GdBoundingBox *box1, struct GdBoundingBox *box2) {
   1321     // test if min x and min z of box1 are within box2
   1322     if (box1->minX >= box2->minX) {
   1323         if (box1->minX <= box2->maxX) {
   1324             if (box1->minZ >= box2->minZ) {
   1325                 if (box1->minZ <= box2->maxZ) {
   1326                     return TRUE;
   1327                 }
   1328             }
   1329         }
   1330     }
   1331 
   1332     // test if max x and min z of box1 are within box2
   1333     if (box1->maxX >= box2->minX) {
   1334         if (box1->maxX <= box2->maxX) {
   1335             if (box1->minZ >= box2->minZ) {
   1336                 if (box1->minZ <= box2->maxZ) {
   1337                     return TRUE;
   1338                 }
   1339             }
   1340         }
   1341     }
   1342 
   1343     // test if max x and max z of box1 are within box2
   1344     if (box1->maxX >= box2->minX) {
   1345         if (box1->maxX <= box2->maxX) {
   1346             if (box1->maxZ >= box2->minZ) {
   1347                 if (box1->maxZ <= box2->maxZ) {
   1348                     return TRUE;
   1349                 }
   1350             }
   1351         }
   1352     }
   1353 
   1354     // test if min x and max z of box1 are within box2
   1355     if (box1->minX >= box2->minX) {
   1356         if (box1->minX <= box2->maxX) {
   1357             if (box1->maxZ >= box2->minZ) {
   1358                 if (box1->maxZ <= box2->maxZ) {
   1359                     return TRUE;
   1360                 }
   1361             }
   1362         }
   1363     }
   1364 
   1365     return FALSE;
   1366 }
   1367 
   1368 /* @ 22D824 for 0x1BC */
   1369 s32 transform_child_objects_recursive(struct GdObj *obj, struct GdObj *parentObj) {
   1370     struct ListNode *curLink;
   1371     struct ObjGroup *curGroup;
   1372     UNUSED u8 filler1[4];
   1373     Mat4f *parentUnkMtx;
   1374     Mat4f *iMtx;
   1375     Mat4f *unkMtx;
   1376     Mat4f *rotMtx;
   1377     Mat4f *rotMtx2;
   1378     UNUSED u8 filler2[24];
   1379     struct GdVec3f scale;
   1380 
   1381     if (parentObj != NULL) {
   1382         set_cur_dynobj(parentObj);
   1383         parentUnkMtx = d_get_matrix_ptr();
   1384         rotMtx = (Mat4f *) d_get_rot_mtx_ptr();
   1385 
   1386         set_cur_dynobj(obj);
   1387         iMtx = d_get_i_mtx_ptr();
   1388         rotMtx2 = (Mat4f *) d_get_rot_mtx_ptr();
   1389 
   1390         d_get_scale(&scale);
   1391 
   1392         unkMtx = d_get_matrix_ptr();
   1393         gd_mult_mat4f(iMtx, parentUnkMtx, unkMtx);
   1394 
   1395         gd_mult_mat4f(iMtx, rotMtx, rotMtx2);
   1396         gd_scale_mat4f_by_vec3f(rotMtx2, &scale);
   1397     } else {
   1398         set_cur_dynobj(obj);
   1399         unkMtx = d_get_matrix_ptr();
   1400         iMtx = d_get_i_mtx_ptr();
   1401         rotMtx = (Mat4f *) d_get_rot_mtx_ptr();
   1402 
   1403         d_get_scale(&scale);
   1404         gd_set_identity_mat4(unkMtx);
   1405         gd_copy_mat4f(iMtx, rotMtx);
   1406         gd_scale_mat4f_by_vec3f(rotMtx, &scale);
   1407     }
   1408 
   1409     // Recursively call this function on attached children
   1410     set_cur_dynobj(obj);
   1411     curGroup = d_get_att_objgroup();
   1412     if (curGroup != NULL) {
   1413         curLink = curGroup->firstMember;
   1414         while (curLink != NULL) {
   1415             transform_child_objects_recursive(curLink->obj, obj);
   1416             curLink = curLink->next;
   1417         }
   1418     }
   1419     return 0;
   1420 }
   1421 
   1422 /* @ 22D9E0 for 0x1BC */
   1423 s32 func_8017F210(struct GdObj *a0, struct GdObj *a1) {
   1424     struct ListNode *sp6C;
   1425     struct ObjGroup *sp68;
   1426     UNUSED u8 filler1[4];
   1427     UNUSED Mat4f *sp60;
   1428     Mat4f *sp5C;
   1429     UNUSED Mat4f *sp58;
   1430     Mat4f *sp54;
   1431     Mat4f *sp50;
   1432     UNUSED u8 filler2[24];
   1433     struct GdVec3f sp2C;
   1434     s32 count = 0;
   1435 
   1436     count++;
   1437 
   1438     if (a1 != NULL) {
   1439         set_cur_dynobj(a1);
   1440         sp60 = d_get_matrix_ptr();
   1441         sp54 = (Mat4f *) d_get_rot_mtx_ptr();
   1442 
   1443         set_cur_dynobj(a0);
   1444         sp5C = d_get_i_mtx_ptr();
   1445         sp50 = (Mat4f *) d_get_rot_mtx_ptr();
   1446 
   1447         d_get_scale(&sp2C);
   1448         gd_mult_mat4f(sp5C, sp54, sp50);
   1449         gd_scale_mat4f_by_vec3f(sp50, &sp2C);
   1450     } else {
   1451         set_cur_dynobj(a0);
   1452         sp58 = d_get_matrix_ptr();
   1453         sp5C = d_get_i_mtx_ptr();
   1454         sp54 = (Mat4f *) d_get_rot_mtx_ptr();
   1455 
   1456         d_get_scale(&sp2C);
   1457         gd_copy_mat4f(sp5C, sp54);
   1458         gd_scale_mat4f_by_vec3f(sp54, &sp2C);
   1459     }
   1460 
   1461     set_cur_dynobj(a0);
   1462     sp68 = d_get_att_objgroup();
   1463 
   1464     if (sp68 != NULL) {
   1465         sp6C = sp68->firstMember;
   1466         while (sp6C != NULL) {
   1467             count += func_8017F210(sp6C->obj, a0);
   1468             sp6C = sp6C->next;
   1469         }
   1470     }
   1471     return count;
   1472 }
   1473 
   1474 /* @ 22DB9C for 0x38; a0 might be ObjUnk200000* */
   1475 void func_8017F3CC(struct Unk8017F3CC *a0) {
   1476     gd_rotate_and_translate_vec3f(&a0->unk20, D_801B9E48);
   1477 }
   1478 
   1479 /* @ 22DBD4 for 0x20 */
   1480 void stub_objects_3(UNUSED f32 a0, UNUSED struct GdObj *a1, UNUSED struct GdObj *a2) {
   1481     UNUSED u8 filler[48];
   1482 }
   1483 
   1484 /**
   1485  * Interpolates between animation transformations `t1` and `t2`, with `dt` as
   1486  * the interpolation factor (between 0 and 1). Sets the current dynobj's matrix
   1487  * as the result of the transformation.
   1488  */
   1489 void interpolate_animation_transform(struct GdAnimTransform *t1, struct GdAnimTransform *t2, f32 dt) {
   1490     Mat4f mtx;
   1491 
   1492     gd_set_identity_mat4(&mtx);
   1493 
   1494     if (dt != 0.0f) {
   1495         struct GdAnimTransform transform;
   1496 
   1497         // interpolate rotation between t1 and t2
   1498         transform.rotate.x = t1->rotate.x + (t2->rotate.x - t1->rotate.x) * dt;
   1499         transform.rotate.y = t1->rotate.y + (t2->rotate.y - t1->rotate.y) * dt;
   1500         transform.rotate.z = t1->rotate.z + (t2->rotate.z - t1->rotate.z) * dt;
   1501 
   1502         // interpolate position between t1 and t2
   1503         transform.pos.x = t1->pos.x + (t2->pos.x - t1->pos.x) * dt;
   1504         transform.pos.y = t1->pos.y + (t2->pos.y - t1->pos.y) * dt;
   1505         transform.pos.z = t1->pos.z + (t2->pos.z - t1->pos.z) * dt;
   1506 
   1507         // not going to interpolate scale?
   1508 
   1509         gd_scale_mat4f_by_vec3f(&mtx, &t1->scale);
   1510         gd_rot_mat_about_vec(&mtx, &transform.rotate);
   1511         gd_add_vec3f_to_mat4f_offset(&mtx, &transform.pos);
   1512     } else {
   1513         d_set_scale(t1->scale.x, t1->scale.y, t1->scale.z);
   1514         gd_rot_mat_about_vec(&mtx, &t1->rotate);
   1515         gd_add_vec3f_to_mat4f_offset(&mtx, &t1->pos);
   1516     }
   1517     d_set_i_matrix(&mtx);
   1518 }
   1519 
   1520 /* @ 22DD94 for 0x1060; orig name: func_8017F5C4 */
   1521 void move_animator(struct ObjAnimator *animObj) {
   1522     struct AnimDataInfo *animData; // array?
   1523     Mat4f *mtxArr;
   1524     Mat4f localMtx;
   1525     struct GdAnimTransform *triPtr;
   1526     struct GdAnimTransform currTransform;  // transformation for the current keyframe
   1527     struct GdAnimTransform nextTransform;  // transformation for the next keyframe
   1528     s16(*animData9s16)[9];              // GdTriangleH[]?
   1529     s16(*animData3s16)[3];             // MyVec3h[]?
   1530     s16(*animData6s16)[6];            // GdPlaneH[]?
   1531     s16(*animDataCam)[6];         // camera GdPlaneH[]?
   1532     struct GdObj *stubObj1 = NULL; // used only for call to stubbed function
   1533     struct GdObj *stubObj2 = NULL; // used only for call to stubbed function
   1534     UNUSED u8 filler[12];
   1535     UNUSED struct GdVec3f unusedVec;
   1536     s32 currKeyFrame;
   1537     s32 nextKeyFrame;
   1538     f32 dt;
   1539     f32 scale = 0.1f;
   1540     struct AnimMtxVec *sp28;
   1541     register struct ListNode *link;
   1542     struct GdObj *linkedObj;
   1543 
   1544     if (animObj->controlFunc != NULL) {
   1545         animObj->controlFunc(animObj);
   1546     }
   1547 
   1548     if (animObj->animatedPartsGrp == NULL) {
   1549         return;  // nothing to animate
   1550     }
   1551 
   1552     animData = (struct AnimDataInfo *) animObj->animdataGrp->firstMember->obj;
   1553 
   1554     if (animObj->attachedToObj != NULL) {
   1555         animObj->frame = ((struct ObjAnimator *) animObj->attachedToObj)->frame
   1556                          / ((struct ObjAnimator *) animObj->attachedToObj)->unk24;
   1557         animData += ((struct ObjAnimator *) animObj->attachedToObj)->animSeqNum;
   1558     }
   1559 
   1560     if (animData->type == 0) {
   1561         return;
   1562     }
   1563 
   1564     unusedVec.x = 4.0f;
   1565     unusedVec.y = 1.0f;
   1566     unusedVec.z = 1.0f;
   1567 
   1568     if (animObj->frame > (f32) animData->count) {
   1569         animObj->frame = 1.0f;
   1570     } else if (animObj->frame < 0.0f) {
   1571         animObj->frame = (f32) animData->count;
   1572     }
   1573 
   1574     currKeyFrame = (s32) animObj->frame;
   1575     dt = animObj->frame - (f32) currKeyFrame;
   1576     nextKeyFrame = currKeyFrame + 1;
   1577 
   1578     if (nextKeyFrame > animData->count) {
   1579         nextKeyFrame = 1;
   1580     }
   1581 
   1582     // convert frame numbers to zero-indexed
   1583     currKeyFrame--;
   1584     nextKeyFrame--;
   1585 
   1586     link = animObj->animatedPartsGrp->firstMember;
   1587     while (link != NULL) {
   1588         linkedObj = link->obj;
   1589         set_cur_dynobj(linkedObj);
   1590         switch (animData->type) {
   1591             case GD_ANIM_MTX4x4: // data = Mat4f* (f32[4][4])
   1592                 mtxArr = (Mat4f *) animData->data;
   1593                 /* This needs be be un-dereferenced pointer addition to make the registers match */
   1594                 d_set_i_matrix(mtxArr + (s32) animObj->frame);
   1595                 break;
   1596             case GD_ANIM_ROT3S: // data = s16(*)[3] - rotation only
   1597                 animData3s16 = (s16(*)[3]) animData->data;
   1598 
   1599                 // keep current object scale
   1600                 d_get_scale(&currTransform.scale);
   1601                 nextTransform.scale.x = currTransform.scale.x;
   1602                 nextTransform.scale.y = currTransform.scale.y;
   1603                 nextTransform.scale.z = currTransform.scale.z;
   1604 
   1605                 // keep current object position
   1606                 d_get_init_pos(&currTransform.pos);
   1607                 nextTransform.pos.x = currTransform.pos.x;
   1608                 nextTransform.pos.y = currTransform.pos.y;
   1609                 nextTransform.pos.z = currTransform.pos.z;
   1610 
   1611                 // use animation rotation
   1612                 currTransform.rotate.x = (f32) animData3s16[currKeyFrame][0] * scale;
   1613                 currTransform.rotate.y = (f32) animData3s16[currKeyFrame][1] * scale;
   1614                 currTransform.rotate.z = (f32) animData3s16[currKeyFrame][2] * scale;
   1615 
   1616                 nextTransform.rotate.x = (f32) animData3s16[nextKeyFrame][0] * scale;
   1617                 nextTransform.rotate.y = (f32) animData3s16[nextKeyFrame][1] * scale;
   1618                 nextTransform.rotate.z = (f32) animData3s16[nextKeyFrame][2] * scale;
   1619 
   1620                 interpolate_animation_transform(&currTransform, &nextTransform, dt);
   1621                 break;
   1622             case GD_ANIM_POS3S: // data = s16(*)[3] - position only
   1623                 animData3s16 = (s16(*)[3]) animData->data;
   1624 
   1625                 // keep current object scale
   1626                 d_get_scale(&currTransform.scale);
   1627                 nextTransform.scale.x = currTransform.scale.x;
   1628                 nextTransform.scale.y = currTransform.scale.y;
   1629                 nextTransform.scale.z = currTransform.scale.z;
   1630 
   1631                 // keep current object rotation
   1632                 d_get_init_rot(&currTransform.rotate);
   1633                 nextTransform.rotate.x = currTransform.rotate.x;
   1634                 nextTransform.rotate.y = currTransform.rotate.y;
   1635                 nextTransform.rotate.z = currTransform.rotate.z;
   1636 
   1637                 // use animation position
   1638                 currTransform.pos.x = (f32) animData3s16[currKeyFrame][0];
   1639                 currTransform.pos.y = (f32) animData3s16[currKeyFrame][1];
   1640                 currTransform.pos.z = (f32) animData3s16[currKeyFrame][2];
   1641 
   1642                 nextTransform.pos.x = (f32) animData3s16[nextKeyFrame][0];
   1643                 nextTransform.pos.y = (f32) animData3s16[nextKeyFrame][1];
   1644                 nextTransform.pos.z = (f32) animData3s16[nextKeyFrame][2];
   1645 
   1646                 interpolate_animation_transform(&currTransform, &nextTransform, dt);
   1647                 break;
   1648             case GD_ANIM_ROT3S_POS3S: // data = s16(*)[6] - rotation and position
   1649                 animData6s16 = (s16(*)[6]) animData->data;
   1650 
   1651                 // keep current object scale
   1652                 d_get_scale(&currTransform.scale);
   1653                 nextTransform.scale.x  = currTransform.scale.x;
   1654                 nextTransform.scale.y  = currTransform.scale.y;
   1655                 nextTransform.scale.z  = currTransform.scale.z;
   1656 
   1657                 // use animation rotation
   1658                 currTransform.rotate.x = (f32) animData6s16[currKeyFrame][0] * scale;
   1659                 currTransform.rotate.y = (f32) animData6s16[currKeyFrame][1] * scale;
   1660                 currTransform.rotate.z = (f32) animData6s16[currKeyFrame][2] * scale;
   1661 
   1662                 nextTransform.rotate.x = (f32) animData6s16[nextKeyFrame][0] * scale;
   1663                 nextTransform.rotate.y = (f32) animData6s16[nextKeyFrame][1] * scale;
   1664                 nextTransform.rotate.z = (f32) animData6s16[nextKeyFrame][2] * scale;
   1665 
   1666                 // use animation position
   1667                 currTransform.pos.x  = (f32) animData6s16[currKeyFrame][3];
   1668                 currTransform.pos.y  = (f32) animData6s16[currKeyFrame][4];
   1669                 currTransform.pos.z  = (f32) animData6s16[currKeyFrame][5];
   1670 
   1671                 nextTransform.pos.x  = (f32) animData6s16[nextKeyFrame][3];
   1672                 nextTransform.pos.y  = (f32) animData6s16[nextKeyFrame][4];
   1673                 nextTransform.pos.z  = (f32) animData6s16[nextKeyFrame][5];
   1674 
   1675                 interpolate_animation_transform(&currTransform, &nextTransform, dt);
   1676                 break;
   1677             case GD_ANIM_SCALE3S_POS3S_ROT3S: // data = s16(*)[9] - scale, position, and rotation
   1678                 animData9s16 = (s16(*)[9]) animData->data;
   1679 
   1680                 currTransform.scale.x  = (f32) animData9s16[currKeyFrame][0] * scale;
   1681                 currTransform.scale.y  = (f32) animData9s16[currKeyFrame][1] * scale;
   1682                 currTransform.scale.z  = (f32) animData9s16[currKeyFrame][2] * scale;
   1683 
   1684                 currTransform.rotate.x = (f32) animData9s16[currKeyFrame][3] * scale;
   1685                 currTransform.rotate.y = (f32) animData9s16[currKeyFrame][4] * scale;
   1686                 currTransform.rotate.z = (f32) animData9s16[currKeyFrame][5] * scale;
   1687 
   1688                 currTransform.pos.x  = (f32) animData9s16[currKeyFrame][6];
   1689                 currTransform.pos.y  = (f32) animData9s16[currKeyFrame][7];
   1690                 currTransform.pos.z  = (f32) animData9s16[currKeyFrame][8];
   1691 
   1692                 nextTransform.scale.x  = (f32) animData9s16[nextKeyFrame][0] * scale;
   1693                 nextTransform.scale.y  = (f32) animData9s16[nextKeyFrame][1] * scale;
   1694                 nextTransform.scale.z  = (f32) animData9s16[nextKeyFrame][2] * scale;
   1695 
   1696                 nextTransform.rotate.x = (f32) animData9s16[nextKeyFrame][3] * scale;
   1697                 nextTransform.rotate.y = (f32) animData9s16[nextKeyFrame][4] * scale;
   1698                 nextTransform.rotate.z = (f32) animData9s16[nextKeyFrame][5] * scale;
   1699 
   1700                 nextTransform.pos.x  = (f32) animData9s16[nextKeyFrame][6];
   1701                 nextTransform.pos.y  = (f32) animData9s16[nextKeyFrame][7];
   1702                 nextTransform.pos.z  = (f32) animData9s16[nextKeyFrame][8];
   1703 
   1704                 interpolate_animation_transform(&currTransform, &nextTransform, dt);
   1705                 break;
   1706             case GD_ANIM_CAMERA_EYE3S_LOOKAT3S: // s16(*)[6]?
   1707                 if (linkedObj->type == OBJ_TYPE_CAMERAS) {
   1708                     animDataCam = animData->data;
   1709 
   1710                     // eye position
   1711                     currTransform.pos.x = (f32) animDataCam[currKeyFrame][0];
   1712                     currTransform.pos.y = (f32) animDataCam[currKeyFrame][1];
   1713                     currTransform.pos.z = (f32) animDataCam[currKeyFrame][2];
   1714 
   1715                     // lookat position
   1716                     nextTransform.pos.x = (f32) animDataCam[currKeyFrame][3];
   1717                     nextTransform.pos.y = (f32) animDataCam[currKeyFrame][4];
   1718                     nextTransform.pos.z = (f32) animDataCam[currKeyFrame][5];
   1719 
   1720                     ((struct ObjCamera *) linkedObj)->worldPos.x = currTransform.pos.x;
   1721                     ((struct ObjCamera *) linkedObj)->worldPos.y = currTransform.pos.y;
   1722                     ((struct ObjCamera *) linkedObj)->worldPos.z = currTransform.pos.z;
   1723 
   1724                     ((struct ObjCamera *) linkedObj)->lookAt.x = nextTransform.pos.x;
   1725                     ((struct ObjCamera *) linkedObj)->lookAt.y = nextTransform.pos.y;
   1726                     ((struct ObjCamera *) linkedObj)->lookAt.z = nextTransform.pos.z;
   1727                 }
   1728                 break;
   1729             case GD_ANIM_SCALE3F_ROT3F_POS3F: // scale, rotation, and position (as floats)
   1730                 triPtr = (struct GdAnimTransform *) animData->data;
   1731                 interpolate_animation_transform(&triPtr[currKeyFrame], &triPtr[nextKeyFrame], dt);
   1732                 break;
   1733             case GD_ANIM_MTX4x4F_SCALE3F: // AnimMtxVec[]
   1734                 sp28 = &((struct AnimMtxVec *) animData->data)[currKeyFrame];
   1735                 d_set_i_matrix(&sp28->matrix);
   1736                 d_set_scale(sp28->vec.x, sp28->vec.y, sp28->vec.z);
   1737                 break;
   1738             case GD_ANIM_SCALE3F_ROT3F_POS3F_2:  // similar to GD_ANIM_SCALE3F_ROT3F_POS3F, but no interpolation? what matrix does d_set_i_matrix set?
   1739                 triPtr = (struct GdAnimTransform *) animData->data;
   1740                 gd_set_identity_mat4(&localMtx);
   1741                 gd_scale_mat4f_by_vec3f(&localMtx, &triPtr->scale);
   1742                 gd_rot_mat_about_vec(&localMtx, &triPtr->rotate);
   1743                 gd_add_vec3f_to_mat4f_offset(&localMtx, &triPtr->pos);
   1744                 d_set_i_matrix(&localMtx);
   1745                 break;
   1746             case GD_ANIM_STUB:
   1747                 if (stubObj1 == NULL) {
   1748                     stubObj1 = linkedObj;
   1749                 } else {
   1750                     if (stubObj2 == NULL) {
   1751                         stubObj2 = linkedObj;
   1752                         stub_objects_3(animObj->frame, stubObj1, stubObj2);
   1753                     } else {
   1754                         fatal_printf("Too many objects to morph");
   1755                     }
   1756                 }
   1757                 break;
   1758             default:
   1759                 fatal_printf("move_animator(): Unkown animation data type");
   1760         }
   1761         link = link->next;
   1762     }
   1763 }
   1764 
   1765 /* @ 22EDF4 for 0x300; orig name: func_80180624 */
   1766 void drag_picked_object(struct GdObj *inputObj) {
   1767     UNUSED u8 filler1[12];
   1768     struct GdVec3f displacement;
   1769     struct GdVec3f spC4;
   1770     struct GdControl *ctrl;
   1771     Mat4f sp80;
   1772     Mat4f sp40;
   1773     UNUSED u8 filler2[12];
   1774     struct GdObj *obj;
   1775     UNUSED u8 filler3[4];
   1776     f32 dispMag;
   1777 
   1778     ctrl = &gGdCtrl;
   1779 
   1780     if (gViewUpdateCamera == NULL) {
   1781         return;
   1782     }
   1783 
   1784     dispMag = gd_vec3f_magnitude(&gViewUpdateCamera->unk40);
   1785     dispMag /= 1000.0f;
   1786 
   1787     displacement.x = ((f32)(ctrl->csrX - ctrl->dragStartX)) * dispMag;
   1788     displacement.y = ((f32) - (ctrl->csrY - ctrl->dragStartY)) * dispMag;
   1789     displacement.z = 0.0f;
   1790 
   1791     gd_inverse_mat4f(&gViewUpdateCamera->unkE8, &sp40);
   1792     gd_mat4f_mult_vec3f(&displacement, &sp40);
   1793 
   1794     obj = inputObj;
   1795     if ((inputObj->drawFlags & OBJ_PICKED) && gGdCtrl.dragging) {
   1796         gd_play_sfx(GD_SFX_PINCH_FACE);
   1797         // Note: this second sfx won't play, as it is "overwritten" by the first
   1798         if (ABS(ctrl->stickDeltaX) + ABS(ctrl->stickDeltaY) >= 11) {
   1799             gd_play_sfx(GD_SFX_PINCH_FACE_2);
   1800         }
   1801 
   1802         switch (inputObj->type) {
   1803             case OBJ_TYPE_JOINTS:
   1804                 ((struct ObjJoint *) obj)->mat128[3][0] += displacement.x;
   1805                 ((struct ObjJoint *) obj)->mat128[3][1] += displacement.y;
   1806                 ((struct ObjJoint *) obj)->mat128[3][2] += displacement.z;
   1807                 break;
   1808             case OBJ_TYPE_GADGETS:
   1809                 break;
   1810             case OBJ_TYPE_NETS:
   1811                 gd_inverse_mat4f(&((struct ObjNet *) obj)->mat128, &sp80);
   1812                 spC4.x = displacement.x;
   1813                 spC4.y = displacement.y;
   1814                 spC4.z = displacement.z;
   1815 
   1816                 gd_mat4f_mult_vec3f(&spC4, &sp80);
   1817                 ((struct ObjNet *) obj)->matE8[3][0] += displacement.x;
   1818                 ((struct ObjNet *) obj)->matE8[3][1] += displacement.y;
   1819                 ((struct ObjNet *) obj)->matE8[3][2] += displacement.z;
   1820                 break;
   1821             case OBJ_TYPE_PARTICLES:
   1822                 break;
   1823             default:;
   1824         }
   1825     }
   1826 }
   1827 
   1828 /* @ 22F0F4 for 0x50; orig name: func_80180924*/
   1829 void move_animators(struct ObjGroup *group) {
   1830     restart_timer("move_animators");
   1831     apply_to_obj_types_in_group(OBJ_TYPE_ANIMATORS, (applyproc_t) move_animator, group);
   1832     split_timer("move_animators");
   1833 }
   1834 
   1835 /* @ 22F144 for 0x3C; orig name: func_80180974 */
   1836 void find_and_drag_picked_object(struct ObjGroup *group) {
   1837     apply_to_obj_types_in_group(OBJ_TYPE_ALL, (applyproc_t) drag_picked_object, group);
   1838 }
   1839 
   1840 /* @ 22F180 for 0x624; orig name: func_801809B0 */
   1841 void move_camera(struct ObjCamera *cam) {
   1842     struct GdObj *spEC;
   1843     struct GdVec3f spE0;
   1844     struct GdVec3f spD4;
   1845     struct GdVec3f spC8;
   1846     UNUSED u8 filler1[12];
   1847     struct GdVec3f spB0;
   1848     Mat4f sp70;
   1849     UNUSED u8 filler2[64];
   1850     Mat4f *sp2C;
   1851     struct GdControl *ctrl;
   1852 
   1853     ctrl = &gGdCtrl;
   1854     if (!(cam->flags & 0x10)) {
   1855         return;
   1856     }
   1857 
   1858     spE0.x = spE0.y = spE0.z = 0.0f;
   1859     spB0.x = spB0.y = spB0.z = 0.0f;
   1860 
   1861     if ((spEC = cam->unk30) != NULL) {
   1862         set_cur_dynobj(spEC);
   1863         d_get_world_pos(&spE0);
   1864         d_get_matrix(&sp70);
   1865 
   1866         spC8.x = sp70[2][0] - cam->unk58;
   1867         spC8.z = sp70[2][2] - cam->unk60;
   1868 
   1869         cam->unk58 += spC8.x * cam->unk180.y;
   1870         cam->unk60 += spC8.z * cam->unk180.y;
   1871 
   1872         cam->unkA8[2][0] = cam->unk58;
   1873         cam->unkA8[2][1] = 0.0f;
   1874         cam->unkA8[2][2] = cam->unk60;
   1875 
   1876         cam->unkA8[0][0] = cam->unkA8[2][2];
   1877         cam->unkA8[0][1] = 0.0f;
   1878         cam->unkA8[0][2] = -cam->unkA8[2][0];
   1879 
   1880         cam->unkA8[1][0] = 0.0f;
   1881         cam->unkA8[1][1] = 1.0f;
   1882         cam->unkA8[1][2] = 0.0f;
   1883 
   1884         // setting the unkA8 matrix above is pointless, if we're just going to overwrite it with the identity matrix.
   1885         gd_set_identity_mat4(&cam->unkA8);
   1886     } else {
   1887         gd_set_identity_mat4(&cam->unkA8);
   1888     }
   1889 
   1890     sp2C = &cam->unk64;
   1891     if ((cam->flags & CAMERA_FLAG_CONTROLLABLE) != 0) {
   1892         if (ctrl->btnB != FALSE && ctrl->prevFrame->btnB == FALSE) {  // new B press
   1893             cam->zoomLevel++;
   1894             if (cam->zoomLevel > cam->maxZoomLevel) {
   1895                 cam->zoomLevel = 0;
   1896             }
   1897 
   1898             switch (cam->zoomLevel) {
   1899                 case 0:
   1900                     gd_play_sfx(GD_SFX_CAM_ZOOM_IN);
   1901                     break;
   1902                 case 1:
   1903                 case 2:
   1904                     gd_play_sfx(GD_SFX_CAM_ZOOM_OUT);
   1905                     break;
   1906             }
   1907         }
   1908 
   1909         if (ctrl->cleft) {
   1910             cam->unk128.y += cam->unk134.y;
   1911         }
   1912 
   1913         if (ctrl->cright) {
   1914             cam->unk128.y -= cam->unk134.y;
   1915         }
   1916 
   1917         if (ctrl->cup) {
   1918             cam->unk128.x += cam->unk134.x;
   1919         }
   1920 
   1921         if (ctrl->cdown) {
   1922             cam->unk128.x -= cam->unk134.x;
   1923         }
   1924 
   1925         cam->unk128.x = gd_clamp_f32(cam->unk128.x, 80.0f);
   1926 
   1927         cam->unk4C.x = cam->zoomPositions[cam->zoomLevel].x;
   1928         cam->unk4C.y = cam->zoomPositions[cam->zoomLevel].y;
   1929         cam->unk4C.z = cam->zoomPositions[cam->zoomLevel].z;
   1930 
   1931         gd_rot_2d_vec(cam->unk128.x, &cam->unk4C.y, &cam->unk4C.z);
   1932         gd_rot_2d_vec(-cam->unk128.y, &cam->unk4C.x, &cam->unk4C.z);
   1933 
   1934         cam->unk40.x += (cam->unk4C.x - cam->unk40.x) * cam->unk17C;
   1935         cam->unk40.y += (cam->unk4C.y - cam->unk40.y) * cam->unk17C;
   1936         cam->unk40.z += (cam->unk4C.z - cam->unk40.z) * cam->unk17C;
   1937     } else {
   1938         gd_set_identity_mat4(sp2C);
   1939     }
   1940 
   1941     spD4.x = cam->unk40.x;
   1942     spD4.y = cam->unk40.y;
   1943     spD4.z = cam->unk40.z;
   1944 
   1945     spD4.x += spB0.x;
   1946     spD4.y += spB0.y;
   1947     spD4.z += spB0.z;
   1948 
   1949     gd_mult_mat4f(sp2C, &cam->unkA8, &cam->unkA8);
   1950     gd_mat4f_mult_vec3f(&spD4, &cam->unkA8);
   1951 
   1952     cam->worldPos.x = spD4.x;
   1953     cam->worldPos.y = spD4.y;
   1954     cam->worldPos.z = spD4.z;
   1955 
   1956     cam->worldPos.x += spE0.x;
   1957     cam->worldPos.y += spE0.y;
   1958     cam->worldPos.z += spE0.z;
   1959 }
   1960 
   1961 /* @ 22F7A4 for 0x38; orig name: func_80180FD4 */
   1962 void move_cameras_in_grp(struct ObjGroup *group) {
   1963     apply_to_obj_types_in_group(OBJ_TYPE_CAMERAS, (applyproc_t) move_camera, group);
   1964 }
   1965 
   1966 /* @ 22F7DC for 0x36C*/
   1967 void func_8018100C(struct ObjLight *light) {
   1968     Mat4f mtx;
   1969     UNUSED u8 filler[12];
   1970 
   1971     if (light->unk40 == 3) {
   1972         if (light->unk30 > 0.0) { //? 0.0f
   1973             light->unk30 -= 0.2;  //? 0.2f
   1974         }
   1975 
   1976         if (light->unk30 < 0.0f) {
   1977             light->unk30 = 0.0f;
   1978         }
   1979 
   1980         if ((light->unk3C & 0x1) != 0) {
   1981             light->unk30 = 1.0f;
   1982         }
   1983 
   1984         light->unk3C &= ~1;
   1985     }
   1986     // if (1)?
   1987     return;
   1988     // unreachable
   1989     light->position.x += light->unk80.x;
   1990     light->position.y += light->unk80.y;
   1991     light->position.z += light->unk80.z;
   1992 
   1993     // should be position.x for second comparison?
   1994     if (light->position.x > 500.0f || light->position.y < -500.0f) {
   1995         light->unk80.x = -light->unk80.x;
   1996     }
   1997 
   1998     if (light->position.y > 500.0f || light->position.y < -500.0f) {
   1999         light->unk80.y = -light->unk80.y;
   2000     }
   2001 
   2002     if (light->position.z > 500.0f || light->position.z < -500.0f) {
   2003         light->unk80.z = -light->unk80.z;
   2004     }
   2005 
   2006     return;
   2007     // more unreachable
   2008     D_801A81C0 += 1.0; //? 1.0f
   2009     D_801A81C4 += 0.6; //? 0.6f
   2010 
   2011     gd_set_identity_mat4(&mtx);
   2012     gd_absrot_mat4(&mtx, GD_Y_AXIS, light->unk68.y);
   2013     gd_absrot_mat4(&mtx, GD_X_AXIS, light->unk68.x);
   2014     gd_absrot_mat4(&mtx, GD_Z_AXIS, light->unk68.z);
   2015     gd_mat4f_mult_vec3f(&light->unk8C, &mtx);
   2016 
   2017     light->position.x = light->unk8C.x;
   2018     light->position.y = light->unk8C.y;
   2019     light->position.z = light->unk8C.z;
   2020     return;
   2021     // even more unreachable
   2022     gd_mat4f_mult_vec3f(&light->unk80, &mtx);
   2023     imout(); // this call would cause an issue if it was reachable
   2024 }
   2025 
   2026 /* @ 22FB48 for 0x38; orig name: func_80181378 */
   2027 void move_lights_in_grp(struct ObjGroup *group) {
   2028     apply_to_obj_types_in_group(OBJ_TYPE_LIGHTS, (applyproc_t) func_8018100C, group);
   2029 }
   2030 
   2031 /* @ 22FB80 for 0xAC; orig name: func_801813B0 */
   2032 void move_group_members(void) {
   2033     s32 i;
   2034 
   2035     if (gGdMoveScene != 0) {
   2036         reset_gadgets_in_grp(sCurrentMoveGrp);
   2037         move_lights_in_grp(sCurrentMoveGrp);
   2038         move_particles_in_grp(sCurrentMoveGrp);
   2039         move_animators(sCurrentMoveGrp);
   2040 
   2041         for (i = 0; i <= 0; i++) {
   2042             move_nets(sCurrentMoveGrp);
   2043         }
   2044 
   2045         move_cameras_in_grp(sCurrentMoveGrp);
   2046     }
   2047 }
   2048 
   2049 /* @ 22FC2C for 0x98; orig name: func_8018145C */
   2050 void proc_view_movement(struct ObjView *view) {
   2051     imin("movement");
   2052     sCurrentMoveCamera = view->activeCam;
   2053     sCurrentMoveView = view;
   2054     if ((sCurrentMoveGrp = view->components) != NULL) {
   2055         move_group_members();
   2056     }
   2057     if ((sCurrentMoveGrp = view->lights) != NULL) {
   2058         move_group_members();
   2059     }
   2060     imout();
   2061 }
   2062 
   2063 /* @ 22FCC4 for 0x44; orig name: func_801814F4 */
   2064 void reset_nets_and_gadgets(struct ObjGroup *group) {
   2065     func_80193848(group);
   2066     apply_to_obj_types_in_group(OBJ_TYPE_GADGETS, (applyproc_t) reset_gadget, group);
   2067 }
   2068 
   2069 /* @ 22FD08 for 0x9C; orig name: func_80181538*/
   2070 void null_obj_lists(void) {
   2071     D_801B9E44 = 0;
   2072     gGdObjCount = 0;
   2073     gGdGroupCount = 0;
   2074     gGdPlaneCount = 0;
   2075     gGdCameraCount = 0;
   2076     sGdViewInfo.count = 0;
   2077 
   2078     gGdCameraList = NULL;
   2079     D_801B9E50 = NULL;
   2080     gGdBoneList = NULL;
   2081     gGdJointList = NULL;
   2082     gGdGroupList = NULL;
   2083     D_801B9E80 = NULL;
   2084     gGdObjectList = NULL;
   2085     gGdViewsGroup = NULL;
   2086 
   2087     reset_net_count();
   2088     reset_joint_counts();
   2089 }