sm64coopdx/data/dynos_gfx_update.cpp
2022-04-01 20:04:24 -07:00

168 lines
6.8 KiB
C++

#include "dynos.cpp.h"
extern "C" {
#include "object_fields.h"
#include "game/level_update.h"
#include "game/object_list_processor.h"
#include "pc/configfile.h"
}
//
// Update animations
//
// Retrieve the current Mario's animation index
static s32 RetrieveCurrentMarioAnimationIndex() {
struct MarioAnimDmaRelatedThing *_AnimDmaTable = gMarioState->animation->animDmaTable;
for (s32 i = 0; i != (s32) _AnimDmaTable->count; ++i) {
void *_AnimAddr = _AnimDmaTable->srcAddr + _AnimDmaTable->anim[i].offset;
if (_AnimAddr == gMarioState->animation->currentAnimAddr) {
return i;
}
}
return -1;
}
// Retrieve the current animation index
// As we don't know the length of the table, let's hope that we'll always find the animation...
static s32 RetrieveCurrentAnimationIndex(struct Object *aObject) {
if (!aObject->oAnimations || !aObject->header.gfx.animInfo.curAnim) {
return -1;
}
for (s32 i = 0; aObject->oAnimations[i] != NULL; ++i) {
if (aObject->oAnimations[i] == aObject->header.gfx.animInfo.curAnim) {
return i;
}
}
return -1;
}
// Must be called twice, before and after geo_set_animation_globals
void DynOS_Gfx_SwapAnimations(void *aPtr) {
static Animation *pDefaultAnimation = NULL;
static Animation sGfxDataAnimation;
// Does the object has a model?
struct Object *_Object = (struct Object *) aPtr;
if (!_Object->header.gfx.sharedChild) {
return;
}
// Swap the current animation with the one from the Gfx data
if (!pDefaultAnimation) {
pDefaultAnimation = _Object->header.gfx.animInfo.curAnim;
// Actor index
s32 _ActorIndex = DynOS_Geo_GetActorIndex(_Object->header.gfx.sharedChild->georef);
if (_ActorIndex == -1) {
return;
}
// Gfx data
GfxData *_GfxData = DynOS_Gfx_GetActorList()[_ActorIndex].mGfxData;
if (!_GfxData) {
return;
}
// Animation table
if (_GfxData->mAnimationTable.Empty()) {
return;
}
// Animation index
s32 _AnimIndex = (_Object == gMarioObject ? RetrieveCurrentMarioAnimationIndex() : RetrieveCurrentAnimationIndex(_Object));
if (_AnimIndex == -1) {
return;
}
// Animation data
const AnimData *_AnimData = (const AnimData *) _GfxData->mAnimationTable[_AnimIndex].second;
if (_AnimData) {
sGfxDataAnimation.flags = _AnimData->mFlags;
sGfxDataAnimation.animYTransDivisor = _AnimData->mUnk02;
sGfxDataAnimation.startFrame = _AnimData->mUnk04;
sGfxDataAnimation.loopStart = _AnimData->mUnk06;
sGfxDataAnimation.loopEnd = _AnimData->mUnk08;
sGfxDataAnimation.unusedBoneCount = _AnimData->mUnk0A.second;
sGfxDataAnimation.values = _AnimData->mValues.second.begin();
sGfxDataAnimation.index = _AnimData->mIndex.second.begin();
sGfxDataAnimation.length = _AnimData->mLength;
_Object->header.gfx.animInfo.curAnim = &sGfxDataAnimation;
}
// Restore the default animation
} else {
_Object->header.gfx.animInfo.curAnim = pDefaultAnimation;
pDefaultAnimation = NULL;
}
}
//
// Update models
//
void DynOS_Gfx_Update() {
if (gObjectLists) {
// Check packs
Array<bool> &_Enabled = DynOS_Gfx_GetPacksEnabled();
const Array<PackData *> &pDynosPacks = DynOS_Gfx_GetPacks();
while (_Enabled.Count() < pDynosPacks.Count()) {
_Enabled.Add(true);
}
// Loop through all object lists
for (s32 list : { OBJ_LIST_PLAYER, OBJ_LIST_DESTRUCTIVE, OBJ_LIST_GENACTOR, OBJ_LIST_PUSHABLE, OBJ_LIST_LEVEL, OBJ_LIST_DEFAULT, OBJ_LIST_SURFACE, OBJ_LIST_POLELIKE, OBJ_LIST_UNIMPORTANT }) {
struct Object *_Head = (struct Object *) &gObjectLists[list];
for (struct Object *_Object = (struct Object *) _Head->header.next; _Object != _Head; _Object = (struct Object *) _Object->header.next) {
if (_Object->header.gfx.sharedChild) {
// Actor index
s32 _ActorIndex = DynOS_Geo_GetActorIndex(_Object->header.gfx.sharedChild->georef);
if (_ActorIndex != -1) {
// Replace the object's model and animations
ActorGfx *_ActorGfx = &DynOS_Gfx_GetActorList()[_ActorIndex];
// Check for disabled downloaded models
if (configDisableDownloadedModels && _ActorGfx->mPackIndex == 99) {
extern const GeoLayout error_model_geo[];
s32 actorIndex = DynOS_Geo_IsCustomActor(_ActorIndex) ? DynOS_Geo_GetActorIndex(error_model_geo) : _ActorIndex;
const void* geoLayout = DynOS_Geo_GetActorLayout(actorIndex);
_ActorGfx->mPackIndex = -1;
_ActorGfx->mGfxData = NULL;
_ActorGfx->mGraphNode = (GraphNode *) DynOS_Geo_GetGraphNode(geoLayout, true);
}
for (s32 i = 0; i != pDynosPacks.Count(); ++i) {
// If enabled and no pack is selected
// load the pack's model and replace the default actor's model
if (_Enabled[i] && _ActorGfx->mPackIndex == -1) {
// Load Gfx data from binary
GfxData *_GfxData = DynOS_Actor_LoadFromBinary(pDynosPacks[i]->mPath, DynOS_Geo_GetActorName(_ActorIndex));
if (_GfxData) {
_ActorGfx->mPackIndex = i;
_ActorGfx->mGfxData = _GfxData;
_ActorGfx->mGraphNode = (GraphNode *) DynOS_Geo_GetGraphNode((*(_GfxData->mGeoLayouts.end() - 1))->mData, true);
_ActorGfx->mGraphNode->georef = DynOS_Geo_GetActorLayout(_ActorIndex);
break;
}
}
// If disabled and this pack is the one selected
// replace the actor's model by the default one
else if (!_Enabled[i] && _ActorGfx->mPackIndex == i) {
_ActorGfx->mPackIndex = -1;
_ActorGfx->mGfxData = NULL;
_ActorGfx->mGraphNode = (GraphNode *) DynOS_Geo_GetGraphNode(DynOS_Geo_GetActorLayout(_ActorIndex), true);
}
}
// Update object
_Object->header.gfx.sharedChild = _ActorGfx->mGraphNode;
}
}
}
}
}
}