diff --git a/src/common/models/model.h b/src/common/models/model.h index 5fdec020c5..829e81776c 100644 --- a/src/common/models/model.h +++ b/src/common/models/model.h @@ -15,15 +15,16 @@ void FlushModels(); extern TDeletingArray Models; extern TArray SpriteModelFrames; -#define MAX_MODELS_PER_FRAME 4 #define MD3_MAX_SURFACES 32 +#define MD3_MIN_MODELS 4 struct FSpriteModelFrame { - int modelIDs[MAX_MODELS_PER_FRAME]; - FTextureID skinIDs[MAX_MODELS_PER_FRAME]; - FTextureID surfaceskinIDs[MAX_MODELS_PER_FRAME][MD3_MAX_SURFACES]; - int modelframes[MAX_MODELS_PER_FRAME]; + uint8_t modelsAmount = 0; + TArray modelIDs; + TArray skinIDs; + TArray surfaceskinIDs; + TArray modelframes; float xscale, yscale, zscale; // [BB] Added zoffset, rotation parameters and flags. // Added xoffset, yoffset diff --git a/src/common/models/models_md3.cpp b/src/common/models/models_md3.cpp index 15224e4fe9..b706b4a7c9 100644 --- a/src/common/models/models_md3.cpp +++ b/src/common/models/models_md3.cpp @@ -306,9 +306,10 @@ void FMD3Model::AddSkins(uint8_t *hitlist) { for (unsigned i = 0; i < Surfaces.Size(); i++) { - if (curSpriteMDLFrame->surfaceskinIDs[curMDLIndex][i].isValid()) + int ssIndex = i + curMDLIndex * MD3_MAX_SURFACES; + if (curSpriteMDLFrame->surfaceskinIDs[ssIndex].isValid()) { - hitlist[curSpriteMDLFrame->surfaceskinIDs[curMDLIndex][i].GetIndex()] |= FTextureManager::HIT_Flat; + hitlist[curSpriteMDLFrame->surfaceskinIDs[ssIndex].GetIndex()] |= FTextureManager::HIT_Flat; } MD3Surface * surf = &Surfaces[i]; @@ -357,9 +358,10 @@ void FMD3Model::RenderFrame(FModelRenderer *renderer, FGameTexture * skin, int f FGameTexture *surfaceSkin = skin; if (!surfaceSkin) { - if (curSpriteMDLFrame->surfaceskinIDs[curMDLIndex][i].isValid()) + int ssIndex = i + curMDLIndex * MD3_MAX_SURFACES; + if (curSpriteMDLFrame->surfaceskinIDs[ssIndex].isValid()) { - surfaceSkin = TexMan.GetGameTexture(curSpriteMDLFrame->surfaceskinIDs[curMDLIndex][i], true); + surfaceSkin = TexMan.GetGameTexture(curSpriteMDLFrame->surfaceskinIDs[ssIndex], true); } else if (surf->numSkins > 0 && surf->Skins[0].isValid()) { diff --git a/src/common/models/models_obj.cpp b/src/common/models/models_obj.cpp index 264ffd6ac2..07bac6ea92 100644 --- a/src/common/models/models_obj.cpp +++ b/src/common/models/models_obj.cpp @@ -638,9 +638,10 @@ void FOBJModel::RenderFrame(FModelRenderer *renderer, FGameTexture * skin, int f FGameTexture *userSkin = skin; if (!userSkin) { - if (i < MD3_MAX_SURFACES && curSpriteMDLFrame->surfaceskinIDs[curMDLIndex][i].isValid()) + int ssIndex = i + curMDLIndex * MD3_MAX_SURFACES; + if (i < MD3_MAX_SURFACES && curSpriteMDLFrame->surfaceskinIDs[ssIndex].isValid()) { - userSkin = TexMan.GetGameTexture(curSpriteMDLFrame->surfaceskinIDs[curMDLIndex][i], true); + userSkin = TexMan.GetGameTexture(curSpriteMDLFrame->surfaceskinIDs[ssIndex], true); } else if (surf->skin.isValid()) { @@ -669,13 +670,14 @@ void FOBJModel::AddSkins(uint8_t* hitlist) { for (size_t i = 0; i < surfaces.Size(); i++) { - if (i < MD3_MAX_SURFACES && curSpriteMDLFrame->surfaceskinIDs[curMDLIndex][i].isValid()) + size_t ssIndex = i + curMDLIndex * MD3_MAX_SURFACES; + if (i < MD3_MAX_SURFACES && curSpriteMDLFrame->surfaceskinIDs[ssIndex].isValid()) { // Precache skins manually reassigned by the user. // On OBJs with lots of skins, such as Doom map OBJs exported from GZDB, // there may be too many skins for the user to manually change, unless // the limit is bumped or surfaceskinIDs is changed to a TArray. - hitlist[curSpriteMDLFrame->surfaceskinIDs[curMDLIndex][i].GetIndex()] |= FTextureManager::HIT_Flat; + hitlist[curSpriteMDLFrame->surfaceskinIDs[ssIndex].GetIndex()] |= FTextureManager::HIT_Flat; return; // No need to precache skin that was replaced } diff --git a/src/common/models/models_ue1.cpp b/src/common/models/models_ue1.cpp index 3066b7759f..9214063025 100644 --- a/src/common/models/models_ue1.cpp +++ b/src/common/models/models_ue1.cpp @@ -242,8 +242,9 @@ void FUE1Model::RenderFrame( FModelRenderer *renderer, FGameTexture *skin, int f FGameTexture *sskin = skin; if ( !sskin ) { - if ( curSpriteMDLFrame->surfaceskinIDs[curMDLIndex][groups[i].texNum].isValid() ) - sskin = TexMan.GetGameTexture(curSpriteMDLFrame->surfaceskinIDs[curMDLIndex][groups[i].texNum], true); + int ssIndex = groups[i].texNum + curMDLIndex * MD3_MAX_SURFACES; + if (curSpriteMDLFrame->surfaceskinIDs[ssIndex].isValid()) + sskin = TexMan.GetGameTexture(curSpriteMDLFrame->surfaceskinIDs[ssIndex], true); if ( !sskin ) { vofs += vsize; @@ -302,9 +303,12 @@ void FUE1Model::BuildVertexBuffer( FModelRenderer *renderer ) void FUE1Model::AddSkins( uint8_t *hitlist ) { - for ( int i=0; isurfaceskinIDs[curMDLIndex][groups[i].texNum].isValid() ) - hitlist[curSpriteMDLFrame->surfaceskinIDs[curMDLIndex][groups[i].texNum].GetIndex()] |= FTextureManager::HIT_Flat; + for (int i = 0; i < numGroups; i++) + { + int ssIndex = groups[i].texNum + curMDLIndex * MD3_MAX_SURFACES; + if (curSpriteMDLFrame->surfaceskinIDs[ssIndex].isValid()) + hitlist[curSpriteMDLFrame->surfaceskinIDs[ssIndex].GetIndex()] |= FTextureManager::HIT_Flat; + } } FUE1Model::~FUE1Model() diff --git a/src/r_data/models.cpp b/src/r_data/models.cpp index 0b8a458b4d..b2d077f29c 100644 --- a/src/r_data/models.cpp +++ b/src/r_data/models.cpp @@ -268,7 +268,7 @@ void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpr } } - for (int i = 0; imodelsAmount; i++) { if (smf->modelIDs[i] != -1) { @@ -317,8 +317,12 @@ void InitModels() FSpriteModelFrame smf; memset(&smf, 0, sizeof(smf)); smf.isVoxel = true; - smf.modelIDs[1] = smf.modelIDs[2] = smf.modelIDs[3] = -1; + smf.modelsAmount = 1; + smf.modelframes.Alloc(1); + smf.modelframes[0] = -1; + smf.modelIDs.Alloc(1); smf.modelIDs[0] = VoxelDefs[i]->Voxel->VoxelIndex; + smf.skinIDs.Alloc(1); smf.skinIDs[0] = md->GetPaletteTexture(); smf.xscale = smf.yscale = smf.zscale = VoxelDefs[i]->Scale; smf.angleoffset = VoxelDefs[i]->AngleOffset.Degrees; @@ -380,7 +384,6 @@ static void ParseModelDefLump(int Lump) FSpriteModelFrame smf; memset(&smf, 0, sizeof(smf)); - smf.modelIDs[0] = smf.modelIDs[1] = smf.modelIDs[2] = smf.modelIDs[3] = -1; smf.xscale=smf.yscale=smf.zscale=1.f; auto type = PClass::FindClass(sc.String); @@ -389,6 +392,47 @@ static void ParseModelDefLump(int Lump) sc.ScriptError("MODELDEF: Unknown actor type '%s'\n", sc.String); } smf.type = type; + FScanner::SavedPos scPos = sc.SavePos(); + sc.MustGetStringName("{"); + while (!sc.CheckString("}")) + { + sc.MustGetString(); + if (sc.Compare("model")) + { + sc.MustGetNumber(); + index = sc.Number; + if (index < 0) + { + sc.ScriptError("Model index must be 0 or greater in %s", type->TypeName.GetChars()); + } + smf.modelsAmount = index + 1; + } + } + //Make sure modelsAmount is at least equal to MD3_MIN_MODELS(4) to ensure compatibility with old mods + if (smf.modelsAmount < MD3_MIN_MODELS) + { + smf.modelsAmount = MD3_MIN_MODELS; + } + //Allocate TArrays + smf.modelIDs.Alloc(smf.modelsAmount); + smf.skinIDs.Alloc(smf.modelsAmount); + smf.surfaceskinIDs.Alloc(smf.modelsAmount * MD3_MAX_SURFACES); + smf.modelframes.Alloc(smf.modelsAmount); + //Make sure all modelIDs are -1 by default + for (auto& modelID : smf.modelIDs) + { + modelID = -1; + } + //Make sure no TArray elements of type FTextureID are null. These elements will have a textureid (FTextureID.texnum) of 0. + for (auto& skinID : smf.skinIDs) + { + skinID = FTextureID(FNullTextureID()); + } + for (auto& surfaceskinID : smf.surfaceskinIDs) + { + surfaceskinID = FTextureID(FNullTextureID()); + } + sc.RestorePos(scPos); sc.MustGetStringName("{"); while (!sc.CheckString("}")) { @@ -404,7 +448,11 @@ static void ParseModelDefLump(int Lump) { sc.MustGetNumber(); index = sc.Number; - if (index < 0 || index >= MAX_MODELS_PER_FRAME) + if (index < 0) + { + sc.ScriptError("Model index must be 0 or greater in %s", type->TypeName.GetChars()); + } + else if (index >= smf.modelsAmount) { sc.ScriptError("Too many models in %s", type->TypeName.GetChars()); } @@ -529,7 +577,7 @@ static void ParseModelDefLump(int Lump) { sc.MustGetNumber(); index=sc.Number; - if (index<0 || index>=MAX_MODELS_PER_FRAME) + if (index<0 || index>= smf.modelsAmount) { sc.ScriptError("Too many models in %s", type->TypeName.GetChars()); } @@ -556,7 +604,7 @@ static void ParseModelDefLump(int Lump) sc.MustGetNumber(); surface = sc.Number; - if (index<0 || index >= MAX_MODELS_PER_FRAME) + if (index<0 || index >= smf.modelsAmount) { sc.ScriptError("Too many models in %s", type->TypeName.GetChars()); } @@ -568,14 +616,15 @@ static void ParseModelDefLump(int Lump) sc.MustGetString(); FixPathSeperator(sc.String); + int ssIndex = surface + index * MD3_MAX_SURFACES; if (sc.Compare("")) { - smf.surfaceskinIDs[index][surface] = FNullTextureID(); + smf.surfaceskinIDs[ssIndex] = FNullTextureID(); } else { - smf.surfaceskinIDs[index][surface] = LoadSkin(path.GetChars(), sc.String); - if (!smf.surfaceskinIDs[index][surface].isValid()) + smf.surfaceskinIDs[ssIndex] = LoadSkin(path.GetChars(), sc.String); + if (!smf.surfaceskinIDs[ssIndex].isValid()) { Printf("Surface Skin '%s' not found in '%s'\n", sc.String, type->TypeName.GetChars()); @@ -610,7 +659,7 @@ static void ParseModelDefLump(int Lump) sc.MustGetNumber(); index=sc.Number; - if (index<0 || index>=MAX_MODELS_PER_FRAME) + if (index<0 || index>= smf.modelsAmount) { sc.ScriptError("Too many models in %s", type->TypeName.GetChars()); } diff --git a/src/rendering/hwrenderer/hw_precache.cpp b/src/rendering/hwrenderer/hw_precache.cpp index 72b977f80c..7ad9192bcc 100644 --- a/src/rendering/hwrenderer/hw_precache.cpp +++ b/src/rendering/hwrenderer/hw_precache.cpp @@ -162,7 +162,7 @@ void hw_PrecacheTexture(uint8_t *texhitlist, TMap &actorhitl FSpriteModelFrame * smf = FindModelFrame(cls, state.sprite, state.Frame, false); if (smf != NULL) { - for (int i = 0; i < MAX_MODELS_PER_FRAME; i++) + for (int i = 0; i < smf->modelsAmount; i++) { if (smf->skinIDs[i].isValid()) {