MapFile.cpp 24 KB

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