Rewrite changed model rendering code, and change how model skins are handled

This commit is contained in:
Ricardo Luís Vaz Silva 2023-05-27 18:40:04 -03:00 committed by Rachael Alexanderson
parent b55ffdbfd3
commit 61d68eb2d6
5 changed files with 148 additions and 96 deletions

View file

@ -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, FSoundID &sid, FSoundID *def);
FSerializer &Serialize(FSerializer &arc, const char *key, FString &sid, FString *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, NumericValue &sid, NumericValue *def);
FSerializer &Serialize(FSerializer &arc, const char *key, struct ModelOverride &sid, struct ModelOverride *def);
template <typename T/*, typename = std::enable_if_t<std::is_base_of_v<DObject, T>>*/> template <typename T/*, typename = std::enable_if_t<std::is_base_of_v<DObject, T>>*/>
FSerializer &Serialize(FSerializer &arc, const char *key, T *&value, T **) 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; return arc;
} }
template<class T, class TT> template<class T, class TT>
FSerializer &Serialize(FSerializer &arc, const char *key, TArray<T, TT> &value, TArray<T, TT> *def) FSerializer &Serialize(FSerializer &arc, const char *key, TArray<T, TT> &value, TArray<T, TT> *def)
{ {

View file

@ -677,17 +677,22 @@ enum EViewPosFlags // [MC] Flags for SetViewPos.
VPSF_ABSOLUTEPOS = 1 << 2, // Use absolute position. VPSF_ABSOLUTEPOS = 1 << 2, // Use absolute position.
}; };
struct ModelOverride
{
int modelID;
TArray<FTextureID> surfaceSkinIDs;
};
class DActorModelData : public DObject class DActorModelData : public DObject
{ {
DECLARE_CLASS(DActorModelData, DObject); DECLARE_CLASS(DActorModelData, DObject);
public: public:
FName modelDef; FName modelDef;
bool hasModel; bool hasModel;
TArray<int> modelIDs; TArray<ModelOverride> models;
TArray<FTextureID> skinIDs; TArray<FTextureID> skinIDs;
TArray<FTextureID> surfaceSkinIDs; TArray<int> animationIDs;
TArray<int> animationIDs; TArray<int> modelFrameGenerators;
TArray<int> modelFrameGenerators;
DActorModelData() = default; DActorModelData() = default;
virtual void Serialize(FSerializer& arc) override; virtual void Serialize(FSerializer& arc) override;

View file

@ -5158,18 +5158,16 @@ void ChangeModelNative(
GC::WriteBarrier(mobj, ptr); 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 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; int queryAnimation = animation != NAME_None ? FindModel(animationpath.GetChars(), animation.GetChars()) : -1;
mobj->modelData->modelDef = modeldef; 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()); 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()); mobj->modelData->animationIDs.AppendFill(-1, animationindex - mobj->modelData->animationIDs.Size());
} }
if(flags & CMDL_USESURFACESKIN) auto skindata = skin != NAME_None ? LoadSkin(skinpath.GetChars(), skin.GetChars()) : FNullTextureID();
{
if(mobj->modelData->surfaceSkinIDs.Size() < skinPosition) if(!(flags & CMDL_USESURFACESKIN) && mobj->modelData->skinIDs.Size() < skinindex)
{
mobj->modelData->surfaceSkinIDs.AppendFill(FNullTextureID(), skinPosition - mobj->modelData->surfaceSkinIDs.Size());
}
}
else if(mobj->modelData->skinIDs.Size() < skinindex)
{ {
mobj->modelData->skinIDs.AppendFill(FNullTextureID(), skinindex - mobj->modelData->skinIDs.Size()); 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<FTextureID> 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 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; mobj->modelData->modelFrameGenerators[modelindex] = generatorindex;
} }
@ -5210,20 +5233,7 @@ void ChangeModelNative(
mobj->modelData->animationIDs[animationindex] = queryAnimation; mobj->modelData->animationIDs[animationindex] = queryAnimation;
} }
auto skindata = skin != NAME_None ? LoadSkin(skinpath.GetChars(), skin.GetChars()) : FNullTextureID(); if (!(flags & CMDL_USESURFACESKIN))
if (flags & CMDL_USESURFACESKIN)
{
if(mobj->modelData->surfaceSkinIDs.Size() == skinPosition)
{
mobj->modelData->surfaceSkinIDs.Push(skindata);
}
else
{
mobj->modelData->surfaceSkinIDs[skinPosition] = skindata;
}
}
else
{ {
if(mobj->modelData->skinIDs.Size() == skinindex) if(mobj->modelData->skinIDs.Size() == skinindex)
{ {
@ -5286,7 +5296,7 @@ void ChangeModelNative(
if(!found) savedModelFiles.Push(fullName); 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->hasmodel = mobj->modelData->hasModel;
mobj->modelData->Destroy(); mobj->modelData->Destroy();

View file

@ -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) void DActorModelData::Serialize(FSerializer& arc)
{ {
Super::Serialize(arc); Super::Serialize(arc);
arc("modelDef", modelDef) arc("modelDef", modelDef)
("modelIDs", modelIDs) ("models", models)
("skinIDs", skinIDs) ("skinIDs", skinIDs)
("surfaceSkinIDs", surfaceSkinIDs) //("surfaceSkinIDs", surfaceSkinIDs)
("animationIDs", animationIDs) ("animationIDs", animationIDs)
("modelFrameGenerators", modelFrameGenerators) ("modelFrameGenerators", modelFrameGenerators)
("hasModel", hasModel); ("hasModel", hasModel);
@ -1338,10 +1347,10 @@ void DActorModelData::Serialize(FSerializer& arc)
void DActorModelData::OnDestroy() void DActorModelData::OnDestroy()
{ {
modelIDs.Reset(); models.Reset();
modelFrameGenerators.Reset(); modelFrameGenerators.Reset();
skinIDs.Reset(); skinIDs.Reset();
surfaceSkinIDs.Reset(); //surfaceSkinIDs.Reset();
animationIDs.Reset(); animationIDs.Reset();
} }

View file

@ -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 //[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 != nullptr)
{ {
if (actor->modelData->modelIDs.Size() > (unsigned)modelsamount) if (actor->modelData->models.Size() > modelsamount)
modelsamount = actor->modelData->modelIDs.Size(); modelsamount = actor->modelData->models.Size();
} }
TArray<FTextureID> surfaceskinids; TArray<FTextureID> surfaceskinids;
@ -313,81 +313,108 @@ void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpr
int boneStartingPosition = 0; int boneStartingPosition = 0;
bool evaluatedSingle = false; bool evaluatedSingle = false;
for (int i = 0; i < modelsamount; i++) for (unsigned i = 0; i < modelsamount; i++)
{ {
int modelid = -1; int modelid = -1;
int animationid = -1; int animationid = -1;
int modelframe = -1; int modelframe = -1;
int modelframenext = -1; int modelframenext = -1;
FTextureID skinid; skinid.SetInvalid(); FTextureID skinid; skinid.SetNull();
surfaceskinids.Clear(); surfaceskinids.Clear();
if (actor->modelData != nullptr) if (actor->modelData != nullptr)
{ {
if (i < (int)actor->modelData->modelIDs.Size()) //modelID
modelid = actor->modelData->modelIDs[i]; 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]; 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()) animationid = smf->animationIDs[i];
skinid = actor->modelData->skinIDs[i];
} }
unsigned sz1 = smf->surfaceskinIDs.Size(); //modelFrame
unsigned sz2 = actor->modelData->surfaceSkinIDs.Size(); if (actor->modelData->modelFrameGenerators.Size() > i
unsigned end = (i + 1) * MD3_MAX_SURFACES; && 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) if (smfNext)
{
long last_ok = -1;
surfaceskinids.Resize(actor->modelData->surfaceSkinIDs.Size());
for (unsigned surface = i * MD3_MAX_SURFACES; surface < end; surface++)
{ {
if (surface >= sz2) break; if(smfNext->modelframes[actor->modelData->modelFrameGenerators[i]] >= 0)
if (actor->modelData->surfaceSkinIDs[surface].isValid())
{ {
surfaceskinids[surface] = actor->modelData->surfaceSkinIDs[surface]; modelframenext = smfNext->modelframes[actor->modelData->modelFrameGenerators[i]];
last_ok = surface;
}
else if(surface < sz1)
{
surfaceskinids[surface] = smf->surfaceskinIDs[surface];
} }
else 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 if (sz2 > surface && (actor->modelData->models[i].surfaceSkinIDs[surface].isValid()))
} {
else continue;
{ }
surfaceskinids.Clear(); 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]; modelid = smf->modelIDs[i];
if (animationid == -1) animationid = smf->animationIDs[i]; animationid = smf->animationIDs[i];
if (modelframe == -1) modelframe = smf->modelframes[i]; modelframe = smf->modelframes[i];
if (modelframenext == -1 && smfNext) modelframenext = smfNext->modelframes[i]; if (smfNext) modelframenext = smfNext->modelframes[i];
if (!skinid.isValid()) skinid = smf->skinIDs[i]; skinid = smf->skinIDs[i];
} }
if (modelid >= 0) if (modelid >= 0)
@ -396,8 +423,9 @@ void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpr
auto tex = skinid.isValid() ? TexMan.GetGameTexture(skinid, true) : nullptr; auto tex = skinid.isValid() ? TexMan.GetGameTexture(skinid, true) : nullptr;
mdl->BuildVertexBuffer(renderer); mdl->BuildVertexBuffer(renderer);
auto& ssids = surfaceskinids.Size() > 0 ? surfaceskinids : smf->surfaceskinIDs; auto ssidp = surfaceskinids.Size() > 0
auto ssidp = (unsigned)(i * MD3_MAX_SURFACES) < ssids.Size() ? &ssids[i * MD3_MAX_SURFACES] : nullptr; ? surfaceskinids.Data()
: (((i * MD3_MAX_SURFACES) < smf->surfaceskinIDs.Size()) ? &smf->surfaceskinIDs[i * MD3_MAX_SURFACES] : nullptr);
bool nextFrame = smfNext && modelframe != modelframenext; bool nextFrame = smfNext && modelframe != modelframenext;