RenderWorld_load.cpp 27 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #pragma hdrstop
  21. #include "../idlib/precompiled.h"
  22. #include "tr_local.h"
  23. /*
  24. ================
  25. idRenderWorldLocal::FreeWorld
  26. ================
  27. */
  28. void idRenderWorldLocal::FreeWorld() {
  29. // this will free all the lightDefs and entityDefs
  30. FreeDefs();
  31. // free all the portals and check light/model references
  32. for ( int i = 0; i < numPortalAreas; i++ ) {
  33. portalArea_t *area;
  34. portal_t *portal, *nextPortal;
  35. area = &portalAreas[i];
  36. for ( portal = area->portals; portal; portal = nextPortal ) {
  37. nextPortal = portal->next;
  38. delete portal->w;
  39. R_StaticFree( portal );
  40. }
  41. // there shouldn't be any remaining lightRefs or entityRefs
  42. if ( area->lightRefs.areaNext != &area->lightRefs ) {
  43. common->Error( "FreeWorld: unexpected remaining lightRefs" );
  44. }
  45. if ( area->entityRefs.areaNext != &area->entityRefs ) {
  46. common->Error( "FreeWorld: unexpected remaining entityRefs" );
  47. }
  48. }
  49. if ( portalAreas ) {
  50. R_StaticFree( portalAreas );
  51. portalAreas = NULL;
  52. numPortalAreas = 0;
  53. R_StaticFree( areaScreenRect );
  54. areaScreenRect = NULL;
  55. }
  56. if ( doublePortals ) {
  57. R_StaticFree( doublePortals );
  58. doublePortals = NULL;
  59. numInterAreaPortals = 0;
  60. }
  61. if ( areaNodes ) {
  62. R_StaticFree( areaNodes );
  63. areaNodes = NULL;
  64. }
  65. // free all the inline idRenderModels
  66. for ( int i = 0; i < localModels.Num(); i++ ) {
  67. renderModelManager->RemoveModel( localModels[i] );
  68. delete localModels[i];
  69. }
  70. localModels.Clear();
  71. areaReferenceAllocator.Shutdown();
  72. interactionAllocator.Shutdown();
  73. mapName = "<FREED>";
  74. }
  75. /*
  76. ================
  77. idRenderWorldLocal::TouchWorldModels
  78. ================
  79. */
  80. void idRenderWorldLocal::TouchWorldModels() {
  81. for ( int i = 0; i < localModels.Num(); i++ ) {
  82. renderModelManager->CheckModel( localModels[i]->Name() );
  83. }
  84. }
  85. /*
  86. ================
  87. idRenderWorldLocal::ReadBinaryShadowModel
  88. ================
  89. */
  90. idRenderModel *idRenderWorldLocal::ReadBinaryModel( idFile *fileIn ) {
  91. idStrStatic< MAX_OSPATH > name;
  92. fileIn->ReadString( name );
  93. idRenderModel * model = renderModelManager->AllocModel();
  94. model->InitEmpty( name );
  95. if ( model->LoadBinaryModel( fileIn, mapTimeStamp ) ) {
  96. return model;
  97. }
  98. return NULL;
  99. }
  100. extern idCVar r_binaryLoadRenderModels;
  101. /*
  102. ================
  103. idRenderWorldLocal::ParseModel
  104. ================
  105. */
  106. idRenderModel *idRenderWorldLocal::ParseModel( idLexer *src, const char *mapName, ID_TIME_T mapTimeStamp, idFile *fileOut ) {
  107. idToken token;
  108. src->ExpectTokenString( "{" );
  109. // parse the name
  110. src->ExpectAnyToken( &token );
  111. idRenderModel * model = renderModelManager->AllocModel();
  112. model->InitEmpty( token );
  113. if ( fileOut != NULL ) {
  114. // write out the type so the binary reader knows what to instantiate
  115. fileOut->WriteString( "shadowmodel" );
  116. fileOut->WriteString( token );
  117. }
  118. int numSurfaces = src->ParseInt();
  119. if ( numSurfaces < 0 ) {
  120. src->Error( "R_ParseModel: bad numSurfaces" );
  121. }
  122. for ( int i = 0; i < numSurfaces; i++ ) {
  123. src->ExpectTokenString( "{" );
  124. src->ExpectAnyToken( &token );
  125. modelSurface_t surf;
  126. surf.shader = declManager->FindMaterial( token );
  127. ((idMaterial*)surf.shader)->AddReference();
  128. srfTriangles_t * tri = R_AllocStaticTriSurf();
  129. surf.geometry = tri;
  130. tri->numVerts = src->ParseInt();
  131. tri->numIndexes = src->ParseInt();
  132. // parse the vertices
  133. idTempArray<float> verts( tri->numVerts * 8 );
  134. for ( int j = 0; j < tri->numVerts; j++ ) {
  135. src->Parse1DMatrix( 8, &verts[j * 8] );
  136. }
  137. // parse the indices
  138. idTempArray<triIndex_t> indexes( tri->numIndexes );
  139. for ( int j = 0; j < tri->numIndexes; j++ ) {
  140. indexes[j] = src->ParseInt();
  141. }
  142. #if 1
  143. // find the island that each vertex belongs to
  144. idTempArray<int> vertIslands( tri->numVerts );
  145. idTempArray<bool> trisVisited( tri->numIndexes );
  146. vertIslands.Zero();
  147. trisVisited.Zero();
  148. int numIslands = 0;
  149. for ( int j = 0; j < tri->numIndexes; j += 3 ) {
  150. if ( trisVisited[j] ) {
  151. continue;
  152. }
  153. int islandNum = ++numIslands;
  154. vertIslands[indexes[j + 0]] = islandNum;
  155. vertIslands[indexes[j + 1]] = islandNum;
  156. vertIslands[indexes[j + 2]] = islandNum;
  157. trisVisited[j] = true;
  158. idList<int> queue;
  159. queue.Append( j );
  160. for ( int n = 0; n < queue.Num(); n++ ) {
  161. int t = queue[n];
  162. for ( int k = 0; k < tri->numIndexes; k += 3 ) {
  163. if ( trisVisited[k] ) {
  164. continue;
  165. }
  166. bool connected = indexes[t + 0] == indexes[k + 0] || indexes[t + 0] == indexes[k + 1] || indexes[t + 0] == indexes[k + 2] ||
  167. indexes[t + 1] == indexes[k + 0] || indexes[t + 1] == indexes[k + 1] || indexes[t + 1] == indexes[k + 2] ||
  168. indexes[t + 2] == indexes[k + 0] || indexes[t + 2] == indexes[k + 1] || indexes[t + 2] == indexes[k + 2];
  169. if ( connected ) {
  170. vertIslands[indexes[k + 0]] = islandNum;
  171. vertIslands[indexes[k + 1]] = islandNum;
  172. vertIslands[indexes[k + 2]] = islandNum;
  173. trisVisited[k] = true;
  174. queue.Append( k );
  175. }
  176. }
  177. }
  178. }
  179. // center the texture coordinates for each island for maximum 16-bit precision
  180. for ( int j = 1; j <= numIslands; j++ ) {
  181. float minS = idMath::INFINITY;
  182. float minT = idMath::INFINITY;
  183. float maxS = -idMath::INFINITY;
  184. float maxT = -idMath::INFINITY;
  185. for ( int k = 0; k < tri->numVerts; k++ ) {
  186. if ( vertIslands[k] == j ) {
  187. minS = Min( minS, verts[k * 8 + 3] );
  188. maxS = Max( maxS, verts[k * 8 + 3] );
  189. minT = Min( minT, verts[k * 8 + 4] );
  190. maxT = Max( maxT, verts[k * 8 + 4] );
  191. }
  192. }
  193. const float averageS = idMath::Ftoi( ( minS + maxS ) * 0.5f );
  194. const float averageT = idMath::Ftoi( ( minT + maxT ) * 0.5f );
  195. for ( int k = 0; k < tri->numVerts; k++ ) {
  196. if ( vertIslands[k] == j ) {
  197. verts[k * 8 + 3] -= averageS;
  198. verts[k * 8 + 4] -= averageT;
  199. }
  200. }
  201. }
  202. #endif
  203. R_AllocStaticTriSurfVerts( tri, tri->numVerts );
  204. for ( int j = 0; j < tri->numVerts; j++ ) {
  205. tri->verts[j].xyz[0] = verts[j * 8 + 0];
  206. tri->verts[j].xyz[1] = verts[j * 8 + 1];
  207. tri->verts[j].xyz[2] = verts[j * 8 + 2];
  208. tri->verts[j].SetTexCoord( verts[j * 8 + 3], verts[j * 8 + 4] );
  209. tri->verts[j].SetNormal( verts[j * 8 + 5], verts[j * 8 + 6], verts[j * 8 + 7] );
  210. }
  211. R_AllocStaticTriSurfIndexes( tri, tri->numIndexes );
  212. for ( int j = 0; j < tri->numIndexes; j++ ) {
  213. tri->indexes[j] = indexes[j];
  214. }
  215. src->ExpectTokenString( "}" );
  216. // add the completed surface to the model
  217. model->AddSurface( surf );
  218. }
  219. src->ExpectTokenString( "}" );
  220. model->FinishSurfaces();
  221. if ( fileOut != NULL && model->SupportsBinaryModel() && r_binaryLoadRenderModels.GetBool() ) {
  222. model->WriteBinaryModel( fileOut, &mapTimeStamp );
  223. }
  224. return model;
  225. }
  226. /*
  227. ================
  228. idRenderWorldLocal::ReadBinaryShadowModel
  229. ================
  230. */
  231. idRenderModel *idRenderWorldLocal::ReadBinaryShadowModel( idFile *fileIn ) {
  232. idStrStatic< MAX_OSPATH > name;
  233. fileIn->ReadString( name );
  234. idRenderModel * model = renderModelManager->AllocModel();
  235. model->InitEmpty( name );
  236. if ( model->LoadBinaryModel( fileIn, mapTimeStamp ) ) {
  237. return model;
  238. }
  239. return NULL;
  240. }
  241. /*
  242. ================
  243. idRenderWorldLocal::ParseShadowModel
  244. ================
  245. */
  246. idRenderModel *idRenderWorldLocal::ParseShadowModel( idLexer *src, idFile *fileOut ) {
  247. idToken token;
  248. src->ExpectTokenString( "{" );
  249. // parse the name
  250. src->ExpectAnyToken( &token );
  251. idRenderModel * model = renderModelManager->AllocModel();
  252. model->InitEmpty( token );
  253. if ( fileOut != NULL ) {
  254. // write out the type so the binary reader knows what to instantiate
  255. fileOut->WriteString( "shadowmodel" );
  256. fileOut->WriteString( token );
  257. }
  258. srfTriangles_t * tri = R_AllocStaticTriSurf();
  259. tri->numVerts = src->ParseInt();
  260. tri->numShadowIndexesNoCaps = src->ParseInt();
  261. tri->numShadowIndexesNoFrontCaps = src->ParseInt();
  262. tri->numIndexes = src->ParseInt();
  263. tri->shadowCapPlaneBits = src->ParseInt();
  264. assert( ( tri->numVerts & 1 ) == 0 );
  265. R_AllocStaticTriSurfPreLightShadowVerts( tri, ALIGN( tri->numVerts, 2 ) );
  266. tri->bounds.Clear();
  267. for ( int j = 0; j < tri->numVerts; j++ ) {
  268. float vec[8];
  269. src->Parse1DMatrix( 3, vec );
  270. tri->preLightShadowVertexes[j].xyzw[0] = vec[0];
  271. tri->preLightShadowVertexes[j].xyzw[1] = vec[1];
  272. tri->preLightShadowVertexes[j].xyzw[2] = vec[2];
  273. tri->preLightShadowVertexes[j].xyzw[3] = 1.0f; // no homogenous value
  274. tri->bounds.AddPoint( tri->preLightShadowVertexes[j].xyzw.ToVec3() );
  275. }
  276. // clear the last vertex if it wasn't stored
  277. if ( ( tri->numVerts & 1 ) != 0 ) {
  278. tri->preLightShadowVertexes[ALIGN( tri->numVerts, 2 ) - 1].xyzw.Zero();
  279. }
  280. // to be consistent set the number of vertices to half the number of shadow vertices
  281. tri->numVerts = ALIGN( tri->numVerts, 2 ) / 2;
  282. R_AllocStaticTriSurfIndexes( tri, tri->numIndexes );
  283. for ( int j = 0; j < tri->numIndexes; j++ ) {
  284. tri->indexes[j] = src->ParseInt();
  285. }
  286. // add the completed surface to the model
  287. modelSurface_t surf;
  288. surf.id = 0;
  289. surf.shader = tr.defaultMaterial;
  290. surf.geometry = tri;
  291. model->AddSurface( surf );
  292. src->ExpectTokenString( "}" );
  293. // NOTE: we do NOT do a model->FinishSurfaceces, because we don't need sil edges, planes, tangents, etc.
  294. if ( fileOut != NULL && model->SupportsBinaryModel() && r_binaryLoadRenderModels.GetBool() ) {
  295. model->WriteBinaryModel( fileOut, &mapTimeStamp );
  296. }
  297. return model;
  298. }
  299. /*
  300. ================
  301. idRenderWorldLocal::SetupAreaRefs
  302. ================
  303. */
  304. void idRenderWorldLocal::SetupAreaRefs() {
  305. connectedAreaNum = 0;
  306. for ( int i = 0; i < numPortalAreas; i++ ) {
  307. portalAreas[i].areaNum = i;
  308. portalAreas[i].lightRefs.areaNext =
  309. portalAreas[i].lightRefs.areaPrev = &portalAreas[i].lightRefs;
  310. portalAreas[i].entityRefs.areaNext =
  311. portalAreas[i].entityRefs.areaPrev = &portalAreas[i].entityRefs;
  312. }
  313. }
  314. /*
  315. ================
  316. idRenderWorldLocal::ParseInterAreaPortals
  317. ================
  318. */
  319. void idRenderWorldLocal::ParseInterAreaPortals( idLexer *src, idFile *fileOut ) {
  320. src->ExpectTokenString( "{" );
  321. numPortalAreas = src->ParseInt();
  322. if ( numPortalAreas < 0 ) {
  323. src->Error( "R_ParseInterAreaPortals: bad numPortalAreas" );
  324. return;
  325. }
  326. if ( fileOut != NULL ) {
  327. // write out the type so the binary reader knows what to instantiate
  328. fileOut->WriteString( "interAreaPortals" );
  329. }
  330. portalAreas = (portalArea_t *)R_ClearedStaticAlloc( numPortalAreas * sizeof( portalAreas[0] ) );
  331. areaScreenRect = (idScreenRect *) R_ClearedStaticAlloc( numPortalAreas * sizeof( idScreenRect ) );
  332. // set the doubly linked lists
  333. SetupAreaRefs();
  334. numInterAreaPortals = src->ParseInt();
  335. if ( numInterAreaPortals < 0 ) {
  336. src->Error( "R_ParseInterAreaPortals: bad numInterAreaPortals" );
  337. return;
  338. }
  339. if ( fileOut != NULL ) {
  340. fileOut->WriteBig( numPortalAreas );
  341. fileOut->WriteBig( numInterAreaPortals );
  342. }
  343. doublePortals = (doublePortal_t *)R_ClearedStaticAlloc( numInterAreaPortals *
  344. sizeof( doublePortals [0] ) );
  345. for ( int i = 0; i < numInterAreaPortals; i++ ) {
  346. int numPoints, a1, a2;
  347. idWinding *w;
  348. portal_t *p;
  349. numPoints = src->ParseInt();
  350. a1 = src->ParseInt();
  351. a2 = src->ParseInt();
  352. if ( fileOut != NULL ) {
  353. fileOut->WriteBig( numPoints );
  354. fileOut->WriteBig( a1 );
  355. fileOut->WriteBig( a2 );
  356. }
  357. w = new (TAG_RENDER_WINDING) idWinding( numPoints );
  358. w->SetNumPoints( numPoints );
  359. for ( int j = 0; j < numPoints; j++ ) {
  360. src->Parse1DMatrix( 3, (*w)[j].ToFloatPtr() );
  361. if ( fileOut != NULL ) {
  362. fileOut->WriteBig( (*w)[j].x );
  363. fileOut->WriteBig( (*w)[j].y );
  364. fileOut->WriteBig( (*w)[j].z );
  365. }
  366. // no texture coordinates
  367. (*w)[j][3] = 0;
  368. (*w)[j][4] = 0;
  369. }
  370. // add the portal to a1
  371. p = (portal_t *)R_ClearedStaticAlloc( sizeof( *p ) );
  372. p->intoArea = a2;
  373. p->doublePortal = &doublePortals[i];
  374. p->w = w;
  375. p->w->GetPlane( p->plane );
  376. p->next = portalAreas[a1].portals;
  377. portalAreas[a1].portals = p;
  378. doublePortals[i].portals[0] = p;
  379. // reverse it for a2
  380. p = (portal_t *)R_ClearedStaticAlloc( sizeof( *p ) );
  381. p->intoArea = a1;
  382. p->doublePortal = &doublePortals[i];
  383. p->w = w->Reverse();
  384. p->w->GetPlane( p->plane );
  385. p->next = portalAreas[a2].portals;
  386. portalAreas[a2].portals = p;
  387. doublePortals[i].portals[1] = p;
  388. }
  389. src->ExpectTokenString( "}" );
  390. }
  391. /*
  392. ================
  393. idRenderWorldLocal::ParseInterAreaPortals
  394. ================
  395. */
  396. void idRenderWorldLocal::ReadBinaryAreaPortals( idFile *file ) {
  397. file->ReadBig( numPortalAreas );
  398. file->ReadBig( numInterAreaPortals );
  399. portalAreas = (portalArea_t *)R_ClearedStaticAlloc( numPortalAreas * sizeof( portalAreas[0] ) );
  400. areaScreenRect = (idScreenRect *) R_ClearedStaticAlloc( numPortalAreas * sizeof( idScreenRect ) );
  401. // set the doubly linked lists
  402. SetupAreaRefs();
  403. doublePortals = (doublePortal_t *)R_ClearedStaticAlloc( numInterAreaPortals * sizeof( doublePortals [0] ) );
  404. for ( int i = 0; i < numInterAreaPortals; i++ ) {
  405. int numPoints, a1, a2;
  406. idWinding *w;
  407. portal_t *p;
  408. file->ReadBig( numPoints );
  409. file->ReadBig( a1 );
  410. file->ReadBig( a2 );
  411. w = new (TAG_RENDER_WINDING) idWinding( numPoints );
  412. w->SetNumPoints( numPoints );
  413. for ( int j = 0; j < numPoints; j++ ) {
  414. file->ReadBig( (*w)[ j ][ 0 ] );
  415. file->ReadBig( (*w)[ j ][ 1 ] );
  416. file->ReadBig( (*w)[ j ][ 2 ] );
  417. // no texture coordinates
  418. (*w)[ j ][ 3 ] = 0;
  419. (*w)[ j ][ 4 ] = 0;
  420. }
  421. // add the portal to a1
  422. p = (portal_t *)R_ClearedStaticAlloc( sizeof( *p ) );
  423. p->intoArea = a2;
  424. p->doublePortal = &doublePortals[i];
  425. p->w = w;
  426. p->w->GetPlane( p->plane );
  427. p->next = portalAreas[a1].portals;
  428. portalAreas[a1].portals = p;
  429. doublePortals[i].portals[0] = p;
  430. // reverse it for a2
  431. p = (portal_t *)R_ClearedStaticAlloc( sizeof( *p ) );
  432. p->intoArea = a1;
  433. p->doublePortal = &doublePortals[i];
  434. p->w = w->Reverse();
  435. p->w->GetPlane( p->plane );
  436. p->next = portalAreas[a2].portals;
  437. portalAreas[a2].portals = p;
  438. doublePortals[i].portals[1] = p;
  439. }
  440. }
  441. /*
  442. ================
  443. idRenderWorldLocal::ParseNodes
  444. ================
  445. */
  446. void idRenderWorldLocal::ParseNodes( idLexer *src, idFile *fileOut ) {
  447. src->ExpectTokenString( "{" );
  448. numAreaNodes = src->ParseInt();
  449. if ( numAreaNodes < 0 ) {
  450. src->Error( "R_ParseNodes: bad numAreaNodes" );
  451. }
  452. areaNodes = (areaNode_t *)R_ClearedStaticAlloc( numAreaNodes * sizeof( areaNodes[0] ) );
  453. if ( fileOut != NULL ) {
  454. // write out the type so the binary reader knows what to instantiate
  455. fileOut->WriteString( "nodes" );
  456. }
  457. if ( fileOut != NULL ) {
  458. fileOut->WriteBig( numAreaNodes );
  459. }
  460. for ( int i = 0; i < numAreaNodes; i++ ) {
  461. areaNode_t *node;
  462. node = &areaNodes[i];
  463. src->Parse1DMatrix( 4, node->plane.ToFloatPtr() );
  464. node->children[0] = src->ParseInt();
  465. node->children[1] = src->ParseInt();
  466. if ( fileOut != NULL ) {
  467. fileOut->WriteBig( node->plane[ 0 ] );
  468. fileOut->WriteBig( node->plane[ 1 ] );
  469. fileOut->WriteBig( node->plane[ 2 ] );
  470. fileOut->WriteBig( node->plane[ 3 ] );
  471. fileOut->WriteBig( node->children[ 0 ] );
  472. fileOut->WriteBig( node->children[ 1 ] );
  473. }
  474. }
  475. src->ExpectTokenString( "}" );
  476. }
  477. /*
  478. ================
  479. idRenderWorldLocal::ReadBinaryNodes
  480. ================
  481. */
  482. void idRenderWorldLocal::ReadBinaryNodes( idFile * file ) {
  483. file->ReadBig( numAreaNodes );
  484. areaNodes = (areaNode_t *)R_ClearedStaticAlloc( numAreaNodes * sizeof( areaNodes[0] ) );
  485. for ( int i = 0; i < numAreaNodes; i++ ) {
  486. areaNode_t * node = &areaNodes[ i ];
  487. file->ReadBig( node->plane[ 0 ] );
  488. file->ReadBig( node->plane[ 1 ] );
  489. file->ReadBig( node->plane[ 2 ] );
  490. file->ReadBig( node->plane[ 3 ] );
  491. file->ReadBig( node->children[ 0 ] );
  492. file->ReadBig( node->children[ 1 ] );
  493. }
  494. }
  495. /*
  496. ================
  497. idRenderWorldLocal::CommonChildrenArea_r
  498. ================
  499. */
  500. int idRenderWorldLocal::CommonChildrenArea_r( areaNode_t *node ) {
  501. int nums[2];
  502. for ( int i = 0; i < 2; i++ ) {
  503. if ( node->children[i] <= 0 ) {
  504. nums[i] = -1 - node->children[i];
  505. } else {
  506. nums[i] = CommonChildrenArea_r( &areaNodes[ node->children[i] ] );
  507. }
  508. }
  509. // solid nodes will match any area
  510. if ( nums[0] == AREANUM_SOLID ) {
  511. nums[0] = nums[1];
  512. }
  513. if ( nums[1] == AREANUM_SOLID ) {
  514. nums[1] = nums[0];
  515. }
  516. int common;
  517. if ( nums[0] == nums[1] ) {
  518. common = nums[0];
  519. } else {
  520. common = CHILDREN_HAVE_MULTIPLE_AREAS;
  521. }
  522. node->commonChildrenArea = common;
  523. return common;
  524. }
  525. /*
  526. =================
  527. idRenderWorldLocal::ClearWorld
  528. Sets up for a single area world
  529. =================
  530. */
  531. void idRenderWorldLocal::ClearWorld() {
  532. numPortalAreas = 1;
  533. portalAreas = (portalArea_t *)R_ClearedStaticAlloc( sizeof( portalAreas[0] ) );
  534. areaScreenRect = (idScreenRect *) R_ClearedStaticAlloc( sizeof( idScreenRect ) );
  535. SetupAreaRefs();
  536. // even though we only have a single area, create a node
  537. // that has both children pointing at it so we don't need to
  538. //
  539. areaNodes = (areaNode_t *)R_ClearedStaticAlloc( sizeof( areaNodes[0] ) );
  540. areaNodes[0].plane[3] = 1;
  541. areaNodes[0].children[0] = -1;
  542. areaNodes[0].children[1] = -1;
  543. }
  544. /*
  545. =================
  546. idRenderWorldLocal::FreeDefs
  547. dump all the interactions
  548. =================
  549. */
  550. void idRenderWorldLocal::FreeDefs() {
  551. generateAllInteractionsCalled = false;
  552. if ( interactionTable ) {
  553. R_StaticFree( interactionTable );
  554. interactionTable = NULL;
  555. }
  556. // free all lightDefs
  557. for ( int i = 0; i < lightDefs.Num(); i++ ) {
  558. idRenderLightLocal * light = lightDefs[i];
  559. if ( light != NULL && light->world == this ) {
  560. FreeLightDef( i );
  561. lightDefs[i] = NULL;
  562. }
  563. }
  564. // free all entityDefs
  565. for ( int i = 0; i < entityDefs.Num(); i++ ) {
  566. idRenderEntityLocal * mod = entityDefs[i];
  567. if ( mod != NULL && mod->world == this ) {
  568. FreeEntityDef( i );
  569. entityDefs[i] = NULL;
  570. }
  571. }
  572. // Reset decals and overlays
  573. for ( int i = 0; i < decals.Num(); i++ ) {
  574. decals[i].entityHandle = -1;
  575. decals[i].lastStartTime = 0;
  576. }
  577. for ( int i = 0; i < overlays.Num(); i++ ) {
  578. overlays[i].entityHandle = -1;
  579. overlays[i].lastStartTime = 0;
  580. }
  581. }
  582. /*
  583. =================
  584. idRenderWorldLocal::InitFromMap
  585. A NULL or empty name will make a world without a map model, which
  586. is still useful for displaying a bare model
  587. =================
  588. */
  589. bool idRenderWorldLocal::InitFromMap( const char *name ) {
  590. idLexer * src;
  591. idToken token;
  592. idRenderModel * lastModel;
  593. // if this is an empty world, initialize manually
  594. if ( !name || !name[0] ) {
  595. FreeWorld();
  596. mapName.Clear();
  597. ClearWorld();
  598. return true;
  599. }
  600. // load it
  601. idStrStatic< MAX_OSPATH > filename = name;
  602. filename.SetFileExtension( PROC_FILE_EXT );
  603. // check for generated file
  604. idStrStatic< MAX_OSPATH > generatedFileName = filename;
  605. generatedFileName.Insert( "generated/", 0 );
  606. generatedFileName.SetFileExtension( "bproc" );
  607. // if we are reloading the same map, check the timestamp
  608. // and try to skip all the work
  609. ID_TIME_T currentTimeStamp = fileSystem->GetTimestamp( filename );
  610. if ( name == mapName ) {
  611. if ( fileSystem->InProductionMode() || ( currentTimeStamp != FILE_NOT_FOUND_TIMESTAMP && currentTimeStamp == mapTimeStamp ) ) {
  612. common->Printf( "idRenderWorldLocal::InitFromMap: retaining existing map\n" );
  613. FreeDefs();
  614. TouchWorldModels();
  615. AddWorldModelEntities();
  616. ClearPortalStates();
  617. return true;
  618. }
  619. common->Printf( "idRenderWorldLocal::InitFromMap: timestamp has changed, reloading.\n" );
  620. }
  621. FreeWorld();
  622. // see if we have a generated version of this
  623. static const byte BPROC_VERSION = 1;
  624. static const unsigned int BPROC_MAGIC = ( 'P' << 24 ) | ( 'R' << 16 ) | ( 'O' << 8 ) | BPROC_VERSION;
  625. bool loaded = false;
  626. idFileLocal file( fileSystem->OpenFileReadMemory( generatedFileName ) );
  627. if ( file != NULL ) {
  628. int numEntries = 0;
  629. int magic = 0;
  630. file->ReadBig( magic );
  631. if ( magic == BPROC_MAGIC ) {
  632. file->ReadBig( numEntries );
  633. file->ReadString( mapName );
  634. file->ReadBig( mapTimeStamp );
  635. loaded = true;
  636. for ( int i = 0; i < numEntries; i++ ) {
  637. idStrStatic< MAX_OSPATH > type;
  638. file->ReadString( type );
  639. type.ToLower();
  640. if ( type == "model" ) {
  641. idRenderModel * lastModel = ReadBinaryModel( file );
  642. if ( lastModel == NULL ) {
  643. loaded = false;
  644. break;
  645. }
  646. renderModelManager->AddModel( lastModel );
  647. localModels.Append( lastModel );
  648. } else if ( type == "shadowmodel" ) {
  649. idRenderModel * lastModel = ReadBinaryModel( file );
  650. if ( lastModel == NULL ) {
  651. loaded = false;
  652. break;
  653. }
  654. renderModelManager->AddModel( lastModel );
  655. localModels.Append( lastModel );
  656. } else if ( type == "interareaportals" ) {
  657. ReadBinaryAreaPortals( file );
  658. } else if ( type == "nodes" ) {
  659. ReadBinaryNodes( file );
  660. } else {
  661. idLib::Error( "Binary proc file failed, unexpected type %s\n", type.c_str() );
  662. }
  663. }
  664. }
  665. }
  666. if ( !loaded ) {
  667. src = new (TAG_RENDER) idLexer( filename, LEXFL_NOSTRINGCONCAT | LEXFL_NODOLLARPRECOMPILE );
  668. if ( !src->IsLoaded() ) {
  669. common->Printf( "idRenderWorldLocal::InitFromMap: %s not found\n", filename.c_str() );
  670. ClearWorld();
  671. return false;
  672. }
  673. mapName = name;
  674. mapTimeStamp = currentTimeStamp;
  675. // if we are writing a demo, archive the load command
  676. if ( common->WriteDemo() ) {
  677. WriteLoadMap();
  678. }
  679. if ( !src->ReadToken( &token ) || token.Icmp( PROC_FILE_ID ) ) {
  680. common->Printf( "idRenderWorldLocal::InitFromMap: bad id '%s' instead of '%s'\n", token.c_str(), PROC_FILE_ID );
  681. delete src;
  682. return false;
  683. }
  684. int numEntries = 0;
  685. idFileLocal outputFile( fileSystem->OpenFileWrite( generatedFileName, "fs_basepath" ) );
  686. if ( outputFile != NULL ) {
  687. int magic = BPROC_MAGIC;
  688. outputFile->WriteBig( magic );
  689. outputFile->WriteBig( numEntries );
  690. outputFile->WriteString( mapName );
  691. outputFile->WriteBig( mapTimeStamp );
  692. }
  693. // parse the file
  694. while ( 1 ) {
  695. if ( !src->ReadToken( &token ) ) {
  696. break;
  697. }
  698. common->UpdateLevelLoadPacifier();
  699. if ( token == "model" ) {
  700. lastModel = ParseModel( src, name, currentTimeStamp, outputFile );
  701. // add it to the model manager list
  702. renderModelManager->AddModel( lastModel );
  703. // save it in the list to free when clearing this map
  704. localModels.Append( lastModel );
  705. numEntries++;
  706. continue;
  707. }
  708. if ( token == "shadowModel" ) {
  709. lastModel = ParseShadowModel( src, outputFile );
  710. // add it to the model manager list
  711. renderModelManager->AddModel( lastModel );
  712. // save it in the list to free when clearing this map
  713. localModels.Append( lastModel );
  714. numEntries++;
  715. continue;
  716. }
  717. if ( token == "interAreaPortals" ) {
  718. ParseInterAreaPortals( src, outputFile );
  719. numEntries++;
  720. continue;
  721. }
  722. if ( token == "nodes" ) {
  723. ParseNodes( src, outputFile );
  724. numEntries++;
  725. continue;
  726. }
  727. src->Error( "idRenderWorldLocal::InitFromMap: bad token \"%s\"", token.c_str() );
  728. }
  729. delete src;
  730. if ( outputFile != NULL ) {
  731. outputFile->Seek( 0, FS_SEEK_SET );
  732. int magic = BPROC_MAGIC;
  733. outputFile->WriteBig( magic );
  734. outputFile->WriteBig( numEntries );
  735. }
  736. }
  737. // if it was a trivial map without any areas, create a single area
  738. if ( !numPortalAreas ) {
  739. ClearWorld();
  740. }
  741. // find the points where we can early-our of reference pushing into the BSP tree
  742. CommonChildrenArea_r( &areaNodes[0] );
  743. AddWorldModelEntities();
  744. ClearPortalStates();
  745. // done!
  746. return true;
  747. }
  748. /*
  749. =====================
  750. idRenderWorldLocal::ClearPortalStates
  751. =====================
  752. */
  753. void idRenderWorldLocal::ClearPortalStates() {
  754. // all portals start off open
  755. for ( int i = 0; i < numInterAreaPortals; i++ ) {
  756. doublePortals[i].blockingBits = PS_BLOCK_NONE;
  757. }
  758. // flood fill all area connections
  759. for ( int i = 0; i < numPortalAreas; i++ ) {
  760. for ( int j = 0; j < NUM_PORTAL_ATTRIBUTES; j++ ) {
  761. connectedAreaNum++;
  762. FloodConnectedAreas( &portalAreas[i], j );
  763. }
  764. }
  765. }
  766. /*
  767. =====================
  768. idRenderWorldLocal::AddWorldModelEntities
  769. =====================
  770. */
  771. void idRenderWorldLocal::AddWorldModelEntities() {
  772. // add the world model for each portal area
  773. // we can't just call AddEntityDef, because that would place the references
  774. // based on the bounding box, rather than explicitly into the correct area
  775. for ( int i = 0; i < numPortalAreas; i++ ) {
  776. common->UpdateLevelLoadPacifier();
  777. idRenderEntityLocal * def = new (TAG_RENDER_ENTITY) idRenderEntityLocal;
  778. // try and reuse a free spot
  779. int index = entityDefs.FindNull();
  780. if ( index == -1 ) {
  781. index = entityDefs.Append(def);
  782. } else {
  783. entityDefs[index] = def;
  784. }
  785. def->index = index;
  786. def->world = this;
  787. def->parms.hModel = renderModelManager->FindModel( va("_area%i", i ) );
  788. if ( def->parms.hModel->IsDefaultModel() || !def->parms.hModel->IsStaticWorldModel() ) {
  789. common->Error( "idRenderWorldLocal::InitFromMap: bad area model lookup" );
  790. }
  791. idRenderModel *hModel = def->parms.hModel;
  792. for ( int j = 0; j < hModel->NumSurfaces(); j++ ) {
  793. const modelSurface_t *surf = hModel->Surface( j );
  794. if ( surf->shader->GetName() == idStr( "textures/smf/portal_sky" ) ) {
  795. def->needsPortalSky = true;
  796. }
  797. }
  798. // the local and global reference bounds are the same for area models
  799. def->localReferenceBounds = def->parms.hModel->Bounds();
  800. def->globalReferenceBounds = def->parms.hModel->Bounds();
  801. def->parms.axis[0][0] = 1.0f;
  802. def->parms.axis[1][1] = 1.0f;
  803. def->parms.axis[2][2] = 1.0f;
  804. // in case an explicit shader is used on the world, we don't
  805. // want it to have a 0 alpha or color
  806. def->parms.shaderParms[0] = 1.0f;
  807. def->parms.shaderParms[1] = 1.0f;
  808. def->parms.shaderParms[2] = 1.0f;
  809. def->parms.shaderParms[3] = 1.0f;
  810. R_DeriveEntityData( def );
  811. AddEntityRefToArea( def, &portalAreas[i] );
  812. }
  813. }
  814. /*
  815. =====================
  816. CheckAreaForPortalSky
  817. =====================
  818. */
  819. bool idRenderWorldLocal::CheckAreaForPortalSky( int areaNum ) {
  820. assert( areaNum >= 0 && areaNum < numPortalAreas );
  821. for ( areaReference_t * ref = portalAreas[areaNum].entityRefs.areaNext; ref->entity; ref = ref->areaNext ) {
  822. assert( ref->area == &portalAreas[areaNum] );
  823. if ( ref->entity && ref->entity->needsPortalSky ) {
  824. return true;
  825. }
  826. }
  827. return false;
  828. }
  829. /*
  830. =====================
  831. ResetLocalRenderModels
  832. =====================
  833. */
  834. void idRenderWorldLocal::ResetLocalRenderModels() {
  835. localModels.Clear(); // Clear out the list when switching between expansion packs, so InitFromMap doesn't try to delete the list whose content has already been deleted by the model manager being re-started
  836. }