diff --git a/src/common/objects/dobjgc.h b/src/common/objects/dobjgc.h index 25e27bfb3..969551d37 100644 --- a/src/common/objects/dobjgc.h +++ b/src/common/objects/dobjgc.h @@ -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 u) noexcept + constexpr bool operator==(TObjPtr u) const noexcept { return ForceGet() == u.ForceGet(); } diff --git a/src/playsim/actor.h b/src/playsim/actor.h index 1e3013b27..84c199eb6 100644 --- a/src/playsim/actor.h +++ b/src/playsim/actor.h @@ -695,12 +695,17 @@ struct ModelOverride TArray surfaceSkinIDs; }; +enum ModelDataFlags +{ + MODELDATA_HADMODEL = 1 << 0, +}; + class DActorModelData : public DObject { DECLARE_CLASS(DActorModelData, DObject); public: FName modelDef; - bool hasModel; + int flags; TArray models; TArray skinIDs; TArray animationIDs; diff --git a/src/playsim/p_actionfunctions.cpp b/src/playsim/p_actionfunctions.cpp index 1b89dcc6c..3da0e5aab 100644 --- a/src/playsim/p_actionfunctions.cpp +++ b/src/playsim/p_actionfunctions.cpp @@ -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(); + + 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(); - - 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; } diff --git a/src/playsim/p_mobj.cpp b/src/playsim/p_mobj.cpp index 8420d4826..986afc44b 100644 --- a/src/playsim/p_mobj.cpp +++ b/src/playsim/p_mobj.cpp @@ -1345,7 +1345,7 @@ void DActorModelData::Serialize(FSerializer& arc) //("surfaceSkinIDs", surfaceSkinIDs) ("animationIDs", animationIDs) ("modelFrameGenerators", modelFrameGenerators) - ("hasModel", hasModel); + ("flags", flags); } void DActorModelData::OnDestroy() diff --git a/src/r_data/models.cpp b/src/r_data/models.cpp index 750dd4e32..89fa8893f 100644 --- a/src/r_data/models.cpp +++ b/src/r_data/models.cpp @@ -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 Voxels; extern TDeletingArray 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; diff --git a/src/r_data/models.h b/src/r_data/models.h index 6f0e4d816..4a7154446 100644 --- a/src/r_data/models.h +++ b/src/r_data/models.h @@ -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 diff --git a/src/rendering/hwrenderer/hw_precache.cpp b/src/rendering/hwrenderer/hw_precache.cpp index 699faf706..d6837252d 100644 --- a/src/rendering/hwrenderer/hw_precache.cpp +++ b/src/rendering/hwrenderer/hw_precache.cpp @@ -159,7 +159,7 @@ void hw_PrecacheTexture(uint8_t *texhitlist, TMap &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++) diff --git a/src/rendering/hwrenderer/scene/hw_sprites.cpp b/src/rendering/hwrenderer/scene/hw_sprites.cpp index 1e02fe443..fba8f98d8 100644 --- a/src/rendering/hwrenderer/scene/hw_sprites.cpp +++ b/src/rendering/hwrenderer/scene/hw_sprites.cpp @@ -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) { diff --git a/src/rendering/hwrenderer/scene/hw_weapon.cpp b/src/rendering/hwrenderer/scene/hw_weapon.cpp index 2500a5bf2..7c16b3729 100644 --- a/src/rendering/hwrenderer/scene/hw_weapon.cpp +++ b/src/rendering/hwrenderer/scene/hw_weapon.cpp @@ -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;