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 "sys/platform.h"
30 #include "framework/CVarSystem.h"
31 #include "framework/Session.h"
32 #include "renderer/RenderWorld.h"
33 #include "renderer/Model_local.h"
34 #include "renderer/tr_local.h"	// just for R_FreeWorldInteractions and R_CreateWorldInteractions
35 
36 #include "renderer/ModelManager.h"
37 
38 class idRenderModelManagerLocal : public idRenderModelManager {
39 public:
40 							idRenderModelManagerLocal();
~idRenderModelManagerLocal()41 	virtual					~idRenderModelManagerLocal() {}
42 
43 	virtual void			Init();
44 	virtual void			Shutdown();
45 	virtual idRenderModel *	AllocModel();
46 	virtual void			FreeModel( idRenderModel *model );
47 	virtual idRenderModel *	FindModel( const char *modelName );
48 	virtual idRenderModel *	CheckModel( const char *modelName );
49 	virtual idRenderModel *	DefaultModel();
50 	virtual void			AddModel( idRenderModel *model );
51 	virtual void			RemoveModel( idRenderModel *model );
52 	virtual void			ReloadModels( bool forceAll = false );
53 	virtual void			FreeModelVertexCaches();
54 	virtual void			WritePrecacheCommands( idFile *file );
55 	virtual void			BeginLevelLoad();
56 	virtual void			EndLevelLoad();
57 
58 	virtual	void			PrintMemInfo( MemInfo_t *mi );
59 
60 private:
61 	idList<idRenderModel*>	models;
62 	idHashIndex				hash;
63 	idRenderModel *			defaultModel;
64 	idRenderModel *			beamModel;
65 	idRenderModel *			spriteModel;
66 	idRenderModel *			trailModel;
67 	bool					insideLevelLoad;		// don't actually load now
68 
69 	idRenderModel *			GetModel( const char *modelName, bool createIfNotFound );
70 
71 	static void				PrintModel_f( const idCmdArgs &args );
72 	static void				ListModels_f( const idCmdArgs &args );
73 	static void				ReloadModels_f( const idCmdArgs &args );
74 	static void				TouchModel_f( const idCmdArgs &args );
75 };
76 
77 
78 idRenderModelManagerLocal	localModelManager;
79 idRenderModelManager *		renderModelManager = &localModelManager;
80 
81 /*
82 ==============
83 idRenderModelManagerLocal::idRenderModelManagerLocal
84 ==============
85 */
idRenderModelManagerLocal()86 idRenderModelManagerLocal::idRenderModelManagerLocal() {
87 	defaultModel = NULL;
88 	beamModel = NULL;
89 	spriteModel = NULL;
90 	insideLevelLoad = false;
91 	trailModel = NULL;
92 }
93 
94 /*
95 ==============
96 idRenderModelManagerLocal::PrintModel_f
97 ==============
98 */
PrintModel_f(const idCmdArgs & args)99 void idRenderModelManagerLocal::PrintModel_f( const idCmdArgs &args ) {
100 	idRenderModel	*model;
101 
102 	if ( args.Argc() != 2 ) {
103 		common->Printf( "usage: printModel <modelName>\n" );
104 		return;
105 	}
106 
107 	model = renderModelManager->CheckModel( args.Argv( 1 ) );
108 	if ( !model ) {
109 		common->Printf( "model \"%s\" not found\n", args.Argv( 1 ) );
110 		return;
111 	}
112 
113 	model->Print();
114 }
115 
116 /*
117 ==============
118 idRenderModelManagerLocal::ListModels_f
119 ==============
120 */
ListModels_f(const idCmdArgs & args)121 void idRenderModelManagerLocal::ListModels_f( const idCmdArgs &args ) {
122 	int		totalMem = 0;
123 	int		inUse = 0;
124 
125 	common->Printf( " mem   srf verts tris\n" );
126 	common->Printf( " ---   --- ----- ----\n" );
127 
128 	for ( int i = 0 ; i < localModelManager.models.Num() ; i++ ) {
129 		idRenderModel	*model = localModelManager.models[i];
130 
131 		if ( !model->IsLoaded() ) {
132 			continue;
133 		}
134 		model->List();
135 		totalMem += model->Memory();
136 		inUse++;
137 	}
138 
139 	common->Printf( " ---   --- ----- ----\n" );
140 	common->Printf( " mem   srf verts tris\n" );
141 
142 	common->Printf( "%i loaded models\n", inUse );
143 	common->Printf( "total memory: %4.1fM\n", (float)totalMem / (1024*1024) );
144 }
145 
146 /*
147 ==============
148 idRenderModelManagerLocal::ReloadModels_f
149 ==============
150 */
ReloadModels_f(const idCmdArgs & args)151 void idRenderModelManagerLocal::ReloadModels_f( const idCmdArgs &args ) {
152 	if ( idStr::Icmp( args.Argv(1), "all" ) == 0 ) {
153 		localModelManager.ReloadModels( true );
154 	} else {
155 		localModelManager.ReloadModels( false );
156 	}
157 }
158 
159 /*
160 ==============
161 idRenderModelManagerLocal::TouchModel_f
162 
163 Precache a specific model
164 ==============
165 */
TouchModel_f(const idCmdArgs & args)166 void idRenderModelManagerLocal::TouchModel_f( const idCmdArgs &args ) {
167 	const char	*model = args.Argv( 1 );
168 
169 	if ( !model[0] ) {
170 		common->Printf( "usage: touchModel <modelName>\n" );
171 		return;
172 	}
173 
174 	common->Printf( "touchModel %s\n", model );
175 	session->UpdateScreen();
176 	idRenderModel *m = renderModelManager->CheckModel( model );
177 	if ( !m ) {
178 		common->Printf( "...not found\n" );
179 	}
180 }
181 
182 /*
183 =================
184 idRenderModelManagerLocal::WritePrecacheCommands
185 =================
186 */
WritePrecacheCommands(idFile * f)187 void idRenderModelManagerLocal::WritePrecacheCommands( idFile *f ) {
188 	for ( int i = 0 ; i < models.Num() ; i++ ) {
189 		idRenderModel	*model = models[i];
190 
191 		if ( !model ) {
192 			continue;
193 		}
194 		if ( !model->IsReloadable() ) {
195 			continue;
196 		}
197 
198 		char	str[1024];
199 		sprintf( str, "touchModel %s\n", model->Name() );
200 		common->Printf( "%s", str );
201 		f->Printf( "%s", str );
202 	}
203 }
204 
205 /*
206 =================
207 idRenderModelManagerLocal::Init
208 =================
209 */
Init()210 void idRenderModelManagerLocal::Init() {
211 	cmdSystem->AddCommand( "listModels", ListModels_f, CMD_FL_RENDERER, "lists all models" );
212 	cmdSystem->AddCommand( "printModel", PrintModel_f, CMD_FL_RENDERER, "prints model info", idCmdSystem::ArgCompletion_ModelName );
213 	cmdSystem->AddCommand( "reloadModels", ReloadModels_f, CMD_FL_RENDERER|CMD_FL_CHEAT, "reloads models" );
214 	cmdSystem->AddCommand( "touchModel", TouchModel_f, CMD_FL_RENDERER, "touches a model", idCmdSystem::ArgCompletion_ModelName );
215 
216 	insideLevelLoad = false;
217 
218 	// create a default model
219 	idRenderModelStatic *model = new idRenderModelStatic;
220 	model->InitEmpty( "_DEFAULT" );
221 	model->MakeDefaultModel();
222 	model->SetLevelLoadReferenced( true );
223 	defaultModel = model;
224 	AddModel( model );
225 
226 	// create the beam model
227 	idRenderModelStatic *beam = new idRenderModelBeam;
228 	beam->InitEmpty( "_BEAM" );
229 	beam->SetLevelLoadReferenced( true );
230 	beamModel = beam;
231 	AddModel( beam );
232 
233 	idRenderModelStatic *sprite = new idRenderModelSprite;
234 	sprite->InitEmpty( "_SPRITE" );
235 	sprite->SetLevelLoadReferenced( true );
236 	spriteModel = sprite;
237 	AddModel( sprite );
238 }
239 
240 /*
241 =================
242 idRenderModelManagerLocal::Shutdown
243 =================
244 */
Shutdown()245 void idRenderModelManagerLocal::Shutdown() {
246 	models.DeleteContents( true );
247 	hash.Free();
248 }
249 
250 /*
251 =================
252 idRenderModelManagerLocal::GetModel
253 =================
254 */
GetModel(const char * modelName,bool createIfNotFound)255 idRenderModel *idRenderModelManagerLocal::GetModel( const char *modelName, bool createIfNotFound ) {
256 	idStr		canonical;
257 	idStr		extension;
258 
259 	if ( !modelName || !modelName[0] ) {
260 		return NULL;
261 	}
262 
263 	canonical = modelName;
264 	canonical.ToLower();
265 
266 	// see if it is already present
267 	int key = hash.GenerateKey( modelName, false );
268 	for ( int i = hash.First( key ); i != -1; i = hash.Next( i ) ) {
269 		idRenderModel *model = models[i];
270 
271 		if ( canonical.Icmp( model->Name() ) == 0 ) {
272 			if ( !model->IsLoaded() ) {
273 				// reload it if it was purged
274 				model->LoadModel();
275 			} else if ( insideLevelLoad && !model->IsLevelLoadReferenced() ) {
276 				// we are reusing a model already in memory, but
277 				// touch all the materials to make sure they stay
278 				// in memory as well
279 				model->TouchData();
280 			}
281 			model->SetLevelLoadReferenced( true );
282 			return model;
283 		}
284 	}
285 
286 	// see if we can load it
287 
288 	// determine which subclass of idRenderModel to initialize
289 
290 	idRenderModel	*model;
291 
292 	canonical.ExtractFileExtension( extension );
293 
294 	if ( ( extension.Icmp( "ase" ) == 0 ) || ( extension.Icmp( "lwo" ) == 0 ) || ( extension.Icmp( "flt" ) == 0 ) ) {
295 		model = new idRenderModelStatic;
296 		model->InitFromFile( modelName );
297 	} else if ( extension.Icmp( "ma" ) == 0 ) {
298 		model = new idRenderModelStatic;
299 		model->InitFromFile( modelName );
300 	} else if ( extension.Icmp( MD5_MESH_EXT ) == 0 ) {
301 		model = new idRenderModelMD5;
302 		model->InitFromFile( modelName );
303 	} else if ( extension.Icmp( "md3" ) == 0 ) {
304 		model = new idRenderModelMD3;
305 		model->InitFromFile( modelName );
306 	} else if ( extension.Icmp( "prt" ) == 0  ) {
307 		model = new idRenderModelPrt;
308 		model->InitFromFile( modelName );
309 	} else if ( extension.Icmp( "liquid" ) == 0  ) {
310 		model = new idRenderModelLiquid;
311 		model->InitFromFile( modelName );
312 	} else {
313 
314 		if ( extension.Length() ) {
315 			common->Warning( "unknown model type '%s'", canonical.c_str() );
316 		}
317 
318 		if ( !createIfNotFound ) {
319 			return NULL;
320 		}
321 
322 		idRenderModelStatic	*smodel = new idRenderModelStatic;
323 		smodel->InitEmpty( modelName );
324 		smodel->MakeDefaultModel();
325 
326 		model = smodel;
327 	}
328 
329 	model->SetLevelLoadReferenced( true );
330 
331 	if ( !createIfNotFound && model->IsDefaultModel() ) {
332 		delete model;
333 		model = NULL;
334 
335 		return NULL;
336 	}
337 
338 	AddModel( model );
339 
340 	return model;
341 }
342 
343 /*
344 =================
345 idRenderModelManagerLocal::AllocModel
346 =================
347 */
AllocModel()348 idRenderModel *idRenderModelManagerLocal::AllocModel() {
349 	return new idRenderModelStatic();
350 }
351 
352 /*
353 =================
354 idRenderModelManagerLocal::FreeModel
355 =================
356 */
FreeModel(idRenderModel * model)357 void idRenderModelManagerLocal::FreeModel( idRenderModel *model ) {
358 	if ( !model ) {
359 		return;
360 	}
361 	if ( !dynamic_cast<idRenderModelStatic *>( model ) ) {
362 		common->Error( "idRenderModelManager::FreeModel: model '%s' is not a static model", model->Name() );
363 		return;
364 	}
365 	if ( model == defaultModel ) {
366 		common->Error( "idRenderModelManager::FreeModel: can't free the default model" );
367 		return;
368 	}
369 	if ( model == beamModel ) {
370 		common->Error( "idRenderModelManager::FreeModel: can't free the beam model" );
371 		return;
372 	}
373 	if ( model == spriteModel ) {
374 		common->Error( "idRenderModelManager::FreeModel: can't free the sprite model" );
375 		return;
376 	}
377 
378 	R_CheckForEntityDefsUsingModel( model );
379 
380 	delete model;
381 }
382 
383 /*
384 =================
385 idRenderModelManagerLocal::FindModel
386 =================
387 */
FindModel(const char * modelName)388 idRenderModel *idRenderModelManagerLocal::FindModel( const char *modelName ) {
389 	return GetModel( modelName, true );
390 }
391 
392 /*
393 =================
394 idRenderModelManagerLocal::CheckModel
395 =================
396 */
CheckModel(const char * modelName)397 idRenderModel *idRenderModelManagerLocal::CheckModel( const char *modelName ) {
398 	return GetModel( modelName, false );
399 }
400 
401 /*
402 =================
403 idRenderModelManagerLocal::DefaultModel
404 =================
405 */
DefaultModel()406 idRenderModel *idRenderModelManagerLocal::DefaultModel() {
407 	return defaultModel;
408 }
409 
410 /*
411 =================
412 idRenderModelManagerLocal::AddModel
413 =================
414 */
AddModel(idRenderModel * model)415 void idRenderModelManagerLocal::AddModel( idRenderModel *model ) {
416 	hash.Add( hash.GenerateKey( model->Name(), false ), models.Append( model ) );
417 }
418 
419 /*
420 =================
421 idRenderModelManagerLocal::RemoveModel
422 =================
423 */
RemoveModel(idRenderModel * model)424 void idRenderModelManagerLocal::RemoveModel( idRenderModel *model ) {
425 	int index = models.FindIndex( model );
426 	hash.RemoveIndex( hash.GenerateKey( model->Name(), false ), index );
427 	models.RemoveIndex( index );
428 }
429 
430 /*
431 =================
432 idRenderModelManagerLocal::ReloadModels
433 =================
434 */
ReloadModels(bool forceAll)435 void idRenderModelManagerLocal::ReloadModels( bool forceAll ) {
436 	if ( forceAll ) {
437 		common->Printf( "Reloading all model files...\n" );
438 	} else {
439 		common->Printf( "Checking for changed model files...\n" );
440 	}
441 
442 	R_FreeDerivedData();
443 
444 	// skip the default model at index 0
445 	for ( int i = 1 ; i < models.Num() ; i++ ) {
446 		idRenderModel	*model = models[i];
447 
448 		// we may want to allow world model reloading in the future, but we don't now
449 		if ( !model->IsReloadable() ) {
450 			continue;
451 		}
452 
453 		if ( !forceAll ) {
454 			// check timestamp
455 			ID_TIME_T current;
456 
457 			fileSystem->ReadFile( model->Name(), NULL, &current );
458 			if ( current <= model->Timestamp() ) {
459 				continue;
460 			}
461 		}
462 
463 		common->DPrintf( "reloading %s.\n", model->Name() );
464 
465 		model->LoadModel();
466 	}
467 
468 	// we must force the world to regenerate, because models may
469 	// have changed size, making their references invalid
470 	R_ReCreateWorldReferences();
471 }
472 
473 /*
474 =================
475 idRenderModelManagerLocal::FreeModelVertexCaches
476 =================
477 */
FreeModelVertexCaches()478 void idRenderModelManagerLocal::FreeModelVertexCaches() {
479 	for ( int i = 0 ; i < models.Num() ; i++ ) {
480 		idRenderModel *model = models[i];
481 		model->FreeVertexCache();
482 	}
483 }
484 
485 /*
486 =================
487 idRenderModelManagerLocal::BeginLevelLoad
488 =================
489 */
BeginLevelLoad()490 void idRenderModelManagerLocal::BeginLevelLoad() {
491 	insideLevelLoad = true;
492 
493 	for ( int i = 0 ; i < models.Num() ; i++ ) {
494 		idRenderModel *model = models[i];
495 
496 		if ( com_purgeAll.GetBool() && model->IsReloadable() ) {
497 			R_CheckForEntityDefsUsingModel( model );
498 			model->PurgeModel();
499 		}
500 
501 		model->SetLevelLoadReferenced( false );
502 	}
503 
504 	// purge unused triangle surface memory
505 	R_PurgeTriSurfData( frameData );
506 }
507 
508 /*
509 =================
510 idRenderModelManagerLocal::EndLevelLoad
511 =================
512 */
EndLevelLoad()513 void idRenderModelManagerLocal::EndLevelLoad() {
514 	common->Printf( "----- idRenderModelManagerLocal::EndLevelLoad -----\n" );
515 
516 	int start = Sys_Milliseconds();
517 
518 	insideLevelLoad = false;
519 	int	purgeCount = 0;
520 	int	keepCount = 0;
521 	int	loadCount = 0;
522 
523 	// purge any models not touched
524 	for ( int i = 0 ; i < models.Num() ; i++ ) {
525 		idRenderModel *model = models[i];
526 
527 		if ( !model->IsLevelLoadReferenced() && model->IsLoaded() && model->IsReloadable() ) {
528 
529 //			common->Printf( "purging %s\n", model->Name() );
530 
531 			purgeCount++;
532 
533 			R_CheckForEntityDefsUsingModel( model );
534 
535 			model->PurgeModel();
536 
537 		} else {
538 
539 //			common->Printf( "keeping %s\n", model->Name() );
540 
541 			keepCount++;
542 		}
543 	}
544 
545 	// purge unused triangle surface memory
546 	R_PurgeTriSurfData( frameData );
547 
548 	// load any new ones
549 	for ( int i = 0 ; i < models.Num() ; i++ ) {
550 		idRenderModel *model = models[i];
551 
552 		if ( model->IsLevelLoadReferenced() && !model->IsLoaded() && model->IsReloadable() ) {
553 
554 			loadCount++;
555 			model->LoadModel();
556 
557 			if ( ( loadCount & 15 ) == 0 ) {
558 				session->PacifierUpdate();
559 			}
560 		}
561 	}
562 
563 	// _D3XP added this
564 	int	end = Sys_Milliseconds();
565 	common->Printf( "%5i models purged from previous level, ", purgeCount );
566 	common->Printf( "%5i models kept.\n", keepCount );
567 	if ( loadCount ) {
568 		common->Printf( "%5i new models loaded in %5.1f seconds\n", loadCount, (end-start) * 0.001 );
569 	}
570 }
571 
572 /*
573 =================
574 idRenderModelManagerLocal::PrintMemInfo
575 =================
576 */
PrintMemInfo(MemInfo_t * mi)577 void idRenderModelManagerLocal::PrintMemInfo( MemInfo_t *mi ) {
578 	int i, j, totalMem = 0;
579 	int *sortIndex;
580 	idFile *f;
581 
582 	f = fileSystem->OpenFileWrite( mi->filebase + "_models.txt" );
583 	if ( !f ) {
584 		return;
585 	}
586 
587 	// sort first
588 	sortIndex = new int[ localModelManager.models.Num()];
589 
590 	for ( i = 0; i <  localModelManager.models.Num(); i++ ) {
591 		sortIndex[i] = i;
592 	}
593 
594 	for ( i = 0; i <  localModelManager.models.Num() - 1; i++ ) {
595 		for ( j = i + 1; j <  localModelManager.models.Num(); j++ ) {
596 			if (  localModelManager.models[sortIndex[i]]->Memory() <  localModelManager.models[sortIndex[j]]->Memory() ) {
597 				int temp = sortIndex[i];
598 				sortIndex[i] = sortIndex[j];
599 				sortIndex[j] = temp;
600 			}
601 		}
602 	}
603 
604 	// print next
605 	for ( int i = 0 ; i < localModelManager.models.Num() ; i++ ) {
606 		idRenderModel	*model = localModelManager.models[sortIndex[i]];
607 		int mem;
608 
609 		if ( !model->IsLoaded() ) {
610 			continue;
611 		}
612 
613 		mem = model->Memory();
614 		totalMem += mem;
615 		f->Printf( "%s %s\n", idStr::FormatNumber( mem ).c_str(), model->Name() );
616 	}
617 
618 	delete sortIndex;
619 	mi->modelAssetsTotal = totalMem;
620 
621 	f->Printf( "\nTotal model bytes allocated: %s\n", idStr::FormatNumber( totalMem ).c_str() );
622 	fileSystem->CloseFile( f );
623 }
624