ModelManager.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 BFG Edition 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 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
  17. 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.
  18. ===========================================================================
  19. */
  20. #pragma hdrstop
  21. #include "../idlib/precompiled.h"
  22. #include "Model_local.h"
  23. #include "tr_local.h" // just for R_FreeWorldInteractions and R_CreateWorldInteractions
  24. idCVar r_binaryLoadRenderModels( "r_binaryLoadRenderModels", "1", 0, "enable binary load/write of render models" );
  25. idCVar preload_MapModels( "preload_MapModels", "1", CVAR_SYSTEM | CVAR_BOOL, "preload models during begin or end levelload" );
  26. class idRenderModelManagerLocal : public idRenderModelManager {
  27. public:
  28. idRenderModelManagerLocal();
  29. virtual ~idRenderModelManagerLocal() {}
  30. virtual void Init();
  31. virtual void Shutdown();
  32. virtual idRenderModel * AllocModel();
  33. virtual void FreeModel( idRenderModel *model );
  34. virtual idRenderModel * FindModel( const char *modelName );
  35. virtual idRenderModel * CheckModel( const char *modelName );
  36. virtual idRenderModel * DefaultModel();
  37. virtual void AddModel( idRenderModel *model );
  38. virtual void RemoveModel( idRenderModel *model );
  39. virtual void ReloadModels( bool forceAll = false );
  40. virtual void FreeModelVertexCaches();
  41. virtual void WritePrecacheCommands( idFile *file );
  42. virtual void BeginLevelLoad();
  43. virtual void EndLevelLoad();
  44. virtual void Preload( const idPreloadManifest &manifest );
  45. virtual void PrintMemInfo( MemInfo_t *mi );
  46. private:
  47. idList<idRenderModel*, TAG_MODEL> models;
  48. idHashIndex hash;
  49. idRenderModel * defaultModel;
  50. idRenderModel * beamModel;
  51. idRenderModel * spriteModel;
  52. bool insideLevelLoad; // don't actually load now
  53. idRenderModel * GetModel( const char *modelName, bool createIfNotFound );
  54. static void PrintModel_f( const idCmdArgs &args );
  55. static void ListModels_f( const idCmdArgs &args );
  56. static void ReloadModels_f( const idCmdArgs &args );
  57. static void TouchModel_f( const idCmdArgs &args );
  58. };
  59. idRenderModelManagerLocal localModelManager;
  60. idRenderModelManager * renderModelManager = &localModelManager;
  61. /*
  62. ==============
  63. idRenderModelManagerLocal::idRenderModelManagerLocal
  64. ==============
  65. */
  66. idRenderModelManagerLocal::idRenderModelManagerLocal() {
  67. defaultModel = NULL;
  68. beamModel = NULL;
  69. spriteModel = NULL;
  70. insideLevelLoad = false;
  71. }
  72. /*
  73. ==============
  74. idRenderModelManagerLocal::PrintModel_f
  75. ==============
  76. */
  77. void idRenderModelManagerLocal::PrintModel_f( const idCmdArgs &args ) {
  78. idRenderModel *model;
  79. if ( args.Argc() != 2 ) {
  80. common->Printf( "usage: printModel <modelName>\n" );
  81. return;
  82. }
  83. model = renderModelManager->CheckModel( args.Argv( 1 ) );
  84. if ( !model ) {
  85. common->Printf( "model \"%s\" not found\n", args.Argv( 1 ) );
  86. return;
  87. }
  88. model->Print();
  89. }
  90. /*
  91. ==============
  92. idRenderModelManagerLocal::ListModels_f
  93. ==============
  94. */
  95. void idRenderModelManagerLocal::ListModels_f( const idCmdArgs &args ) {
  96. int totalMem = 0;
  97. int inUse = 0;
  98. common->Printf( " mem srf verts tris\n" );
  99. common->Printf( " --- --- ----- ----\n" );
  100. for ( int i = 0; i < localModelManager.models.Num(); i++ ) {
  101. idRenderModel *model = localModelManager.models[i];
  102. if ( !model->IsLoaded() ) {
  103. continue;
  104. }
  105. model->List();
  106. totalMem += model->Memory();
  107. inUse++;
  108. }
  109. common->Printf( " --- --- ----- ----\n" );
  110. common->Printf( " mem srf verts tris\n" );
  111. common->Printf( "%i loaded models\n", inUse );
  112. common->Printf( "total memory: %4.1fM\n", (float)totalMem / (1024*1024) );
  113. }
  114. /*
  115. ==============
  116. idRenderModelManagerLocal::ReloadModels_f
  117. ==============
  118. */
  119. void idRenderModelManagerLocal::ReloadModels_f( const idCmdArgs &args ) {
  120. if ( idStr::Icmp( args.Argv(1), "all" ) == 0 ) {
  121. localModelManager.ReloadModels( true );
  122. } else {
  123. localModelManager.ReloadModels( false );
  124. }
  125. }
  126. /*
  127. ==============
  128. idRenderModelManagerLocal::TouchModel_f
  129. Precache a specific model
  130. ==============
  131. */
  132. void idRenderModelManagerLocal::TouchModel_f( const idCmdArgs &args ) {
  133. const char *model = args.Argv( 1 );
  134. if ( !model[0] ) {
  135. common->Printf( "usage: touchModel <modelName>\n" );
  136. return;
  137. }
  138. common->Printf( "touchModel %s\n", model );
  139. const bool captureToImage = false;
  140. common->UpdateScreen( captureToImage );
  141. idRenderModel *m = renderModelManager->CheckModel( model );
  142. if ( !m ) {
  143. common->Printf( "...not found\n" );
  144. }
  145. }
  146. /*
  147. =================
  148. idRenderModelManagerLocal::WritePrecacheCommands
  149. =================
  150. */
  151. void idRenderModelManagerLocal::WritePrecacheCommands( idFile *f ) {
  152. for ( int i = 0; i < models.Num(); i++ ) {
  153. idRenderModel *model = models[i];
  154. if ( !model ) {
  155. continue;
  156. }
  157. if ( !model->IsReloadable() ) {
  158. continue;
  159. }
  160. char str[1024];
  161. sprintf( str, "touchModel %s\n", model->Name() );
  162. common->Printf( "%s", str );
  163. f->Printf( "%s", str );
  164. }
  165. }
  166. /*
  167. =================
  168. idRenderModelManagerLocal::Init
  169. =================
  170. */
  171. void idRenderModelManagerLocal::Init() {
  172. cmdSystem->AddCommand( "listModels", ListModels_f, CMD_FL_RENDERER, "lists all models" );
  173. cmdSystem->AddCommand( "printModel", PrintModel_f, CMD_FL_RENDERER, "prints model info", idCmdSystem::ArgCompletion_ModelName );
  174. cmdSystem->AddCommand( "reloadModels", ReloadModels_f, CMD_FL_RENDERER|CMD_FL_CHEAT, "reloads models" );
  175. cmdSystem->AddCommand( "touchModel", TouchModel_f, CMD_FL_RENDERER, "touches a model", idCmdSystem::ArgCompletion_ModelName );
  176. insideLevelLoad = false;
  177. // create a default model
  178. idRenderModelStatic *model = new (TAG_MODEL) idRenderModelStatic;
  179. model->InitEmpty( "_DEFAULT" );
  180. model->MakeDefaultModel();
  181. model->SetLevelLoadReferenced( true );
  182. defaultModel = model;
  183. AddModel( model );
  184. // create the beam model
  185. idRenderModelStatic *beam = new (TAG_MODEL) idRenderModelBeam;
  186. beam->InitEmpty( "_BEAM" );
  187. beam->SetLevelLoadReferenced( true );
  188. beamModel = beam;
  189. AddModel( beam );
  190. idRenderModelStatic *sprite = new (TAG_MODEL) idRenderModelSprite;
  191. sprite->InitEmpty( "_SPRITE" );
  192. sprite->SetLevelLoadReferenced( true );
  193. spriteModel = sprite;
  194. AddModel( sprite );
  195. }
  196. /*
  197. =================
  198. idRenderModelManagerLocal::Shutdown
  199. =================
  200. */
  201. void idRenderModelManagerLocal::Shutdown() {
  202. models.DeleteContents( true );
  203. hash.Free();
  204. }
  205. /*
  206. =================
  207. idRenderModelManagerLocal::GetModel
  208. =================
  209. */
  210. idRenderModel *idRenderModelManagerLocal::GetModel( const char *_modelName, bool createIfNotFound ) {
  211. if ( !_modelName || !_modelName[0] ) {
  212. return NULL;
  213. }
  214. idStrStatic< MAX_OSPATH > canonical = _modelName;
  215. canonical.ToLower();
  216. idStrStatic< MAX_OSPATH > extension;
  217. canonical.ExtractFileExtension( extension );
  218. // see if it is already present
  219. int key = hash.GenerateKey( canonical, false );
  220. for ( int i = hash.First( key ); i != -1; i = hash.Next( i ) ) {
  221. idRenderModel *model = models[i];
  222. if ( canonical.Icmp( model->Name() ) == 0 ) {
  223. if ( !model->IsLoaded() ) {
  224. // reload it if it was purged
  225. idStr generatedFileName = "generated/rendermodels/";
  226. generatedFileName.AppendPath( canonical );
  227. generatedFileName.SetFileExtension( va( "b%s", extension.c_str() ) );
  228. if ( model->SupportsBinaryModel() && r_binaryLoadRenderModels.GetBool() ) {
  229. idFileLocal file( fileSystem->OpenFileReadMemory( generatedFileName ) );
  230. model->PurgeModel();
  231. if ( !model->LoadBinaryModel( file, 0 ) ) {
  232. model->LoadModel();
  233. }
  234. } else {
  235. model->LoadModel();
  236. }
  237. } else if ( insideLevelLoad && !model->IsLevelLoadReferenced() ) {
  238. // we are reusing a model already in memory, but
  239. // touch all the materials to make sure they stay
  240. // in memory as well
  241. model->TouchData();
  242. }
  243. model->SetLevelLoadReferenced( true );
  244. return model;
  245. }
  246. }
  247. // see if we can load it
  248. // determine which subclass of idRenderModel to initialize
  249. idRenderModel * model = NULL;
  250. if ( ( extension.Icmp( "ase" ) == 0 ) || ( extension.Icmp( "lwo" ) == 0 ) || ( extension.Icmp( "flt" ) == 0 ) || ( extension.Icmp( "ma" ) == 0 ) ) {
  251. model = new (TAG_MODEL) idRenderModelStatic;
  252. } else if ( extension.Icmp( MD5_MESH_EXT ) == 0 ) {
  253. model = new (TAG_MODEL) idRenderModelMD5;
  254. } else if ( extension.Icmp( "md3" ) == 0 ) {
  255. model = new (TAG_MODEL) idRenderModelMD3;
  256. } else if ( extension.Icmp( "prt" ) == 0 ) {
  257. model = new (TAG_MODEL) idRenderModelPrt;
  258. } else if ( extension.Icmp( "liquid" ) == 0 ) {
  259. model = new (TAG_MODEL) idRenderModelLiquid;
  260. }
  261. idStrStatic< MAX_OSPATH > generatedFileName;
  262. if ( model != NULL ) {
  263. generatedFileName = "generated/rendermodels/";
  264. generatedFileName.AppendPath( canonical );
  265. generatedFileName.SetFileExtension( va( "b%s", extension.c_str() ) );
  266. // Get the timestamp on the original file, if it's newer than what is stored in binary model, regenerate it
  267. ID_TIME_T sourceTimeStamp = fileSystem->GetTimestamp( canonical );
  268. idFileLocal file( fileSystem->OpenFileReadMemory( generatedFileName ) );
  269. if ( !model->SupportsBinaryModel() || !r_binaryLoadRenderModels.GetBool() ) {
  270. model->InitFromFile( canonical );
  271. } else {
  272. if ( !model->LoadBinaryModel( file, sourceTimeStamp ) ) {
  273. model->InitFromFile( canonical );
  274. idFileLocal outputFile( fileSystem->OpenFileWrite( generatedFileName, "fs_basepath" ) );
  275. idLib::Printf( "Writing %s\n", generatedFileName.c_str() );
  276. model->WriteBinaryModel( outputFile );
  277. } /* else {
  278. idLib::Printf( "loaded binary model %s from file %s\n", model->Name(), generatedFileName.c_str() );
  279. } */
  280. }
  281. }
  282. // Not one of the known formats
  283. if ( model == NULL ) {
  284. if ( extension.Length() ) {
  285. common->Warning( "unknown model type '%s'", canonical.c_str() );
  286. }
  287. if ( !createIfNotFound ) {
  288. return NULL;
  289. }
  290. idRenderModelStatic *smodel = new (TAG_MODEL) idRenderModelStatic;
  291. smodel->InitEmpty( canonical );
  292. smodel->MakeDefaultModel();
  293. model = smodel;
  294. }
  295. if ( cvarSystem->GetCVarBool( "fs_buildresources" ) ) {
  296. fileSystem->AddModelPreload( canonical );
  297. }
  298. model->SetLevelLoadReferenced( true );
  299. if ( !createIfNotFound && model->IsDefaultModel() ) {
  300. delete model;
  301. model = NULL;
  302. return NULL;
  303. }
  304. if ( cvarSystem->GetCVarBool( "fs_buildgame" ) ) {
  305. fileSystem->AddModelPreload( model->Name() );
  306. }
  307. AddModel( model );
  308. return model;
  309. }
  310. /*
  311. =================
  312. idRenderModelManagerLocal::AllocModel
  313. =================
  314. */
  315. idRenderModel *idRenderModelManagerLocal::AllocModel() {
  316. return new (TAG_MODEL) idRenderModelStatic();
  317. }
  318. /*
  319. =================
  320. idRenderModelManagerLocal::FreeModel
  321. =================
  322. */
  323. void idRenderModelManagerLocal::FreeModel( idRenderModel *model ) {
  324. if ( !model ) {
  325. return;
  326. }
  327. if ( !dynamic_cast<idRenderModelStatic *>( model ) ) {
  328. common->Error( "idRenderModelManager::FreeModel: model '%s' is not a static model", model->Name() );
  329. return;
  330. }
  331. if ( model == defaultModel ) {
  332. common->Error( "idRenderModelManager::FreeModel: can't free the default model" );
  333. return;
  334. }
  335. if ( model == beamModel ) {
  336. common->Error( "idRenderModelManager::FreeModel: can't free the beam model" );
  337. return;
  338. }
  339. if ( model == spriteModel ) {
  340. common->Error( "idRenderModelManager::FreeModel: can't free the sprite model" );
  341. return;
  342. }
  343. R_CheckForEntityDefsUsingModel( model );
  344. delete model;
  345. }
  346. /*
  347. =================
  348. idRenderModelManagerLocal::FindModel
  349. =================
  350. */
  351. idRenderModel *idRenderModelManagerLocal::FindModel( const char *modelName ) {
  352. return GetModel( modelName, true );
  353. }
  354. /*
  355. =================
  356. idRenderModelManagerLocal::CheckModel
  357. =================
  358. */
  359. idRenderModel *idRenderModelManagerLocal::CheckModel( const char *modelName ) {
  360. return GetModel( modelName, false );
  361. }
  362. /*
  363. =================
  364. idRenderModelManagerLocal::DefaultModel
  365. =================
  366. */
  367. idRenderModel *idRenderModelManagerLocal::DefaultModel() {
  368. return defaultModel;
  369. }
  370. /*
  371. =================
  372. idRenderModelManagerLocal::AddModel
  373. =================
  374. */
  375. void idRenderModelManagerLocal::AddModel( idRenderModel *model ) {
  376. hash.Add( hash.GenerateKey( model->Name(), false ), models.Append( model ) );
  377. }
  378. /*
  379. =================
  380. idRenderModelManagerLocal::RemoveModel
  381. =================
  382. */
  383. void idRenderModelManagerLocal::RemoveModel( idRenderModel *model ) {
  384. int index = models.FindIndex( model );
  385. if ( index != -1 ) {
  386. hash.RemoveIndex( hash.GenerateKey( model->Name(), false ), index );
  387. models.RemoveIndex( index );
  388. }
  389. }
  390. /*
  391. =================
  392. idRenderModelManagerLocal::ReloadModels
  393. =================
  394. */
  395. void idRenderModelManagerLocal::ReloadModels( bool forceAll ) {
  396. if ( forceAll ) {
  397. common->Printf( "Reloading all model files...\n" );
  398. } else {
  399. common->Printf( "Checking for changed model files...\n" );
  400. }
  401. R_FreeDerivedData();
  402. // skip the default model at index 0
  403. for ( int i = 1; i < models.Num(); i++ ) {
  404. idRenderModel *model = models[i];
  405. // we may want to allow world model reloading in the future, but we don't now
  406. if ( !model->IsReloadable() ) {
  407. continue;
  408. }
  409. if ( !forceAll ) {
  410. // check timestamp
  411. ID_TIME_T current;
  412. fileSystem->ReadFile( model->Name(), NULL, &current );
  413. if ( current <= model->Timestamp() ) {
  414. continue;
  415. }
  416. }
  417. common->DPrintf( "reloading %s.\n", model->Name() );
  418. model->LoadModel();
  419. }
  420. // we must force the world to regenerate, because models may
  421. // have changed size, making their references invalid
  422. R_ReCreateWorldReferences();
  423. }
  424. /*
  425. =================
  426. idRenderModelManagerLocal::FreeModelVertexCaches
  427. =================
  428. */
  429. void idRenderModelManagerLocal::FreeModelVertexCaches() {
  430. for ( int i = 0; i < models.Num(); i++ ) {
  431. idRenderModel *model = models[i];
  432. model->FreeVertexCache();
  433. }
  434. }
  435. /*
  436. =================
  437. idRenderModelManagerLocal::BeginLevelLoad
  438. =================
  439. */
  440. void idRenderModelManagerLocal::BeginLevelLoad() {
  441. insideLevelLoad = true;
  442. for ( int i = 0; i < models.Num(); i++ ) {
  443. idRenderModel *model = models[i];
  444. // always reload all models
  445. if ( model->IsReloadable() ) {
  446. R_CheckForEntityDefsUsingModel( model );
  447. model->PurgeModel();
  448. }
  449. model->SetLevelLoadReferenced( false );
  450. }
  451. vertexCache.FreeStaticData();
  452. }
  453. /*
  454. =================
  455. idRenderModelManagerLocal::Preload
  456. =================
  457. */
  458. void idRenderModelManagerLocal::Preload( const idPreloadManifest &manifest ) {
  459. if ( preload_MapModels.GetBool() ) {
  460. // preload this levels images
  461. int start = Sys_Milliseconds();
  462. int numLoaded = 0;
  463. idList< preloadSort_t > preloadSort;
  464. preloadSort.Resize( manifest.NumResources() );
  465. for ( int i = 0; i < manifest.NumResources(); i++ ) {
  466. const preloadEntry_s & p = manifest.GetPreloadByIndex( i );
  467. idResourceCacheEntry rc;
  468. idStrStatic< MAX_OSPATH > filename;
  469. if ( p.resType == PRELOAD_MODEL ) {
  470. filename = "generated/rendermodels/";
  471. filename += p.resourceName;
  472. idStrStatic< 16 > ext;
  473. filename.ExtractFileExtension( ext );
  474. filename.SetFileExtension( va( "b%s", ext.c_str() ) );
  475. }
  476. if ( p.resType == PRELOAD_PARTICLE ) {
  477. filename = "generated/particles/";
  478. filename += p.resourceName;
  479. filename += ".bprt";
  480. }
  481. if ( !filename.IsEmpty() ) {
  482. if ( fileSystem->GetResourceCacheEntry( filename, rc ) ) {
  483. preloadSort_t ps = {};
  484. ps.idx = i;
  485. ps.ofs = rc.offset;
  486. preloadSort.Append( ps );
  487. }
  488. }
  489. }
  490. preloadSort.SortWithTemplate( idSort_Preload() );
  491. for ( int i = 0; i < preloadSort.Num(); i++ ) {
  492. const preloadSort_t & ps = preloadSort[ i ];
  493. const preloadEntry_s & p = manifest.GetPreloadByIndex( ps.idx );
  494. if ( p.resType == PRELOAD_MODEL ) {
  495. idRenderModel * model = FindModel( p.resourceName );
  496. if ( model != NULL ) {
  497. model->SetLevelLoadReferenced( true );
  498. }
  499. } else if ( p.resType == PRELOAD_PARTICLE ) {
  500. declManager->FindType( DECL_PARTICLE, p.resourceName );
  501. }
  502. numLoaded++;
  503. }
  504. int end = Sys_Milliseconds();
  505. common->Printf( "%05d models preloaded ( or were already loaded ) in %5.1f seconds\n", numLoaded, ( end - start ) * 0.001 );
  506. common->Printf( "----------------------------------------\n" );
  507. }
  508. }
  509. /*
  510. =================
  511. idRenderModelManagerLocal::EndLevelLoad
  512. =================
  513. */
  514. void idRenderModelManagerLocal::EndLevelLoad() {
  515. common->Printf( "----- idRenderModelManagerLocal::EndLevelLoad -----\n" );
  516. int start = Sys_Milliseconds();
  517. insideLevelLoad = false;
  518. int purgeCount = 0;
  519. int keepCount = 0;
  520. int loadCount = 0;
  521. // purge any models not touched
  522. for ( int i = 0; i < models.Num(); i++ ) {
  523. idRenderModel *model = models[i];
  524. if ( !model->IsLevelLoadReferenced() && model->IsLoaded() && model->IsReloadable() ) {
  525. // common->Printf( "purging %s\n", model->Name() );
  526. purgeCount++;
  527. R_CheckForEntityDefsUsingModel( model );
  528. model->PurgeModel();
  529. } else {
  530. // common->Printf( "keeping %s\n", model->Name() );
  531. keepCount++;
  532. }
  533. common->UpdateLevelLoadPacifier();
  534. }
  535. // load any new ones
  536. for ( int i = 0; i < models.Num(); i++ ) {
  537. common->UpdateLevelLoadPacifier();
  538. idRenderModel *model = models[i];
  539. if ( model->IsLevelLoadReferenced() && !model->IsLoaded() && model->IsReloadable() ) {
  540. loadCount++;
  541. model->LoadModel();
  542. }
  543. }
  544. // create static vertex/index buffers for all models
  545. for ( int i = 0; i < models.Num(); i++ ) {
  546. common->UpdateLevelLoadPacifier();
  547. idRenderModel *model = models[i];
  548. if ( model->IsLoaded() ) {
  549. for ( int j = 0; j < model->NumSurfaces(); j++ ) {
  550. R_CreateStaticBuffersForTri( *(model->Surface( j )->geometry) );
  551. }
  552. }
  553. }
  554. // _D3XP added this
  555. int end = Sys_Milliseconds();
  556. common->Printf( "%5i models purged from previous level, ", purgeCount );
  557. common->Printf( "%5i models kept.\n", keepCount );
  558. if ( loadCount ) {
  559. common->Printf( "%5i new models loaded in %5.1f seconds\n", loadCount, (end-start) * 0.001 );
  560. }
  561. common->Printf( "---------------------------------------------------\n" );
  562. }
  563. /*
  564. =================
  565. idRenderModelManagerLocal::PrintMemInfo
  566. =================
  567. */
  568. void idRenderModelManagerLocal::PrintMemInfo( MemInfo_t *mi ) {
  569. int i, j, totalMem = 0;
  570. int *sortIndex;
  571. idFile *f;
  572. f = fileSystem->OpenFileWrite( mi->filebase + "_models.txt" );
  573. if ( !f ) {
  574. return;
  575. }
  576. // sort first
  577. sortIndex = new (TAG_MODEL) int[ localModelManager.models.Num()];
  578. for ( i = 0; i < localModelManager.models.Num(); i++ ) {
  579. sortIndex[i] = i;
  580. }
  581. for ( i = 0; i < localModelManager.models.Num() - 1; i++ ) {
  582. for ( j = i + 1; j < localModelManager.models.Num(); j++ ) {
  583. if ( localModelManager.models[sortIndex[i]]->Memory() < localModelManager.models[sortIndex[j]]->Memory() ) {
  584. int temp = sortIndex[i];
  585. sortIndex[i] = sortIndex[j];
  586. sortIndex[j] = temp;
  587. }
  588. }
  589. }
  590. // print next
  591. for ( int i = 0; i < localModelManager.models.Num(); i++ ) {
  592. idRenderModel *model = localModelManager.models[sortIndex[i]];
  593. int mem;
  594. if ( !model->IsLoaded() ) {
  595. continue;
  596. }
  597. mem = model->Memory();
  598. totalMem += mem;
  599. f->Printf( "%s %s\n", idStr::FormatNumber( mem ).c_str(), model->Name() );
  600. }
  601. delete [] sortIndex;
  602. mi->modelAssetsTotal = totalMem;
  603. f->Printf( "\nTotal model bytes allocated: %s\n", idStr::FormatNumber( totalMem ).c_str() );
  604. fileSystem->CloseFile( f );
  605. }