diff --git a/src/common/engine/serializer.h b/src/common/engine/serializer.h index 63bfb3529..93c7ef5a1 100644 --- a/src/common/engine/serializer.h +++ b/src/common/engine/serializer.h @@ -234,6 +234,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FName &value, FName *d FSerializer &Serialize(FSerializer &arc, const char *key, FSoundID &sid, FSoundID *def); FSerializer &Serialize(FSerializer &arc, const char *key, FString &sid, FString *def); FSerializer &Serialize(FSerializer &arc, const char *key, NumericValue &sid, NumericValue *def); +FSerializer &Serialize(FSerializer &arc, const char *key, struct ModelOverride &sid, struct ModelOverride *def); template >*/> FSerializer &Serialize(FSerializer &arc, const char *key, T *&value, T **) @@ -244,7 +245,6 @@ FSerializer &Serialize(FSerializer &arc, const char *key, T *&value, T **) return arc; } - template FSerializer &Serialize(FSerializer &arc, const char *key, TArray &value, TArray *def) { diff --git a/src/playsim/actor.h b/src/playsim/actor.h index 2521cd2a2..baf78fe2e 100644 --- a/src/playsim/actor.h +++ b/src/playsim/actor.h @@ -677,17 +677,22 @@ enum EViewPosFlags // [MC] Flags for SetViewPos. VPSF_ABSOLUTEPOS = 1 << 2, // Use absolute position. }; +struct ModelOverride +{ + int modelID; + TArray surfaceSkinIDs; +}; + class DActorModelData : public DObject { DECLARE_CLASS(DActorModelData, DObject); public: - FName modelDef; - bool hasModel; - TArray modelIDs; - TArray skinIDs; - TArray surfaceSkinIDs; - TArray animationIDs; - TArray modelFrameGenerators; + FName modelDef; + bool hasModel; + TArray models; + TArray skinIDs; + TArray animationIDs; + TArray modelFrameGenerators; DActorModelData() = default; virtual void Serialize(FSerializer& arc) override; diff --git a/src/playsim/p_actionfunctions.cpp b/src/playsim/p_actionfunctions.cpp index 49f33342e..6eec02193 100644 --- a/src/playsim/p_actionfunctions.cpp +++ b/src/playsim/p_actionfunctions.cpp @@ -5158,18 +5158,16 @@ void ChangeModelNative( GC::WriteBarrier(mobj, ptr); }; - unsigned skinPosition = skinindex + modelindex * MD3_MAX_SURFACES; - 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; mobj->modelData->modelDef = modeldef; - assert(mobj->modelData->modelIDs.Size() == mobj->modelData->modelFrameGenerators.Size()); + assert(mobj->modelData->models.Size() == mobj->modelData->modelFrameGenerators.Size()); - if(mobj->modelData->modelIDs.Size() < modelindex) + if(mobj->modelData->models.Size() < modelindex) { - mobj->modelData->modelIDs.AppendFill(-1, modelindex - mobj->modelData->modelIDs.Size()); + mobj->modelData->models.AppendFill({-1, {}}, modelindex - mobj->modelData->models.Size()); mobj->modelData->modelFrameGenerators.AppendFill(-1, modelindex - mobj->modelData->modelFrameGenerators.Size()); } @@ -5178,26 +5176,51 @@ void ChangeModelNative( mobj->modelData->animationIDs.AppendFill(-1, animationindex - mobj->modelData->animationIDs.Size()); } - if(flags & CMDL_USESURFACESKIN) - { - if(mobj->modelData->surfaceSkinIDs.Size() < skinPosition) - { - mobj->modelData->surfaceSkinIDs.AppendFill(FNullTextureID(), skinPosition - mobj->modelData->surfaceSkinIDs.Size()); - } - } - else if(mobj->modelData->skinIDs.Size() < skinindex) + auto skindata = skin != NAME_None ? LoadSkin(skinpath.GetChars(), skin.GetChars()) : FNullTextureID(); + + if(!(flags & CMDL_USESURFACESKIN) && mobj->modelData->skinIDs.Size() < skinindex) { mobj->modelData->skinIDs.AppendFill(FNullTextureID(), skinindex - mobj->modelData->skinIDs.Size()); } - if(mobj->modelData->modelIDs.Size() == modelindex) + if(mobj->modelData->models.Size() == modelindex) { - mobj->modelData->modelIDs.Push(queryModel); - mobj->modelData->modelFrameGenerators.Push(generatorindex); + + if(flags & CMDL_USESURFACESKIN && skinindex >= 0) + { + TArray surfaceSkins; + if(skinindex > 0) + { + surfaceSkins.AppendFill(FNullTextureID(), skinindex - 1); + } + surfaceSkins.Push(skindata); + mobj->modelData->models.Push({queryModel, std::move(surfaceSkins)}); + mobj->modelData->modelFrameGenerators.Push(generatorindex); + } + else + { + mobj->modelData->models.Push({queryModel, {}}); + mobj->modelData->modelFrameGenerators.Push(generatorindex); + } } else { - mobj->modelData->modelIDs[modelindex] = queryModel; + if(flags & CMDL_USESURFACESKIN && skinindex >= 0) + { + if(skinindex > mobj->modelData->models[modelindex].surfaceSkinIDs.Size()) + { + mobj->modelData->models[modelindex].surfaceSkinIDs.AppendFill(FNullTextureID(), skinindex - mobj->modelData->models[modelindex].surfaceSkinIDs.Size()); + } + if(skinindex == mobj->modelData->models[modelindex].surfaceSkinIDs.Size()) + { + mobj->modelData->models[modelindex].surfaceSkinIDs.Push(skindata); + } + else + { + mobj->modelData->models[modelindex].surfaceSkinIDs[skinindex] = skindata; + } + } + mobj->modelData->models[modelindex].modelID = queryModel; mobj->modelData->modelFrameGenerators[modelindex] = generatorindex; } @@ -5210,20 +5233,7 @@ void ChangeModelNative( mobj->modelData->animationIDs[animationindex] = queryAnimation; } - auto skindata = skin != NAME_None ? LoadSkin(skinpath.GetChars(), skin.GetChars()) : FNullTextureID(); - - if (flags & CMDL_USESURFACESKIN) - { - if(mobj->modelData->surfaceSkinIDs.Size() == skinPosition) - { - mobj->modelData->surfaceSkinIDs.Push(skindata); - } - else - { - mobj->modelData->surfaceSkinIDs[skinPosition] = skindata; - } - } - else + if (!(flags & CMDL_USESURFACESKIN)) { if(mobj->modelData->skinIDs.Size() == skinindex) { @@ -5286,7 +5296,7 @@ void ChangeModelNative( if(!found) savedModelFiles.Push(fullName); } - if (mobj->modelData->modelIDs.Size() == 0 && mobj->modelData->modelFrameGenerators.Size() == 0 && mobj->modelData->skinIDs.Size() == 0 && mobj->modelData->surfaceSkinIDs.Size() == 0 && mobj->modelData->animationIDs.Size() == 0 && modeldef == NAME_None) + 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(); diff --git a/src/playsim/p_mobj.cpp b/src/playsim/p_mobj.cpp index 987436424..543c80f1d 100644 --- a/src/playsim/p_mobj.cpp +++ b/src/playsim/p_mobj.cpp @@ -1324,13 +1324,22 @@ bool AActor::Massacre () // //---------------------------------------------------------------------------- +FSerializer &Serialize(FSerializer &arc, const char *key, ModelOverride &sid, ModelOverride *def) +{ + arc.BeginObject(key); + arc("modelID", sid.modelID); + arc("surfaceSkinIDs", sid.surfaceSkinIDs); + arc.EndObject(); + return arc; +} + void DActorModelData::Serialize(FSerializer& arc) { Super::Serialize(arc); arc("modelDef", modelDef) - ("modelIDs", modelIDs) + ("models", models) ("skinIDs", skinIDs) - ("surfaceSkinIDs", surfaceSkinIDs) + //("surfaceSkinIDs", surfaceSkinIDs) ("animationIDs", animationIDs) ("modelFrameGenerators", modelFrameGenerators) ("hasModel", hasModel); @@ -1338,10 +1347,10 @@ void DActorModelData::Serialize(FSerializer& arc) void DActorModelData::OnDestroy() { - modelIDs.Reset(); + models.Reset(); modelFrameGenerators.Reset(); skinIDs.Reset(); - surfaceSkinIDs.Reset(); + //surfaceSkinIDs.Reset(); animationIDs.Reset(); } diff --git a/src/r_data/models.cpp b/src/r_data/models.cpp index 03d1def7e..0c91a248b 100644 --- a/src/r_data/models.cpp +++ b/src/r_data/models.cpp @@ -299,12 +299,12 @@ void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpr } } - int modelsamount = smf->modelsAmount; + unsigned 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 (actor->modelData->modelIDs.Size() > (unsigned)modelsamount) - modelsamount = actor->modelData->modelIDs.Size(); + if (actor->modelData->models.Size() > modelsamount) + modelsamount = actor->modelData->models.Size(); } TArray surfaceskinids; @@ -313,81 +313,108 @@ void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpr int boneStartingPosition = 0; bool evaluatedSingle = false; - for (int i = 0; i < modelsamount; i++) + for (unsigned i = 0; i < modelsamount; i++) { int modelid = -1; int animationid = -1; int modelframe = -1; int modelframenext = -1; - FTextureID skinid; skinid.SetInvalid(); + FTextureID skinid; skinid.SetNull(); surfaceskinids.Clear(); + if (actor->modelData != nullptr) { - if (i < (int)actor->modelData->modelIDs.Size()) - modelid = actor->modelData->modelIDs[i]; + //modelID + if (actor->modelData->models.Size() > i && actor->modelData->models[i].modelID >= 0) + { + modelid = actor->modelData->models[i].modelID; + } + else if(smf->modelsAmount > i) + { + modelid = smf->modelIDs[i]; + } - if (i < (int)actor->modelData->animationIDs.Size()) + //animationID + if (actor->modelData->animationIDs.Size() > i && actor->modelData->animationIDs[i] >= 0) + { animationid = actor->modelData->animationIDs[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 && actor->modelData->modelFrameGenerators[i] <= modelsamount && smf->modelframes[actor->modelData->modelFrameGenerators[i]] != -1) - { - modelframe = smf->modelframes[actor->modelData->modelFrameGenerators[i]]; - if (smfNext) modelframenext = smfNext->modelframes[actor->modelData->modelFrameGenerators[i]]; - } } - if (i < (int)actor->modelData->skinIDs.Size()) + else if(smf->modelsAmount > i) { - if (actor->modelData->skinIDs[i].isValid()) - skinid = actor->modelData->skinIDs[i]; + animationid = smf->animationIDs[i]; } - unsigned sz1 = smf->surfaceskinIDs.Size(); - unsigned sz2 = actor->modelData->surfaceSkinIDs.Size(); - unsigned end = (i + 1) * MD3_MAX_SURFACES; + //modelFrame + if (actor->modelData->modelFrameGenerators.Size() > i + && actor->modelData->modelFrameGenerators[i] >= 0 + && actor->modelData->modelFrameGenerators[i] < modelsamount + && smf->modelframes[actor->modelData->modelFrameGenerators[i]] >= 0 + ) { + modelframe = smf->modelframes[actor->modelData->modelFrameGenerators[i]]; - if(actor->modelData->surfaceSkinIDs.Size() > 0) - { - long last_ok = -1; - surfaceskinids.Resize(actor->modelData->surfaceSkinIDs.Size()); - for (unsigned surface = i * MD3_MAX_SURFACES; surface < end; surface++) + if (smfNext) { - if (surface >= sz2) break; - - if (actor->modelData->surfaceSkinIDs[surface].isValid()) + if(smfNext->modelframes[actor->modelData->modelFrameGenerators[i]] >= 0) { - surfaceskinids[surface] = actor->modelData->surfaceSkinIDs[surface]; - last_ok = surface; - } - else if(surface < sz1) - { - surfaceskinids[surface] = smf->surfaceskinIDs[surface]; + modelframenext = smfNext->modelframes[actor->modelData->modelFrameGenerators[i]]; } else { - surfaceskinids[surface].SetInvalid(); + modelframenext = smfNext->modelframes[i]; } } - if(last_ok >= 0) + } + else if(smf->modelsAmount > i) + { + modelframe = smf->modelframes[i]; + if (smfNext) modelframenext = smfNext->modelframes[i]; + } + + //skinID + if (actor->modelData->skinIDs.Size() > i && actor->modelData->skinIDs[i].isValid()) + { + skinid = actor->modelData->skinIDs[i]; + } + else if(smf->modelsAmount > i) + { + skinid = smf->skinIDs[i]; + } + + //surfaceSkinIDs + if(actor->modelData->models.Size() > i && actor->modelData->models[i].surfaceSkinIDs.Size() > 0) + { + unsigned sz1 = smf->surfaceskinIDs.Size(); + unsigned sz2 = actor->modelData->models[i].surfaceSkinIDs.Size(); + unsigned start = i * MD3_MAX_SURFACES; + + surfaceskinids = actor->modelData->models[i].surfaceSkinIDs; + surfaceskinids.Resize(MD3_MAX_SURFACES); + + for (unsigned surface = 0; surface < MD3_MAX_SURFACES; surface++) { - surfaceskinids.Resize(max(last_ok + 1, (long)sz1)); // clear out - } - else - { - surfaceskinids.Clear(); + if (sz2 > surface && (actor->modelData->models[i].surfaceSkinIDs[surface].isValid())) + { + continue; + } + if((surface + start) < sz1) + { + surfaceskinids[surface] = smf->surfaceskinIDs[surface + start]; + } + else + { + surfaceskinids[surface].SetNull(); + } } } } - if (i < smf->modelsAmount) + else { - if (modelid == -1) modelid = smf->modelIDs[i]; - if (animationid == -1) animationid = smf->animationIDs[i]; - if (modelframe == -1) modelframe = smf->modelframes[i]; - if (modelframenext == -1 && smfNext) modelframenext = smfNext->modelframes[i]; - if (!skinid.isValid()) skinid = smf->skinIDs[i]; + modelid = smf->modelIDs[i]; + animationid = smf->animationIDs[i]; + modelframe = smf->modelframes[i]; + if (smfNext) modelframenext = smfNext->modelframes[i]; + skinid = smf->skinIDs[i]; } if (modelid >= 0) @@ -396,8 +423,9 @@ void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpr auto tex = skinid.isValid() ? TexMan.GetGameTexture(skinid, true) : nullptr; mdl->BuildVertexBuffer(renderer); - auto& ssids = surfaceskinids.Size() > 0 ? surfaceskinids : smf->surfaceskinIDs; - auto ssidp = (unsigned)(i * MD3_MAX_SURFACES) < ssids.Size() ? &ssids[i * MD3_MAX_SURFACES] : nullptr; + auto ssidp = surfaceskinids.Size() > 0 + ? surfaceskinids.Data() + : (((i * MD3_MAX_SURFACES) < smf->surfaceskinIDs.Size()) ? &smf->surfaceskinIDs[i * MD3_MAX_SURFACES] : nullptr); bool nextFrame = smfNext && modelframe != modelframenext;