mirror of
https://github.com/ZDoom/gzdoom.git
synced 2025-02-17 01:31:25 +00:00
Surfaceskin modification
- Made it so when rendering a model, it clones an smf to use so that data isn't overwritten - Reimplemented the skin index property. This changes the behavior of this index if CMDL_USESURFACESKIN is activated
This commit is contained in:
parent
ec3d81a34f
commit
69ee1eb0a2
7 changed files with 62 additions and 27 deletions
|
@ -70,7 +70,7 @@ public:
|
|||
IModelVertexBuffer *GetVertexBuffer(int type) const { return mVBuf[type]; }
|
||||
void DestroyVertexBuffer();
|
||||
|
||||
const FSpriteModelFrame *curSpriteMDLFrame;
|
||||
const FSpriteModelFrame* curSpriteMDLFrame;
|
||||
int curMDLIndex;
|
||||
void PushSpriteMDLFrame(const FSpriteModelFrame *smf, int index) { curSpriteMDLFrame = smf; curMDLIndex = index; };
|
||||
|
||||
|
|
|
@ -681,6 +681,7 @@ public:
|
|||
bool hasModel;
|
||||
TArray<int> modelIDs;
|
||||
TArray<FTextureID> skinIDs;
|
||||
TArray<FTextureID> surfaceSkinIDs;
|
||||
|
||||
DActorModelData() = default;
|
||||
virtual void Serialize(FSerializer& arc) override;
|
||||
|
|
|
@ -5032,15 +5032,17 @@ enum ChangeModelFlags
|
|||
{
|
||||
CMDL_WEAPONTOPLAYER = 1,
|
||||
CMDL_HIDEMODEL = 1 << 1,
|
||||
CMDL_USESURFACESKIN = 1 << 2,
|
||||
};
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_ChangeModel)
|
||||
{
|
||||
PARAM_ACTION_PROLOGUE(AActor);
|
||||
PARAM_NAME(modeldef)
|
||||
PARAM_INT(index)
|
||||
PARAM_INT(modelindex)
|
||||
PARAM_STRING_VAL(modelpath)
|
||||
PARAM_NAME(model)
|
||||
PARAM_INT(skinindex)
|
||||
PARAM_STRING_VAL(skinpath)
|
||||
PARAM_NAME(skin)
|
||||
PARAM_INT(flags)
|
||||
|
@ -5059,6 +5061,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_ChangeModel)
|
|||
ptr->hasModel = mobj->hasmodel ? 1 : 0;
|
||||
ptr->modelIDs = *new TArray<int>();
|
||||
ptr->skinIDs = *new TArray<FTextureID>();
|
||||
ptr->surfaceSkinIDs = *new TArray<FTextureID>();
|
||||
ptr->modelDef = NAME_None;
|
||||
mobj->modelData = ptr;
|
||||
mobj->hasmodel = 1;
|
||||
|
@ -5067,19 +5070,38 @@ DEFINE_ACTION_FUNCTION(AActor, A_ChangeModel)
|
|||
|
||||
int maxModels = mobj->modelData->modelIDs.Size();
|
||||
int maxSkins = mobj->modelData->skinIDs.Size();
|
||||
int maxSurfaceSkins = mobj->modelData->surfaceSkinIDs.Size();
|
||||
|
||||
int skinPosition = skinindex + modelindex * MD3_MAX_SURFACES;
|
||||
|
||||
int queryModel = !(flags & CMDL_HIDEMODEL) ? model != NAME_None ? FindModel(modelpath.GetChars(), model.GetChars()) : -1 : -2;
|
||||
|
||||
//[SM] - Let's clear out any potential entries at the specified indices
|
||||
mobj->modelData->modelDef = modeldef;
|
||||
if(maxModels > index) mobj->modelData->modelIDs.Pop(mobj->modelData->modelIDs[index]);
|
||||
if(maxSkins > index) mobj->modelData->skinIDs.Pop(mobj->modelData->skinIDs[index]);
|
||||
if(maxModels > modelindex) mobj->modelData->modelIDs.Pop(mobj->modelData->modelIDs[modelindex]);
|
||||
if (flags & CMDL_USESURFACESKIN)
|
||||
{
|
||||
if (maxSurfaceSkins > skinPosition)
|
||||
mobj->modelData->surfaceSkinIDs.Delete(skinPosition); //[SM] - It seems the only way to make sure this does what it's told is from Delete, not Pop
|
||||
}
|
||||
else
|
||||
{
|
||||
if (maxSkins > skinindex)
|
||||
mobj->modelData->skinIDs.Pop(mobj->modelData->skinIDs[skinindex]);
|
||||
}
|
||||
|
||||
//[SM] - We need to fill up any holes this new index will make so that it doesn't leave behind any undefined behavior
|
||||
while ((int)mobj->modelData->modelIDs.Size() < index) mobj->modelData->modelIDs.Push(-1);
|
||||
while ((int)mobj->modelData->skinIDs.Size() < index) mobj->modelData->skinIDs.Push(FNullTextureID());
|
||||
|
||||
mobj->modelData->modelIDs.Insert(index, queryModel);
|
||||
mobj->modelData->skinIDs.Insert(index, skin != NAME_None ? LoadSkin(skinpath.GetChars(), skin.GetChars()) : FNullTextureID());
|
||||
while ((int)mobj->modelData->modelIDs.Size() < modelindex) mobj->modelData->modelIDs.Push(-1);
|
||||
if (flags & CMDL_USESURFACESKIN)
|
||||
while ((int)mobj->modelData->surfaceSkinIDs.Size() < skinPosition) mobj->modelData->surfaceSkinIDs.Push(FNullTextureID());
|
||||
else
|
||||
while ((int)mobj->modelData->skinIDs.Size() < skinindex) mobj->modelData->skinIDs.Push(FNullTextureID());
|
||||
|
||||
mobj->modelData->modelIDs.Insert(modelindex, queryModel);
|
||||
if (flags & CMDL_USESURFACESKIN)
|
||||
mobj->modelData->surfaceSkinIDs.Insert(skinPosition, skin != NAME_None ? LoadSkin(skinpath.GetChars(), skin.GetChars()) : FNullTextureID());
|
||||
else
|
||||
mobj->modelData->skinIDs.Insert(skinindex, skin != NAME_None ? LoadSkin(skinpath.GetChars(), skin.GetChars()) : FNullTextureID());
|
||||
|
||||
//[SM] - We need to serialize file paths and model names so that they are pushed on loading save files. Likewise, let's not include models that were already parsed when initialized.
|
||||
if (queryModel >= 0)
|
||||
|
@ -5098,12 +5120,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_ChangeModel)
|
|||
mobj->modelData->modelIDs.Pop(mobj->modelData->modelIDs.Last());
|
||||
while (mobj->modelData->skinIDs.Size() > 0 && mobj->modelData->skinIDs.Last() == FNullTextureID())
|
||||
mobj->modelData->skinIDs.Pop(mobj->modelData->skinIDs.Last());
|
||||
while (mobj->modelData->surfaceSkinIDs.Size() > 0 && mobj->modelData->surfaceSkinIDs.Last() == FNullTextureID())
|
||||
mobj->modelData->surfaceSkinIDs.Pop(mobj->modelData->surfaceSkinIDs.Last());
|
||||
|
||||
if (mobj->modelData->modelIDs.Size() == 0 && mobj->modelData->skinIDs.Size() == 0 && modeldef == NAME_None)
|
||||
if (mobj->modelData->modelIDs.Size() == 0 && mobj->modelData->skinIDs.Size() == 0 && mobj->modelData->surfaceSkinIDs.Size() == 0 && modeldef == NAME_None)
|
||||
{
|
||||
mobj->hasmodel = mobj->modelData->hasModel;
|
||||
mobj->modelData->modelIDs.Reset();
|
||||
mobj->modelData->skinIDs.Reset();
|
||||
mobj->modelData->surfaceSkinIDs.Reset();
|
||||
mobj->modelData->Destroy();
|
||||
}
|
||||
|
||||
|
|
|
@ -1368,6 +1368,7 @@ void DActorModelData::Serialize(FSerializer& arc)
|
|||
arc("modelDef", modelDef)
|
||||
("modelIDs", modelIDs)
|
||||
("skinIDs", skinIDs)
|
||||
("surfaceSkinIDs", surfaceSkinIDs)
|
||||
("hasModel", hasModel);
|
||||
}
|
||||
|
||||
|
|
|
@ -55,7 +55,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, int translation, AActor* actor);
|
||||
void RenderFrameModels(FModelRenderer* renderer, FLevelLocals* Level, const FSpriteModelFrame *smf, const FState* curState, const int curTics, const PClass* ti, int translation, AActor* actor);
|
||||
|
||||
|
||||
void RenderModel(FModelRenderer *renderer, float x, float y, float z, FSpriteModelFrame *smf, AActor *actor, double ticFrac)
|
||||
|
@ -230,11 +230,13 @@ 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 && !(smf->flags & MDL_NOINTERPOLATION))
|
||||
if (gl_interpolate_model_frames && !(tempsmf->flags & MDL_NOINTERPOLATION))
|
||||
{
|
||||
FState *nextState = curState->GetNextState();
|
||||
if (curState != nextState && nextState)
|
||||
|
@ -256,7 +258,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 ((smf->flags & MDL_INTERPOLATEDOUBLEDFRAMES))
|
||||
if ((tempsmf->flags & MDL_INTERPOLATEDOUBLEDFRAMES))
|
||||
{
|
||||
const FState *prevState = curState - 1;
|
||||
if ((curState->sprite == prevState->sprite) && (curState->Frame == prevState->Frame))
|
||||
|
@ -276,36 +278,41 @@ void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpr
|
|||
}
|
||||
}
|
||||
|
||||
//[SM] - these temporary arrays prevent actual smf data from being overwritten, which was the source of my problems
|
||||
TArray<int> tempModelIDs = smf->modelIDs;
|
||||
TArray<FTextureID> tempSkinIDs = smf->skinIDs;
|
||||
for (int i = 0; i < smf->modelsAmount; i++)
|
||||
for (int i = 0; i < tempsmf->modelsAmount; i++)
|
||||
{
|
||||
if (actor->modelData != nullptr)
|
||||
{
|
||||
if (i < (int)actor->modelData->modelIDs.Size())
|
||||
{
|
||||
if(actor->modelData->modelIDs[i] != -1)
|
||||
tempModelIDs[i] = actor->modelData->modelIDs[i];
|
||||
tempsmf->modelIDs[i] = actor->modelData->modelIDs[i];
|
||||
}
|
||||
if (i < (int)actor->modelData->skinIDs.Size())
|
||||
{
|
||||
if (actor->modelData->skinIDs[i].isValid())
|
||||
tempSkinIDs[i] = actor->modelData->skinIDs[i];
|
||||
tempsmf->skinIDs[i] = 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];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tempModelIDs[i] >= 0)
|
||||
if (tempsmf->modelIDs[i] >= 0)
|
||||
{
|
||||
FModel * mdl = Models[tempModelIDs[i]];
|
||||
auto tex = tempSkinIDs[i].isValid() ? TexMan.GetGameTexture(tempSkinIDs[i], true) : nullptr;
|
||||
FModel * mdl = Models[tempsmf->modelIDs[i]];
|
||||
auto tex = tempsmf->skinIDs[i].isValid() ? TexMan.GetGameTexture(tempsmf->skinIDs[i], true) : nullptr;
|
||||
mdl->BuildVertexBuffer(renderer);
|
||||
|
||||
mdl->PushSpriteMDLFrame(smf, i);
|
||||
mdl->PushSpriteMDLFrame(tempsmf, i);
|
||||
|
||||
if (smfNext && smf->modelframes[i] != smfNext->modelframes[i])
|
||||
mdl->RenderFrame(renderer, tex, smf->modelframes[i], smfNext->modelframes[i], inter, translation);
|
||||
if (smfNext && tempsmf->modelframes[i] != smfNext->modelframes[i])
|
||||
mdl->RenderFrame(renderer, tex, tempsmf->modelframes[i], smfNext->modelframes[i], inter, translation);
|
||||
else
|
||||
mdl->RenderFrame(renderer, tex, smf->modelframes[i], smf->modelframes[i], 0.f, translation);
|
||||
mdl->RenderFrame(renderer, tex, tempsmf->modelframes[i], tempsmf->modelframes[i], 0.f, translation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1132,7 +1132,7 @@ class Actor : Thinker native
|
|||
native void A_SetBlend(color color1, double alpha, int tics, color color2 = 0, double alpha2 = 0.);
|
||||
deprecated("2.3", "Use 'b<FlagName> = [true/false]' instead") native void A_ChangeFlag(string flagname, bool value);
|
||||
native void A_ChangeCountFlags(int kill = FLAG_NO_CHANGE, int item = FLAG_NO_CHANGE, int secret = FLAG_NO_CHANGE);
|
||||
action native void A_ChangeModel(name modeldef, int index = 0, string modelpath = "", name model = "", string skinpath = "", name skin = "", int flags = 0);
|
||||
action native void A_ChangeModel(name modeldef, int modelindex = 0, string modelpath = "", name model = "", int skinindex = 0, string skinpath = "", name skin = "", int flags = 0);
|
||||
|
||||
void A_SetFriendly (bool set)
|
||||
{
|
||||
|
|
|
@ -370,6 +370,7 @@ enum ChangeModelFlags
|
|||
{
|
||||
CMDL_WEAPONTOPLAYER = 1,
|
||||
CMDL_HIDEMODEL = 1 << 1,
|
||||
CMDL_USESURFACESKIN = 1 << 2,
|
||||
};
|
||||
|
||||
// Activation flags
|
||||
|
|
Loading…
Reference in a new issue