ModelManager.cpp 16 KB

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