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.

781 lines
19 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "vbsp.h"
  9. /*
  10. tag all brushes with original contents
  11. brushes may contain multiple contents
  12. there will be no brush overlap after csg phase
  13. each side has a count of the other sides it splits
  14. the best split will be the one that minimizes the total split counts
  15. of all remaining sides
  16. precalc side on plane table
  17. evaluate split side
  18. {
  19. cost = 0
  20. for all sides
  21. for all sides
  22. get
  23. if side splits side and splitside is on same child
  24. cost++;
  25. }
  26. */
  27. void SplitBrush2( bspbrush_t *brush, int planenum, bspbrush_t **front, bspbrush_t **back )
  28. {
  29. SplitBrush( brush, planenum, front, back );
  30. #if 0
  31. if (*front && (*front)->sides[(*front)->numsides-1].texinfo == -1)
  32. (*front)->sides[(*front)->numsides-1].texinfo = (*front)->sides[0].texinfo; // not -1
  33. if (*back && (*back)->sides[(*back)->numsides-1].texinfo == -1)
  34. (*back)->sides[(*back)->numsides-1].texinfo = (*back)->sides[0].texinfo; // not -1
  35. #endif
  36. }
  37. /*
  38. ===============
  39. SubtractBrush
  40. Returns a list of brushes that remain after B is subtracted from A.
  41. May by empty if A is contained inside B.
  42. The originals are undisturbed.
  43. ===============
  44. */
  45. bspbrush_t *SubtractBrush (bspbrush_t *a, bspbrush_t *b)
  46. { // a - b = out (list)
  47. int i;
  48. bspbrush_t *front, *back;
  49. bspbrush_t *out, *in;
  50. in = a;
  51. out = NULL;
  52. for (i=0 ; i<b->numsides && in ; i++)
  53. {
  54. SplitBrush2 (in, b->sides[i].planenum, &front, &back);
  55. if (in != a)
  56. FreeBrush (in);
  57. if (front)
  58. { // add to list
  59. front->next = out;
  60. out = front;
  61. }
  62. in = back;
  63. }
  64. if (in)
  65. FreeBrush (in);
  66. else
  67. { // didn't really intersect
  68. FreeBrushList (out);
  69. return a;
  70. }
  71. return out;
  72. }
  73. /*
  74. ===============
  75. IntersectBrush
  76. Returns a single brush made up by the intersection of the
  77. two provided brushes, or NULL if they are disjoint.
  78. The originals are undisturbed.
  79. ===============
  80. */
  81. bspbrush_t *IntersectBrush (bspbrush_t *a, bspbrush_t *b)
  82. {
  83. int i;
  84. bspbrush_t *front, *back;
  85. bspbrush_t *in;
  86. in = a;
  87. for (i=0 ; i<b->numsides && in ; i++)
  88. {
  89. SplitBrush2 (in, b->sides[i].planenum, &front, &back);
  90. if (in != a)
  91. FreeBrush (in);
  92. if (front)
  93. FreeBrush (front);
  94. in = back;
  95. }
  96. if (in == a || !in)
  97. return NULL;
  98. in->next = NULL;
  99. return in;
  100. }
  101. /*
  102. ===============
  103. BrushesDisjoint
  104. Returns true if the two brushes definately do not intersect.
  105. There will be false negatives for some non-axial combinations.
  106. ===============
  107. */
  108. qboolean BrushesDisjoint (bspbrush_t *a, bspbrush_t *b)
  109. {
  110. int i, j;
  111. // check bounding boxes
  112. for (i=0 ; i<3 ; i++)
  113. if (a->mins[i] >= b->maxs[i]
  114. || a->maxs[i] <= b->mins[i])
  115. return true; // bounding boxes don't overlap
  116. // check for opposing planes
  117. for (i=0 ; i<a->numsides ; i++)
  118. {
  119. for (j=0 ; j<b->numsides ; j++)
  120. {
  121. if (a->sides[i].planenum ==
  122. (b->sides[j].planenum^1) )
  123. return true; // opposite planes, so not touching
  124. }
  125. }
  126. return false; // might intersect
  127. }
  128. int minplanenums[3];
  129. int maxplanenums[3];
  130. /*
  131. ===============
  132. ClipBrushToBox
  133. Any planes shared with the box edge will be set to no texinfo
  134. ===============
  135. */
  136. bspbrush_t *ClipBrushToBox (bspbrush_t *brush, const Vector& clipmins, const Vector& clipmaxs)
  137. {
  138. int i, j;
  139. bspbrush_t *front, *back;
  140. int p;
  141. for (j=0 ; j<2 ; j++)
  142. {
  143. if (brush->maxs[j] > clipmaxs[j])
  144. {
  145. SplitBrush (brush, maxplanenums[j], &front, &back);
  146. if (front)
  147. FreeBrush (front);
  148. brush = back;
  149. if (!brush)
  150. return NULL;
  151. }
  152. if (brush->mins[j] < clipmins[j])
  153. {
  154. SplitBrush (brush, minplanenums[j], &front, &back);
  155. if (back)
  156. FreeBrush (back);
  157. brush = front;
  158. if (!brush)
  159. return NULL;
  160. }
  161. }
  162. // remove any colinear faces
  163. for (i=0 ; i<brush->numsides ; i++)
  164. {
  165. p = brush->sides[i].planenum & ~1;
  166. if (p == maxplanenums[0] || p == maxplanenums[1]
  167. || p == minplanenums[0] || p == minplanenums[1])
  168. {
  169. brush->sides[i].texinfo = TEXINFO_NODE;
  170. brush->sides[i].visible = false;
  171. }
  172. }
  173. return brush;
  174. }
  175. //-----------------------------------------------------------------------------
  176. // Creates a clipped brush from a map brush
  177. //-----------------------------------------------------------------------------
  178. static bspbrush_t *CreateClippedBrush( mapbrush_t *mb, const Vector& clipmins, const Vector& clipmaxs )
  179. {
  180. int nNumSides = mb->numsides;
  181. if (!nNumSides)
  182. return NULL;
  183. // if the brush is outside the clip area, skip it
  184. for (int j=0 ; j<3 ; j++)
  185. {
  186. if (mb->mins[j] >= clipmaxs[j] || mb->maxs[j] <= clipmins[j])
  187. {
  188. return NULL;
  189. }
  190. }
  191. // make a copy of the brush
  192. bspbrush_t *newbrush = AllocBrush( nNumSides );
  193. newbrush->original = mb;
  194. newbrush->numsides = nNumSides;
  195. memcpy (newbrush->sides, mb->original_sides, nNumSides*sizeof(side_t));
  196. for (int j=0 ; j<nNumSides; j++)
  197. {
  198. if (newbrush->sides[j].winding)
  199. {
  200. newbrush->sides[j].winding = CopyWinding (newbrush->sides[j].winding);
  201. }
  202. if (newbrush->sides[j].surf & SURF_HINT)
  203. {
  204. newbrush->sides[j].visible = true; // hints are always visible
  205. }
  206. // keep a pointer to the original map brush side -- use to create the original face later!!
  207. //newbrush->sides[j].original = &mb->original_sides[j];
  208. }
  209. VectorCopy (mb->mins, newbrush->mins);
  210. VectorCopy (mb->maxs, newbrush->maxs);
  211. // carve off anything outside the clip box
  212. newbrush = ClipBrushToBox (newbrush, clipmins, clipmaxs);
  213. return newbrush;
  214. }
  215. //-----------------------------------------------------------------------------
  216. // Creates a clipped brush from a map brush
  217. //-----------------------------------------------------------------------------
  218. static void ComputeBoundingPlanes( const Vector& clipmins, const Vector& clipmaxs )
  219. {
  220. Vector normal;
  221. float dist;
  222. for (int i=0 ; i<2 ; i++)
  223. {
  224. VectorClear (normal);
  225. normal[i] = 1;
  226. dist = clipmaxs[i];
  227. maxplanenums[i] = g_MainMap->FindFloatPlane (normal, dist);
  228. dist = clipmins[i];
  229. minplanenums[i] = g_MainMap->FindFloatPlane (normal, dist);
  230. }
  231. }
  232. //-----------------------------------------------------------------------------
  233. // This forces copies of texinfo data for matching sides of a brush
  234. //-----------------------------------------------------------------------------
  235. void CopyMatchingTexinfos( side_t *pDestSides, int numDestSides, const bspbrush_t *pSource )
  236. {
  237. for ( int i = 0; i < numDestSides; i++ )
  238. {
  239. side_t *pSide = &pDestSides[i];
  240. plane_t *pPlane = &g_MainMap->mapplanes[pSide->planenum];
  241. // We have to use the *original sides* because MapBSPBrushList could have generated
  242. // splits when cutting the original brush to the block being processed. This
  243. // will generate faces that use TEXINFO_NODE, which is definitely *not* what we want.
  244. // If we end up with faces using TEXINFO_NODE here, the area portal will flood into
  245. // the entire water volume intersecting the areaportal.
  246. mapbrush_t *pSourceBrush = pSource->original;
  247. Assert( pSourceBrush );
  248. const side_t *pSourceSide = pSourceBrush->original_sides;
  249. const side_t *pBestSide = NULL;
  250. float flBestDot = -1.0f;
  251. for ( int j = 0; j < pSourceBrush->numsides; ++j, ++pSourceSide )
  252. {
  253. if ( pSourceSide->texinfo == TEXINFO_NODE )
  254. continue;
  255. plane_t *pSourcePlane = &g_MainMap->mapplanes[pSourceSide->planenum];
  256. float flDot = DotProduct( pPlane->normal, pSourcePlane->normal );
  257. if ( flDot == 1.0f || pSide->planenum == pSourceSide->planenum )
  258. {
  259. pBestSide = pSourceSide;
  260. break;
  261. }
  262. else if ( flDot > flBestDot )
  263. {
  264. pBestSide = pSourceSide;
  265. flBestDot = flDot;
  266. }
  267. }
  268. if ( pBestSide )
  269. {
  270. pSide->texinfo = pBestSide->texinfo;
  271. if ( pSide->original )
  272. {
  273. pSide->original->texinfo = pSide->texinfo;
  274. }
  275. }
  276. else
  277. {
  278. texinfo_t *pTexInfo = &texinfo[pSide->texinfo];
  279. dtexdata_t *pTexData = GetTexData( pTexInfo->texdata );
  280. Msg("Found no matching plane for %s\n", TexDataStringTable_GetString( pTexData->nameStringTableID ) );
  281. }
  282. }
  283. }
  284. // This is a hack to allow areaportals to work in water
  285. // It was done this way for ease of implementation.
  286. // This searches a brush list to find intersecting areaportals and water
  287. // If an areaportal is found inside water, then the water contents and
  288. // texture information is copied over to the areaportal so that the
  289. // resulting space has the same properties as the water (normal areaportals assume "empty" surroundings)
  290. void FixupAreaportalWaterBrushes( bspbrush_t *pList )
  291. {
  292. for ( bspbrush_t *pAreaportal = pList; pAreaportal; pAreaportal = pAreaportal->next )
  293. {
  294. if ( !(pAreaportal->original->contents & CONTENTS_AREAPORTAL) )
  295. continue;
  296. for ( bspbrush_t *pWater = pList; pWater; pWater = pWater->next )
  297. {
  298. // avoid using areaportal/water combo brushes that have already been fixed up
  299. if ( pWater->original->contents & CONTENTS_AREAPORTAL )
  300. continue;
  301. if ( !(pWater->original->contents & MASK_SPLITAREAPORTAL) )
  302. continue;
  303. if ( BrushesDisjoint( pAreaportal, pWater ) )
  304. continue;
  305. bspbrush_t *pIntersect = IntersectBrush( pAreaportal, pWater );
  306. if ( !pIntersect )
  307. continue;
  308. FreeBrush( pIntersect );
  309. pAreaportal->original->contents |= pWater->original->contents;
  310. // HACKHACK: Ideally, this should have been done before the bspbrush_t was
  311. // created from the map brush. But since it hasn't been, retexture the original map
  312. // brush's sides
  313. CopyMatchingTexinfos( pAreaportal->sides, pAreaportal->numsides, pWater );
  314. CopyMatchingTexinfos( pAreaportal->original->original_sides, pAreaportal->original->numsides, pWater );
  315. }
  316. }
  317. }
  318. //-----------------------------------------------------------------------------
  319. // MakeBspBrushList
  320. //-----------------------------------------------------------------------------
  321. // UNDONE: Put detail brushes in a separate brush array and pass that instead of "onlyDetail" ?
  322. bspbrush_t *MakeBspBrushList (int startbrush, int endbrush, const Vector& clipmins, const Vector& clipmaxs, int detailScreen)
  323. {
  324. ComputeBoundingPlanes( clipmins, clipmaxs );
  325. bspbrush_t *pBrushList = NULL;
  326. int i;
  327. for (i=startbrush ; i<endbrush ; i++)
  328. {
  329. mapbrush_t *mb = &g_MainMap->mapbrushes[i];
  330. if ( detailScreen != FULL_DETAIL )
  331. {
  332. bool onlyDetail = (detailScreen == ONLY_DETAIL);
  333. bool detail = (mb->contents & CONTENTS_DETAIL) != 0;
  334. if ( onlyDetail ^ detail )
  335. {
  336. // both of these must have the same value or we're not interested in this brush
  337. continue;
  338. }
  339. }
  340. bspbrush_t *pNewBrush = CreateClippedBrush( mb, clipmins, clipmaxs );
  341. if ( pNewBrush )
  342. {
  343. pNewBrush->next = pBrushList;
  344. pBrushList = pNewBrush;
  345. }
  346. }
  347. return pBrushList;
  348. }
  349. //-----------------------------------------------------------------------------
  350. // A version which uses a passed-in list of brushes
  351. //-----------------------------------------------------------------------------
  352. bspbrush_t *MakeBspBrushList (mapbrush_t **pBrushes, int nBrushCount, const Vector& clipmins, const Vector& clipmaxs)
  353. {
  354. ComputeBoundingPlanes( clipmins, clipmaxs );
  355. bspbrush_t *pBrushList = NULL;
  356. for ( int i=0; i < nBrushCount; ++i )
  357. {
  358. bspbrush_t *pNewBrush = CreateClippedBrush( pBrushes[i], clipmins, clipmaxs );
  359. if ( pNewBrush )
  360. {
  361. pNewBrush->next = pBrushList;
  362. pBrushList = pNewBrush;
  363. }
  364. }
  365. return pBrushList;
  366. }
  367. /*
  368. ===============
  369. AddBspBrushListToTail
  370. ===============
  371. */
  372. bspbrush_t *AddBrushListToTail (bspbrush_t *list, bspbrush_t *tail)
  373. {
  374. bspbrush_t *walk, *next;
  375. for (walk=list ; walk ; walk=next)
  376. { // add to end of list
  377. next = walk->next;
  378. walk->next = NULL;
  379. tail->next = walk;
  380. tail = walk;
  381. }
  382. return tail;
  383. }
  384. /*
  385. ===========
  386. CullList
  387. Builds a new list that doesn't hold the given brush
  388. ===========
  389. */
  390. bspbrush_t *CullList (bspbrush_t *list, bspbrush_t *skip1)
  391. {
  392. bspbrush_t *newlist;
  393. bspbrush_t *next;
  394. newlist = NULL;
  395. for ( ; list ; list = next)
  396. {
  397. next = list->next;
  398. if (list == skip1)
  399. {
  400. FreeBrush (list);
  401. continue;
  402. }
  403. list->next = newlist;
  404. newlist = list;
  405. }
  406. return newlist;
  407. }
  408. /*
  409. ==================
  410. WriteBrushMap
  411. ==================
  412. */
  413. void WriteBrushMap (char *name, bspbrush_t *list)
  414. {
  415. FILE *f;
  416. side_t *s;
  417. int i;
  418. winding_t *w;
  419. Msg("writing %s\n", name);
  420. f = fopen (name, "w");
  421. if (!f)
  422. Error ("Can't write %s\b", name);
  423. fprintf (f, "{\n\"classname\" \"worldspawn\"\n");
  424. for ( ; list ; list=list->next )
  425. {
  426. fprintf (f, "{\n");
  427. for (i=0,s=list->sides ; i<list->numsides ; i++,s++)
  428. {
  429. w = BaseWindingForPlane (g_MainMap->mapplanes[s->planenum].normal, g_MainMap->mapplanes[s->planenum].dist);
  430. fprintf (f,"( %i %i %i ) ", (int)w->p[0][0], (int)w->p[0][1], (int)w->p[0][2]);
  431. fprintf (f,"( %i %i %i ) ", (int)w->p[1][0], (int)w->p[1][1], (int)w->p[1][2]);
  432. fprintf (f,"( %i %i %i ) ", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2]);
  433. fprintf (f, "%s 0 0 0 1 1\n", TexDataStringTable_GetString( GetTexData( texinfo[s->texinfo].texdata )->nameStringTableID ) );
  434. FreeWinding (w);
  435. }
  436. fprintf (f, "}\n");
  437. }
  438. fprintf (f, "}\n");
  439. fclose (f);
  440. }
  441. // UNDONE: This isn't quite working yet
  442. #if 0
  443. void WriteBrushVMF(char *name, bspbrush_t *list)
  444. {
  445. FILE *f;
  446. side_t *s;
  447. int i;
  448. winding_t *w;
  449. Vector u, v;
  450. Msg("writing %s\n", name);
  451. f = fopen (name, "w");
  452. if (!f)
  453. Error ("Can't write %s\b", name);
  454. fprintf (f, "world\n{\n\"classname\" \"worldspawn\"\n");
  455. for ( ; list ; list=list->next )
  456. {
  457. fprintf (f, "\tsolid\n\t{\n");
  458. for (i=0,s=list->sides ; i<list->numsides ; i++,s++)
  459. {
  460. fprintf( f, "\t\tside\n\t\t{\n" );
  461. fprintf( f, "\t\t\t\"plane\" \"" );
  462. w = BaseWindingForPlane (mapplanes[s->planenum].normal, mapplanes[s->planenum].dist);
  463. fprintf (f,"(%i %i %i) ", (int)w->p[0][0], (int)w->p[0][1], (int)w->p[0][2]);
  464. fprintf (f,"(%i %i %i) ", (int)w->p[1][0], (int)w->p[1][1], (int)w->p[1][2]);
  465. fprintf (f,"(%i %i %i)", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2]);
  466. fprintf( f, "\"\n" );
  467. fprintf( f, "\t\t\t\"material\" \"%s\"\n", GetTexData( texinfo[s->texinfo].texdata )->name );
  468. // UNDONE: recreate correct texture axes
  469. BasisForPlane( mapplanes[s->planenum].normal, u, v );
  470. fprintf( f, "\t\t\t\"uaxis\" \"[%.3f %.3f %.3f 0] 1.0\"\n", u[0], u[1], u[2] );
  471. fprintf( f, "\t\t\t\"vaxis\" \"[%.3f %.3f %.3f 0] 1.0\"\n", v[0], v[1], v[2] );
  472. fprintf( f, "\t\t\t\"rotation\" \"0.0\"\n" );
  473. fprintf( f, "\t\t\t\"lightmapscale\" \"16.0\"\n" );
  474. FreeWinding (w);
  475. fprintf (f, "\t\t}\n");
  476. }
  477. fprintf (f, "\t}\n");
  478. }
  479. fprintf (f, "}\n");
  480. fclose (f);
  481. }
  482. #endif
  483. void PrintBrushContentsToString( int contents, char *pOut, int nMaxChars )
  484. {
  485. #define ADD_CONTENTS( flag ) \
  486. if ( contents & flag ) \
  487. Q_strncat( pOut, #flag " ", nMaxChars, COPY_ALL_CHARACTERS );
  488. pOut[0] = 0;
  489. ADD_CONTENTS(CONTENTS_SOLID)
  490. ADD_CONTENTS(CONTENTS_WINDOW)
  491. ADD_CONTENTS(CONTENTS_AUX)
  492. ADD_CONTENTS(CONTENTS_GRATE)
  493. ADD_CONTENTS(CONTENTS_SLIME)
  494. ADD_CONTENTS(CONTENTS_WATER)
  495. ADD_CONTENTS(CONTENTS_BLOCKLOS)
  496. ADD_CONTENTS(CONTENTS_OPAQUE)
  497. ADD_CONTENTS(CONTENTS_TESTFOGVOLUME)
  498. ADD_CONTENTS(CONTENTS_BLOCKLIGHT)
  499. ADD_CONTENTS(CONTENTS_TEAM1)
  500. ADD_CONTENTS(CONTENTS_TEAM2)
  501. ADD_CONTENTS(CONTENTS_MOVEABLE)
  502. ADD_CONTENTS(CONTENTS_AREAPORTAL)
  503. ADD_CONTENTS(CONTENTS_PLAYERCLIP)
  504. ADD_CONTENTS(CONTENTS_MONSTERCLIP)
  505. ADD_CONTENTS(CONTENTS_ORIGIN)
  506. ADD_CONTENTS(CONTENTS_MONSTER)
  507. ADD_CONTENTS(CONTENTS_DEBRIS)
  508. ADD_CONTENTS(CONTENTS_DETAIL)
  509. ADD_CONTENTS(CONTENTS_TRANSLUCENT)
  510. ADD_CONTENTS(CONTENTS_LADDER)
  511. ADD_CONTENTS(CONTENTS_HITBOX)
  512. }
  513. void PrintBrushContents( int contents )
  514. {
  515. char str[1024];
  516. PrintBrushContentsToString( contents, str, sizeof( str ) );
  517. Msg( "%s", str );
  518. }
  519. /*
  520. ==================
  521. BrushGE
  522. Returns true if b1 is allowed to bite b2
  523. ==================
  524. */
  525. qboolean BrushGE (bspbrush_t *b1, bspbrush_t *b2)
  526. {
  527. // Areaportals are allowed to bite water + slime
  528. // NOTE: This brush combo should have been fixed up
  529. // in a first pass (FixupAreaportalWaterBrushes)
  530. if( (b2->original->contents & MASK_SPLITAREAPORTAL) &&
  531. (b1->original->contents & CONTENTS_AREAPORTAL) )
  532. {
  533. return true;
  534. }
  535. // detail brushes never bite structural brushes
  536. if ( (b1->original->contents & CONTENTS_DETAIL)
  537. && !(b2->original->contents & CONTENTS_DETAIL) )
  538. return false;
  539. if (b1->original->contents & CONTENTS_SOLID)
  540. return true;
  541. // Transparent brushes are not marked as detail anymore, so let them cut each other.
  542. if ( (b1->original->contents & TRANSPARENT_CONTENTS) && (b2->original->contents & TRANSPARENT_CONTENTS) )
  543. return true;
  544. return false;
  545. }
  546. /*
  547. =================
  548. ChopBrushes
  549. Carves any intersecting solid brushes into the minimum number
  550. of non-intersecting brushes.
  551. =================
  552. */
  553. bspbrush_t *ChopBrushes (bspbrush_t *head)
  554. {
  555. bspbrush_t *b1, *b2, *next;
  556. bspbrush_t *tail;
  557. bspbrush_t *keep;
  558. bspbrush_t *sub, *sub2;
  559. int c1, c2;
  560. qprintf ("---- ChopBrushes ----\n");
  561. qprintf ("original brushes: %i\n", CountBrushList (head));
  562. #if DEBUG_BRUSHMODEL
  563. if (entity_num == DEBUG_BRUSHMODEL)
  564. WriteBrushList ("before.gl", head, false);
  565. #endif
  566. keep = NULL;
  567. newlist:
  568. // find tail
  569. if (!head)
  570. return NULL;
  571. for (tail=head ; tail->next ; tail=tail->next)
  572. ;
  573. for (b1=head ; b1 ; b1=next)
  574. {
  575. next = b1->next;
  576. for (b2=b1->next ; b2 ; b2 = b2->next)
  577. {
  578. if (BrushesDisjoint (b1, b2))
  579. continue;
  580. sub = NULL;
  581. sub2 = NULL;
  582. c1 = 999999;
  583. c2 = 999999;
  584. if ( BrushGE (b2, b1) )
  585. {
  586. // printf( "b2 bites b1\n" );
  587. sub = SubtractBrush (b1, b2);
  588. if (sub == b1)
  589. continue; // didn't really intersect
  590. if (!sub)
  591. { // b1 is swallowed by b2
  592. head = CullList (b1, b1);
  593. goto newlist;
  594. }
  595. c1 = CountBrushList (sub);
  596. }
  597. if ( BrushGE (b1, b2) )
  598. {
  599. // printf( "b1 bites b2\n" );
  600. sub2 = SubtractBrush (b2, b1);
  601. if (sub2 == b2)
  602. continue; // didn't really intersect
  603. if (!sub2)
  604. { // b2 is swallowed by b1
  605. FreeBrushList (sub);
  606. head = CullList (b1, b2);
  607. goto newlist;
  608. }
  609. c2 = CountBrushList (sub2);
  610. }
  611. if (!sub && !sub2)
  612. continue; // neither one can bite
  613. // only accept if it didn't fragment
  614. // (commening this out allows full fragmentation)
  615. if (c1 > 1 && c2 > 1)
  616. {
  617. const int contents1 = b1->original->contents;
  618. const int contents2 = b2->original->contents;
  619. // if both detail, allow fragmentation
  620. if ( !((contents1&contents2) & CONTENTS_DETAIL) && !((contents1|contents2) & CONTENTS_AREAPORTAL) )
  621. {
  622. if (sub2)
  623. FreeBrushList (sub2);
  624. if (sub)
  625. FreeBrushList (sub);
  626. continue;
  627. }
  628. }
  629. if (c1 < c2)
  630. {
  631. if (sub2)
  632. FreeBrushList (sub2);
  633. tail = AddBrushListToTail (sub, tail);
  634. head = CullList (b1, b1);
  635. goto newlist;
  636. }
  637. else
  638. {
  639. if (sub)
  640. FreeBrushList (sub);
  641. tail = AddBrushListToTail (sub2, tail);
  642. head = CullList (b1, b2);
  643. goto newlist;
  644. }
  645. }
  646. if (!b2)
  647. { // b1 is no longer intersecting anything, so keep it
  648. b1->next = keep;
  649. keep = b1;
  650. }
  651. }
  652. qprintf ("output brushes: %i\n", CountBrushList (keep));
  653. #if DEBUG_BRUSHMODEL
  654. if ( entity_num == DEBUG_BRUSHMODEL )
  655. {
  656. WriteBrushList ("after.gl", keep, false);
  657. WriteBrushMap ("after.map", keep);
  658. }
  659. #endif
  660. return keep;
  661. }