diff --git a/src/common/models/model.h b/src/common/models/model.h index ec13914989..9a4435d396 100644 --- a/src/common/models/model.h +++ b/src/common/models/model.h @@ -61,7 +61,7 @@ public: virtual bool Load(const char * fn, int lumpnum, const char * buffer, int length) = 0; virtual int FindFrame(const char * name) = 0; - virtual void RenderFrame(FModelRenderer *renderer, FGameTexture * skin, int frame, int frame2, double inter, int translation=0) = 0; + virtual void RenderFrame(FModelRenderer *renderer, FGameTexture * skin, int frame, int frame2, double inter, int translation, const TArray& surfaceskinids) = 0; virtual void BuildVertexBuffer(FModelRenderer *renderer) = 0; virtual void AddSkins(uint8_t *hitlist) = 0; virtual float getAspectFactor(float vscale) { return 1.f; } diff --git a/src/common/models/model_kvx.h b/src/common/models/model_kvx.h index 8d456d52c5..9f5a0e013e 100644 --- a/src/common/models/model_kvx.h +++ b/src/common/models/model_kvx.h @@ -59,7 +59,7 @@ public: bool Load(const char * fn, int lumpnum, const char * buffer, int length) override; void Initialize(); virtual int FindFrame(const char * name) override; - virtual void RenderFrame(FModelRenderer *renderer, FGameTexture * skin, int frame, int frame2, double inter, int translation=0) override; + virtual void RenderFrame(FModelRenderer *renderer, FGameTexture * skin, int frame, int frame2, double inter, int translation, const TArray& surfaceskinids) override; virtual void AddSkins(uint8_t *hitlist) override; FTextureID GetPaletteTexture() const { return mPalette; } void BuildVertexBuffer(FModelRenderer *renderer) override; diff --git a/src/common/models/model_md2.h b/src/common/models/model_md2.h index c04445535a..50f7e19521 100644 --- a/src/common/models/model_md2.h +++ b/src/common/models/model_md2.h @@ -113,7 +113,7 @@ public: virtual bool Load(const char * fn, int lumpnum, const char * buffer, int length); virtual int FindFrame(const char * name); - virtual void RenderFrame(FModelRenderer *renderer, FGameTexture * skin, int frame, int frame2, double inter, int translation=0); + virtual void RenderFrame(FModelRenderer *renderer, FGameTexture * skin, int frame, int frame2, double inter, int translation, const TArray& surfaceskinids); virtual void LoadGeometry(); virtual void AddSkins(uint8_t *hitlist); diff --git a/src/common/models/model_md3.h b/src/common/models/model_md3.h index 3e6630a5af..257c41906d 100644 --- a/src/common/models/model_md3.h +++ b/src/common/models/model_md3.h @@ -67,7 +67,7 @@ public: virtual bool Load(const char * fn, int lumpnum, const char * buffer, int length); virtual int FindFrame(const char * name); - virtual void RenderFrame(FModelRenderer *renderer, FGameTexture * skin, int frame, int frame2, double inter, int translation=0); + virtual void RenderFrame(FModelRenderer *renderer, FGameTexture * skin, int frame, int frame2, double inter, int translation, const TArray& surfaceskinids); void LoadGeometry(); void BuildVertexBuffer(FModelRenderer *renderer); virtual void AddSkins(uint8_t *hitlist); diff --git a/src/common/models/model_obj.h b/src/common/models/model_obj.h index ed190c1cd3..38cc0c27c4 100644 --- a/src/common/models/model_obj.h +++ b/src/common/models/model_obj.h @@ -98,7 +98,7 @@ public: ~FOBJModel(); bool Load(const char* fn, int lumpnum, const char* buffer, int length) override; int FindFrame(const char* name) override; - void RenderFrame(FModelRenderer* renderer, FGameTexture* skin, int frame, int frame2, double inter, int translation=0) override; + void RenderFrame(FModelRenderer* renderer, FGameTexture* skin, int frame, int frame2, double inter, int translation, const TArray& surfaceskinids) override; void BuildVertexBuffer(FModelRenderer* renderer) override; void AddSkins(uint8_t* hitlist) override; }; diff --git a/src/common/models/model_ue1.h b/src/common/models/model_ue1.h index 9674883551..b69e21a1cb 100644 --- a/src/common/models/model_ue1.h +++ b/src/common/models/model_ue1.h @@ -26,7 +26,7 @@ public: bool Load(const char * fn, int lumpnum, const char * buffer, int length) override; int FindFrame(const char * name) override; - void RenderFrame(FModelRenderer *renderer, FGameTexture * skin, int frame, int frame2, double inter, int translation=0) override; + void RenderFrame(FModelRenderer *renderer, FGameTexture * skin, int frame, int frame2, double inter, int translation, const TArray& surfaceskinids) override; void BuildVertexBuffer(FModelRenderer *renderer) override; void AddSkins(uint8_t *hitlist) override; void LoadGeometry(); diff --git a/src/common/models/models_md2.cpp b/src/common/models/models_md2.cpp index 8924392a42..84b64ec627 100644 --- a/src/common/models/models_md2.cpp +++ b/src/common/models/models_md2.cpp @@ -363,7 +363,7 @@ int FDMDModel::FindFrame(const char * name) // //=========================================================================== -void FDMDModel::RenderFrame(FModelRenderer *renderer, FGameTexture * skin, int frameno, int frameno2, double inter, int translation) +void FDMDModel::RenderFrame(FModelRenderer *renderer, FGameTexture * skin, int frameno, int frameno2, double inter, int translation, const TArray&) { if (frameno >= info.numFrames || frameno2 >= info.numFrames) return; diff --git a/src/common/models/models_md3.cpp b/src/common/models/models_md3.cpp index 0ec4d700f0..9b545dae53 100644 --- a/src/common/models/models_md3.cpp +++ b/src/common/models/models_md3.cpp @@ -344,7 +344,7 @@ int FMD3Model::FindFrame(const char * name) // //=========================================================================== -void FMD3Model::RenderFrame(FModelRenderer *renderer, FGameTexture * skin, int frameno, int frameno2, double inter, int translation) +void FMD3Model::RenderFrame(FModelRenderer *renderer, FGameTexture * skin, int frameno, int frameno2, double inter, int translation, const TArray& surfaceskinids) { if ((unsigned)frameno >= Frames.Size() || (unsigned)frameno2 >= Frames.Size()) return; @@ -358,17 +358,14 @@ void FMD3Model::RenderFrame(FModelRenderer *renderer, FGameTexture * skin, int f FGameTexture *surfaceSkin = skin; if (!surfaceSkin) { - if (curSpriteMDLFrame) + int ssIndex = i + curMDLIndex * MD3_MAX_SURFACES; + if (surfaceskinids[ssIndex].isValid()) { - int ssIndex = i + curMDLIndex * MD3_MAX_SURFACES; - if (curSpriteMDLFrame->surfaceskinIDs[ssIndex].isValid()) - { - surfaceSkin = TexMan.GetGameTexture(curSpriteMDLFrame->surfaceskinIDs[ssIndex], true); - } - else if (surf->numSkins > 0 && surf->Skins[0].isValid()) - { - surfaceSkin = TexMan.GetGameTexture(surf->Skins[0], true); - } + surfaceSkin = TexMan.GetGameTexture(surfaceskinids[ssIndex], true); + } + else if (surf->numSkins > 0 && surf->Skins[0].isValid()) + { + surfaceSkin = TexMan.GetGameTexture(surf->Skins[0], true); } if (!surfaceSkin) diff --git a/src/common/models/models_obj.cpp b/src/common/models/models_obj.cpp index 42fc6fd2ad..e91f9622c5 100644 --- a/src/common/models/models_obj.cpp +++ b/src/common/models/models_obj.cpp @@ -628,7 +628,7 @@ int FOBJModel::FindFrame(const char* name) * @param inter The amount to interpolate the two frames. * @param translation The translation for the skin */ -void FOBJModel::RenderFrame(FModelRenderer *renderer, FGameTexture * skin, int frameno, int frameno2, double inter, int translation) +void FOBJModel::RenderFrame(FModelRenderer *renderer, FGameTexture * skin, int frameno, int frameno2, double inter, int translation, const TArray& surfaceskinids) { // Prevent the model from rendering if the frame number is < 0 if (frameno < 0 || frameno2 < 0) return; @@ -638,12 +638,12 @@ void FOBJModel::RenderFrame(FModelRenderer *renderer, FGameTexture * skin, int f OBJSurface *surf = &surfaces[i]; FGameTexture *userSkin = skin; - if (!userSkin && curSpriteMDLFrame) + if (!userSkin) { int ssIndex = i + curMDLIndex * MD3_MAX_SURFACES; - if (i < MD3_MAX_SURFACES && curSpriteMDLFrame->surfaceskinIDs[ssIndex].isValid()) + if (i < MD3_MAX_SURFACES && surfaceskinids[ssIndex].isValid()) { - userSkin = TexMan.GetGameTexture(curSpriteMDLFrame->surfaceskinIDs[ssIndex], true); + userSkin = TexMan.GetGameTexture(surfaceskinids[ssIndex], true); } else if (surf->skin.isValid()) { diff --git a/src/common/models/models_ue1.cpp b/src/common/models/models_ue1.cpp index c7ffe88a97..650d6a7c07 100644 --- a/src/common/models/models_ue1.cpp +++ b/src/common/models/models_ue1.cpp @@ -227,7 +227,7 @@ int FUE1Model::FindFrame( const char *name ) return -1; } -void FUE1Model::RenderFrame( FModelRenderer *renderer, FGameTexture *skin, int frame, int frame2, double inter, int translation ) +void FUE1Model::RenderFrame( FModelRenderer *renderer, FGameTexture *skin, int frame, int frame2, double inter, int translation, const TArray& surfaceskinids) { // the moment of magic if ( (frame >= numFrames) || (frame2 >= numFrames) ) return; @@ -247,8 +247,8 @@ void FUE1Model::RenderFrame( FModelRenderer *renderer, FGameTexture *skin, int f if ( !sskin ) { int ssIndex = groups[i].texNum + curMDLIndex * MD3_MAX_SURFACES; - if (curSpriteMDLFrame && curSpriteMDLFrame->surfaceskinIDs[ssIndex].isValid()) - sskin = TexMan.GetGameTexture(curSpriteMDLFrame->surfaceskinIDs[ssIndex], true); + if (surfaceskinids[ssIndex].isValid()) + sskin = TexMan.GetGameTexture(surfaceskinids[ssIndex], true); if ( !sskin ) { vofs += vsize; diff --git a/src/common/models/models_voxel.cpp b/src/common/models/models_voxel.cpp index 50fc4df090..77450941f6 100644 --- a/src/common/models/models_voxel.cpp +++ b/src/common/models/models_voxel.cpp @@ -400,7 +400,7 @@ float FVoxelModel::getAspectFactor(float stretch) // //=========================================================================== -void FVoxelModel::RenderFrame(FModelRenderer *renderer, FGameTexture * skin, int frame, int frame2, double inter, int translation) +void FVoxelModel::RenderFrame(FModelRenderer *renderer, FGameTexture * skin, int frame, int frame2, double inter, int translation, const TArray&) { renderer->SetMaterial(skin, true, translation); renderer->SetupFrame(this, 0, 0, 0); diff --git a/src/g_game.cpp b/src/g_game.cpp index 1e61d0f6da..73e1e5314f 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -2121,10 +2121,10 @@ void G_DoLoadGame () BackupSaveName = savename; //Push any added models from A_ChangeModel - for (int i = 0; i < savedModelFiles.Size(); i++) + for (auto& smf : savedModelFiles) { - FString modelFilePath = savedModelFiles[i].Left(savedModelFiles[i].LastIndexOf("/")+1); - FString modelFileName = savedModelFiles[i].Right(savedModelFiles[i].Len() - savedModelFiles[i].Left(savedModelFiles[i].LastIndexOf("/") + 1).Len()); + FString modelFilePath = smf.Left(smf.LastIndexOf("/")+1); + FString modelFileName = smf.Right(smf.Len() - smf.Left(smf.LastIndexOf("/") + 1).Len()); FindModel(modelFilePath, modelFileName); } diff --git a/src/r_data/models.cpp b/src/r_data/models.cpp index 0c0a1a29c1..7d85f05c05 100644 --- a/src/r_data/models.cpp +++ b/src/r_data/models.cpp @@ -230,13 +230,11 @@ void RenderHUDModel(FModelRenderer *renderer, DPSprite *psp, float ofsX, float o void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpriteModelFrame *smf, const FState *curState, const int curTics, const PClass *ti, int translation, AActor* actor) { - //[SM] - Create a temporary sprite model frame, which prevents data from being overwritten - FSpriteModelFrame* tempsmf = new FSpriteModelFrame(*smf); // [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. FSpriteModelFrame * smfNext = nullptr; double inter = 0.; - if (gl_interpolate_model_frames && !(tempsmf->flags & MDL_NOINTERPOLATION)) + if (gl_interpolate_model_frames && !(smf->flags & MDL_NOINTERPOLATION)) { FState *nextState = curState->GetNextState(); if (curState != nextState && nextState) @@ -258,7 +256,7 @@ void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpr { // [BB] Workaround for actors that use the same frame twice in a row. // Most of the standard Doom monsters do this in their see state. - if ((tempsmf->flags & MDL_INTERPOLATEDOUBLEDFRAMES)) + if ((smf->flags & MDL_INTERPOLATEDOUBLEDFRAMES)) { const FState *prevState = curState - 1; if ((curState->sprite == prevState->sprite) && (curState->Frame == prevState->Frame)) @@ -278,61 +276,75 @@ void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpr } } + int modelsamount = smf->modelsAmount; //[SM] - if we added any models for the frame to also render, then we also need to update modelsAmount for this smf if (actor->modelData != nullptr) { - if (tempsmf->modelsAmount < actor->modelData->modelIDs.Size()) - { - tempsmf->modelsAmount = actor->modelData->modelIDs.Size(); - while (tempsmf->modelframes.Size() < actor->modelData->modelIDs.Size()) tempsmf->modelframes.Push(-1); - while (smfNext->modelframes.Size() < actor->modelData->modelIDs.Size()) smfNext->modelframes.Push(-1); - } + modelsamount = actor->modelData->modelIDs.Size(); } - for (int i = 0; i < tempsmf->modelsAmount; i++) + TArray surfaceskinids; + + for (int i = 0; i < modelsamount; i++) { + int modelid = -1; + int modelframe = -1; + int modelframenext = -1; + FTextureID skinid; skinid.SetInvalid(); + + surfaceskinids.Clear(); + bool surfaceskinsswapped = false; if (actor->modelData != nullptr) { - if (i < (int)actor->modelData->modelIDs.Size()) - { - if (actor->modelData->modelIDs[i] != -1) - tempsmf->modelIDs[i] = actor->modelData->modelIDs[i]; - } + modelid = actor->modelData->modelIDs[i]; + if (i < (int)actor->modelData->modelFrameGenerators.Size()) { //[SM] - We will use this little snippet to allow a modder to specify a model index to clone. It's also pointless to clone something that clones something else in this case. And causes me headaches. - if (actor->modelData->modelFrameGenerators[i] >= 0 && smf->modelframes[i] != -1) + if (actor->modelData->modelFrameGenerators[i] >= 0 && smf->modelframes.Size() < (unsigned)i && smf->modelframes[i] != -1) { - tempsmf->modelframes[i] = tempsmf->modelframes[actor->modelData->modelFrameGenerators[i]]; - if (smfNext) smfNext->modelframes[i] = smfNext->modelframes[actor->modelData->modelFrameGenerators[i]]; + modelframe = smf->modelframes[actor->modelData->modelFrameGenerators[i]]; + if (smfNext) modelframenext = smfNext->modelframes[actor->modelData->modelFrameGenerators[i]]; } } if (i < (int)actor->modelData->skinIDs.Size()) { if (actor->modelData->skinIDs[i].isValid()) - tempsmf->skinIDs[i] = actor->modelData->skinIDs[i]; + skinid = actor->modelData->skinIDs[i]; } for (int surface = i * MD3_MAX_SURFACES; surface < (i + 1) * MD3_MAX_SURFACES; surface++) { if (surface < (int)actor->modelData->surfaceSkinIDs.Size()) { if (actor->modelData->surfaceSkinIDs[surface].isValid()) - tempsmf->surfaceskinIDs[surface] = actor->modelData->surfaceSkinIDs[surface]; + { + // only make a copy of the surfaceskinIDs array if really needed + if (surfaceskinids.Size() == 0) surfaceskinids = smf->surfaceskinIDs; + surfaceskinids[surface] = actor->modelData->surfaceSkinIDs[surface]; + } } } } - if (tempsmf->modelIDs[i] >= 0) + if (i < smf->modelsAmount) { - FModel * mdl = Models[tempsmf->modelIDs[i]]; - auto tex = tempsmf->skinIDs[i].isValid() ? TexMan.GetGameTexture(tempsmf->skinIDs[i], true) : nullptr; + if (modelid == -1) modelid = smf->modelIDs[i]; + if (modelframe == -1) modelframe = smf->modelframes[i]; + if (modelframenext == -1 && smfNext) modelframenext = smfNext->modelframes[i]; + if (!skinid.isValid()) skinid = smf->skinIDs[i]; + } + + if (modelid >= 0) + { + FModel * mdl = Models[modelid]; + auto tex = skinid.isValid() ? TexMan.GetGameTexture(skinid, true) : nullptr; mdl->BuildVertexBuffer(renderer); - mdl->PushSpriteMDLFrame(tempsmf, i); + mdl->PushSpriteMDLFrame(smf, i); - if (smfNext && tempsmf->modelframes[i] != smfNext->modelframes[i]) - mdl->RenderFrame(renderer, tex, tempsmf->modelframes[i], smfNext->modelframes[i], inter, translation); + if (smfNext && modelframe != modelframenext) + mdl->RenderFrame(renderer, tex, modelframe, modelframenext, inter, translation, surfaceskinids.Size() > 0? surfaceskinids : smf->surfaceskinIDs); else - mdl->RenderFrame(renderer, tex, tempsmf->modelframes[i], tempsmf->modelframes[i], 0.f, translation); + mdl->RenderFrame(renderer, tex, modelframe, modelframe, 0.f, translation, surfaceskinids.Size() > 0 ? surfaceskinids : smf->surfaceskinIDs); } } }