doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ModelManager.cpp
Go to the documentation of this file.
1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
8 
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.
13 
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.
18 
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/>.
21 
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.
23 
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.
25 
26 ===========================================================================
27 */
28 
29 #include "../idlib/precompiled.h"
30 #pragma hdrstop
31 
32 #include "Model_local.h"
33 #include "tr_local.h" // just for R_FreeWorldInteractions and R_CreateWorldInteractions
34 
35 
37 public:
40 
41  virtual void Init();
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();
55 
56  virtual void PrintMemInfo( MemInfo_t *mi );
57 
58 private:
65  bool insideLevelLoad; // don't actually load now
66 
67  idRenderModel * GetModel( const char *modelName, bool createIfNotFound );
68 
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 );
73 };
74 
75 
78 
79 /*
80 ==============
81 idRenderModelManagerLocal::idRenderModelManagerLocal
82 ==============
83 */
86  beamModel = NULL;
87  spriteModel = NULL;
88  insideLevelLoad = false;
89  trailModel = NULL;
90 }
91 
92 /*
93 ==============
94 idRenderModelManagerLocal::PrintModel_f
95 ==============
96 */
98  idRenderModel *model;
99 
100  if ( args.Argc() != 2 ) {
101  common->Printf( "usage: printModel <modelName>\n" );
102  return;
103  }
104 
105  model = renderModelManager->CheckModel( args.Argv( 1 ) );
106  if ( !model ) {
107  common->Printf( "model \"%s\" not found\n", args.Argv( 1 ) );
108  return;
109  }
110 
111  model->Print();
112 }
113 
114 /*
115 ==============
116 idRenderModelManagerLocal::ListModels_f
117 ==============
118 */
120  int totalMem = 0;
121  int inUse = 0;
122 
123  common->Printf( " mem srf verts tris\n" );
124  common->Printf( " --- --- ----- ----\n" );
125 
126  for ( int i = 0 ; i < localModelManager.models.Num() ; i++ ) {
127  idRenderModel *model = localModelManager.models[i];
128 
129  if ( !model->IsLoaded() ) {
130  continue;
131  }
132  model->List();
133  totalMem += model->Memory();
134  inUse++;
135  }
136 
137  common->Printf( " --- --- ----- ----\n" );
138  common->Printf( " mem srf verts tris\n" );
139 
140  common->Printf( "%i loaded models\n", inUse );
141  common->Printf( "total memory: %4.1fM\n", (float)totalMem / (1024*1024) );
142 }
143 
144 /*
145 ==============
146 idRenderModelManagerLocal::ReloadModels_f
147 ==============
148 */
150  if ( idStr::Icmp( args.Argv(1), "all" ) == 0 ) {
151  localModelManager.ReloadModels( true );
152  } else {
153  localModelManager.ReloadModels( false );
154  }
155 }
156 
157 /*
158 ==============
159 idRenderModelManagerLocal::TouchModel_f
160 
161 Precache a specific model
162 ==============
163 */
165  const char *model = args.Argv( 1 );
166 
167  if ( !model[0] ) {
168  common->Printf( "usage: touchModel <modelName>\n" );
169  return;
170  }
171 
172  common->Printf( "touchModel %s\n", model );
174  idRenderModel *m = renderModelManager->CheckModel( model );
175  if ( !m ) {
176  common->Printf( "...not found\n" );
177  }
178 }
179 
180 /*
181 =================
182 idRenderModelManagerLocal::WritePrecacheCommands
183 =================
184 */
186  for ( int i = 0 ; i < models.Num() ; i++ ) {
187  idRenderModel *model = models[i];
188 
189  if ( !model ) {
190  continue;
191  }
192  if ( !model->IsReloadable() ) {
193  continue;
194  }
195 
196  char str[1024];
197  sprintf( str, "touchModel %s\n", model->Name() );
198  common->Printf( "%s", str );
199  f->Printf( "%s", str );
200  }
201 }
202 
203 /*
204 =================
205 idRenderModelManagerLocal::Init
206 =================
207 */
209  cmdSystem->AddCommand( "listModels", ListModels_f, CMD_FL_RENDERER, "lists all models" );
211  cmdSystem->AddCommand( "reloadModels", ReloadModels_f, CMD_FL_RENDERER|CMD_FL_CHEAT, "reloads models" );
213 
214  insideLevelLoad = false;
215 
216  // create a default model
218  model->InitEmpty( "_DEFAULT" );
219  model->MakeDefaultModel();
220  model->SetLevelLoadReferenced( true );
221  defaultModel = model;
222  AddModel( model );
223 
224  // create the beam model
226  beam->InitEmpty( "_BEAM" );
227  beam->SetLevelLoadReferenced( true );
228  beamModel = beam;
229  AddModel( beam );
230 
232  sprite->InitEmpty( "_SPRITE" );
233  sprite->SetLevelLoadReferenced( true );
234  spriteModel = sprite;
235  AddModel( sprite );
236 }
237 
238 /*
239 =================
240 idRenderModelManagerLocal::Shutdown
241 =================
242 */
244  models.DeleteContents( true );
245  hash.Free();
246 }
247 
248 /*
249 =================
250 idRenderModelManagerLocal::GetModel
251 =================
252 */
253 idRenderModel *idRenderModelManagerLocal::GetModel( const char *modelName, bool createIfNotFound ) {
254  idStr canonical;
255  idStr extension;
256 
257  if ( !modelName || !modelName[0] ) {
258  return NULL;
259  }
260 
261  canonical = modelName;
262  canonical.ToLower();
263 
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];
268 
269  if ( canonical.Icmp( model->Name() ) == 0 ) {
270  if ( !model->IsLoaded() ) {
271  // reload it if it was purged
272  model->LoadModel();
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
276  // in memory as well
277  model->TouchData();
278  }
279  model->SetLevelLoadReferenced( true );
280  return model;
281  }
282  }
283 
284  // see if we can load it
285 
286  // determine which subclass of idRenderModel to initialize
287 
288  idRenderModel *model;
289 
290  canonical.ExtractFileExtension( extension );
291 
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 );
310  } else {
311 
312  if ( extension.Length() ) {
313  common->Warning( "unknown model type '%s'", canonical.c_str() );
314  }
315 
316  if ( !createIfNotFound ) {
317  return NULL;
318  }
319 
321  smodel->InitEmpty( modelName );
322  smodel->MakeDefaultModel();
323 
324  model = smodel;
325  }
326 
327  model->SetLevelLoadReferenced( true );
328 
329  if ( !createIfNotFound && model->IsDefaultModel() ) {
330  delete model;
331  model = NULL;
332 
333  return NULL;
334  }
335 
336  AddModel( model );
337 
338  return model;
339 }
340 
341 /*
342 =================
343 idRenderModelManagerLocal::AllocModel
344 =================
345 */
347  return new idRenderModelStatic();
348 }
349 
350 /*
351 =================
352 idRenderModelManagerLocal::FreeModel
353 =================
354 */
356  if ( !model ) {
357  return;
358  }
359  if ( !dynamic_cast<idRenderModelStatic *>( model ) ) {
360  common->Error( "idRenderModelManager::FreeModel: model '%s' is not a static model", model->Name() );
361  return;
362  }
363  if ( model == defaultModel ) {
364  common->Error( "idRenderModelManager::FreeModel: can't free the default model" );
365  return;
366  }
367  if ( model == beamModel ) {
368  common->Error( "idRenderModelManager::FreeModel: can't free the beam model" );
369  return;
370  }
371  if ( model == spriteModel ) {
372  common->Error( "idRenderModelManager::FreeModel: can't free the sprite model" );
373  return;
374  }
375 
377 
378  delete model;
379 }
380 
381 /*
382 =================
383 idRenderModelManagerLocal::FindModel
384 =================
385 */
387  return GetModel( modelName, true );
388 }
389 
390 /*
391 =================
392 idRenderModelManagerLocal::CheckModel
393 =================
394 */
396  return GetModel( modelName, false );
397 }
398 
399 /*
400 =================
401 idRenderModelManagerLocal::DefaultModel
402 =================
403 */
405  return defaultModel;
406 }
407 
408 /*
409 =================
410 idRenderModelManagerLocal::AddModel
411 =================
412 */
414  hash.Add( hash.GenerateKey( model->Name(), false ), models.Append( model ) );
415 }
416 
417 /*
418 =================
419 idRenderModelManagerLocal::RemoveModel
420 =================
421 */
423  int index = models.FindIndex( model );
424  hash.RemoveIndex( hash.GenerateKey( model->Name(), false ), index );
425  models.RemoveIndex( index );
426 }
427 
428 /*
429 =================
430 idRenderModelManagerLocal::ReloadModels
431 =================
432 */
434  if ( forceAll ) {
435  common->Printf( "Reloading all model files...\n" );
436  } else {
437  common->Printf( "Checking for changed model files...\n" );
438  }
439 
441 
442  // skip the default model at index 0
443  for ( int i = 1 ; i < models.Num() ; i++ ) {
444  idRenderModel *model = models[i];
445 
446  // we may want to allow world model reloading in the future, but we don't now
447  if ( !model->IsReloadable() ) {
448  continue;
449  }
450 
451  if ( !forceAll ) {
452  // check timestamp
453  ID_TIME_T current;
454 
455  fileSystem->ReadFile( model->Name(), NULL, &current );
456  if ( current <= model->Timestamp() ) {
457  continue;
458  }
459  }
460 
461  common->DPrintf( "reloading %s.\n", model->Name() );
462 
463  model->LoadModel();
464  }
465 
466  // we must force the world to regenerate, because models may
467  // have changed size, making their references invalid
469 }
470 
471 /*
472 =================
473 idRenderModelManagerLocal::FreeModelVertexCaches
474 =================
475 */
477  for ( int i = 0 ; i < models.Num() ; i++ ) {
478  idRenderModel *model = models[i];
479  model->FreeVertexCache();
480  }
481 }
482 
483 /*
484 =================
485 idRenderModelManagerLocal::BeginLevelLoad
486 =================
487 */
489  insideLevelLoad = true;
490 
491  for ( int i = 0 ; i < models.Num() ; i++ ) {
492  idRenderModel *model = models[i];
493 
494  if ( com_purgeAll.GetBool() && model->IsReloadable() ) {
496  model->PurgeModel();
497  }
498 
499  model->SetLevelLoadReferenced( false );
500  }
501 
502  // purge unused triangle surface memory
504 }
505 
506 /*
507 =================
508 idRenderModelManagerLocal::EndLevelLoad
509 =================
510 */
512  common->Printf( "----- idRenderModelManagerLocal::EndLevelLoad -----\n" );
513 
514  int start = Sys_Milliseconds();
515 
516  insideLevelLoad = false;
517  int purgeCount = 0;
518  int keepCount = 0;
519  int loadCount = 0;
520 
521  // purge any models not touched
522  for ( int i = 0 ; i < models.Num() ; i++ ) {
523  idRenderModel *model = models[i];
524 
525  if ( !model->IsLevelLoadReferenced() && model->IsLoaded() && model->IsReloadable() ) {
526 
527 // common->Printf( "purging %s\n", model->Name() );
528 
529  purgeCount++;
530 
532 
533  model->PurgeModel();
534 
535  } else {
536 
537 // common->Printf( "keeping %s\n", model->Name() );
538 
539  keepCount++;
540  }
541  }
542 
543  // purge unused triangle surface memory
545 
546  // load any new ones
547  for ( int i = 0 ; i < models.Num() ; i++ ) {
548  idRenderModel *model = models[i];
549 
550  if ( model->IsLevelLoadReferenced() && !model->IsLoaded() && model->IsReloadable() ) {
551 
552  loadCount++;
553  model->LoadModel();
554 
555  if ( ( loadCount & 15 ) == 0 ) {
557  }
558  }
559  }
560 
561  // _D3XP added this
562  int end = Sys_Milliseconds();
563  common->Printf( "%5i models purged from previous level, ", purgeCount );
564  common->Printf( "%5i models kept.\n", keepCount );
565  if ( loadCount ) {
566  common->Printf( "%5i new models loaded in %5.1f seconds\n", loadCount, (end-start) * 0.001 );
567  }
568  common->Printf( "---------------------------------------------------\n" );
569 }
570 
571 /*
572 =================
573 idRenderModelManagerLocal::PrintMemInfo
574 =================
575 */
577  int i, j, totalMem = 0;
578  int *sortIndex;
579  idFile *f;
580 
581  f = fileSystem->OpenFileWrite( mi->filebase + "_models.txt" );
582  if ( !f ) {
583  return;
584  }
585 
586  // sort first
587  sortIndex = new int[ localModelManager.models.Num()];
588 
589  for ( i = 0; i < localModelManager.models.Num(); i++ ) {
590  sortIndex[i] = i;
591  }
592 
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];
598  sortIndex[j] = temp;
599  }
600  }
601  }
602 
603  // print next
604  for ( int i = 0 ; i < localModelManager.models.Num() ; i++ ) {
605  idRenderModel *model = localModelManager.models[sortIndex[i]];
606  int mem;
607 
608  if ( !model->IsLoaded() ) {
609  continue;
610  }
611 
612  mem = model->Memory();
613  totalMem += mem;
614  f->Printf( "%s %s\n", idStr::FormatNumber( mem ).c_str(), model->Name() );
615  }
616 
617  delete sortIndex;
618  mi->modelAssetsTotal = totalMem;
619 
620  f->Printf( "\nTotal model bytes allocated: %s\n", idStr::FormatNumber( totalMem ).c_str() );
621  fileSystem->CloseFile( f );
622 }
virtual idRenderModel * DefaultModel()
virtual void SetLevelLoadReferenced(bool referenced)=0
virtual int Memory() const =0
virtual void ReloadModels(bool forceAll=false)
int Next(const int index) const
Definition: HashIndex.h:247
void ToLower(void)
Definition: Str.h:817
virtual void Print() const =0
virtual int ReadFile(const char *relativePath, void **buffer, ID_TIME_T *timestamp=NULL)=0
int Length(void) const
Definition: Str.h:702
idCVar com_purgeAll("com_purgeAll","0", CVAR_BOOL|CVAR_ARCHIVE|CVAR_SYSTEM,"purge everything between level loads")
virtual void TouchData()=0
virtual bool IsLevelLoadReferenced()=0
int Sys_Milliseconds(void)
static void ArgCompletion_ModelName(const idCmdArgs &args, void(*callback)(const char *s))
Definition: CmdSystem.h:160
idFileSystem * fileSystem
Definition: FileSystem.cpp:500
virtual void SetLevelLoadReferenced(bool referenced)
Definition: Model.cpp:2250
virtual void BeginLevelLoad()
virtual void AddModel(idRenderModel *model)
virtual void FreeModel(idRenderModel *model)
virtual const char * Name() const =0
idRenderModel * spriteModel
idCmdSystem * cmdSystem
Definition: CmdSystem.cpp:116
virtual bool IsReloadable() const =0
frameData_t * frameData
Definition: tr_backend.cpp:34
void RemoveIndex(const int key, const int index)
Definition: HashIndex.h:294
virtual void FreeVertexCache()=0
int i
Definition: process.py:33
void MakeDefaultModel()
Definition: Model.cpp:229
void Free(void)
Definition: HashIndex.cpp:75
virtual void PurgeModel()=0
int Icmp(const char *text) const
Definition: Str.h:667
void R_CheckForEntityDefsUsingModel(idRenderModel *model)
int First(const int key) const
Definition: HashIndex.h:238
virtual idRenderModel * FindModel(const char *modelName)
void R_ReCreateWorldReferences(void)
Definition: File.h:50
virtual void WritePrecacheCommands(idFile *file)
virtual void InitEmpty(const char *name)
Definition: Model.cpp:332
GLuint index
Definition: glext.h:3476
static idStr FormatNumber(int number)
Definition: Str.cpp:1682
static void TouchModel_f(const idCmdArgs &args)
GLuint GLuint end
Definition: glext.h:2845
virtual void List() const =0
idCommon * common
Definition: Common.cpp:206
#define NULL
Definition: Lib.h:88
virtual idRenderModel * AllocModel()
idList< idRenderModel * > models
virtual idFile * OpenFileWrite(const char *relativePath, const char *basePath="fs_savepath")=0
static void ReloadModels_f(const idCmdArgs &args)
idRenderModel * defaultModel
virtual idRenderModel * CheckModel(const char *modelName)
int Argc(void) const
Definition: CmdArgs.h:48
void DeleteContents(bool clear)
Definition: List.h:207
virtual void RemoveModel(idRenderModel *model)
virtual void UpdateScreen(bool outOfSequence=true)=0
virtual void Printf(const char *fmt,...) id_attribute((format(printf
idStr filebase
Definition: Common.h:94
virtual void LoadModel()=0
int modelAssetsTotal
Definition: Common.h:108
static void ListModels_f(const idCmdArgs &args)
int GenerateKey(const char *string, bool caseSensitive=true) const
Definition: HashIndex.h:379
virtual void InitFromFile(const char *fileName)=0
int Append(const type &obj)
Definition: List.h:646
idRenderModel * beamModel
void R_FreeDerivedData(void)
idRenderModelManager * renderModelManager
virtual bool IsDefaultModel() const =0
virtual void PacifierUpdate()=0
bool GetBool(void) const
Definition: CVarSystem.h:142
virtual bool IsLoaded()=0
tuple f
Definition: idal.py:89
virtual void PrintMemInfo(MemInfo_t *mi)
#define MD5_MESH_EXT
Definition: Model.h:42
int Num(void) const
Definition: List.h:265
bool RemoveIndex(int index)
Definition: List.h:849
static void PrintModel_f(const idCmdArgs &args)
Definition: Str.h:116
const char * c_str(void) const
Definition: Str.h:487
void R_PurgeTriSurfData(frameData_t *frame)
Definition: tr_trisurf.cpp:208
int FindIndex(const type &obj) const
Definition: List.h:761
const char * Argv(int arg) const
Definition: CmdArgs.h:50
idRenderModelManagerLocal localModelManager
void Add(const int key, const int index)
Definition: HashIndex.h:193
GLint j
Definition: qgl.h:264
virtual idRenderModel * CheckModel(const char *modelName)=0
idRenderModel * trailModel
idSession * session
Definition: Session.cpp:48
virtual void FreeModelVertexCaches()
void ExtractFileExtension(idStr &dest) const
Definition: Str.cpp:965
virtual void CloseFile(idFile *f)=0
virtual void DPrintf(const char *fmt,...) id_attribute((format(printf
virtual void Error(const char *fmt,...) id_attribute((format(printf
virtual void virtual void Warning(const char *fmt,...) id_attribute((format(printf
int sprintf(idStr &string, const char *fmt,...)
Definition: Str.cpp:1528
virtual int Printf(const char *fmt,...) id_attribute((format(printf
Definition: File.cpp:260
virtual ~idRenderModelManagerLocal()
GLuint start
Definition: glext.h:2845
virtual void AddCommand(const char *cmdName, cmdFunction_t function, int flags, const char *description, argCompletion_t argCompletion=NULL)=0
idRenderModel * GetModel(const char *modelName, bool createIfNotFound)