CollisionModel_files.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672
  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. /*
  21. ===============================================================================
  22. Trace model vs. polygonal model collision detection.
  23. ===============================================================================
  24. */
  25. #pragma hdrstop
  26. #include "../idlib/precompiled.h"
  27. #include "CollisionModel_local.h"
  28. #define CM_FILE_EXT "cm"
  29. #define CM_BINARYFILE_EXT "bcm"
  30. #define CM_FILEID "CM"
  31. #define CM_FILEVERSION "1.00"
  32. /*
  33. ===============================================================================
  34. Writing of collision model file
  35. ===============================================================================
  36. */
  37. void CM_GetNodeBounds( idBounds *bounds, cm_node_t *node );
  38. int CM_GetNodeContents( cm_node_t *node );
  39. /*
  40. ================
  41. idCollisionModelManagerLocal::WriteNodes
  42. ================
  43. */
  44. void idCollisionModelManagerLocal::WriteNodes( idFile *fp, cm_node_t *node ) {
  45. fp->WriteFloatString( "\t( %d %f )\n", node->planeType, node->planeDist );
  46. if ( node->planeType != -1 ) {
  47. WriteNodes( fp, node->children[0] );
  48. WriteNodes( fp, node->children[1] );
  49. }
  50. }
  51. /*
  52. ================
  53. idCollisionModelManagerLocal::CountPolygonMemory
  54. ================
  55. */
  56. int idCollisionModelManagerLocal::CountPolygonMemory( cm_node_t *node ) const {
  57. cm_polygonRef_t *pref;
  58. cm_polygon_t *p;
  59. int memory;
  60. memory = 0;
  61. for ( pref = node->polygons; pref; pref = pref->next ) {
  62. p = pref->p;
  63. if ( p->checkcount == checkCount ) {
  64. continue;
  65. }
  66. p->checkcount = checkCount;
  67. memory += sizeof( cm_polygon_t ) + ( p->numEdges - 1 ) * sizeof( p->edges[0] );
  68. }
  69. if ( node->planeType != -1 ) {
  70. memory += CountPolygonMemory( node->children[0] );
  71. memory += CountPolygonMemory( node->children[1] );
  72. }
  73. return memory;
  74. }
  75. /*
  76. ================
  77. idCollisionModelManagerLocal::WritePolygons
  78. ================
  79. */
  80. void idCollisionModelManagerLocal::WritePolygons( idFile *fp, cm_node_t *node ) {
  81. cm_polygonRef_t *pref;
  82. cm_polygon_t *p;
  83. int i;
  84. for ( pref = node->polygons; pref; pref = pref->next ) {
  85. p = pref->p;
  86. if ( p->checkcount == checkCount ) {
  87. continue;
  88. }
  89. p->checkcount = checkCount;
  90. fp->WriteFloatString( "\t%d (", p->numEdges );
  91. for ( i = 0; i < p->numEdges; i++ ) {
  92. fp->WriteFloatString( " %d", p->edges[i] );
  93. }
  94. fp->WriteFloatString( " ) ( %f %f %f ) %f", p->plane.Normal()[0], p->plane.Normal()[1], p->plane.Normal()[2], p->plane.Dist() );
  95. fp->WriteFloatString( " ( %f %f %f )", p->bounds[0][0], p->bounds[0][1], p->bounds[0][2] );
  96. fp->WriteFloatString( " ( %f %f %f )", p->bounds[1][0], p->bounds[1][1], p->bounds[1][2] );
  97. fp->WriteFloatString( " \"%s\"\n", p->material->GetName() );
  98. }
  99. if ( node->planeType != -1 ) {
  100. WritePolygons( fp, node->children[0] );
  101. WritePolygons( fp, node->children[1] );
  102. }
  103. }
  104. /*
  105. ================
  106. idCollisionModelManagerLocal::CountBrushMemory
  107. ================
  108. */
  109. int idCollisionModelManagerLocal::CountBrushMemory( cm_node_t *node ) const {
  110. cm_brushRef_t *bref;
  111. cm_brush_t *b;
  112. int memory;
  113. memory = 0;
  114. for ( bref = node->brushes; bref; bref = bref->next ) {
  115. b = bref->b;
  116. if ( b->checkcount == checkCount ) {
  117. continue;
  118. }
  119. b->checkcount = checkCount;
  120. memory += sizeof( cm_brush_t ) + ( b->numPlanes - 1 ) * sizeof( b->planes[0] );
  121. }
  122. if ( node->planeType != -1 ) {
  123. memory += CountBrushMemory( node->children[0] );
  124. memory += CountBrushMemory( node->children[1] );
  125. }
  126. return memory;
  127. }
  128. /*
  129. ================
  130. idCollisionModelManagerLocal::WriteBrushes
  131. ================
  132. */
  133. void idCollisionModelManagerLocal::WriteBrushes( idFile *fp, cm_node_t *node ) {
  134. cm_brushRef_t *bref;
  135. cm_brush_t *b;
  136. int i;
  137. for ( bref = node->brushes; bref; bref = bref->next ) {
  138. b = bref->b;
  139. if ( b->checkcount == checkCount ) {
  140. continue;
  141. }
  142. b->checkcount = checkCount;
  143. fp->WriteFloatString( "\t%d {\n", b->numPlanes );
  144. for ( i = 0; i < b->numPlanes; i++ ) {
  145. fp->WriteFloatString( "\t\t( %f %f %f ) %f\n", b->planes[i].Normal()[0], b->planes[i].Normal()[1], b->planes[i].Normal()[2], b->planes[i].Dist() );
  146. }
  147. fp->WriteFloatString( "\t} ( %f %f %f )", b->bounds[0][0], b->bounds[0][1], b->bounds[0][2] );
  148. fp->WriteFloatString( " ( %f %f %f ) \"%s\"\n", b->bounds[1][0], b->bounds[1][1], b->bounds[1][2], StringFromContents( b->contents ) );
  149. }
  150. if ( node->planeType != -1 ) {
  151. WriteBrushes( fp, node->children[0] );
  152. WriteBrushes( fp, node->children[1] );
  153. }
  154. }
  155. /*
  156. ================
  157. idCollisionModelManagerLocal::WriteCollisionModel
  158. ================
  159. */
  160. void idCollisionModelManagerLocal::WriteCollisionModel( idFile *fp, cm_model_t *model ) {
  161. int i, polygonMemory, brushMemory;
  162. fp->WriteFloatString( "collisionModel \"%s\" {\n", model->name.c_str() );
  163. // vertices
  164. fp->WriteFloatString( "\tvertices { /* numVertices = */ %d\n", model->numVertices );
  165. for ( i = 0; i < model->numVertices; i++ ) {
  166. fp->WriteFloatString( "\t/* %d */ ( %f %f %f )\n", i, model->vertices[i].p[0], model->vertices[i].p[1], model->vertices[i].p[2] );
  167. }
  168. fp->WriteFloatString( "\t}\n" );
  169. // edges
  170. fp->WriteFloatString( "\tedges { /* numEdges = */ %d\n", model->numEdges );
  171. for ( i = 0; i < model->numEdges; i++ ) {
  172. fp->WriteFloatString( "\t/* %d */ ( %d %d ) %d %d\n", i, model->edges[i].vertexNum[0], model->edges[i].vertexNum[1], model->edges[i].internal, model->edges[i].numUsers );
  173. }
  174. fp->WriteFloatString( "\t}\n" );
  175. // nodes
  176. fp->WriteFloatString( "\tnodes {\n" );
  177. WriteNodes( fp, model->node );
  178. fp->WriteFloatString( "\t}\n" );
  179. // polygons
  180. checkCount++;
  181. polygonMemory = CountPolygonMemory( model->node );
  182. fp->WriteFloatString( "\tpolygons /* polygonMemory = */ %d {\n", polygonMemory );
  183. checkCount++;
  184. WritePolygons( fp, model->node );
  185. fp->WriteFloatString( "\t}\n" );
  186. // brushes
  187. checkCount++;
  188. brushMemory = CountBrushMemory( model->node );
  189. fp->WriteFloatString( "\tbrushes /* brushMemory = */ %d {\n", brushMemory );
  190. checkCount++;
  191. WriteBrushes( fp, model->node );
  192. fp->WriteFloatString( "\t}\n" );
  193. // closing brace
  194. fp->WriteFloatString( "}\n" );
  195. }
  196. /*
  197. ================
  198. idCollisionModelManagerLocal::WriteCollisionModelsToFile
  199. ================
  200. */
  201. void idCollisionModelManagerLocal::WriteCollisionModelsToFile( const char *filename, int firstModel, int lastModel, unsigned int mapFileCRC ) {
  202. int i;
  203. idFile *fp;
  204. idStr name;
  205. name = filename;
  206. name.SetFileExtension( CM_FILE_EXT );
  207. common->Printf( "writing %s\n", name.c_str() );
  208. fp = fileSystem->OpenFileWrite( name, "fs_basepath" );
  209. if ( !fp ) {
  210. common->Warning( "idCollisionModelManagerLocal::WriteCollisionModelsToFile: Error opening file %s\n", name.c_str() );
  211. return;
  212. }
  213. // write file id and version
  214. fp->WriteFloatString( "%s \"%s\"\n\n", CM_FILEID, CM_FILEVERSION );
  215. // write the map file crc
  216. fp->WriteFloatString( "%u\n\n", mapFileCRC );
  217. // write the collision models
  218. for ( i = firstModel; i < lastModel; i++ ) {
  219. WriteCollisionModel( fp, models[ i ] );
  220. }
  221. fileSystem->CloseFile( fp );
  222. }
  223. /*
  224. ================
  225. idCollisionModelManagerLocal::WriteCollisionModelForMapEntity
  226. ================
  227. */
  228. bool idCollisionModelManagerLocal::WriteCollisionModelForMapEntity( const idMapEntity *mapEnt, const char *filename, const bool testTraceModel ) {
  229. idFile *fp;
  230. idStr name;
  231. cm_model_t *model;
  232. SetupHash();
  233. model = CollisionModelForMapEntity( mapEnt );
  234. model->name = filename;
  235. name = filename;
  236. name.SetFileExtension( CM_FILE_EXT );
  237. common->Printf( "writing %s\n", name.c_str() );
  238. fp = fileSystem->OpenFileWrite( name, "fs_basepath" );
  239. if ( !fp ) {
  240. common->Printf( "idCollisionModelManagerLocal::WriteCollisionModelForMapEntity: Error opening file %s\n", name.c_str() );
  241. FreeModel( model );
  242. return false;
  243. }
  244. // write file id and version
  245. fp->WriteFloatString( "%s \"%s\"\n\n", CM_FILEID, CM_FILEVERSION );
  246. // write the map file crc
  247. fp->WriteFloatString( "%u\n\n", 0 );
  248. // write the collision model
  249. WriteCollisionModel( fp, model );
  250. fileSystem->CloseFile( fp );
  251. if ( testTraceModel ) {
  252. idTraceModel trm;
  253. TrmFromModel( model, trm );
  254. }
  255. FreeModel( model );
  256. return true;
  257. }
  258. /*
  259. ===============================================================================
  260. Loading of collision model file
  261. ===============================================================================
  262. */
  263. /*
  264. ================
  265. idCollisionModelManagerLocal::ParseVertices
  266. ================
  267. */
  268. void idCollisionModelManagerLocal::ParseVertices( idLexer *src, cm_model_t *model ) {
  269. int i;
  270. src->ExpectTokenString( "{" );
  271. model->numVertices = src->ParseInt();
  272. model->maxVertices = model->numVertices;
  273. model->vertices = (cm_vertex_t *) Mem_ClearedAlloc( model->maxVertices * sizeof( cm_vertex_t ), TAG_COLLISION );
  274. for ( i = 0; i < model->numVertices; i++ ) {
  275. src->Parse1DMatrix( 3, model->vertices[i].p.ToFloatPtr() );
  276. model->vertices[i].side = 0;
  277. model->vertices[i].sideSet = 0;
  278. model->vertices[i].checkcount = 0;
  279. }
  280. src->ExpectTokenString( "}" );
  281. }
  282. /*
  283. ================
  284. idCollisionModelManagerLocal::ParseEdges
  285. ================
  286. */
  287. void idCollisionModelManagerLocal::ParseEdges( idLexer *src, cm_model_t *model ) {
  288. int i;
  289. src->ExpectTokenString( "{" );
  290. model->numEdges = src->ParseInt();
  291. model->maxEdges = model->numEdges;
  292. model->edges = (cm_edge_t *) Mem_ClearedAlloc( model->maxEdges * sizeof( cm_edge_t ), TAG_COLLISION );
  293. for ( i = 0; i < model->numEdges; i++ ) {
  294. src->ExpectTokenString( "(" );
  295. model->edges[i].vertexNum[0] = src->ParseInt();
  296. model->edges[i].vertexNum[1] = src->ParseInt();
  297. src->ExpectTokenString( ")" );
  298. model->edges[i].side = 0;
  299. model->edges[i].sideSet = 0;
  300. model->edges[i].internal = src->ParseInt();
  301. model->edges[i].numUsers = src->ParseInt();
  302. model->edges[i].normal = vec3_origin;
  303. model->edges[i].checkcount = 0;
  304. model->numInternalEdges += model->edges[i].internal;
  305. }
  306. src->ExpectTokenString( "}" );
  307. }
  308. /*
  309. ================
  310. idCollisionModelManagerLocal::ParseNodes
  311. ================
  312. */
  313. cm_node_t *idCollisionModelManagerLocal::ParseNodes( idLexer *src, cm_model_t *model, cm_node_t *parent ) {
  314. cm_node_t *node;
  315. model->numNodes++;
  316. node = AllocNode( model, model->numNodes < NODE_BLOCK_SIZE_SMALL ? NODE_BLOCK_SIZE_SMALL : NODE_BLOCK_SIZE_LARGE );
  317. node->brushes = NULL;
  318. node->polygons = NULL;
  319. node->parent = parent;
  320. src->ExpectTokenString( "(" );
  321. node->planeType = src->ParseInt();
  322. node->planeDist = src->ParseFloat();
  323. src->ExpectTokenString( ")" );
  324. if ( node->planeType != -1 ) {
  325. node->children[0] = ParseNodes( src, model, node );
  326. node->children[1] = ParseNodes( src, model, node );
  327. }
  328. return node;
  329. }
  330. /*
  331. ================
  332. idCollisionModelManagerLocal::ParsePolygons
  333. ================
  334. */
  335. void idCollisionModelManagerLocal::ParsePolygons( idLexer *src, cm_model_t *model ) {
  336. cm_polygon_t *p;
  337. int i, numEdges;
  338. idVec3 normal;
  339. idToken token;
  340. if ( src->CheckTokenType( TT_NUMBER, 0, &token ) ) {
  341. model->polygonBlock = (cm_polygonBlock_t *) Mem_ClearedAlloc( sizeof( cm_polygonBlock_t ) + token.GetIntValue(), TAG_COLLISION );
  342. model->polygonBlock->bytesRemaining = token.GetIntValue();
  343. model->polygonBlock->next = ( (byte *) model->polygonBlock ) + sizeof( cm_polygonBlock_t );
  344. }
  345. src->ExpectTokenString( "{" );
  346. while ( !src->CheckTokenString( "}" ) ) {
  347. // parse polygon
  348. numEdges = src->ParseInt();
  349. p = AllocPolygon( model, numEdges );
  350. p->numEdges = numEdges;
  351. src->ExpectTokenString( "(" );
  352. for ( i = 0; i < p->numEdges; i++ ) {
  353. p->edges[i] = src->ParseInt();
  354. }
  355. src->ExpectTokenString( ")" );
  356. src->Parse1DMatrix( 3, normal.ToFloatPtr() );
  357. p->plane.SetNormal( normal );
  358. p->plane.SetDist( src->ParseFloat() );
  359. src->Parse1DMatrix( 3, p->bounds[0].ToFloatPtr() );
  360. src->Parse1DMatrix( 3, p->bounds[1].ToFloatPtr() );
  361. src->ExpectTokenType( TT_STRING, 0, &token );
  362. // get material
  363. p->material = declManager->FindMaterial( token );
  364. p->contents = p->material->GetContentFlags();
  365. p->checkcount = 0;
  366. // filter polygon into tree
  367. R_FilterPolygonIntoTree( model, model->node, NULL, p );
  368. }
  369. }
  370. /*
  371. ================
  372. idCollisionModelManagerLocal::ParseBrushes
  373. ================
  374. */
  375. void idCollisionModelManagerLocal::ParseBrushes( idLexer *src, cm_model_t *model ) {
  376. cm_brush_t *b;
  377. int i, numPlanes;
  378. idVec3 normal;
  379. idToken token;
  380. if ( src->CheckTokenType( TT_NUMBER, 0, &token ) ) {
  381. model->brushBlock = (cm_brushBlock_t *) Mem_ClearedAlloc( sizeof( cm_brushBlock_t ) + token.GetIntValue(), TAG_COLLISION );
  382. model->brushBlock->bytesRemaining = token.GetIntValue();
  383. model->brushBlock->next = ( (byte *) model->brushBlock ) + sizeof( cm_brushBlock_t );
  384. }
  385. src->ExpectTokenString( "{" );
  386. while ( !src->CheckTokenString( "}" ) ) {
  387. // parse brush
  388. numPlanes = src->ParseInt();
  389. b = AllocBrush( model, numPlanes );
  390. b->numPlanes = numPlanes;
  391. src->ExpectTokenString( "{" );
  392. for ( i = 0; i < b->numPlanes; i++ ) {
  393. src->Parse1DMatrix( 3, normal.ToFloatPtr() );
  394. b->planes[i].SetNormal( normal );
  395. b->planes[i].SetDist( src->ParseFloat() );
  396. }
  397. src->ExpectTokenString( "}" );
  398. src->Parse1DMatrix( 3, b->bounds[0].ToFloatPtr() );
  399. src->Parse1DMatrix( 3, b->bounds[1].ToFloatPtr() );
  400. src->ReadToken( &token );
  401. if ( token.type == TT_NUMBER ) {
  402. b->contents = token.GetIntValue(); // old .cm files use a single integer
  403. } else {
  404. b->contents = ContentsFromString( token );
  405. }
  406. b->checkcount = 0;
  407. b->primitiveNum = 0;
  408. b->material = NULL;
  409. // filter brush into tree
  410. R_FilterBrushIntoTree( model, model->node, NULL, b );
  411. }
  412. }
  413. /*
  414. ================
  415. idCollisionModelManagerLocal::ParseCollisionModel
  416. ================
  417. */
  418. cm_model_t * idCollisionModelManagerLocal::ParseCollisionModel( idLexer *src ) {
  419. cm_model_t *model;
  420. idToken token;
  421. if ( numModels >= MAX_SUBMODELS ) {
  422. common->Error( "LoadModel: no free slots" );
  423. return NULL;
  424. }
  425. model = AllocModel();
  426. models[numModels ] = model;
  427. numModels++;
  428. // parse the file
  429. src->ExpectTokenType( TT_STRING, 0, &token );
  430. model->name = token;
  431. src->ExpectTokenString( "{" );
  432. while ( !src->CheckTokenString( "}" ) ) {
  433. src->ReadToken( &token );
  434. if ( token == "vertices" ) {
  435. ParseVertices( src, model );
  436. continue;
  437. }
  438. if ( token == "edges" ) {
  439. ParseEdges( src, model );
  440. continue;
  441. }
  442. if ( token == "nodes" ) {
  443. src->ExpectTokenString( "{" );
  444. model->node = ParseNodes( src, model, NULL );
  445. src->ExpectTokenString( "}" );
  446. continue;
  447. }
  448. if ( token == "polygons" ) {
  449. ParsePolygons( src, model );
  450. continue;
  451. }
  452. if ( token == "brushes" ) {
  453. ParseBrushes( src, model );
  454. continue;
  455. }
  456. src->Error( "ParseCollisionModel: bad token \"%s\"", token.c_str() );
  457. }
  458. // calculate edge normals
  459. checkCount++;
  460. CalculateEdgeNormals( model, model->node );
  461. // get model bounds from brush and polygon bounds
  462. CM_GetNodeBounds( &model->bounds, model->node );
  463. // get model contents
  464. model->contents = CM_GetNodeContents( model->node );
  465. // total memory used by this model
  466. model->usedMemory = model->numVertices * sizeof(cm_vertex_t) +
  467. model->numEdges * sizeof(cm_edge_t) +
  468. model->polygonMemory +
  469. model->brushMemory +
  470. model->numNodes * sizeof(cm_node_t) +
  471. model->numPolygonRefs * sizeof(cm_polygonRef_t) +
  472. model->numBrushRefs * sizeof(cm_brushRef_t);
  473. return model;
  474. }
  475. /*
  476. ================
  477. idCollisionModelManagerLocal::LoadCollisionModelFile
  478. ================
  479. */
  480. bool idCollisionModelManagerLocal::LoadCollisionModelFile( const char *name, unsigned int mapFileCRC ) {
  481. idToken token;
  482. idLexer *src;
  483. unsigned int crc;
  484. // load it
  485. idStrStatic< MAX_OSPATH > fileName = name;
  486. // check for generated file
  487. idStrStatic< MAX_OSPATH > generatedFileName = fileName;
  488. generatedFileName.Insert( "generated/", 0 );
  489. generatedFileName.SetFileExtension( CM_BINARYFILE_EXT );
  490. // if we are reloading the same map, check the timestamp
  491. // and try to skip all the work
  492. ID_TIME_T currentTimeStamp = fileSystem->GetTimestamp( fileName );
  493. // see if we have a generated version of this
  494. bool loaded = false;
  495. idFileLocal file( fileSystem->OpenFileReadMemory( generatedFileName ) );
  496. if ( file != NULL ) {
  497. int numEntries = 0;
  498. file->ReadBig( numEntries );
  499. file->ReadString( mapName );
  500. file->ReadBig( crc );
  501. idStrStatic< 32 > fileID;
  502. idStrStatic< 32 > fileVersion;
  503. file->ReadString( fileID );
  504. file->ReadString( fileVersion );
  505. if ( fileID == CM_FILEID && fileVersion == CM_FILEVERSION && crc == mapFileCRC && numEntries > 0 ) {
  506. for ( int i = 0; i < numEntries; i++ ) {
  507. cm_model_t *model = LoadBinaryModelFromFile( file, currentTimeStamp );
  508. models[ numModels ] = model;
  509. numModels++;
  510. }
  511. loaded = true;
  512. }
  513. }
  514. if ( !loaded ) {
  515. fileName.SetFileExtension( CM_FILE_EXT );
  516. src = new (TAG_COLLISION) idLexer( fileName );
  517. src->SetFlags( LEXFL_NOSTRINGCONCAT | LEXFL_NODOLLARPRECOMPILE );
  518. if ( !src->IsLoaded() ) {
  519. delete src;
  520. return false;
  521. }
  522. int numEntries = 0;
  523. idFileLocal outputFile( fileSystem->OpenFileWrite( generatedFileName, "fs_basepath" ) );
  524. if ( outputFile != NULL ) {
  525. outputFile->WriteBig( numEntries );
  526. outputFile->WriteString( mapName );
  527. outputFile->WriteBig( mapFileCRC );
  528. outputFile->WriteString( CM_FILEID );
  529. outputFile->WriteString( CM_FILEVERSION );
  530. }
  531. if ( !src->ExpectTokenString( CM_FILEID ) ) {
  532. common->Warning( "%s is not an CM file.", fileName.c_str() );
  533. delete src;
  534. return false;
  535. }
  536. if ( !src->ReadToken( &token ) || token != CM_FILEVERSION ) {
  537. common->Warning( "%s has version %s instead of %s", fileName.c_str(), token.c_str(), CM_FILEVERSION );
  538. delete src;
  539. return false;
  540. }
  541. if ( !src->ExpectTokenType( TT_NUMBER, TT_INTEGER, &token ) ) {
  542. common->Warning( "%s has no map file CRC", fileName.c_str() );
  543. delete src;
  544. return false;
  545. }
  546. crc = token.GetUnsignedLongValue();
  547. if ( mapFileCRC && crc != mapFileCRC ) {
  548. common->Printf( "%s is out of date\n", fileName.c_str() );
  549. delete src;
  550. return false;
  551. }
  552. // parse the file
  553. while ( 1 ) {
  554. if ( !src->ReadToken( &token ) ) {
  555. break;
  556. }
  557. if ( token == "collisionModel" ) {
  558. cm_model_t *model = ParseCollisionModel( src );
  559. if ( model == NULL ) {
  560. delete src;
  561. return false;
  562. }
  563. if ( outputFile != NULL ) {
  564. WriteBinaryModelToFile( model, outputFile, currentTimeStamp );
  565. numEntries++;
  566. }
  567. continue;
  568. }
  569. src->Error( "idCollisionModelManagerLocal::LoadCollisionModelFile: bad token \"%s\"", token.c_str() );
  570. }
  571. delete src;
  572. if ( outputFile != NULL ) {
  573. outputFile->Seek( 0, FS_SEEK_SET );
  574. outputFile->WriteBig( numEntries );
  575. }
  576. }
  577. return true;
  578. }