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.

704 lines
18 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Builds/merges the BSP tree of detail brushes
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "vbsp.h"
  8. #include "detail.h"
  9. #include "utlvector.h"
  10. #include <assert.h>
  11. face_t *NewFaceFromFace (face_t *f);
  12. face_t *ComputeVisibleBrushSides( bspbrush_t *list );
  13. //-----------------------------------------------------------------------------
  14. // Purpose: Copies a face and its winding
  15. // Input : *pFace -
  16. // Output : face_t
  17. //-----------------------------------------------------------------------------
  18. face_t *CopyFace( face_t *pFace )
  19. {
  20. face_t *f = NewFaceFromFace( pFace );
  21. f->w = CopyWinding( pFace->w );
  22. return f;
  23. }
  24. //-----------------------------------------------------------------------------
  25. // Purpose: Link this brush into the list for this leaf
  26. // Input : *node -
  27. // *brush -
  28. //-----------------------------------------------------------------------------
  29. void AddBrushToLeaf( node_t *node, bspbrush_t *brush )
  30. {
  31. brush->next = node->brushlist;
  32. node->brushlist = brush;
  33. }
  34. //-----------------------------------------------------------------------------
  35. // Purpose: Recursively filter a brush through the tree
  36. // Input : *node -
  37. // *brush -
  38. //-----------------------------------------------------------------------------
  39. void MergeBrush_r( node_t *node, bspbrush_t *brush )
  40. {
  41. if ( node->planenum == PLANENUM_LEAF )
  42. {
  43. if ( node->contents & CONTENTS_SOLID )
  44. {
  45. FreeBrush( brush );
  46. }
  47. else
  48. {
  49. AddBrushToLeaf( node, brush );
  50. }
  51. return;
  52. }
  53. bspbrush_t *front, *back;
  54. SplitBrush( brush, node->planenum, &front, &back );
  55. FreeBrush( brush );
  56. if ( front )
  57. {
  58. MergeBrush_r( node->children[0], front );
  59. }
  60. if ( back )
  61. {
  62. MergeBrush_r( node->children[1], back );
  63. }
  64. }
  65. //-----------------------------------------------------------------------------
  66. // Purpose: Recursively filter a face into the tree leaving references to the
  67. // original face in any visible leaves that a clipped fragment falls
  68. // into.
  69. // Input : *node - current head of tree
  70. // *face - clipped face fragment
  71. // *original - unclipped original face
  72. // Output : Returns true if any references were left
  73. //-----------------------------------------------------------------------------
  74. bool MergeFace_r( node_t *node, face_t *face, face_t *original )
  75. {
  76. bool referenced = false;
  77. if ( node->planenum == PLANENUM_LEAF )
  78. {
  79. if ( node->contents & CONTENTS_SOLID )
  80. {
  81. FreeFace( face );
  82. return false;
  83. }
  84. leafface_t *plist = new leafface_t;
  85. plist->pFace = original;
  86. plist->pNext = node->leaffacelist;
  87. node->leaffacelist = plist;
  88. referenced = true;
  89. }
  90. else
  91. {
  92. // UNDONE: Don't copy the faces each time unless it's necessary!?!?!
  93. plane_t *plane = &g_MainMap->mapplanes[node->planenum];
  94. winding_t *frontwinding, *backwinding, *onwinding;
  95. Vector offset;
  96. WindingCenter( face->w, offset );
  97. // UNDONE: Export epsilon from original face clipping code
  98. ClassifyWindingEpsilon_Offset(face->w, plane->normal, plane->dist, 0.001, &frontwinding, &backwinding, &onwinding, -offset);
  99. if ( onwinding )
  100. {
  101. // face is in the split plane, go down the appropriate side according to the facing direction
  102. assert( frontwinding == NULL );
  103. assert( backwinding == NULL );
  104. if ( DotProduct( g_MainMap->mapplanes[face->planenum].normal, g_MainMap->mapplanes[node->planenum].normal ) > 0 )
  105. {
  106. frontwinding = onwinding;
  107. }
  108. else
  109. {
  110. backwinding = onwinding;
  111. }
  112. }
  113. if ( frontwinding )
  114. {
  115. face_t *tmp = NewFaceFromFace( face );
  116. tmp->w = frontwinding;
  117. referenced = MergeFace_r( node->children[0], tmp, original );
  118. }
  119. if ( backwinding )
  120. {
  121. face_t *tmp = NewFaceFromFace( face );
  122. tmp->w = backwinding;
  123. bool test = MergeFace_r( node->children[1], tmp, original );
  124. referenced = referenced || test;
  125. }
  126. }
  127. FreeFace( face );
  128. return referenced;
  129. }
  130. //-----------------------------------------------------------------------------
  131. // Purpose: Loop through each face and filter it into the tree
  132. // Input : *out -
  133. // *pFaces -
  134. //-----------------------------------------------------------------------------
  135. face_t *FilterFacesIntoTree( tree_t *out, face_t *pFaces )
  136. {
  137. face_t *pLeafFaceList = NULL;
  138. for ( face_t *f = pFaces; f; f = f->next )
  139. {
  140. if( f->merged || f->split[0] || f->split[1] )
  141. continue;
  142. face_t *tmp = CopyFace( f );
  143. face_t *original = CopyFace( f );
  144. if ( MergeFace_r( out->headnode, tmp, original ) )
  145. {
  146. // clear out portal (comes from a different tree)
  147. original->portal = NULL;
  148. original->next = pLeafFaceList;
  149. pLeafFaceList = original;
  150. }
  151. else
  152. {
  153. FreeFace( original );
  154. }
  155. }
  156. return pLeafFaceList;
  157. }
  158. //-----------------------------------------------------------------------------
  159. // Purpose: Splits the face list into faces from the same plane and tries to merge
  160. // them if possible
  161. // Input : **pFaceList -
  162. //-----------------------------------------------------------------------------
  163. void TryMergeFaceList( face_t **pFaceList )
  164. {
  165. face_t **pPlaneList = NULL;
  166. // divide the list into buckets by plane number
  167. pPlaneList = new face_t *[g_MainMap->nummapplanes];
  168. memset( pPlaneList, 0, sizeof(face_t *) * g_MainMap->nummapplanes );
  169. face_t *pFaces = *pFaceList;
  170. face_t *pOutput = NULL;
  171. while ( pFaces )
  172. {
  173. face_t *next = pFaces->next;
  174. // go ahead and delete the old split/merged faces
  175. if ( pFaces->merged || pFaces->split[0] || pFaces->split[1] )
  176. {
  177. Error("Split face in merge list!");
  178. }
  179. else
  180. {
  181. // add to the list for this plane
  182. pFaces->next = pPlaneList[pFaces->planenum];
  183. pPlaneList[pFaces->planenum] = pFaces;
  184. }
  185. pFaces = next;
  186. }
  187. // now merge each plane's list of faces
  188. int merged = 0;
  189. for ( int i = 0; i < g_MainMap->nummapplanes; i++ )
  190. {
  191. if ( pPlaneList[i] )
  192. {
  193. MergeFaceList( &pPlaneList[i] );
  194. }
  195. // move these over to the output face list
  196. face_t *list = pPlaneList[i];
  197. while ( list )
  198. {
  199. face_t *next = list->next;
  200. if ( list->merged )
  201. merged++;
  202. list->next = pOutput;
  203. pOutput = list;
  204. list = next;
  205. }
  206. }
  207. if ( merged )
  208. {
  209. Msg("\nMerged %d detail faces...", merged );
  210. }
  211. delete[] pPlaneList;
  212. *pFaceList = pOutput;
  213. }
  214. //-----------------------------------------------------------------------------
  215. // Purpose: filter each brush in the list into the tree
  216. // Input : *out -
  217. // *brushes -
  218. //-----------------------------------------------------------------------------
  219. void FilterBrushesIntoTree( tree_t *out, bspbrush_t *brushes )
  220. {
  221. // Merge all of the brushes into the world tree
  222. for ( bspbrush_t *plist = brushes; plist; plist = plist->next )
  223. {
  224. MergeBrush_r( out->headnode, CopyBrush(plist) );
  225. }
  226. }
  227. //-----------------------------------------------------------------------------
  228. // Purpose: Build faces for the detail brushes and merge them into the BSP
  229. // Input : *worldtree -
  230. // brush_start -
  231. // brush_end -
  232. //-----------------------------------------------------------------------------
  233. face_t *MergeDetailTree( tree_t *worldtree, int brush_start, int brush_end )
  234. {
  235. int start;
  236. bspbrush_t *detailbrushes = NULL;
  237. face_t *pFaces = NULL;
  238. face_t *pLeafFaceList = NULL;
  239. // Grab the list of detail brushes
  240. detailbrushes = MakeBspBrushList (brush_start, brush_end, g_MainMap->map_mins, g_MainMap->map_maxs, ONLY_DETAIL );
  241. if (detailbrushes)
  242. {
  243. start = Plat_FloatTime();
  244. Msg("Chop Details...");
  245. // if there are detail brushes, chop them against each other
  246. if (!nocsg)
  247. detailbrushes = ChopBrushes (detailbrushes);
  248. Msg("done (%d)\n", (int)(Plat_FloatTime() - start) );
  249. // Now mark the visible sides so we can eliminate all detail brush sides
  250. // that are covered by other detail brush sides
  251. // NOTE: This still leaves detail brush sides that are covered by the world. (these are removed in the merge operation)
  252. Msg("Find Visible Detail Sides...");
  253. pFaces = ComputeVisibleBrushSides( detailbrushes );
  254. TryMergeFaceList( &pFaces );
  255. SubdivideFaceList( &pFaces );
  256. Msg("done (%d)\n", (int)(Plat_FloatTime() - start) );
  257. start = Plat_FloatTime();
  258. Msg("Merging details...");
  259. // Merge the detail solids and faces into the world tree
  260. // Merge all of the faces into the world tree
  261. pLeafFaceList = FilterFacesIntoTree( worldtree, pFaces );
  262. FilterBrushesIntoTree( worldtree, detailbrushes );
  263. FreeFaceList( pFaces );
  264. FreeBrushList(detailbrushes);
  265. Msg("done (%d)\n", (int)(Plat_FloatTime() - start) );
  266. }
  267. return pLeafFaceList;
  268. }
  269. //-----------------------------------------------------------------------------
  270. // Purpose: Quick overlap test for brushes
  271. // Input : *p1 -
  272. // *p2 -
  273. // Output : Returns false if the brushes cannot intersect
  274. //-----------------------------------------------------------------------------
  275. bool BrushBoxOverlap( bspbrush_t *p1, bspbrush_t *p2 )
  276. {
  277. if ( p1 == p2 )
  278. return false;
  279. for ( int i = 0; i < 3; i++ )
  280. {
  281. if ( p1->mins[i] > p2->maxs[i] || p1->maxs[i] < p2->mins[i] )
  282. return false;
  283. }
  284. return true;
  285. }
  286. //-----------------------------------------------------------------------------
  287. // Purpose:
  288. // Input : *pFace - input face to test
  289. // *pbrush - brush to clip face against
  290. // **pOutputList - list of faces clipped from pFace
  291. // Output : Returns true if the brush completely clips the face
  292. //-----------------------------------------------------------------------------
  293. // NOTE: This assumes the brushes have already been chopped so that no solid space
  294. // is enclosed by more than one brush!!
  295. bool ClipFaceToBrush( face_t *pFace, bspbrush_t *pbrush, face_t **pOutputList )
  296. {
  297. int planenum = pFace->planenum & (~1);
  298. int foundSide = -1;
  299. CUtlVector<int> sortedSides;
  300. int i;
  301. for ( i = 0; i < pbrush->numsides && foundSide < 0; i++ )
  302. {
  303. int bplane = pbrush->sides[i].planenum & (~1);
  304. if ( bplane == planenum )
  305. foundSide = i;
  306. }
  307. Vector offset = -0.5f * (pbrush->maxs + pbrush->mins);
  308. face_t *currentface = CopyFace( pFace );
  309. if ( foundSide >= 0 )
  310. {
  311. sortedSides.RemoveAll();
  312. for ( i = 0; i < pbrush->numsides; i++ )
  313. {
  314. // don't clip to bevels
  315. if ( pbrush->sides[i].bevel )
  316. continue;
  317. if ( g_MainMap->mapplanes[pbrush->sides[i].planenum].type <= PLANE_Z )
  318. {
  319. sortedSides.AddToHead( i );
  320. }
  321. else
  322. {
  323. sortedSides.AddToTail( i );
  324. }
  325. }
  326. for ( i = 0; i < sortedSides.Count(); i++ )
  327. {
  328. int index = sortedSides[i];
  329. if ( index == foundSide )
  330. continue;
  331. plane_t *plane = &g_MainMap->mapplanes[pbrush->sides[index].planenum];
  332. winding_t *frontwinding, *backwinding;
  333. ClipWindingEpsilon_Offset(currentface->w, plane->normal, plane->dist, 0.001, &frontwinding, &backwinding, offset);
  334. // only clip if some part of this face is on the back side of all brush sides
  335. if ( !backwinding || WindingIsTiny(backwinding))
  336. {
  337. FreeFaceList( *pOutputList );
  338. *pOutputList = NULL;
  339. break;
  340. }
  341. if ( frontwinding && !WindingIsTiny(frontwinding) )
  342. {
  343. // add this fragment to the return list
  344. // make a face for the fragment
  345. face_t *f = NewFaceFromFace( pFace );
  346. f->w = frontwinding;
  347. // link the fragment in
  348. f->next = *pOutputList;
  349. *pOutputList = f;
  350. }
  351. // update the current winding to be the part behind each plane
  352. FreeWinding( currentface->w );
  353. currentface->w = backwinding;
  354. }
  355. // free the bit that is left in solid or not clipped (if we broke out early)
  356. FreeFace( currentface );
  357. // if we made it all the way through and didn't produce any fragments then the whole face was clipped away
  358. if ( !*pOutputList && i == sortedSides.Count() )
  359. {
  360. return true;
  361. }
  362. }
  363. return false;
  364. }
  365. //-----------------------------------------------------------------------------
  366. // Purpose: Given an original side and chopped winding, make a face_t
  367. // Input : *side - side of the original brush
  368. // *winding - winding for this face (portion of the side)
  369. // Output : face_t
  370. //-----------------------------------------------------------------------------
  371. face_t *MakeBrushFace( side_t *originalSide, winding_t *winding )
  372. {
  373. face_t *f = AllocFace();
  374. f->merged = NULL;
  375. f->split[0] = f->split[1] = NULL;
  376. f->w = CopyWinding( winding );
  377. f->originalface = originalSide;
  378. //
  379. // save material info
  380. //
  381. f->texinfo = originalSide->texinfo;
  382. f->dispinfo = -1;
  383. f->smoothingGroups = originalSide->smoothingGroups;
  384. // save plane info
  385. f->planenum = originalSide->planenum;
  386. f->contents = originalSide->contents;
  387. return f;
  388. }
  389. //-----------------------------------------------------------------------------
  390. // Purpose: Chop away sides that are inside other brushes.
  391. // Brushes have already been chopped up so that they do not overlap,
  392. // they merely touch.
  393. // Input : *list - list of brushes
  394. // Output : face_t * - list of visible faces (some marked bad/split)
  395. //-----------------------------------------------------------------------------
  396. // assumes brushes were chopped!
  397. side_t *FindOriginalSide( mapbrush_t *mb, side_t *pBspSide )
  398. {
  399. side_t *bestside = NULL;
  400. float bestdot = 0;
  401. plane_t *p1 = g_MainMap->mapplanes + pBspSide->planenum;
  402. for (int i=0 ; i<mb->numsides ; i++)
  403. {
  404. side_t *side = &mb->original_sides[i];
  405. if (side->bevel)
  406. continue;
  407. if (side->texinfo == TEXINFO_NODE)
  408. continue; // non-visible
  409. if ((side->planenum&~1) == (pBspSide->planenum&~1))
  410. { // exact match
  411. return mb->original_sides + i;
  412. }
  413. // see how close the match is
  414. plane_t *p2 = &g_MainMap->mapplanes[side->planenum&~1];
  415. float dot = DotProduct (p1->normal, p2->normal);
  416. if (dot > bestdot)
  417. {
  418. bestdot = dot;
  419. bestside = side;
  420. }
  421. }
  422. if ( !bestside )
  423. {
  424. Error( "Bad detail brush side\n" );
  425. }
  426. return bestside;
  427. }
  428. static bool IsAllNodraw( mapbrush_t *pMapBrush )
  429. {
  430. for ( int i = 0; i < pMapBrush->numsides; i++ )
  431. {
  432. if ( !(pMapBrush->original_sides[i].surf & SURF_NODRAW) )
  433. return false;
  434. }
  435. return true;
  436. }
  437. // Get a list of brushes from pBrushList that could cut faces on the source brush
  438. int GetListOfCutBrushes( CUtlVector<bspbrush_t *> &out, bspbrush_t *pSourceBrush, bspbrush_t *pBrushList )
  439. {
  440. mapbrush_t *mb = pSourceBrush->original;
  441. for ( bspbrush_t *walk = pBrushList; walk; walk = walk->next )
  442. {
  443. if ( walk == pSourceBrush )
  444. continue;
  445. // only clip to transparent brushes if the original brush is transparent
  446. if ( walk->original->contents & TRANSPARENT_CONTENTS )
  447. {
  448. if ( !(mb->contents & TRANSPARENT_CONTENTS) )
  449. continue;
  450. }
  451. // don't clip to clip brushes, etc.
  452. if ( !(walk->original->contents & ALL_VISIBLE_CONTENTS) )
  453. continue;
  454. // brushes overlap, test faces
  455. if ( !BrushBoxOverlap( pSourceBrush, walk ) )
  456. continue;
  457. out.AddToTail( walk );
  458. }
  459. return out.Count();
  460. }
  461. // Count the number of real (unsplit) faces in the list
  462. static int CountFaceList( face_t *f )
  463. {
  464. int count = 0;
  465. for ( ; f; f = f->next )
  466. {
  467. if ( f->split[0] )
  468. continue;
  469. count++;
  470. }
  471. return count;
  472. }
  473. // Clips f to a list of potential cutting brushes
  474. // If f clips into new faces, returns the list of new faces in pOutputList
  475. static void ClipFaceToBrushList( face_t *f, const CUtlVector<bspbrush_t *> &cutBrushes, face_t **pOutputList )
  476. {
  477. *pOutputList = NULL;
  478. if ( f->split[0] )
  479. return;
  480. face_t *pClipList = CopyFace( f );
  481. pClipList->next = NULL;
  482. bool clipped = false;
  483. for ( int i = 0; i < cutBrushes.Count(); i++ )
  484. {
  485. bspbrush_t *cut = cutBrushes[i];
  486. for ( face_t *pCutFace = pClipList; pCutFace; pCutFace = pCutFace->next )
  487. {
  488. face_t *pClip = NULL;
  489. // already split, no need to clip
  490. if ( pCutFace->split[0] )
  491. continue;
  492. if ( ClipFaceToBrush( pCutFace, cut, &pClip ) )
  493. {
  494. clipped = true;
  495. // mark face bad, the brush clipped it away
  496. pCutFace->split[0] = pCutFace;
  497. }
  498. else if ( pClip )
  499. {
  500. clipped = true;
  501. // mark this face as split
  502. pCutFace->split[0] = pCutFace;
  503. // insert face fragments at head of list (UNDONE: reverses order, do we care?)
  504. while ( pClip )
  505. {
  506. face_t *next = pClip->next;
  507. pClip->next = pClipList;
  508. pClipList = pClip;
  509. pClip = next;
  510. }
  511. }
  512. }
  513. }
  514. if ( clipped )
  515. {
  516. *pOutputList = pClipList;
  517. }
  518. else
  519. {
  520. // didn't do any clipping, go ahead and free the copy of the face here.
  521. FreeFaceList( pClipList );
  522. }
  523. }
  524. // Compute a list of faces that are visible on the detail brush sides
  525. face_t *ComputeVisibleBrushSides( bspbrush_t *list )
  526. {
  527. face_t *pTotalFaces = NULL;
  528. CUtlVector<bspbrush_t *> cutBrushes;
  529. // Go through the whole brush list
  530. for ( bspbrush_t *pbrush = list; pbrush; pbrush = pbrush->next )
  531. {
  532. face_t *pFaces = NULL;
  533. mapbrush_t *mb = pbrush->original;
  534. if ( !(mb->contents & ALL_VISIBLE_CONTENTS) )
  535. continue;
  536. // Make a face for each brush side, then clip it by the other
  537. // details to see if any fragments are visible
  538. for ( int i = 0; i < pbrush->numsides; i++ )
  539. {
  540. winding_t *winding = pbrush->sides[i].winding;
  541. if ( !winding )
  542. continue;
  543. if (! (pbrush->sides[i].contents & ALL_VISIBLE_CONTENTS) )
  544. continue;
  545. side_t *side = FindOriginalSide( mb, pbrush->sides + i );
  546. face_t *f = MakeBrushFace( side, winding );
  547. // link to head of face list
  548. f->next = pFaces;
  549. pFaces = f;
  550. }
  551. // Make a list of brushes that can cut the face list for this brush
  552. cutBrushes.RemoveAll();
  553. if ( GetListOfCutBrushes( cutBrushes, pbrush, list ) )
  554. {
  555. // now cut each face to find visible fragments
  556. for ( face_t *f = pFaces; f; f = f->next )
  557. {
  558. // this will be a new list of faces that this face cuts into
  559. face_t *pClip = NULL;
  560. ClipFaceToBrushList( f, cutBrushes, &pClip );
  561. if ( pClip )
  562. {
  563. int outCount = CountFaceList(pClip);
  564. // it cut into more faces (or it was completely cut away)
  565. if ( outCount <= 1 )
  566. {
  567. // was removed or cut down, mark as split
  568. f->split[0] = f;
  569. // insert face fragments at head of list (UNDONE: reverses order, do we care?)
  570. while ( pClip )
  571. {
  572. face_t *next = pClip->next;
  573. pClip->next = pFaces;
  574. pFaces = pClip;
  575. pClip = next;
  576. }
  577. }
  578. else
  579. {
  580. // it cut into more than one visible fragment
  581. // Don't fragment details
  582. // UNDONE: Build 2d convex hull of this list and swap face winding
  583. // with that polygon? That would fix the remaining issues.
  584. FreeFaceList( pClip );
  585. pClip = NULL;
  586. }
  587. }
  588. }
  589. }
  590. // move visible fragments to global face list
  591. while ( pFaces )
  592. {
  593. face_t *next = pFaces->next;
  594. if ( pFaces->split[0] )
  595. {
  596. FreeFace( pFaces );
  597. }
  598. else
  599. {
  600. pFaces->next = pTotalFaces;
  601. pTotalFaces = pFaces;
  602. }
  603. pFaces = next;
  604. }
  605. }
  606. return pTotalFaces;
  607. }