Team Fortress 2 Source Code as on 22/4/2020
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.

693 lines
18 KiB

  1. //========= Copyright 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.Size(); 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.Size() )
  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. // save plane info
  384. f->planenum = originalSide->planenum;
  385. f->contents = originalSide->contents;
  386. return f;
  387. }
  388. //-----------------------------------------------------------------------------
  389. // Purpose: Chop away sides that are inside other brushes.
  390. // Brushes have already been chopped up so that they do not overlap,
  391. // they merely touch.
  392. // Input : *list - list of brushes
  393. // Output : face_t * - list of visible faces (some marked bad/split)
  394. //-----------------------------------------------------------------------------
  395. // assumes brushes were chopped!
  396. side_t *FindOriginalSide( mapbrush_t *mb, side_t *pBspSide )
  397. {
  398. side_t *bestside = NULL;
  399. float bestdot = 0;
  400. plane_t *p1 = g_MainMap->mapplanes + pBspSide->planenum;
  401. for (int i=0 ; i<mb->numsides ; i++)
  402. {
  403. side_t *side = &mb->original_sides[i];
  404. if (side->bevel)
  405. continue;
  406. if (side->texinfo == TEXINFO_NODE)
  407. continue; // non-visible
  408. if ((side->planenum&~1) == (pBspSide->planenum&~1))
  409. { // exact match
  410. return mb->original_sides + i;
  411. }
  412. // see how close the match is
  413. plane_t *p2 = &g_MainMap->mapplanes[side->planenum&~1];
  414. float dot = DotProduct (p1->normal, p2->normal);
  415. if (dot > bestdot)
  416. {
  417. bestdot = dot;
  418. bestside = side;
  419. }
  420. }
  421. if ( !bestside )
  422. {
  423. Error( "Bad detail brush side\n" );
  424. }
  425. return bestside;
  426. }
  427. // Get a list of brushes from pBrushList that could cut faces on the source brush
  428. int GetListOfCutBrushes( CUtlVector<bspbrush_t *> &out, bspbrush_t *pSourceBrush, bspbrush_t *pBrushList )
  429. {
  430. mapbrush_t *mb = pSourceBrush->original;
  431. for ( bspbrush_t *walk = pBrushList; walk; walk = walk->next )
  432. {
  433. if ( walk == pSourceBrush )
  434. continue;
  435. // only clip to transparent brushes if the original brush is transparent
  436. if ( walk->original->contents & TRANSPARENT_CONTENTS )
  437. {
  438. if ( !(mb->contents & TRANSPARENT_CONTENTS) )
  439. continue;
  440. }
  441. // don't clip to clip brushes, etc.
  442. if ( !(walk->original->contents & ALL_VISIBLE_CONTENTS) )
  443. continue;
  444. // brushes overlap, test faces
  445. if ( !BrushBoxOverlap( pSourceBrush, walk ) )
  446. continue;
  447. out.AddToTail( walk );
  448. }
  449. return out.Count();
  450. }
  451. // Count the number of real (unsplit) faces in the list
  452. static int CountFaceList( face_t *f )
  453. {
  454. int count = 0;
  455. for ( ; f; f = f->next )
  456. {
  457. if ( f->split[0] )
  458. continue;
  459. count++;
  460. }
  461. return count;
  462. }
  463. // Clips f to a list of potential cutting brushes
  464. // If f clips into new faces, returns the list of new faces in pOutputList
  465. static void ClipFaceToBrushList( face_t *f, const CUtlVector<bspbrush_t *> &cutBrushes, face_t **pOutputList )
  466. {
  467. *pOutputList = NULL;
  468. if ( f->split[0] )
  469. return;
  470. face_t *pClipList = CopyFace( f );
  471. pClipList->next = NULL;
  472. bool clipped = false;
  473. for ( int i = 0; i < cutBrushes.Count(); i++ )
  474. {
  475. bspbrush_t *cut = cutBrushes[i];
  476. for ( face_t *pCutFace = pClipList; pCutFace; pCutFace = pCutFace->next )
  477. {
  478. face_t *pClip = NULL;
  479. // already split, no need to clip
  480. if ( pCutFace->split[0] )
  481. continue;
  482. if ( ClipFaceToBrush( pCutFace, cut, &pClip ) )
  483. {
  484. clipped = true;
  485. // mark face bad, the brush clipped it away
  486. pCutFace->split[0] = pCutFace;
  487. }
  488. else if ( pClip )
  489. {
  490. clipped = true;
  491. // mark this face as split
  492. pCutFace->split[0] = pCutFace;
  493. // insert face fragments at head of list (UNDONE: reverses order, do we care?)
  494. while ( pClip )
  495. {
  496. face_t *next = pClip->next;
  497. pClip->next = pClipList;
  498. pClipList = pClip;
  499. pClip = next;
  500. }
  501. }
  502. }
  503. }
  504. if ( clipped )
  505. {
  506. *pOutputList = pClipList;
  507. }
  508. else
  509. {
  510. // didn't do any clipping, go ahead and free the copy of the face here.
  511. FreeFaceList( pClipList );
  512. }
  513. }
  514. // Compute a list of faces that are visible on the detail brush sides
  515. face_t *ComputeVisibleBrushSides( bspbrush_t *list )
  516. {
  517. face_t *pTotalFaces = NULL;
  518. CUtlVector<bspbrush_t *> cutBrushes;
  519. // Go through the whole brush list
  520. for ( bspbrush_t *pbrush = list; pbrush; pbrush = pbrush->next )
  521. {
  522. face_t *pFaces = NULL;
  523. mapbrush_t *mb = pbrush->original;
  524. if ( !(mb->contents & ALL_VISIBLE_CONTENTS) )
  525. continue;
  526. // Make a face for each brush side, then clip it by the other
  527. // details to see if any fragments are visible
  528. for ( int i = 0; i < pbrush->numsides; i++ )
  529. {
  530. winding_t *winding = pbrush->sides[i].winding;
  531. if ( !winding )
  532. continue;
  533. if (! (pbrush->sides[i].contents & ALL_VISIBLE_CONTENTS) )
  534. continue;
  535. side_t *side = FindOriginalSide( mb, pbrush->sides + i );
  536. face_t *f = MakeBrushFace( side, winding );
  537. // link to head of face list
  538. f->next = pFaces;
  539. pFaces = f;
  540. }
  541. // Make a list of brushes that can cut the face list for this brush
  542. cutBrushes.RemoveAll();
  543. if ( GetListOfCutBrushes( cutBrushes, pbrush, list ) )
  544. {
  545. // now cut each face to find visible fragments
  546. for ( face_t *f = pFaces; f; f = f->next )
  547. {
  548. // this will be a new list of faces that this face cuts into
  549. face_t *pClip = NULL;
  550. ClipFaceToBrushList( f, cutBrushes, &pClip );
  551. if ( pClip )
  552. {
  553. int outCount = CountFaceList(pClip);
  554. // it cut into more faces (or it was completely cut away)
  555. if ( outCount <= 1 )
  556. {
  557. // was removed or cut down, mark as split
  558. f->split[0] = f;
  559. // insert face fragments at head of list (UNDONE: reverses order, do we care?)
  560. while ( pClip )
  561. {
  562. face_t *next = pClip->next;
  563. pClip->next = pFaces;
  564. pFaces = pClip;
  565. pClip = next;
  566. }
  567. }
  568. else
  569. {
  570. // it cut into more than one visible fragment
  571. // Don't fragment details
  572. // UNDONE: Build 2d convex hull of this list and swap face winding
  573. // with that polygon? That would fix the remaining issues.
  574. FreeFaceList( pClip );
  575. pClip = NULL;
  576. }
  577. }
  578. }
  579. }
  580. // move visible fragments to global face list
  581. while ( pFaces )
  582. {
  583. face_t *next = pFaces->next;
  584. if ( pFaces->split[0] )
  585. {
  586. FreeFace( pFaces );
  587. }
  588. else
  589. {
  590. pFaces->next = pTotalFaces;
  591. pTotalFaces = pFaces;
  592. }
  593. pFaces = next;
  594. }
  595. }
  596. return pTotalFaces;
  597. }