ActorModelData cleanup in preparation for decoupled model animations

This commit is contained in:
Ricardo Luís Vaz Silva 2023-11-17 20:34:43 -03:00 committed by Rachael Alexanderson
parent 848dbd4d3d
commit 1a8dfd2dfa
9 changed files with 73 additions and 52 deletions

View file

@ -210,8 +210,8 @@ class TObjPtr
{
union
{
T pp;
DObject *o;
mutable T pp;
mutable DObject *o;
};
public:
@ -273,16 +273,22 @@ public:
{
return GC::ReadBarrier(pp);
}
constexpr bool operator!=(T u) noexcept
constexpr const T operator->() const noexcept
{
return GC::ReadBarrier(pp);
}
constexpr bool operator!=(T u) const noexcept
{
return GC::ReadBarrier(o) != u;
}
constexpr bool operator==(T u) noexcept
constexpr bool operator==(T u) const noexcept
{
return GC::ReadBarrier(o) == u;
}
constexpr bool operator==(TObjPtr<T> u) noexcept
constexpr bool operator==(TObjPtr<T> u) const noexcept
{
return ForceGet() == u.ForceGet();
}

View file

@ -695,12 +695,17 @@ struct ModelOverride
TArray<FTextureID> surfaceSkinIDs;
};
enum ModelDataFlags
{
MODELDATA_HADMODEL = 1 << 0,
};
class DActorModelData : public DObject
{
DECLARE_CLASS(DActorModelData, DObject);
public:
FName modelDef;
bool hasModel;
int flags;
TArray<ModelOverride> models;
TArray<FTextureID> skinIDs;
TArray<int> animationIDs;

View file

@ -5088,6 +5088,35 @@ DEFINE_ACTION_FUNCTION(AActor, A_SetMugshotState)
// This function allows the changing of an actor's modeldef, or models and/or skins at a given index
//==========================================================================
static void EnsureModelData(AActor * mobj)
{
if (mobj->modelData == nullptr)
{
auto ptr = Create<DActorModelData>();
ptr->flags = (mobj->hasmodel ? MODELDATA_HADMODEL : 0);
ptr->modelDef = NAME_None;
mobj->modelData = ptr;
mobj->hasmodel = true;
GC::WriteBarrier(mobj, ptr);
}
}
static void CleanupModelData(AActor * mobj)
{
if ( mobj->modelData->models.Size() == 0
&& mobj->modelData->modelFrameGenerators.Size() == 0
&& mobj->modelData->skinIDs.Size() == 0
&& mobj->modelData->animationIDs.Size() == 0
&& mobj->modelData->modelDef == NAME_None)
{
mobj->hasmodel = mobj->modelData->flags & MODELDATA_HADMODEL;
mobj->modelData->Destroy();
mobj->modelData = nullptr;
}
}
enum ChangeModelFlags
{
CMDL_WEAPONTOPLAYER = 1,
@ -5139,17 +5168,7 @@ void ChangeModelNative(
if (skinpath.Len() != 0 && skinpath[(int)skinpath.Len() - 1] != '/') skinpath += '/';
if (animationpath.Len() != 0 && animationpath[(int)animationpath.Len() - 1] != '/') animationpath += '/';
if (mobj->modelData == nullptr)
{
auto ptr = Create<DActorModelData>();
ptr->hasModel = mobj->hasmodel;
ptr->modelDef = NAME_None;
mobj->modelData = ptr;
mobj->hasmodel = true;
GC::WriteBarrier(mobj, ptr);
};
EnsureModelData(mobj);
int queryModel = !(flags & CMDL_HIDEMODEL) ? model != NAME_None ? FindModel(modelpath.GetChars(), model.GetChars()) : -1 : -2;
int queryAnimation = animation != NAME_None ? FindModel(animationpath.GetChars(), animation.GetChars()) : -1;
@ -5290,12 +5309,7 @@ void ChangeModelNative(
if(!found) savedModelFiles.Push(fullName);
}
if (mobj->modelData->models.Size() == 0 && mobj->modelData->modelFrameGenerators.Size() == 0 && mobj->modelData->skinIDs.Size() == 0 && mobj->modelData->animationIDs.Size() == 0 && modeldef == NAME_None)
{
mobj->hasmodel = mobj->modelData->hasModel;
mobj->modelData->Destroy();
mobj->modelData = nullptr;
}
CleanupModelData(mobj);
return;
}

View file

@ -1345,7 +1345,7 @@ void DActorModelData::Serialize(FSerializer& arc)
//("surfaceSkinIDs", surfaceSkinIDs)
("animationIDs", animationIDs)
("modelFrameGenerators", modelFrameGenerators)
("hasModel", hasModel);
("flags", flags);
}
void DActorModelData::OnDestroy()

View file

@ -43,6 +43,7 @@
#include "i_time.h"
#include "texturemanager.h"
#include "modelrenderer.h"
#include "actor.h"
#ifdef _MSC_VER
@ -55,7 +56,7 @@ EXTERN_CVAR (Bool, r_drawvoxels)
extern TDeletingArray<FVoxel *> Voxels;
extern TDeletingArray<FVoxelDef *> VoxelDefs;
void RenderFrameModels(FModelRenderer* renderer, FLevelLocals* Level, const FSpriteModelFrame *smf, const FState* curState, const int curTics, const PClass* ti, FTranslationID translation, AActor* actor);
void RenderFrameModels(FModelRenderer* renderer, FLevelLocals* Level, const FSpriteModelFrame *smf, const FState* curState, const int curTics, FTranslationID translation, AActor* actor);
void RenderModel(FModelRenderer *renderer, float x, float y, float z, FSpriteModelFrame *smf, AActor *actor, double ticFrac)
@ -189,7 +190,7 @@ void RenderModel(FModelRenderer *renderer, float x, float y, float z, FSpriteMod
float orientation = scaleFactorX * scaleFactorY * scaleFactorZ;
renderer->BeginDrawModel(actor->RenderStyle, smf, objectToWorldMatrix, orientation < 0);
RenderFrameModels(renderer, actor->Level, smf, actor->state, actor->tics, actor->modelData != nullptr ? actor->modelData->modelDef != NAME_None ? PClass::FindActor(actor->modelData->modelDef) : actor->GetClass() : actor->GetClass(), translation, actor);
RenderFrameModels(renderer, actor->Level, smf, actor->state, actor->tics, translation, actor);
renderer->EndDrawModel(actor->RenderStyle, smf);
}
@ -248,14 +249,11 @@ void RenderHUDModel(FModelRenderer *renderer, DPSprite *psp, FVector3 translatio
auto trans = psp->GetTranslation();
if ((psp->Flags & PSPF_PLAYERTRANSLATED)) trans = psp->Owner->mo->Translation;
auto callerclass = psp->Caller->modelData != nullptr && psp->Caller->modelData->modelDef != NAME_None ?
PClass::FindActor(psp->Caller->modelData->modelDef) : psp->Caller->GetClass();
RenderFrameModels(renderer, playermo->Level, smf, psp->GetState(), psp->GetTics(), callerclass, trans, psp->Caller);
RenderFrameModels(renderer, playermo->Level, smf, psp->GetState(), psp->GetTics(), trans, psp->Caller);
renderer->EndDrawHUDModel(playermo->RenderStyle, smf);
}
void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpriteModelFrame *smf, const FState *curState, const int curTics, const PClass *ti, FTranslationID translation, AActor* actor)
void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpriteModelFrame *smf, const FState *curState, const int curTics, FTranslationID translation, AActor* actor)
{
// [BB] Frame interpolation: Find the FSpriteModelFrame smfNext which follows after smf in the animation
// and the scalar value inter ( element of [0,1) ), both necessary to determine the interpolated frame.
@ -298,7 +296,7 @@ void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpr
}
}
if (nextState && inter != 0.0)
smfNext = FindModelFrame(ti, nextState->sprite, nextState->Frame, false);
smfNext = FindModelFrame(actor, nextState->sprite, nextState->Frame, false);
}
}
}
@ -969,7 +967,7 @@ static void ParseModelDefLump(int Lump)
//
//===========================================================================
FSpriteModelFrame * FindModelFrame(const PClass * ti, int sprite, int frame, bool dropped)
FSpriteModelFrame * FindModelFrameRaw(const PClass * ti, int sprite, int frame, bool dropped)
{
if (GetDefaultByType(ti)->hasmodel)
{
@ -1008,6 +1006,11 @@ FSpriteModelFrame * FindModelFrame(const PClass * ti, int sprite, int frame, boo
return nullptr;
}
FSpriteModelFrame * FindModelFrame(const AActor * thing, int sprite, int frame, bool dropped)
{
return FindModelFrameRaw((thing->modelData != nullptr && thing->modelData->modelDef != NAME_None) ? PClass::FindActor(thing->modelData->modelDef) : thing->GetClass(), sprite, frame, dropped);
}
//===========================================================================
//
// IsHUDModelForPlayerAvailable
@ -1022,7 +1025,7 @@ bool IsHUDModelForPlayerAvailable (player_t * player)
// [MK] check that at least one psprite uses models
for (DPSprite *psp = player->psprites; psp != nullptr && psp->GetID() < PSP_TARGETCENTER; psp = psp->GetNext())
{
FSpriteModelFrame *smf = psp->Caller != nullptr ? FindModelFrame(psp->Caller->modelData != nullptr ? psp->Caller->modelData->modelDef != NAME_None ? PClass::FindActor(psp->Caller->modelData->modelDef) : psp->Caller->GetClass() : psp->Caller->GetClass(), psp->GetSprite(), psp->GetFrame(), false) : nullptr;
FSpriteModelFrame *smf = psp->Caller != nullptr ? FindModelFrame(psp->Caller, psp->GetSprite(), psp->GetFrame(), false) : nullptr;
if ( smf != nullptr ) return true;
}
return false;

View file

@ -62,7 +62,8 @@ enum
MDL_FORCECULLBACKFACES = 1<<14,
};
FSpriteModelFrame * FindModelFrame(const PClass * ti, int sprite, int frame, bool dropped);
FSpriteModelFrame * FindModelFrame(const AActor * thing, int sprite, int frame, bool dropped);
FSpriteModelFrame * FindModelFrameRaw(const PClass * ti, int sprite, int frame, bool dropped);
bool IsHUDModelForPlayerAvailable(player_t * player);
// Check if circle potentially intersects with node AABB

View file

@ -159,7 +159,7 @@ void hw_PrecacheTexture(uint8_t *texhitlist, TMap<PClassActor*, bool> &actorhitl
{
auto &state = cls->GetStates()[i];
spritelist[state.sprite].Insert(gltrans, true);
FSpriteModelFrame * smf = FindModelFrame(cls, state.sprite, state.Frame, false);
FSpriteModelFrame * smf = FindModelFrameRaw(cls, state.sprite, state.Frame, false);
if (smf != NULL)
{
for (int i = 0; i < smf->modelsAmount; i++)

View file

@ -783,20 +783,14 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
if (fabs(viewpos.X - vp.Pos.X) < 32 && fabs(viewpos.Y - vp.Pos.Y) < 32) return;
}
modelframe = isPicnumOverride ? nullptr : FindModelFrame(thing, spritenum, thing->frame, !!(thing->flags & MF_DROPPED));
// Too close to the camera. This doesn't look good if it is a sprite.
if (fabs(thingpos.X - vp.Pos.X) < 2 && fabs(thingpos.Y - vp.Pos.Y) < 2)
if (fabs(thingpos.X - vp.Pos.X) < 2 && fabs(thingpos.Y - vp.Pos.Y) < 2
&& vp.Pos.Z >= thingpos.Z - 2 && vp.Pos.Z <= thingpos.Z + thing->Height + 2
&& !thing->Vel.isZero() && !modelframe) // exclude vertically moving objects from this check.
{
if (vp.Pos.Z >= thingpos.Z - 2 && vp.Pos.Z <= thingpos.Z + thing->Height + 2)
{
// exclude vertically moving objects from this check.
if (!thing->Vel.isZero())
{
if (!FindModelFrame(thing->GetClass(), spritenum, thing->frame, false))
{
return;
}
}
}
return;
}
// don't draw first frame of a player missile
@ -856,8 +850,6 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t
z += fz;
}
modelframe = isPicnumOverride ? nullptr : FindModelFrame(thing->modelData != nullptr ? thing->modelData->modelDef != NAME_None ? PClass::FindActor(thing->modelData->modelDef) : thing->GetClass() : thing->GetClass(), spritenum, thing->frame, !!(thing->flags & MF_DROPPED));
// don't bother drawing sprite shadows if this is a model (it will never look right)
if (modelframe && isSpriteShadow)
{

View file

@ -707,7 +707,7 @@ void HWDrawInfo::PreparePlayerSprites2D(sector_t * viewsector, area_t in_area)
{
if (!psp->GetState()) continue;
FSpriteModelFrame *smf = psp->Caller != nullptr ? FindModelFrame(psp->Caller->modelData != nullptr ? psp->Caller->modelData->modelDef != NAME_None ? PClass::FindActor(psp->Caller->modelData->modelDef) : psp->Caller->GetClass() : psp->Caller->GetClass(), psp->GetSprite(), psp->GetFrame(), false) : nullptr;
FSpriteModelFrame *smf = psp->Caller != nullptr ? FindModelFrame(psp->Caller, psp->GetSprite(), psp->GetFrame(), false) : nullptr;
// This is an 'either-or' proposition. This maybe needs some work to allow overlays with weapon models but as originally implemented this just won't work.
if (smf) continue;
@ -792,7 +792,7 @@ void HWDrawInfo::PreparePlayerSprites3D(sector_t * viewsector, area_t in_area)
for (DPSprite *psp = player->psprites; psp != nullptr && psp->GetID() < PSP_TARGETCENTER; psp = psp->GetNext())
{
if (!psp->GetState()) continue;
FSpriteModelFrame *smf = psp->Caller != nullptr ? FindModelFrame(psp->Caller->modelData != nullptr ? psp->Caller->modelData->modelDef != NAME_None ? PClass::FindActor(psp->Caller->modelData->modelDef) : psp->Caller->GetClass() : psp->Caller->GetClass(), psp->GetSprite(), psp->GetFrame(), false) : nullptr;
FSpriteModelFrame *smf = psp->Caller != nullptr ? FindModelFrame(psp->Caller, psp->GetSprite(), psp->GetFrame(), false) : nullptr;
// This is an 'either-or' proposition. This maybe needs some work to allow overlays with weapon models but as originally implemented this just won't work.
if (!smf) continue;