2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
26 ===========================================================================
29 #include "../idlib/precompiled.h"
32 #include "Model_local.h"
33 #include "tr_local.h" // just for R_FreeWorldInteractions and R_CreateWorldInteractions
36 class idRenderModelManagerLocal : public idRenderModelManager {
38 idRenderModelManagerLocal();
39 virtual ~idRenderModelManagerLocal() {}
42 virtual void Shutdown();
43 virtual idRenderModel * AllocModel();
44 virtual void FreeModel( idRenderModel *model );
45 virtual idRenderModel * FindModel( const char *modelName );
46 virtual idRenderModel * CheckModel( const char *modelName );
47 virtual idRenderModel * DefaultModel();
48 virtual void AddModel( idRenderModel *model );
49 virtual void RemoveModel( idRenderModel *model );
50 virtual void ReloadModels( bool forceAll = false );
51 virtual void FreeModelVertexCaches();
52 virtual void WritePrecacheCommands( idFile *file );
53 virtual void BeginLevelLoad();
54 virtual void EndLevelLoad();
56 virtual void PrintMemInfo( MemInfo_t *mi );
59 idList<idRenderModel*> models;
61 idRenderModel * defaultModel;
62 idRenderModel * beamModel;
63 idRenderModel * spriteModel;
64 idRenderModel * trailModel;
65 bool insideLevelLoad; // don't actually load now
67 idRenderModel * GetModel( const char *modelName, bool createIfNotFound );
69 static void PrintModel_f( const idCmdArgs &args );
70 static void ListModels_f( const idCmdArgs &args );
71 static void ReloadModels_f( const idCmdArgs &args );
72 static void TouchModel_f( const idCmdArgs &args );
76 idRenderModelManagerLocal localModelManager;
77 idRenderModelManager * renderModelManager = &localModelManager;
81 idRenderModelManagerLocal::idRenderModelManagerLocal
84 idRenderModelManagerLocal::idRenderModelManagerLocal() {
88 insideLevelLoad = false;
94 idRenderModelManagerLocal::PrintModel_f
97 void idRenderModelManagerLocal::PrintModel_f( const idCmdArgs &args ) {
100 if ( args.Argc() != 2 ) {
101 common->Printf( "usage: printModel <modelName>\n" );
105 model = renderModelManager->CheckModel( args.Argv( 1 ) );
107 common->Printf( "model \"%s\" not found\n", args.Argv( 1 ) );
116 idRenderModelManagerLocal::ListModels_f
119 void idRenderModelManagerLocal::ListModels_f( const idCmdArgs &args ) {
123 common->Printf( " mem srf verts tris\n" );
124 common->Printf( " --- --- ----- ----\n" );
126 for ( int i = 0 ; i < localModelManager.models.Num() ; i++ ) {
127 idRenderModel *model = localModelManager.models[i];
129 if ( !model->IsLoaded() ) {
133 totalMem += model->Memory();
137 common->Printf( " --- --- ----- ----\n" );
138 common->Printf( " mem srf verts tris\n" );
140 common->Printf( "%i loaded models\n", inUse );
141 common->Printf( "total memory: %4.1fM\n", (float)totalMem / (1024*1024) );
146 idRenderModelManagerLocal::ReloadModels_f
149 void idRenderModelManagerLocal::ReloadModels_f( const idCmdArgs &args ) {
150 if ( idStr::Icmp( args.Argv(1), "all" ) == 0 ) {
151 localModelManager.ReloadModels( true );
153 localModelManager.ReloadModels( false );
159 idRenderModelManagerLocal::TouchModel_f
161 Precache a specific model
164 void idRenderModelManagerLocal::TouchModel_f( const idCmdArgs &args ) {
165 const char *model = args.Argv( 1 );
168 common->Printf( "usage: touchModel <modelName>\n" );
172 common->Printf( "touchModel %s\n", model );
173 session->UpdateScreen();
174 idRenderModel *m = renderModelManager->CheckModel( model );
176 common->Printf( "...not found\n" );
182 idRenderModelManagerLocal::WritePrecacheCommands
185 void idRenderModelManagerLocal::WritePrecacheCommands( idFile *f ) {
186 for ( int i = 0 ; i < models.Num() ; i++ ) {
187 idRenderModel *model = models[i];
192 if ( !model->IsReloadable() ) {
197 sprintf( str, "touchModel %s\n", model->Name() );
198 common->Printf( "%s", str );
199 f->Printf( "%s", str );
205 idRenderModelManagerLocal::Init
208 void idRenderModelManagerLocal::Init() {
209 cmdSystem->AddCommand( "listModels", ListModels_f, CMD_FL_RENDERER, "lists all models" );
210 cmdSystem->AddCommand( "printModel", PrintModel_f, CMD_FL_RENDERER, "prints model info", idCmdSystem::ArgCompletion_ModelName );
211 cmdSystem->AddCommand( "reloadModels", ReloadModels_f, CMD_FL_RENDERER|CMD_FL_CHEAT, "reloads models" );
212 cmdSystem->AddCommand( "touchModel", TouchModel_f, CMD_FL_RENDERER, "touches a model", idCmdSystem::ArgCompletion_ModelName );
214 insideLevelLoad = false;
216 // create a default model
217 idRenderModelStatic *model = new idRenderModelStatic;
218 model->InitEmpty( "_DEFAULT" );
219 model->MakeDefaultModel();
220 model->SetLevelLoadReferenced( true );
221 defaultModel = model;
224 // create the beam model
225 idRenderModelStatic *beam = new idRenderModelBeam;
226 beam->InitEmpty( "_BEAM" );
227 beam->SetLevelLoadReferenced( true );
231 idRenderModelStatic *sprite = new idRenderModelSprite;
232 sprite->InitEmpty( "_SPRITE" );
233 sprite->SetLevelLoadReferenced( true );
234 spriteModel = sprite;
240 idRenderModelManagerLocal::Shutdown
243 void idRenderModelManagerLocal::Shutdown() {
244 models.DeleteContents( true );
250 idRenderModelManagerLocal::GetModel
253 idRenderModel *idRenderModelManagerLocal::GetModel( const char *modelName, bool createIfNotFound ) {
257 if ( !modelName || !modelName[0] ) {
261 canonical = modelName;
264 // see if it is already present
265 int key = hash.GenerateKey( modelName, false );
266 for ( int i = hash.First( key ); i != -1; i = hash.Next( i ) ) {
267 idRenderModel *model = models[i];
269 if ( canonical.Icmp( model->Name() ) == 0 ) {
270 if ( !model->IsLoaded() ) {
271 // reload it if it was purged
273 } else if ( insideLevelLoad && !model->IsLevelLoadReferenced() ) {
274 // we are reusing a model already in memory, but
275 // touch all the materials to make sure they stay
279 model->SetLevelLoadReferenced( true );
284 // see if we can load it
286 // determine which subclass of idRenderModel to initialize
288 idRenderModel *model;
290 canonical.ExtractFileExtension( extension );
292 if ( ( extension.Icmp( "ase" ) == 0 ) || ( extension.Icmp( "lwo" ) == 0 ) || ( extension.Icmp( "flt" ) == 0 ) ) {
293 model = new idRenderModelStatic;
294 model->InitFromFile( modelName );
295 } else if ( extension.Icmp( "ma" ) == 0 ) {
296 model = new idRenderModelStatic;
297 model->InitFromFile( modelName );
298 } else if ( extension.Icmp( MD5_MESH_EXT ) == 0 ) {
299 model = new idRenderModelMD5;
300 model->InitFromFile( modelName );
301 } else if ( extension.Icmp( "md3" ) == 0 ) {
302 model = new idRenderModelMD3;
303 model->InitFromFile( modelName );
304 } else if ( extension.Icmp( "prt" ) == 0 ) {
305 model = new idRenderModelPrt;
306 model->InitFromFile( modelName );
307 } else if ( extension.Icmp( "liquid" ) == 0 ) {
308 model = new idRenderModelLiquid;
309 model->InitFromFile( modelName );
312 if ( extension.Length() ) {
313 common->Warning( "unknown model type '%s'", canonical.c_str() );
316 if ( !createIfNotFound ) {
320 idRenderModelStatic *smodel = new idRenderModelStatic;
321 smodel->InitEmpty( modelName );
322 smodel->MakeDefaultModel();
327 model->SetLevelLoadReferenced( true );
329 if ( !createIfNotFound && model->IsDefaultModel() ) {
343 idRenderModelManagerLocal::AllocModel
346 idRenderModel *idRenderModelManagerLocal::AllocModel() {
347 return new idRenderModelStatic();
352 idRenderModelManagerLocal::FreeModel
355 void idRenderModelManagerLocal::FreeModel( idRenderModel *model ) {
359 if ( !dynamic_cast<idRenderModelStatic *>( model ) ) {
360 common->Error( "idRenderModelManager::FreeModel: model '%s' is not a static model", model->Name() );
363 if ( model == defaultModel ) {
364 common->Error( "idRenderModelManager::FreeModel: can't free the default model" );
367 if ( model == beamModel ) {
368 common->Error( "idRenderModelManager::FreeModel: can't free the beam model" );
371 if ( model == spriteModel ) {
372 common->Error( "idRenderModelManager::FreeModel: can't free the sprite model" );
376 R_CheckForEntityDefsUsingModel( model );
383 idRenderModelManagerLocal::FindModel
386 idRenderModel *idRenderModelManagerLocal::FindModel( const char *modelName ) {
387 return GetModel( modelName, true );
392 idRenderModelManagerLocal::CheckModel
395 idRenderModel *idRenderModelManagerLocal::CheckModel( const char *modelName ) {
396 return GetModel( modelName, false );
401 idRenderModelManagerLocal::DefaultModel
404 idRenderModel *idRenderModelManagerLocal::DefaultModel() {
410 idRenderModelManagerLocal::AddModel
413 void idRenderModelManagerLocal::AddModel( idRenderModel *model ) {
414 hash.Add( hash.GenerateKey( model->Name(), false ), models.Append( model ) );
419 idRenderModelManagerLocal::RemoveModel
422 void idRenderModelManagerLocal::RemoveModel( idRenderModel *model ) {
423 int index = models.FindIndex( model );
424 hash.RemoveIndex( hash.GenerateKey( model->Name(), false ), index );
425 models.RemoveIndex( index );
430 idRenderModelManagerLocal::ReloadModels
433 void idRenderModelManagerLocal::ReloadModels( bool forceAll ) {
435 common->Printf( "Reloading all model files...\n" );
437 common->Printf( "Checking for changed model files...\n" );
442 // skip the default model at index 0
443 for ( int i = 1 ; i < models.Num() ; i++ ) {
444 idRenderModel *model = models[i];
446 // we may want to allow world model reloading in the future, but we don't now
447 if ( !model->IsReloadable() ) {
455 fileSystem->ReadFile( model->Name(), NULL, ¤t );
456 if ( current <= model->Timestamp() ) {
461 common->DPrintf( "reloading %s.\n", model->Name() );
466 // we must force the world to regenerate, because models may
467 // have changed size, making their references invalid
468 R_ReCreateWorldReferences();
473 idRenderModelManagerLocal::FreeModelVertexCaches
476 void idRenderModelManagerLocal::FreeModelVertexCaches() {
477 for ( int i = 0 ; i < models.Num() ; i++ ) {
478 idRenderModel *model = models[i];
479 model->FreeVertexCache();
485 idRenderModelManagerLocal::BeginLevelLoad
488 void idRenderModelManagerLocal::BeginLevelLoad() {
489 insideLevelLoad = true;
491 for ( int i = 0 ; i < models.Num() ; i++ ) {
492 idRenderModel *model = models[i];
494 if ( com_purgeAll.GetBool() && model->IsReloadable() ) {
495 R_CheckForEntityDefsUsingModel( model );
499 model->SetLevelLoadReferenced( false );
502 // purge unused triangle surface memory
503 R_PurgeTriSurfData( frameData );
508 idRenderModelManagerLocal::EndLevelLoad
511 void idRenderModelManagerLocal::EndLevelLoad() {
512 common->Printf( "----- idRenderModelManagerLocal::EndLevelLoad -----\n" );
514 int start = Sys_Milliseconds();
516 insideLevelLoad = false;
521 // purge any models not touched
522 for ( int i = 0 ; i < models.Num() ; i++ ) {
523 idRenderModel *model = models[i];
525 if ( !model->IsLevelLoadReferenced() && model->IsLoaded() && model->IsReloadable() ) {
527 // common->Printf( "purging %s\n", model->Name() );
531 R_CheckForEntityDefsUsingModel( model );
537 // common->Printf( "keeping %s\n", model->Name() );
543 // purge unused triangle surface memory
544 R_PurgeTriSurfData( frameData );
547 for ( int i = 0 ; i < models.Num() ; i++ ) {
548 idRenderModel *model = models[i];
550 if ( model->IsLevelLoadReferenced() && !model->IsLoaded() && model->IsReloadable() ) {
555 if ( ( loadCount & 15 ) == 0 ) {
556 session->PacifierUpdate();
562 int end = Sys_Milliseconds();
563 common->Printf( "%5i models purged from previous level, ", purgeCount );
564 common->Printf( "%5i models kept.\n", keepCount );
566 common->Printf( "%5i new models loaded in %5.1f seconds\n", loadCount, (end-start) * 0.001 );
568 common->Printf( "---------------------------------------------------\n" );
573 idRenderModelManagerLocal::PrintMemInfo
576 void idRenderModelManagerLocal::PrintMemInfo( MemInfo_t *mi ) {
577 int i, j, totalMem = 0;
581 f = fileSystem->OpenFileWrite( mi->filebase + "_models.txt" );
587 sortIndex = new int[ localModelManager.models.Num()];
589 for ( i = 0; i < localModelManager.models.Num(); i++ ) {
593 for ( i = 0; i < localModelManager.models.Num() - 1; i++ ) {
594 for ( j = i + 1; j < localModelManager.models.Num(); j++ ) {
595 if ( localModelManager.models[sortIndex[i]]->Memory() < localModelManager.models[sortIndex[j]]->Memory() ) {
596 int temp = sortIndex[i];
597 sortIndex[i] = sortIndex[j];
604 for ( int i = 0 ; i < localModelManager.models.Num() ; i++ ) {
605 idRenderModel *model = localModelManager.models[sortIndex[i]];
608 if ( !model->IsLoaded() ) {
612 mem = model->Memory();
614 f->Printf( "%s %s\n", idStr::FormatNumber( mem ).c_str(), model->Name() );
618 mi->modelAssetsTotal = totalMem;
620 f->Printf( "\nTotal model bytes allocated: %s\n", idStr::FormatNumber( totalMem ).c_str() );
621 fileSystem->CloseFile( f );