sm64pc/src/goddard/dynlist_proc.c

3133 lines
104 KiB
C

#include <ultra64.h>
#include <macros.h>
#include <stdio.h>
#include "gd_types.h"
#include "bad_declarations.h"
#include "gd_main.h"
#include "draw_objects.h"
#include "objects.h"
#include "particles.h"
#include "dynlist_proc.h"
#include "old_menu.h"
#include "debug_utils.h"
#include "joints.h"
#include "skin.h"
#include "gd_math.h"
#include "shape_helper.h"
#include "renderer.h"
/**
* @file dynlist_proc.c
*
* Functions for parsing and processing Goddard's DynList object format.
* It also has utility functions for abstracting at runtime over the various
* flavors of `GdObj`s.
*/
// constants
/// Size of the dynamic object name buffer
#define DYNOBJ_NAME_SIZE 8
/// Total number of dynamic `GdObj`s that can be created
#define DYNOBJ_LIST_SIZE 3000
/// Maximum number of verticies supported when adding vertices node to an `ObjShape`
#define VTX_BUF_SIZE 3000
// types
/// Information about a dynamically created `GdObj`
struct DynObjInfo {
char name[DYNOBJ_NAME_SIZE];
struct GdObj *obj;
s32 num;
s32 unk;
};
/// @name DynList Accessors
/// Accessor marcos for easy interpretation of data in a `DynList` packet
///@{
#define Dyn1AsInt(dyn) ((dyn)->w1.word)
#define Dyn1AsPtr(dyn) ((dyn)->w1.ptr)
#define Dyn1AsStr(dyn) ((dyn)->w1.str)
#define Dyn1AsID(dyn) ((DynId)((dyn)->w1.ptr))
#define Dyn2AsInt(dyn) ((dyn)->w2.word)
#define Dyn2AsPtr(dyn) ((dyn)->w2.ptr)
#define Dyn2AsStr(dyn) ((dyn)->w2.str)
#define Dyn2AsID(dyn) ((DynId)((dyn)->w2.ptr))
#define DynVec(dyn) (&(dyn)->vec)
#define DynVecX(dyn) ((dyn)->vec.x)
#define DynVecY(dyn) ((dyn)->vec.y)
#define DynVecZ(dyn) ((dyn)->vec.z)
///@}
// data
static struct DynObjInfo *sGdDynObjList = NULL; // @ 801A8250; info for all loaded/made dynobjs
static struct GdObj *sDynListCurObj = NULL; // @ 801A8254
static struct GdPlaneF sGdNullPlaneF = { // @ 801A8258
{ 0.0, 0.0, 0.0 },
{ 0.0, 0.0, 0.0 }
};
static s32 sGdDynObjIdIsInt = FALSE; // @ 801A8270; str (0) or int (1) for Dyn Obj ID
// bss
static char sIntDynIdBuffer[DYNOBJ_NAME_SIZE]; ///< buffer for returning formated string from
///< `print_int_dynid()`
static struct DynObjInfo sNullDynObjInfo; // @ 801B9F08
static char sDynIdBuf[DYNOBJ_NAME_SIZE]; // @ 801B9F20; small buf for printing dynid to?
static s32
sUnnamedObjCount; // @ 801B9F28; used to print empty string ids (not NULL char *) to sDynIdBuf
static s32 sLoadedDynObjs; // @ 801B9F2C; total loaded dynobjs
static struct DynObjInfo *sDynListCurInfo; // @ 801B9F30; info for most recently added object
static struct DynObjInfo
*sParentNetInfo; ///< Information for `ObjNet` made by `d_add_net_with_subgroup()`
static struct DynObjInfo *sStashedDynObjInfo; // @ 801B9F38
static struct GdObj *sStashedDynObj; // @ 801B9F3C
static s32 sDynNetCount; // @ 801B9F40
static char sDynNetIdBuf[0x20]; // @ 801B9F48
static char sBackBuf[0x100]; // @ 801B9F68
// necessary foreward declarations
void d_add_net_with_subgroup(s32, DynId);
void d_end_net_subgroup(DynId);
void d_attach_joint_to_net(s32, DynId);
void d_addto_group(DynId);
void d_link_with(DynId);
void d_link_with_ptr(void *);
void d_set_normal(f32, f32, f32);
void d_make_vertex(struct GdVec3f *);
void d_set_rotation(f32, f32, f32);
void d_center_of_gravity(f32, f32, f32);
void d_set_shape_offset(f32, f32, f32);
void d_clear_flags(s32);
void d_attach(DynId);
void d_attach_to(s32, struct GdObj *);
void d_attachto_dynid(s32, DynId);
void d_set_att_offset(const struct GdVec3f *);
void d_set_nodegroup(DynId);
void d_set_matgroup(DynId);
void d_set_skinshape(DynId);
void d_set_planegroup(DynId);
void d_set_shapeptr(DynId);
void d_friction(f32, f32, f32);
void d_set_spring(f32);
void d_set_ambient(f32, f32, f32);
void d_set_control_type(s32);
void d_set_skin_weight(s32, f32);
void d_set_id(s32);
void d_set_material(void *, s32);
void d_map_materials(DynId);
void d_map_vertices(DynId);
void d_set_texture_st(f32, f32);
void d_use_texture(void *);
void d_make_netfromshapeid(DynId);
void d_make_netfromshape_ptrptr(struct ObjShape **);
void add_to_dynobj_list(struct GdObj *, DynId);
/**
* Store the active dynamic `GdObj` into a one object stash.
*/
void push_dynobj_stash(void) {
sStashedDynObjInfo = sDynListCurInfo;
sStashedDynObj = sDynListCurObj;
}
/**
* Set the stashed `GdObj` as the active dynamic `GdObj`.
*/
void pop_dynobj_stash(void) {
sDynListCurObj = sStashedDynObj;
sDynListCurInfo = sStashedDynObjInfo;
}
/**
* Reset dynlist related variables to a starting state
*/
void reset_dynlist(void) {
sUnnamedObjCount = 0;
sLoadedDynObjs = 0;
sDynIdBuf[0] = '\0';
sGdDynObjList = NULL;
sDynListCurObj = NULL;
sDynNetCount = 0;
sGdDynObjIdIsInt = FALSE;
gd_strcpy(sNullDynObjInfo.name, "NullObj");
}
/**
* Parse a `DynList` array into active `GdObj`s.
*
* @returns Pointer to current dynamically created dynamic `GdObj`.
* Normally the dynlist specifically sets an object for return.
*/
struct GdObj *proc_dynlist(struct DynList *dylist) {
UNUSED u32 pad[2];
if (dylist++->cmd != 0xD1D4) {
fatal_printf("proc_dynlist() not a valid dyn list");
}
while (dylist->cmd != 58) {
switch (dylist->cmd) {
case 43:
d_copystr_to_idbuf(Dyn1AsStr(dylist));
break;
case 15:
d_makeobj(Dyn2AsInt(dylist), Dyn1AsID(dylist));
break;
case 46:
d_add_net_with_subgroup(Dyn2AsInt(dylist), Dyn1AsID(dylist));
break;
case 48:
d_end_net_subgroup(Dyn1AsID(dylist));
break;
case 47:
d_attach_joint_to_net(Dyn2AsInt(dylist), Dyn1AsID(dylist));
break;
case 16:
d_start_group(Dyn1AsID(dylist));
break;
case 17:
d_end_group(Dyn1AsID(dylist));
break;
case 18:
d_addto_group(Dyn1AsID(dylist));
break;
case 30:
d_use_obj(Dyn1AsID(dylist));
break;
case 28:
d_link_with(Dyn1AsID(dylist));
break;
case 50:
d_add_valptr(Dyn1AsID(dylist), (u32) DynVecY(dylist), Dyn2AsInt(dylist),
(size_t) DynVecX(dylist));
break;
case 29:
d_link_with_ptr(Dyn1AsPtr(dylist));
break;
case 12:
proc_dynlist(Dyn1AsPtr(dylist));
break;
case 0:
dynid_is_int(Dyn2AsInt(dylist));
break;
case 1:
d_set_init_pos(DynVecX(dylist), DynVecY(dylist), DynVecZ(dylist));
break;
case 2:
d_set_rel_pos(DynVecX(dylist), DynVecY(dylist), DynVecZ(dylist));
break;
case 3:
d_set_world_pos(DynVecX(dylist), DynVecY(dylist), DynVecZ(dylist));
break;
case 4:
d_set_normal(DynVecX(dylist), DynVecY(dylist), DynVecZ(dylist));
break;
case 5:
d_set_scale(DynVecX(dylist), DynVecY(dylist), DynVecZ(dylist));
break;
case 49:
d_make_vertex(DynVec(dylist));
break;
case 6:
d_set_rotation(DynVecX(dylist), DynVecY(dylist), DynVecZ(dylist));
break;
case 27:
d_center_of_gravity(DynVecX(dylist), DynVecY(dylist), DynVecZ(dylist));
break;
case 26:
d_set_shape_offset(DynVecX(dylist), DynVecY(dylist), DynVecZ(dylist));
break;
case 44:
d_set_parm_f(Dyn2AsInt(dylist), DynVecX(dylist));
break;
case 45:
d_set_parm_ptr(Dyn2AsInt(dylist), Dyn1AsPtr(dylist));
break;
case 8:
d_set_flags(Dyn2AsInt(dylist));
break;
case 9:
d_clear_flags(Dyn2AsInt(dylist));
break;
case 7:
d_set_obj_draw_flag(Dyn2AsInt(dylist));
break;
case 39:
d_attach(Dyn1AsID(dylist));
break;
case 40:
d_attachto_dynid(Dyn2AsInt(dylist), Dyn1AsID(dylist));
break;
case 41:
d_set_att_offset(DynVec(dylist));
break;
case 21:
d_set_nodegroup(Dyn1AsID(dylist));
break;
case 20:
d_set_matgroup(Dyn1AsID(dylist));
break;
case 22:
d_set_skinshape(Dyn1AsID(dylist));
break;
case 23:
d_set_planegroup(Dyn1AsID(dylist));
break;
case 24:
d_set_shapeptrptr(Dyn1AsPtr(dylist));
break;
case 25:
d_set_shapeptr(Dyn1AsID(dylist));
break;
case 19:
d_set_type(Dyn2AsInt(dylist));
break;
case 13:
d_set_colour_num(Dyn2AsInt(dylist));
break;
case 10:
d_friction(DynVecX(dylist), DynVecY(dylist), DynVecZ(dylist));
break;
case 11:
d_set_spring(DynVecX(dylist));
break;
case 33:
d_set_ambient(DynVecX(dylist), DynVecY(dylist), DynVecZ(dylist));
break;
case 34:
d_set_diffuse(DynVecX(dylist), DynVecY(dylist), DynVecZ(dylist));
break;
case 31:
d_set_control_type(Dyn2AsInt(dylist));
break;
case 32:
d_set_skin_weight(Dyn2AsInt(dylist), DynVecX(dylist));
break;
case 35:
d_set_id(Dyn2AsInt(dylist));
break;
case 36:
d_set_material(Dyn1AsPtr(dylist), Dyn2AsInt(dylist));
break;
case 37:
d_map_materials(Dyn1AsID(dylist));
break;
case 38:
d_map_vertices(Dyn1AsID(dylist));
break;
case 53:
d_set_texture_st(DynVecX(dylist), DynVecY(dylist));
break;
case 52:
d_use_texture(Dyn2AsPtr(dylist));
break;
case 54:
d_make_netfromshapeid(Dyn1AsID(dylist));
break;
case 55:
d_make_netfromshape_ptrptr(Dyn1AsPtr(dylist));
break;
default:
fatal_printf("proc_dynlist(): unkown command");
}
dylist++;
}
return sDynListCurObj;
}
/**
* Copy input `str` into a buffer that will be concatenated to a dynamic
* `GdObj`'s name string when creating a new dynamic object. If input
* is `NULL`, then a generic string is created based on the number of
* unnamed objects.
*/
void d_copystr_to_idbuf(char *str) {
if (str != NULL) {
if (str[0] == '\0') {
sprintf(sDynIdBuf, "__%d", ++sUnnamedObjCount);
} else {
gd_strcpy(sDynIdBuf, str);
}
} else {
sDynIdBuf[0] = '\0';
}
}
/**
* Concatenate input `str` into a buffer that will be concatenated to a dynamic
* `GdObj`'s name string when creating a new dynamic object. If input
* is `NULL`, then a generic string is created based on the number of
* unnamed objects.
*
* @note Not called
*/
void d_catstr_to_idbuf(char *str) {
char buf[0xff + 1];
if (str != NULL) {
if (str[0] == '\0') {
sprintf(buf, "__%d", ++sUnnamedObjCount);
} else {
gd_strcpy(buf, str);
}
} else {
buf[0] = '\0';
}
gd_strcat(sDynIdBuf, buf);
}
/**
* Stash the current string that is appended to a created dynamic `GdObj` name.
*/
void cpy_idbuf_to_backbuf(void) {
gd_strcpy(sBackBuf, sDynIdBuf);
}
/**
* Pop the stash for the string that is appended to a created dynamic `GdObj` name.
*/
void cpy_backbuf_to_idbuf(void) {
gd_strcpy(sDynIdBuf, sBackBuf);
}
/**
* Get the `DynObjInfo` struct for object `id`
*
* @param id Either a string or integer id for a dynamic `GdObj`
* @returns pointer to that object's information
*/
struct DynObjInfo *get_dynobj_info(DynId id) {
struct DynObjInfo *foundDynobj;
char buf[0x100];
s32 i;
if (sLoadedDynObjs == 0) {
return NULL;
}
if (sGdDynObjIdIsInt) {
sprintf(buf, "N%d", DynIdAsInt(id));
} else {
gd_strcpy(buf, DynIdAsStr(id)); // strcpy
}
gd_strcat(buf, sDynIdBuf); // strcat
foundDynobj = NULL;
for (i = 0; i < sLoadedDynObjs; i++) {
if (gd_str_not_equal(sGdDynObjList[i].name, buf) == 0) // strcmp equal
{
foundDynobj = &sGdDynObjList[i];
break;
}
}
return foundDynobj;
}
/**
* Reset the number of created dynamic objects and
* free the dynamic object information list (`sGdDynObjList`).
* The objects themselves still exist, though.
*
* @note Not called
*/
void reset_dynamic_objs(void) {
UNUSED s32 pad;
if (sLoadedDynObjs == 0) {
return;
}
gd_free(sGdDynObjList);
sLoadedDynObjs = 0;
sGdDynObjList = NULL;
}
/**
* Create an `ObjNet` and an associated node `ObjGroup`. This function creates
* its own naming string to append to later created dynamic objects.
*/
void d_add_net_with_subgroup(UNUSED s32 a0, DynId id) {
d_makeobj(D_NET, id);
d_set_obj_draw_flag(OBJ_NOT_DRAWABLE);
// this creates a string to append to the names of the objs created after this
sprintf(sDynNetIdBuf, "c%d", ++sDynNetCount);
d_set_type(4);
cpy_idbuf_to_backbuf();
d_copystr_to_idbuf(sDynNetIdBuf);
d_start_group(id);
cpy_backbuf_to_idbuf();
d_use_obj(id);
sParentNetInfo = sDynListCurInfo;
}
/**
* End the `ObjNet`+`ObjGroup` set created by `d_add_net_with_subgroup()`.
*/
void d_end_net_subgroup(DynId id) {
d_use_obj(id);
cpy_idbuf_to_backbuf();
d_copystr_to_idbuf(sDynNetIdBuf);
d_end_group(id);
d_set_nodegroup(id);
cpy_backbuf_to_idbuf();
sParentNetInfo = NULL;
}
/**
* Create an `ObjJoint` and add that to the `ObjNet` created by
* `d_add_net_with_subgroup()`.
*
* @param arg0 Not used
* @param id Id for created `ObjJoint`
*/
void d_attach_joint_to_net(UNUSED s32 arg0, DynId id) {
UNUSED struct DynObjInfo *curInfo = sDynListCurInfo;
UNUSED u32 pad[2];
d_makeobj(D_JOINT, id);
d_set_type(3);
d_set_shapeptrptr(NULL);
d_attach_to(0xD, sParentNetInfo->obj);
sParentNetInfo = sDynListCurInfo;
}
/**
* Create a new `ObjNet` linked with the dynamic `ObjShape` `id`.
* The newly made net is added to the dynamic object list.
*/
void d_make_netfromshapeid(DynId id) {
struct DynObjInfo *dyninfo = get_dynobj_info(id);
struct ObjNet *net;
if (dyninfo == NULL) {
fatal_printf("dMakeNetFromShape(\"%s\"): Undefined object", DynIdAsStr(id));
}
net = make_netfromshape((struct ObjShape *) dyninfo->obj);
add_to_dynobj_list(&net->header, NULL);
}
/**
* Create a new `ObjNet` linked with the doubly indirected `ObjShape`.
* The newly made net is added to the dynamic object list, but
* the shape is not moved into the dynamic list.
*/
void d_make_netfromshape_ptrptr(struct ObjShape **shapePtr) {
UNUSED u32 pad;
struct ObjNet *net = make_netfromshape(*shapePtr);
printf("dMakeNetFromShapePtrPtr\n");
add_to_dynobj_list(&net->header, NULL);
}
/**
* Add `newobj` identified by `id` to the dynamic `GdObj` list. Once a `GdObj`
* is in the dynamic list, it can referred to by its `id` when that object is
* needed later.
*/
void add_to_dynobj_list(struct GdObj *newobj, DynId id) {
UNUSED u32 pad;
char idbuf[0x100];
start_memtracker("dynlist");
if (sGdDynObjList == NULL) {
sGdDynObjList = gd_malloc_temp(DYNOBJ_LIST_SIZE * sizeof(struct DynObjInfo));
if (sGdDynObjList == NULL) {
fatal_printf("dMakeObj(): Cant allocate dynlist memory");
}
}
stop_memtracker("dynlist");
if (sGdDynObjIdIsInt) {
sprintf(idbuf, "N%d", DynIdAsInt(id));
id = NULL;
} else {
sprintf(idbuf, "U%d", ((u32) sLoadedDynObjs) + 1);
}
if (DynIdAsStr(id) != NULL) {
if (get_dynobj_info(id) != NULL) {
fatal_printf("dMakeObj(\"%s\"): Object with same name already exists", DynIdAsStr(id));
}
gd_strcpy(sGdDynObjList[sLoadedDynObjs].name, DynIdAsStr(id));
} else {
gd_strcpy(sGdDynObjList[sLoadedDynObjs].name, idbuf);
}
gd_strcat(sGdDynObjList[sLoadedDynObjs].name, sDynIdBuf);
if (gd_strlen(sGdDynObjList[sLoadedDynObjs].name) > (DYNOBJ_NAME_SIZE - 1)) {
fatal_printf("dyn list obj name too long '%s'", sGdDynObjList[sLoadedDynObjs].name);
}
sGdDynObjList[sLoadedDynObjs].num = sLoadedDynObjs;
sDynListCurInfo = &sGdDynObjList[sLoadedDynObjs];
sGdDynObjList[sLoadedDynObjs++].obj = newobj;
// A good place to bounds-check your array is
// after you finish writing a new member to it.
if (sLoadedDynObjs >= DYNOBJ_LIST_SIZE) {
fatal_printf("dMakeObj(): Too many dynlist objects");
}
sDynListCurObj = newobj;
}
/**
* Format `id` into string, if `DynId`s are currently being interpreted
* as numbers.
*
* @returns pointer to global buffer for id
* @retval NULL if `id` is `NULL` or if `DynId`s are interpreted as strings
*/
char *print_int_dynid(DynId id) {
if (id && sGdDynObjIdIsInt) {
sprintf(sIntDynIdBuffer, "N%d", DynIdAsInt(id));
return sIntDynIdBuffer;
}
return NULL;
}
/**
* Create a new `GdObj` of `type` and add that object to the
* dynamic object list with `id`. Created objects have default
* parameters, which are usually 0 or NULL.
*
* @returns pointer to created object
*/
struct GdObj *d_makeobj(enum DObjTypes type, DynId id) {
struct GdObj *dobj;
UNUSED struct ObjGroup *dgroup;
switch (type) {
case D_CAR_DYNAMICS:
fatal_printf("dmakeobj() Car dynamics are missing!");
break;
case D_JOINT:
dobj = &make_joint(0, 0.0f, 0.0f, 0.0f)->header;
break;
case D_ANOTHER_JOINT:
dobj = &make_joint(0, 0.0f, 0.0f, 0.0f)->header;
break;
case D_NET:
dobj = &make_net(0, NULL, NULL, NULL, NULL)->header;
break;
case D_GROUP:
dobj = &make_group(0)->header;
dgroup = (struct ObjGroup *) dobj;
break;
case D_DATA_GRP:
d_makeobj(D_GROUP, id);
((struct ObjGroup *) sDynListCurObj)->linkType = 1;
//! @bug Returns garbage when making `D_DATA_GRP` object
#ifdef AVOID_UB
return NULL;
#else
return;
#endif
case D_CAMERA:
dobj = &make_camera(0, NULL)->header;
break;
case D_BONE:
dobj = &make_bone(0, NULL, NULL, 0)->header;
break;
case D_PARTICLE:
dobj = &make_particle(0, 0, 0.0f, 0.0f, 0.0f)->header;
break;
case D_VERTEX:
dobj = &gd_make_vertex(0.0f, 0.0f, 0.0f)->header;
break;
case D_FACE:
dobj = &make_face_with_colour(1.0, 1.0, 1.0)->header;
break;
case D_PLANE:
dobj = &make_plane(FALSE, NULL)->header;
break;
case D_MATERIAL:
dobj = &make_material(0, NULL, 0)->header;
break;
case D_SHAPE:
dobj = &make_shape(0, print_int_dynid(id))->header;
break;
case D_GADGET:
dobj = &make_gadget(0, 0)->header;
break;
case D_LABEL:
//! @bug When making a `D_LABEL`, the call to `make_label()`
//! compiles incorrectly due to Goddard only declaring
//! the functions, not prototyping the functions
dobj = &make_label(NULL, NULL, 8, 0, 0, 0)->header;
break;
case D_VIEW:
dobj = &make_view(NULL,
(VIEW_2_COL_BUF | VIEW_ALLOC_ZBUF | VIEW_UNK_2000 | VIEW_UNK_4000
| VIEW_1_CYCLE | VIEW_MOVEMENT | VIEW_DRAW),
2, 0, 0, 0, 0, NULL)
->header;
break;
case D_ANIMATOR:
dobj = &make_animator()->header;
break;
case D_LIGHT:
dobj = &make_light(0, NULL, 0)->header;
addto_group(gGdLightGroup, dobj);
break;
default:
fatal_printf("dMakeObj(): Unkown object type");
}
add_to_dynobj_list(dobj, id);
return dobj;
}
/**
* Attach dynamic object `id` to the current active `ObjJoint` object.
*
* @note This function doesn't actually do anything.
*/
void d_attach(DynId id) {
struct DynObjInfo *info;
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
info = get_dynobj_info(id);
if (info == NULL) {
fatal_printf("dAttach(\"%s\"): Undefined object", DynIdAsStr(id));
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_JOINTS:
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dAttach()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Attach the current dynamic `GdObj` into the proper subgroup of `obj` and set
* the "attach flags" of the current dynamic object to `flag`
*/
void d_attach_to(s32 flag, struct GdObj *obj) {
UNUSED u32 pad4C;
struct ObjGroup *attgrp;
UNUSED u32 pad[2];
UNUSED struct DynObjInfo *curInfo = sDynListCurInfo;
struct GdVec3f dynobjPos; // transformed into attach offset
struct GdVec3f objPos;
push_dynobj_stash();
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
// find or generate attachment groups
switch (obj->type) {
case OBJ_TYPE_JOINTS:
if ((attgrp = ((struct ObjJoint *) obj)->unk1F8) == NULL) {
attgrp = ((struct ObjJoint *) obj)->unk1F8 = make_group(0);
}
break;
case OBJ_TYPE_NETS:
if ((attgrp = ((struct ObjNet *) obj)->unk1D4) == NULL) {
attgrp = ((struct ObjNet *) obj)->unk1D4 = make_group(0);
}
break;
case OBJ_TYPE_PARTICLES:
if ((attgrp = ((struct ObjParticle *) obj)->unkB4) == NULL) {
attgrp = ((struct ObjParticle *) obj)->unkB4 = make_group(0);
}
break;
case OBJ_TYPE_ANIMATORS:
if ((attgrp = ((struct ObjAnimator *) obj)->unk30) == NULL) {
attgrp = ((struct ObjAnimator *) obj)->unk30 = make_group(0);
}
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dAttachTo()",
sDynListCurInfo->name, sDynListCurObj->type);
}
if (group_contains_obj(attgrp, sDynListCurObj)) {
return;
}
addto_group(attgrp, sDynListCurObj);
if (flag & 9) {
d_get_world_pos(&dynobjPos);
set_cur_dynobj(obj);
d_get_world_pos(&objPos);
dynobjPos.x -= objPos.x;
dynobjPos.y -= objPos.y;
dynobjPos.z -= objPos.z;
}
pop_dynobj_stash();
switch (sDynListCurObj->type) {
case OBJ_TYPE_JOINTS:
((struct ObjJoint *) sDynListCurObj)->unk1FC = flag;
((struct ObjJoint *) sDynListCurObj)->unk20C = obj;
break;
case OBJ_TYPE_NETS:
((struct ObjNet *) sDynListCurObj)->unk1E4 = flag;
((struct ObjNet *) sDynListCurObj)->unk1E8 = obj;
break;
case OBJ_TYPE_PARTICLES:
((struct ObjParticle *) sDynListCurObj)->unkB8 = flag;
((struct ObjParticle *) sDynListCurObj)->unkBC = obj;
break;
case OBJ_TYPE_ANIMATORS:
((struct ObjAnimator *) sDynListCurObj)->unk34 = flag;
((struct ObjAnimator *) sDynListCurObj)->unk44 = obj;
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dAttachTo()",
sDynListCurInfo->name, sDynListCurObj->type);
}
if (flag & 9) {
d_set_att_offset(&dynobjPos);
}
}
/**
* Attach the current dynamic object to dynamic object `id`. This function
* is a wrapper around `d_attach_to()`
*/
void d_attachto_dynid(s32 flag, DynId id) {
struct DynObjInfo *info;
if (id == NULL) {
return;
}
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
info = get_dynobj_info(id);
if (info == NULL) {
fatal_printf("dAttachTo(\"%s\"): Undefined object", DynIdAsStr(id));
}
d_attach_to(flag, info->obj);
}
/**
* Helper function to copy bytes. Where's memcpy when you need it?
*/
void copy_bytes(u8 *src, u8 *dst, s32 num) {
if (num == 0) {
return;
}
while (num--) {
*dst++ = *src++;
}
}
/**
* Allocate the animation data for `animator` onto the goddard heap.
* Animation data of type `::GD_ANIM_9H` is converted to a `AnimMtxVec` struct,
* rather than solely byted copied like the other types.
*/
void alloc_animdata(struct ObjAnimator *animator) {
UNUSED u32 pad5C;
// probably should be three GdVec3fs, not triangle...
// vec0 = position; vec1 = scale? rotation?; vec2 = translation
struct GdTriangleF tri; //+58; temp float for converting half to f32?
s16(*halfarr)[9]; //+54; data to convert into a AnimMtxVec
struct AnimDataInfo *curAnimSrc; //+50; source animation data...
struct AnimDataInfo *animDst; //+4c; destination anim data II
struct AnimDataInfo *animDataArr; //+48; start of allocated anim data memory
struct ObjGroup *animgrp; //+44
s32 datasize; //+40; anim data allocation size?
s32 dataIdx; //+3C; byte count?
s32 animCnt; //+38; count of animdata "info" structs
s32 i; //+34
void *allocSpace; //+30; allocated animdata space
f32 allocMtxScale = 0.1f; //+2C; scale postion/rotation of GD_ANIM_9H data
struct AnimMtxVec *curMtxVec; //+28
UNUSED u32 pad20;
start_memtracker("animdata");
if ((animgrp = animator->animdata) == NULL) {
fatal_printf("no anim group");
}
if ((curAnimSrc = (struct AnimDataInfo *) animgrp->link1C->obj) == NULL) {
fatal_printf("no animation data");
}
// count number of array-ed animation data structs
animDst = curAnimSrc;
animCnt = 0;
while (animDst++->count >= 0) {
animCnt++;
}
animDst = gd_malloc_perm(animCnt * sizeof(struct AnimDataInfo)); // gd_alloc_perm
if ((animDataArr = animDst) == NULL) {
fatal_printf("cant allocate animation data");
}
for (i = 0; i < animCnt; i++) {
allocSpace = NULL;
if (curAnimSrc->type != 0) {
switch (curAnimSrc->type) {
case GD_ANIM_CAMERA:
datasize = sizeof(s16[6]);
break;
case GD_ANIM_3H_SCALED:
datasize = sizeof(s16[3]);
break;
case GD_ANIM_3H:
datasize = sizeof(s16[3]);
break;
case GD_ANIM_6H_SCALED:
datasize = sizeof(s16[6]);
break;
case GD_ANIM_TRI_F_2:
datasize = sizeof(f32[3][3]);
break;
/* This function will convert the s16[9] array into a struct AnimMtxVec */
case GD_ANIM_9H:
datasize = sizeof(struct AnimMtxVec);
break;
case GD_ANIM_MATRIX:
datasize = sizeof(Mat4f);
break;
default:
fatal_printf("unknown anim type for allocation");
break;
}
allocSpace = gd_malloc_perm(curAnimSrc->count * datasize); // gd_alloc_perm
if (allocSpace == NULL) {
fatal_printf("cant allocate animation data");
}
if (curAnimSrc->type == GD_ANIM_9H) {
for (dataIdx = 0; dataIdx < curAnimSrc->count; dataIdx++) {
halfarr = &((s16(*)[9]) curAnimSrc->data)[dataIdx];
curMtxVec = &((struct AnimMtxVec *) allocSpace)[dataIdx];
tri.p0.x = (f32)(*halfarr)[0] * allocMtxScale;
tri.p0.y = (f32)(*halfarr)[1] * allocMtxScale;
tri.p0.z = (f32)(*halfarr)[2] * allocMtxScale;
tri.p1.x = (f32)(*halfarr)[3] * allocMtxScale;
tri.p1.y = (f32)(*halfarr)[4] * allocMtxScale;
tri.p1.z = (f32)(*halfarr)[5] * allocMtxScale;
tri.p2.x = (f32)(*halfarr)[6];
tri.p2.y = (f32)(*halfarr)[7];
tri.p2.z = (f32)(*halfarr)[8];
gd_set_identity_mat4(&curMtxVec->matrix);
gd_rot_mat_about_vec(&curMtxVec->matrix, &tri.p1);
gd_add_vec3f_to_mat4f_offset(&curMtxVec->matrix, &tri.p2);
((struct AnimMtxVec *) allocSpace)[dataIdx].vec.x = tri.p0.x;
((struct AnimMtxVec *) allocSpace)[dataIdx].vec.y = tri.p0.y;
((struct AnimMtxVec *) allocSpace)[dataIdx].vec.z = tri.p0.z;
}
curAnimSrc->type = GD_ANIM_MTX_VEC;
} else {
copy_bytes(curAnimSrc->data, allocSpace, curAnimSrc->count * datasize);
}
}
animDst[i].type = curAnimSrc->type;
animDst[i].count = curAnimSrc->count;
animDst[i].data = allocSpace;
curAnimSrc++; // next anim data struct
}
animgrp->link1C->obj = (void *) animDataArr;
stop_memtracker("animdata");
}
/**
* Generate or create the various `ObjVertex`, `ObjFace`, and/or
* `ObjMaterial` when groups of those structures are attached to
* `shape`. This function is called when `d_set_nodegroup()`,
* `d_set_planegroup()`, or `d_set_matgroup()` are called
* when an `ObjShape` is the active dynamic object.
*
* @note Face/vertices need to be set before materials
*/
void chk_shapegen(struct ObjShape *shape) {
struct ObjFace *face; // sp5C; made face
struct ObjVertex *vtx; // sp58; made gdvtx
struct ObjVertex **vtxbuf; // sp54; heap storage for made gd vtx
struct ObjGroup *shapeMtls; // sp50
struct ObjGroup *shapeFaces; // sp4C
struct ObjGroup *shapeVtx; // sp48
UNUSED u32 pad44;
struct ObjGroup *madeFaces; // sp40
struct ObjGroup *madeVtx; // sp3C
u32 i; // sp38
struct GdVtxData *vtxdata; // sp34
struct GdFaceData *facedata; // sp30
struct GdObj *oldObjHead; // sp2C
start_memtracker("chk_shapegen");
add_to_stacktrace("chk_shapegen");
shapeMtls = shape->mtlGroup;
shapeFaces = shape->faceGroup;
shapeVtx = shape->vtxGroup;
if (shapeVtx != NULL && shapeFaces != NULL) {
if ((shapeVtx->linkType & 1) && (shapeFaces->linkType & 1)) //? needs the double if
{
// These Links point to special, compressed data structures
vtxdata = (struct GdVtxData *) shapeVtx->link1C->obj;
facedata = (struct GdFaceData *) shapeFaces->link1C->obj;
if (facedata->type != 1) {
fatal_printf("unsupported poly type");
}
if (vtxdata->type != 1) {
fatal_printf("unsupported vertex type");
}
if (vtxdata->count >= VTX_BUF_SIZE) {
fatal_printf("shapegen() too many vertices");
}
vtxbuf = gd_malloc_temp(VTX_BUF_SIZE * sizeof(struct ObjVertex *));
oldObjHead = gGdObjectList;
for (i = 0; i < vtxdata->count; i++) {
vtx = gd_make_vertex(vtxdata->data[i][0], vtxdata->data[i][1], vtxdata->data[i][2]);
vtx->normal.x = vtx->normal.y = vtx->normal.z = 0.0f;
vtxbuf[i] = vtx;
}
madeVtx = make_group_of_type(OBJ_TYPE_VERTICES, oldObjHead, NULL);
oldObjHead = gGdObjectList;
for (i = 0; i < facedata->count; i++) {
//! @bug Call to `make_face_with_colour()` compiles incorrectly
//! due to Goddard only declaring the functions,
//! not prototyping the functions
face = make_face_with_colour(1.0, 1.0, 1.0);
face->mtlId = (s32) facedata->data[i][0];
add_3_vtx_to_face(face, vtxbuf[facedata->data[i][1]], vtxbuf[facedata->data[i][2]],
vtxbuf[facedata->data[i][3]]);
vtxbuf[facedata->data[i][1]]->normal.x += face->normal.x;
vtxbuf[facedata->data[i][1]]->normal.y += face->normal.y;
vtxbuf[facedata->data[i][1]]->normal.z += face->normal.z;
vtxbuf[facedata->data[i][2]]->normal.x += face->normal.x;
vtxbuf[facedata->data[i][2]]->normal.y += face->normal.y;
vtxbuf[facedata->data[i][2]]->normal.z += face->normal.z;
vtxbuf[facedata->data[i][3]]->normal.x += face->normal.x;
vtxbuf[facedata->data[i][3]]->normal.y += face->normal.y;
vtxbuf[facedata->data[i][3]]->normal.z += face->normal.z;
}
if (shape->flag & 0x10) {
for (i = 0; i < vtxdata->count; i++) {
vtxbuf[i]->normal.x = vtxbuf[i]->pos.x;
vtxbuf[i]->normal.y = vtxbuf[i]->pos.y;
vtxbuf[i]->normal.z = vtxbuf[i]->pos.z;
gd_normalize_vec3f(&vtxbuf[i]->normal);
}
} else {
for (i = 0; i < vtxdata->count; i++) {
gd_normalize_vec3f(&vtxbuf[i]->normal);
}
}
gd_free(vtxbuf);
madeFaces = make_group_of_type(OBJ_TYPE_FACES, oldObjHead, NULL);
shape->faceGroup = madeFaces;
shape->vtxGroup = madeVtx;
}
}
if (shapeMtls != NULL) {
if (shape->faceGroup) {
map_face_materials(shape->faceGroup, shapeMtls);
} else {
fatal_printf("chk_shapegen() please set face group before mats");
}
}
imout();
stop_memtracker("chk_shapegen");
}
/**
* Set the "node group" of the current dynamic object to dynamic object `id`.
* The node group depends on the type of the current dynamic object:
* * the vertex group is set for `ObjShape`
* * the joints/weight group is set for `ObjNet`
* * data is set for `ObjAnimator`
* * something is set for `ObjGadget`
*/
void d_set_nodegroup(DynId id) {
struct DynObjInfo *info; // sp2C
UNUSED u32 pad[2];
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
info = get_dynobj_info(id);
if (info == NULL) {
fatal_printf("dSetNodeGroup(\"%s\"): Undefined group", DynIdAsStr(id));
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_NETS:
((struct ObjNet *) sDynListCurObj)->unk1C8 = (struct ObjGroup *) info->obj;
((struct ObjNet *) sDynListCurObj)->unk1D0 = (struct ObjGroup *) info->obj;
break;
case OBJ_TYPE_SHAPES:
((struct ObjShape *) sDynListCurObj)->vtxGroup = (struct ObjGroup *) info->obj;
chk_shapegen((struct ObjShape *) sDynListCurObj);
break;
case OBJ_TYPE_GADGETS:
((struct ObjGadget *) sDynListCurObj)->unk54 = (struct ObjGroup *) info->obj;
break;
case OBJ_TYPE_ANIMATORS:
((struct ObjAnimator *) sDynListCurObj)->animdata = (struct ObjGroup *) info->obj;
alloc_animdata((struct ObjAnimator *) sDynListCurObj);
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetNodeGroup()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Set the material group of the current dynamic `ObjShape` to `id`.
*/
void d_set_matgroup(DynId id) {
struct DynObjInfo *info; // sp1C
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
info = get_dynobj_info(id);
if (info == NULL) {
fatal_printf("dSetMatGroup(\"%s\"): Undefined group", DynIdAsStr(id));
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_SHAPES:
((struct ObjShape *) sDynListCurObj)->mtlGroup = (struct ObjGroup *) info->obj;
chk_shapegen((struct ObjShape *) sDynListCurObj);
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetMatGroup()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* At one time in the past, this set the s and t value of the current
* dynamic `ObjVertex`. However, this function does nothing now.
* See `BetaVtx` for a possible remnant of vertex code that had
* ST coordinates.
*/
void d_set_texture_st(UNUSED f32 s, UNUSED f32 t) {
UNUSED u32 pad[2];
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_VERTICES:
break; // ifdef-ed out?
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetTextureST()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Set the texture pointer of the current dynamic `ObjMaterial`.
*/
void d_use_texture(void *texture) {
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_MATERIALS:
((struct ObjMaterial *) sDynListCurObj)->texture = texture;
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dUseTexture()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Set the current dynamic `ObjNet`'s skin group with the vertex group from
* the dynamic `ObjShape` with `id`.
*/
void d_set_skinshape(DynId id) {
struct DynObjInfo *info;
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
info = get_dynobj_info(id);
if (info == NULL) {
fatal_printf("dSetSkinShape(\"%s\"): Undefined object", DynIdAsStr(id));
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_NETS:
((struct ObjNet *) sDynListCurObj)->skinGrp = ((struct ObjShape *) info->obj)->vtxGroup;
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetSkinShape()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Map the material ids for the `ObjFace`s in the current dynamic `ObjGroup`
* to pointer to `ObjMaterial`s in the `ObjGroup` `id`.
*
* See `map_face_materials()` for more info.
*/
void d_map_materials(DynId id) {
struct DynObjInfo *info;
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
info = get_dynobj_info(id);
if (info == NULL) {
fatal_printf("dMapMaterials(\"%s\"): Undefined group", DynIdAsStr(id));
}
map_face_materials((struct ObjGroup *) sDynListCurObj, (struct ObjGroup *) info->obj);
}
/**
* Map the vertex ids for the `ObjFace`s in the current dynamic `ObjGroup`
* to pointer to `ObjVertex` in the `ObjGroup` `id`.
*
* See `map_vertices()` for more info.
*/
void d_map_vertices(DynId id) {
struct DynObjInfo *info;
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
info = get_dynobj_info(id);
if (info == NULL) {
fatal_printf("dMapVertices(\"%s\"): Undefined group", DynIdAsStr(id));
}
map_vertices((struct ObjGroup *) sDynListCurObj, (struct ObjGroup *) info->obj);
}
/**
* In practice, this is used to set the faces of the current
* active dynamic `ObjShape` to the dynamic group `id` of `ObjFace`s.
* It also has interactions with `ObjNet`s, but there are no examples
* of that usage in existing code.
*/
void d_set_planegroup(DynId id) {
struct DynObjInfo *info; // sp2C
UNUSED u32 pad[2];
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
info = get_dynobj_info(id);
if (info == NULL) {
fatal_printf("dSetPlaneGroup(\"%s\"): Undefined group", DynIdAsStr(id));
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_NETS:
((struct ObjNet *) sDynListCurObj)->unk1CC = (struct ObjGroup *) info->obj;
break;
case OBJ_TYPE_SHAPES:
((struct ObjShape *) sDynListCurObj)->faceGroup = (struct ObjGroup *) info->obj;
chk_shapegen((struct ObjShape *) sDynListCurObj);
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetPlaneGroup()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Set the shape pointer of the current active dynamic object to the
* pointer pointed to by `shpPtrptr`.
*/
void d_set_shapeptrptr(struct ObjShape **shpPtrptr) {
struct ObjShape *defaultptr = NULL;
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
if (shpPtrptr == NULL) {
shpPtrptr = &defaultptr;
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_JOINTS:
((struct ObjJoint *) sDynListCurObj)->unk20 = *shpPtrptr;
((struct ObjJoint *) sDynListCurObj)->unk1C8 = 0;
break;
case OBJ_TYPE_NETS:
((struct ObjNet *) sDynListCurObj)->unk1A8 = *shpPtrptr;
break;
case OBJ_TYPE_BONES:
((struct ObjBone *) sDynListCurObj)->unkF0 = *shpPtrptr;
break;
case OBJ_TYPE_GADGETS:
((struct ObjGadget *) sDynListCurObj)->unk50 = *shpPtrptr;
break;
case OBJ_TYPE_PARTICLES:
((struct ObjParticle *) sDynListCurObj)->unk1C = *shpPtrptr;
break;
case OBJ_TYPE_LIGHTS:
((struct ObjLight *) sDynListCurObj)->unk9C = *shpPtrptr;
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetShapePtrPtr()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Set the shape pointer of the current active dynamic object to dynamic
* `ObjShape` `id`.
*/
void d_set_shapeptr(DynId id) {
struct DynObjInfo *info; // sp24
if (id == NULL) {
return;
}
info = get_dynobj_info(id);
if (info == NULL) {
fatal_printf("dSetShapePtr(\"%s\"): Undefined object", DynIdAsStr(id));
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_JOINTS:
((struct ObjJoint *) sDynListCurObj)->unk20 = (struct ObjShape *) info->obj;
((struct ObjJoint *) sDynListCurObj)->unk1C8 = 0;
break;
case OBJ_TYPE_NETS:
((struct ObjNet *) sDynListCurObj)->unk1A8 = (struct ObjShape *) info->obj;
break;
case OBJ_TYPE_BONES:
((struct ObjBone *) sDynListCurObj)->unkF0 = (struct ObjShape *) info->obj;
break;
case OBJ_TYPE_GADGETS:
((struct ObjGadget *) sDynListCurObj)->unk50 = (struct ObjShape *) info->obj;
break;
case OBJ_TYPE_PARTICLES:
((struct ObjParticle *) sDynListCurObj)->unk1C = (struct ObjShape *) info->obj;
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetShapePtr()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Set the current active dynamic object to object `id`.
*/
struct GdObj *d_use_obj(DynId id) {
struct DynObjInfo *info = get_dynobj_info(id);
if (info == NULL) {
fatal_printf("dUseObj(\"%s\"): Undefined object", DynIdAsStr(id));
}
sDynListCurObj = info->obj;
sDynListCurInfo = info;
return info->obj;
}
/**
* Set the current active dynamic object to `obj`. This object can
* any type of `GdObj`, not just an object created through the
* dynmaic object system.
*/
void set_cur_dynobj(struct GdObj *obj) {
sDynListCurObj = obj;
sDynListCurInfo = &sNullDynObjInfo;
}
/**
* Start a dynamic `ObjGroup` identified with `id`.
*/
void d_start_group(DynId id) {
d_makeobj(D_GROUP, id);
}
/**
* Add all dynamic objects created between the start of dynamic `ObjGroup` `id`
* and this call.
*/
void d_end_group(DynId id) {
UNUSED u32 pad;
struct DynObjInfo *info = get_dynobj_info(id); // sp20;
struct ObjGroup *dynGrp; // sp1C
s32 i; // sp18
if (info == NULL) {
fatal_printf("dEndGroup(\"%s\"): Undefined group", DynIdAsStr(id));
}
dynGrp = (struct ObjGroup *) info->obj;
for (i = info->num + 1; i < sLoadedDynObjs; i++) {
if (sGdDynObjList[i].obj->type != OBJ_TYPE_GROUPS) {
addto_group(dynGrp, sGdDynObjList[i].obj);
}
}
}
/**
* Add the current dynamic object to the dynamic `ObjGroup` `id`.
*/
void d_addto_group(DynId id) {
UNUSED u32 pad;
struct DynObjInfo *info = get_dynobj_info(id); // sp20
struct ObjGroup *targetGrp;
if (info == NULL) {
fatal_printf("dAddToGroup(\"%s\"): Undefined group", DynIdAsStr(id));
}
targetGrp = (struct ObjGroup *) info->obj;
addto_group(targetGrp, sDynListCurObj);
}
/**
* Set if `DynId` should be treated as integer values,
* or as `char *` string pointers.
*
* @param isIntBool `TRUE` to interpret ids as integers
*/
void dynid_is_int(s32 isIntBool) {
sGdDynObjIdIsInt = isIntBool;
}
/**
* Set the initial position of the current dynamic object
* to `(x, y, z)`.
*/
void d_set_init_pos(f32 x, f32 y, f32 z) {
UNUSED u32 pad2c[3];
struct GdObj *dynobj = sDynListCurObj; // sp28
UNUSED u32 pad[1];
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_JOINTS:
((struct ObjJoint *) dynobj)->unk14.x = x;
((struct ObjJoint *) dynobj)->unk14.y = y;
((struct ObjJoint *) dynobj)->unk14.z = z;
((struct ObjJoint *) dynobj)->unk3C.x = x;
((struct ObjJoint *) dynobj)->unk3C.y = y;
((struct ObjJoint *) dynobj)->unk3C.z = z;
((struct ObjJoint *) dynobj)->unk54.x = x;
((struct ObjJoint *) dynobj)->unk54.y = y;
((struct ObjJoint *) dynobj)->unk54.z = z;
break;
case OBJ_TYPE_NETS:
((struct ObjNet *) dynobj)->unk14.x = x;
((struct ObjNet *) dynobj)->unk14.y = y;
((struct ObjNet *) dynobj)->unk14.z = z;
((struct ObjNet *) dynobj)->unk20.x = x;
((struct ObjNet *) dynobj)->unk20.y = y;
((struct ObjNet *) dynobj)->unk20.z = z;
break;
case OBJ_TYPE_PARTICLES:
((struct ObjParticle *) dynobj)->unk20.x = x;
((struct ObjParticle *) dynobj)->unk20.y = y;
((struct ObjParticle *) dynobj)->unk20.z = z;
break;
case OBJ_TYPE_CAMERAS:
((struct ObjCamera *) dynobj)->unk14.x = x;
((struct ObjCamera *) dynobj)->unk14.y = y;
((struct ObjCamera *) dynobj)->unk14.z = z;
break;
case OBJ_TYPE_VERTICES:
d_set_rel_pos(x, y, z);
((struct ObjVertex *) dynobj)->initPos.x = x;
((struct ObjVertex *) dynobj)->initPos.y = y;
((struct ObjVertex *) dynobj)->initPos.z = z;
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetInitPos()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Set the velocity of the current active dynamic object. The
* values of the input `GdVec3f` are copied into the object.
*/
void d_set_velocity(const struct GdVec3f *vel) {
struct GdObj *dynobj = sDynListCurObj;
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_JOINTS:
((struct ObjJoint *) dynobj)->unk78.x = vel->x;
((struct ObjJoint *) dynobj)->unk78.y = vel->y;
((struct ObjJoint *) dynobj)->unk78.z = vel->z;
break;
case OBJ_TYPE_NETS:
((struct ObjNet *) dynobj)->unk50.x = vel->x;
((struct ObjNet *) dynobj)->unk50.y = vel->y;
((struct ObjNet *) dynobj)->unk50.z = vel->z;
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetVelocity()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Read the velocity value of the current dynamic object into `dst`
*
* @param[out] dst values are copied to this `GdVec3f`
*/
void d_get_velocity(struct GdVec3f *dst) {
struct GdObj *dynobj = sDynListCurObj;
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_JOINTS:
dst->x = ((struct ObjJoint *) dynobj)->unk78.x;
dst->y = ((struct ObjJoint *) dynobj)->unk78.y;
dst->z = ((struct ObjJoint *) dynobj)->unk78.z;
break;
case OBJ_TYPE_NETS:
dst->x = ((struct ObjNet *) dynobj)->unk50.x;
dst->y = ((struct ObjNet *) dynobj)->unk50.y;
dst->z = ((struct ObjNet *) dynobj)->unk50.z;
break;
default:
dst->x = dst->y = dst->z = 0.0f;
break;
}
}
/**
* Set the torque vectore for the current dynamic object.
* Values from input `GdVec3f` are copied into the object.
*
* @note Not called
*/
void d_set_torque(const struct GdVec3f *src) {
struct GdObj *dynobj = sDynListCurObj;
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_NETS:
((struct ObjNet *) dynobj)->unkA4.x = src->x;
((struct ObjNet *) dynobj)->unkA4.y = src->y;
((struct ObjNet *) dynobj)->unkA4.z = src->z;
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetTorque()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Get the initial position of the current dynamic object and
* store in `dst`.
*/
void d_get_init_pos(struct GdVec3f *dst) {
struct GdObj *dynobj = sDynListCurObj;
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_JOINTS:
dst->x = ((struct ObjJoint *) dynobj)->unk54.x;
dst->y = ((struct ObjJoint *) dynobj)->unk54.y;
dst->z = ((struct ObjJoint *) dynobj)->unk54.z;
break;
case OBJ_TYPE_NETS:
dst->x = ((struct ObjNet *) dynobj)->unk20.x;
dst->y = ((struct ObjNet *) dynobj)->unk20.y;
dst->z = ((struct ObjNet *) dynobj)->unk20.z;
break;
case OBJ_TYPE_VERTICES:
dst->x = ((struct ObjVertex *) dynobj)->initPos.x;
dst->y = ((struct ObjVertex *) dynobj)->initPos.y;
dst->z = ((struct ObjVertex *) dynobj)->initPos.z;
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dGetInitPos()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Get the initial rotation of the current dynamic object and
* store in `dst`.
*/
void d_get_init_rot(struct GdVec3f *dst) {
struct GdObj *dynobj = sDynListCurObj;
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_JOINTS:
dst->x = ((struct ObjJoint *) dynobj)->unk6C.x;
dst->y = ((struct ObjJoint *) dynobj)->unk6C.y;
dst->z = ((struct ObjJoint *) dynobj)->unk6C.z;
break;
case OBJ_TYPE_NETS:
dst->x = ((struct ObjNet *) dynobj)->unk68.x;
dst->y = ((struct ObjNet *) dynobj)->unk68.y;
dst->z = ((struct ObjNet *) dynobj)->unk68.z;
break;
case OBJ_TYPE_LIGHTS:
dst->x = dst->y = dst->z = 0.0f;
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dGetInitRot()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Set the position of the current dynamic object.
*
* @note This function automatically adjusts the three zoom levels
* for an `ObjCamera`.
*/
void d_set_rel_pos(f32 x, f32 y, f32 z) {
struct GdObj *dynobj = sDynListCurObj; // sp34
UNUSED struct GdVec3f unusedVec; // sp28
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_JOINTS:
((struct ObjJoint *) dynobj)->unk3C.x = x;
((struct ObjJoint *) dynobj)->unk3C.y = y;
((struct ObjJoint *) dynobj)->unk3C.z = z;
break;
case OBJ_TYPE_CAMERAS:
unusedVec.x = x;
unusedVec.y = y;
unusedVec.z = z;
((struct ObjCamera *) dynobj)->unk40.x = x;
((struct ObjCamera *) dynobj)->unk40.y = y;
((struct ObjCamera *) dynobj)->unk40.z = z;
((struct ObjCamera *) dynobj)->positions[0].x = x;
((struct ObjCamera *) dynobj)->positions[0].y = y;
((struct ObjCamera *) dynobj)->positions[0].z = z;
((struct ObjCamera *) dynobj)->positions[1].x = x * 1.5; //? 1.5f
((struct ObjCamera *) dynobj)->positions[1].y = y * 1.5; //? 1.5f
((struct ObjCamera *) dynobj)->positions[1].z = z * 1.5; //? 1.5f
((struct ObjCamera *) dynobj)->positions[2].x = x * 2.0f;
((struct ObjCamera *) dynobj)->positions[2].y = y * 2.0f;
((struct ObjCamera *) dynobj)->positions[2].z = z * 2.0f;
((struct ObjCamera *) dynobj)->zoomLevels = 2;
break;
case OBJ_TYPE_VERTICES:
((struct ObjVertex *) dynobj)->pos.x = x;
((struct ObjVertex *) dynobj)->pos.y = y;
((struct ObjVertex *) dynobj)->pos.z = z;
break;
case OBJ_TYPE_LABELS:
((struct ObjLabel *) dynobj)->vec14.x = x;
((struct ObjLabel *) dynobj)->vec14.y = y;
((struct ObjLabel *) dynobj)->vec14.z = z;
break;
case OBJ_TYPE_PARTICLES:
((struct ObjParticle *) dynobj)->unk20.x = x;
((struct ObjParticle *) dynobj)->unk20.y = y;
((struct ObjParticle *) dynobj)->unk20.z = z;
break;
case OBJ_TYPE_NETS:
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetRelPos()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Offset the current position of the current dynamic object.
*/
void d_addto_rel_pos(struct GdVec3f *src) {
struct GdObj *dynobj = sDynListCurObj; // sp24
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_VERTICES:
((struct ObjVertex *) dynobj)->pos.x += src->x;
((struct ObjVertex *) dynobj)->pos.y += src->y;
((struct ObjVertex *) dynobj)->pos.z += src->z;
break;
case OBJ_TYPE_JOINTS:
((struct ObjJoint *) dynobj)->unk3C.x += src->x;
((struct ObjJoint *) dynobj)->unk3C.y += src->y;
((struct ObjJoint *) dynobj)->unk3C.z += src->z;
break;
case OBJ_TYPE_PARTICLES:
((struct ObjParticle *) dynobj)->unk20.x += src->x;
((struct ObjParticle *) dynobj)->unk20.y += src->y;
((struct ObjParticle *) dynobj)->unk20.z += src->z;
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dAddToRelPos()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Store the current dynamic object's position into `dst`.
*/
void d_get_rel_pos(struct GdVec3f *dst) {
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_VERTICES:
dst->x = ((struct ObjVertex *) sDynListCurObj)->pos.x;
dst->y = ((struct ObjVertex *) sDynListCurObj)->pos.y;
dst->z = ((struct ObjVertex *) sDynListCurObj)->pos.z;
break;
case OBJ_TYPE_JOINTS:
dst->x = ((struct ObjJoint *) sDynListCurObj)->unk3C.x;
dst->y = ((struct ObjJoint *) sDynListCurObj)->unk3C.y;
dst->z = ((struct ObjJoint *) sDynListCurObj)->unk3C.z;
break;
case OBJ_TYPE_CAMERAS:
dst->x = ((struct ObjCamera *) sDynListCurObj)->unk40.x;
dst->y = ((struct ObjCamera *) sDynListCurObj)->unk40.y;
dst->z = ((struct ObjCamera *) sDynListCurObj)->unk40.z;
break;
case OBJ_TYPE_PARTICLES:
dst->x = ((struct ObjParticle *) sDynListCurObj)->unk20.x;
dst->y = ((struct ObjParticle *) sDynListCurObj)->unk20.y;
dst->z = ((struct ObjParticle *) sDynListCurObj)->unk20.z;
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dGetRelPos()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Return a pointer to the attached object group of the current
* dynamic object.
*/
struct ObjGroup *d_get_att_objgroup(void) {
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_JOINTS:
return ((struct ObjJoint *) sDynListCurObj)->unk1F8;
break; // lol
case OBJ_TYPE_NETS:
return ((struct ObjNet *) sDynListCurObj)->unk1D4;
break; // lol
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dGetAttObjGroup()",
sDynListCurInfo->name, sDynListCurObj->type);
}
// No null return due to `fatal_printf()` being a non-returning function?
}
/**
* Return a pointer to the attached object of the current dynamic object.
*/
struct GdObj *d_get_att_to_obj(void) {
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_JOINTS:
return ((struct ObjJoint *) sDynListCurObj)->unk20C;
break; // lol
case OBJ_TYPE_NETS:
return ((struct ObjNet *) sDynListCurObj)->unk1E8;
break; // lol
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dGetAttToObj()",
sDynListCurInfo->name, sDynListCurObj->type);
}
// No null return due to `fatal_printf()` being a non-returning function?
}
/**
* Store the current dynamic object's scale into `dst`.
*/
void d_get_scale(struct GdVec3f *dst) {
struct GdObj *dynobj; // sp24
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
dynobj = sDynListCurObj;
switch (sDynListCurObj->type) {
case OBJ_TYPE_JOINTS:
dst->x = ((struct ObjJoint *) dynobj)->unk9C.x;
dst->y = ((struct ObjJoint *) dynobj)->unk9C.y;
dst->z = ((struct ObjJoint *) dynobj)->unk9C.z;
break;
case OBJ_TYPE_NETS:
dst->x = ((struct ObjNet *) dynobj)->unk1AC.x;
dst->y = ((struct ObjNet *) dynobj)->unk1AC.y;
dst->z = ((struct ObjNet *) dynobj)->unk1AC.z;
break;
case OBJ_TYPE_LIGHTS:
dst->x = 1.0f;
dst->y = 1.0f;
dst->z = 1.0f;
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dGetScale()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Set the offset of the attached object on the current dynamic object.
*/
void d_set_att_offset(const struct GdVec3f *off) {
struct GdObj *dynobj; // sp24
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
dynobj = sDynListCurObj;
switch (sDynListCurObj->type) {
case OBJ_TYPE_JOINTS:
((struct ObjJoint *) dynobj)->unk200.x = off->x;
((struct ObjJoint *) dynobj)->unk200.y = off->y;
((struct ObjJoint *) dynobj)->unk200.z = off->z;
((struct ObjJoint *) dynobj)->unk54.x = off->x;
((struct ObjJoint *) dynobj)->unk54.y = off->y;
((struct ObjJoint *) dynobj)->unk54.z = off->z;
break;
case OBJ_TYPE_NETS:
((struct ObjNet *) dynobj)->unk1D8.x = off->x;
((struct ObjNet *) dynobj)->unk1D8.y = off->y;
((struct ObjNet *) dynobj)->unk1D8.z = off->z;
((struct ObjNet *) dynobj)->unk20.x = off->x;
((struct ObjNet *) dynobj)->unk20.y = off->y;
((struct ObjNet *) dynobj)->unk20.z = off->z;
break;
case OBJ_TYPE_PARTICLES:
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetAttOffset()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* An incorrectly-coded recursive function that was presumably supposed to
* set the offset of an attached object. Now, it will only call itself
* until it encounters a NULL pointer, which will trigger a `fatal_printf()`
* call.
*
* @note Not called
*/
void d_set_att_to_offset(UNUSED u32 a) {
struct GdObj *dynobj; // sp3c
UNUSED u8 pad[24];
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
dynobj = sDynListCurObj;
push_dynobj_stash();
switch (sDynListCurObj->type) {
case OBJ_TYPE_JOINTS:
set_cur_dynobj(((struct ObjJoint *) dynobj)->unk20C);
break;
case OBJ_TYPE_NETS:
set_cur_dynobj(((struct ObjNet *) dynobj)->unk1E8);
break;
case OBJ_TYPE_PARTICLES:
set_cur_dynobj(((struct ObjParticle *) dynobj)->unkBC);
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetAttToOffset()",
sDynListCurInfo->name, sDynListCurObj->type);
}
if (sDynListCurObj == NULL) {
fatal_printf("dSetAttOffset(): Object '%s' isnt attached to anything",
sStashedDynObjInfo->name);
}
d_set_att_to_offset(a);
pop_dynobj_stash();
}
/**
* Store the offset of the attached object into `dst`.
*
* @note Not called
*/
void d_get_att_offset(struct GdVec3f *dst) {
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_JOINTS:
dst->x = ((struct ObjJoint *) sDynListCurObj)->unk200.x;
dst->y = ((struct ObjJoint *) sDynListCurObj)->unk200.y;
dst->z = ((struct ObjJoint *) sDynListCurObj)->unk200.z;
break;
case OBJ_TYPE_NETS:
dst->x = ((struct ObjNet *) sDynListCurObj)->unk1D8.x;
dst->y = ((struct ObjNet *) sDynListCurObj)->unk1D8.y;
dst->z = ((struct ObjNet *) sDynListCurObj)->unk1D8.z;
break;
case OBJ_TYPE_PARTICLES:
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dGetAttOffset()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Get the attached object flags for the current dynamic object.
*/
s32 d_get_att_flags(void) {
s32 attflag; // sp24
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_JOINTS:
attflag = ((struct ObjJoint *) sDynListCurObj)->unk1FC;
break;
case OBJ_TYPE_NETS:
attflag = ((struct ObjNet *) sDynListCurObj)->unk1E4;
break;
case OBJ_TYPE_PARTICLES:
attflag = ((struct ObjParticle *) sDynListCurObj)->unkB8;
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dGetAttFlags()",
sDynListCurInfo->name, sDynListCurObj->type);
}
return attflag;
}
/**
* Set the world position of the current dynamic object.
*
* @note Sets the upper left coordinates of an `ObjView`
*/
void d_set_world_pos(f32 x, f32 y, f32 z) {
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_CAMERAS:
((struct ObjCamera *) sDynListCurObj)->unk14.x = x;
((struct ObjCamera *) sDynListCurObj)->unk14.y = y;
((struct ObjCamera *) sDynListCurObj)->unk14.z = z;
break;
case OBJ_TYPE_JOINTS:
((struct ObjJoint *) sDynListCurObj)->unk14.x = x;
((struct ObjJoint *) sDynListCurObj)->unk14.y = y;
((struct ObjJoint *) sDynListCurObj)->unk14.z = z;
break;
case OBJ_TYPE_NETS:
((struct ObjNet *) sDynListCurObj)->unk14.x = x;
((struct ObjNet *) sDynListCurObj)->unk14.y = y;
((struct ObjNet *) sDynListCurObj)->unk14.z = z;
break;
case OBJ_TYPE_GADGETS:
((struct ObjGadget *) sDynListCurObj)->unk14.x = x;
((struct ObjGadget *) sDynListCurObj)->unk14.y = y;
((struct ObjGadget *) sDynListCurObj)->unk14.z = z;
break;
case OBJ_TYPE_VIEWS:
((struct ObjView *) sDynListCurObj)->upperLeft.x = x;
((struct ObjView *) sDynListCurObj)->upperLeft.y = y;
((struct ObjView *) sDynListCurObj)->upperLeft.z = z;
break;
case OBJ_TYPE_VERTICES:
((struct ObjVertex *) sDynListCurObj)->pos.x = x;
((struct ObjVertex *) sDynListCurObj)->pos.y = y;
((struct ObjVertex *) sDynListCurObj)->pos.z = z;
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetWorldPos()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Set the normal of the current dynamic `ObjVertex`. The input `x, y, z` values
* are normalized into a unit vector before setting the vertex normal.
*/
void d_set_normal(f32 x, f32 y, f32 z) {
struct GdVec3f normal; // sp1C
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
normal.x = x;
normal.y = y;
normal.z = z;
gd_normalize_vec3f(&normal);
switch (sDynListCurObj->type) {
case OBJ_TYPE_VERTICES:
((struct ObjVertex *) sDynListCurObj)->normal.x = normal.x;
((struct ObjVertex *) sDynListCurObj)->normal.y = normal.y;
((struct ObjVertex *) sDynListCurObj)->normal.z = normal.z;
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetNormal()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Get a pointer to the world position vector of the active
* dynamic object. This is a pointer inside the actual object.
*
* @note Not called.
*/
struct GdVec3f *d_get_world_pos_ptr(void) {
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_VERTICES:
return &((struct ObjVertex *) sDynListCurObj)->pos;
break;
case OBJ_TYPE_PARTICLES:
return &((struct ObjParticle *) sDynListCurObj)->unk20;
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dGetWorldPosPtr()",
sDynListCurInfo->name, sDynListCurObj->type);
}
// No null return due to `fatal_printf()` being a non-returning function?
}
/**
* Copy the world position of the current dynamic object into `dst`.
*/
void d_get_world_pos(struct GdVec3f *dst) {
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_VERTICES:
dst->x = ((struct ObjVertex *) sDynListCurObj)->pos.x;
dst->y = ((struct ObjVertex *) sDynListCurObj)->pos.y;
dst->z = ((struct ObjVertex *) sDynListCurObj)->pos.z;
break;
case OBJ_TYPE_JOINTS:
dst->x = ((struct ObjJoint *) sDynListCurObj)->unk14.x;
dst->y = ((struct ObjJoint *) sDynListCurObj)->unk14.y;
dst->z = ((struct ObjJoint *) sDynListCurObj)->unk14.z;
break;
case OBJ_TYPE_NETS:
dst->x = ((struct ObjNet *) sDynListCurObj)->unk14.x;
dst->y = ((struct ObjNet *) sDynListCurObj)->unk14.y;
dst->z = ((struct ObjNet *) sDynListCurObj)->unk14.z;
break;
case OBJ_TYPE_PARTICLES:
dst->x = ((struct ObjParticle *) sDynListCurObj)->unk20.x;
dst->y = ((struct ObjParticle *) sDynListCurObj)->unk20.y;
dst->z = ((struct ObjParticle *) sDynListCurObj)->unk20.z;
break;
case OBJ_TYPE_CAMERAS:
dst->x = ((struct ObjCamera *) sDynListCurObj)->unk14.x;
dst->y = ((struct ObjCamera *) sDynListCurObj)->unk14.y;
dst->z = ((struct ObjCamera *) sDynListCurObj)->unk14.z;
break;
case OBJ_TYPE_BONES:
dst->x = ((struct ObjBone *) sDynListCurObj)->unk14.x;
dst->y = ((struct ObjBone *) sDynListCurObj)->unk14.y;
dst->z = ((struct ObjBone *) sDynListCurObj)->unk14.z;
break;
case OBJ_TYPE_SHAPES:
dst->x = dst->y = dst->z = 0.0f;
break;
case OBJ_TYPE_LABELS:
dst->x = dst->y = dst->z = 0.0f;
break;
case OBJ_TYPE_GADGETS:
dst->x = ((struct ObjGadget *) sDynListCurObj)->unk14.x;
dst->y = ((struct ObjGadget *) sDynListCurObj)->unk14.y;
dst->z = ((struct ObjGadget *) sDynListCurObj)->unk14.z;
break;
case OBJ_TYPE_PLANES:
dst->x = ((struct ObjPlane *) sDynListCurObj)->plane28.p0.x;
dst->y = ((struct ObjPlane *) sDynListCurObj)->plane28.p0.y;
dst->z = ((struct ObjPlane *) sDynListCurObj)->plane28.p0.z;
dst->x += ((struct ObjPlane *) sDynListCurObj)->plane28.p1.x;
dst->y += ((struct ObjPlane *) sDynListCurObj)->plane28.p1.y;
dst->z += ((struct ObjPlane *) sDynListCurObj)->plane28.p1.z;
dst->x *= 0.5; //? 0.5f
dst->y *= 0.5; //? 0.5f
dst->z *= 0.5; //? 0.5f
break;
case OBJ_TYPE_ZONES:
dst->x = ((struct ObjZone *) sDynListCurObj)->unk14.p0.x;
dst->y = ((struct ObjZone *) sDynListCurObj)->unk14.p0.y;
dst->z = ((struct ObjZone *) sDynListCurObj)->unk14.p0.z;
dst->x += ((struct ObjZone *) sDynListCurObj)->unk14.p1.x;
dst->y += ((struct ObjZone *) sDynListCurObj)->unk14.p1.y;
dst->z += ((struct ObjZone *) sDynListCurObj)->unk14.p1.z;
dst->x *= 0.5; //? 0.5f
dst->y *= 0.5; //? 0.5f
dst->z *= 0.5; //? 0.5f
break;
case OBJ_TYPE_LIGHTS:
dst->x = ((struct ObjLight *) sDynListCurObj)->position.x;
dst->y = ((struct ObjLight *) sDynListCurObj)->position.y;
dst->z = ((struct ObjLight *) sDynListCurObj)->position.z;
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dGetWorldPos()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Create a new dynamic `ObjVertex` at point `pos`.
*
* @param[in] pos values are copied to set vertex position
*/
void d_make_vertex(struct GdVec3f *pos) {
d_makeobj(D_VERTEX, AsDynId(NULL));
d_set_init_pos(pos->x, pos->y, pos->z);
}
/**
* Scale the current dynamic object by factor `(x, y, z)`.
*
* @note Sets the lower right coordinates of an `ObjView`
*/
void d_set_scale(f32 x, f32 y, f32 z) {
struct GdObj *initDynobj; // sp24;
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
initDynobj = sDynListCurObj;
push_dynobj_stash();
switch (sDynListCurObj->type) {
case OBJ_TYPE_JOINTS:
((struct ObjJoint *) initDynobj)->unk9C.x = x;
((struct ObjJoint *) initDynobj)->unk9C.y = y;
((struct ObjJoint *) initDynobj)->unk9C.z = z;
break;
case OBJ_TYPE_NETS:
((struct ObjNet *) initDynobj)->unk1AC.x = x;
((struct ObjNet *) initDynobj)->unk1AC.y = y;
((struct ObjNet *) initDynobj)->unk1AC.z = z;
break;
case OBJ_TYPE_VIEWS:
((struct ObjView *) initDynobj)->lowerRight.x = x;
((struct ObjView *) initDynobj)->lowerRight.y = y;
((struct ObjView *) initDynobj)->lowerRight.z = z;
break;
case OBJ_TYPE_PARTICLES:
break;
case OBJ_TYPE_GADGETS:
if (((struct ObjGadget *) initDynobj)->unk50 != NULL) {
scale_verts_in_shape(((struct ObjGadget *) initDynobj)->unk50, x, y, z);
}
((struct ObjGadget *) initDynobj)->unk40.x = x;
((struct ObjGadget *) initDynobj)->unk40.y = y;
((struct ObjGadget *) initDynobj)->unk40.z = z;
break;
case OBJ_TYPE_LIGHTS:
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetScale()",
sDynListCurInfo->name, sDynListCurObj->type);
}
pop_dynobj_stash();
}
/**
* Set the rotation value of the current active dynamic object.
*/
void d_set_rotation(f32 x, f32 y, f32 z) {
struct GdObj *dynobj; // sp2C
UNUSED u32 pad;
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
dynobj = sDynListCurObj;
switch (sDynListCurObj->type) {
case OBJ_TYPE_JOINTS:
((struct ObjJoint *) dynobj)->unk6C.x = x;
((struct ObjJoint *) dynobj)->unk6C.y = y;
((struct ObjJoint *) dynobj)->unk6C.z = z;
break;
case OBJ_TYPE_NETS:
((struct ObjNet *) dynobj)->unk68.x = x;
((struct ObjNet *) dynobj)->unk68.y = y;
((struct ObjNet *) dynobj)->unk68.z = z;
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetRotation()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Set the center of gravity of the current dynamic `ObjNet`.
*/
void d_center_of_gravity(f32 x, f32 y, f32 z) {
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_NETS:
((struct ObjNet *) sDynListCurObj)->unkB0.x = x;
((struct ObjNet *) sDynListCurObj)->unkB0.y = y;
((struct ObjNet *) sDynListCurObj)->unkB0.z = z;
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dCofG()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Set the shape offset of the current dynamic `ObjJoint`.
*/
void d_set_shape_offset(f32 x, f32 y, f32 z) {
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_JOINTS:
((struct ObjJoint *) sDynListCurObj)->unkC0.x = x;
((struct ObjJoint *) sDynListCurObj)->unkC0.y = y;
((struct ObjJoint *) sDynListCurObj)->unkC0.z = z;
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dShapeOffset()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Create a new `ObjValPtr` to dynamic object `objId` and attach
* that valptr to the current dynamic object.
*
* @param type `::ValPtrType`
*/
void d_add_valptr(DynId objId, u32 vflags, s32 type, size_t offset) {
struct GdObj *dynobj; // sp2C
struct ObjValPtrs *valptr; // sp28
struct DynObjInfo *info; // sp24
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
dynobj = sDynListCurObj;
if (vflags == 0x40000) {
info = get_dynobj_info(objId);
if (info == NULL) {
fatal_printf("dAddValPtr(\"%s\"): Undefined object", DynIdAsStr(objId));
}
valptr = make_valptrs(info->obj, vflags, type, offset);
} else {
valptr = make_valptrs(objId, vflags, type, offset);
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_GADGETS:
if (((struct ObjGadget *) dynobj)->unk4C == NULL) {
((struct ObjGadget *) dynobj)->unk4C = make_group(0);
}
addto_group(((struct ObjGadget *) dynobj)->unk4C, &valptr->header);
break;
case OBJ_TYPE_LABELS:
((struct ObjLabel *) dynobj)->valptr = valptr;
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dAddValPtr()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Add a value processing function (`valptrproc_t`) to the current
* dynamic `ObjLabel`.
*/
void d_add_valproc(valptrproc_t proc) {
struct GdObj *dynobj; // sp1C
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
dynobj = sDynListCurObj;
switch (sDynListCurObj->type) {
case OBJ_TYPE_LABELS:
((struct ObjLabel *) dynobj)->valfn = proc;
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dAddValProc()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Link a variable pointer to the current active dynamic object.
* In the final game, this is used to link arrays of raw vertex, face,
* or animation data to `ObjGroup`s, or to link joints to `ObjAnimator`s.
*/
void d_link_with_ptr(void *ptr) {
struct GdObj *dynobj; // sp34
struct ObjValPtrs *valptr; // sp30
struct Links *link; // sp2C
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
dynobj = sDynListCurObj;
add_to_stacktrace("dLinkWithPtr");
switch (sDynListCurObj->type) {
case OBJ_TYPE_CAMERAS:
((struct ObjCamera *) dynobj)->unk30 = ptr;
break;
case OBJ_TYPE_GROUPS:
link = make_link_to_obj(NULL, ptr);
((struct ObjGroup *) dynobj)->link1C = link;
break;
case OBJ_TYPE_BONES:
add_joint2bone((struct ObjBone *) dynobj, ptr);
break;
case OBJ_TYPE_VIEWS:
((struct ObjView *) dynobj)->components = ptr;
((struct ObjView *) dynobj)->unk1C =
setup_view_buffers(((struct ObjView *) dynobj)->namePtr, ((struct ObjView *) dynobj),
(s32)((struct ObjView *) dynobj)->upperLeft.x,
(s32)((struct ObjView *) dynobj)->upperLeft.y,
(s32)((struct ObjView *) dynobj)->lowerRight.x,
(s32)((struct ObjView *) dynobj)->lowerRight.y);
reset_nets_and_gadgets(((struct ObjView *) dynobj)->components);
break;
case OBJ_TYPE_FACES:
if (((struct ObjFace *) dynobj)->vtxCount >= 4) {
fatal_printf("too many points");
}
((struct ObjFace *) dynobj)->vertices[((struct ObjFace *) dynobj)->vtxCount] = ptr;
((struct ObjFace *) dynobj)->vtxCount++;
if (((struct ObjFace *) dynobj)->vtxCount >= 3) {
calc_face_normal((struct ObjFace *) dynobj);
}
break;
case OBJ_TYPE_ANIMATORS:
if (((struct ObjAnimator *) dynobj)->unk14 == NULL) {
((struct ObjAnimator *) dynobj)->unk14 = make_group(0);
}
addto_group(((struct ObjAnimator *) dynobj)->unk14, ptr);
break;
case OBJ_TYPE_LABELS:
valptr = make_valptrs(ptr, OBJ_TYPE_ALL, 0, 0);
((struct ObjLabel *) dynobj)->valptr = valptr;
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dLinkWithPtr()",
sDynListCurInfo->name, sDynListCurObj->type);
}
imout();
}
/**
* Link the dynamic object `id` to the current dynamic object by wrapping
* `d_link_with_ptr()`.
*/
void d_link_with(DynId id) {
struct DynObjInfo *info; // sp1C
struct DynObjInfo *origInfo = sDynListCurInfo; // sp18
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
if (id == NULL) {
return;
}
info = get_dynobj_info(id);
if (info == NULL) {
fatal_printf("dLinkWith(\"%s\"): Undefined object", DynIdAsStr(id));
}
d_link_with_ptr(info->obj);
set_cur_dynobj(origInfo->obj);
sDynListCurInfo = origInfo;
}
/**
* Set the object specific flags of the current dynamic object.
*/
void d_set_flags(s32 flags) {
struct GdObj *dynobj; // sp24
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
dynobj = sDynListCurObj;
switch (sDynListCurObj->type) {
case OBJ_TYPE_JOINTS:
((struct ObjJoint *) dynobj)->unk1BC |= flags;
break;
case OBJ_TYPE_BONES:
((struct ObjBone *) dynobj)->unk104 |= flags;
break;
case OBJ_TYPE_NETS:
((struct ObjNet *) dynobj)->unk34 |= flags;
break;
case OBJ_TYPE_CAMERAS:
((struct ObjCamera *) dynobj)->unk2C |= flags;
break;
case OBJ_TYPE_VIEWS:
((struct ObjView *) dynobj)->flags |= flags;
break;
case OBJ_TYPE_SHAPES:
((struct ObjShape *) dynobj)->flag |= flags;
break;
case OBJ_TYPE_PARTICLES:
((struct ObjParticle *) dynobj)->unk54 |= flags;
break;
case OBJ_TYPE_LIGHTS:
((struct ObjLight *) dynobj)->flags |= flags;
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetFlags()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Clear object specific flags from the current dynamic object.
*/
void d_clear_flags(s32 flags) {
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_JOINTS:
((struct ObjJoint *) sDynListCurObj)->unk1BC &= ~flags;
break;
case OBJ_TYPE_BONES:
((struct ObjBone *) sDynListCurObj)->unk104 &= ~flags;
break;
case OBJ_TYPE_NETS:
((struct ObjNet *) sDynListCurObj)->unk34 &= ~flags;
break;
case OBJ_TYPE_CAMERAS:
((struct ObjCamera *) sDynListCurObj)->unk2C &= ~flags;
break;
case OBJ_TYPE_PARTICLES:
((struct ObjParticle *) sDynListCurObj)->unk54 &= ~flags;
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dClrFlags()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Set variable float parameters on the current dynamic object.
* These are mainly used for `ObjGadget`s to set the drawing size
* range.
*/
void d_set_parm_f(enum DParmF param, f32 val) {
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_SHAPES:
switch (param) {
case PARM_F_ALPHA:
((struct ObjShape *) sDynListCurObj)->unk58 = val;
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.",
"dSetParmf() - unsupported parm.", sDynListCurInfo->name,
sDynListCurObj->type);
}
break;
case OBJ_TYPE_GADGETS:
switch (param) {
case PARM_F_RANGE_LEFT:
((struct ObjGadget *) sDynListCurObj)->unk38 = val;
break;
case PARM_F_RANGE_RIGHT:
((struct ObjGadget *) sDynListCurObj)->unk3C = val;
break;
case PARM_F_VARVAL:
((struct ObjGadget *) sDynListCurObj)->varval.f = val;
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.",
"dSetParmf() - unsupported parm.", sDynListCurInfo->name,
sDynListCurObj->type);
}
break;
case OBJ_TYPE_VERTICES:
switch (param) {
case PARM_F_ALPHA:
((struct ObjVertex *) sDynListCurObj)->alpha = val;
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.",
"dSetParmf() - unsupported parm.", sDynListCurInfo->name,
sDynListCurObj->type);
}
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetParmf()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Set various pointer parameters for the current dynamic object.
* Normally, this is used to set `char *` pointer for various objects,
* but it can also set the vertices for an `ObjFace`.
*/
void d_set_parm_ptr(enum DParmPtr param, void *ptr) {
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_LABELS:
switch (param) {
case PARM_PTR_CHAR:
((struct ObjLabel *) sDynListCurObj)->fmtstr = ptr;
break;
default:
fatal_printf("Bad parm");
}
break;
case OBJ_TYPE_VIEWS:
switch (param) {
case PARM_PTR_CHAR:
((struct ObjView *) sDynListCurObj)->namePtr = ptr;
break;
default:
fatal_printf("Bad parm");
}
break;
case OBJ_TYPE_FACES:
switch (param) {
case PARM_PTR_OBJ_VTX:
if (((struct ObjFace *) sDynListCurObj)->vtxCount > 3) {
fatal_printf("dsetparmp() too many points");
}
((struct ObjFace *) sDynListCurObj)
->vertices[((struct ObjFace *) sDynListCurObj)->vtxCount++] = ptr;
break;
default:
fatal_printf("Bad parm");
}
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetParmp()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Set the generic drawing flags for the current dynamic object.
*/
void d_set_obj_draw_flag(enum ObjDrawingFlags flag) {
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
sDynListCurObj->drawFlags |= flag;
}
/**
* Set an object specific type field for the current dynamic object.
*/
void d_set_type(s32 type) {
struct GdObj *dynobj = sDynListCurObj; // sp24
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_NETS:
((struct ObjNet *) dynobj)->netType = type;
break;
case OBJ_TYPE_GADGETS:
((struct ObjGadget *) dynobj)->unk24 = type;
break;
case OBJ_TYPE_GROUPS:
((struct ObjGroup *) dynobj)->debugPrint = type;
break;
case OBJ_TYPE_JOINTS:
((struct ObjJoint *) dynobj)->unk1CC = type;
break;
case OBJ_TYPE_PARTICLES:
((struct ObjParticle *) dynobj)->unk60 = type;
break;
case OBJ_TYPE_MATERIALS:
((struct ObjMaterial *) dynobj)->type = type;
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetType()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Set the specific object ID field for the current dynamic object.
*/
void d_set_id(s32 id) {
struct GdObj *dynobj = sDynListCurObj; // sp24
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_MATERIALS:
((struct ObjMaterial *) dynobj)->id = id;
break;
case OBJ_TYPE_JOINTS:
((struct ObjJoint *) dynobj)->id = id;
break;
case OBJ_TYPE_VERTICES:
((struct ObjVertex *) dynobj)->id = id;
break;
case OBJ_TYPE_LIGHTS:
((struct ObjLight *) dynobj)->id = id;
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetID()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
// TODO: enumerate colors?
/**
* Set the colour of the current dynamic object. The input color is an index
* for `gd_get_colour()`
*/
void d_set_colour_num(s32 colornum) {
struct GdColour *rgbcolor; // sp24
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_JOINTS:
((struct ObjJoint *) sDynListCurObj)->unk1C8 = colornum;
break;
case OBJ_TYPE_PARTICLES:
((struct ObjParticle *) sDynListCurObj)->unk58 = colornum;
break;
case OBJ_TYPE_NETS:
((struct ObjNet *) sDynListCurObj)->unk40 = colornum;
break;
case OBJ_TYPE_GADGETS:
((struct ObjGadget *) sDynListCurObj)->unk5C = colornum;
break;
case OBJ_TYPE_FACES:
rgbcolor = gd_get_colour(colornum);
if (rgbcolor != NULL) {
((struct ObjFace *) sDynListCurObj)->colour.r = rgbcolor->r;
((struct ObjFace *) sDynListCurObj)->colour.g = rgbcolor->g;
((struct ObjFace *) sDynListCurObj)->colour.b = rgbcolor->b;
((struct ObjFace *) sDynListCurObj)->colNum = colornum;
} else {
fatal_printf("dSetColNum: Unkown colour number");
}
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dColourNum()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Set the material ID of the current dynamic `ObjFace`.
*/
void d_set_material(UNUSED void *a0, s32 mtlId) {
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_FACES:
((struct ObjFace *) sDynListCurObj)->mtlId = mtlId;
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetMaterial()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Set the friction vec of the current dynamic `ObjJoint`.
*/
void d_friction(f32 x, f32 y, f32 z) {
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_JOINTS:
((struct ObjJoint *) sDynListCurObj)->unkDC.x = x;
((struct ObjJoint *) sDynListCurObj)->unkDC.y = y;
((struct ObjJoint *) sDynListCurObj)->unkDC.z = z;
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dFriction()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Set the spring constant of the current dynamic `ObjBone`.
*/
void d_set_spring(f32 spring) {
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_BONES:
((struct ObjBone *) sDynListCurObj)->unk110 = spring;
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetSpring()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Set the ambient color of the current dynamic `ObjMaterial`.
*/
void d_set_ambient(f32 r, f32 g, f32 b) {
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_MATERIALS:
((struct ObjMaterial *) sDynListCurObj)->Ka.r = r;
((struct ObjMaterial *) sDynListCurObj)->Ka.g = g;
((struct ObjMaterial *) sDynListCurObj)->Ka.b = b;
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetAmbient()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Set the diffuse color of the current dynamic `ObjMaterial` or `ObjLight`.
*/
void d_set_diffuse(f32 r, f32 g, f32 b) {
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_MATERIALS:
((struct ObjMaterial *) sDynListCurObj)->Kd.r = r;
((struct ObjMaterial *) sDynListCurObj)->Kd.g = g;
((struct ObjMaterial *) sDynListCurObj)->Kd.b = b;
break;
case OBJ_TYPE_LIGHTS:
((struct ObjLight *) sDynListCurObj)->diffuse.r = r;
((struct ObjLight *) sDynListCurObj)->diffuse.g = g;
((struct ObjLight *) sDynListCurObj)->diffuse.b = b;
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetDiffuse()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Set the control type of the current dynamic `ObjNet`.
*/
void d_set_control_type(s32 ctrltype) {
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_NETS:
((struct ObjNet *) sDynListCurObj)->unk210 = ctrltype;
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dControlType()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Get a pointer to a `GdPlaneF` in the current dynamic object.
* If the current object does not have a plane, a pointer to
* a global plane at (0,0) is returned.
*/
struct GdPlaneF *d_get_plane(void) {
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_NETS:
return &((struct ObjNet *) sDynListCurObj)->unkBC;
break;
case OBJ_TYPE_PLANES:
return &((struct ObjPlane *) sDynListCurObj)->plane28;
break;
case OBJ_TYPE_ZONES:
return &((struct ObjZone *) sDynListCurObj)->unk14;
break;
default:
return &sGdNullPlaneF;
}
}
/**
* Copy the matrix from the current dynamic object into `dst`.
*/
void d_get_matrix(Mat4f *dst) {
struct GdObj *dynobj; // sp24
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
dynobj = sDynListCurObj;
switch (sDynListCurObj->type) {
case OBJ_TYPE_NETS:
gd_copy_mat4f(&((struct ObjNet *) dynobj)->mat128, dst);
break;
break; // lol
case OBJ_TYPE_JOINTS:
gd_copy_mat4f(&((struct ObjJoint *) dynobj)->matE8, dst);
break;
case OBJ_TYPE_CAMERAS:
gd_copy_mat4f(&((struct ObjCamera *) dynobj)->unkE8, dst);
break;
case OBJ_TYPE_PARTICLES:
gd_set_identity_mat4(dst);
break;
case OBJ_TYPE_SHAPES:
gd_set_identity_mat4(dst);
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dGetMatrix()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Set the matrix of the current dynamic object by copying `src` into the object.
*/
void d_set_matrix(Mat4f *src) {
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_NETS:
gd_copy_mat4f(src, &((struct ObjNet *) sDynListCurObj)->mat128);
//! @bug When setting an `ObjNet` matrix, the source is copied twice
//! due to a probable copy-paste line repeat error
gd_copy_mat4f(src, &((struct ObjNet *) sDynListCurObj)->mat128);
break;
case OBJ_TYPE_JOINTS:
gd_copy_mat4f(src, &((struct ObjJoint *) sDynListCurObj)->matE8);
break;
case OBJ_TYPE_CAMERAS:
gd_copy_mat4f(src, &((struct ObjCamera *) sDynListCurObj)->unk64);
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetMatrix()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Set the rotation matrix of the current dynamic object by copying
* the input matrix `src`.
*/
void d_set_rot_mtx(Mat4f *src) {
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_JOINTS:
gd_copy_mat4f(src, &((struct ObjJoint *) sDynListCurObj)->mat128);
break;
case OBJ_TYPE_NETS:
gd_copy_mat4f(src, &((struct ObjNet *) sDynListCurObj)->mat168);
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetRMatrix()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Get a pointer to the current dynamic object's rotation matrix.
*/
Mat4f *d_get_rot_mtx_ptr(void) {
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_JOINTS:
return &((struct ObjJoint *) sDynListCurObj)->mat128;
case OBJ_TYPE_NETS:
return &((struct ObjNet *) sDynListCurObj)->mat168;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dGetRMatrixPtr()",
sDynListCurInfo->name, sDynListCurObj->type);
}
// No null return due to `fatal_printf()` being a non-returning function?
}
/**
* Copy `src` into the identity matrix of the current dynamic object.
*/
void d_set_idn_mtx(Mat4f *src) {
struct GdObj *dynobj; // sp24
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
dynobj = sDynListCurObj;
switch (sDynListCurObj->type) {
case OBJ_TYPE_NETS:
gd_copy_mat4f(src, &((struct ObjNet *) dynobj)->matE8);
break;
case OBJ_TYPE_JOINTS:
gd_copy_mat4f(src, &((struct ObjJoint *) dynobj)->mat168);
break;
case OBJ_TYPE_LIGHTS:
((struct ObjLight *) dynobj)->position.x = (*src)[3][0];
((struct ObjLight *) dynobj)->position.y = (*src)[3][1];
((struct ObjLight *) dynobj)->position.z = (*src)[3][2];
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetIMatrix()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}
/**
* Get a pointer to the current dynamic object's matrix.
*/
Mat4f *d_get_matrix_ptr(void) {
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_NETS:
return &((struct ObjNet *) sDynListCurObj)->mat128;
break;
case OBJ_TYPE_CAMERAS:
return &((struct ObjCamera *) sDynListCurObj)->unk64;
break;
case OBJ_TYPE_BONES:
return &((struct ObjBone *) sDynListCurObj)->mat70;
break;
case OBJ_TYPE_JOINTS:
return &((struct ObjJoint *) sDynListCurObj)->matE8;
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dGetMatrixPtr()",
sDynListCurInfo->name, sDynListCurObj->type);
}
// No null return due to `fatal_printf()` being a non-returning function?
}
/**
* Get a pointer to the current dynamic object's identity matrix.
*/
Mat4f *d_get_idn_mtx_ptr(void) {
struct GdObj *dynobj; // sp24
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
dynobj = sDynListCurObj;
switch (sDynListCurObj->type) {
case OBJ_TYPE_NETS:
return &((struct ObjNet *) dynobj)->matE8;
break;
case OBJ_TYPE_JOINTS:
return &((struct ObjJoint *) dynobj)->mat168;
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dGetIMatrixPtr()",
sDynListCurInfo->name, sDynListCurObj->type);
}
// No null return due to `fatal_printf()` being a non-returning function?
}
/**
* Use the dynamic object system to calculate the distance between
* two `GdObj`s. The objects don't have to be dynamic objects.
*/
f32 d_calc_world_dist_btwn(struct GdObj *obj1, struct GdObj *obj2) {
struct GdVec3f obj1pos; // sp34
struct GdVec3f obj2pos; // sp28
struct GdVec3f posdiff; // sp1C
set_cur_dynobj(obj1);
d_get_world_pos(&obj1pos);
set_cur_dynobj(obj2);
d_get_world_pos(&obj2pos);
posdiff.x = obj2pos.x - obj1pos.x;
posdiff.y = obj2pos.y - obj1pos.y;
posdiff.z = obj2pos.z - obj1pos.z;
return gd_vec3f_magnitude(&posdiff);
}
/**
* Create a new weight for the current dynamic `ObjJoint`. The input weight value
* is out of 100.
*/
void d_set_skin_weight(s32 id, f32 percentWeight) {
if (sDynListCurObj == NULL) {
fatal_printf("proc_dynlist(): No current object");
}
switch (sDynListCurObj->type) {
case OBJ_TYPE_JOINTS:
set_skin_weight((struct ObjJoint *) sDynListCurObj, id, NULL,
percentWeight / 100.0); //? 100.0f
break;
default:
fatal_printf("%s: Object '%s'(%x) does not support this function.", "dSetSkinWeight()",
sDynListCurInfo->name, sDynListCurObj->type);
}
}