MapFile.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968
  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 "precompiled.h"
  21. #pragma hdrstop
  22. /*
  23. ===============
  24. FloatCRC
  25. ===============
  26. */
  27. ID_INLINE unsigned int FloatCRC( float f ) {
  28. return *(unsigned int *)&f;
  29. }
  30. /*
  31. ===============
  32. StringCRC
  33. ===============
  34. */
  35. ID_INLINE unsigned int StringCRC( const char *str ) {
  36. unsigned int i, crc;
  37. const unsigned char *ptr;
  38. crc = 0;
  39. ptr = reinterpret_cast<const unsigned char*>(str);
  40. for ( i = 0; str[i]; i++ ) {
  41. crc ^= str[i] << (i & 3);
  42. }
  43. return crc;
  44. }
  45. /*
  46. =================
  47. ComputeAxisBase
  48. WARNING : special case behaviour of atan2(y,x) <-> atan(y/x) might not be the same everywhere when x == 0
  49. rotation by (0,RotY,RotZ) assigns X to normal
  50. =================
  51. */
  52. static void ComputeAxisBase( const idVec3 &normal, idVec3 &texS, idVec3 &texT ) {
  53. float RotY, RotZ;
  54. idVec3 n;
  55. // do some cleaning
  56. n[0] = ( idMath::Fabs( normal[0] ) < 1e-6f ) ? 0.0f : normal[0];
  57. n[1] = ( idMath::Fabs( normal[1] ) < 1e-6f ) ? 0.0f : normal[1];
  58. n[2] = ( idMath::Fabs( normal[2] ) < 1e-6f ) ? 0.0f : normal[2];
  59. RotY = -atan2( n[2], idMath::Sqrt( n[1] * n[1] + n[0] * n[0]) );
  60. RotZ = atan2( n[1], n[0] );
  61. // rotate (0,1,0) and (0,0,1) to compute texS and texT
  62. texS[0] = -sin(RotZ);
  63. texS[1] = cos(RotZ);
  64. texS[2] = 0;
  65. // the texT vector is along -Z ( T texture coorinates axis )
  66. texT[0] = -sin(RotY) * cos(RotZ);
  67. texT[1] = -sin(RotY) * sin(RotZ);
  68. texT[2] = -cos(RotY);
  69. }
  70. /*
  71. =================
  72. idMapBrushSide::GetTextureVectors
  73. =================
  74. */
  75. void idMapBrushSide::GetTextureVectors( idVec4 v[2] ) const {
  76. int i;
  77. idVec3 texX, texY;
  78. ComputeAxisBase( plane.Normal(), texX, texY );
  79. for ( i = 0; i < 2; i++ ) {
  80. v[i][0] = texX[0] * texMat[i][0] + texY[0] * texMat[i][1];
  81. v[i][1] = texX[1] * texMat[i][0] + texY[1] * texMat[i][1];
  82. v[i][2] = texX[2] * texMat[i][0] + texY[2] * texMat[i][1];
  83. v[i][3] = texMat[i][2] + ( origin * v[i].ToVec3() );
  84. }
  85. }
  86. /*
  87. =================
  88. idMapPatch::Parse
  89. =================
  90. */
  91. idMapPatch *idMapPatch::Parse( idLexer &src, const idVec3 &origin, bool patchDef3, float version ) {
  92. float info[7];
  93. idDrawVert *vert;
  94. idToken token;
  95. int i, j;
  96. if ( !src.ExpectTokenString( "{" ) ) {
  97. return NULL;
  98. }
  99. // read the material (we had an implicit 'textures/' in the old format...)
  100. if ( !src.ReadToken( &token ) ) {
  101. src.Error( "idMapPatch::Parse: unexpected EOF" );
  102. return NULL;
  103. }
  104. // Parse it
  105. if (patchDef3) {
  106. if ( !src.Parse1DMatrix( 7, info ) ) {
  107. src.Error( "idMapPatch::Parse: unable to Parse patchDef3 info" );
  108. return NULL;
  109. }
  110. } else {
  111. if ( !src.Parse1DMatrix( 5, info ) ) {
  112. src.Error( "idMapPatch::Parse: unable to parse patchDef2 info" );
  113. return NULL;
  114. }
  115. }
  116. idMapPatch *patch = new idMapPatch( info[0], info[1] );
  117. patch->SetSize( info[0], info[1] );
  118. if ( version < 2.0f ) {
  119. patch->SetMaterial( "textures/" + token );
  120. } else {
  121. patch->SetMaterial( token );
  122. }
  123. if ( patchDef3 ) {
  124. patch->SetHorzSubdivisions( info[2] );
  125. patch->SetVertSubdivisions( info[3] );
  126. patch->SetExplicitlySubdivided( true );
  127. }
  128. if ( patch->GetWidth() < 0 || patch->GetHeight() < 0 ) {
  129. src.Error( "idMapPatch::Parse: bad size" );
  130. delete patch;
  131. return NULL;
  132. }
  133. // these were written out in the wrong order, IMHO
  134. if ( !src.ExpectTokenString( "(" ) ) {
  135. src.Error( "idMapPatch::Parse: bad patch vertex data" );
  136. delete patch;
  137. return NULL;
  138. }
  139. for ( j = 0; j < patch->GetWidth(); j++ ) {
  140. if ( !src.ExpectTokenString( "(" ) ) {
  141. src.Error( "idMapPatch::Parse: bad vertex row data" );
  142. delete patch;
  143. return NULL;
  144. }
  145. for ( i = 0; i < patch->GetHeight(); i++ ) {
  146. float v[5];
  147. if ( !src.Parse1DMatrix( 5, v ) ) {
  148. src.Error( "idMapPatch::Parse: bad vertex column data" );
  149. delete patch;
  150. return NULL;
  151. }
  152. vert = &((*patch)[i * patch->GetWidth() + j]);
  153. vert->xyz[0] = v[0] - origin[0];
  154. vert->xyz[1] = v[1] - origin[1];
  155. vert->xyz[2] = v[2] - origin[2];
  156. vert->st[0] = v[3];
  157. vert->st[1] = v[4];
  158. }
  159. if ( !src.ExpectTokenString( ")" ) ) {
  160. delete patch;
  161. src.Error( "idMapPatch::Parse: unable to parse patch control points" );
  162. return NULL;
  163. }
  164. }
  165. if ( !src.ExpectTokenString( ")" ) ) {
  166. src.Error( "idMapPatch::Parse: unable to parse patch control points, no closure" );
  167. delete patch;
  168. return NULL;
  169. }
  170. // read any key/value pairs
  171. while( src.ReadToken( &token ) ) {
  172. if ( token == "}" ) {
  173. src.ExpectTokenString( "}" );
  174. break;
  175. }
  176. if ( token.type == TT_STRING ) {
  177. idStr key = token;
  178. src.ExpectTokenType( TT_STRING, 0, &token );
  179. patch->epairs.Set( key, token );
  180. }
  181. }
  182. return patch;
  183. }
  184. /*
  185. ============
  186. idMapPatch::Write
  187. ============
  188. */
  189. bool idMapPatch::Write( idFile *fp, int primitiveNum, const idVec3 &origin ) const {
  190. int i, j;
  191. const idDrawVert *v;
  192. if ( GetExplicitlySubdivided() ) {
  193. fp->WriteFloatString( "// primitive %d\n{\n patchDef3\n {\n", primitiveNum );
  194. fp->WriteFloatString( " \"%s\"\n ( %d %d %d %d 0 0 0 )\n", GetMaterial(), GetWidth(), GetHeight(), GetHorzSubdivisions(), GetVertSubdivisions());
  195. } else {
  196. fp->WriteFloatString( "// primitive %d\n{\n patchDef2\n {\n", primitiveNum );
  197. fp->WriteFloatString( " \"%s\"\n ( %d %d 0 0 0 )\n", GetMaterial(), GetWidth(), GetHeight());
  198. }
  199. fp->WriteFloatString( " (\n" );
  200. for ( i = 0; i < GetWidth(); i++ ) {
  201. fp->WriteFloatString( " ( " );
  202. for ( j = 0; j < GetHeight(); j++ ) {
  203. v = &verts[ j * GetWidth() + i ];
  204. fp->WriteFloatString( " ( %f %f %f %f %f )", v->xyz[0] + origin[0],
  205. v->xyz[1] + origin[1], v->xyz[2] + origin[2], v->st[0], v->st[1] );
  206. }
  207. fp->WriteFloatString( " )\n" );
  208. }
  209. fp->WriteFloatString( " )\n }\n}\n" );
  210. return true;
  211. }
  212. /*
  213. ===============
  214. idMapPatch::GetGeometryCRC
  215. ===============
  216. */
  217. unsigned int idMapPatch::GetGeometryCRC( void ) const {
  218. int i, j;
  219. unsigned int crc;
  220. crc = GetHorzSubdivisions() ^ GetVertSubdivisions();
  221. for ( i = 0; i < GetWidth(); i++ ) {
  222. for ( j = 0; j < GetHeight(); j++ ) {
  223. crc ^= FloatCRC( verts[j * GetWidth() + i].xyz.x );
  224. crc ^= FloatCRC( verts[j * GetWidth() + i].xyz.y );
  225. crc ^= FloatCRC( verts[j * GetWidth() + i].xyz.z );
  226. }
  227. }
  228. crc ^= StringCRC( GetMaterial() );
  229. return crc;
  230. }
  231. /*
  232. =================
  233. idMapBrush::Parse
  234. =================
  235. */
  236. idMapBrush *idMapBrush::Parse( idLexer &src, const idVec3 &origin, bool newFormat, float version ) {
  237. int i;
  238. idVec3 planepts[3];
  239. idToken token;
  240. idList<idMapBrushSide*> sides;
  241. idMapBrushSide *side;
  242. idDict epairs;
  243. if ( !src.ExpectTokenString( "{" ) ) {
  244. return NULL;
  245. }
  246. do {
  247. if ( !src.ReadToken( &token ) ) {
  248. src.Error( "idMapBrush::Parse: unexpected EOF" );
  249. sides.DeleteContents( true );
  250. return NULL;
  251. }
  252. if ( token == "}" ) {
  253. break;
  254. }
  255. // here we may have to jump over brush epairs ( only used in editor )
  256. do {
  257. // if token is a brace
  258. if ( token == "(" ) {
  259. break;
  260. }
  261. // the token should be a key string for a key/value pair
  262. if ( token.type != TT_STRING ) {
  263. src.Error( "idMapBrush::Parse: unexpected %s, expected ( or epair key string", token.c_str() );
  264. sides.DeleteContents( true );
  265. return NULL;
  266. }
  267. idStr key = token;
  268. if ( !src.ReadTokenOnLine( &token ) || token.type != TT_STRING ) {
  269. src.Error( "idMapBrush::Parse: expected epair value string not found" );
  270. sides.DeleteContents( true );
  271. return NULL;
  272. }
  273. epairs.Set( key, token );
  274. // try to read the next key
  275. if ( !src.ReadToken( &token ) ) {
  276. src.Error( "idMapBrush::Parse: unexpected EOF" );
  277. sides.DeleteContents( true );
  278. return NULL;
  279. }
  280. } while (1);
  281. src.UnreadToken( &token );
  282. side = new idMapBrushSide();
  283. sides.Append(side);
  284. if ( newFormat ) {
  285. if ( !src.Parse1DMatrix( 4, side->plane.ToFloatPtr() ) ) {
  286. src.Error( "idMapBrush::Parse: unable to read brush side plane definition" );
  287. sides.DeleteContents( true );
  288. return NULL;
  289. }
  290. } else {
  291. // read the three point plane definition
  292. if (!src.Parse1DMatrix( 3, planepts[0].ToFloatPtr() ) ||
  293. !src.Parse1DMatrix( 3, planepts[1].ToFloatPtr() ) ||
  294. !src.Parse1DMatrix( 3, planepts[2].ToFloatPtr() ) ) {
  295. src.Error( "idMapBrush::Parse: unable to read brush side plane definition" );
  296. sides.DeleteContents( true );
  297. return NULL;
  298. }
  299. planepts[0] -= origin;
  300. planepts[1] -= origin;
  301. planepts[2] -= origin;
  302. side->plane.FromPoints( planepts[0], planepts[1], planepts[2] );
  303. }
  304. // read the texture matrix
  305. // this is odd, because the texmat is 2D relative to default planar texture axis
  306. if ( !src.Parse2DMatrix( 2, 3, side->texMat[0].ToFloatPtr() ) ) {
  307. src.Error( "idMapBrush::Parse: unable to read brush side texture matrix" );
  308. sides.DeleteContents( true );
  309. return NULL;
  310. }
  311. side->origin = origin;
  312. // read the material
  313. if ( !src.ReadTokenOnLine( &token ) ) {
  314. src.Error( "idMapBrush::Parse: unable to read brush side material" );
  315. sides.DeleteContents( true );
  316. return NULL;
  317. }
  318. // we had an implicit 'textures/' in the old format...
  319. if ( version < 2.0f ) {
  320. side->material = "textures/" + token;
  321. } else {
  322. side->material = token;
  323. }
  324. // Q2 allowed override of default flags and values, but we don't any more
  325. if ( src.ReadTokenOnLine( &token ) ) {
  326. if ( src.ReadTokenOnLine( &token ) ) {
  327. if ( src.ReadTokenOnLine( &token ) ) {
  328. }
  329. }
  330. }
  331. } while( 1 );
  332. if ( !src.ExpectTokenString( "}" ) ) {
  333. sides.DeleteContents( true );
  334. return NULL;
  335. }
  336. idMapBrush *brush = new idMapBrush();
  337. for ( i = 0; i < sides.Num(); i++ ) {
  338. brush->AddSide( sides[i] );
  339. }
  340. brush->epairs = epairs;
  341. return brush;
  342. }
  343. /*
  344. =================
  345. idMapBrush::ParseQ3
  346. =================
  347. */
  348. idMapBrush *idMapBrush::ParseQ3( idLexer &src, const idVec3 &origin ) {
  349. int i, shift[2], rotate;
  350. float scale[2];
  351. idVec3 planepts[3];
  352. idToken token;
  353. idList<idMapBrushSide*> sides;
  354. idMapBrushSide *side;
  355. idDict epairs;
  356. do {
  357. if ( src.CheckTokenString( "}" ) ) {
  358. break;
  359. }
  360. side = new idMapBrushSide();
  361. sides.Append( side );
  362. // read the three point plane definition
  363. if (!src.Parse1DMatrix( 3, planepts[0].ToFloatPtr() ) ||
  364. !src.Parse1DMatrix( 3, planepts[1].ToFloatPtr() ) ||
  365. !src.Parse1DMatrix( 3, planepts[2].ToFloatPtr() ) ) {
  366. src.Error( "idMapBrush::ParseQ3: unable to read brush side plane definition" );
  367. sides.DeleteContents( true );
  368. return NULL;
  369. }
  370. planepts[0] -= origin;
  371. planepts[1] -= origin;
  372. planepts[2] -= origin;
  373. side->plane.FromPoints( planepts[0], planepts[1], planepts[2] );
  374. // read the material
  375. if ( !src.ReadTokenOnLine( &token ) ) {
  376. src.Error( "idMapBrush::ParseQ3: unable to read brush side material" );
  377. sides.DeleteContents( true );
  378. return NULL;
  379. }
  380. // we have an implicit 'textures/' in the old format
  381. side->material = "textures/" + token;
  382. // read the texture shift, rotate and scale
  383. shift[0] = src.ParseInt();
  384. shift[1] = src.ParseInt();
  385. rotate = src.ParseInt();
  386. scale[0] = src.ParseFloat();
  387. scale[1] = src.ParseFloat();
  388. side->texMat[0] = idVec3( 0.03125f, 0.0f, 0.0f );
  389. side->texMat[1] = idVec3( 0.0f, 0.03125f, 0.0f );
  390. side->origin = origin;
  391. // Q2 allowed override of default flags and values, but we don't any more
  392. if ( src.ReadTokenOnLine( &token ) ) {
  393. if ( src.ReadTokenOnLine( &token ) ) {
  394. if ( src.ReadTokenOnLine( &token ) ) {
  395. }
  396. }
  397. }
  398. } while( 1 );
  399. idMapBrush *brush = new idMapBrush();
  400. for ( i = 0; i < sides.Num(); i++ ) {
  401. brush->AddSide( sides[i] );
  402. }
  403. brush->epairs = epairs;
  404. return brush;
  405. }
  406. /*
  407. ============
  408. idMapBrush::Write
  409. ============
  410. */
  411. bool idMapBrush::Write( idFile *fp, int primitiveNum, const idVec3 &origin ) const {
  412. int i;
  413. idMapBrushSide *side;
  414. fp->WriteFloatString( "// primitive %d\n{\n brushDef3\n {\n", primitiveNum );
  415. // write brush epairs
  416. for ( i = 0; i < epairs.GetNumKeyVals(); i++) {
  417. fp->WriteFloatString( " \"%s\" \"%s\"\n", epairs.GetKeyVal(i)->GetKey().c_str(), epairs.GetKeyVal(i)->GetValue().c_str());
  418. }
  419. // write brush sides
  420. for ( i = 0; i < GetNumSides(); i++ ) {
  421. side = GetSide( i );
  422. fp->WriteFloatString( " ( %f %f %f %f ) ", side->plane[0], side->plane[1], side->plane[2], side->plane[3] );
  423. fp->WriteFloatString( "( ( %f %f %f ) ( %f %f %f ) ) \"%s\" 0 0 0\n",
  424. side->texMat[0][0], side->texMat[0][1], side->texMat[0][2],
  425. side->texMat[1][0], side->texMat[1][1], side->texMat[1][2],
  426. side->material.c_str() );
  427. }
  428. fp->WriteFloatString( " }\n}\n" );
  429. return true;
  430. }
  431. /*
  432. ===============
  433. idMapBrush::GetGeometryCRC
  434. ===============
  435. */
  436. unsigned int idMapBrush::GetGeometryCRC( void ) const {
  437. int i, j;
  438. idMapBrushSide *mapSide;
  439. unsigned int crc;
  440. crc = 0;
  441. for ( i = 0; i < GetNumSides(); i++ ) {
  442. mapSide = GetSide(i);
  443. for ( j = 0; j < 4; j++ ) {
  444. crc ^= FloatCRC( mapSide->GetPlane()[j] );
  445. }
  446. crc ^= StringCRC( mapSide->GetMaterial() );
  447. }
  448. return crc;
  449. }
  450. /*
  451. ================
  452. idMapEntity::Parse
  453. ================
  454. */
  455. idMapEntity *idMapEntity::Parse( idLexer &src, bool worldSpawn, float version ) {
  456. idToken token;
  457. idMapEntity *mapEnt;
  458. idMapPatch *mapPatch;
  459. idMapBrush *mapBrush;
  460. bool worldent;
  461. idVec3 origin;
  462. double v1, v2, v3;
  463. if ( !src.ReadToken(&token) ) {
  464. return NULL;
  465. }
  466. if ( token != "{" ) {
  467. src.Error( "idMapEntity::Parse: { not found, found %s", token.c_str() );
  468. return NULL;
  469. }
  470. mapEnt = new idMapEntity();
  471. if ( worldSpawn ) {
  472. mapEnt->primitives.Resize( 1024, 256 );
  473. }
  474. origin.Zero();
  475. worldent = false;
  476. do {
  477. if ( !src.ReadToken(&token) ) {
  478. src.Error( "idMapEntity::Parse: EOF without closing brace" );
  479. return NULL;
  480. }
  481. if ( token == "}" ) {
  482. break;
  483. }
  484. if ( token == "{" ) {
  485. // parse a brush or patch
  486. if ( !src.ReadToken( &token ) ) {
  487. src.Error( "idMapEntity::Parse: unexpected EOF" );
  488. return NULL;
  489. }
  490. if ( worldent ) {
  491. origin.Zero();
  492. }
  493. // if is it a brush: brush, brushDef, brushDef2, brushDef3
  494. if ( token.Icmpn( "brush", 5 ) == 0 ) {
  495. mapBrush = idMapBrush::Parse( src, origin, ( !token.Icmp( "brushDef2" ) || !token.Icmp( "brushDef3" ) ), version );
  496. if ( !mapBrush ) {
  497. return NULL;
  498. }
  499. mapEnt->AddPrimitive( mapBrush );
  500. }
  501. // if is it a patch: patchDef2, patchDef3
  502. else if ( token.Icmpn( "patch", 5 ) == 0 ) {
  503. mapPatch = idMapPatch::Parse( src, origin, !token.Icmp( "patchDef3" ), version );
  504. if ( !mapPatch ) {
  505. return NULL;
  506. }
  507. mapEnt->AddPrimitive( mapPatch );
  508. }
  509. // assume it's a brush in Q3 or older style
  510. else {
  511. src.UnreadToken( &token );
  512. mapBrush = idMapBrush::ParseQ3( src, origin );
  513. if ( !mapBrush ) {
  514. return NULL;
  515. }
  516. mapEnt->AddPrimitive( mapBrush );
  517. }
  518. } else {
  519. idStr key, value;
  520. // parse a key / value pair
  521. key = token;
  522. src.ReadTokenOnLine( &token );
  523. value = token;
  524. // strip trailing spaces that sometimes get accidentally
  525. // added in the editor
  526. value.StripTrailingWhitespace();
  527. key.StripTrailingWhitespace();
  528. mapEnt->epairs.Set( key, value );
  529. if ( !idStr::Icmp( key, "origin" ) ) {
  530. // scanf into doubles, then assign, so it is idVec size independent
  531. v1 = v2 = v3 = 0;
  532. sscanf( value, "%lf %lf %lf", &v1, &v2, &v3 );
  533. origin.x = v1;
  534. origin.y = v2;
  535. origin.z = v3;
  536. }
  537. else if ( !idStr::Icmp( key, "classname" ) && !idStr::Icmp( value, "worldspawn" ) ) {
  538. worldent = true;
  539. }
  540. }
  541. } while( 1 );
  542. return mapEnt;
  543. }
  544. /*
  545. ============
  546. idMapEntity::Write
  547. ============
  548. */
  549. bool idMapEntity::Write( idFile *fp, int entityNum ) const {
  550. int i;
  551. idMapPrimitive *mapPrim;
  552. idVec3 origin;
  553. fp->WriteFloatString( "// entity %d\n{\n", entityNum );
  554. // write entity epairs
  555. for ( i = 0; i < epairs.GetNumKeyVals(); i++) {
  556. fp->WriteFloatString( "\"%s\" \"%s\"\n", epairs.GetKeyVal(i)->GetKey().c_str(), epairs.GetKeyVal(i)->GetValue().c_str());
  557. }
  558. epairs.GetVector( "origin", "0 0 0", origin );
  559. // write pritimives
  560. for ( i = 0; i < GetNumPrimitives(); i++ ) {
  561. mapPrim = GetPrimitive( i );
  562. switch( mapPrim->GetType() ) {
  563. case idMapPrimitive::TYPE_BRUSH:
  564. static_cast<idMapBrush*>(mapPrim)->Write( fp, i, origin );
  565. break;
  566. case idMapPrimitive::TYPE_PATCH:
  567. static_cast<idMapPatch*>(mapPrim)->Write( fp, i, origin );
  568. break;
  569. }
  570. }
  571. fp->WriteFloatString( "}\n" );
  572. return true;
  573. }
  574. /*
  575. ===============
  576. idMapEntity::RemovePrimitiveData
  577. ===============
  578. */
  579. void idMapEntity::RemovePrimitiveData() {
  580. primitives.DeleteContents(true);
  581. }
  582. /*
  583. ===============
  584. idMapEntity::GetGeometryCRC
  585. ===============
  586. */
  587. unsigned int idMapEntity::GetGeometryCRC( void ) const {
  588. int i;
  589. unsigned int crc;
  590. idMapPrimitive *mapPrim;
  591. crc = 0;
  592. for ( i = 0; i < GetNumPrimitives(); i++ ) {
  593. mapPrim = GetPrimitive( i );
  594. switch( mapPrim->GetType() ) {
  595. case idMapPrimitive::TYPE_BRUSH:
  596. crc ^= static_cast<idMapBrush*>(mapPrim)->GetGeometryCRC();
  597. break;
  598. case idMapPrimitive::TYPE_PATCH:
  599. crc ^= static_cast<idMapPatch*>(mapPrim)->GetGeometryCRC();
  600. break;
  601. }
  602. }
  603. return crc;
  604. }
  605. /*
  606. ===============
  607. idMapFile::Parse
  608. ===============
  609. */
  610. bool idMapFile::Parse( const char *filename, bool ignoreRegion, bool osPath ) {
  611. // no string concatenation for epairs and allow path names for materials
  612. idLexer src( LEXFL_NOSTRINGCONCAT | LEXFL_NOSTRINGESCAPECHARS | LEXFL_ALLOWPATHNAMES );
  613. idToken token;
  614. idStr fullName;
  615. idMapEntity *mapEnt;
  616. int i, j, k;
  617. name = filename;
  618. name.StripFileExtension();
  619. fullName = name;
  620. hasPrimitiveData = false;
  621. if ( !ignoreRegion ) {
  622. // try loading a .reg file first
  623. fullName.SetFileExtension( "reg" );
  624. src.LoadFile( fullName, osPath );
  625. }
  626. if ( !src.IsLoaded() ) {
  627. // now try a .map file
  628. fullName.SetFileExtension( "map" );
  629. src.LoadFile( fullName, osPath );
  630. if ( !src.IsLoaded() ) {
  631. // didn't get anything at all
  632. return false;
  633. }
  634. }
  635. version = OLD_MAP_VERSION;
  636. fileTime = src.GetFileTime();
  637. entities.DeleteContents( true );
  638. if ( src.CheckTokenString( "Version" ) ) {
  639. src.ReadTokenOnLine( &token );
  640. version = token.GetFloatValue();
  641. }
  642. while( 1 ) {
  643. mapEnt = idMapEntity::Parse( src, ( entities.Num() == 0 ), version );
  644. if ( !mapEnt ) {
  645. break;
  646. }
  647. entities.Append( mapEnt );
  648. }
  649. SetGeometryCRC();
  650. // if the map has a worldspawn
  651. if ( entities.Num() ) {
  652. // "removeEntities" "classname" can be set in the worldspawn to remove all entities with the given classname
  653. const idKeyValue *removeEntities = entities[0]->epairs.MatchPrefix( "removeEntities", NULL );
  654. while ( removeEntities ) {
  655. RemoveEntities( removeEntities->GetValue() );
  656. removeEntities = entities[0]->epairs.MatchPrefix( "removeEntities", removeEntities );
  657. }
  658. // "overrideMaterial" "material" can be set in the worldspawn to reset all materials
  659. idStr material;
  660. if ( entities[0]->epairs.GetString( "overrideMaterial", "", material ) ) {
  661. for ( i = 0; i < entities.Num(); i++ ) {
  662. mapEnt = entities[i];
  663. for ( j = 0; j < mapEnt->GetNumPrimitives(); j++ ) {
  664. idMapPrimitive *mapPrimitive = mapEnt->GetPrimitive( j );
  665. switch( mapPrimitive->GetType() ) {
  666. case idMapPrimitive::TYPE_BRUSH: {
  667. idMapBrush *mapBrush = static_cast<idMapBrush *>(mapPrimitive);
  668. for ( k = 0; k < mapBrush->GetNumSides(); k++ ) {
  669. mapBrush->GetSide( k )->SetMaterial( material );
  670. }
  671. break;
  672. }
  673. case idMapPrimitive::TYPE_PATCH: {
  674. static_cast<idMapPatch *>(mapPrimitive)->SetMaterial( material );
  675. break;
  676. }
  677. }
  678. }
  679. }
  680. }
  681. // force all entities to have a name key/value pair
  682. if ( entities[0]->epairs.GetBool( "forceEntityNames" ) ) {
  683. for ( i = 1; i < entities.Num(); i++ ) {
  684. mapEnt = entities[i];
  685. if ( !mapEnt->epairs.FindKey( "name" ) ) {
  686. mapEnt->epairs.Set( "name", va( "%s%d", mapEnt->epairs.GetString( "classname", "forcedName" ), i ) );
  687. }
  688. }
  689. }
  690. // move the primitives of any func_group entities to the worldspawn
  691. if ( entities[0]->epairs.GetBool( "moveFuncGroups" ) ) {
  692. for ( i = 1; i < entities.Num(); i++ ) {
  693. mapEnt = entities[i];
  694. if ( idStr::Icmp( mapEnt->epairs.GetString( "classname" ), "func_group" ) == 0 ) {
  695. entities[0]->primitives.Append( mapEnt->primitives );
  696. mapEnt->primitives.Clear();
  697. }
  698. }
  699. }
  700. }
  701. hasPrimitiveData = true;
  702. return true;
  703. }
  704. /*
  705. ============
  706. idMapFile::Write
  707. ============
  708. */
  709. bool idMapFile::Write( const char *fileName, const char *ext, bool fromBasePath ) {
  710. int i;
  711. idStr qpath;
  712. idFile *fp;
  713. qpath = fileName;
  714. qpath.SetFileExtension( ext );
  715. idLib::common->Printf( "writing %s...\n", qpath.c_str() );
  716. if ( fromBasePath ) {
  717. fp = idLib::fileSystem->OpenFileWrite( qpath, "fs_devpath" );
  718. }
  719. else {
  720. fp = idLib::fileSystem->OpenExplicitFileWrite( qpath );
  721. }
  722. if ( !fp ) {
  723. idLib::common->Warning( "Couldn't open %s\n", qpath.c_str() );
  724. return false;
  725. }
  726. fp->WriteFloatString( "Version %f\n", (float) CURRENT_MAP_VERSION );
  727. for ( i = 0; i < entities.Num(); i++ ) {
  728. entities[i]->Write( fp, i );
  729. }
  730. idLib::fileSystem->CloseFile( fp );
  731. return true;
  732. }
  733. /*
  734. ===============
  735. idMapFile::SetGeometryCRC
  736. ===============
  737. */
  738. void idMapFile::SetGeometryCRC( void ) {
  739. int i;
  740. geometryCRC = 0;
  741. for ( i = 0; i < entities.Num(); i++ ) {
  742. geometryCRC ^= entities[i]->GetGeometryCRC();
  743. }
  744. }
  745. /*
  746. ===============
  747. idMapFile::AddEntity
  748. ===============
  749. */
  750. int idMapFile::AddEntity( idMapEntity *mapEnt ) {
  751. int ret = entities.Append( mapEnt );
  752. return ret;
  753. }
  754. /*
  755. ===============
  756. idMapFile::FindEntity
  757. ===============
  758. */
  759. idMapEntity *idMapFile::FindEntity( const char *name ) {
  760. for ( int i = 0; i < entities.Num(); i++ ) {
  761. idMapEntity *ent = entities[i];
  762. if ( idStr::Icmp( ent->epairs.GetString( "name" ), name ) == 0 ) {
  763. return ent;
  764. }
  765. }
  766. return NULL;
  767. }
  768. /*
  769. ===============
  770. idMapFile::RemoveEntity
  771. ===============
  772. */
  773. void idMapFile::RemoveEntity( idMapEntity *mapEnt ) {
  774. entities.Remove( mapEnt );
  775. delete mapEnt;
  776. }
  777. /*
  778. ===============
  779. idMapFile::RemoveEntity
  780. ===============
  781. */
  782. void idMapFile::RemoveEntities( const char *classname ) {
  783. for ( int i = 0; i < entities.Num(); i++ ) {
  784. idMapEntity *ent = entities[i];
  785. if ( idStr::Icmp( ent->epairs.GetString( "classname" ), classname ) == 0 ) {
  786. delete entities[i];
  787. entities.RemoveIndex( i );
  788. i--;
  789. }
  790. }
  791. }
  792. /*
  793. ===============
  794. idMapFile::RemoveAllEntities
  795. ===============
  796. */
  797. void idMapFile::RemoveAllEntities() {
  798. entities.DeleteContents( true );
  799. hasPrimitiveData = false;
  800. }
  801. /*
  802. ===============
  803. idMapFile::RemovePrimitiveData
  804. ===============
  805. */
  806. void idMapFile::RemovePrimitiveData() {
  807. for ( int i = 0; i < entities.Num(); i++ ) {
  808. idMapEntity *ent = entities[i];
  809. ent->RemovePrimitiveData();
  810. }
  811. hasPrimitiveData = false;
  812. }
  813. /*
  814. ===============
  815. idMapFile::NeedsReload
  816. ===============
  817. */
  818. bool idMapFile::NeedsReload() {
  819. if ( name.Length() ) {
  820. ID_TIME_T time = (ID_TIME_T)-1;
  821. if ( idLib::fileSystem->ReadFile( name, NULL, &time ) > 0 ) {
  822. return ( time > fileTime );
  823. }
  824. }
  825. return true;
  826. }