Brush.cpp 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583
  1. /*
  2. ===========================================================================
  3. Doom 3 GPL Source Code
  4. Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
  6. Doom 3 Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #include "../../../idlib/precompiled.h"
  21. #pragma hdrstop
  22. #include "Brush.h"
  23. #define BRUSH_EPSILON 0.1f
  24. #define BRUSH_PLANE_NORMAL_EPSILON 0.00001f
  25. #define BRUSH_PLANE_DIST_EPSILON 0.01f
  26. #define OUTPUT_UPDATE_TIME 500 // update every 500 msec
  27. //#define OUTPUT_CHOP_STATS
  28. /*
  29. ============
  30. DisplayRealTimeString
  31. ============
  32. */
  33. void DisplayRealTimeString( char *string, ... ) {
  34. va_list argPtr;
  35. char buf[MAX_STRING_CHARS];
  36. static int lastUpdateTime;
  37. int time;
  38. time = Sys_Milliseconds();
  39. if ( time > lastUpdateTime + OUTPUT_UPDATE_TIME ) {
  40. va_start( argPtr, string );
  41. vsprintf( buf, string, argPtr );
  42. va_end( argPtr );
  43. common->Printf( buf );
  44. lastUpdateTime = time;
  45. }
  46. }
  47. //===============================================================
  48. //
  49. // idBrushSide
  50. //
  51. //===============================================================
  52. /*
  53. ============
  54. idBrushSide::idBrushSide
  55. ============
  56. */
  57. idBrushSide::idBrushSide( void ) {
  58. flags = 0;
  59. planeNum = -1;
  60. winding = NULL;
  61. }
  62. /*
  63. ============
  64. idBrushSide::idBrushSide
  65. ============
  66. */
  67. idBrushSide::idBrushSide( const idPlane &plane, int planeNum ) {
  68. this->flags = 0;
  69. this->plane = plane;
  70. this->planeNum = planeNum;
  71. this->winding = NULL;
  72. }
  73. /*
  74. ============
  75. idBrushSide::~idBrushSide
  76. ============
  77. */
  78. idBrushSide::~idBrushSide( void ) {
  79. if ( winding ) {
  80. delete winding;
  81. }
  82. }
  83. /*
  84. ============
  85. idBrushSide::Copy
  86. ============
  87. */
  88. idBrushSide *idBrushSide::Copy( void ) const {
  89. idBrushSide *side;
  90. side = new idBrushSide( plane, planeNum );
  91. side->flags = flags;
  92. if ( winding ) {
  93. side->winding = winding->Copy();
  94. }
  95. else {
  96. side->winding = NULL;
  97. }
  98. return side;
  99. }
  100. /*
  101. ============
  102. idBrushSide::Split
  103. ============
  104. */
  105. int idBrushSide::Split( const idPlane &splitPlane, idBrushSide **front, idBrushSide **back ) const {
  106. idWinding *frontWinding, *backWinding;
  107. assert( winding );
  108. *front = *back = NULL;
  109. winding->Split( splitPlane, 0.0f, &frontWinding, &backWinding );
  110. if ( frontWinding ) {
  111. (*front) = new idBrushSide( plane, planeNum );
  112. (*front)->winding = frontWinding;
  113. (*front)->flags = flags;
  114. }
  115. if ( backWinding ) {
  116. (*back) = new idBrushSide( plane, planeNum );
  117. (*back)->winding = backWinding;
  118. (*back)->flags = flags;
  119. }
  120. if ( frontWinding && backWinding ) {
  121. return PLANESIDE_CROSS;
  122. }
  123. else if ( frontWinding ) {
  124. return PLANESIDE_FRONT;
  125. }
  126. else {
  127. return PLANESIDE_BACK;
  128. }
  129. }
  130. //===============================================================
  131. //
  132. // idBrushSide
  133. //
  134. //===============================================================
  135. /*
  136. ============
  137. idBrush::idBrush
  138. ============
  139. */
  140. idBrush::idBrush( void ) {
  141. contents = flags = 0;
  142. bounds.Clear();
  143. sides.Clear();
  144. windingsValid = false;
  145. }
  146. /*
  147. ============
  148. idBrush::~idBrush
  149. ============
  150. */
  151. idBrush::~idBrush( void ) {
  152. for ( int i = 0; i < sides.Num(); i++ ) {
  153. delete sides[i];
  154. }
  155. }
  156. /*
  157. ============
  158. idBrush::RemoveSidesWithoutWinding
  159. ============
  160. */
  161. bool idBrush::RemoveSidesWithoutWinding( void ) {
  162. int i;
  163. for ( i = 0; i < sides.Num(); i++ ) {
  164. if ( sides[i]->winding ) {
  165. continue;
  166. }
  167. sides.RemoveIndex( i );
  168. i--;
  169. }
  170. return ( sides.Num() >= 4 );
  171. }
  172. /*
  173. ============
  174. idBrush::CreateWindings
  175. ============
  176. */
  177. bool idBrush::CreateWindings( void ) {
  178. int i, j;
  179. idBrushSide *side;
  180. bounds.Clear();
  181. for ( i = 0; i < sides.Num(); i++ ) {
  182. side = sides[i];
  183. if ( side->winding ) {
  184. delete side->winding;
  185. }
  186. side->winding = new idWinding( side->plane.Normal(), side->plane.Dist() );
  187. for ( j = 0; j < sides.Num() && side->winding; j++ ) {
  188. if ( i == j ) {
  189. continue;
  190. }
  191. // keep the winding if on the clip plane
  192. side->winding = side->winding->Clip( -sides[j]->plane, BRUSH_EPSILON, true );
  193. }
  194. if ( side->winding ) {
  195. for ( j = 0; j < side->winding->GetNumPoints(); j++ ) {
  196. bounds.AddPoint( (*side->winding)[j].ToVec3() );
  197. }
  198. }
  199. }
  200. if ( bounds[0][0] > bounds[1][0] ) {
  201. return false;
  202. }
  203. for ( i = 0; i < 3; i++ ) {
  204. if ( bounds[0][i] < MIN_WORLD_COORD || bounds[1][i] > MAX_WORLD_COORD ) {
  205. return false;
  206. }
  207. }
  208. windingsValid = true;
  209. return true;
  210. }
  211. /*
  212. ============
  213. idBrush::BoundBrush
  214. ============
  215. */
  216. void idBrush::BoundBrush( const idBrush *original ) {
  217. int i, j;
  218. idBrushSide *side;
  219. idWinding *w;
  220. assert( windingsValid );
  221. bounds.Clear();
  222. for ( i = 0; i < sides.Num(); i++ ) {
  223. side = sides[i];
  224. w = side->winding;
  225. if ( !w ) {
  226. continue;
  227. }
  228. for ( j = 0; j < w->GetNumPoints(); j++ ) {
  229. bounds.AddPoint( (*w)[j].ToVec3() );
  230. }
  231. }
  232. if ( bounds[0][0] > bounds[1][0] ) {
  233. if ( original ) {
  234. idBrushMap *bm = new idBrushMap( "error_brush", "_original" );
  235. bm->WriteBrush( original );
  236. delete bm;
  237. }
  238. common->Error( "idBrush::BoundBrush: brush %d on entity %d without windings", primitiveNum, entityNum );
  239. }
  240. for ( i = 0; i < 3; i++ ) {
  241. if ( bounds[0][i] < MIN_WORLD_COORD || bounds[1][i] > MAX_WORLD_COORD ) {
  242. if ( original ) {
  243. idBrushMap *bm = new idBrushMap( "error_brush", "_original" );
  244. bm->WriteBrush( original );
  245. delete bm;
  246. }
  247. common->Error( "idBrush::BoundBrush: brush %d on entity %d is unbounded", primitiveNum, entityNum );
  248. }
  249. }
  250. }
  251. /*
  252. ============
  253. idBrush::FromSides
  254. ============
  255. */
  256. bool idBrush::FromSides( idList<idBrushSide *> &sideList ) {
  257. int i;
  258. for ( i = 0; i < sideList.Num(); i++ ) {
  259. sides.Append( sideList[i] );
  260. }
  261. sideList.Clear();
  262. return CreateWindings();
  263. }
  264. /*
  265. ============
  266. idBrush::FromWinding
  267. ============
  268. */
  269. bool idBrush::FromWinding( const idWinding &w, const idPlane &windingPlane ) {
  270. int i, j, bestAxis;
  271. idPlane plane;
  272. idVec3 normal, axialNormal;
  273. sides.Append( new idBrushSide( windingPlane, -1 ) );
  274. sides.Append( new idBrushSide( -windingPlane, -1 ) );
  275. bestAxis = 0;
  276. for ( i = 1; i < 3; i++ ) {
  277. if ( idMath::Fabs( windingPlane.Normal()[i] ) > idMath::Fabs( windingPlane.Normal()[bestAxis] ) ) {
  278. bestAxis = i;
  279. }
  280. }
  281. axialNormal = vec3_origin;
  282. if ( windingPlane.Normal()[bestAxis] > 0.0f ) {
  283. axialNormal[bestAxis] = 1.0f;
  284. }
  285. else {
  286. axialNormal[bestAxis] = -1.0f;
  287. }
  288. for ( i = 0; i < w.GetNumPoints(); i++ ) {
  289. j = (i+1) % w.GetNumPoints();
  290. normal = ( w[j].ToVec3() - w[i].ToVec3() ).Cross( axialNormal );
  291. if ( normal.Normalize() < 0.5f ) {
  292. continue;
  293. }
  294. plane.SetNormal( normal );
  295. plane.FitThroughPoint( w[j].ToVec3() );
  296. sides.Append( new idBrushSide( plane, -1 ) );
  297. }
  298. if ( sides.Num() < 4 ) {
  299. for ( i = 0; i < sides.Num(); i++ ) {
  300. delete sides[i];
  301. }
  302. sides.Clear();
  303. return false;
  304. }
  305. sides[0]->winding = w.Copy();
  306. windingsValid = true;
  307. BoundBrush();
  308. return true;
  309. }
  310. /*
  311. ============
  312. idBrush::FromBounds
  313. ============
  314. */
  315. bool idBrush::FromBounds( const idBounds &bounds ) {
  316. int axis, dir;
  317. idVec3 normal;
  318. idPlane plane;
  319. for ( axis = 0; axis < 3; axis++ ) {
  320. for ( dir = -1; dir <= 1; dir += 2 ) {
  321. normal = vec3_origin;
  322. normal[axis] = dir;
  323. plane.SetNormal( normal );
  324. plane.SetDist( dir * bounds[(dir == 1)][axis] );
  325. sides.Append( new idBrushSide( plane, -1 ) );
  326. }
  327. }
  328. return CreateWindings();
  329. }
  330. /*
  331. ============
  332. idBrush::Transform
  333. ============
  334. */
  335. void idBrush::Transform( const idVec3 &origin, const idMat3 &axis ) {
  336. int i;
  337. bool transformed = false;
  338. if ( axis.IsRotated() ) {
  339. for ( i = 0; i < sides.Num(); i++ ) {
  340. sides[i]->plane.RotateSelf( vec3_origin, axis );
  341. }
  342. transformed = true;
  343. }
  344. if ( origin != vec3_origin ) {
  345. for ( i = 0; i < sides.Num(); i++ ) {
  346. sides[i]->plane.TranslateSelf( origin );
  347. }
  348. transformed = true;
  349. }
  350. if ( transformed ) {
  351. CreateWindings();
  352. }
  353. }
  354. /*
  355. ============
  356. idBrush::GetVolume
  357. ============
  358. */
  359. float idBrush::GetVolume( void ) const {
  360. int i;
  361. idWinding *w;
  362. idVec3 corner;
  363. float d, area, volume;
  364. // grab the first valid point as a corner
  365. w = NULL;
  366. for ( i = 0; i < sides.Num(); i++ ) {
  367. w = sides[i]->winding;
  368. if ( w ) {
  369. break;
  370. }
  371. }
  372. if ( !w ) {
  373. return 0.0f;
  374. }
  375. corner = (*w)[0].ToVec3();
  376. // create tetrahedrons to all other sides
  377. volume = 0.0f;
  378. for ( ; i < sides.Num(); i++) {
  379. w = sides[i]->winding;
  380. if ( !w ) {
  381. continue;
  382. }
  383. d = -( corner * sides[i]->plane.Normal() - sides[i]->plane.Dist() );
  384. area = w->GetArea();
  385. volume += d * area;
  386. }
  387. return ( volume * ( 1.0f / 3.0f ) );
  388. }
  389. /*
  390. ============
  391. idBrush::Subtract
  392. ============
  393. */
  394. bool idBrush::Subtract( const idBrush *b, idBrushList &list ) const {
  395. int i;
  396. idBrush *front, *back;
  397. const idBrush *in;
  398. list.Clear();
  399. in = this;
  400. for ( i = 0; i < b->sides.Num() && in; i++ ) {
  401. in->Split( b->sides[i]->plane, b->sides[i]->planeNum, &front, &back );
  402. if ( in != this ) {
  403. delete in;
  404. }
  405. if ( front ) {
  406. list.AddToTail( front );
  407. }
  408. in = back;
  409. }
  410. // if didn't really intersect
  411. if ( !in ) {
  412. list.Free();
  413. return false;
  414. }
  415. delete in;
  416. return true;
  417. }
  418. /*
  419. ============
  420. idBrush::TryMerge
  421. ============
  422. */
  423. bool idBrush::TryMerge( const idBrush *brush, const idPlaneSet &planeList ) {
  424. int i, j, k, l, m, seperatingPlane;
  425. const idBrush *brushes[2];
  426. const idWinding *w;
  427. const idPlane *plane;
  428. // brush bounds should overlap
  429. for ( i = 0; i < 3; i++ ) {
  430. if ( bounds[0][i] > brush->bounds[1][i] + 0.1f ) {
  431. return false;
  432. }
  433. if ( bounds[1][i] < brush->bounds[0][i] - 0.1f ) {
  434. return false;
  435. }
  436. }
  437. // the brushes should share an opposite plane
  438. seperatingPlane = -1;
  439. for ( i = 0; i < GetNumSides(); i++ ) {
  440. for ( j = 0; j < brush->GetNumSides(); j++ ) {
  441. if ( GetSide(i)->GetPlaneNum() == (brush->GetSide(j)->GetPlaneNum() ^ 1) ) {
  442. // may only have one seperating plane
  443. if ( seperatingPlane != -1 ) {
  444. return false;
  445. }
  446. seperatingPlane = GetSide(i)->GetPlaneNum();
  447. break;
  448. }
  449. }
  450. }
  451. if ( seperatingPlane == -1 ) {
  452. return false;
  453. }
  454. brushes[0] = this;
  455. brushes[1] = brush;
  456. for ( i = 0; i < 2; i++ ) {
  457. j = !i;
  458. for ( k = 0; k < brushes[i]->GetNumSides(); k++ ) {
  459. // if the brush side plane is the seprating plane
  460. if ( !( ( brushes[i]->GetSide(k)->GetPlaneNum() ^ seperatingPlane ) >> 1 ) ) {
  461. continue;
  462. }
  463. plane = &brushes[i]->GetSide(k)->GetPlane();
  464. // all the non seperating brush sides of the other brush should be at the back or on the plane
  465. for ( l = 0; l < brushes[j]->GetNumSides(); l++ ) {
  466. w = brushes[j]->GetSide(l)->GetWinding();
  467. if ( !w ) {
  468. continue;
  469. }
  470. if ( !( ( brushes[j]->GetSide(l)->GetPlaneNum() ^ seperatingPlane ) >> 1 ) ) {
  471. continue;
  472. }
  473. for ( m = 0; m < w->GetNumPoints(); m++ ) {
  474. if ( plane->Distance( (*w)[m].ToVec3() ) > 0.1f ) {
  475. return false;
  476. }
  477. }
  478. }
  479. }
  480. }
  481. // add any sides from the other brush to this brush
  482. for ( i = 0; i < brush->GetNumSides(); i++ ) {
  483. for ( j = 0; j < GetNumSides(); j++ ) {
  484. if ( !( ( brush->GetSide(i)->GetPlaneNum() ^ GetSide(j)->GetPlaneNum() ) >> 1 ) ) {
  485. break;
  486. }
  487. }
  488. if ( j < GetNumSides() ) {
  489. sides[j]->flags &= brush->GetSide(i)->GetFlags();
  490. continue;
  491. }
  492. sides.Append( brush->GetSide(i)->Copy() );
  493. }
  494. // remove any side from this brush that is the opposite of a side of the other brush
  495. for ( i = 0; i < GetNumSides(); i++ ) {
  496. for ( j = 0; j < brush->GetNumSides(); j++ ) {
  497. if ( GetSide(i)->GetPlaneNum() == ( brush->GetSide(j)->GetPlaneNum() ^ 1 ) ) {
  498. break;
  499. }
  500. }
  501. if ( j < brush->GetNumSides() ) {
  502. delete sides[i];
  503. sides.RemoveIndex(i);
  504. i--;
  505. continue;
  506. }
  507. }
  508. contents |= brush->contents;
  509. CreateWindings();
  510. BoundBrush();
  511. return true;
  512. }
  513. /*
  514. ============
  515. idBrush::Split
  516. ============
  517. */
  518. int idBrush::Split( const idPlane &plane, int planeNum, idBrush **front, idBrush **back ) const {
  519. int res, i, j;
  520. idBrushSide *side, *frontSide, *backSide;
  521. float dist, maxBack, maxFront, *maxBackWinding, *maxFrontWinding;
  522. idWinding *w, *mid;
  523. assert( windingsValid );
  524. if ( front ) {
  525. *front = NULL;
  526. }
  527. if ( back ) {
  528. *back = NULL;
  529. }
  530. res = bounds.PlaneSide( plane, -BRUSH_EPSILON );
  531. if ( res == PLANESIDE_FRONT ) {
  532. if ( front ) {
  533. *front = Copy();
  534. }
  535. return res;
  536. }
  537. if ( res == PLANESIDE_BACK ) {
  538. if ( back ) {
  539. *back = Copy();
  540. }
  541. return res;
  542. }
  543. maxBackWinding = (float *) _alloca16( sides.Num() * sizeof(float) );
  544. maxFrontWinding = (float *) _alloca16( sides.Num() * sizeof(float) );
  545. maxFront = maxBack = 0.0f;
  546. for ( i = 0; i < sides.Num(); i++ ) {
  547. side = sides[i];
  548. w = side->winding;
  549. if ( !w ) {
  550. continue;
  551. }
  552. maxBackWinding[i] = 10.0f;
  553. maxFrontWinding[i] = -10.0f;
  554. for ( j = 0; j < w->GetNumPoints(); j++ ) {
  555. dist = plane.Distance( (*w)[j].ToVec3() );
  556. if ( dist > maxFrontWinding[i] ) {
  557. maxFrontWinding[i] = dist;
  558. }
  559. if ( dist < maxBackWinding[i] ) {
  560. maxBackWinding[i] = dist;
  561. }
  562. }
  563. if ( maxFrontWinding[i] > maxFront ) {
  564. maxFront = maxFrontWinding[i];
  565. }
  566. if ( maxBackWinding[i] < maxBack ) {
  567. maxBack = maxBackWinding[i];
  568. }
  569. }
  570. if ( maxFront < BRUSH_EPSILON ) {
  571. if ( back ) {
  572. *back = Copy();
  573. }
  574. return PLANESIDE_BACK;
  575. }
  576. if ( maxBack > -BRUSH_EPSILON ) {
  577. if ( front ) {
  578. *front = Copy();
  579. }
  580. return PLANESIDE_FRONT;
  581. }
  582. mid = new idWinding( plane.Normal(), plane.Dist() );
  583. for ( i = 0; i < sides.Num() && mid; i++ ) {
  584. mid = mid->Clip( -sides[i]->plane, BRUSH_EPSILON, false );
  585. }
  586. if ( mid ) {
  587. if ( mid->IsTiny() ) {
  588. delete mid;
  589. mid = NULL;
  590. }
  591. else if ( mid->IsHuge() ) {
  592. // if the winding is huge then the brush is unbounded
  593. common->Warning( "brush %d on entity %d is unbounded"
  594. "( %1.2f %1.2f %1.2f )-( %1.2f %1.2f %1.2f )-( %1.2f %1.2f %1.2f )", primitiveNum, entityNum,
  595. bounds[0][0], bounds[0][1], bounds[0][2], bounds[1][0], bounds[1][1], bounds[1][2],
  596. bounds[1][0]-bounds[0][0], bounds[1][1]-bounds[0][1], bounds[1][2]-bounds[0][2] );
  597. delete mid;
  598. mid = NULL;
  599. }
  600. }
  601. if ( !mid ) {
  602. if ( maxFront > - maxBack ) {
  603. if ( front ) {
  604. *front = Copy();
  605. }
  606. return PLANESIDE_FRONT;
  607. }
  608. else {
  609. if ( back ) {
  610. *back = Copy();
  611. }
  612. return PLANESIDE_BACK;
  613. }
  614. }
  615. if ( !front && !back ) {
  616. delete mid;
  617. return PLANESIDE_CROSS;
  618. }
  619. *front = new idBrush();
  620. (*front)->SetContents( contents );
  621. (*front)->SetEntityNum( entityNum );
  622. (*front)->SetPrimitiveNum( primitiveNum );
  623. *back = new idBrush();
  624. (*back)->SetContents( contents );
  625. (*back)->SetEntityNum( entityNum );
  626. (*back)->SetPrimitiveNum( primitiveNum );
  627. for ( i = 0; i < sides.Num(); i++ ) {
  628. side = sides[i];
  629. if ( !side->winding ) {
  630. continue;
  631. }
  632. // if completely at the front
  633. if ( maxBackWinding[i] >= BRUSH_EPSILON ) {
  634. (*front)->sides.Append( side->Copy() );
  635. }
  636. // if completely at the back
  637. else if ( maxFrontWinding[i] <= -BRUSH_EPSILON ) {
  638. (*back)->sides.Append( side->Copy() );
  639. }
  640. else {
  641. // split the side
  642. side->Split( plane, &frontSide, &backSide );
  643. if ( frontSide ) {
  644. (*front)->sides.Append( frontSide );
  645. }
  646. else if ( maxFrontWinding[i] > -BRUSH_EPSILON ) {
  647. // favor an overconstrained brush
  648. side = side->Copy();
  649. side->winding = side->winding->Clip( idPlane( plane.Normal(), (plane.Dist() - (BRUSH_EPSILON+0.02f)) ), 0.01f, true );
  650. assert( side->winding );
  651. (*front)->sides.Append( side );
  652. }
  653. if ( backSide ) {
  654. (*back)->sides.Append( backSide );
  655. }
  656. else if ( maxBackWinding[i] < BRUSH_EPSILON ) {
  657. // favor an overconstrained brush
  658. side = side->Copy();
  659. side->winding = side->winding->Clip( idPlane( -plane.Normal(), -(plane.Dist() + (BRUSH_EPSILON+0.02f)) ), 0.01f, true );
  660. assert( side->winding );
  661. (*back)->sides.Append( side );
  662. }
  663. }
  664. }
  665. side = new idBrushSide( -plane, planeNum^1 );
  666. side->winding = mid->Reverse();
  667. side->flags |= SFL_SPLIT;
  668. (*front)->sides.Append( side );
  669. (*front)->windingsValid = true;
  670. (*front)->BoundBrush( this );
  671. side = new idBrushSide( plane, planeNum );
  672. side->winding = mid;
  673. side->flags |= SFL_SPLIT;
  674. (*back)->sides.Append( side );
  675. (*back)->windingsValid = true;
  676. (*back)->BoundBrush( this );
  677. return PLANESIDE_CROSS;
  678. }
  679. /*
  680. ============
  681. idBrush::AddBevelsForAxialBox
  682. ============
  683. */
  684. #define BRUSH_BEVEL_EPSILON 0.1f
  685. void idBrush::AddBevelsForAxialBox( void ) {
  686. int axis, dir, i, j, k, l, order;
  687. idBrushSide *side, *newSide;
  688. idPlane plane;
  689. idVec3 normal, vec;
  690. idWinding *w, *w2;
  691. float d, minBack;
  692. assert( windingsValid );
  693. // add the axial planes
  694. order = 0;
  695. for ( axis = 0; axis < 3; axis++ ) {
  696. for ( dir = -1; dir <= 1; dir += 2, order++ ) {
  697. // see if the plane is already present
  698. for ( i = 0; i < sides.Num(); i++ ) {
  699. if ( dir > 0 ) {
  700. if ( sides[i]->plane.Normal()[axis] >= 0.9999f ) {
  701. break;
  702. }
  703. }
  704. else {
  705. if ( sides[i]->plane.Normal()[axis] <= -0.9999f ) {
  706. break;
  707. }
  708. }
  709. }
  710. if ( i >= sides.Num() ) {
  711. normal = vec3_origin;
  712. normal[axis] = dir;
  713. plane.SetNormal( normal );
  714. plane.SetDist( dir * bounds[(dir == 1)][axis] );
  715. newSide = new idBrushSide( plane, -1 );
  716. newSide->SetFlag( SFL_BEVEL );
  717. sides.Append( newSide );
  718. }
  719. }
  720. }
  721. // if the brush is pure axial we're done
  722. if ( sides.Num() == 6 ) {
  723. return;
  724. }
  725. // test the non-axial plane edges
  726. for ( i = 0; i < sides.Num(); i++ ) {
  727. side = sides[i];
  728. w = side->winding;
  729. if ( !w ) {
  730. continue;
  731. }
  732. for ( j = 0; j < w->GetNumPoints(); j++) {
  733. k = (j+1) % w->GetNumPoints();
  734. vec = (*w)[j].ToVec3() - (*w)[k].ToVec3();
  735. if ( vec.Normalize() < 0.5f ) {
  736. continue;
  737. }
  738. for ( k = 0; k < 3; k++ ) {
  739. if ( vec[k] == 1.0f || vec[k] == -1.0f || (vec[k] == 0.0f && vec[(k+1)%3] == 0.0f) ) {
  740. break; // axial
  741. }
  742. }
  743. if ( k < 3 ) {
  744. continue; // only test non-axial edges
  745. }
  746. // try the six possible slanted axials from this edge
  747. for ( axis = 0; axis < 3; axis++ ) {
  748. for ( dir = -1; dir <= 1; dir += 2 ) {
  749. // construct a plane
  750. normal = vec3_origin;
  751. normal[axis] = dir;
  752. normal = vec.Cross( normal );
  753. if ( normal.Normalize() < 0.5f ) {
  754. continue;
  755. }
  756. plane.SetNormal( normal );
  757. plane.FitThroughPoint( (*w)[j].ToVec3() );
  758. // if all the points on all the sides are
  759. // behind this plane, it is a proper edge bevel
  760. for ( k = 0; k < sides.Num(); k++ ) {
  761. // if this plane has allready been used, skip it
  762. if ( plane.Compare( sides[k]->plane, 0.001f, 0.1f ) ) {
  763. break;
  764. }
  765. w2 = sides[k]->winding;
  766. if ( !w2 ) {
  767. continue;
  768. }
  769. minBack = 0.0f;
  770. for ( l = 0; l < w2->GetNumPoints(); l++ ) {
  771. d = plane.Distance( (*w2)[l].ToVec3() );
  772. if ( d > BRUSH_BEVEL_EPSILON ) {
  773. break; // point at the front
  774. }
  775. if ( d < minBack ) {
  776. minBack = d;
  777. }
  778. }
  779. // if some point was at the front
  780. if ( l < w2->GetNumPoints() ) {
  781. break;
  782. }
  783. // if no points at the back then the winding is on the bevel plane
  784. if ( minBack > -BRUSH_BEVEL_EPSILON ) {
  785. break;
  786. }
  787. }
  788. if ( k < sides.Num() ) {
  789. continue; // wasn't part of the outer hull
  790. }
  791. // add this plane
  792. newSide = new idBrushSide( plane, -1 );
  793. newSide->SetFlag( SFL_BEVEL );
  794. sides.Append( newSide );
  795. }
  796. }
  797. }
  798. }
  799. }
  800. /*
  801. ============
  802. idBrush::ExpandForAxialBox
  803. ============
  804. */
  805. void idBrush::ExpandForAxialBox( const idBounds &bounds ) {
  806. int i, j;
  807. idBrushSide *side;
  808. idVec3 v;
  809. AddBevelsForAxialBox();
  810. for ( i = 0; i < sides.Num(); i++ ) {
  811. side = sides[i];
  812. for ( j = 0; j < 3; j++ ) {
  813. if ( side->plane.Normal()[j] > 0.0f ) {
  814. v[j] = bounds[0][j];
  815. }
  816. else {
  817. v[j] = bounds[1][j];
  818. }
  819. }
  820. side->plane.SetDist( side->plane.Dist() + v * -side->plane.Normal() );
  821. }
  822. if ( !CreateWindings() ) {
  823. common->Error( "idBrush::ExpandForAxialBox: brush %d on entity %d imploded", primitiveNum, entityNum );
  824. }
  825. /*
  826. // after expansion at least all non bevel sides should have a winding
  827. for ( i = 0; i < sides.Num(); i++ ) {
  828. side = sides[i];
  829. if ( !side->winding ) {
  830. if ( !( side->flags & SFL_BEVEL ) ) {
  831. int shit = 1;
  832. }
  833. }
  834. }
  835. */
  836. }
  837. /*
  838. ============
  839. idBrush::Copy
  840. ============
  841. */
  842. idBrush *idBrush::Copy( void ) const {
  843. int i;
  844. idBrush *b;
  845. b = new idBrush();
  846. b->entityNum = entityNum;
  847. b->primitiveNum = primitiveNum;
  848. b->contents = contents;
  849. b->windingsValid = windingsValid;
  850. b->bounds = bounds;
  851. for ( i = 0; i < sides.Num(); i++ ) {
  852. b->sides.Append( sides[i]->Copy() );
  853. }
  854. return b;
  855. }
  856. //===============================================================
  857. //
  858. // idBrushList
  859. //
  860. //===============================================================
  861. /*
  862. ============
  863. idBrushList::idBrushList
  864. ============
  865. */
  866. idBrushList::idBrushList( void ) {
  867. numBrushes = numBrushSides = 0;
  868. head = tail = NULL;
  869. }
  870. /*
  871. ============
  872. idBrushList::~idBrushList
  873. ============
  874. */
  875. idBrushList::~idBrushList( void ) {
  876. }
  877. /*
  878. ============
  879. idBrushList::GetBounds
  880. ============
  881. */
  882. idBounds idBrushList::GetBounds( void ) const {
  883. idBounds bounds;
  884. idBrush *b;
  885. bounds.Clear();
  886. for ( b = Head(); b; b = b->Next() ) {
  887. bounds += b->GetBounds();
  888. }
  889. return bounds;
  890. }
  891. /*
  892. ============
  893. idBrushList::AddToTail
  894. ============
  895. */
  896. void idBrushList::AddToTail( idBrush *brush ) {
  897. brush->next = NULL;
  898. if ( tail ) {
  899. tail->next = brush;
  900. }
  901. tail = brush;
  902. if ( !head ) {
  903. head = brush;
  904. }
  905. numBrushes++;
  906. numBrushSides += brush->sides.Num();
  907. }
  908. /*
  909. ============
  910. idBrushList::AddToTail
  911. ============
  912. */
  913. void idBrushList::AddToTail( idBrushList &list ) {
  914. idBrush *brush, *next;
  915. for ( brush = list.head; brush; brush = next ) {
  916. next = brush->next;
  917. brush->next = NULL;
  918. if ( tail ) {
  919. tail->next = brush;
  920. }
  921. tail = brush;
  922. if ( !head ) {
  923. head = brush;
  924. }
  925. numBrushes++;
  926. numBrushSides += brush->sides.Num();
  927. }
  928. list.head = list.tail = NULL;
  929. list.numBrushes = 0;
  930. }
  931. /*
  932. ============
  933. idBrushList::AddToFront
  934. ============
  935. */
  936. void idBrushList::AddToFront( idBrush *brush ) {
  937. brush->next = head;
  938. head = brush;
  939. if ( !tail ) {
  940. tail = brush;
  941. }
  942. numBrushes++;
  943. numBrushSides += brush->sides.Num();
  944. }
  945. /*
  946. ============
  947. idBrushList::AddToFront
  948. ============
  949. */
  950. void idBrushList::AddToFront( idBrushList &list ) {
  951. idBrush *brush, *next;
  952. for ( brush = list.head; brush; brush = next ) {
  953. next = brush->next;
  954. brush->next = head;
  955. head = brush;
  956. if ( !tail ) {
  957. tail = brush;
  958. }
  959. numBrushes++;
  960. numBrushSides += brush->sides.Num();
  961. }
  962. list.head = list.tail = NULL;
  963. list.numBrushes = 0;
  964. }
  965. /*
  966. ============
  967. idBrushList::Remove
  968. ============
  969. */
  970. void idBrushList::Remove( idBrush *brush ) {
  971. idBrush *b, *last;
  972. last = NULL;
  973. for ( b = head; b; b = b->next ) {
  974. if ( b == brush ) {
  975. if ( last ) {
  976. last->next = b->next;
  977. }
  978. else {
  979. head = b->next;
  980. }
  981. if ( b == tail ) {
  982. tail = last;
  983. }
  984. numBrushes--;
  985. numBrushSides -= brush->sides.Num();
  986. return;
  987. }
  988. last = b;
  989. }
  990. }
  991. /*
  992. ============
  993. idBrushList::Delete
  994. ============
  995. */
  996. void idBrushList::Delete( idBrush *brush ) {
  997. idBrush *b, *last;
  998. last = NULL;
  999. for ( b = head; b; b = b->next ) {
  1000. if ( b == brush ) {
  1001. if ( last ) {
  1002. last->next = b->next;
  1003. }
  1004. else {
  1005. head = b->next;
  1006. }
  1007. if ( b == tail ) {
  1008. tail = last;
  1009. }
  1010. numBrushes--;
  1011. numBrushSides -= b->sides.Num();
  1012. delete b;
  1013. return;
  1014. }
  1015. last = b;
  1016. }
  1017. }
  1018. /*
  1019. ============
  1020. idBrushList::Copy
  1021. ============
  1022. */
  1023. idBrushList *idBrushList::Copy( void ) const {
  1024. idBrush *brush;
  1025. idBrushList *list;
  1026. list = new idBrushList;
  1027. for ( brush = head; brush; brush = brush->next ) {
  1028. list->AddToTail( brush->Copy() );
  1029. }
  1030. return list;
  1031. }
  1032. /*
  1033. ============
  1034. idBrushList::Free
  1035. ============
  1036. */
  1037. void idBrushList::Free( void ) {
  1038. idBrush *brush, *next;
  1039. for ( brush = head; brush; brush = next ) {
  1040. next = brush->next;
  1041. delete brush;
  1042. }
  1043. head = tail = NULL;
  1044. numBrushes = numBrushSides = 0;
  1045. }
  1046. /*
  1047. ============
  1048. idBrushList::Split
  1049. ============
  1050. */
  1051. void idBrushList::Split( const idPlane &plane, int planeNum, idBrushList &frontList, idBrushList &backList, bool useBrushSavedPlaneSide ) {
  1052. idBrush *b, *front, *back;
  1053. frontList.Clear();
  1054. backList.Clear();
  1055. if ( !useBrushSavedPlaneSide ) {
  1056. for ( b = head; b; b = b->next ) {
  1057. b->Split( plane, planeNum, &front, &back );
  1058. if ( front ) {
  1059. frontList.AddToTail( front );
  1060. }
  1061. if ( back ) {
  1062. backList.AddToTail( back );
  1063. }
  1064. }
  1065. return;
  1066. }
  1067. for ( b = head; b; b = b->next ) {
  1068. if ( b->savedPlaneSide & BRUSH_PLANESIDE_BOTH ) {
  1069. b->Split( plane, planeNum, &front, &back );
  1070. if ( front ) {
  1071. frontList.AddToTail( front );
  1072. }
  1073. if ( back ) {
  1074. backList.AddToTail( back );
  1075. }
  1076. }
  1077. else if ( b->savedPlaneSide & BRUSH_PLANESIDE_FRONT ) {
  1078. frontList.AddToTail( b->Copy() );
  1079. }
  1080. else {
  1081. backList.AddToTail( b->Copy() );
  1082. }
  1083. }
  1084. }
  1085. /*
  1086. ============
  1087. idBrushList::Chop
  1088. ============
  1089. */
  1090. void idBrushList::Chop( bool (*ChopAllowed)( idBrush *b1, idBrush *b2 ) ) {
  1091. idBrush *b1, *b2, *next;
  1092. idBrushList sub1, sub2, keep;
  1093. int i, j, c1, c2;
  1094. idPlaneSet planeList;
  1095. #ifdef OUTPUT_CHOP_STATS
  1096. common->Printf( "[Brush CSG]\n");
  1097. common->Printf( "%6d original brushes\n", this->Num() );
  1098. #endif
  1099. CreatePlaneList( planeList );
  1100. for ( b1 = this->Head(); b1; b1 = this->Head() ) {
  1101. for ( b2 = b1->next; b2; b2 = next ) {
  1102. next = b2->next;
  1103. for ( i = 0; i < 3; i++ ) {
  1104. if ( b1->bounds[0][i] >= b2->bounds[1][i] ) {
  1105. break;
  1106. }
  1107. if ( b1->bounds[1][i] <= b2->bounds[0][i] ) {
  1108. break;
  1109. }
  1110. }
  1111. if ( i < 3 ) {
  1112. continue;
  1113. }
  1114. for ( i = 0; i < b1->GetNumSides(); i++ ) {
  1115. for ( j = 0; j < b2->GetNumSides(); j++ ) {
  1116. if ( b1->GetSide(i)->GetPlaneNum() == ( b2->GetSide(j)->GetPlaneNum() ^ 1 ) ) {
  1117. // opposite planes, so not touching
  1118. break;
  1119. }
  1120. }
  1121. if ( j < b2->GetNumSides() ) {
  1122. break;
  1123. }
  1124. }
  1125. if ( i < b1->GetNumSides() ) {
  1126. continue;
  1127. }
  1128. sub1.Clear();
  1129. sub2.Clear();
  1130. c1 = 999999;
  1131. c2 = 999999;
  1132. // if b2 may chop up b1
  1133. if ( !ChopAllowed || ChopAllowed( b2, b1 ) ) {
  1134. if ( !b1->Subtract( b2, sub1 ) ) {
  1135. // didn't really intersect
  1136. continue;
  1137. }
  1138. if ( sub1.IsEmpty() ) {
  1139. // b1 is swallowed by b2
  1140. this->Delete( b1 );
  1141. break;
  1142. }
  1143. c1 = sub1.Num();
  1144. }
  1145. // if b1 may chop up b2
  1146. if ( !ChopAllowed || ChopAllowed( b1, b2 ) ) {
  1147. if ( !b2->Subtract( b1, sub2 ) ) {
  1148. // didn't really intersect
  1149. continue;
  1150. }
  1151. if ( sub2.IsEmpty() ) {
  1152. // b2 is swallowed by b1
  1153. sub1.Free();
  1154. this->Delete( b2 );
  1155. continue;
  1156. }
  1157. c2 = sub2.Num();
  1158. }
  1159. if ( sub1.IsEmpty() && sub2.IsEmpty() ) {
  1160. continue;
  1161. }
  1162. // don't allow too much fragmentation
  1163. if ( c1 > 2 && c2 > 2 ) {
  1164. sub1.Free();
  1165. sub2.Free();
  1166. continue;
  1167. }
  1168. if ( c1 < c2 ) {
  1169. sub2.Free();
  1170. this->AddToTail( sub1 );
  1171. this->Delete( b1 );
  1172. break;
  1173. }
  1174. else {
  1175. sub1.Free();
  1176. this->AddToTail( sub2 );
  1177. this->Delete( b2 );
  1178. continue;
  1179. }
  1180. }
  1181. if ( !b2 ) {
  1182. // b1 is no longer intersecting anything, so keep it
  1183. this->Remove( b1 );
  1184. keep.AddToTail( b1 );
  1185. #ifdef OUTPUT_CHOP_STATS
  1186. DisplayRealTimeString( "\r%6d", keep.numBrushes );
  1187. #endif
  1188. }
  1189. }
  1190. *this = keep;
  1191. #ifdef OUTPUT_CHOP_STATS
  1192. common->Printf( "\r%6d output brushes\n", Num() );
  1193. #endif
  1194. }
  1195. /*
  1196. ============
  1197. idBrushList::Merge
  1198. ============
  1199. */
  1200. void idBrushList::Merge( bool (*MergeAllowed)( idBrush *b1, idBrush *b2 ) ) {
  1201. idPlaneSet planeList;
  1202. idBrush *b1, *b2, *nextb2;
  1203. int numMerges;
  1204. common->Printf( "[Brush Merge]\n");
  1205. common->Printf( "%6d original brushes\n", Num() );
  1206. CreatePlaneList( planeList );
  1207. numMerges = 0;
  1208. for ( b1 = Head(); b1; b1 = b1->next ) {
  1209. for ( b2 = Head(); b2; b2 = nextb2 ) {
  1210. nextb2 = b2->Next();
  1211. if ( b2 == b1 ) {
  1212. continue;
  1213. }
  1214. if ( MergeAllowed && !MergeAllowed( b1, b2 ) ) {
  1215. continue;
  1216. }
  1217. if ( b1->TryMerge( b2, planeList ) ) {
  1218. Delete( b2 );
  1219. DisplayRealTimeString( "\r%6d", ++numMerges );
  1220. nextb2 = Head();
  1221. }
  1222. }
  1223. }
  1224. common->Printf( "\r%6d brushes merged\n", numMerges );
  1225. }
  1226. /*
  1227. ============
  1228. idBrushList::SetFlagOnFacingBrushSides
  1229. ============
  1230. */
  1231. void idBrushList::SetFlagOnFacingBrushSides( const idPlane &plane, int flag ) {
  1232. int i;
  1233. idBrush *b;
  1234. const idWinding *w;
  1235. for ( b = head; b; b = b->next ) {
  1236. if ( idMath::Fabs( b->GetBounds().PlaneDistance( plane ) ) > 0.1f ) {
  1237. continue;
  1238. }
  1239. for ( i = 0; i < b->GetNumSides(); i++ ) {
  1240. w = b->GetSide(i)->GetWinding();
  1241. if ( !w ) {
  1242. if ( b->GetSide(i)->GetPlane().Compare( plane, BRUSH_PLANE_NORMAL_EPSILON, BRUSH_PLANE_DIST_EPSILON ) ) {
  1243. b->GetSide(i)->SetFlag( flag );
  1244. }
  1245. continue;
  1246. }
  1247. if ( w->PlaneSide( plane ) == SIDE_ON ) {
  1248. b->GetSide(i)->SetFlag( flag );
  1249. }
  1250. }
  1251. }
  1252. }
  1253. /*
  1254. ============
  1255. idBrushList::CreatePlaneList
  1256. ============
  1257. */
  1258. void idBrushList::CreatePlaneList( idPlaneSet &planeList ) const {
  1259. int i;
  1260. idBrush *b;
  1261. idBrushSide *side;
  1262. planeList.Resize( 512, 128 );
  1263. for ( b = Head(); b; b = b->Next() ) {
  1264. for ( i = 0; i < b->GetNumSides(); i++ ) {
  1265. side = b->GetSide( i );
  1266. side->SetPlaneNum( planeList.FindPlane( side->GetPlane(), BRUSH_PLANE_NORMAL_EPSILON, BRUSH_PLANE_DIST_EPSILON ) );
  1267. }
  1268. }
  1269. }
  1270. /*
  1271. ============
  1272. idBrushList::CreatePlaneList
  1273. ============
  1274. */
  1275. void idBrushList::WriteBrushMap( const idStr &fileName, const idStr &ext ) const {
  1276. idBrushMap *map;
  1277. map = new idBrushMap( fileName, ext );
  1278. map->WriteBrushList( *this );
  1279. delete map;
  1280. }
  1281. //===============================================================
  1282. //
  1283. // idBrushMap
  1284. //
  1285. //===============================================================
  1286. /*
  1287. ============
  1288. idBrushMap::idBrushMap
  1289. ============
  1290. */
  1291. idBrushMap::idBrushMap( const idStr &fileName, const idStr &ext ) {
  1292. idStr qpath;
  1293. qpath = fileName;
  1294. qpath.StripFileExtension();
  1295. qpath += ext;
  1296. qpath.SetFileExtension( "map" );
  1297. common->Printf( "writing %s...\n", qpath.c_str() );
  1298. fp = fileSystem->OpenFileWrite( qpath, "fs_devpath" );
  1299. if ( !fp ) {
  1300. common->Error( "Couldn't open %s\n", qpath.c_str() );
  1301. return;
  1302. }
  1303. texture = "textures/washroom/btile01";
  1304. fp->WriteFloatString( "Version %1.2f\n", (float) CURRENT_MAP_VERSION );
  1305. fp->WriteFloatString( "{\n" );
  1306. fp->WriteFloatString( "\"classname\" \"worldspawn\"\n" );
  1307. brushCount = 0;
  1308. }
  1309. /*
  1310. ============
  1311. idBrushMap::~idBrushMap
  1312. ============
  1313. */
  1314. idBrushMap::~idBrushMap( void ) {
  1315. if ( !fp ) {
  1316. return;
  1317. }
  1318. fp->WriteFloatString( "}\n" );
  1319. fileSystem->CloseFile( fp );
  1320. }
  1321. /*
  1322. ============
  1323. idBrushMap::WriteBrush
  1324. ============
  1325. */
  1326. void idBrushMap::WriteBrush( const idBrush *brush ) {
  1327. int i;
  1328. idBrushSide *side;
  1329. if ( !fp ) {
  1330. return;
  1331. }
  1332. fp->WriteFloatString( "// primitive %d\n{\nbrushDef3\n{\n", brushCount++ );
  1333. for ( i = 0; i < brush->GetNumSides(); i++ ) {
  1334. side = brush->GetSide( i );
  1335. fp->WriteFloatString( " ( %f %f %f %f ) ", side->GetPlane()[0], side->GetPlane()[1], side->GetPlane()[2], -side->GetPlane().Dist() );
  1336. fp->WriteFloatString( "( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) %s 0 0 0\n", texture.c_str() );
  1337. }
  1338. fp->WriteFloatString( "}\n}\n" );
  1339. }
  1340. /*
  1341. ============
  1342. idBrushMap::WriteBrushList
  1343. ============
  1344. */
  1345. void idBrushMap::WriteBrushList( const idBrushList &brushList ) {
  1346. idBrush *b;
  1347. if ( !fp ) {
  1348. return;
  1349. }
  1350. for ( b = brushList.Head(); b; b = b->Next() ) {
  1351. WriteBrush( b );
  1352. }
  1353. }