diff --git a/src/gl/models/gl_models.h b/src/gl/models/gl_models.h index 70379a3d22..33fa00736e 100644 --- a/src/gl/models/gl_models.h +++ b/src/gl/models/gl_models.h @@ -34,6 +34,7 @@ public: virtual int FindFrame(const char * name) = 0; virtual void RenderFrame(FTexture * skin, int frame, int frame2, double inter, int translation=0) = 0; virtual void BuildVertexBuffer() = 0; + virtual void AddSkins(BYTE *hitlist) = 0; void DestroyVertexBuffer() { delete mVBuf; @@ -155,6 +156,8 @@ public: virtual int FindFrame(const char * name); virtual void RenderFrame(FTexture * skin, int frame, int frame2, double inter, int translation=0); virtual void LoadGeometry(); + virtual void AddSkins(BYTE *hitlist); + void UnloadGeometry(); void BuildVertexBuffer(); @@ -260,6 +263,7 @@ public: virtual void RenderFrame(FTexture * skin, int frame, int frame2, double inter, int translation=0); void LoadGeometry(); void BuildVertexBuffer(); + virtual void AddSkins(BYTE *hitlist); }; struct FVoxelVertexHash @@ -312,6 +316,7 @@ public: void Initialize(); virtual int FindFrame(const char * name); virtual void RenderFrame(FTexture * skin, int frame, int frame2, double inter, int translation=0); + virtual void AddSkins(BYTE *hitlist); FTextureID GetPaletteTexture() const { return mPalette; } void BuildVertexBuffer(); float getAspectFactor(); diff --git a/src/gl/models/gl_models_md2.cpp b/src/gl/models/gl_models_md2.cpp index c45569df97..c0bd155fb3 100644 --- a/src/gl/models/gl_models_md2.cpp +++ b/src/gl/models/gl_models_md2.cpp @@ -336,7 +336,22 @@ void FDMDModel::BuildVertexBuffer() } } +//=========================================================================== +// +// for skin precaching +// +//=========================================================================== +void FDMDModel::AddSkins(BYTE *hitlist) +{ + for (int i = 0; i < info.numSkins; i++) + { + if (skins[i].isValid()) + { + hitlist[skins[i].GetIndex()] |= FTexture::TEX_Flat; + } + } +} //=========================================================================== // diff --git a/src/gl/models/gl_models_md3.cpp b/src/gl/models/gl_models_md3.cpp index 3da5bd1c09..267e85c910 100644 --- a/src/gl/models/gl_models_md3.cpp +++ b/src/gl/models/gl_models_md3.cpp @@ -309,6 +309,27 @@ void FMD3Model::BuildVertexBuffer() } +//=========================================================================== +// +// for skin precaching +// +//=========================================================================== + +void FMD3Model::AddSkins(BYTE *hitlist) +{ + for (int i = 0; i < numSurfaces; i++) + { + MD3Surface * surf = &surfaces[i]; + for (int j = 0; j < surf->numSkins; j++) + { + if (surf->skins[j].isValid()) + { + hitlist[surf->skins[j].GetIndex()] |= FTexture::TEX_Flat; + } + } + } +} + //=========================================================================== // // diff --git a/src/gl/models/gl_voxels.cpp b/src/gl/models/gl_voxels.cpp index babb62d102..ec7f0573b9 100644 --- a/src/gl/models/gl_voxels.cpp +++ b/src/gl/models/gl_voxels.cpp @@ -397,6 +397,17 @@ void FVoxelModel::BuildVertexBuffer() } +//=========================================================================== +// +// for skin precaching +// +//=========================================================================== + +void FVoxelModel::AddSkins(BYTE *hitlist) +{ + hitlist[mPalette.GetIndex()] |= FTexture::TEX_Flat; +} + //=========================================================================== // // diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index a87e522d36..44368775ac 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -1019,23 +1019,10 @@ bool FGLInterface::UsesColormap() const void FGLInterface::PrecacheTexture(FTexture *tex, int cache) { - if (tex != NULL) + if (cache & (FTextureManager::HIT_Wall | FTextureManager::HIT_Flat | FTextureManager::HIT_Sky)) { - if (cache) - { - if (gl_precache) - { - if (cache & (FTextureManager::HIT_Wall | FTextureManager::HIT_Flat | FTextureManager::HIT_Sky)) - { - FMaterial * gltex = FMaterial::ValidateTexture(tex, false); - if (gltex) gltex->Precache(); - } - } - } - else - { - if (tex->gl_info.Material[0]) tex->gl_info.Material[0]->Clean(true); - } + FMaterial * gltex = FMaterial::ValidateTexture(tex, false); + if (gltex) gltex->Precache(); } } @@ -1047,15 +1034,8 @@ void FGLInterface::PrecacheTexture(FTexture *tex, int cache) void FGLInterface::PrecacheSprite(FTexture *tex, SpriteHits &hits) { - if (hits.CountUsed() == 0) - { - if (tex->gl_info.Material[1]) tex->gl_info.Material[1]->Clean(true); - } - else - { - FMaterial * gltex = FMaterial::ValidateTexture(tex, true); - if (gltex) gltex->PrecacheList(hits); - } + FMaterial * gltex = FMaterial::ValidateTexture(tex, true); + if (gltex) gltex->PrecacheList(hits); } //========================================================================== @@ -1070,6 +1050,8 @@ void FGLInterface::Precache(BYTE *texhitlist, TMap &actorhit SpriteHits **spritehitlist = new SpriteHits*[TexMan.NumTextures()]; TMap::Iterator it(actorhitlist); TMap::Pair *pair; + BYTE *modellist = new BYTE[Models.Size()]; + memset(modellist, 0, Models.Size()); memset(spritehitlist, 0, sizeof(SpriteHits**) * TexMan.NumTextures()); // this isn't done by the main code so it needs to be done here first: @@ -1095,6 +1077,9 @@ void FGLInterface::Precache(BYTE *texhitlist, TMap &actorhit } } + // Check all used actors. + // 1. mark all sprites associated with its states + // 2. mark all model data and skins associated with its states while (it.NextPair(pair)) { PClassActor *cls = pair->Key; @@ -1103,11 +1088,29 @@ void FGLInterface::Precache(BYTE *texhitlist, TMap &actorhit for (int i = 0; i < cls->NumOwnedStates; i++) { spritelist[cls->OwnedStates[i].sprite].Insert(gltrans, true); + FSpriteModelFrame * smf = gl_FindModelFrame(cls, cls->OwnedStates[i].sprite, cls->OwnedStates[i].Frame, false); + if (smf != NULL) + { + for (int i = 0; i < MAX_MODELS_PER_FRAME; i++) + { + if (smf->skinIDs[i].isValid()) + { + texhitlist[smf->skinIDs[i].GetIndex()] |= FTexture::TEX_Flat; + } + else if (smf->modelIDs[i] != -1) + { + Models[smf->modelIDs[i]]->AddSkins(texhitlist); + } + if (smf->modelIDs[i] != -1) + { + modellist[smf->modelIDs[i]] = 1; + } + } + } } } - // Precache textures (and sprites). - + // mark all sprite textures belonging to the marked sprites. for (int i = (int)(sprites.Size() - 1); i >= 0; i--) { if (spritelist[i].CountUsed()) @@ -1129,14 +1132,59 @@ void FGLInterface::Precache(BYTE *texhitlist, TMap &actorhit } } + // delete everything unused before creating any new resources to avoid memory usage peaks. + + // delete unused models + for (unsigned i = 0; i < Models.Size(); i++) + { + if (!modellist[i]) Models[i]->DestroyVertexBuffer(); + } + + // delete unused textures int cnt = TexMan.NumTextures(); for (int i = cnt - 1; i >= 0; i--) { - PrecacheTexture(TexMan.ByIndex(i), texhitlist[i]); - if (spritehitlist[i] != nullptr) PrecacheSprite(TexMan.ByIndex(i), *spritehitlist[i]); + FTexture *tex = TexMan.ByIndex(i); + if (tex != nullptr) + { + if (!texhitlist[i]) + { + if (tex->gl_info.Material[0]) tex->gl_info.Material[0]->Clean(true); + } + if (spritehitlist[i] == nullptr || (*spritehitlist[i]).CountUsed() == 0) + { + if (tex->gl_info.Material[1]) tex->gl_info.Material[1]->Clean(true); + } + } } + + if (gl_precache) + { + // cache all used textures + for (int i = cnt - 1; i >= 0; i--) + { + FTexture *tex = TexMan.ByIndex(i); + if (tex != nullptr) + { + PrecacheTexture(tex, texhitlist[i]); + if (spritehitlist[i] != nullptr && (*spritehitlist[i]).CountUsed() > 0) + { + PrecacheSprite(tex, *spritehitlist[i]); + } + } + } + + // cache all used models + for (unsigned i = 0; i < Models.Size(); i++) + { + if (modellist[i]) + Models[i]->BuildVertexBuffer(); + } + } + delete[] spritehitlist; delete[] spritelist; + delete[] modellist; }