Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1637 lines
38 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "vbsp.h"
  9. #include "disp_vbsp.h"
  10. #include "UtlVector.h"
  11. #include "faces.h"
  12. #include "builddisp.h"
  13. #include "tier1/strtools.h"
  14. #include "utilmatlib.h"
  15. #include "utldict.h"
  16. #include "map.h"
  17. int c_nofaces;
  18. int c_facenodes;
  19. // NOTE: This is a global used to link faces back to the tree node/portals they came from
  20. // it's used when filling water volumes
  21. node_t *dfacenodes[MAX_MAP_FACES];
  22. /*
  23. =========================================================
  24. ONLY SAVE OUT PLANES THAT ARE ACTUALLY USED AS NODES
  25. =========================================================
  26. */
  27. void EmitFaceVertexes (face_t **list, face_t *f);
  28. void AssignOccluderAreas();
  29. /*
  30. ============
  31. EmitPlanes
  32. There is no oportunity to discard planes, because all of the original
  33. brushes will be saved in the map.
  34. ============
  35. */
  36. void EmitPlanes (void)
  37. {
  38. int i;
  39. dplane_t *dp;
  40. plane_t *mp;
  41. int planetranslate[MAX_MAP_PLANES];
  42. mp = g_MainMap->mapplanes;
  43. for (i=0 ; i<g_MainMap->nummapplanes ; i++, mp++)
  44. {
  45. dp = &dplanes[numplanes];
  46. planetranslate[i] = numplanes;
  47. VectorCopy ( mp->normal, dp->normal);
  48. dp->dist = mp->dist;
  49. dp->type = mp->type;
  50. numplanes++;
  51. }
  52. }
  53. //========================================================
  54. void EmitMarkFace (dleaf_t *leaf_p, face_t *f)
  55. {
  56. int i;
  57. int facenum;
  58. while (f->merged)
  59. f = f->merged;
  60. if (f->split[0])
  61. {
  62. EmitMarkFace (leaf_p, f->split[0]);
  63. EmitMarkFace (leaf_p, f->split[1]);
  64. return;
  65. }
  66. facenum = f->outputnumber;
  67. if (facenum == -1)
  68. return; // degenerate face
  69. if (facenum < 0 || facenum >= numfaces)
  70. Error ("Bad leafface");
  71. for (i=leaf_p->firstleafface ; i<numleaffaces ; i++)
  72. if (dleaffaces[i] == facenum)
  73. break; // merged out face
  74. if (i == numleaffaces)
  75. {
  76. if (numleaffaces >= MAX_MAP_LEAFFACES)
  77. Error ("Too many detail brush faces, max = %d\n", MAX_MAP_LEAFFACES);
  78. dleaffaces[numleaffaces] = facenum;
  79. numleaffaces++;
  80. }
  81. }
  82. /*
  83. ==================
  84. EmitLeaf
  85. ==================
  86. */
  87. void EmitLeaf (node_t *node)
  88. {
  89. dleaf_t *leaf_p;
  90. portal_t *p;
  91. int s;
  92. face_t *f;
  93. bspbrush_t *b;
  94. int i;
  95. int brushnum;
  96. leafface_t *pList;
  97. // emit a leaf
  98. if (numleafs >= MAX_MAP_LEAFS)
  99. Error ("Too many BSP leaves, max = %d", MAX_MAP_LEAFS);
  100. node->diskId = numleafs;
  101. leaf_p = &dleafs[numleafs];
  102. numleafs++;
  103. if( nummodels == 0 )
  104. {
  105. leaf_p->cluster = node->cluster;
  106. }
  107. else
  108. {
  109. // Submodels don't have clusters. If this isn't set to -1 here, then there
  110. // will be multiple leaves (albeit from different models) that reference
  111. // the same cluster and parts of the code like ivp.cpp's ConvertWaterModelToPhysCollide
  112. // won't work.
  113. leaf_p->cluster = -1;
  114. }
  115. leaf_p->contents = node->contents;
  116. leaf_p->area = node->area;
  117. // By default, assume the leaf can see the skybox.
  118. // VRAD will do the actual computation to see if it really can see the skybox
  119. leaf_p->flags = LEAF_FLAGS_SKY;
  120. //
  121. // write bounding box info
  122. //
  123. VECTOR_COPY (node->mins, leaf_p->mins);
  124. VECTOR_COPY (node->maxs, leaf_p->maxs);
  125. //
  126. // write the leafbrushes
  127. //
  128. leaf_p->firstleafbrush = numleafbrushes;
  129. for (b=node->brushlist ; b ; b=b->next)
  130. {
  131. if (numleafbrushes >= MAX_MAP_LEAFBRUSHES)
  132. Error ("Too many brushes in one leaf, max = %d", MAX_MAP_LEAFBRUSHES);
  133. brushnum = b->original - g_MainMap->mapbrushes;
  134. for (i=leaf_p->firstleafbrush ; i<numleafbrushes ; i++)
  135. {
  136. if (dleafbrushes[i] == brushnum)
  137. break;
  138. }
  139. if (i == numleafbrushes)
  140. {
  141. dleafbrushes[numleafbrushes] = brushnum;
  142. numleafbrushes++;
  143. }
  144. }
  145. leaf_p->numleafbrushes = numleafbrushes - leaf_p->firstleafbrush;
  146. //
  147. // write the leaffaces
  148. //
  149. if (leaf_p->contents & CONTENTS_SOLID)
  150. return; // no leaffaces in solids
  151. leaf_p->firstleafface = numleaffaces;
  152. for (p = node->portals ; p ; p = p->next[s])
  153. {
  154. s = (p->nodes[1] == node);
  155. f = p->face[s];
  156. if (!f)
  157. continue; // not a visible portal
  158. EmitMarkFace (leaf_p, f);
  159. }
  160. // emit the detail faces
  161. for ( pList = node->leaffacelist; pList; pList = pList->pNext )
  162. {
  163. EmitMarkFace( leaf_p, pList->pFace );
  164. }
  165. leaf_p->numleaffaces = numleaffaces - leaf_p->firstleafface;
  166. }
  167. // per face plane - original face "side" list
  168. side_t *pOrigFaceSideList[MAX_MAP_PLANES];
  169. //-----------------------------------------------------------------------------
  170. //-----------------------------------------------------------------------------
  171. int CreateOrigFace( face_t *f )
  172. {
  173. int i, j;
  174. dface_t *of;
  175. side_t *side;
  176. int vIndices[128];
  177. int eIndex[2];
  178. winding_t *pWinding;
  179. // not a real face!
  180. if( !f->w )
  181. return -1;
  182. // get the original face -- the "side"
  183. side = f->originalface;
  184. // get the original face winding
  185. if( !side->winding )
  186. {
  187. return -1;
  188. }
  189. //
  190. // get the next original face
  191. //
  192. if( numorigfaces >= MAX_MAP_FACES )
  193. Error( "Too many faces in map, max = %d", MAX_MAP_FACES );
  194. of = &dorigfaces[numorigfaces];
  195. numorigfaces++;
  196. // set original face to -1 -- it is an origianl face!
  197. of->origFace = -1;
  198. //
  199. // add side to plane list
  200. //
  201. side->next = pOrigFaceSideList[f->planenum];
  202. pOrigFaceSideList[f->planenum] = side;
  203. side->origIndex = numorigfaces - 1;
  204. pWinding = CopyWinding( side->winding );
  205. //
  206. // plane info
  207. //
  208. of->planenum = side->planenum;
  209. if ( side->contents & CONTENTS_DETAIL )
  210. of->onNode = 0;
  211. else
  212. of->onNode = 1;
  213. of->side = side->planenum & 1;
  214. //
  215. // edge info
  216. //
  217. of->firstedge = numsurfedges;
  218. of->numedges = side->winding->numpoints;
  219. //
  220. // material info
  221. //
  222. of->texinfo = side->texinfo;
  223. of->dispinfo = f->dispinfo;
  224. //
  225. // save the vertices
  226. //
  227. for( i = 0; i < pWinding->numpoints; i++ )
  228. {
  229. //
  230. // compare vertices
  231. //
  232. vIndices[i] = GetVertexnum( pWinding->p[i] );
  233. }
  234. //
  235. // save off points -- as edges
  236. //
  237. for( i = 0; i < pWinding->numpoints; i++ )
  238. {
  239. //
  240. // look for matching edges first
  241. //
  242. eIndex[0] = vIndices[i];
  243. eIndex[1] = vIndices[(i+1)%pWinding->numpoints];
  244. for( j = firstmodeledge; j < numedges; j++ )
  245. {
  246. if( ( eIndex[0] == dedges[j].v[1] ) &&
  247. ( eIndex[1] == dedges[j].v[0] ) &&
  248. ( edgefaces[j][0]->contents == f->contents ) )
  249. {
  250. // check for multiple backward edges!! -- shouldn't have
  251. if( edgefaces[j][1] )
  252. continue;
  253. // set back edge
  254. edgefaces[j][1] = f;
  255. //
  256. // get next surface edge
  257. //
  258. if( numsurfedges >= MAX_MAP_SURFEDGES )
  259. Error( "Too much brush geometry in bsp, numsurfedges == MAX_MAP_SURFEDGES" );
  260. dsurfedges[numsurfedges] = -j;
  261. numsurfedges++;
  262. break;
  263. }
  264. }
  265. if( j == numedges )
  266. {
  267. //
  268. // get next edge
  269. //
  270. AddEdge( eIndex[0], eIndex[1], f );
  271. //
  272. // get next surface edge
  273. //
  274. if( numsurfedges >= MAX_MAP_SURFEDGES )
  275. Error( "Too much brush geometry in bsp, numsurfedges == MAX_MAP_SURFEDGES" );
  276. dsurfedges[numsurfedges] = ( numedges - 1 );
  277. numsurfedges++;
  278. }
  279. }
  280. // return the index
  281. return ( numorigfaces - 1 );
  282. }
  283. //-----------------------------------------------------------------------------
  284. // Purpose: search for a face within the origface list and return the index if
  285. // found
  286. // Input: f - the face to compare
  287. // Output: the index of the face it found, -1 if not found
  288. //-----------------------------------------------------------------------------
  289. int FindOrigFace( face_t *f )
  290. {
  291. int i;
  292. static int bClear = 0;
  293. side_t *pSide;
  294. //
  295. // initially clear the face side lists (per face plane)
  296. //
  297. if( !bClear )
  298. {
  299. for( i = 0; i < MAX_MAP_PLANES; i++ )
  300. {
  301. pOrigFaceSideList[i] = NULL;
  302. }
  303. bClear = 1;
  304. }
  305. //
  306. // compare the sides
  307. //
  308. for( pSide = pOrigFaceSideList[f->planenum]; pSide; pSide = pSide->next )
  309. {
  310. if( pSide == f->originalface )
  311. return pSide->origIndex;
  312. }
  313. // original face not found in list
  314. return -1;
  315. }
  316. //-----------------------------------------------------------------------------
  317. // Purpose: to find an the original face within the list of original faces, if
  318. // a match is not found then create a new origFace -- either way pass
  319. // back the index of the origface in the list
  320. // Input: f - face containing the original face information
  321. // Output: the index of the origface in the origface list
  322. //-----------------------------------------------------------------------------
  323. int FindOrCreateOrigFace( face_t *f )
  324. {
  325. int index;
  326. // check for an original face
  327. if( !f->originalface )
  328. return -1;
  329. //
  330. // find or create a orig face and return the index
  331. //
  332. index = FindOrigFace( f );
  333. if( index == -1 )
  334. return CreateOrigFace( f );
  335. else if( index == -2 )
  336. return -1;
  337. return index;
  338. }
  339. // dumb linear search. Hopefully this is not too slow
  340. uint16 BrushIndexFromSide( side_t *pSide )
  341. {
  342. if ( pSide->original )
  343. {
  344. pSide = pSide->original;
  345. }
  346. for ( int i = 0; i < g_MainMap->nummapbrushes; i++ )
  347. {
  348. mapbrush_t *pBrush = &g_MainMap->mapbrushes[i];
  349. const side_t *pFirstSide = pBrush->original_sides;
  350. const side_t *pLastSide = pFirstSide + pBrush->numsides;
  351. if ( pSide >= pFirstSide && pSide < pLastSide )
  352. {
  353. return uint16(i);
  354. }
  355. }
  356. return uint16(-1);
  357. }
  358. void BuildBrushListForFace( CUtlVectorFixedGrowable<int, 64> &brushList, face_t *pFace )
  359. {
  360. int nFaceBrush = BrushIndexFromSide( pFace->originalface );
  361. brushList.AddToTail( nFaceBrush );
  362. if ( pFace->pMergedList )
  363. {
  364. for ( int i = 0; i < pFace->pMergedList->Count(); i++ )
  365. {
  366. int nAddBrush = BrushIndexFromSide( pFace->pMergedList->Element(i) );
  367. if ( nAddBrush == uint16(-1) )
  368. continue;
  369. bool bFound = false;
  370. for ( int j = 0; j < brushList.Count(); j++ )
  371. {
  372. if ( nAddBrush == brushList[j] )
  373. {
  374. bFound = true;
  375. break;
  376. }
  377. }
  378. if ( !bFound )
  379. {
  380. brushList.AddToTail( nAddBrush );
  381. }
  382. }
  383. }
  384. }
  385. /*
  386. ==================
  387. EmitFace
  388. ==================
  389. */
  390. void EmitFace( face_t *f, qboolean onNode )
  391. {
  392. dface_t *df;
  393. int i;
  394. int e;
  395. // void SubdivideFaceBySubdivSize( face_t *f ); // garymcthack
  396. // SubdivideFaceBySubdivSize( f );
  397. // set initial output number
  398. f->outputnumber = -1;
  399. // degenerated
  400. if( f->numpoints < 3 )
  401. return;
  402. // not a final face
  403. if( f->merged || f->split[0] || f->split[1] )
  404. return;
  405. // don't emit NODRAW faces for runtime
  406. if ( texinfo[f->texinfo].flags & SURF_NODRAW )
  407. {
  408. // keep NODRAW terrain surfaces though
  409. if ( f->dispinfo == -1 )
  410. return;
  411. Warning("NODRAW on terrain surface!\n");
  412. }
  413. // save output number so leaffaces can use
  414. f->outputnumber = numfaces;
  415. //
  416. // get the next available .bsp face slot
  417. //
  418. if (numfaces >= MAX_MAP_FACES)
  419. Error( "Too many faces in map, max = %d", MAX_MAP_FACES );
  420. df = &dfaces[numfaces];
  421. // Save the correlation between dfaces and faces -- since dfaces doesnt have worldcraft face id
  422. dfaceids.AddToTail();
  423. dfaceids[numfaces].hammerfaceid = f->originalface->id;
  424. // save the brush this face came from
  425. int nOut = dfacebrushlists.AddToTail();
  426. Assert( nOut == numfaces );
  427. CUtlVectorFixedGrowable<int, 64> brushList;
  428. BuildBrushListForFace( brushList, f );
  429. if ( brushList.Count() == 1 )
  430. {
  431. dfacebrushlists[nOut].m_nFaceBrushCount = 1;
  432. dfacebrushlists[nOut].m_nFaceBrushStart = brushList[0];
  433. }
  434. else
  435. {
  436. dfacebrushlists[nOut].m_nFaceBrushCount = brushList.Count();
  437. int nStart = dfacebrushes.Count();
  438. dfacebrushlists[nOut].m_nFaceBrushStart = nStart;
  439. dfacebrushes.AddMultipleToTail( brushList.Count() );
  440. for ( int i = 0; i < brushList.Count(); i++ )
  441. {
  442. dfacebrushes[nStart+i] = brushList[i];
  443. }
  444. }
  445. numfaces++;
  446. //
  447. // plane info - planenum is used by qlight, but not quake
  448. //
  449. df->planenum = f->planenum;
  450. df->onNode = onNode;
  451. df->side = f->planenum & 1;
  452. //
  453. // material info
  454. //
  455. df->texinfo = f->texinfo;
  456. df->dispinfo = f->dispinfo;
  457. df->smoothingGroups = f->smoothingGroups;
  458. // save the original "side"/face data
  459. df->origFace = FindOrCreateOrigFace( f );
  460. df->surfaceFogVolumeID = -1;
  461. dfacenodes[numfaces-1] = f->fogVolumeLeaf;
  462. if ( f->fogVolumeLeaf )
  463. {
  464. Assert( f->fogVolumeLeaf->planenum == PLANENUM_LEAF );
  465. }
  466. //
  467. // edge info
  468. //
  469. df->firstedge = numsurfedges;
  470. df->numedges = f->numpoints;
  471. // UNDONE: Nodraw faces have no winding - revisit to see if this is necessary
  472. if ( f->w )
  473. {
  474. df->area = WindingArea( f->w );
  475. }
  476. else
  477. {
  478. df->area = 0;
  479. }
  480. df->firstPrimID = f->firstPrimID;
  481. df->SetNumPrims( f->numPrims );
  482. df->SetDynamicShadowsEnabled( f->originalface->m_bDynamicShadowsEnabled );
  483. //
  484. // save off points -- as edges
  485. //
  486. for( i = 0; i < f->numpoints; i++ )
  487. {
  488. //e = GetEdge (f->pts[i], f->pts[(i+1)%f->numpoints], f);
  489. e = GetEdge2 (f->vertexnums[i], f->vertexnums[(i+1)%f->numpoints], f);
  490. if (numsurfedges >= MAX_MAP_SURFEDGES)
  491. Error( "Too much brush geometry in bsp, numsurfedges == MAX_MAP_SURFEDGES" );
  492. dsurfedges[numsurfedges] = e;
  493. numsurfedges++;
  494. }
  495. // Create overlay face lists.
  496. side_t *pSide = f->originalface;
  497. if ( pSide )
  498. {
  499. int nOverlayCount = pSide->aOverlayIds.Count();
  500. if ( nOverlayCount > 0 )
  501. {
  502. Overlay_AddFaceToLists( ( numfaces - 1 ), pSide );
  503. }
  504. nOverlayCount = pSide->aWaterOverlayIds.Count();
  505. if ( nOverlayCount > 0 )
  506. {
  507. OverlayTransition_AddFaceToLists( ( numfaces - 1 ), pSide );
  508. }
  509. }
  510. }
  511. //-----------------------------------------------------------------------------
  512. // Purpose: Emit all of the faces stored at the leaves (faces from detail brushes)
  513. //-----------------------------------------------------------------------------
  514. void EmitLeafFaces( face_t *pLeafFaceList )
  515. {
  516. face_t *f = pLeafFaceList;
  517. while ( f )
  518. {
  519. EmitFace( f, false );
  520. f = f->next;
  521. }
  522. }
  523. //-----------------------------------------------------------------------------
  524. // Purpose: Free the list of faces stored at the leaves
  525. //-----------------------------------------------------------------------------
  526. void FreeLeafFaces( face_t *pLeafFaceList )
  527. {
  528. int count = 0;
  529. face_t *f, *next;
  530. f = pLeafFaceList;
  531. while ( f )
  532. {
  533. next = f->next;
  534. FreeFace( f );
  535. f = next;
  536. count++;
  537. }
  538. }
  539. /*
  540. ============
  541. EmitDrawingNode_r
  542. ============
  543. */
  544. int EmitDrawNode_r (node_t *node)
  545. {
  546. dnode_t *n;
  547. face_t *f;
  548. int i;
  549. if (node->planenum == PLANENUM_LEAF)
  550. {
  551. EmitLeaf (node);
  552. return -numleafs;
  553. }
  554. // emit a node
  555. if (numnodes == MAX_MAP_NODES)
  556. Error ("MAX_MAP_NODES");
  557. node->diskId = numnodes;
  558. n = &dnodes[numnodes];
  559. numnodes++;
  560. VECTOR_COPY (node->mins, n->mins);
  561. VECTOR_COPY (node->maxs, n->maxs);
  562. if (node->planenum & 1)
  563. Error ("WriteDrawNodes_r: odd planenum");
  564. n->planenum = node->planenum;
  565. n->firstface = numfaces;
  566. n->area = node->area;
  567. if (!node->faces)
  568. c_nofaces++;
  569. else
  570. c_facenodes++;
  571. for (f=node->faces ; f ; f=f->next)
  572. EmitFace (f, true);
  573. n->numfaces = numfaces - n->firstface;
  574. //
  575. // recursively output the other nodes
  576. //
  577. for (i=0 ; i<2 ; i++)
  578. {
  579. if (node->children[i]->planenum == PLANENUM_LEAF)
  580. {
  581. n->children[i] = -(numleafs + 1);
  582. EmitLeaf (node->children[i]);
  583. }
  584. else
  585. {
  586. n->children[i] = numnodes;
  587. EmitDrawNode_r (node->children[i]);
  588. }
  589. }
  590. return n - dnodes;
  591. }
  592. //=========================================================
  593. // This will generate a scratchpad file with the level's geometry in it and the noshadow faces drawn red.
  594. // #define SCRATCHPAD_NO_SHADOW_FACES
  595. #if defined( SCRATCHPAD_NO_SHADOW_FACES )
  596. #include "scratchpad_helpers.h"
  597. IScratchPad3D *g_pPad;
  598. #endif
  599. void MarkNoShadowFaces()
  600. {
  601. #if defined( SCRATCHPAD_NO_SHADOW_FACES )
  602. g_pPad = ScratchPad3D_Create();
  603. ScratchPad_DrawWorld( g_pPad, false, CSPColor(1,1,1,0.3) );
  604. for ( int iFace=0; iFace < numfaces; iFace++ )
  605. {
  606. dface_t *pFace = &dfaces[iFace];
  607. if ( !pFace->AreDynamicShadowsEnabled() )
  608. {
  609. ScratchPad_DrawFace( g_pPad, pFace, iFace, CSPColor(1,0,0,1), Vector(1,0,0) );
  610. ScratchPad_DrawFace( g_pPad, pFace, iFace, CSPColor(1,0,0,1), Vector(-1,0,0) );
  611. ScratchPad_DrawFace( g_pPad, pFace, iFace, CSPColor(1,0,0,1), Vector(0,1,0) );
  612. }
  613. }
  614. g_pPad->Release();
  615. #endif
  616. }
  617. struct texinfomap_t
  618. {
  619. int refCount;
  620. int outputIndex;
  621. };
  622. struct texdatamap_t
  623. {
  624. int refCount;
  625. int outputIndex;
  626. };
  627. // Find the best used texinfo to remap this brush side
  628. int FindMatchingBrushSideTexinfo( int sideIndex, const texinfomap_t *pMap )
  629. {
  630. dbrushside_t &side = dbrushsides[sideIndex];
  631. // find one with the same flags & surfaceprops (even if the texture name is different)
  632. int sideTexFlags = texinfo[side.texinfo].flags;
  633. int sideTexData = texinfo[side.texinfo].texdata;
  634. int sideSurfaceProp = g_SurfaceProperties[sideTexData];
  635. for ( int j = 0; j < texinfo.Count(); j++ )
  636. {
  637. if ( pMap[j].refCount > 0 &&
  638. texinfo[j].flags == sideTexFlags &&
  639. g_SurfaceProperties[texinfo[j].texdata] == sideSurfaceProp )
  640. {
  641. // found one
  642. return j;
  643. }
  644. }
  645. // can't find a better match
  646. return side.texinfo;
  647. }
  648. // Remove all unused texinfos and rebuild array
  649. void ComapctTexinfoArray( texinfomap_t *pMap )
  650. {
  651. CUtlVector<texinfo_t> old;
  652. old.CopyArray( texinfo.Base(), texinfo.Count() );
  653. texinfo.RemoveAll();
  654. int firstSky = -1;
  655. int first2DSky = -1;
  656. for ( int i = 0; i < old.Count(); i++ )
  657. {
  658. if ( !pMap[i].refCount )
  659. {
  660. pMap[i].outputIndex = -1;
  661. continue;
  662. }
  663. // only add one sky texinfo + one 2D sky texinfo
  664. if ( old[i].flags & SURF_SKY2D )
  665. {
  666. if ( first2DSky < 0 )
  667. {
  668. first2DSky = texinfo.AddToTail( old[i] );
  669. }
  670. pMap[i].outputIndex = first2DSky;
  671. continue;
  672. }
  673. if ( old[i].flags & SURF_SKY )
  674. {
  675. if ( firstSky < 0 )
  676. {
  677. firstSky = texinfo.AddToTail( old[i] );
  678. }
  679. pMap[i].outputIndex = firstSky;
  680. continue;
  681. }
  682. pMap[i].outputIndex = texinfo.AddToTail( old[i] );
  683. }
  684. }
  685. void CompactTexdataArray( texdatamap_t *pMap )
  686. {
  687. CUtlVector<char> oldStringData;
  688. oldStringData.CopyArray( g_TexDataStringData.Base(), g_TexDataStringData.Count() );
  689. g_TexDataStringData.RemoveAll();
  690. CUtlVector<int> oldStringTable;
  691. oldStringTable.CopyArray( g_TexDataStringTable.Base(), g_TexDataStringTable.Count() );
  692. g_TexDataStringTable.RemoveAll();
  693. CUtlVector<dtexdata_t> oldTexData;
  694. oldTexData.CopyArray( dtexdata, numtexdata );
  695. // clear current table and rebuild
  696. numtexdata = 0;
  697. for ( int i = 0; i < oldTexData.Count(); i++ )
  698. {
  699. const char *pString = &oldStringData[oldStringTable[oldTexData[i].nameStringTableID]];
  700. if ( !pMap[i].refCount && V_stristr( pString, "tools/tools" ) )
  701. pMap[i].refCount = 1; // special case for tools textures, artificially bump refcount
  702. // unreferenced, note in map and skip
  703. if ( !pMap[i].refCount )
  704. {
  705. pMap[i].outputIndex = -1;
  706. continue;
  707. }
  708. pMap[i].outputIndex = numtexdata;
  709. // get old string and re-add to table
  710. int nameIndex = TexDataStringTable_AddOrFindString( pString );
  711. // copy old texdata and fixup with new name in compacted table
  712. dtexdata[numtexdata] = oldTexData[i];
  713. dtexdata[numtexdata].nameStringTableID = nameIndex;
  714. numtexdata++;
  715. }
  716. }
  717. void CompactTexinfos()
  718. {
  719. Msg("Compacting texture/material tables...\n");
  720. texinfomap_t *texinfoMap = new texinfomap_t[texinfo.Count()];
  721. texdatamap_t *texdataMap = new texdatamap_t[numtexdata];
  722. memset( texinfoMap, 0, sizeof(texinfoMap[0])*texinfo.Count() );
  723. memset( texdataMap, 0, sizeof(texdataMap[0])*numtexdata );
  724. int i;
  725. // get texinfos referenced by faces
  726. for ( i = 0; i < numfaces; i++ )
  727. {
  728. texinfoMap[dfaces[i].texinfo].refCount++;
  729. }
  730. // get texinfos referenced by brush sides
  731. for ( i = 0; i < numbrushsides; i++ )
  732. {
  733. // not referenced by any visible geometry
  734. Assert( dbrushsides[i].texinfo >= 0 );
  735. if ( !texinfoMap[dbrushsides[i].texinfo].refCount )
  736. {
  737. dbrushsides[i].texinfo = FindMatchingBrushSideTexinfo( i, texinfoMap );
  738. // didn't find anything suitable, go ahead and reference it
  739. if ( !texinfoMap[dbrushsides[i].texinfo].refCount )
  740. {
  741. texinfoMap[dbrushsides[i].texinfo].refCount++;
  742. }
  743. }
  744. }
  745. // get texinfos referenced by overlays
  746. for ( i = 0; i < g_nOverlayCount; i++ )
  747. {
  748. texinfoMap[g_Overlays[i].nTexInfo].refCount++;
  749. }
  750. for ( i = 0; i < numleafwaterdata; i++ )
  751. {
  752. if ( dleafwaterdata[i].surfaceTexInfoID >= 0 )
  753. {
  754. texinfoMap[dleafwaterdata[i].surfaceTexInfoID].refCount++;
  755. }
  756. }
  757. for ( i = 0; i < *pNumworldlights; i++ )
  758. {
  759. if ( dworldlights[i].texinfo >= 0 )
  760. {
  761. texinfoMap[dworldlights[i].texinfo].refCount++;
  762. }
  763. }
  764. for ( i = 0; i < g_nWaterOverlayCount; i++ )
  765. {
  766. if ( g_WaterOverlays[i].nTexInfo >= 0 )
  767. {
  768. texinfoMap[g_WaterOverlays[i].nTexInfo].refCount++;
  769. }
  770. }
  771. // reference all used texdatas
  772. for ( i = 0; i < texinfo.Count(); i++ )
  773. {
  774. if ( texinfoMap[i].refCount > 0 )
  775. {
  776. texdataMap[texinfo[i].texdata].refCount++;
  777. }
  778. }
  779. int oldCount = texinfo.Count();
  780. int oldTexdataCount = numtexdata;
  781. int oldTexdataString = g_TexDataStringData.Count();
  782. ComapctTexinfoArray( texinfoMap );
  783. CompactTexdataArray( texdataMap );
  784. for ( i = 0; i < texinfo.Count(); i++ )
  785. {
  786. int mapIndex = texdataMap[texinfo[i].texdata].outputIndex;
  787. Assert( mapIndex >= 0 );
  788. texinfo[i].texdata = mapIndex;
  789. //const char *pName = TexDataStringTable_GetString( dtexdata[texinfo[i].texdata].nameStringTableID );
  790. }
  791. // remap texinfos on faces
  792. for ( i = 0; i < numfaces; i++ )
  793. {
  794. Assert( texinfoMap[dfaces[i].texinfo].outputIndex >= 0 );
  795. dfaces[i].texinfo = texinfoMap[dfaces[i].texinfo].outputIndex;
  796. }
  797. // remap texinfos on brushsides
  798. for ( i = 0; i < numbrushsides; i++ )
  799. {
  800. Assert( texinfoMap[dbrushsides[i].texinfo].outputIndex >= 0 );
  801. dbrushsides[i].texinfo = texinfoMap[dbrushsides[i].texinfo].outputIndex;
  802. }
  803. // remap texinfos on overlays
  804. for ( i = 0; i < g_nOverlayCount; i++ )
  805. {
  806. g_Overlays[i].nTexInfo = texinfoMap[g_Overlays[i].nTexInfo].outputIndex;
  807. }
  808. // remap leaf water data
  809. for ( i = 0; i < numleafwaterdata; i++ )
  810. {
  811. if ( dleafwaterdata[i].surfaceTexInfoID >= 0 )
  812. {
  813. dleafwaterdata[i].surfaceTexInfoID = texinfoMap[dleafwaterdata[i].surfaceTexInfoID].outputIndex;
  814. }
  815. }
  816. // remap world lights
  817. for ( i = 0; i < *pNumworldlights; i++ )
  818. {
  819. if ( dworldlights[i].texinfo >= 0 )
  820. {
  821. dworldlights[i].texinfo = texinfoMap[dworldlights[i].texinfo].outputIndex;
  822. }
  823. }
  824. // remap water overlays
  825. for ( i = 0; i < g_nWaterOverlayCount; i++ )
  826. {
  827. if ( g_WaterOverlays[i].nTexInfo >= 0 )
  828. {
  829. g_WaterOverlays[i].nTexInfo = texinfoMap[g_WaterOverlays[i].nTexInfo].outputIndex;
  830. }
  831. }
  832. Msg("Reduced %d texinfos to %d\n", oldCount, texinfo.Count() );
  833. Msg("Reduced %d texdatas to %d (%d bytes to %d)\n", oldTexdataCount, numtexdata, oldTexdataString, g_TexDataStringData.Count() );
  834. delete[] texinfoMap;
  835. delete[] texdataMap;
  836. }
  837. /*
  838. ============
  839. WriteBSP
  840. ============
  841. */
  842. void WriteBSP (node_t *headnode, face_t *pLeafFaceList )
  843. {
  844. int i;
  845. int oldfaces;
  846. int oldorigfaces;
  847. c_nofaces = 0;
  848. c_facenodes = 0;
  849. qprintf ("--- WriteBSP ---\n");
  850. oldfaces = numfaces;
  851. oldorigfaces = numorigfaces;
  852. GetEdge2_InitOptimizedList();
  853. EmitLeafFaces( pLeafFaceList );
  854. dmodels[nummodels].headnode = EmitDrawNode_r (headnode);
  855. // Only emit area portals for the main world.
  856. if( nummodels == 0 )
  857. {
  858. EmitAreaPortals (headnode);
  859. }
  860. //
  861. // add all displacement faces for the particular model
  862. //
  863. for( i = 0; i < nummapdispinfo; i++ )
  864. {
  865. int entityIndex = GetDispInfoEntityNum( &mapdispinfo[i] );
  866. if( entityIndex == entity_num )
  867. {
  868. EmitFaceVertexes( NULL, &mapdispinfo[i].face );
  869. EmitFace( &mapdispinfo[i].face, FALSE );
  870. }
  871. }
  872. EmitWaterVolumesForBSP( &dmodels[nummodels], headnode );
  873. qprintf ("%5i nodes with faces\n", c_facenodes);
  874. qprintf ("%5i nodes without faces\n", c_nofaces);
  875. qprintf ("%5i faces\n", numfaces-oldfaces);
  876. qprintf( "%5i original faces\n", numorigfaces-oldorigfaces );
  877. }
  878. //===========================================================
  879. /*
  880. ============
  881. SetModelNumbers
  882. ============
  883. */
  884. void SetModelNumbers (void)
  885. {
  886. int i;
  887. int models;
  888. char value[10];
  889. models = 1;
  890. for (i=1 ; i<num_entities ; i++)
  891. {
  892. if (!entities[i].numbrushes)
  893. continue;
  894. if ( !IsFuncOccluder(i) )
  895. {
  896. sprintf (value, "*%i", models);
  897. models++;
  898. }
  899. else
  900. {
  901. sprintf (value, "");
  902. }
  903. SetKeyValue (&entities[i], "model", value);
  904. }
  905. }
  906. /*
  907. ============
  908. SetLightStyles
  909. ============
  910. */
  911. #define MAX_SWITCHED_LIGHTS 32
  912. void SetLightStyles (void)
  913. {
  914. int stylenum;
  915. char *t;
  916. entity_t *e;
  917. int i, j;
  918. char value[10];
  919. char lighttargets[MAX_SWITCHED_LIGHTS][64];
  920. // any light that is controlled (has a targetname)
  921. // must have a unique style number generated for it
  922. stylenum = 0;
  923. for (i=1 ; i<num_entities ; i++)
  924. {
  925. e = &entities[i];
  926. t = ValueForKey (e, "classname");
  927. if (Q_strncasecmp (t, "light", 5))
  928. continue;
  929. // This is not true for dynamic lights
  930. if (!Q_strcasecmp (t, "light_dynamic"))
  931. continue;
  932. t = ValueForKey (e, "targetname");
  933. if (!t[0])
  934. continue;
  935. // find this targetname
  936. for (j=0 ; j<stylenum ; j++)
  937. if (!strcmp (lighttargets[j], t))
  938. break;
  939. if (j == stylenum)
  940. {
  941. if (stylenum == MAX_SWITCHED_LIGHTS)
  942. Error ("Too many switched lights (error at light %s), max = %d", t, MAX_SWITCHED_LIGHTS);
  943. strcpy (lighttargets[j], t);
  944. stylenum++;
  945. }
  946. sprintf (value, "%i", 32 + j);
  947. char *pCurrentStyle = ValueForKey( e, "style" );
  948. // the designer has set a default lightstyle as well as making the light switchable
  949. if ( pCurrentStyle )
  950. {
  951. int oldStyle = atoi(pCurrentStyle);
  952. if ( oldStyle != 0 )
  953. {
  954. // save off the default style so the game code can make a switchable copy of it
  955. SetKeyValue( e, "defaultstyle", pCurrentStyle );
  956. }
  957. }
  958. SetKeyValue (e, "style", value);
  959. }
  960. }
  961. /*
  962. ============
  963. EmitBrushes
  964. ============
  965. */
  966. void EmitBrushes (void)
  967. {
  968. int i, j, bnum, s, x;
  969. dbrush_t *db;
  970. mapbrush_t *b;
  971. dbrushside_t *cp;
  972. Vector normal;
  973. vec_t dist;
  974. int planenum;
  975. numbrushsides = 0;
  976. numbrushes = g_MainMap->nummapbrushes;
  977. for (bnum=0 ; bnum<g_MainMap->nummapbrushes ; bnum++)
  978. {
  979. b = &g_MainMap->mapbrushes[bnum];
  980. db = &dbrushes[bnum];
  981. db->contents = b->contents;
  982. db->firstside = numbrushsides;
  983. db->numsides = b->numsides;
  984. for (j=0 ; j<b->numsides ; j++)
  985. {
  986. if (numbrushsides == MAX_MAP_BRUSHSIDES)
  987. Error ("MAX_MAP_BRUSHSIDES");
  988. cp = &dbrushsides[numbrushsides];
  989. numbrushsides++;
  990. cp->planenum = b->original_sides[j].planenum;
  991. cp->texinfo = b->original_sides[j].texinfo;
  992. if ( cp->texinfo == -1 )
  993. {
  994. cp->texinfo = g_MainMap->g_ClipTexinfo;
  995. }
  996. cp->bevel = b->original_sides[j].bevel;
  997. cp->thin = b->original_sides[j].thin;
  998. }
  999. // add any axis planes not contained in the brush to bevel off corners
  1000. for (x=0 ; x<3 ; x++)
  1001. {
  1002. for (s=-1 ; s<=1 ; s+=2)
  1003. {
  1004. // add the plane
  1005. VectorCopy (vec3_origin, normal);
  1006. normal[x] = s;
  1007. if (s == -1)
  1008. dist = -b->mins[x];
  1009. else
  1010. dist = b->maxs[x];
  1011. planenum = g_MainMap->FindFloatPlane (normal, dist);
  1012. for (i=0 ; i<b->numsides ; i++)
  1013. {
  1014. if (b->original_sides[i].planenum == planenum)
  1015. break;
  1016. }
  1017. if (i == b->numsides)
  1018. {
  1019. if (numbrushsides >= MAX_MAP_BRUSHSIDES)
  1020. Error ("MAX_MAP_BRUSHSIDES");
  1021. dbrushsides[numbrushsides].planenum = planenum;
  1022. dbrushsides[numbrushsides].texinfo =
  1023. dbrushsides[numbrushsides-1].texinfo;
  1024. numbrushsides++;
  1025. db->numsides++;
  1026. }
  1027. }
  1028. }
  1029. }
  1030. }
  1031. /*
  1032. ==================
  1033. BeginBSPFile
  1034. ==================
  1035. */
  1036. void BeginBSPFile (void)
  1037. {
  1038. // these values may actually be initialized
  1039. // if the file existed when loaded, so clear them explicitly
  1040. nummodels = 0;
  1041. numfaces = 0;
  1042. numnodes = 0;
  1043. numbrushsides = 0;
  1044. numvertexes = 0;
  1045. numleaffaces = 0;
  1046. numleafbrushes = 0;
  1047. numsurfedges = 0;
  1048. // edge 0 is not used, because 0 can't be negated
  1049. numedges = 1;
  1050. // leave vertex 0 as an error
  1051. numvertexes = 1;
  1052. // leave leaf 0 as an error
  1053. numleafs = 1;
  1054. dleafs[0].contents = CONTENTS_SOLID;
  1055. // BUGBUG: This doesn't work!
  1056. #if 0
  1057. // make a default empty leaf for the tracing code
  1058. memset( &dleafs[1], 0, sizeof(dleafs[1]) );
  1059. dleafs[1].contents = CONTENTS_EMPTY;
  1060. #endif
  1061. }
  1062. // We can't calculate this properly until vvis (since we need vis to do this), so we set
  1063. // to zero everywhere by default.
  1064. static void ClearDistToClosestWater( void )
  1065. {
  1066. int i;
  1067. for( i = 0; i < numleafs; i++ )
  1068. {
  1069. g_LeafMinDistToWater[i] = 0;
  1070. }
  1071. }
  1072. void DiscoverMacroTextures()
  1073. {
  1074. CUtlDict<int,int> tempDict;
  1075. g_FaceMacroTextureInfos.SetSize( numfaces );
  1076. for ( int iFace=0; iFace < numfaces; iFace++ )
  1077. {
  1078. texinfo_t *pTexInfo = &texinfo[dfaces[iFace].texinfo];
  1079. if ( pTexInfo->texdata < 0 )
  1080. continue;
  1081. dtexdata_t *pTexData = &dtexdata[pTexInfo->texdata];
  1082. const char *pMaterialName = &g_TexDataStringData[ g_TexDataStringTable[pTexData->nameStringTableID] ];
  1083. MaterialSystemMaterial_t hMaterial = FindMaterial( pMaterialName, NULL, false );
  1084. const char *pMacroTextureName = GetMaterialVar( hMaterial, "$macro_texture" );
  1085. if ( pMacroTextureName )
  1086. {
  1087. if ( tempDict.Find( pMacroTextureName ) == tempDict.InvalidIndex() )
  1088. {
  1089. Msg( "-- DiscoverMacroTextures: %s\n", pMacroTextureName );
  1090. tempDict.Insert( pMacroTextureName, 0 );
  1091. }
  1092. int stringID = TexDataStringTable_AddOrFindString( pMacroTextureName );
  1093. g_FaceMacroTextureInfos[iFace].m_MacroTextureNameID = (unsigned short)stringID;
  1094. }
  1095. else
  1096. {
  1097. g_FaceMacroTextureInfos[iFace].m_MacroTextureNameID = 0xFFFF;
  1098. }
  1099. }
  1100. }
  1101. // Make sure that we have a water lod control entity if we have water in the map.
  1102. void EnsurePresenceOfWaterLODControlEntity( void )
  1103. {
  1104. extern bool g_bHasWater;
  1105. if( !g_bHasWater )
  1106. {
  1107. // Don't bother if there isn't any water in the map.
  1108. return;
  1109. }
  1110. for( int i=0; i < num_entities; i++ )
  1111. {
  1112. entity_t *e = &entities[i];
  1113. const char *pClassName = ValueForKey( e, "classname" );
  1114. if( !Q_stricmp( pClassName, "water_lod_control" ) )
  1115. {
  1116. // Found one!!!!
  1117. return;
  1118. }
  1119. }
  1120. // None found, add one.
  1121. Warning( "Water found with no water_lod_control entity, creating a default one.\n" );
  1122. entity_t *mapent = &entities[num_entities];
  1123. num_entities++;
  1124. memset(mapent, 0, sizeof(*mapent));
  1125. mapent->firstbrush = g_MainMap->nummapbrushes;
  1126. mapent->numbrushes = 0;
  1127. SetKeyValue( mapent, "classname", "water_lod_control" );
  1128. SetKeyValue( mapent, "cheapwaterstartdistance", "1000" );
  1129. SetKeyValue( mapent, "cheapwaterenddistance", "2000" );
  1130. }
  1131. /*
  1132. ============
  1133. EndBSPFile
  1134. ============
  1135. */
  1136. void EndBSPFile (void)
  1137. {
  1138. // Mark noshadow faces.
  1139. MarkNoShadowFaces();
  1140. EmitBrushes ();
  1141. EmitPlanes ();
  1142. // stick flat normals at the verts
  1143. SaveVertexNormals();
  1144. // Figure out lightmap extents for all faces.
  1145. UpdateAllFaceLightmapExtents();
  1146. // Generate geometry and lightmap alpha for displacements.
  1147. EmitDispLMAlphaAndNeighbors();
  1148. // Emit overlay data.
  1149. Overlay_EmitOverlayFaces();
  1150. OverlayTransition_EmitOverlayFaces();
  1151. // phys collision needs dispinfo to operate (needs to generate phys collision for displacement surfs)
  1152. EmitPhysCollision();
  1153. // We can't calculate this properly until vvis (since we need vis to do this), so we set
  1154. // to zero everywhere by default.
  1155. ClearDistToClosestWater();
  1156. // Emit static props found in the .vmf file
  1157. EmitStaticProps();
  1158. // Place detail props found in .vmf and based on material properties
  1159. EmitDetailObjects();
  1160. // Compute bounds after creating disp info because we need to reference it
  1161. ComputeBoundsNoSkybox();
  1162. // Make sure that we have a water lod control eneity if we have water in the map.
  1163. EnsurePresenceOfWaterLODControlEntity();
  1164. // Doing this here because stuff about may filter out entities
  1165. UnparseEntities ();
  1166. // remove unused texinfos
  1167. CompactTexinfos();
  1168. // Figure out which faces want macro textures.
  1169. DiscoverMacroTextures();
  1170. char targetPath[1024];
  1171. GetPlatformMapPath( source, targetPath, 0, 1024 );
  1172. Msg ("Writing %s\n", targetPath);
  1173. WriteBSPFile (targetPath);
  1174. }
  1175. /*
  1176. ==================
  1177. BeginModel
  1178. ==================
  1179. */
  1180. int firstmodleaf;
  1181. void BeginModel (void)
  1182. {
  1183. dmodel_t *mod;
  1184. int start, end;
  1185. mapbrush_t *b;
  1186. int j;
  1187. entity_t *e;
  1188. Vector mins, maxs;
  1189. if (nummodels == MAX_MAP_MODELS)
  1190. Error ("Too many brush models in map, max = %d", MAX_MAP_MODELS);
  1191. mod = &dmodels[nummodels];
  1192. mod->firstface = numfaces;
  1193. firstmodleaf = numleafs;
  1194. firstmodeledge = numedges;
  1195. firstmodelface = numfaces;
  1196. //
  1197. // bound the brushes
  1198. //
  1199. e = &entities[entity_num];
  1200. start = e->firstbrush;
  1201. end = start + e->numbrushes;
  1202. ClearBounds (mins, maxs);
  1203. for (j=start ; j<end ; j++)
  1204. {
  1205. b = &g_MainMap->mapbrushes[j];
  1206. if (!b->numsides)
  1207. continue; // not a real brush (origin brush)
  1208. AddPointToBounds (b->mins, mins, maxs);
  1209. AddPointToBounds (b->maxs, mins, maxs);
  1210. }
  1211. VectorCopy (mins, mod->mins);
  1212. VectorCopy (maxs, mod->maxs);
  1213. }
  1214. /*
  1215. ==================
  1216. EndModel
  1217. ==================
  1218. */
  1219. void EndModel (void)
  1220. {
  1221. dmodel_t *mod;
  1222. mod = &dmodels[nummodels];
  1223. mod->numfaces = numfaces - mod->firstface;
  1224. nummodels++;
  1225. }
  1226. //-----------------------------------------------------------------------------
  1227. // figure out which leaf a point is in
  1228. //-----------------------------------------------------------------------------
  1229. static int PointLeafnum_r (const Vector& p, int num)
  1230. {
  1231. float d;
  1232. while (num >= 0)
  1233. {
  1234. dnode_t* node = dnodes + num;
  1235. dplane_t* plane = dplanes + node->planenum;
  1236. if (plane->type < 3)
  1237. d = p[plane->type] - plane->dist;
  1238. else
  1239. d = DotProduct (plane->normal, p) - plane->dist;
  1240. if (d < 0)
  1241. num = node->children[1];
  1242. else
  1243. num = node->children[0];
  1244. }
  1245. return -1 - num;
  1246. }
  1247. int PointLeafnum ( dmodel_t* pModel, const Vector& p )
  1248. {
  1249. return PointLeafnum_r (p, pModel->headnode);
  1250. }
  1251. //-----------------------------------------------------------------------------
  1252. // Adds a noew to the bounding box
  1253. //-----------------------------------------------------------------------------
  1254. static void AddNodeToBounds(int node, CUtlVector<int>& skipAreas, Vector& mins, Vector& maxs)
  1255. {
  1256. // not a leaf
  1257. if (node >= 0)
  1258. {
  1259. AddNodeToBounds( dnodes[node].children[0], skipAreas, mins, maxs );
  1260. AddNodeToBounds( dnodes[node].children[1], skipAreas, mins, maxs );
  1261. }
  1262. else
  1263. {
  1264. int leaf = - 1 - node;
  1265. // Don't bother with solid leaves
  1266. if (dleafs[leaf].contents & CONTENTS_SOLID)
  1267. return;
  1268. // Skip 3D skybox
  1269. int i;
  1270. for ( i = skipAreas.Count(); --i >= 0; )
  1271. {
  1272. if (dleafs[leaf].area == skipAreas[i])
  1273. return;
  1274. }
  1275. unsigned int firstface = dleafs[leaf].firstleafface;
  1276. for ( i = 0; i < dleafs[leaf].numleaffaces; ++i )
  1277. {
  1278. unsigned int face = dleaffaces[ firstface + i ];
  1279. // Skip skyboxes + nodraw
  1280. texinfo_t& tex = texinfo[dfaces[face].texinfo];
  1281. if (tex.flags & (SURF_SKY | SURF_NODRAW))
  1282. continue;
  1283. unsigned int firstedge = dfaces[face].firstedge;
  1284. Assert( firstedge >= 0 );
  1285. for (int j = 0; j < dfaces[face].numedges; ++j)
  1286. {
  1287. Assert( firstedge+j < numsurfedges );
  1288. int edge = abs(dsurfedges[firstedge+j]);
  1289. dedge_t* pEdge = &dedges[edge];
  1290. Assert( pEdge->v[0] >= 0 );
  1291. Assert( pEdge->v[1] >= 0 );
  1292. AddPointToBounds (dvertexes[pEdge->v[0]].point, mins, maxs);
  1293. AddPointToBounds (dvertexes[pEdge->v[1]].point, mins, maxs);
  1294. }
  1295. }
  1296. }
  1297. }
  1298. //-----------------------------------------------------------------------------
  1299. // Check to see if a displacement lives in any leaves that are not
  1300. // in the 3d skybox
  1301. //-----------------------------------------------------------------------------
  1302. bool IsBoxInsideWorld( int node, CUtlVector<int> &skipAreas, const Vector &vecMins, const Vector &vecMaxs )
  1303. {
  1304. while( 1 )
  1305. {
  1306. // leaf
  1307. if (node < 0)
  1308. {
  1309. // get the leaf
  1310. int leaf = - 1 - node;
  1311. // Don't bother with solid leaves
  1312. if (dleafs[leaf].contents & CONTENTS_SOLID)
  1313. return false;
  1314. // Skip 3D skybox
  1315. int i;
  1316. for ( i = skipAreas.Count(); --i >= 0; )
  1317. {
  1318. if ( dleafs[leaf].area == skipAreas[i] )
  1319. return false;
  1320. }
  1321. return true;
  1322. }
  1323. //
  1324. // get displacement bounding box position relative to the node plane
  1325. //
  1326. dnode_t *pNode = &dnodes[ node ];
  1327. dplane_t *pPlane = &dplanes[ pNode->planenum ];
  1328. int sideResult = BrushBspBoxOnPlaneSide( vecMins, vecMaxs, pPlane );
  1329. // front side
  1330. if( sideResult == 1 )
  1331. {
  1332. node = pNode->children[0];
  1333. }
  1334. // back side
  1335. else if( sideResult == 2 )
  1336. {
  1337. node = pNode->children[1];
  1338. }
  1339. //split
  1340. else
  1341. {
  1342. if ( IsBoxInsideWorld( pNode->children[0], skipAreas, vecMins, vecMaxs ) )
  1343. return true;
  1344. node = pNode->children[1];
  1345. }
  1346. }
  1347. }
  1348. //-----------------------------------------------------------------------------
  1349. // Adds the displacement surfaces in the world to the bounds
  1350. //-----------------------------------------------------------------------------
  1351. void AddDispsToBounds( int nHeadNode, CUtlVector<int>& skipAreas, Vector &vecMins, Vector &vecMaxs )
  1352. {
  1353. Vector vecDispMins, vecDispMaxs;
  1354. // first determine how many displacement surfaces there will be per leaf
  1355. int i;
  1356. for ( i = 0; i < g_dispinfo.Count(); ++i )
  1357. {
  1358. ComputeDispInfoBounds( i, vecDispMins, vecDispMaxs );
  1359. if ( IsBoxInsideWorld( nHeadNode, skipAreas, vecDispMins, vecDispMaxs ) )
  1360. {
  1361. AddPointToBounds( vecDispMins, vecMins, vecMaxs );
  1362. AddPointToBounds( vecDispMaxs, vecMins, vecMaxs );
  1363. }
  1364. }
  1365. }
  1366. //-----------------------------------------------------------------------------
  1367. // Compute the bounding box, excluding 3D skybox + skybox, add it to keyvalues
  1368. //-----------------------------------------------------------------------------
  1369. void ComputeBoundsNoSkybox( )
  1370. {
  1371. // Check to make sure we actually have anything in the tree. otherwise we'll
  1372. // recurse indefinitely
  1373. if ( numnodes == 0 )
  1374. return;
  1375. // Iterate over all world leaves, skip those which are part of skybox
  1376. Vector mins, maxs;
  1377. ClearBounds (mins, maxs);
  1378. AddNodeToBounds( dmodels[0].headnode, g_SkyAreas, mins, maxs );
  1379. AddDispsToBounds( dmodels[0].headnode, g_SkyAreas, mins, maxs );
  1380. // Add the bounds to the worldspawn data
  1381. for (int i = 0; i < num_entities; ++i)
  1382. {
  1383. char* pEntity = ValueForKey(&entities[i], "classname");
  1384. if (!strcmp(pEntity, "worldspawn"))
  1385. {
  1386. char string[ 128 ];
  1387. sprintf (string, "%i %i %i", (int)mins[0], (int)mins[1], (int)mins[2]);
  1388. SetKeyValue (&entities[i], "world_mins", string);
  1389. sprintf (string, "%i %i %i", (int)maxs[0], (int)maxs[1], (int)maxs[2]);
  1390. SetKeyValue (&entities[i], "world_maxs", string);
  1391. break;
  1392. }
  1393. }
  1394. }