perfect_dark/src/lib/model.c

4322 lines
104 KiB
C

#include <ultra64.h>
#include "constants.h"
#include "game/game_096700.h"
#include "game/acosfasinf.h"
#include "game/quaternion.h"
#include "game/camera.h"
#include "game/floor.h"
#include "game/ceil.h"
#include "game/tex.h"
#include "game/gfxmemory.h"
#include "game/bg.h"
#include "game/file.h"
#include "bss.h"
#include "lib/rng.h"
#include "lib/mtx.h"
#include "lib/anim.h"
#include "lib/model.h"
#include "data.h"
#include "types.h"
#if VERSION >= VERSION_PAL_BETA
u8 var8005efb0_2 = 0;
#endif
u32 var8005efb0 = 0;
bool g_ModelDistanceDisabled = false;
f32 g_ModelDistanceScale = 1;
bool var8005efbc = false;
f32 var8005efc0 = 0;
bool (*var8005efc4)(struct model *model, struct modelnode *node) = NULL;
#if VERSION >= VERSION_PAL_BETA
bool var8005efd8_2 = false;
#endif
struct gfxvtx *(*g_ModelVtxAllocatorFunc)(s32 numvertices) = NULL;
void (*g_ModelJointPositionedFunc)(s32 mtxindex, Mtxf *mtx) = NULL;
void modelSetDistanceChecksDisabled(bool disabled)
{
g_ModelDistanceDisabled = disabled;
}
void modelSetDistanceScale(f32 scale)
{
g_ModelDistanceScale = scale;
}
void modelSetVtxAllocatorFunc(struct gfxvtx *(*fn)(s32 numvertices))
{
g_ModelVtxAllocatorFunc = fn;
}
s32 model0001a524(struct modelnode *node, s32 arg1)
{
s32 index;
union modelrodata *rodata1;
union modelrodata *rodata2;
union modelrodata *rodata3;
while (node) {
switch (node->type & 0xff) {
case MODELNODETYPE_CHRINFO:
rodata1 = node->rodata;
return rodata1->chrinfo.mtxindex;
case MODELNODETYPE_POSITION:
rodata2 = node->rodata;
return rodata2->position.mtxindexes[arg1 == 0x200 ? 2 : (arg1 == 0x100 ? 1 : 0)];
case MODELNODETYPE_POSITIONHELD:
rodata3 = node->rodata;
return rodata3->positionheld.mtxindex;
}
node = node->parent;
}
return -1;
}
Mtxf *model0001a5cc(struct model *model, struct modelnode *node, s32 arg2)
{
s32 index = model0001a524(node, arg2);
if (index >= 0) {
return &model->matrices[index];
}
return NULL;
}
Mtxf *model0001a60c(struct model *model)
{
return model0001a5cc(model, model->filedata->rootnode, 0);
}
struct modelnode *model0001a634(struct model *model, s32 mtxindex)
{
struct modelnode *node = model->filedata->rootnode;
union modelrodata *rodata1;
union modelrodata *rodata2;
union modelrodata *rodata3;
while (node) {
switch (node->type & 0xff) {
case MODELNODETYPE_CHRINFO:
rodata1 = node->rodata;
if (mtxindex == rodata1->chrinfo.mtxindex) {
return node;
}
break;
case MODELNODETYPE_POSITION:
rodata2 = node->rodata;
if (mtxindex == rodata2->position.mtxindexes[0]
|| mtxindex == rodata2->position.mtxindexes[1]
|| mtxindex == rodata2->position.mtxindexes[2]) {
return node;
}
break;
case MODELNODETYPE_POSITIONHELD:
rodata3 = node->rodata;
if (mtxindex == rodata3->positionheld.mtxindex) {
return node;
}
break;
}
if (node->child) {
node = node->child;
} else {
while (node) {
if (node && node->next) {
node = node->next;
break;
}
node = node->parent;
}
}
}
return NULL;
}
struct modelnode *model0001a740(struct modelnode *node)
{
while (node) {
u32 type = node->type & 0xff;
if (type == MODELNODETYPE_CHRINFO
|| type == MODELNODETYPE_POSITION
|| type == MODELNODETYPE_POSITIONHELD) {
break;
}
node = node->parent;
}
return node;
}
struct modelnode *model0001a784(struct modelnode *node)
{
while ((node = node->parent)) {
u32 type = node->type & 0xff;
if (type == MODELNODETYPE_CHRINFO
|| type == MODELNODETYPE_POSITION
|| type == MODELNODETYPE_POSITIONHELD) {
break;
}
}
return node;
}
struct modelnode *model0001a7cc(struct modelnode *basenode)
{
struct modelnode *node = basenode->child;
while (node) {
u32 type = node->type & 0xff;
if (type == MODELNODETYPE_CHRINFO
|| type == MODELNODETYPE_POSITION
|| type == MODELNODETYPE_POSITIONHELD) {
break;
}
if (node->child) {
node = node->child;
} else {
while (node) {
if (node == basenode) {
node = NULL;
break;
}
if (node->next) {
node = node->next;
break;
}
node = node->parent;
}
}
}
return node;
}
struct modelnode *model0001a85c(struct modelnode *basenode)
{
struct modelnode *node = basenode;
struct modelnode *next;
u32 type;
while (node) {
if (node != basenode && node->child) {
node = node->child;
} else {
while (node) {
if (node != basenode) {
type = node->type & 0xff;
if (type == MODELNODETYPE_CHRINFO
|| type == MODELNODETYPE_POSITION
|| type == MODELNODETYPE_POSITIONHELD) {
node = NULL;
break;
}
}
if (node->next) {
node = node->next;
break;
}
node = node->parent;
}
if (!node) {
break;
}
}
type = node->type & 0xff;
if (type == MODELNODETYPE_CHRINFO
|| type == MODELNODETYPE_POSITION
|| type == MODELNODETYPE_POSITIONHELD) {
break;
}
}
return node;
}
struct modelnode *modelGetPart(struct modelfiledata *modelfiledata, s32 partnum)
{
s32 upper;
s32 lower;
u32 i;
s16 *partnums;
if (modelfiledata->numparts == 0) {
return NULL;
}
partnums = (s16 *)&modelfiledata->parts[modelfiledata->numparts];
lower = 0;
upper = modelfiledata->numparts;
while (upper >= lower) {
i = (lower + upper) / 2;
if (partnum == partnums[i]) {
return modelfiledata->parts[i];
}
if (partnum < partnums[i]) {
upper = i - 1;
} else {
lower = i + 1;
}
}
return NULL;
}
void *modelGetPartRodata(struct modelfiledata *modelfiledata, s32 partnum)
{
struct modelnode *node = modelGetPart(modelfiledata, partnum);
if (node) {
return node->rodata;
}
return NULL;
}
f32 model0001a9e8(struct model *model)
{
Mtxf *mtx = model0001a60c(model);
if (mtx) {
return -mtx->m[3][2];
}
return 0;
}
#if VERSION >= VERSION_NTSC_1_0
// ntsc-beta has this function in another file
void *modelGetNodeRwData(struct model *model, struct modelnode *node)
{
u32 index = 0;
union modelrwdata **rwdatas = model->rwdatas;
switch (node->type & 0xff) {
case MODELNODETYPE_CHRINFO:
index = node->rodata->chrinfo.rwdataindex;
break;
case MODELNODETYPE_DL:
index = node->rodata->dl.rwdataindex;
break;
case MODELNODETYPE_DISTANCE:
index = node->rodata->distance.rwdataindex;
break;
case MODELNODETYPE_TOGGLE:
index = node->rodata->toggle.rwdataindex;
break;
case MODELNODETYPE_REORDER:
index = node->rodata->reorder.rwdataindex;
break;
case MODELNODETYPE_0B:
index = node->rodata->type0b.rwdataindex;
break;
case MODELNODETYPE_CHRGUNFIRE:
index = node->rodata->chrgunfire.rwdataindex;
break;
case MODELNODETYPE_HEADSPOT:
index = node->rodata->headspot.rwdataindex;
break;
}
while (node->parent) {
node = node->parent;
if ((node->type & 0xff) == MODELNODETYPE_HEADSPOT) {
struct modelrwdata_headspot *tmp = modelGetNodeRwData(model, node);
rwdatas = tmp->rwdatas;
break;
}
}
return &rwdatas[index];
}
#endif
void modelNodeGetPosition(struct model *model, struct modelnode *node, struct coord *pos)
{
switch (node->type & 0xff) {
case MODELNODETYPE_CHRINFO:
{
struct modelrwdata_chrinfo *rwdata = modelGetNodeRwData(model, node);
pos->x = rwdata->pos.x;
pos->y = rwdata->pos.y;
pos->z = rwdata->pos.z;
}
break;
case MODELNODETYPE_POSITION:
{
struct modelrodata_position *rodata = &node->rodata->position;
pos->x = rodata->pos.x;
pos->y = rodata->pos.y;
pos->z = rodata->pos.z;
}
break;
case MODELNODETYPE_POSITIONHELD:
{
struct modelrodata_positionheld *rodata = &node->rodata->positionheld;
pos->x = rodata->pos.x;
pos->y = rodata->pos.y;
pos->z = rodata->pos.z;
}
break;
default:
pos->x = 0;
pos->y = 0;
pos->z = 0;
break;
}
}
void modelNodeSetPosition(struct model *model, struct modelnode *node, struct coord *pos)
{
switch (node->type & 0xff) {
case MODELNODETYPE_CHRINFO:
{
struct modelrwdata_chrinfo *rwdata = modelGetNodeRwData(model, node);
struct coord diff[1];
diff[0].x = pos->x - rwdata->pos.x;
diff[0].z = pos->z - rwdata->pos.z;
rwdata->pos.x = pos->x;
rwdata->pos.y = pos->y;
rwdata->pos.z = pos->z;
rwdata->unk24.x += diff[0].x; rwdata->unk24.z += diff[0].z;
rwdata->unk34.x += diff[0].x; rwdata->unk34.z += diff[0].z;
rwdata->unk40.x += diff[0].x; rwdata->unk40.z += diff[0].z;
rwdata->unk4c.x += diff[0].x; rwdata->unk4c.z += diff[0].z;
}
break;
case MODELNODETYPE_POSITION:
{
struct modelrodata_position *rodata = &node->rodata->position;
rodata->pos.x = pos->x;
rodata->pos.y = pos->y;
rodata->pos.z = pos->z;
}
break;
case MODELNODETYPE_POSITIONHELD:
{
struct modelrodata_positionheld *rodata = &node->rodata->positionheld;
rodata->pos.x = pos->x;
rodata->pos.y = pos->y;
rodata->pos.z = pos->z;
}
break;
}
}
void modelGetRootPosition(struct model *model, struct coord *pos)
{
modelNodeGetPosition(model, model->filedata->rootnode, pos);
}
void modelSetRootPosition(struct model *model, struct coord *pos)
{
modelNodeSetPosition(model, model->filedata->rootnode, pos);
}
void modelNodeGetModelRelativePosition(struct model *model, struct modelnode *node, struct coord *pos)
{
pos->x = 0;
pos->y = 0;
pos->z = 0;
while (node) {
struct coord nodepos;
u32 type = node->type & 0xff;
if (type == MODELNODETYPE_CHRINFO
|| type == MODELNODETYPE_POSITION
|| type == MODELNODETYPE_POSITIONHELD) {
modelNodeGetPosition(model, node, &nodepos);
pos->x += nodepos.x;
pos->y += nodepos.y;
pos->z += nodepos.z;
}
node = node->parent;
}
}
f32 model0001ae44(struct model *model)
{
if ((model->filedata->rootnode->type & 0xff) == MODELNODETYPE_CHRINFO) {
union modelrwdata *rwdata = modelGetNodeRwData(model, model->filedata->rootnode);
return rwdata->chrinfo.unk14;
}
return 0;
}
void model0001ae90(struct model *model, f32 angle)
{
if ((model->filedata->rootnode->type & 0xff) == MODELNODETYPE_CHRINFO) {
struct modelrwdata_chrinfo *rwdata = modelGetNodeRwData(model, model->filedata->rootnode);
f32 diff = angle - rwdata->unk14;
if (diff < 0) {
diff += M_BADTAU;
}
rwdata->unk30 += diff;
if (rwdata->unk30 >= M_BADTAU) {
rwdata->unk30 -= M_BADTAU;
}
rwdata->unk20 += diff;
if (rwdata->unk20 >= M_BADTAU) {
rwdata->unk20 -= M_BADTAU;
}
rwdata->unk14 = angle;
}
}
void modelSetScale(struct model *model, f32 scale)
{
model->scale = scale;
}
void modelSetAnimScale(struct model *model, f32 scale)
{
if (model->anim) {
model->anim->animscale = scale;
}
}
f32 model0001af80(struct model *model)
{
return model->filedata->unk10 * model->scale;
}
void model0001af98(struct coord *arg0, struct coord *arg1, f32 frac)
{
arg0->x += (arg1->x - arg0->x) * frac;
arg0->y += (arg1->y - arg0->y) * frac;
arg0->z += (arg1->z - arg0->z) * frac;
}
f32 model0001afe8(f32 arg0, f32 angle, f32 mult)
{
f32 value = angle - arg0;
if (angle < arg0) {
value += M_BADTAU;
}
if (value < M_PI) {
arg0 += value * mult;
if (arg0 >= M_BADTAU) {
arg0 -= M_BADTAU;
}
} else {
arg0 -= (M_BADTAU - value) * mult;
if (arg0 < 0) {
arg0 += M_BADTAU;
}
}
return arg0;
}
void model0001b07c(struct coord *arg0, struct coord *arg1, f32 mult)
{
arg0->x = model0001afe8(arg0->x, arg1->x, mult);
arg0->y = model0001afe8(arg0->y, arg1->y, mult);
arg0->z = model0001afe8(arg0->z, arg1->z, mult);
}
void model0001b0e8(struct model *model, struct modelnode *node)
{
union modelrwdata *rwdata;
struct anim *anim = model->anim;
struct coord sp34;
struct coord sp28;
f32 frac;
if (!anim) {
return;
}
rwdata = modelGetNodeRwData(model, node);
if (rwdata->chrinfo.unk00) {
return;
}
sp34.x = rwdata->chrinfo.unk34.x;
sp34.y = rwdata->chrinfo.unk34.y;
sp34.z = rwdata->chrinfo.unk34.z;
rwdata->chrinfo.unk14 = rwdata->chrinfo.unk30;
if (g_Vars.in_cutscene && anim->speed > 0.0f) {
#if VERSION >= VERSION_PAL_BETA
frac = floorf(anim->frac / anim->speed + 0.01f) * anim->speed;
#else
frac = floorf(anim->frac / anim->speed) * anim->speed;
#endif
} else {
frac = anim->frac;
}
if (frac != 0.0f && rwdata->chrinfo.unk01) {
model0001af98(&sp34, &rwdata->chrinfo.unk24, frac);
rwdata->chrinfo.unk14 = model0001afe8(rwdata->chrinfo.unk30, rwdata->chrinfo.unk20, frac);
}
if (anim->animnum2 || anim->fracmerge) {
if (rwdata->chrinfo.unk02) {
f32 y = rwdata->chrinfo.unk4c.y;
if (anim->frac2 != 0.0f) {
y += (rwdata->chrinfo.unk40.y - y) * anim->frac2;
}
sp34.y += (y - sp34.y) * anim->fracmerge;
}
}
if (anim->unk70 == NULL) {
rwdata->chrinfo.pos.x = sp34.x;
rwdata->chrinfo.pos.y = rwdata->chrinfo.ground + sp34.f[1];
rwdata->chrinfo.pos.z = sp34.z;
} else {
sp28.x = sp34.x;
sp28.y = sp34.y;
sp28.z = sp34.z;
if (anim->unk70(model, &rwdata->chrinfo.pos, &sp28, &rwdata->chrinfo.ground)) {
rwdata->chrinfo.pos.x = sp28.x;
rwdata->chrinfo.pos.y = rwdata->chrinfo.ground + sp28.f[1];
rwdata->chrinfo.pos.z = sp28.z;
sp34.x = sp28.x - sp34.x;
sp34.z = sp28.z - sp34.z;
rwdata->chrinfo.unk34.x += sp34.x;
rwdata->chrinfo.unk34.z += sp34.z;
if (rwdata->chrinfo.unk01) {
rwdata->chrinfo.unk24.x += sp34.x;
rwdata->chrinfo.unk24.z += sp34.z;
}
if (rwdata->chrinfo.unk02) {
rwdata->chrinfo.unk4c.x += sp34.x;
rwdata->chrinfo.unk4c.z += sp34.z;
rwdata->chrinfo.unk40.x += sp34.x;
rwdata->chrinfo.unk40.z += sp34.z;
}
}
}
}
void model0001b3bc(struct model *model)
{
struct modelnode *node = model->filedata->rootnode;
if (node && (node->type & 0xff) == MODELNODETYPE_CHRINFO) {
model0001b0e8(model, node);
}
}
void model0001b400(struct modelrenderdata *arg0, struct model *model, struct modelnode *node)
{
struct anim *anim = model->anim;
union modelrodata *rodata = node->rodata;
union modelrwdata *rwdata = modelGetNodeRwData(model, node);
f32 scale = model->scale;
struct coord *sp254 = &rwdata->chrinfo.pos;
f32 sp250 = rwdata->chrinfo.unk14;
Mtxf *sp24c;
u32 stack1;
Mtxf *mtx = &model->matrices[rodata->chrinfo.mtxindex];
s32 sp240 = rodata->chrinfo.unk00;
struct skeleton *skel = model->filedata->skel;
struct coord sp230;
struct coord sp224;
struct coord sp218;
Mtxf sp1d8;
Mtxf sp198;
Mtxf sp158;
f32 sp154;
struct coord sp148;
struct coord sp13c;
struct coord sp130;
struct coord sp124;
struct coord sp118;
struct coord sp10c;
f32 spfc[4];
f32 spec[4];
u8 stack4[0xc];
f32 spdc;
struct coord spd0;
struct coord spc4;
struct coord spb8;
Mtxf sp78;
Mtxf sp38;
if (rodata->chrinfo.mtxindex);
if (node->parent) {
sp24c = model0001a5cc(model, node->parent, 0);
} else {
sp24c = arg0->unk00;
}
anim00024050(sp240, anim->flip, skel, anim->animnum, anim->unk04, &sp230, &sp224, &sp218);
if (g_Vars.in_cutscene && anim->speed > 0) {
#if VERSION >= VERSION_PAL_BETA
sp154 = floorf(anim->frac / anim->speed + 0.01f) * anim->speed;
#else
sp154 = floorf(anim->frac / anim->speed) * anim->speed;
#endif
} else {
sp154 = anim->frac;
}
if (sp154 != 0.0f) {
anim00024050(sp240, anim->flip, skel, anim->animnum, anim->unk05, &sp148, &sp13c, &sp130);
model0001b07c(&sp230, &sp148, sp154);
}
if (anim->fracmerge != 0.0f) {
anim00024050(sp240, anim->flip2, skel, anim->animnum2, anim->unk06, &sp124, &sp118, &sp10c);
if (anim->frac2 != 0.0f) {
anim00024050(sp240, anim->flip2, skel, anim->animnum2, anim->unk07, &spd0, &spc4, &spb8);
model0001b07c(&sp124, &spd0, anim->frac2);
}
if ((g_Anims[anim->animnum].flags & ANIMFLAG_02) && (g_Anims[anim->animnum2].flags & ANIMFLAG_02) == 0) {
mtx4LoadYRotation(rwdata->chrinfo.unk14, &sp78);
mtx4LoadRotation(&sp124, &sp38);
mtx00015be0(&sp78, &sp38);
quaternion0f097044(&sp38, spec);
} else {
quaternion0f096ca0(&sp124, spec);
}
quaternion0f096ca0(&sp230, spfc);
quaternion0f0976c0(spfc, spec);
quaternionSlerp(spfc, spec, anim->fracmerge, &spdc);
quaternionToMtx(&spdc, &sp1d8);
} else {
mtx4LoadRotation(&sp230, &sp1d8);
}
if (g_Anims[anim->animnum].flags & ANIMFLAG_02) {
mtx4LoadTranslation(sp254, &sp198);
} else {
if (rwdata->chrinfo.unk18 != 0.0f) {
sp250 = model0001afe8(sp250, rwdata->chrinfo.unk1c, rwdata->chrinfo.unk18);
}
mtx4LoadYRotationWithTranslation(sp254, sp250, &sp198);
}
mtx00015be4(&sp198, &sp1d8, &sp158);
if (scale != 1.0f) {
mtx00015f4c(scale, &sp158);
}
if (sp24c) {
mtx00015be4(sp24c, &sp158, mtx);
} else {
mtx4Copy(&sp158, mtx);
}
}
void modelPositionJointUsingVecRot(struct modelrenderdata *renderdata, struct model *model, struct modelnode *node, struct coord *rot, struct coord *pos, bool allowscale, struct coord *arg6)
{
s32 nodetype = node->type;
struct modelrodata_position *rodata = &node->rodata->position;
Mtxf *rendermtx;
u32 stack;
Mtxf mtx68;
s32 mtxindex0 = rodata->mtxindex0;
s32 mtxindex1 = rodata->mtxindex1;
s32 mtxindex2 = rodata->mtxindex2;
Mtxf *matrices = model->matrices;
if (node->parent != NULL) {
rendermtx = model0001a5cc(model, node->parent, 0);
} else {
rendermtx = renderdata->unk00;
}
if (rendermtx != NULL) {
Mtxf *nodemtx = &matrices[mtxindex0];
mtx4LoadRotationAndTranslation(pos, rot, &mtx68);
if (allowscale && model->scale != 1.0f) {
mtx00015f04(model->scale, &mtx68);
}
if (arg6->x != 1.0f) {
mtx00015df0(arg6->x, &mtx68);
}
if (arg6->y != 1.0f) {
mtx00015e4c(arg6->y, &mtx68);
}
if (arg6->z != 1.0f) {
mtx00015ea8(arg6->z, &mtx68);
}
mtx00015be4(rendermtx, &mtx68, nodemtx);
if (g_ModelJointPositionedFunc != NULL) {
g_ModelJointPositionedFunc(mtxindex0, nodemtx);
}
} else {
Mtxf *nodemtx = &matrices[mtxindex0];
mtx4LoadRotationAndTranslation(pos, rot, nodemtx);
if (allowscale && model->scale != 1.0f) {
mtx00015f04(model->scale, nodemtx);
}
if (arg6->x != 1.0f) {
mtx00015df0(arg6->x, nodemtx);
}
if (arg6->y != 1.0f) {
mtx00015e4c(arg6->y, nodemtx);
}
if (arg6->z != 1.0f) {
mtx00015ea8(arg6->z, nodemtx);
}
}
if (nodetype & MODELNODETYPE_0100) {
Mtxf *nodemtx = &matrices[mtxindex1];
f32 sp3c[4];
f32 sp2c[4];
quaternion0f096ca0(rot, sp3c);
quaternion0f097518(sp3c, 0.5f, sp2c);
if (rendermtx != NULL) {
quaternionToTransformMtx(pos, sp2c, &mtx68);
mtx00015be4(rendermtx, &mtx68, nodemtx);
} else {
quaternionToTransformMtx(pos, sp2c, nodemtx);
}
}
if (nodetype & MODELNODETYPE_0200) {
Mtxf *finalmtx = rendermtx ? &mtx68 : &matrices[mtxindex2];
f32 roty = rot->y;
if (roty < M_PI) {
roty *= 0.5f;
} else {
roty = M_BADTAU - (M_BADTAU - roty) * 0.5f;
}
mtx4LoadYRotation(roty, finalmtx);
if (roty >= M_PI) {
roty = M_BADTAU - roty;
}
if (roty < 0.890118f) { // 51 degrees
roty = func0f096700(roty);
} else {
roty = 1.5f;
}
mtx00015edc(roty, finalmtx);
mtx4SetTranslation(pos, finalmtx);
if (rendermtx != NULL) {
Mtxf *nodemtx = &matrices[mtxindex2];
mtx00015be4(rendermtx, finalmtx, nodemtx);
}
}
}
void modelPositionJointUsingQuatRot(struct modelrenderdata *renderdata, struct model *model, struct modelnode *node, f32 rot[4], struct coord *pos, struct coord *arg5)
{
s32 nodetype = node->type;
struct modelrodata_position *rodata = &node->rodata->position;
Mtxf *rendermtx;
u32 stack;
Mtxf mtx58;
s32 mtxindex0 = rodata->mtxindex0;
s32 mtxindex1 = rodata->mtxindex1;
s32 mtxindex2 = rodata->mtxindex2;
Mtxf *matrices = model->matrices;
if (node->parent != NULL) {
rendermtx = model0001a5cc(model, node->parent, 0);
} else {
rendermtx = renderdata->unk00;
}
if (rendermtx != NULL) {
Mtxf *nodemtx = &matrices[mtxindex0];
quaternionToTransformMtx(pos, rot, &mtx58);
if (arg5->x != 1.0f) {
mtx00015df0(arg5->x, &mtx58);
}
if (arg5->y != 1.0f) {
mtx00015e4c(arg5->y, &mtx58);
}
if (arg5->z != 1.0f) {
mtx00015ea8(arg5->z, &mtx58);
}
mtx00015be4(rendermtx, &mtx58, nodemtx);
if (g_ModelJointPositionedFunc != NULL) {
g_ModelJointPositionedFunc(mtxindex0, nodemtx);
}
} else {
Mtxf *nodemtx = &matrices[mtxindex0];
quaternionToTransformMtx(pos, rot, nodemtx);
if (arg5->x != 1.0f) {
mtx00015df0(arg5->x, nodemtx);
}
if (arg5->y != 1.0f) {
mtx00015e4c(arg5->y, nodemtx);
}
if (arg5->z != 1.0f) {
mtx00015ea8(arg5->z, nodemtx);
}
}
if (nodetype & MODELNODETYPE_0100) {
Mtxf *nodemtx = &matrices[mtxindex1];
f32 sp2c[4];
quaternion0f097518(rot, 0.5f, sp2c);
if (rendermtx != NULL) {
quaternionToTransformMtx(pos, sp2c, &mtx58);
mtx00015be4(rendermtx, &mtx58, nodemtx);
} else {
quaternionToTransformMtx(pos, sp2c, nodemtx);
}
}
if (nodetype & MODELNODETYPE_0200) {
Mtxf *finalmtx = rendermtx ? &mtx58 : &matrices[mtxindex2];
f32 roty = 2.0f * acosf(rot[0]);
if (roty < M_PI) {
roty *= 0.5f;
} else {
roty = M_BADTAU - (M_BADTAU - roty) * 0.5f;
}
mtx4LoadYRotation(roty, finalmtx);
if (roty >= M_PI) {
roty = M_BADTAU - roty;
}
if (roty < 0.890118f) { // 51 degrees
roty = func0f096700(roty);
} else {
roty = 1.5f;
}
mtx00015edc(roty, finalmtx);
mtx4SetTranslation(pos, finalmtx);
if (rendermtx != NULL) {
Mtxf *nodemtx = &matrices[mtxindex2];
mtx00015be4(rendermtx, finalmtx, nodemtx);
}
}
}
void model0001bfa8(struct modelrenderdata *renderdata, struct model *model, struct modelnode *node)
{
struct anim *anim;
struct modelrodata_position *rodata = &node->rodata->position;
s32 partnum;
struct skeleton *skel;
struct coord sp144;
struct coord sp138;
struct coord sp12c;
bool sp128;
Mtxf spe8;
Mtxf *mtx;
f32 spe0;
struct coord spd4;
struct coord spc8;
struct coord spbc;
struct coord spb0;
struct coord spa4;
struct coord sp98;
f32 sp88[4];
f32 sp78[4];
f32 sp68[4];
struct coord sp5c;
struct coord sp50;
struct coord sp44;
anim = model->anim;
if (anim != NULL) {
partnum = rodata->part;
skel = model->filedata->skel;
if (anim->animnum != 0) {
sp128 = (g_Anims[anim->animnum].flags & ANIMFLAG_02) && node == model->filedata->rootnode;
anim00024050(partnum, anim->flip, skel, anim->animnum, anim->unk04, &sp144, &sp138, &sp12c);
if (g_Vars.in_cutscene && anim->speed > 0.0f) {
#if VERSION >= VERSION_PAL_BETA
spe0 = floorf(anim->frac / anim->speed + 0.0099999997764826f) * anim->speed;
#else
spe0 = floorf(anim->frac / anim->speed) * anim->speed;
#endif
} else {
spe0 = anim->frac;
}
if (spe0 != 0.0f) {
anim00024050(partnum, anim->flip, skel, anim->animnum, anim->unk05, &spd4, &spc8, &spbc);
model0001b07c(&sp144, &spd4, spe0);
#if VERSION >= VERSION_PAL_BETA
if (sp128 || var8005efd8_2)
#else
if (sp128)
#endif
{
model0001af98(&sp138, &spc8, spe0);
}
}
} else {
sp138.f[0] = sp138.f[1] = sp138.f[2] = 0.0f;
sp144.f[0] = sp144.f[1] = sp144.f[2] = 0.0f;
sp12c.f[0] = sp12c.f[1] = sp12c.f[2] = 1.0f;
sp128 = false;
}
if (anim->fracmerge != 0.0f) {
anim00024050(partnum, anim->flip2, skel, anim->animnum2, anim->unk06, &spb0, &spa4, &sp98);
if (anim->frac2 != 0.0f) {
anim00024050(partnum, anim->flip2, skel, anim->animnum2, anim->unk07, &sp5c, &sp50, &sp44);
model0001b07c(&spb0, &sp5c, anim->frac2);
}
quaternion0f096ca0(&sp144, sp88);
quaternion0f096ca0(&spb0, sp78);
quaternion0f0976c0(sp88, sp78);
quaternionSlerp(sp88, sp78, anim->fracmerge, sp68);
if (sp138.f[0] != 0.0f || sp138.f[1] != 0.0f || sp138.f[2] != 0.0f) {
sp138.x *= anim->animscale;
sp138.y *= anim->animscale;
sp138.z *= anim->animscale;
if (node != model->filedata->rootnode) {
sp138.x += rodata->pos.x;
sp138.y += rodata->pos.y;
sp138.z += rodata->pos.z;
}
modelPositionJointUsingQuatRot(renderdata, model, node, sp68, &sp138, &sp12c);
} else if (node != model->filedata->rootnode) {
modelPositionJointUsingQuatRot(renderdata, model, node, sp68, &rodata->pos, &sp12c);
} else {
modelPositionJointUsingQuatRot(renderdata, model, node, sp68, &sp138, &sp12c);
}
} else if (sp128) {
f32 mult = func0f15c888();
sp138.x *= mult;
sp138.y *= mult;
sp138.z *= mult;
modelPositionJointUsingVecRot(renderdata, model, node, &sp144, &sp138, true, &sp12c);
} else if (sp138.f[0] != 0.0f || sp138.f[1] != 0.0f || sp138.f[2] != 0.0f) {
sp138.x *= anim->animscale;
sp138.y *= anim->animscale;
sp138.z *= anim->animscale;
if (node != model->filedata->rootnode) {
sp138.x += rodata->pos.x;
sp138.y += rodata->pos.y;
sp138.z += rodata->pos.z;
}
modelPositionJointUsingVecRot(renderdata, model, node, &sp144, &sp138, false, &sp12c);
} else if (node != model->filedata->rootnode) {
modelPositionJointUsingVecRot(renderdata, model, node, &sp144, &rodata->pos, false, &sp12c);
} else {
modelPositionJointUsingVecRot(renderdata, model, node, &sp144, &sp138, false, &sp12c);
}
} else {
if (node->parent) {
mtx = model0001a5cc(model, node->parent, 0);
} else {
mtx = renderdata->unk00;
}
if (mtx) {
mtx4LoadTranslation(&rodata->pos, &spe8);
mtx00015be4(mtx, &spe8, &model->matrices[rodata->mtxindex0]);
} else {
mtx4LoadTranslation(&rodata->pos, &model->matrices[rodata->mtxindex0]);
}
}
}
void model0001c5b4(struct modelrenderdata *arg0, struct model *model, struct modelnode *node)
{
union modelrodata *rodata = node->rodata;
Mtxf *sp68;
Mtxf sp28;
s32 mtxindex = rodata->positionheld.mtxindex;
Mtxf *matrices = model->matrices;
if (node->parent) {
sp68 = model0001a5cc(model, node->parent, 0);
} else {
sp68 = arg0->unk00;
}
if (sp68) {
mtx4LoadTranslation(&rodata->positionheld.pos, &sp28);
mtx00015be4(sp68, &sp28, &matrices[mtxindex]);
} else {
mtx4LoadTranslation(&rodata->positionheld.pos, &matrices[mtxindex]);
}
}
/**
* For a distance node, set its target to visible based on distance.
*/
void model0001c664(struct model *model, struct modelnode *node)
{
union modelrodata *rodata = node->rodata;
union modelrwdata *rwdata = modelGetNodeRwData(model, node);
Mtxf *mtx = model0001a5cc(model, node, 0);
f32 distance;
if (g_ModelDistanceDisabled || !mtx) {
distance = 0;
} else {
distance = -mtx->m[3][2] * camGetLodScaleZ();
if (g_ModelDistanceScale != 1) {
distance *= g_ModelDistanceScale;
}
}
if (distance > rodata->distance.near * model->scale || rodata->distance.near == 0) {
if (distance <= rodata->distance.far * model->scale) {
rwdata->distance.visible = true;
node->child = rodata->distance.target;
return;
}
}
rwdata->distance.visible = false;
node->child = NULL;
}
void model0001c784(struct model *model, struct modelnode *node)
{
struct modelrodata_distance *rodata = &node->rodata->distance;
struct modelrwdata_distance *rwdata = modelGetNodeRwData(model, node);
if (rwdata->visible) {
node->child = rodata->target;
} else {
node->child = NULL;
}
}
void model0001c7d0(struct model *model, struct modelnode *node)
{
struct modelrodata_toggle *rodata = &node->rodata->toggle;
struct modelrwdata_toggle *rwdata = modelGetNodeRwData(model, node);
if (rwdata->visible) {
node->child = rodata->target;
} else {
node->child = NULL;
}
}
/**
* Attach a head model to its placeholder on the body model.
*
* The given modelnode is assumed to be of type MODELNODETYPE_HEADSPOT.
*/
void modelAttachHead(struct model *model, struct modelnode *bodynode)
{
struct modelrwdata_headspot *rwdata = modelGetNodeRwData(model, bodynode);
if (rwdata->modelfiledata) {
struct modelnode *headnode = rwdata->modelfiledata->rootnode;
bodynode->child = headnode;
while (headnode) {
headnode->parent = bodynode;
headnode = headnode->next;
}
}
}
void model0001c868(struct modelnode *basenode, bool visible)
{
union modelrodata *rodata = basenode->rodata;
struct modelnode *node1;
struct modelnode *node2;
struct modelnode *loopnode;
if (visible) {
node1 = rodata->reorder.unk18;
node2 = rodata->reorder.unk1c;
} else {
node1 = rodata->reorder.unk1c;
node2 = rodata->reorder.unk18;
}
if (node1) {
// I think what's happening here is there's two groups of siblings,
// where node1 and node2 are the head nodes. Either group can be first,
// and this is ensuring the node1 group is first.
// Note that node2 might be NULL.
basenode->child = node1;
node1->prev = NULL;
// Skip through node1's siblings until node2 is found or the end is
// reached
loopnode = node1;
while (loopnode->next && loopnode->next != node2) {
loopnode = loopnode->next;
}
loopnode->next = node2;
if (node2) {
// Append node2 and its siblings to node1's siblings
node2->prev = loopnode;
loopnode = node2;
while (loopnode->next && loopnode->next != node1) {
loopnode = loopnode->next;
}
loopnode->next = NULL;
}
} else {
basenode->child = node2;
if (node2) {
node2->prev = NULL;
}
}
}
void modelRenderNodeReorder(struct model *model, struct modelnode *node)
{
union modelrwdata *rwdata = modelGetNodeRwData(model, node);
model0001c868(node, rwdata->reorder.visible);
}
void model0001c950(struct model *model, struct modelnode *node)
{
union modelrodata *rodata = node->rodata;
union modelrwdata *rwdata = modelGetNodeRwData(model, node);
Mtxf *mtx = model0001a5cc(model, node, 0);
struct coord sp38;
struct coord sp2c;
f32 tmp;
if (rodata->reorder.unk20 == 0) {
sp38.x = rodata->reorder.unk0c[0];
sp38.y = rodata->reorder.unk0c[1];
sp38.z = rodata->reorder.unk0c[2];
mtx4RotateVecInPlace(mtx, &sp38);
} else if (rodata->reorder.unk20 == 2) {
sp38.x = mtx->m[1][0] * rodata->reorder.unk0c[1];
sp38.y = mtx->m[1][1] * rodata->reorder.unk0c[1];
sp38.z = mtx->m[1][2] * rodata->reorder.unk0c[1];
} else if (rodata->reorder.unk20 == 3) {
sp38.x = mtx->m[2][0] * rodata->reorder.unk0c[2];
sp38.y = mtx->m[2][1] * rodata->reorder.unk0c[2];
sp38.z = mtx->m[2][2] * rodata->reorder.unk0c[2];
} else if (rodata->reorder.unk20 == 1) {
sp38.x = mtx->m[0][0] * rodata->reorder.unk0c[0];
sp38.y = mtx->m[0][1] * rodata->reorder.unk0c[0];
sp38.z = mtx->m[0][2] * rodata->reorder.unk0c[0];
}
sp2c.x = rodata->reorder.unk00;
sp2c.y = rodata->reorder.unk04;
sp2c.z = rodata->reorder.unk08;
mtx4TransformVecInPlace(mtx, &sp2c);
tmp = sp38.f[0] * sp2c.f[0] + sp38.f[1] * sp2c.f[1] + sp38.f[2] * sp2c.f[2];
if (tmp < 0) {
rwdata->reorder.visible = true;
} else {
rwdata->reorder.visible = false;
}
modelRenderNodeReorder(model, node);
}
void model0001cb0c(struct model *model, struct modelnode *parent)
{
struct modelnode *node = parent->child;
if (parent);
while (node) {
s32 type = node->type & 0xff;
bool dochildren = true;
switch (type) {
case MODELNODETYPE_CHRINFO:
case MODELNODETYPE_POSITION:
case MODELNODETYPE_0B:
case MODELNODETYPE_CHRGUNFIRE:
case MODELNODETYPE_0D:
case MODELNODETYPE_0E:
case MODELNODETYPE_0F:
case MODELNODETYPE_POSITIONHELD:
dochildren = false;
break;
case MODELNODETYPE_DISTANCE:
model0001c664(model, node);
break;
case MODELNODETYPE_REORDER:
model0001c950(model, node);
break;
case MODELNODETYPE_HEADSPOT:
modelAttachHead(model, node);
break;
case MODELNODETYPE_DL:
break;
}
if (dochildren && node->child) {
node = node->child;
} else {
while (node) {
if (node == parent->parent) {
node = NULL;
break;
}
if (node->next) {
node = node->next;
break;
}
node = node->parent;
}
}
}
}
void model0001cc20(struct model *model)
{
struct modelnode *node = model->filedata->rootnode;
while (node) {
u32 type = node->type & 0xff;
switch (type) {
case MODELNODETYPE_DISTANCE:
model0001c664(model, node);
break;
case MODELNODETYPE_REORDER:
model0001c950(model, node);
break;
case MODELNODETYPE_TOGGLE:
model0001c7d0(model, node);
break;
case MODELNODETYPE_HEADSPOT:
modelAttachHead(model, node);
break;
case MODELNODETYPE_CHRINFO:
case MODELNODETYPE_DL:
default:
break;
}
if (node->child) {
node = node->child;
} else {
while (node) {
if (node->next) {
node = node->next;
break;
}
node = node->parent;
}
}
}
}
void model0001cd18(struct modelrenderdata *arg0, struct model *model)
{
struct modelnode *node = model->filedata->rootnode;
while (node) {
u32 type = node->type & 0xff;
switch (type) {
case MODELNODETYPE_CHRINFO:
model0001b400(arg0, model, node);
break;
case MODELNODETYPE_POSITION:
model0001bfa8(arg0, model, node);
break;
case MODELNODETYPE_POSITIONHELD:
model0001c5b4(arg0, model, node);
break;
case MODELNODETYPE_DISTANCE:
model0001c664(model, node);
break;
case MODELNODETYPE_REORDER:
model0001c950(model, node);
break;
case MODELNODETYPE_TOGGLE:
model0001c7d0(model, node);
break;
case MODELNODETYPE_HEADSPOT:
modelAttachHead(model, node);
break;
case MODELNODETYPE_DL:
default:
break;
}
if (node->child) {
node = node->child;
} else {
while (node) {
if (node->next) {
node = node->next;
break;
}
node = node->parent;
}
}
}
}
void model0001ce64(struct modelrenderdata *arg0, struct model *model)
{
model->matrices = arg0->unk10;
arg0->unk10 += model->filedata->nummatrices;
#if VERSION >= VERSION_PAL_BETA
if (var8005efb0_2 || !model00018680()) {
model0001cd18(arg0, model);
}
#else
if (!model00018680()) {
model0001cd18(arg0, model);
}
#endif
}
void model0001cebc(struct modelrenderdata *arg0, struct model *model)
{
struct anim *anim = model->anim;
f32 speed;
f32 frac;
f32 frac2;
if (anim && anim->animnum) {
if (PLAYERCOUNT() >= 2) {
frac = anim->frac;
frac2 = anim->frac2;
speed = anim->speed;
if (speed < 0) {
speed = -speed;
}
if (speed > 0.5f) {
anim->frac = 0;
anim->frac2 = 0;
}
}
anim00023d38(anim->animnum);
anim->unk04 = anim00023ab0(anim->animnum, anim->framea);
if (anim->frac != 0) {
anim->unk05 = anim00023ab0(anim->animnum, anim->frameb);
}
if (anim->animnum2) {
anim00023d38(anim->animnum2);
anim->unk06 = anim00023ab0(anim->animnum2, anim->frame2a);
if (anim->frac2 != 0) {
anim->unk07 = anim00023ab0(anim->animnum2, anim->frame2b);
}
}
anim00023d0c();
}
model0001ce64(arg0, model);
if (PLAYERCOUNT() >= 2 && anim && anim->animnum) {
anim->frac = frac;
anim->frac2 = frac2;
}
}
s16 modelGetAnimNum(struct model *model)
{
if (model->anim) {
return model->anim->animnum;
}
return 0;
}
bool modelIsFlipped(struct model *model)
{
if (model->anim) {
return model->anim->flip;
}
return false;
}
f32 modelGetCurAnimFrame(struct model *model)
{
if (model->anim) {
return model->anim->frame;
}
return 0;
}
f32 modelGetAnimEndFrame(struct model *model)
{
struct anim *anim = model->anim;
if (anim) {
if (anim->endframe >= 0) {
return anim->endframe;
}
if (anim->animnum) {
return animGetNumFrames(anim->animnum) - 1;
} else {
return 0;
}
}
return 0;
}
s32 modelGetNumAnimFrames(struct model *model)
{
if (model->anim) {
return animGetNumFrames(modelGetAnimNum(model));
}
return 0;
}
f32 modelGetAnimSpeed(struct model *model)
{
if (model->anim) {
return model->anim->speed;
}
return 1;
}
f32 modelGetAbsAnimSpeed(struct model *model)
{
f32 speed;
if (model->anim) {
speed = model->anim->speed;
if (speed < 0) {
speed = -speed;
}
return speed;
}
return 1;
}
f32 modelGetEffectiveAnimSpeed(struct model *model)
{
if (model->anim) {
return modelGetAnimSpeed(model) * model->anim->playspeed;
}
return 1;
}
/**
* Constrain the given frame number to the bounds of the animation, unless the
* animation is looping in which case wrap it to the other side.
*/
s32 modelConstrainOrWrapAnimFrame(s32 frame, s16 animnum, f32 endframe)
{
if (frame < 0) {
if (var8005efbc || (g_Anims[animnum].flags & ANIMFLAG_LOOP)) {
frame = animGetNumFrames(animnum) - (-frame % animGetNumFrames(animnum));
} else {
frame = 0;
}
} else if (endframe >= 0 && frame > (s32)endframe) {
frame = ceil(endframe);
} else if (frame >= animGetNumFrames(animnum)) {
if (var8005efbc || (g_Anims[animnum].flags & ANIMFLAG_LOOP)) {
frame = frame % animGetNumFrames(animnum);
} else {
frame = animGetNumFrames(animnum) - 1;
}
}
return frame;
}
void modelCopyAnimForMerge(struct model *model, f32 merge)
{
struct anim *anim = model->anim;
struct modelnode *node;
u32 nodetype;
if (anim) {
if (merge > 0 && anim->animnum) {
if (anim->animnum2 && anim->fracmerge == 1) {
return;
}
node = model->filedata->rootnode;
nodetype = node->type & 0xff;
anim->frame2 = anim->frame;
anim->frac2 = anim->frac;
anim->animnum2 = anim->animnum;
anim->flip2 = anim->flip;
anim->frame2a = anim->framea;
anim->frame2b = anim->frameb;
anim->speed2 = anim->speed;
anim->newspeed2 = anim->newspeed;
anim->oldspeed2 = anim->oldspeed;
anim->timespeed2 = anim->timespeed;
anim->elapsespeed2 = anim->elapsespeed;
anim->endframe2 = anim->endframe;
if (nodetype == MODELNODETYPE_CHRINFO) {
struct modelrwdata_chrinfo *rwdata = modelGetNodeRwData(model, node);
rwdata->unk02 = 1;
rwdata->unk4c.x = rwdata->unk34.x;
rwdata->unk4c.y = rwdata->unk34.y;
rwdata->unk4c.z = rwdata->unk34.z;
rwdata->unk40.x = rwdata->unk24.x;
rwdata->unk40.y = rwdata->unk24.y;
rwdata->unk40.z = rwdata->unk24.z;
}
} else {
anim->animnum2 = 0;
}
}
}
void model0001d62c(struct model *model, s16 animnum, s32 flip, f32 fstartframe, f32 speed, f32 merge)
{
struct anim *anim = model->anim;
if (anim) {
s32 isfirstanim = !anim->animnum;
s32 type;
if (anim->animnum2) {
anim->timemerge = merge;
anim->elapsemerge = 0;
anim->fracmerge = 1;
} else {
anim->timemerge = 0;
anim->fracmerge = 0;
}
anim->animnum = animnum;
anim->flip = flip;
anim->endframe = -1;
anim->speed = speed;
anim->timespeed = 0;
model0001e018(model, fstartframe);
anim->looping = false;
type = model->filedata->rootnode->type & 0xff;
if (type == MODELNODETYPE_CHRINFO) {
u32 stack;
struct modelrodata_chrinfo *rodata = &model->filedata->rootnode->rodata->chrinfo;
struct modelrwdata_chrinfo *rwdata = (struct modelrwdata_chrinfo *) modelGetNodeRwData(model, model->filedata->rootnode);
s32 spa4 = rodata->unk00;
struct skeleton *skel = model->filedata->skel;
f32 scale;
f32 sp98;
f32 sp94;
struct coord sp88 = {0, 0, 0};
f32 sp84;
u8 sp83;
struct coord sp74;
struct coord sp68;
f32 sp64;
struct coord sp58;
struct coord sp4c;
f32 angle;
f32 y;
f32 x;
f32 z;
if (g_Anims[anim->animnum].flags & ANIMFLAG_02) {
sp64 = func0f15c888();
anim00023d38(anim->animnum);
sp83 = anim00023ab0(anim->animnum, anim->framea);
anim00023d0c();
anim00024050(spa4, anim->flip, skel, anim->animnum, sp83, &sp74, &sp88, &sp68);
rwdata->unk34.x = sp88.x * sp64;
rwdata->unk34.y = sp88.y * sp64;
rwdata->unk34.z = sp88.z * sp64;
rwdata->unk30 = rwdata->unk14;
if (anim->frac == 0) {
rwdata->unk01 = 0;
} else {
anim00023d38(anim->animnum);
sp83 = anim00023ab0(anim->animnum, anim->frameb);
anim00023d0c();
anim00024050(spa4, anim->flip, skel, anim->animnum, sp83, &sp74, &sp88, &sp68);
rwdata->unk24.x = sp88.x * sp64;
rwdata->unk24.y = sp88.y * sp64;
rwdata->unk24.z = sp88.z * sp64;
rwdata->unk20 = rwdata->unk14;
rwdata->unk01 = 1;
}
} else {
sp84 = anim00024b64(spa4, anim->flip, skel, anim->animnum, anim->frameb, &sp88, anim->average);
scale = model->scale * anim->animscale;
if (scale != 1) {
sp88.x *= scale;
sp88.y *= scale;
sp88.z *= scale;
}
if (anim->average) {
sp88.y = rwdata->pos.y - rwdata->ground;
}
sp98 = cosf(rwdata->unk14);
sp94 = sinf(rwdata->unk14);
if (anim->frac == 0) {
rwdata->unk34.x = rwdata->pos.f[0];
rwdata->unk34.y = rwdata->pos.f[1] - rwdata->ground;
rwdata->unk34.z = rwdata->pos.f[2];
rwdata->unk30 = rwdata->unk14;
sp58.x = rwdata->unk34.f[0] + sp88.f[0] * sp98 + sp88.f[2] * sp94;
sp58.y = sp88.f[1];
sp58.z = rwdata->unk34.f[2] - sp88.f[0] * sp94 + sp88.f[2] * sp98;
rwdata->unk24.x = sp58.f[0];
rwdata->unk24.y = sp58.f[1];
rwdata->unk24.z = sp58.f[2];
if (rwdata->unk18 == 0) {
rwdata->unk20 = rwdata->unk30 + sp84;
if (rwdata->unk20 >= M_BADTAU) {
rwdata->unk20 -= M_BADTAU;
}
}
rwdata->unk01 = 1;
} else {
x = sp88.f[0] * sp98 + sp88.f[2] * sp94;
y = sp88.f[1];
z = -sp88.f[0] * sp94 + sp88.f[2] * sp98;
sp4c.f[0] = rwdata->pos.f[0] + x * (1 - anim->frac);
sp4c.f[1] = y;
sp4c.f[2] = rwdata->pos.f[2] + z * (1 - anim->frac);
rwdata->unk24.f[0] = sp4c.f[0];
rwdata->unk24.f[1] = sp4c.f[1];
rwdata->unk24.f[2] = sp4c.f[2];
rwdata->unk34.f[0] = rwdata->unk24.f[0] - x;
rwdata->unk34.f[1] = (rwdata->pos.f[1] - rwdata->ground) - (y - (rwdata->pos.f[1] - rwdata->ground)) * anim->frac / (1 - anim->frac);
rwdata->unk34.f[2] = rwdata->unk24.f[2] - z;
angle = rwdata->unk14 - sp84;
if (angle < 0) {
angle += M_BADTAU;
}
rwdata->unk30 = model0001afe8(rwdata->unk14, angle, anim->frac);
if (rwdata->unk18 == 0) {
rwdata->unk20 = rwdata->unk30 + sp84;
if (rwdata->unk20 >= M_BADTAU) {
rwdata->unk20 -= M_BADTAU;
}
}
rwdata->unk01 = 1;
}
if (isfirstanim) {
rwdata->unk34.f[1] = rwdata->unk24.f[1];
}
}
}
}
}
bool modelIsAnimMerging(struct model *model)
{
if (model && model->anim && model->anim->animnum2
&& model->anim->fracmerge != 0 && model->anim->fracmerge != 1) {
return true;
}
return false;
}
void modelSetAnimationWithMerge(struct model *model, s16 animnum, u32 flip, f32 startframe, f32 speed, f32 timemerge, bool domerge)
{
if (model) {
if (model->anim && model->anim->animnum
&& (g_Anims[model->anim->animnum].flags & ANIMFLAG_02)
&& (g_Anims[animnum].flags & ANIMFLAG_02) == 0) {
timemerge = 0;
}
if (domerge) {
modelCopyAnimForMerge(model, timemerge);
}
model0001d62c(model, animnum, flip, startframe, speed, timemerge);
}
}
void modelSetAnimation(struct model *model, s16 animnum, s32 flip, f32 startframe, f32 speed, f32 merge)
{
if (model) {
if (model->anim && model->anim->animnum
&& (g_Anims[model->anim->animnum].flags & ANIMFLAG_02)
&& (g_Anims[animnum].flags & ANIMFLAG_02) == 0) {
merge = 0;
}
modelCopyAnimForMerge(model, merge);
model0001d62c(model, animnum, flip, startframe, speed, merge);
}
}
void modelCopyAnimData(struct model *src, struct model *dst)
{
if (src->anim && dst->anim) {
*dst->anim = *src->anim;
}
}
void modelSetAnimLooping(struct model *model, f32 loopframe, f32 loopmerge)
{
if (model->anim) {
model->anim->looping = true;
model->anim->loopframe = loopframe;
model->anim->loopmerge = loopmerge;
}
}
void modelSetAnimEndFrame(struct model *model, f32 endframe)
{
struct anim *anim = model->anim;
if (anim) {
if (anim->animnum && endframe < animGetNumFrames(anim->animnum) - 1) {
anim->endframe = endframe;
} else {
anim->endframe = -1;
}
}
}
void modelSetAnimFlipFunction(struct model *model, void *callback)
{
if (model->anim) {
model->anim->flipfunc = callback;
}
}
#if VERSION < VERSION_NTSC_1_0
void modelSetAnimUnk6c(struct model *model, s32 value)
{
if (model->anim) {
model->anim->unk6c = value;
}
}
#endif
void modelSetAnimSpeed(struct model *model, f32 speed, f32 startframe)
{
struct anim *anim = model->anim;
if (anim) {
if (startframe > 0) {
anim->timespeed = startframe;
anim->newspeed = speed;
anim->elapsespeed = 0;
anim->oldspeed = anim->speed;
} else {
anim->speed = speed;
anim->timespeed = 0;
}
}
}
void modelSetAnimSpeedAuto(struct model *model, f32 arg1, f32 startframe)
{
struct anim *anim = model->anim;
f32 tmp;
f32 speed;
if (anim) {
if (anim->frame <= arg1) {
tmp = arg1 - anim->frame;
} else {
tmp = animGetNumFrames(anim->animnum) - anim->frame + arg1;
}
speed = anim->speed + (tmp + tmp) / startframe;
modelSetAnimSpeed(model, speed, startframe);
}
}
void modelSetAnimPlaySpeed(struct model *model, f32 speed, f32 startframe)
{
struct anim *anim = model->anim;
if (anim) {
if (startframe > 0) {
anim->timeplay = startframe;
anim->newplay = speed;
anim->elapseplay = 0;
anim->oldplay = anim->playspeed;
} else {
anim->playspeed = speed;
anim->timeplay = 0;
}
}
}
void modelSetAnim70(struct model *model, void *callback)
{
if (model->anim) {
model->anim->unk70 = callback;
}
}
void model0001e018(struct model *model, f32 arg1)
{
s32 sp28;
s32 sp24;
bool sp20;
struct anim *anim = model->anim;
if (anim) {
sp28 = floor(arg1);
sp20 = anim->speed >= 0;
sp24 = (sp20 ? sp28 + 1 : sp28 - 1);
anim->framea = modelConstrainOrWrapAnimFrame(sp28, anim->animnum, anim->endframe);
anim->frameb = modelConstrainOrWrapAnimFrame(sp24, anim->animnum, anim->endframe);
if (anim->framea == anim->frameb) {
anim->frac = 0;
anim->frame = anim->framea;
} else if (sp20) {
anim->frac = arg1 - sp28;
anim->frame = anim->framea + anim->frac;
} else {
anim->frac = 1 - (arg1 - sp24);
anim->frame = anim->frameb + (1 - anim->frac);
}
}
}
void model0001e14c(struct model *model, f32 arg1, f32 arg2)
{
struct anim *anim = model->anim;
if (anim) {
model0001e018(model, arg1);
if (anim->animnum2) {
s32 sp28 = floor(arg2);
s32 sp24;
bool sp20 = anim->speed2 >= 0;
sp24 = (sp20 ? sp28 + 1 : sp28 - 1);
anim->frame2a = modelConstrainOrWrapAnimFrame(sp28, anim->animnum2, anim->endframe2);
anim->frame2b = modelConstrainOrWrapAnimFrame(sp24, anim->animnum2, anim->endframe2);
if (anim->frame2a == anim->frame2b) {
anim->frac2 = 0;
anim->frame2 = anim->frame2a;
} else if (sp20) {
anim->frac2 = arg2 - sp28;
anim->frame2 = anim->frame2a + anim->frac2;
} else {
anim->frac2 = 1 - (arg2 - sp24);
anim->frame2 = anim->frame2b + (1 - anim->frac2);
}
}
}
}
bool var8005efdc = true;
void model0001e29c(bool value)
{
var8005efdc = value;
}
bool model0001e2a8(void)
{
return var8005efdc;
}
void model0001e2b4(struct model *model, f32 curframe, f32 endframe, f32 curframe2, f32 endframe2)
{
struct anim *anim = model->anim;
if (anim != NULL) {
struct modelnode *rootnode = model->filedata->rootnode;
u16 nodetype = rootnode->type;
if ((nodetype & 0xff) == MODELNODETYPE_CHRINFO) {
struct modelrodata_chrinfo *rodata = &rootnode->rodata->chrinfo;
struct modelrwdata_chrinfo *rwdata = modelGetNodeRwData(model, rootnode);
if (rwdata->unk00 == 0) {
s32 sp118 = rodata->unk00;
struct skeleton *skel = model->filedata->skel;
f32 scale = model->scale * anim->animscale;
f32 sine;
f32 cosine;
struct coord spfc = {0, 0, 0};
u8 s0;
f32 f20;
s32 floorcur;
s32 floorend;
struct coord spe0;
f32 f30;
struct coord spd0;
f32 spcc;
s32 spc8;
bool forwards;
f32 absspeed;
f32 absspeed2;
f32 f22;
s32 s0frame;
struct coord spa8;
struct coord sp9c;
struct coord sp90;
u32 stack;
spe0.x = rwdata->unk34.x;
spe0.y = rwdata->unk34.y;
spe0.z = rwdata->unk34.z;
f30 = rwdata->unk30;
spd0.x = rwdata->unk24.x;
spd0.y = rwdata->unk24.y;
spd0.z = rwdata->unk24.z;
spcc = rwdata->unk20;
spc8 = rwdata->unk01;
absspeed = anim->speed;
if (absspeed < 0.0f) {
absspeed = -absspeed;
}
absspeed2 = anim->speed2;
if (absspeed2 < 0.0f) {
absspeed2 = -absspeed2;
}
forwards = false;
if (curframe <= endframe) {
forwards = true;
}
if (forwards) {
floorcur = floor(curframe) + 1;
floorend = floor(endframe);
} else {
floorcur = ceil(curframe) - 1;
floorend = ceil(endframe);
}
if (g_Anims[anim->animnum].flags & ANIMFLAG_02) {
f20 = func0f15c888();
if (floorend != anim->framea) {
s0frame = modelConstrainOrWrapAnimFrame(floorend, anim->animnum, anim->endframe);
anim->framea = s0frame;
if (spc8 && floorend == anim->frameb) {
spe0.x = spd0.x;
spe0.y = spd0.y;
spe0.z = spd0.z;
} else {
anim00023d38(anim->animnum);
s0 = anim00023ab0(anim->animnum, s0frame);
anim00023d0c();
anim00024050(sp118, anim->flip, skel, anim->animnum, s0, &spa8, &spfc, &sp9c);
spe0.x = spfc.x * f20;
spe0.y = spfc.y * f20;
spe0.z = spfc.z * f20;
}
floorcur = floorend;
if (forwards) {
floorcur++;
} else {
floorcur--;
}
s0frame = modelConstrainOrWrapAnimFrame(floorcur, anim->animnum, anim->endframe);
anim->frameb = s0frame;
anim00023d38(anim->animnum);
s0 = anim00023ab0(anim->animnum, s0frame);
anim00023d0c();
anim00024050(sp118, anim->flip, skel, anim->animnum, s0, &spa8, &spfc, &sp9c);
spc8 = true;
spd0.x = spfc.x * f20;
spd0.y = spfc.y * f20;
spd0.z = spfc.z * f20;
}
} else {
while (true) {
if (forwards) {
if (floorend < floorcur) {
break;
}
} else {
if (floorend > floorcur) {
break;
}
}
s0frame = modelConstrainOrWrapAnimFrame(floorcur, anim->animnum, anim->endframe);
anim->framea = s0frame;
if (spc8) {
spe0.x = spd0.x;
spe0.y = spd0.y;
spe0.z = spd0.z;
if (rwdata->unk18 == 0.0f) {
f30 = spcc;
}
} else {
f22 = anim00024b64(sp118, anim->flip, skel, anim->animnum, s0frame, &spfc, anim->average);
if (scale != 1.0f) {
spfc.x *= scale;
spfc.y *= scale;
spfc.z *= scale;
}
if (!forwards) {
spfc.x = -spfc.x;
spfc.z = -spfc.z;
if (f22 > 0.0f) {
f22 = M_BADTAU - f22;
}
}
if (anim->average) {
spfc.y = rwdata->pos.y - rwdata->ground;
}
cosine = cosf(rwdata->unk14);
sine = sinf(rwdata->unk14);
spe0.x += spfc.x * cosine + spfc.z * sine;
spe0.y = spfc.y;
spe0.z += (-spfc.x * sine) + (spfc.z * cosine);
if (rwdata->unk18 == 0.0f) {
f30 += f22;
if (f30 >= M_BADTAU) {
f30 -= M_BADTAU;
}
}
}
if (forwards) {
floorcur++;
} else {
floorcur--;
}
s0frame = modelConstrainOrWrapAnimFrame(floorcur, anim->animnum, anim->endframe);
anim->frameb = s0frame;
if (anim->frameb != anim->framea) {
f22 = anim00024b64(sp118, anim->flip, skel, anim->animnum, s0frame, &spfc, anim->average);
spc8 = true;
if (scale != 1.0f) {
spfc.x *= scale;
spfc.y *= scale;
spfc.z *= scale;
}
if (!forwards) {
spfc.x = -spfc.x;
spfc.z = -spfc.z;
if (f22 > 0.0f) {
f22 = M_BADTAU - f22;
}
}
if (anim->average) {
spfc.y = rwdata->unk34.y;
}
cosine = cosf(rwdata->unk30);
sine = sinf(rwdata->unk30);
if (var8005efdc && anim->animnum2) {
spd0.x = spfc.x * cosine + spfc.f[2] * sine;
spd0.z = -spfc.x * sine + spfc.f[2] * cosine;
if (absspeed > 0.0f) {
f32 f0 = anim->fracmerge - anim->playspeed / (absspeed * anim->timemerge);
if (f0 < 0.0f) {
f0 = 0.0f;
}
f0 = (f0 + anim->fracmerge) / 2.0f;
if (1);
sp90.f[0] = (rwdata->unk40.x - rwdata->unk4c.x) * absspeed2 / absspeed;
sp90.f[2] = (rwdata->unk40.z - rwdata->unk4c.z) * absspeed2 / absspeed;
spd0.x += (sp90.x - spd0.x) * f0;
spd0.z += (sp90.z - spd0.z) * f0;
} else {
spd0.x += (rwdata->unk40.x - rwdata->unk4c.x) * anim->fracmerge;
spd0.z += (rwdata->unk40.z - rwdata->unk4c.z) * anim->fracmerge;
}
spd0.x += spe0.x;
spd0.z += spe0.z;
spd0.y = spfc.y;
} else {
spd0.x = spe0.x + spfc.x * cosine + spfc.f[2] * sine;
spd0.y = spfc.y;
spd0.z = spe0.z - spfc.x * sine + spfc.f[2] * cosine;
}
if (rwdata->unk5c > 0.0f && absspeed > 0.0f) {
f32 increment = 1.0f / absspeed;
if (increment > rwdata->unk5c) {
increment = rwdata->unk5c;
rwdata->unk5c = 0.0f;
} else {
rwdata->unk5c -= increment;
}
f22 += rwdata->unk58 * increment;
if (f22 < 0.0f) {
f22 += M_BADTAU;
} else if (f22 >= M_BADTAU) {
f22 -= M_BADTAU;
}
}
if (rwdata->unk18 == 0.0f) {
spcc = f30 + f22;
if (spcc >= M_BADTAU) {
spcc -= M_BADTAU;
}
}
}
}
}
rwdata->unk34.x = spe0.x;
rwdata->unk34.y = spe0.y;
rwdata->unk34.z = spe0.z;
rwdata->unk30 = f30;
rwdata->unk24.x = spd0.f[0];
rwdata->unk24.y = spd0.f[1];
rwdata->unk24.z = spd0.f[2];
rwdata->unk20 = spcc;
rwdata->unk01 = spc8;
if (anim->framea == anim->frameb) {
anim->frac = 0.0f;
anim->frame = anim->framea;
} else if (forwards) {
anim->frac = endframe - floorend;
anim->frame = anim->framea + anim->frac;
} else {
anim->frac = floorend - endframe;
anim->frame = anim->frameb + (1.0f - anim->frac);
}
if (anim->animnum2 && (g_Anims[anim->animnum].flags & ANIMFLAG_02) == 0) {
s32 floorcur2 = floor(curframe2);
s32 floorend2 = floor(endframe2);
if ((forwards && floorcur2 < floorend2) || (!forwards && floorend2 < floorcur2)) {
if (rwdata->unk02 != 0) {
rwdata->unk4c.f[1] = rwdata->unk40.f[1];
} else {
rwdata->unk4c.f[1] = rwdata->unk34.f[1];
}
anim->frame2a = modelConstrainOrWrapAnimFrame(floorend2, anim->animnum2, anim->endframe2);
s0frame = modelConstrainOrWrapAnimFrame(floorend2 + 1, anim->animnum2, anim->endframe2);
anim->frame2b = s0frame;
anim00024b64(sp118, anim->flip2, skel, anim->animnum2, s0frame, &spfc, anim->average);
if (scale != 1.0f) {
spfc.y *= scale;
}
if (anim->average) {
spfc.y = rwdata->unk4c.y;
}
rwdata->unk40.y = spfc.y;
rwdata->unk02 = 1;
}
if (forwards) {
anim->frac2 = endframe2 - floorend2;
anim->frame2 = anim->frame2a + anim->frac2;
} else {
anim->frac2 = 1.0f - (endframe2 - floorend2);
anim->frame2 = anim->frame2b + (1.0f - anim->frac2);
}
} else {
rwdata->unk02 = 0;
}
} else {
model0001e14c(model, endframe, endframe2);
}
} else {
model0001e14c(model, endframe, endframe2);
}
}
}
void model0001ee18(struct model *model, s32 lvupdate240, bool arg2)
{
f32 frame;
f32 frame2;
f32 speed;
f32 speed2;
f32 startframe;
f32 endframe;
f32 realendframe;
struct anim *anim = model->anim;
if (anim && lvupdate240 > 0) {
frame = anim->frame;
frame2 = anim->frame2;
for (; lvupdate240 > 0; lvupdate240--) {
if (anim->timeplay > 0) {
anim->elapseplay += 0.25f;
if (anim->elapseplay < anim->timeplay) {
anim->playspeed = anim->oldplay + (anim->newplay - anim->oldplay) * anim->elapseplay / anim->timeplay;
} else {
anim->timeplay = 0;
anim->playspeed = anim->newplay;
}
}
if (anim->timemerge > 0) {
anim->elapsemerge += anim->playspeed * 0.25f;
if (anim->elapsemerge == 0) {
anim->fracmerge = 1;
} else {
if (anim->elapsemerge < anim->timemerge) {
anim->fracmerge = (anim->timemerge - anim->elapsemerge) / anim->timemerge;
} else {
anim->timemerge = 0;
anim->fracmerge = 0;
anim->animnum2 = 0;
}
}
}
if (anim->timespeed > 0) {
anim->elapsespeed += anim->playspeed * 0.25f;
if (anim->elapsespeed < anim->timespeed) {
anim->speed = anim->oldspeed + (anim->newspeed - anim->oldspeed) * anim->elapsespeed / anim->timespeed;
} else {
anim->timespeed = 0;
anim->speed = anim->newspeed;
}
}
speed = anim->speed;
frame += anim->playspeed * speed * 0.25f;
if (anim->animnum2) {
if (anim->timespeed2 > 0) {
anim->elapsespeed2 += anim->playspeed * 0.25f;
if (anim->elapsespeed2 < anim->timespeed2) {
anim->speed2 = anim->oldspeed2 + (anim->newspeed2 - anim->oldspeed2) * anim->elapsespeed2 / anim->timespeed2;
} else {
anim->timespeed2 = 0;
anim->speed2 = anim->newspeed2;
}
}
speed2 = anim->speed2;
frame2 += anim->playspeed * speed2 * 0.25f;
}
if (anim->looping) {
realendframe = anim->endframe;
if (speed >= 0) {
endframe = animGetNumFrames(anim->animnum) - 1;
startframe = anim->loopframe;
if (realendframe >= 0 && endframe > realendframe) {
endframe = realendframe;
}
} else {
endframe = anim->loopframe;
startframe = animGetNumFrames(anim->animnum) - 1;
if (realendframe >= 0 && startframe > realendframe) {
startframe = realendframe;
}
}
if ((speed >= 0 && frame >= endframe) || (speed < 0 && frame <= endframe)) {
f32 prevnewspeed = anim->newspeed;
f32 prevoldspeed = anim->oldspeed;
f32 prevtimespeed = anim->timespeed;
f32 prevelapsespeed = anim->elapsespeed;
if (arg2) {
model0001e2b4(model, anim->frame, endframe, 0, 0);
} else {
model0001e14c(model, endframe, 0);
}
modelSetAnimation(model, anim->animnum, anim->flip, startframe, anim->speed, anim->loopmerge);
anim->looping = true;
anim->endframe = realendframe;
anim->newspeed = prevnewspeed;
anim->oldspeed = prevoldspeed;
anim->timespeed = prevtimespeed;
anim->elapsespeed = prevelapsespeed;
frame2 = frame;
frame = startframe + frame - endframe;
if (anim->flipfunc) {
anim->flipfunc();
}
}
}
}
if (arg2) {
if (anim->animnum2) {
model0001e2b4(model, anim->frame, frame, anim->frame2, frame2);
} else {
model0001e2b4(model, anim->frame, frame, 0, 0);
}
} else {
if (anim->animnum2) {
model0001e14c(model, frame, frame2);
} else {
model0001e14c(model, frame, 0);
}
}
}
}
#if VERSION < VERSION_PAL_BETA
/**
* This is identical to the above function but removes the 0.25f multipliers.
*/
void model0001f314(struct model *model, s32 lvupdate240, bool arg2)
{
f32 frame;
f32 frame2;
f32 speed;
f32 speed2;
f32 startframe;
f32 endframe;
f32 realendframe;
struct anim *anim = model->anim;
if (anim && lvupdate240 > 0) {
frame = anim->frame;
frame2 = anim->frame2;
for (; lvupdate240 > 0; lvupdate240--) {
if (anim->timeplay > 0) {
anim->elapseplay++;
if (anim->elapseplay < anim->timeplay) {
anim->playspeed = anim->oldplay + (anim->newplay - anim->oldplay) * anim->elapseplay / anim->timeplay;
} else {
anim->timeplay = 0;
anim->playspeed = anim->newplay;
}
}
if (anim->timemerge > 0) {
anim->elapsemerge += anim->playspeed;
if (anim->elapsemerge == 0) {
anim->fracmerge = 1;
} else {
if (anim->elapsemerge < anim->timemerge) {
anim->fracmerge = (anim->timemerge - anim->elapsemerge) / anim->timemerge;
} else {
anim->timemerge = 0;
anim->fracmerge = 0;
anim->animnum2 = 0;
}
}
}
if (anim->timespeed > 0) {
anim->elapsespeed += anim->playspeed;
if (anim->elapsespeed < anim->timespeed) {
anim->speed = anim->oldspeed + (anim->newspeed - anim->oldspeed) * anim->elapsespeed / anim->timespeed;
} else {
anim->timespeed = 0;
anim->speed = anim->newspeed;
}
}
speed = anim->speed;
frame += anim->playspeed * speed;
if (anim->animnum2) {
if (anim->timespeed2 > 0) {
anim->elapsespeed2 += anim->playspeed;
if (anim->elapsespeed2 < anim->timespeed2) {
anim->speed2 = anim->oldspeed2 + (anim->newspeed2 - anim->oldspeed2) * anim->elapsespeed2 / anim->timespeed2;
} else {
anim->timespeed2 = 0;
anim->speed2 = anim->newspeed2;
}
}
speed2 = anim->speed2;
frame2 += anim->playspeed * speed2;
}
if (anim->looping) {
realendframe = anim->endframe;
if (speed >= 0) {
endframe = animGetNumFrames(anim->animnum) - 1;
startframe = anim->loopframe;
if (realendframe >= 0 && endframe > realendframe) {
endframe = realendframe;
}
} else {
endframe = anim->loopframe;
startframe = animGetNumFrames(anim->animnum) - 1;
if (realendframe >= 0 && startframe > realendframe) {
startframe = realendframe;
}
}
if ((speed >= 0 && frame >= endframe) || (speed < 0 && frame <= endframe)) {
f32 prevnewspeed = anim->newspeed;
f32 prevoldspeed = anim->oldspeed;
f32 prevtimespeed = anim->timespeed;
f32 prevelapsespeed = anim->elapsespeed;
if (arg2) {
model0001e2b4(model, anim->frame, endframe, 0, 0);
} else {
model0001e14c(model, endframe, 0);
}
modelSetAnimation(model, anim->animnum, anim->flip, startframe, anim->speed, anim->loopmerge);
anim->looping = true;
anim->endframe = realendframe;
anim->newspeed = prevnewspeed;
anim->oldspeed = prevoldspeed;
anim->timespeed = prevtimespeed;
anim->elapsespeed = prevelapsespeed;
frame2 = frame;
frame = startframe + frame - endframe;
if (anim->flipfunc) {
anim->flipfunc();
}
}
}
}
if (arg2) {
if (anim->animnum2) {
model0001e2b4(model, anim->frame, frame, anim->frame2, frame2);
} else {
model0001e2b4(model, anim->frame, frame, 0, 0);
}
} else {
if (anim->animnum2) {
model0001e14c(model, frame, frame2);
} else {
model0001e14c(model, frame, 0);
}
}
}
}
#endif
void model0001f7e0(struct modelrenderdata *renderdata)
{
gDPPipeSync(renderdata->gdl++);
gDPSetCycleType(renderdata->gdl++, G_CYC_1CYCLE);
if (renderdata->zbufferenabled) {
gDPSetRenderMode(renderdata->gdl++, G_RM_AA_ZB_OPA_SURF, G_RM_AA_ZB_OPA_SURF2);
} else {
gDPSetRenderMode(renderdata->gdl++, G_RM_AA_OPA_SURF, G_RM_AA_OPA_SURF2);
}
gDPSetCombineMode(renderdata->gdl++, G_CC_MODULATEIA, G_CC_MODULATEIA);
}
void model0001f890(struct modelrenderdata *renderdata, bool arg1)
{
if (renderdata->unk30 == 7) {
if (arg1) {
gDPPipeSync(renderdata->gdl++);
gDPSetCycleType(renderdata->gdl++, G_CYC_2CYCLE);
gDPSetFogColorViaWord(renderdata->gdl++, renderdata->fogcolour);
gDPSetEnvColorViaWord(renderdata->gdl++, renderdata->envcolour | 0xff);
gDPSetCombineLERP(renderdata->gdl++, TEXEL0, ENVIRONMENT, SHADE_ALPHA, ENVIRONMENT, TEXEL0, ENVIRONMENT, SHADE, ENVIRONMENT, COMBINED, 0, SHADE, 0, 0, 0, 0, COMBINED);
if (renderdata->zbufferenabled) {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_ZB_OPA_SURF2);
} else {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_OPA_SURF2);
}
} else {
if (renderdata->zbufferenabled) {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_ZB_XLU_SURF2);
} else {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_XLU_SURF2);
}
}
} else if (renderdata->unk30 == 8) {
if (arg1) {
gDPPipeSync(renderdata->gdl++);
gDPSetCycleType(renderdata->gdl++, G_CYC_2CYCLE);
gDPSetFogColorViaWord(renderdata->gdl++, renderdata->fogcolour);
gDPSetEnvColorViaWord(renderdata->gdl++, renderdata->envcolour);
gDPSetCombineLERP(renderdata->gdl++, TEXEL0, ENVIRONMENT, SHADE_ALPHA, ENVIRONMENT, TEXEL0, 0, ENVIRONMENT, 0, COMBINED, 0, SHADE, 0, 0, 0, 0, COMBINED);
if (renderdata->zbufferenabled) {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_ZB_XLU_SURF2);
} else {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_XLU_SURF2);
}
}
} else if (renderdata->unk30 == 9) {
if ((renderdata->envcolour & 0xff) == 0) {
if (arg1) {
gDPPipeSync(renderdata->gdl++);
gDPSetCycleType(renderdata->gdl++, G_CYC_2CYCLE);
gDPSetFogColorViaWord(renderdata->gdl++, renderdata->fogcolour);
gDPSetEnvColorViaWord(renderdata->gdl++, 0xffffffff);
gDPSetPrimColor(renderdata->gdl++, 0, 0, 0, 0, 0, (renderdata->envcolour >> 8) & 0xff);
gDPSetCombineLERP(renderdata->gdl++, TEXEL1, TEXEL0, LOD_FRACTION, TEXEL0, TEXEL1, TEXEL0, LOD_FRACTION, TEXEL0, COMBINED, 0, SHADE, 0, COMBINED, 0, SHADE, PRIMITIVE);
if (renderdata->zbufferenabled) {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_ZB_OPA_SURF2);
} else {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_OPA_SURF2);
}
} else {
if (renderdata->zbufferenabled) {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_ZB_XLU_SURF2);
} else {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_XLU_SURF2);
}
}
} else {
if (arg1) {
gDPPipeSync(renderdata->gdl++);
gDPSetCycleType(renderdata->gdl++, G_CYC_2CYCLE);
gDPSetFogColorViaWord(renderdata->gdl++, renderdata->fogcolour);
gDPSetEnvColor(renderdata->gdl++, 0, 0, 0, renderdata->envcolour);
gDPSetCombineLERP(renderdata->gdl++, TEXEL1, TEXEL0, LOD_FRACTION, TEXEL0, 1, 0, SHADE, ENVIRONMENT, COMBINED, 0, SHADE, 0, 0, 0, 0, COMBINED);
if (renderdata->zbufferenabled) {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_ZB_TEX_EDGE2);
} else {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_TEX_EDGE2);
}
} else {
gDPSetPrimColor(renderdata->gdl++, 0, 0, 0, 0, 0, (renderdata->envcolour >> 8) & 0xff);
gDPSetCombineLERP(renderdata->gdl++, TEXEL1, TEXEL0, LOD_FRACTION, TEXEL0, SHADE, ENVIRONMENT, TEXEL0, 0, COMBINED, 0, SHADE, 0, 1, 0, PRIMITIVE, COMBINED);
if (renderdata->zbufferenabled) {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_ZB_TEX_EDGE2);
} else {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_TEX_EDGE2);
}
}
}
} else if (renderdata->unk30 == 4) {
if (arg1) {
gDPPipeSync(renderdata->gdl++);
gDPSetCycleType(renderdata->gdl++, G_CYC_2CYCLE);
gDPSetFogColorViaWord(renderdata->gdl++, renderdata->envcolour);
gDPSetCombineMode(renderdata->gdl++, G_CC_TRILERP, G_CC_MODULATEIA2);
if (renderdata->zbufferenabled) {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_ZB_OPA_SURF2);
} else {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_OPA_SURF2);
}
} else {
if (renderdata->zbufferenabled) {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_ZB_XLU_SURF2);
} else {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_XLU_SURF2);
}
}
} else if (renderdata->unk30 == 5) {
u8 alpha;
if (arg1) {
gDPPipeSync(renderdata->gdl++);
gDPSetCycleType(renderdata->gdl++, G_CYC_2CYCLE);
gDPSetFogColorViaWord(renderdata->gdl++, renderdata->fogcolour);
alpha = renderdata->envcolour & 0xff;
if (alpha < 255) {
gDPSetEnvColor(renderdata->gdl++, 0xff, 0xff, 0xff, alpha);
if (renderdata->envcolour & 0xff00) {
gDPSetCombineLERP(renderdata->gdl++, TEXEL1, TEXEL0, LOD_FRACTION, TEXEL0, 1, SHADE, ENVIRONMENT, 0, COMBINED, 0, SHADE, 0, COMBINED, 0, SHADE, 0);
} else {
gDPSetCombineLERP(renderdata->gdl++, TEXEL1, TEXEL0, LOD_FRACTION, TEXEL0, 1, 0, ENVIRONMENT, 0, COMBINED, 0, SHADE, 0, COMBINED, 0, SHADE, 0);
}
} else {
gDPSetCombineMode(renderdata->gdl++, G_CC_TRILERP, G_CC_MODULATEIA2);
}
if (renderdata->zbufferenabled) {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_ZB_XLU_SURF2);
} else {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_XLU_SURF2);
}
} else {
alpha = renderdata->envcolour & 0xff;
if (alpha < 255) {
gDPSetCombineLERP(renderdata->gdl++, TEXEL1, TEXEL0, LOD_FRACTION, TEXEL0, TEXEL0, 0, ENVIRONMENT, 0, COMBINED, 0, SHADE, 0, COMBINED, 0, SHADE, 0);
} else {
gDPSetCombineMode(renderdata->gdl++, G_CC_TRILERP, G_CC_MODULATEIA2);
}
}
} else {
if (arg1) {
gDPPipeSync(renderdata->gdl++);
gDPSetCycleType(renderdata->gdl++, G_CYC_2CYCLE);
gDPSetCombineMode(renderdata->gdl++, G_CC_TRILERP, G_CC_MODULATEIA2);
if (renderdata->zbufferenabled) {
gDPSetRenderMode(renderdata->gdl++, G_RM_PASS, G_RM_AA_ZB_OPA_SURF2);
} else {
gDPSetRenderMode(renderdata->gdl++, G_RM_PASS, G_RM_AA_OPA_SURF2);
}
} else {
if (renderdata->zbufferenabled) {
gDPSetRenderMode(renderdata->gdl++, G_RM_PASS, G_RM_AA_ZB_XLU_SURF2);
} else {
gDPSetRenderMode(renderdata->gdl++, G_RM_PASS, G_RM_AA_XLU_SURF2);
}
}
}
}
void model00020248(struct modelrenderdata *renderdata, bool arg1)
{
if (renderdata->unk30 == 7) {
gDPPipeSync(renderdata->gdl++);
gDPSetCycleType(renderdata->gdl++, G_CYC_2CYCLE);
gDPSetFogColorViaWord(renderdata->gdl++, renderdata->fogcolour);
gDPSetEnvColorViaWord(renderdata->gdl++, renderdata->envcolour | 0x000000ff);
gDPSetCombineLERP(renderdata->gdl++, TEXEL0, ENVIRONMENT, SHADE_ALPHA, ENVIRONMENT, TEXEL0, ENVIRONMENT, SHADE, ENVIRONMENT, COMBINED, 0, SHADE, 0, 0, 0, 0, COMBINED);
if (arg1) {
if (renderdata->zbufferenabled) {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_ZB_OPA_SURF2);
} else {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_OPA_SURF2);
}
} else {
if (renderdata->zbufferenabled) {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_ZB_XLU_SURF2);
} else {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_XLU_SURF2);
}
}
} else if (renderdata->unk30 == 8) {
gDPPipeSync(renderdata->gdl++);
gDPSetCycleType(renderdata->gdl++, G_CYC_2CYCLE);
gDPSetFogColorViaWord(renderdata->gdl++, renderdata->fogcolour);
gDPSetEnvColorViaWord(renderdata->gdl++, renderdata->envcolour);
gDPSetCombineLERP(renderdata->gdl++, TEXEL0, ENVIRONMENT, SHADE_ALPHA, ENVIRONMENT, TEXEL0, 0, ENVIRONMENT, 0, COMBINED, 0, SHADE, 0, 0, 0, 0, COMBINED);
if (renderdata->zbufferenabled) {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_ZB_XLU_SURF2);
} else {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_XLU_SURF2);
}
} else if (renderdata->unk30 == 9) {
if ((renderdata->envcolour & 0xff) == 0) {
gDPPipeSync(renderdata->gdl++);
gDPSetCycleType(renderdata->gdl++, G_CYC_2CYCLE);
gDPSetFogColorViaWord(renderdata->gdl++, renderdata->fogcolour);
gDPSetEnvColorViaWord(renderdata->gdl++, 0xffffffff);
gDPSetPrimColor(renderdata->gdl++, 0, 0, 0, 0, 0, (renderdata->envcolour >> 8) & 0xff);
if (arg1) {
gDPSetCombineLERP(renderdata->gdl++, TEXEL1, TEXEL0, LOD_FRACTION, TEXEL0, TEXEL1, TEXEL0, LOD_FRACTION, TEXEL0, COMBINED, 0, SHADE, 0, COMBINED, 0, SHADE, PRIMITIVE);
if (renderdata->zbufferenabled) {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_ZB_OPA_SURF2);
} else {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_OPA_SURF2);
}
} else {
gDPSetCombineLERP(renderdata->gdl++, TEXEL1, TEXEL0, LOD_FRACTION, TEXEL0, TEXEL1, TEXEL0, LOD_FRACTION, TEXEL0, COMBINED, 0, SHADE, 0, COMBINED, 0, SHADE, PRIMITIVE);
if (renderdata->zbufferenabled) {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_ZB_XLU_SURF2);
} else {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_XLU_SURF2);
}
}
} else {
gDPPipeSync(renderdata->gdl++);
gDPSetCycleType(renderdata->gdl++, G_CYC_2CYCLE);
gDPSetFogColorViaWord(renderdata->gdl++, renderdata->fogcolour);
gDPSetEnvColorViaWord(renderdata->gdl++, renderdata->envcolour & 0xff);
if (arg1) {
gDPSetCombineLERP(renderdata->gdl++, TEXEL1, TEXEL0, LOD_FRACTION, TEXEL0, 1, 0, SHADE, ENVIRONMENT, COMBINED, 0, SHADE, 0, 0, 0, 0, COMBINED);
if (renderdata->zbufferenabled) {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_ZB_TEX_EDGE2);
} else {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_TEX_EDGE2);
}
} else {
gDPSetPrimColor(renderdata->gdl++, 0, 0, 0, 0, 0, (renderdata->envcolour >> 8) & 0xff);
gDPSetCombineLERP(renderdata->gdl++, TEXEL1, TEXEL0, LOD_FRACTION, TEXEL0, SHADE, ENVIRONMENT, TEXEL0, 0, COMBINED, 0, SHADE, 0, 1, 0, PRIMITIVE, COMBINED);
if (renderdata->zbufferenabled) {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_ZB_TEX_EDGE2);
} else {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_TEX_EDGE2);
}
}
}
} else if (renderdata->unk30 == 4) {
gDPPipeSync(renderdata->gdl++);
gDPSetCycleType(renderdata->gdl++, G_CYC_2CYCLE);
gDPSetFogColorViaWord(renderdata->gdl++, renderdata->envcolour);
gDPSetCombineMode(renderdata->gdl++, G_CC_TRILERP, G_CC_MODULATEIA2);
if (arg1) {
if (renderdata->zbufferenabled) {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_ZB_OPA_SURF2);
} else {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_OPA_SURF2);
}
} else {
if (renderdata->zbufferenabled) {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_ZB_XLU_SURF2);
} else {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_XLU_SURF2);
}
}
} else if (renderdata->unk30 == 5) {
u8 alpha;
gDPPipeSync(renderdata->gdl++);
gDPSetCycleType(renderdata->gdl++, G_CYC_2CYCLE);
gDPSetFogColorViaWord(renderdata->gdl++, renderdata->fogcolour);
alpha = renderdata->envcolour & 0xff;
if (alpha < 255) {
gDPSetEnvColor(renderdata->gdl++, 0xff, 0xff, 0xff, alpha);
if (arg1) {
if (renderdata->envcolour & 0xff00) {
gDPSetCombineLERP(renderdata->gdl++, TEXEL1, TEXEL0, LOD_FRACTION, TEXEL0, 1, SHADE, ENVIRONMENT, 0, COMBINED, 0, SHADE, 0, COMBINED, 0, SHADE, 0);
} else {
gDPSetCombineLERP(renderdata->gdl++, TEXEL1, TEXEL0, LOD_FRACTION, TEXEL0, 1, 0, ENVIRONMENT, 0, COMBINED, 0, SHADE, 0, COMBINED, 0, SHADE, 0);
}
} else {
gDPSetCombineLERP(renderdata->gdl++, TEXEL1, TEXEL0, LOD_FRACTION, TEXEL0, TEXEL0, 0, ENVIRONMENT, 0, COMBINED, 0, SHADE, 0, COMBINED, 0, SHADE, 0);
}
} else {
gDPSetCombineMode(renderdata->gdl++, G_CC_TRILERP, G_CC_MODULATEIA2);
}
if (renderdata->zbufferenabled) {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_ZB_XLU_SURF2);
} else {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_XLU_SURF2);
}
} else {
gDPPipeSync(renderdata->gdl++);
gDPSetCycleType(renderdata->gdl++, G_CYC_2CYCLE);
gDPSetFogColorViaWord(renderdata->gdl++, 0xffffff00);
gDPSetCombineMode(renderdata->gdl++, G_CC_TRILERP, G_CC_MODULATEIA2);
if (arg1) {
if (renderdata->zbufferenabled) {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_ZB_OPA_SURF2);
} else {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_OPA_SURF2);
}
} else {
if (renderdata->zbufferenabled) {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_ZB_XLU_SURF2);
} else {
gDPSetRenderMode(renderdata->gdl++, G_RM_FOG_PRIM_A, G_RM_AA_XLU_SURF2);
}
}
}
}
void model00020bdc(struct modelrenderdata *renderdata)
{
gDPPipeSync(renderdata->gdl++);
gDPSetCycleType(renderdata->gdl++, G_CYC_2CYCLE);
if (renderdata->zbufferenabled) {
gDPSetRenderMode(renderdata->gdl++, G_RM_PASS, G_RM_AA_ZB_OPA_SURF2);
} else {
gDPSetRenderMode(renderdata->gdl++, G_RM_PASS, G_RM_AA_OPA_SURF2);
}
gDPSetCombineMode(renderdata->gdl++, G_CC_TRILERP, G_CC_MODULATEIA2);
}
void modelApplyCullMode(struct modelrenderdata *renderdata)
{
if (renderdata->cullmode == CULLMODE_NONE) {
gSPClearGeometryMode(renderdata->gdl++, G_CULL_BOTH);
} else if (renderdata->cullmode == CULLMODE_FRONT) {
gSPSetGeometryMode(renderdata->gdl++, G_CULL_FRONT);
} else if (renderdata->cullmode == CULLMODE_BACK) {
gSPSetGeometryMode(renderdata->gdl++, G_CULL_BACK);
}
}
void modelRenderNodeGundl(struct modelrenderdata *renderdata, struct model *model, struct modelnode *node)
{
struct modelrodata_gundl *rodata = &node->rodata->gundl;
if (var8005efc4 && !var8005efc4(model, node)) {
return;
}
if ((renderdata->flags & 1) && rodata->primary) {
gSPSegment(renderdata->gdl++, SPSEGMENT_MODEL_COL1, osVirtualToPhysical(rodata->baseaddr));
if (renderdata->cullmode) {
modelApplyCullMode(renderdata);
}
switch (rodata->unk12) {
case 1:
model0001f7e0(renderdata);
break;
case 3:
model0001f890(renderdata, true);
break;
case 4:
model00020248(renderdata, true);
break;
case 2:
model00020bdc(renderdata);
break;
}
gSPDisplayList(renderdata->gdl++, rodata->primary);
if (rodata->unk12 == 3 && rodata->secondary) {
model0001f890(renderdata, false);
gSPDisplayList(renderdata->gdl++, rodata->secondary);
}
}
if ((renderdata->flags & 2) && rodata->primary && rodata->unk12 == 4 && rodata->secondary) {
gSPSegment(renderdata->gdl++, SPSEGMENT_MODEL_COL1, osVirtualToPhysical(rodata->baseaddr));
if (renderdata->cullmode) {
modelApplyCullMode(renderdata);
}
model00020248(renderdata, false);
gSPDisplayList(renderdata->gdl++, rodata->secondary);
}
}
void modelRenderNodeDl(struct modelrenderdata *renderdata, struct model *model, struct modelnode *node)
{
union modelrodata *rodata = node->rodata;
if (var8005efc4 && !var8005efc4(model, node)) {
return;
}
if (renderdata->flags & 1) {
union modelrwdata *rwdata = modelGetNodeRwData(model, node);
if (rwdata->dl.gdl) {
gSPSegment(renderdata->gdl++, SPSEGMENT_MODEL_COL1, osVirtualToPhysical(rodata->dl.colourtable));
if (renderdata->cullmode) {
modelApplyCullMode(renderdata);
}
switch (rodata->dl.mcount) {
case 1:
model0001f7e0(renderdata);
break;
case 3:
model0001f890(renderdata, true);
break;
case 4:
model00020248(renderdata, true);
break;
case 2:
model00020bdc(renderdata);
break;
}
gSPSegment(renderdata->gdl++, SPSEGMENT_MODEL_VTX, osVirtualToPhysical(rwdata->dl.vertices));
gSPSegment(renderdata->gdl++, SPSEGMENT_MODEL_COL2, osVirtualToPhysical(rwdata->dl.colours));
gSPDisplayList(renderdata->gdl++, rwdata->dl.gdl);
if (rodata->dl.mcount == 3 && rodata->dl.secondary) {
model0001f890(renderdata, false);
gSPDisplayList(renderdata->gdl++, rodata->dl.secondary);
}
}
}
if (renderdata->flags & 2) {
union modelrwdata *rwdata = modelGetNodeRwData(model, node);
if (rwdata->dl.gdl && rodata->dl.mcount == 4 && rodata->dl.secondary) {
gSPSegment(renderdata->gdl++, SPSEGMENT_MODEL_COL1, osVirtualToPhysical(rodata->dl.colourtable));
if (renderdata->cullmode) {
modelApplyCullMode(renderdata);
}
gSPSegment(renderdata->gdl++, SPSEGMENT_MODEL_VTX, osVirtualToPhysical(rwdata->dl.vertices));
gSPSegment(renderdata->gdl++, SPSEGMENT_MODEL_COL2, osVirtualToPhysical(rwdata->dl.colours));
model00020248(renderdata, false);
gSPDisplayList(renderdata->gdl++, rodata->dl.secondary);
}
}
}
/**
* Star gunfire is a muzzle flash in a first person perspective, where the
* muzzle flash has 3 or 4 "arms" that flare out from the main body.
*
* Some weapons that use this are the Cyclone, Dragon, K7 Avenger, AR34,
* SuperDragon and RC-P45.
*
* This function reads vertices from the model definition, tweaks them randomly,
* writes them to a newly allocated vertices table and queues the node's
* displaylist to the renderdata's DL.
*/
void modelRenderNodeStarGunfire(struct modelrenderdata *renderdata, struct modelnode *node)
{
if (renderdata->flags & 2) {
struct modelrodata_stargunfire *rodata = &node->rodata->stargunfire;
s32 i;
if (rodata->gdl) {
struct gfxvtx *src = (struct gfxvtx *) rodata->vertices;
struct gfxvtx *dst = g_ModelVtxAllocatorFunc(rodata->unk00 * 4);
gSPSegment(renderdata->gdl++, SPSEGMENT_MODEL_VTX, osVirtualToPhysical(dst));
gSPSegment(renderdata->gdl++, SPSEGMENT_MODEL_COL2, osVirtualToPhysical((void *)ALIGN8((u32)&rodata->vertices[rodata->unk00 << 2])));
gSPSegment(renderdata->gdl++, SPSEGMENT_MODEL_COL1, osVirtualToPhysical(rodata->baseaddr));
gDPSetFogColor(renderdata->gdl++, 0x00, 0x00, 0x00, 0x00);
gSPDisplayList(renderdata->gdl++, rodata->gdl);
for (i = 0; i < rodata->unk00; i++) {
u16 rand1 = (random() << 10) & 0xffff;
s32 s4 = ((coss(rand1) << 5) * 181) >> 18;
s32 s3 = ((sins(rand1) << 5) * 181) >> 18;
s32 s1 = random() >> 31;
s32 mult = 0x10000 - (random() & 0x3fff);
s32 corner1 = 0x200 + s3;
s32 corner2 = 0x200 - s3;
s32 corner3 = 0x200 - s4;
s32 corner4 = 0x200 + s4;
dst[0] = src[0];
dst[1] = src[1];
dst[2] = src[2];
dst[3] = src[3];
dst[0].s = corner3;
dst[0].t = corner2;
dst[0].x = (src[(s1 + 0) % 4].x * mult) >> 16;
dst[0].y = (src[(s1 + 0) % 4].y * mult) >> 16;
dst[0].z = (src[(s1 + 0) % 4].z * mult) >> 16;
dst[1].s = corner1;
dst[1].t = corner3;
dst[1].x = (src[(s1 + 1) % 4].x * mult) >> 16;
dst[1].y = (src[(s1 + 1) % 4].y * mult) >> 16;
dst[1].z = (src[(s1 + 1) % 4].z * mult) >> 16;
dst[2].s = corner4;
dst[2].t = corner1;
dst[2].x = (src[(s1 + 2) % 4].x * mult) >> 16;
dst[2].y = (src[(s1 + 2) % 4].y * mult) >> 16;
dst[2].z = (src[(s1 + 2) % 4].z * mult) >> 16;
dst[3].s = corner2;
dst[3].t = corner4;
dst[3].x = (src[(s1 + 3) % 4].x * mult) >> 16;
dst[3].y = (src[(s1 + 3) % 4].y * mult) >> 16;
dst[3].z = (src[(s1 + 3) % 4].z * mult) >> 16;
src += 4;
dst += 4;
}
}
}
}
void model000216cc(struct modelrenderdata *renderdata, struct textureconfig *tconfig, s32 arg2)
{
texSelect(&renderdata->gdl, tconfig, arg2, renderdata->zbufferenabled, 2, 1, NULL);
}
void modelRenderNodeChrGunfire(struct modelrenderdata *renderdata, struct model *model, struct modelnode *node)
{
u32 stack[3];
f32 negspc0;
struct modelrodata_chrgunfire *rodata = &node->rodata->chrgunfire;
union modelrwdata *rwdata = modelGetNodeRwData(model, node);
struct gfxvtx *vertices;
f32 spf0;
f32 spec;
struct coord spe0;
f32 spdc;
f32 spd8;
f32 spd4;
f32 spd0;
f32 spcc;
f32 spc8;
f32 spc4;
f32 spc0;
f32 spbc;
f32 negspcc;
f32 negspc8;
f32 scale;
Mtxf *mtx;
f32 tmp;
struct coord sp9c;
struct coord sp90;
struct gfxvtx vtxtemplate = {0};
struct colour colourtemplate = {0xffffffff};
struct textureconfig *tconfig;
struct colour *colours;
f32 distance;
if ((renderdata->flags & 2) && rwdata->chrgunfire.visible) {
s32 index = model0001a524(node, 0);
mtx = &model->matrices[index];
spe0.x = -(rodata->pos.f[0] * mtx->m[0][0] + rodata->pos.f[1] * mtx->m[1][0] + rodata->pos.f[2] * mtx->m[2][0] + mtx->m[3][0]);
spe0.y = -(rodata->pos.f[0] * mtx->m[0][1] + rodata->pos.f[1] * mtx->m[1][1] + rodata->pos.f[2] * mtx->m[2][1] + mtx->m[3][1]);
spe0.z = -(rodata->pos.f[0] * mtx->m[0][2] + rodata->pos.f[1] * mtx->m[1][2] + rodata->pos.f[2] * mtx->m[2][2] + mtx->m[3][2]);
distance = sqrtf(spe0.f[0] * spe0.f[0] + spe0.f[1] * spe0.f[1] + spe0.f[2] * spe0.f[2]);
if (distance > 0) {
f32 tmp = 1 / (model->scale * distance);
spe0.f[0] *= tmp;
spe0.f[1] *= tmp;
spe0.f[2] *= tmp;
} else {
spe0.f[0] = 0;
spe0.f[1] = 0;
spe0.f[2] = 1 / model->scale;
}
spec = acosf(spe0.f[0] * mtx->m[1][0] + spe0.f[1] * mtx->m[1][1] + spe0.f[2] * mtx->m[1][2]);
spf0 = acosf(-(spe0.f[0] * mtx->m[2][0] + spe0.f[1] * mtx->m[2][1] + spe0.f[2] * mtx->m[2][2]) / sinf(spec));
tmp = -(spe0.f[0] * mtx->m[0][0] + spe0.f[1] * mtx->m[0][1] + spe0.f[2] * mtx->m[0][2]);
if (tmp < 0) {
spf0 = M_BADTAU - spf0;
}
spdc = cosf(spf0);
spd8 = sinf(spf0);
spd4 = cosf(spec);
spd0 = sinf(spec);
scale = 0.75f + (random() % 128) * (1.0f / 256.0f); // 0.75 to 1.25
sp9c.f[0] = rodata->dim.f[0] * scale;
sp9c.f[1] = rodata->dim.f[1] * scale;
sp9c.f[2] = rodata->dim.f[2] * scale;
spcc = sp9c.f[0] * spdc * 0.5f;
spc8 = sp9c.f[2] * spd8 * 0.5f;
spc4 = sp9c.f[1] * spd0 * 0.5f;
spc0 = sp9c.f[0] * spd4 * spd8 * 0.5f;
spbc = sp9c.f[2] * spd4 * spdc * 0.5f;
negspcc = -spcc;
negspc8 = -spc8;
negspc0 = -spc0;
sp90.f[0] = rodata->pos.f[0] - sp9c.f[0] * 0.5f;
sp90.f[1] = rodata->pos.f[1];
sp90.f[2] = rodata->pos.f[2];
vertices = g_ModelVtxAllocatorFunc(4);
colours = (struct colour *) gfxAllocateColours(1);
vertices[0] = vtxtemplate;
vertices[1] = vtxtemplate;
vertices[2] = vtxtemplate;
vertices[3] = vtxtemplate;
colours[0] = colourtemplate;
vertices[0].x = sp90.f[0] + negspcc + negspc0;
vertices[0].y = sp90.f[1] - spc4;
vertices[0].z = sp90.f[2] - negspc8 + -spbc;
vertices[1].x = sp90.f[0] + negspcc - negspc0;
vertices[1].y = sp90.f[1] + spc4;
vertices[1].z = sp90.f[2] - negspc8 - -spbc;
vertices[2].x = sp90.f[0] - negspcc - negspc0;
vertices[2].y = sp90.f[1] + spc4;
vertices[2].z = sp90.f[2] + negspc8 - -spbc;
vertices[3].x = sp90.f[0] - negspcc + negspc0;
vertices[3].y = sp90.f[1] - spc4;
vertices[3].z = sp90.f[2] + negspc8 + -spbc;
gSPSegment(renderdata->gdl++, SPSEGMENT_MODEL_COL1, osVirtualToPhysical(rodata->baseaddr));
if (rodata->texture) {
s32 centre;
u16 sp62;
s32 sp5c;
s32 sp58;
tconfig = rodata->texture;
sp62 = (random() * 1024) & 0xffff;
sp5c = (coss(sp62) * tconfig->width * 0xb5) >> 18;
sp58 = (sins(sp62) * tconfig->width * 0xb5) >> 18;
centre = tconfig->width << 4;
vertices[0].s = centre - sp5c;
vertices[0].t = centre - sp58;
vertices[1].s = centre + sp58;
vertices[1].t = centre - sp5c;
vertices[2].s = centre + sp5c;
vertices[2].t = centre + sp58;
vertices[3].s = centre - sp58;
vertices[3].t = centre + sp5c;
model000216cc(renderdata, tconfig, 4);
} else {
model000216cc(renderdata, NULL, 1);
}
gSPSetGeometryMode(renderdata->gdl++, G_CULL_BACK);
gSPMatrix(renderdata->gdl++, osVirtualToPhysical(mtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gDPSetColorArray(renderdata->gdl++, osVirtualToPhysical(colours), 1);
gDPSetVerticeArray(renderdata->gdl++, osVirtualToPhysical(vertices), 4);
gDPTri2(renderdata->gdl++, 0, 1, 2, 2, 3, 0);
}
}
void modelRender(struct modelrenderdata *renderdata, struct model *model)
{
union modelrodata *rodata;
union modelrwdata *rwdata;
u32 type;
struct modelnode *node = model->filedata->rootnode;
gSPSegment(renderdata->gdl++, SPSEGMENT_MODEL_MTX, osVirtualToPhysical(model->matrices));
while (node) {
type = node->type & 0xff;
switch (type) {
case MODELNODETYPE_DISTANCE:
case MODELNODETYPE_TOGGLE:
rodata = node->rodata;
rwdata = modelGetNodeRwData(model, node);
switch (type) {
case MODELNODETYPE_DISTANCE:
node->child = rwdata->distance.visible ? rodata->distance.target : NULL;
break;
case MODELNODETYPE_TOGGLE:
node->child = rwdata->toggle.visible ? rodata->toggle.target : NULL;
break;
}
break;
case MODELNODETYPE_HEADSPOT:
rwdata = modelGetNodeRwData(model, node);
if (rwdata->headspot.modelfiledata) {
struct modelnode *loopnode = rwdata->headspot.modelfiledata->rootnode;
node->child = loopnode;
while (loopnode) {
loopnode->parent = node;
loopnode = loopnode->next;
}
}
break;
case MODELNODETYPE_REORDER:
modelRenderNodeReorder(model, node);
break;
case MODELNODETYPE_CHRGUNFIRE:
modelRenderNodeChrGunfire(renderdata, model, node);
break;
case MODELNODETYPE_GUNDL:
modelRenderNodeGundl(renderdata, model, node);
break;
case MODELNODETYPE_DL:
modelRenderNodeDl(renderdata, model, node);
break;
case MODELNODETYPE_STARGUNFIRE:
modelRenderNodeStarGunfire(renderdata, node);
break;
case MODELNODETYPE_CHRINFO:
default:
break;
}
if (node->child) {
node = node->child;
} else {
while (node) {
if (node->next) {
node = node->next;
break;
}
node = node->parent;
}
}
}
}
bool model000220fc(struct modelrodata_bbox *bbox, Mtxf *mtx, struct coord *arg2, struct coord *arg3)
{
f32 xthingx;
f32 xthingy;
f32 xthingz;
u32 stack1[3];
f32 xsum1;
f32 xsum2;
f32 xsum3;
f32 f0;
u32 stack;
f32 ythingx;
f32 ythingy;
f32 ythingz;
u32 stack2[3];
f32 ysum1;
f32 ysum2;
f32 ysum3;
f32 mult1;
f32 mult2;
f32 bestsum2;
f32 bestsum1;
f32 anotherbestsum3;
f32 anotherbestsum1;
f32 xmin = bbox->xmin;
f32 xmax = bbox->xmax;
f32 ymin = bbox->ymin;
f32 ymax = bbox->ymax;
f32 zmin = bbox->zmin;
f32 zmax = bbox->zmax;
f32 mult3;
f32 mult4;
f32 zthingx;
f32 zthingy;
f32 zthingz;
u32 stack3[3];
f32 zsum1;
f32 zsum2;
f32 zsum3;
if (var8005efc0 != 0.0f) {
xmin -= var8005efc0;
xmax += var8005efc0;
ymin -= var8005efc0;
ymax += var8005efc0;
zmin -= var8005efc0;
zmax += var8005efc0;
}
// x
xthingx = mtx->m[0][0] * mtx->m[0][0];
xthingy = mtx->m[0][1] * mtx->m[0][1];
xthingz = mtx->m[0][2] * mtx->m[0][2];
xsum1 = mtx->m[0][0] * arg3->f[0] + mtx->m[0][1] * arg3->f[1] + mtx->m[0][2] * arg3->f[2];
xsum2 = mtx->m[0][0] * (arg2->f[0] - mtx->m[3][0]) + mtx->m[0][1] * (arg2->f[1] - mtx->m[3][1]) + mtx->m[0][2] * (arg2->f[2] - mtx->m[3][2]);
f0 = -(xthingx + xthingy + xthingz) * xmax;
xsum3 = -(xsum2 + f0);
f0 = -(xthingx + xthingy + xthingz) * xmin;
xsum2 = -(xsum2 + f0);
if (xsum1 < 0.0f) {
xsum1 = -xsum1;
xsum2 = -xsum2;
xsum3 = -xsum3;
}
if (xsum2 < 0.0f && xsum3 < 0.0f) {
return false;
}
if (xsum3 < xsum2) {
f32 tmp = xsum2;
xsum2 = xsum3;
xsum3 = tmp;
}
// y
ythingx = mtx->m[1][0] * mtx->m[1][0];
ythingy = mtx->m[1][1] * mtx->m[1][1];
ythingz = mtx->m[1][2] * mtx->m[1][2];
ysum1 = mtx->m[1][0] * arg3->f[0] + mtx->m[1][1] * arg3->f[1] + mtx->m[1][2] * arg3->f[2];
ysum2 = mtx->m[1][0] * (arg2->f[0] - mtx->m[3][0]) + mtx->m[1][1] * (arg2->f[1] - mtx->m[3][1]) + mtx->m[1][2] * (arg2->f[2] - mtx->m[3][2]);
f0 = -(ythingx + ythingy + ythingz) * ymax;
ysum3 = -(ysum2 + f0);
f0 = -(ythingx + ythingy + ythingz) * ymin;
ysum2 = -(ysum2 + f0);
if (ysum1 < 0.0f) {
ysum1 = -ysum1;
ysum2 = -ysum2;
ysum3 = -ysum3;
}
if (ysum2 < 0.0f && ysum3 < 0.0f) {
return false;
}
if (ysum3 < ysum2) {
f32 tmp = ysum2;
ysum2 = ysum3;
ysum3 = tmp;
}
// Do x and y comparison things
mult1 = ysum2 * xsum1;
mult2 = xsum2 * ysum1;
mult3 = xsum3 * ysum1;
mult4 = ysum3 * xsum1;
if (mult1 < mult2) {
if (mult4 < mult2) {
return false;
}
bestsum2 = xsum2;
bestsum1 = xsum1;
} else {
if (mult3 < mult1) {
return false;
}
bestsum2 = ysum2;
bestsum1 = ysum1;
}
if (mult3 < mult4) {
anotherbestsum3 = xsum3;
anotherbestsum1 = xsum1;
} else {
anotherbestsum3 = ysum3;
anotherbestsum1 = ysum1;
}
// z
zthingx = mtx->m[2][0] * mtx->m[2][0];
zthingy = mtx->m[2][1] * mtx->m[2][1];
zthingz = mtx->m[2][2] * mtx->m[2][2];
zsum1 = mtx->m[2][0] * arg3->f[0] + mtx->m[2][1] * arg3->f[1] + mtx->m[2][2] * arg3->f[2];
zsum2 = mtx->m[2][0] * (arg2->f[0] - mtx->m[3][0]) + mtx->m[2][1] * (arg2->f[1] - mtx->m[3][1]) + mtx->m[2][2] * (arg2->f[2] - mtx->m[3][2]);
f0 = -(zthingx + zthingy + zthingz) * zmax;
zsum3 = -(zsum2 + f0);
f0 = -(zthingx + zthingy + zthingz) * zmin;
zsum2 = -(zsum2 + f0);
if (zsum1 < 0.0f) {
zsum1 = -zsum1;
zsum2 = -zsum2;
zsum3 = -zsum3;
}
if (zsum2 < 0.0f && zsum3 < 0.0f) {
return false;
}
if (zsum3 < zsum2) {
f32 tmp = zsum2;
zsum2 = zsum3;
zsum3 = tmp;
}
// Do z comparison things with the result of the x/y comparison thing
if (bestsum2 * zsum1 < zsum2 * bestsum1) {
if (anotherbestsum3 * zsum1 < zsum2 * anotherbestsum1) {
return false;
}
} else {
if (zsum3 * bestsum1 < bestsum2 * zsum1) {
return false;
}
}
return true;
}
s32 model000225d4(struct model *model, struct coord *arg1, struct coord *arg2, struct modelnode **startnode)
{
struct modelnode *node;
bool dochildren = true;
Mtxf *mtx;
union modelrodata *rodata;
union modelrwdata *rwdata;
u32 type;
if (model);
if (*startnode) {
node = *startnode;
*startnode = NULL;
} else {
node = model->filedata->rootnode;
}
while (node) {
if (dochildren && node->child) {
node = node->child;
} else {
while (node) {
if (node->next) {
node = node->next;
break;
}
node = node->parent;
}
if (!node) {
break;
}
}
dochildren = true;
type = node->type & 0xff;
switch (type) {
case MODELNODETYPE_BBOX:
rodata = node->rodata;
mtx = model0001a5cc(model, node, 0);
if (model000220fc(&rodata->bbox, mtx, arg1, arg2)) {
*startnode = node;
return rodata->bbox.hitpart;
}
dochildren = false;
break;
case MODELNODETYPE_DISTANCE:
rodata = node->rodata;
rwdata = modelGetNodeRwData(model, node);
node->child = rwdata->distance.visible ? rodata->distance.target : NULL;
break;
case MODELNODETYPE_TOGGLE:
rodata = node->rodata;
rwdata = modelGetNodeRwData(model, node);
node->child = rwdata->toggle.visible ? rodata->toggle.target : NULL;
break;
case MODELNODETYPE_HEADSPOT:
rwdata = modelGetNodeRwData(model, node);
if (rwdata->headspot.modelfiledata) {
struct modelnode *loopnode = rwdata->headspot.modelfiledata->rootnode;
node->child = loopnode;
while (loopnode) {
loopnode->parent = node;
loopnode = loopnode->next;
}
}
break;
case MODELNODETYPE_CHRINFO:
case MODELNODETYPE_DL:
default:
break;
}
}
return 0;
}
#define PROMOTE(var) \
if (var) \
var = (void *)((u32)var + diff)
void modelPromoteNodeOffsetsToPointers(struct modelnode *node, u32 vma, u32 fileramaddr)
{
union modelrodata *rodata;
s32 diff = fileramaddr - vma;
while (node) {
u32 type = node->type & 0xff;
PROMOTE(node->rodata);
PROMOTE(node->parent);
PROMOTE(node->next);
PROMOTE(node->prev);
PROMOTE(node->child);
switch (type) {
case MODELNODETYPE_CHRINFO:
break;
case MODELNODETYPE_POSITION:
break;
case MODELNODETYPE_GUNDL:
rodata = node->rodata;
PROMOTE(rodata->gundl.vertices);
rodata->gundl.baseaddr = (void *)fileramaddr;
break;
case MODELNODETYPE_DL:
rodata = node->rodata;
PROMOTE(rodata->dl.vertices);
rodata->dl.colourtable = (void *)fileramaddr;
break;
case MODELNODETYPE_DISTANCE:
rodata = node->rodata;
PROMOTE(rodata->distance.target);
node->child = rodata->distance.target;
break;
case MODELNODETYPE_TOGGLE:
rodata = node->rodata;
PROMOTE(rodata->toggle.target);
break;
case MODELNODETYPE_REORDER:
rodata = node->rodata;
PROMOTE(rodata->reorder.unk18);
PROMOTE(rodata->reorder.unk1c);
break;
case MODELNODETYPE_11:
rodata = node->rodata;
PROMOTE(rodata->type11.unk14);
break;
case MODELNODETYPE_0B:
rodata = node->rodata;
PROMOTE(rodata->type0b.unk3c);
rodata->type0b.baseaddr = (void *)fileramaddr;
break;
case MODELNODETYPE_CHRGUNFIRE:
rodata = node->rodata;
PROMOTE(rodata->chrgunfire.texture);
rodata->chrgunfire.baseaddr = (void *)fileramaddr;
break;
case MODELNODETYPE_0D:
rodata = node->rodata;
PROMOTE(rodata->type0d.unk10);
PROMOTE(rodata->type0d.unk14);
rodata->type0d.baseaddr = (void *)fileramaddr;
break;
case MODELNODETYPE_STARGUNFIRE:
rodata = node->rodata;
PROMOTE(rodata->stargunfire.vertices);
rodata->stargunfire.baseaddr = (void *)fileramaddr;
break;
default:
break;
}
if (node->child) {
node = node->child;
} else {
while (node) {
if (node->next) {
node = node->next;
break;
}
node = node->parent;
}
}
}
}
/**
* Convert a model file's file-relative offsets to global pointers,
* and sort the part numbers list so they can be looked up using bisection.
*
* Offsets in model files are based from virtual memory address 0x0f000000.
* This vma address is specified as an argument to the function.
*/
void modelPromoteOffsetsToPointers(struct modelfiledata *filedata, u32 vma, u32 fileramaddr)
{
s32 diff = fileramaddr - vma;
s32 i;
s16 *partnums;
PROMOTE(filedata->rootnode);
PROMOTE(filedata->parts);
PROMOTE(filedata->texconfigs);
for (i = 0; i < filedata->numparts; i++) {
PROMOTE(filedata->parts[i]);
}
modelPromoteNodeOffsetsToPointers(filedata->rootnode, vma, fileramaddr);
// Sort parts by part number so they can be bisected during lookup
partnums = (s16 *)&filedata->parts[filedata->numparts];
if (filedata->numparts) {
struct modelnode *tmpnode;
s16 tmpnum;
bool changed;
do {
changed = false;
for (i = 0; i < filedata->numparts - 1; i++) {
if (partnums[i] > partnums[i + 1]) {
tmpnum = partnums[i];
partnums[i] = partnums[i + 1];
partnums[i + 1] = tmpnum;
tmpnode = filedata->parts[i];
filedata->parts[i] = filedata->parts[i + 1];
filedata->parts[i + 1] = tmpnode;
changed = true;
}
}
} while (changed == true);
}
}
s32 modelCalculateRwDataIndexes(struct modelnode *basenode)
{
u16 len = 0;
struct modelnode *node = basenode;
union modelrodata *rodata;
while (node) {
u32 type = node->type & 0xff;
switch (type) {
case MODELNODETYPE_CHRINFO:
rodata = node->rodata;
rodata->chrinfo.rwdataindex = len;
len += sizeof(struct modelrwdata_chrinfo) / 4;
break;
case MODELNODETYPE_DISTANCE:
rodata = node->rodata;
rodata->distance.rwdataindex = len;
len += sizeof(struct modelrwdata_distance) / 4;
node->child = rodata->distance.target;
break;
case MODELNODETYPE_TOGGLE:
rodata = node->rodata;
rodata->toggle.rwdataindex = len;
len += sizeof(struct modelrwdata_toggle) / 4;
node->child = rodata->toggle.target;
break;
case MODELNODETYPE_HEADSPOT:
rodata = node->rodata;
rodata->headspot.rwdataindex = len;
len += sizeof(struct modelrwdata_headspot) / 4;
node->child = NULL;
break;
case MODELNODETYPE_REORDER:
rodata = node->rodata;
rodata->reorder.rwdataindex = len;
len += sizeof(struct modelrwdata_reorder) / 4;
model0001c868(node, false);
break;
case MODELNODETYPE_0B:
rodata = node->rodata;
rodata->type0b.rwdataindex = len;
len += sizeof(struct modelrwdata_0b) / 4;
break;
case MODELNODETYPE_CHRGUNFIRE:
rodata = node->rodata;
rodata->chrgunfire.rwdataindex = len;
len += sizeof(struct modelrwdata_chrgunfire) / 4;
break;
case MODELNODETYPE_DL:
rodata = node->rodata;
rodata->dl.rwdataindex = len;
len += sizeof(struct modelrwdata_dl) / 4;
break;
default:
break;
}
if (node->child) {
node = node->child;
} else {
while (node) {
if (node == basenode->parent) {
node = NULL;
break;
}
if (node->next) {
node = node->next;
break;
}
node = node->parent;
}
}
}
return len;
}
void modelCalculateRwDataLen(struct modelfiledata *filedata)
{
filedata->rwdatalen = modelCalculateRwDataIndexes(filedata->rootnode);
}
void modelInitRwData(struct model *model, struct modelnode *startnode)
{
struct modelnode *node = startnode;
union modelrodata *rodata;
union modelrwdata *rwdata;
while (node) {
u32 type = node->type & 0xff;
switch (type) {
case MODELNODETYPE_CHRINFO:
rwdata = modelGetNodeRwData(model, node);
rwdata->chrinfo.unk00 = 0;
rwdata->chrinfo.ground = 0;
rwdata->chrinfo.pos.x = 0;
rwdata->chrinfo.pos.y = 0;
rwdata->chrinfo.pos.z = 0;
rwdata->chrinfo.unk14 = 0;
rwdata->chrinfo.unk18 = 0;
rwdata->chrinfo.unk1c = 0;
rwdata->chrinfo.unk01 = 0;
rwdata->chrinfo.unk34.x = 0;
rwdata->chrinfo.unk34.y = 0;
rwdata->chrinfo.unk34.z = 0;
rwdata->chrinfo.unk30 = 0;
rwdata->chrinfo.unk24.x = 0;
rwdata->chrinfo.unk24.y = 0;
rwdata->chrinfo.unk24.z = 0;
rwdata->chrinfo.unk20 = 0;
rwdata->chrinfo.unk02 = 0;
rwdata->chrinfo.unk4c.x = 0;
rwdata->chrinfo.unk4c.y = 0;
rwdata->chrinfo.unk4c.z = 0;
rwdata->chrinfo.unk40.x = 0;
rwdata->chrinfo.unk40.y = 0;
rwdata->chrinfo.unk40.z = 0;
rwdata->chrinfo.unk5c = 0;
break;
case MODELNODETYPE_DISTANCE:
rodata = node->rodata;
rwdata = modelGetNodeRwData(model, node);
rwdata->distance.visible = false;
node->child = rodata->distance.target;
break;
case MODELNODETYPE_TOGGLE:
rodata = node->rodata;
rwdata = modelGetNodeRwData(model, node);
rwdata->toggle.visible = true;
node->child = rodata->toggle.target;
break;
case MODELNODETYPE_HEADSPOT:
rwdata = modelGetNodeRwData(model, node);
rwdata->headspot.modelfiledata = NULL;
rwdata->headspot.rwdatas = NULL;
break;
case MODELNODETYPE_REORDER:
rwdata = modelGetNodeRwData(model, node);
rwdata->reorder.visible = false;
modelRenderNodeReorder(model, node);
break;
case MODELNODETYPE_0B:
rwdata = modelGetNodeRwData(model, node);
rwdata->type0b.unk00 = 0;
break;
case MODELNODETYPE_CHRGUNFIRE:
rwdata = modelGetNodeRwData(model, node);
rwdata->chrgunfire.visible = false;
break;
case MODELNODETYPE_DL:
rodata = node->rodata;
rwdata = modelGetNodeRwData(model, node);
rwdata->dl.vertices = rodata->dl.vertices;
rwdata->dl.gdl = rodata->dl.primary;
rwdata->dl.colours = (void *) ALIGN8((u32)(rodata->dl.vertices + rodata->dl.numvertices));
if (rodata->dl.numvertices);
if (rodata->dl.numvertices);
if (rodata->dl.numvertices);
break;
default:
break;
}
if (node->child) {
node = node->child;
} else {
while (node) {
if (node == startnode->parent) {
node = NULL;
break;
}
if (node->next) {
node = node->next;
break;
}
node = node->parent;
}
}
}
}
void modelInit(struct model *model, struct modelfiledata *filedata, union modelrwdata **rwdatas, bool resetanim)
{
struct modelnode *node;
model->unk00 = 0;
model->filedata = filedata;
model->rwdatas = rwdatas;
model->unk02 = -1;
model->scale = 1;
model->attachedtomodel = NULL;
model->attachedtonode = NULL;
node = filedata->rootnode;
while (node) {
u32 type = node->type & 0xff;
if (type == MODELNODETYPE_HEADSPOT) {
model->unk00 |= 1;
}
if (node->child) {
node = node->child;
} else {
while (node) {
if (node == filedata->rootnode->parent) {
node = NULL;
break;
}
if (node->next) {
node = node->next;
break;
}
node = node->parent;
}
}
}
if (rwdatas != NULL) {
modelInitRwData(model, filedata->rootnode);
}
if (resetanim) {
model->anim = NULL;
}
}
void animInit(struct anim *anim)
{
anim->animnum = 0;
anim->animnum2 = 0;
anim->looping = 0;
anim->flipfunc = NULL;
anim->unk6c = 0;
anim->unk70 = NULL;
anim->average = 0;
anim->frac = 0;
anim->timespeed = 0;
anim->frac2 = 0;
anim->timespeed2 = 0;
anim->fracmerge = 0;
anim->timemerge = 0;
anim->timeplay = 0;
anim->endframe = -1;
anim->endframe2 = -1;
anim->speed = 1;
anim->speed2 = 1;
anim->playspeed = 1;
anim->animscale = 1;
}
void model00023108(struct model *pmodel, struct modelfiledata *pmodeldef, struct modelnode *pnode, struct modelfiledata *cmodeldef)
{
struct modelrwdata_headspot *rwdata = modelGetNodeRwData(pmodel, pnode);
struct modelnode *node;
rwdata->modelfiledata = cmodeldef;
rwdata->rwdatas = &pmodel->rwdatas[pmodeldef->rwdatalen];
pnode->child = cmodeldef->rootnode;
node = pnode->child;
while (node) {
node->parent = pnode;
node = node->next;
}
pmodeldef->rwdatalen += modelCalculateRwDataIndexes(pnode->child);
}
/**
* This function can be called repeatedly to iterate a model's display lists.
*
* On the first call, the value passed as nodeptr should point to a NULL value.
* Each time the function is called, it will update *gdlptr to point to the next
* display list, and will update *nodeptr to point to the current node. On
* subsequent calls, the same values should be passed as nodeptr and gdlptr so
* the function can continue correctly.
*
* Note that some node types support multiple display lists, so the function
* may return the same node while it iterates the display lists for that node.
*/
void modelIterateDisplayLists(struct modelfiledata *filedata, struct modelnode **nodeptr, Gfx **gdlptr)
{
struct modelnode *node = *nodeptr;
union modelrodata *rodata;
Gfx *gdl = NULL;
if (node == NULL) {
node = filedata->rootnode;
}
while (node) {
u32 type = node->type & 0xff;
switch (type) {
case MODELNODETYPE_GUNDL:
rodata = node->rodata;
if (node != *nodeptr) {
gdl = rodata->gundl.primary;
} else if (rodata->gundl.secondary != *gdlptr) {
gdl = rodata->gundl.secondary;
}
break;
case MODELNODETYPE_DL:
rodata = node->rodata;
if (node != *nodeptr) {
gdl = rodata->dl.primary;
} else if (rodata->dl.secondary != *gdlptr) {
gdl = rodata->dl.secondary;
}
break;
case MODELNODETYPE_STARGUNFIRE:
rodata = node->rodata;
if (node != *nodeptr) {
gdl = rodata->stargunfire.gdl;
}
break;
case MODELNODETYPE_DISTANCE:
rodata = node->rodata;
node->child = rodata->distance.target;
break;
case MODELNODETYPE_TOGGLE:
rodata = node->rodata;
node->child = rodata->toggle.target;
break;
case MODELNODETYPE_REORDER:
model0001c868(node, true);
break;
}
if (gdl) {
break;
}
if (node->child) {
node = node->child;
} else {
while (node) {
if (node->next) {
node = node->next;
break;
}
node = node->parent;
}
}
}
*gdlptr = gdl;
*nodeptr = node;
}
void modelNodeReplaceGdl(u32 arg0, struct modelnode *node, Gfx *find, Gfx *replacement)
{
union modelrodata *rodata;
u32 type = node->type & 0xff;
switch (type) {
case MODELNODETYPE_GUNDL:
rodata = node->rodata;
if (rodata->gundl.primary == find) {
rodata->gundl.primary = replacement;
return;
}
if (rodata->gundl.secondary == find) {
rodata->gundl.secondary = replacement;
return;
}
break;
case MODELNODETYPE_DL:
rodata = node->rodata;
if (rodata->dl.primary == find) {
rodata->dl.primary = replacement;
return;
}
if (rodata->dl.secondary == find) {
rodata->dl.secondary = replacement;
return;
}
break;
case MODELNODETYPE_STARGUNFIRE:
rodata = node->rodata;
if (rodata->stargunfire.gdl == find) {
rodata->stargunfire.gdl = replacement;
return;
}
break;
}
}