BSP.cpp 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316
  1. /* Copyright (c) 2002-2012 Croteam Ltd.
  2. This program is free software; you can redistribute it and/or modify
  3. it under the terms of version 2 of the GNU General Public License as published by
  4. the Free Software Foundation
  5. This program is distributed in the hope that it will be useful,
  6. but WITHOUT ANY WARRANTY; without even the implied warranty of
  7. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  8. GNU General Public License for more details.
  9. You should have received a copy of the GNU General Public License along
  10. with this program; if not, write to the Free Software Foundation, Inc.,
  11. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
  12. #include "stdh.h"
  13. #include <Engine/Templates/BSP.h>
  14. #include <Engine/Templates/BSP_internal.h>
  15. #include <Engine/Base/Stream.h>
  16. #include <Engine/Math/Vector.h>
  17. #include <Engine/Math/Plane.h>
  18. #include <Engine/Math/OBBox.h>
  19. #include <Engine/Math/Functions.h>
  20. #include <Engine/Templates/StaticStackArray.cpp>
  21. #include <Engine/Templates/DynamicArray.cpp>
  22. // epsilon value used for BSP cutting
  23. //#define BSP_EPSILON ((Type) 0.015625) // 1/2^6 ~= 1.5 cm
  24. #define BSP_EPSILON Type((1.0/65536.0)*4*mth_fCSGEpsilon) // 1/2^16
  25. //#define BSP_EPSILON Type(0.00390625) // 1/2^8
  26. //#define EPSILON (1.0f/8388608.0f) // 1/2^23
  27. //#define EPSILON 0.0009765625f // 1/2^10
  28. //#define EPSILON 0.03125f // 1/2^5
  29. //#define EPSILON 0.00390625f // 1/2^8
  30. template <class Type>
  31. inline BOOL EpsilonEq(const Type &a, const Type &b) { return Abs(a-b)<=BSP_EPSILON; };
  32. template <class Type>
  33. inline BOOL EpsilonNe(const Type &a, const Type &b) { return Abs(a-b)> BSP_EPSILON; };
  34. /////////////////////////////////////////////////////////////////////
  35. // BSP vertex
  36. /*
  37. * Assignment operator with coordinates only.
  38. */
  39. template<class Type, int iDimensions>
  40. BSPVertex<Type, iDimensions> &BSPVertex<Type, iDimensions>::operator=(const Vector<Type, iDimensions> &vCoordinates)
  41. {
  42. *(Vector<Type, iDimensions> *)this = vCoordinates;
  43. return *this;
  44. }
  45. /////////////////////////////////////////////////////////////////////
  46. // BSP vertex container
  47. /*
  48. * Default constructor.
  49. */
  50. template<class Type, int iDimensions>
  51. BSPVertexContainer<Type, iDimensions>::BSPVertexContainer(void)
  52. {
  53. }
  54. template<class Type, int iDimensions>
  55. void BSPVertexContainer<Type, iDimensions>::AddVertex(const Vector<Type, iDimensions> &vPoint)
  56. {
  57. bvc_aVertices.Push() = vPoint;
  58. }
  59. /*
  60. * Initialize for a direction.
  61. */
  62. template<class Type, int iDimensions>
  63. void BSPVertexContainer<Type, iDimensions>::Initialize(const Vector<Type, iDimensions> &vDirection)
  64. {
  65. bvc_vDirection = vDirection;
  66. // init array of vertices
  67. bvc_aVertices.SetAllocationStep(32);
  68. // find largest axis of direction vector
  69. INDEX iMaxAxis = 0;
  70. Type tMaxAxis = (Type)0;//vDirection(1);
  71. for( INDEX iAxis=1; iAxis<=iDimensions; iAxis++) {
  72. if( Abs(vDirection(iAxis)) > Abs(tMaxAxis) ) {
  73. tMaxAxis = vDirection(iAxis);
  74. iMaxAxis = iAxis;
  75. }
  76. }
  77. /* This assert would seem natural here, but it is not possible because of parallel planes!
  78. // must be greater or equal than minimal max axis of any normalized vector in that space
  79. ASSERT( Abs(tMaxAxis) > (1.0/sqrt(double(iDimensions))-0.01) );
  80. */
  81. // remember that axis index and sign for sorting
  82. bvc_iMaxAxis = iMaxAxis;
  83. bvc_tMaxAxisSign = Sgn(tMaxAxis);
  84. }
  85. /*
  86. * Unnitialize.
  87. */
  88. template<class Type, int iDimensions>
  89. void BSPVertexContainer<Type, iDimensions>::Uninitialize(void)
  90. {
  91. // delete array of vertices
  92. bvc_aVertices.Delete();
  93. // destroy axis index and sign
  94. bvc_iMaxAxis = -1;
  95. bvc_tMaxAxisSign = (Type)0;
  96. }
  97. static INDEX qsort_iCompareAxis;
  98. template<class Type, int iDimensions>
  99. class CVertexComparator {
  100. public:
  101. /*
  102. * Compare two vertices.
  103. */
  104. static inline int CompareVertices(const Vector<Type, iDimensions> &vx0, const Vector<Type, iDimensions> &vx1, INDEX iAxis)
  105. {
  106. if (vx0(iAxis)<vx1(iAxis)) return -1;
  107. else if (vx0(iAxis)>vx1(iAxis)) return 1;
  108. else return 0;
  109. }
  110. /*
  111. * Compare two vertices for quick-sort.
  112. */
  113. static int qsort_CompareVertices_plus( const void *pvVertex0, const void *pvVertex1)
  114. {
  115. BSPVertex<Type, iDimensions> &vx0 = *(BSPVertex<Type, iDimensions> *)pvVertex0;
  116. BSPVertex<Type, iDimensions> &vx1 = *(BSPVertex<Type, iDimensions> *)pvVertex1;
  117. return +CompareVertices(vx0, vx1, qsort_iCompareAxis);
  118. }
  119. static int qsort_CompareVertices_minus( const void *pvVertex0, const void *pvVertex1)
  120. {
  121. BSPVertex<Type, iDimensions> &vx0 = *(BSPVertex<Type, iDimensions> *)pvVertex0;
  122. BSPVertex<Type, iDimensions> &vx1 = *(BSPVertex<Type, iDimensions> *)pvVertex1;
  123. return -CompareVertices(vx0, vx1, qsort_iCompareAxis);
  124. }
  125. };
  126. /*
  127. * Sort vertices in this container along the largest axis of container direction.
  128. */
  129. template<class Type, int iDimensions>
  130. void BSPVertexContainer<Type, iDimensions>::Sort(void)
  131. {
  132. // if there are no vertices, or the container is not line
  133. if (bvc_aVertices.Count()==0 || IsPlannar()) {
  134. // do not attempt to sort
  135. return;
  136. }
  137. // sort by max. axis
  138. qsort_iCompareAxis = bvc_iMaxAxis;
  139. // if the sign of axis is positive
  140. if (bvc_tMaxAxisSign>0) {
  141. // sort them normally
  142. if (bvc_aVertices.Count()>0) {
  143. qsort(&bvc_aVertices[0], bvc_aVertices.Count(), sizeof(BSPVertex<Type, iDimensions>),
  144. CVertexComparator<Type, iDimensions>::qsort_CompareVertices_plus);
  145. }
  146. // if it is negative
  147. } else {
  148. // sort them inversely
  149. if (bvc_aVertices.Count()>0) {
  150. qsort(&bvc_aVertices[0], bvc_aVertices.Count(), sizeof(BSPVertex<Type, iDimensions>),
  151. CVertexComparator<Type, iDimensions>::qsort_CompareVertices_minus);
  152. }
  153. }
  154. }
  155. /*
  156. * Elliminate paired vertices.
  157. */
  158. template<class Type, int iDimensions>
  159. void BSPVertexContainer<Type, iDimensions>::ElliminatePairedVertices(void)
  160. {
  161. // if there are no vertices, or the container is not line
  162. if (bvc_aVertices.Count()==0 || IsPlannar()) {
  163. // do not attempt to sort
  164. return;
  165. }
  166. // initially, last vertices are far away
  167. Type tLastInside; tLastInside = (Type)32000;
  168. BSPVertex<Type, iDimensions> *pbvxLastInside = NULL;
  169. // for all vertices in container
  170. for (INDEX iVertex=0; iVertex<bvc_aVertices.Count(); iVertex++) {
  171. BSPVertex<Type, iDimensions> &bvx = bvc_aVertices[iVertex]; // reference to this vertex
  172. Type t = bvx(bvc_iMaxAxis); // coordinate along max. axis
  173. // if last inside vertex is next to this one
  174. if ( EpsilonEq(t, tLastInside) ) {
  175. // last vertex is far away
  176. tLastInside = (Type)32000;
  177. IFDEBUG(pbvxLastInside = NULL);
  178. // otherwise
  179. } else {
  180. // make this last inside vertex
  181. tLastInside = t;
  182. pbvxLastInside = &bvx;
  183. }
  184. }
  185. }
  186. /*
  187. * Create edges from vertices in one container -- must be sorted before.
  188. */
  189. template<class Type, int iDimensions>
  190. void BSPVertexContainer<Type, iDimensions>::CreateEdges(CDynamicArray<BSPEdge<Type, iDimensions> > &abed, ULONG ulEdgeTag)
  191. {
  192. // if there are no vertices, or the container is not line
  193. if (bvc_aVertices.Count()==0 || IsPlannar()) {
  194. // do not attempt to sort
  195. return;
  196. }
  197. // initially, edge is inactive
  198. BOOL bActive = FALSE;
  199. BSPEdge<Type, iDimensions> *pbed = NULL;
  200. // for all vertices in container
  201. for (INDEX iVertex=0; iVertex<bvc_aVertices.Count(); iVertex++) {
  202. BSPVertex<Type, iDimensions> &bvx = bvc_aVertices[iVertex]; // reference to this vertex
  203. // if edge is inactive
  204. if (!bActive) {
  205. // create new edge
  206. pbed = abed.New();
  207. pbed->bed_ulEdgeTag = ulEdgeTag;
  208. // set start vertex
  209. pbed->bed_vVertex0 = bvx;
  210. } else {
  211. // set end vertex
  212. pbed->bed_vVertex1 = bvx;
  213. // trash edge pointer
  214. IFDEBUG(pbed = NULL);
  215. }
  216. // toggle edge
  217. bActive = !bActive;
  218. }
  219. }
  220. /////////////////////////////////////////////////////////////////////
  221. // BSP edge
  222. /*
  223. * Constructor with two vectors.
  224. */
  225. template<class Type, int iDimensions>
  226. BSPEdge<Type, iDimensions>::BSPEdge(const Vector<Type, iDimensions> &vVertex0, const Vector<Type, iDimensions> &vVertex1, ULONG ulTag)
  227. : bed_vVertex0(vVertex0)
  228. , bed_vVertex1(vVertex1)
  229. , bed_ulEdgeTag(ulTag)
  230. {}
  231. // remove all edges marked for removal
  232. template<class Type, int iDimensions>
  233. void BSPEdge<Type, iDimensions>::RemoveMarkedBSPEdges(CDynamicArray<BSPEdge<Type, iDimensions> > &abed)
  234. {
  235. typedef BSPEdge<Type, iDimensions> edge_t; // local declaration, to fix macro expansion in FOREACHINDYNAMICARRAY
  236. // conut edges left
  237. INDEX ctEdgesLeft = 0;
  238. {FOREACHINDYNAMICARRAY(abed, edge_t, itbed) {
  239. if (itbed->bed_ulEdgeTag != 0) {
  240. ctEdgesLeft++;
  241. }
  242. }}
  243. // make a copy of array without removed edges
  244. CDynamicArray<BSPEdge<Type, iDimensions> > abed2;
  245. abed2.New(ctEdgesLeft);
  246. abed2.Lock();
  247. INDEX iedNew = 0;
  248. {FOREACHINDYNAMICARRAY(abed, edge_t, itbed) {
  249. edge_t &bed = *itbed;
  250. if (bed.bed_ulEdgeTag != 0) {
  251. abed2[iedNew] = bed;
  252. iedNew++;
  253. }
  254. }}
  255. abed2.Unlock();
  256. // use that copy instead the original array
  257. abed.Clear();
  258. abed.MoveArray(abed2);
  259. }
  260. // optimize a polygon made out of BSP edges using tag information
  261. template<class Type, int iDimensions>
  262. void BSPEdge<Type, iDimensions>::OptimizeBSPEdges(CDynamicArray<BSPEdge<Type, iDimensions> > &abed)
  263. {
  264. typedef BSPEdge<Type, iDimensions> edge_t; // local declaration, to fix macro expansion in FOREACHINDYNAMICARRAY
  265. // if there are no edges
  266. if (abed.Count()==0) {
  267. // do nothing
  268. return;
  269. }
  270. BOOL bSomeJoined;
  271. // repeat
  272. do {
  273. bSomeJoined = FALSE;
  274. // for each edge
  275. {FOREACHINDYNAMICARRAY(abed, edge_t, itbed1) {
  276. edge_t &bed1 = *itbed1;
  277. // if it is already marked
  278. if (bed1.bed_ulEdgeTag == 0) {
  279. // skip it
  280. continue;
  281. }
  282. // if it is dummy edge
  283. if (bed1.bed_vVertex0==bed1.bed_vVertex1) {
  284. // mark it for removal
  285. bSomeJoined = TRUE;
  286. bed1.bed_ulEdgeTag = 0;
  287. // skip it
  288. continue;
  289. }
  290. // for each other edge
  291. {FOREACHINDYNAMICARRAY(abed, edge_t, itbed2) {
  292. edge_t &bed2 = *itbed2;
  293. if (&bed1==&bed2) {
  294. continue;
  295. }
  296. // if it is already marked
  297. if (bed2.bed_ulEdgeTag == 0) {
  298. // skip it
  299. continue;
  300. }
  301. // if they originate from same edge (plane)
  302. if (bed1.bed_ulEdgeTag == bed2.bed_ulEdgeTag) {
  303. // if they are complemented
  304. if (bed1.bed_vVertex0==bed2.bed_vVertex1 && bed1.bed_vVertex1==bed2.bed_vVertex0) {
  305. // marked them both
  306. bSomeJoined = TRUE;
  307. bed1.bed_ulEdgeTag = 0;
  308. bed2.bed_ulEdgeTag = 0;
  309. // skip them both
  310. break;
  311. }
  312. // if second one continues after first one
  313. if (bed1.bed_vVertex1==bed2.bed_vVertex0) {
  314. // extend end of first edge to the end of second one
  315. bed1.bed_vVertex1=bed2.bed_vVertex1;
  316. bSomeJoined = TRUE;
  317. // marked second edge
  318. bed2.bed_ulEdgeTag = 0;
  319. // if second one continues before first one
  320. } else if (bed1.bed_vVertex0==bed2.bed_vVertex1) {
  321. // extend start of first edge to the start of second one
  322. bed1.bed_vVertex0=bed2.bed_vVertex0;
  323. bSomeJoined = TRUE;
  324. // marked second edge
  325. bed2.bed_ulEdgeTag = 0;
  326. }
  327. }
  328. }}
  329. }}
  330. // while some edges can be joined
  331. } while(bSomeJoined);
  332. // remove all marked edges
  333. RemoveMarkedBSPEdges(abed);
  334. }
  335. /////////////////////////////////////////////////////////////////////
  336. // BSP polygon
  337. /*
  338. * Add an edge to the polygon.
  339. */
  340. template<class Type, int iDimensions>
  341. inline void BSPPolygon<Type, iDimensions>::AddEdge(const Vector<Type, iDimensions> &vPoint0, const Vector<Type, iDimensions> &vPoint1, ULONG ulTag)
  342. {
  343. *bpo_abedPolygonEdges.New() = BSPEdge<Type, iDimensions>(vPoint0, vPoint1, ulTag);
  344. }
  345. /////////////////////////////////////////////////////////////////////
  346. // BSP node
  347. /*
  348. * Recursive destructor.
  349. */
  350. template<class Type, int iDimensions>
  351. void BSPNode<Type, iDimensions>::DeleteBSPNodeRecursively(void)
  352. {
  353. // delete sub-trees first, before deleting this node
  354. if (bn_pbnFront!=NULL) {
  355. bn_pbnFront->DeleteBSPNodeRecursively();
  356. }
  357. if (bn_pbnBack!=NULL) {
  358. bn_pbnBack->DeleteBSPNodeRecursively();
  359. }
  360. delete this;
  361. }
  362. /*
  363. * Constructor for a leaf node.
  364. */
  365. template<class Type, int iDimensions>
  366. BSPNode<Type, iDimensions>::BSPNode(enum BSPNodeLocation bnl)
  367. : bn_bnlLocation(bnl)
  368. , bn_pbnFront(NULL)
  369. , bn_pbnBack(NULL)
  370. {
  371. ASSERT(bnl == BNL_INSIDE || bnl == BNL_OUTSIDE);
  372. }
  373. /*
  374. * Constructor for a branch node.
  375. */
  376. template<class Type, int iDimensions>
  377. BSPNode<Type, iDimensions>::BSPNode(const Plane<Type, iDimensions> &plSplitPlane, ULONG ulPlaneTag,
  378. BSPNode<Type, iDimensions> &bnFront, BSPNode<Type, iDimensions> &bnBack)
  379. : Plane<Type, iDimensions>(plSplitPlane)
  380. , bn_pbnFront(&bnFront)
  381. , bn_pbnBack(&bnBack)
  382. , bn_bnlLocation(BNL_BRANCH)
  383. , bn_ulPlaneTag(ulPlaneTag)
  384. {
  385. }
  386. /*
  387. * Constructor for cloning a bsp (sub)tree.
  388. */
  389. template<class Type, int iDimensions>
  390. BSPNode<Type, iDimensions>::BSPNode(BSPNode<Type, iDimensions> &bnRoot)
  391. : Plane<Type, iDimensions>(bnRoot) // copy the plane
  392. , bn_bnlLocation(bnRoot.bn_bnlLocation) // copy the location
  393. , bn_ulPlaneTag(bnRoot.bn_ulPlaneTag) // copy the plane tag
  394. {
  395. // if this has a front child
  396. if (bnRoot.bn_pbnFront != NULL) {
  397. // clone front sub tree
  398. bn_pbnFront = new BSPNode<Type, iDimensions>(*bnRoot.bn_pbnFront);
  399. // otherwise
  400. } else {
  401. // no front sub tree
  402. bn_pbnFront = NULL;
  403. }
  404. // if this has a back child
  405. if (bnRoot.bn_pbnBack != NULL) {
  406. // clone back sub tree
  407. bn_pbnBack = new BSPNode<Type, iDimensions>(*bnRoot.bn_pbnBack);
  408. // otherwise
  409. } else {
  410. // no back sub tree
  411. bn_pbnBack = NULL;
  412. }
  413. }
  414. /* Test if a sphere is inside, outside, or intersecting. (Just a trivial rejection test) */
  415. template<class Type, int iDimensions>
  416. FLOAT BSPNode<Type, iDimensions>::TestSphere(const Vector<Type, iDimensions> &vSphereCenter, Type tSphereRadius) const
  417. {
  418. // if this is an inside node
  419. if (bn_bnlLocation == BNL_INSIDE) {
  420. // it is inside
  421. return 1;
  422. // if this is an outside node
  423. } else if (bn_bnlLocation == BNL_OUTSIDE) {
  424. // it is outside
  425. return -1;
  426. // if this is a branch
  427. } else {
  428. ASSERT(bn_bnlLocation == BNL_BRANCH);
  429. // test the sphere against the split plane
  430. Type tCenterDistance = PointDistance(vSphereCenter);
  431. // if the sphere is in front of the plane
  432. if (tCenterDistance > +tSphereRadius) {
  433. // recurse down the front node
  434. return bn_pbnFront->TestSphere(vSphereCenter, tSphereRadius);
  435. // if the sphere is behind the plane
  436. } else if (tCenterDistance < -tSphereRadius) {
  437. // recurse down the back node
  438. return bn_pbnBack->TestSphere(vSphereCenter, tSphereRadius);
  439. // if the sphere is split by the plane
  440. } else {
  441. // if front node touches
  442. FLOAT fFront = bn_pbnFront->TestSphere(vSphereCenter, tSphereRadius);
  443. if (fFront==0) {
  444. // it touches
  445. return 0;
  446. }
  447. // if back node touches
  448. FLOAT fBack = bn_pbnBack->TestSphere(vSphereCenter, tSphereRadius);
  449. if (fBack==0) {
  450. // it touches
  451. return 0;
  452. }
  453. // if front and back have same classification
  454. if (fFront==fBack) {
  455. // return it
  456. return fFront;
  457. // if front and back have different classification
  458. } else {
  459. // it touches
  460. return 0;
  461. }
  462. }
  463. }
  464. }
  465. /* Test if a box is inside, outside, or intersecting. (Just a trivial rejection test) */
  466. template<class Type, int iDimensions>
  467. FLOAT BSPNode<Type, iDimensions>::TestBox(const OBBox<Type> &box) const
  468. {
  469. // if this is an inside node
  470. if (bn_bnlLocation == BNL_INSIDE) {
  471. // it is inside
  472. return 1;
  473. // if this is an outside node
  474. } else if (bn_bnlLocation == BNL_OUTSIDE) {
  475. // it is outside
  476. return -1;
  477. // if this is a branch
  478. } else {
  479. ASSERT(bn_bnlLocation == BNL_BRANCH);
  480. // test the box against the split plane
  481. Type tTest = box.TestAgainstPlane(*this);
  482. // if the sphere is in front of the plane
  483. if (tTest>0) {
  484. // recurse down the front node
  485. return bn_pbnFront->TestBox(box);
  486. // if the sphere is behind the plane
  487. } else if (tTest<0) {
  488. // recurse down the back node
  489. return bn_pbnBack->TestBox(box);
  490. // if the sphere is split by the plane
  491. } else {
  492. // if front node touches
  493. FLOAT fFront = bn_pbnFront->TestBox(box);
  494. if (fFront==0) {
  495. // it touches
  496. return 0;
  497. }
  498. // if back node touches
  499. FLOAT fBack = bn_pbnBack->TestBox(box);
  500. if (fBack==0) {
  501. // it touches
  502. return 0;
  503. }
  504. // if front and back have same classification
  505. if (fFront==fBack) {
  506. // return it
  507. return fFront;
  508. // if front and back have different classification
  509. } else {
  510. // it touches
  511. return 0;
  512. }
  513. }
  514. }
  515. }
  516. // find minimum/maximum parameters of points on a line that are inside - recursive
  517. template<class Type, int iDimensions>
  518. void BSPNode<Type, iDimensions>::FindLineMinMax(
  519. BSPLine<Type, iDimensions> &bl,
  520. const Vector<Type, iDimensions> &v0,
  521. const Vector<Type, iDimensions> &v1,
  522. Type t0, Type t1)
  523. {
  524. // if this is an inside node
  525. if (bn_bnlLocation == BNL_INSIDE) {
  526. // just update min/max
  527. bl.bl_tMin = Min(bl.bl_tMin, t0);
  528. bl.bl_tMax = Max(bl.bl_tMax, t1);
  529. return;
  530. // if this is an outside node
  531. } else if (bn_bnlLocation == BNL_OUTSIDE) {
  532. // do nothing
  533. return;
  534. // if this is a branch
  535. } else {
  536. ASSERT(bn_bnlLocation == BNL_BRANCH);
  537. // test the points against the split plane
  538. Type tD0 = PointDistance(v0);
  539. Type tD1 = PointDistance(v1);
  540. // if both are front
  541. if (tD0>=0 && tD1>=0) {
  542. // recurse down the front node
  543. bn_pbnFront->FindLineMinMax(bl, v0, v1, t0, t1);
  544. return;
  545. // if both are back
  546. } else if (tD0<0 && tD1<0) {
  547. // recurse down the back node
  548. bn_pbnBack->FindLineMinMax(bl, v0, v1, t0, t1);
  549. return;
  550. // if on different sides
  551. } else {
  552. // find split point
  553. Type tFraction = tD0/(tD0-tD1);
  554. Vector<Type, iDimensions> vS = v0+(v1-v0)*tFraction;
  555. Type tS = t0+(t1-t0)*tFraction;
  556. // if first is front
  557. if (tD0>=0) {
  558. // recurse first part down the front node
  559. bn_pbnFront->FindLineMinMax(bl, v0, vS, t0, tS);
  560. // recurse second part down the back node
  561. bn_pbnBack->FindLineMinMax(bl, vS, v1, tS, t1);
  562. return;
  563. // if first is back
  564. } else {
  565. // recurse first part down the back node
  566. bn_pbnBack->FindLineMinMax(bl, v0, vS, t0, tS);
  567. // recurse second part down the front node
  568. bn_pbnFront->FindLineMinMax(bl, vS, v1, tS, t1);
  569. return;
  570. }
  571. }
  572. }
  573. }
  574. /////////////////////////////////////////////////////////////////////
  575. // BSP cutter
  576. /*
  577. * Constructor for splitting a polygon with a BSP tree.
  578. */
  579. template<class Type, int iDimensions>
  580. BSPCutter<Type, iDimensions>::BSPCutter(BSPPolygon<Type, iDimensions> &bpoPolygon, BSPNode<Type, iDimensions> &bnRoot)
  581. {
  582. // cut the polygon with entire tree
  583. CutPolygon(bpoPolygon, bnRoot);
  584. }
  585. /*
  586. * Destructor.
  587. */
  588. template<class Type, int iDimensions>
  589. BSPCutter<Type, iDimensions>::~BSPCutter(void)
  590. {
  591. }
  592. /*
  593. * Cut a polygon with a BSP tree.
  594. */
  595. template<class Type, int iDimensions>
  596. void BSPCutter<Type, iDimensions>::CutPolygon(BSPPolygon<Type, iDimensions> &bpoPolygon, BSPNode<Type, iDimensions> &bn)
  597. {
  598. // if the polygon has no edges
  599. if (bpoPolygon.bpo_abedPolygonEdges.Count()==0) {
  600. // skip cutting
  601. return;
  602. }
  603. // if this node is inside node
  604. if (bn.bn_bnlLocation == BNL_INSIDE) {
  605. // add entire polygon to inside part
  606. bc_abedInside.MoveArray(bpoPolygon.bpo_abedPolygonEdges);
  607. // if this node is outside node
  608. } else if (bn.bn_bnlLocation == BNL_OUTSIDE) {
  609. // add entire polygon to outside part
  610. bc_abedOutside.MoveArray(bpoPolygon.bpo_abedPolygonEdges);
  611. // if this node is a branch
  612. } else if (bn.bn_bnlLocation == BNL_BRANCH) {
  613. BSPPolygon<Type, iDimensions> bpoFront; // part of polygon in front of this splitter
  614. BSPPolygon<Type, iDimensions> bpoBack; // part of polygon behind this splitter
  615. // split the polygon with split plane of this node
  616. BOOL bOnPlane = SplitPolygon(bpoPolygon, (Plane<Type, iDimensions> &)bn, bn.bn_ulPlaneTag, bpoFront, bpoBack);
  617. // if the polygon is not on the split plane
  618. if (!bOnPlane) {
  619. // recursively split front part with front part of bsp
  620. CutPolygon(bpoFront, *bn.bn_pbnFront);
  621. // recursively split back part with back part of bsp
  622. CutPolygon(bpoBack, *bn.bn_pbnBack);
  623. // if the polygon is on the split plane
  624. } else {
  625. BSPNode<Type, iDimensions> *pbnFront; // front node (relative to the polygon orientation)
  626. BSPNode<Type, iDimensions> *pbnBack; // back node (relative to the polygon orientation)
  627. // check the direction of the polygon with the front direction of the split plane
  628. Type tDirection = (Vector<Type, iDimensions> &)bpoPolygon%(Vector<Type, iDimensions> &)bn;
  629. // if the directions are same
  630. if (tDirection > +BSP_EPSILON) {
  631. // make nodes relative to polygon same as relative to the split plane
  632. pbnFront = bn.bn_pbnFront;
  633. pbnBack = bn.bn_pbnBack;
  634. // if the directions are opposite
  635. } else if (tDirection < -BSP_EPSILON) {
  636. // make nodes relative to polygon opposite as relative to the split plane
  637. pbnFront = bn.bn_pbnBack;
  638. pbnBack = bn.bn_pbnFront;
  639. // if the directions are indeterminate
  640. } else {
  641. // that must not be
  642. ASSERT(FALSE);
  643. }
  644. // cut it with front part of bsp
  645. BSPCutter<Type, iDimensions> bcFront(bpoPolygon, *pbnFront);
  646. // there must be no on-border parts
  647. ASSERT(bcFront.bc_abedBorderInside.Count()==0 && bcFront.bc_abedBorderOutside.Count()==0);
  648. // make a polygon from parts that are inside in front part of BSP
  649. BSPPolygon<Type, iDimensions> bpoInsideFront((Plane<Type, iDimensions> &)bpoPolygon, bcFront.bc_abedInside, bpoPolygon.bpo_ulPlaneTag);
  650. // cut them with back part of bsp
  651. BSPCutter<Type, iDimensions> bcBackInsideFront(bpoInsideFront, *pbnBack);
  652. // make a polygon from parts that are outside in front part of BSP
  653. BSPPolygon<Type, iDimensions> bpoOutsideFront((Plane<Type, iDimensions> &)bpoPolygon, bcFront.bc_abedOutside, bpoPolygon.bpo_ulPlaneTag);
  654. // cut them with back part of bsp
  655. BSPCutter<Type, iDimensions> bcBackOutsideFront(bpoOutsideFront, *pbnBack);
  656. // add parts that are inside both in front and back to inside part
  657. bc_abedInside.MoveArray(bcBackInsideFront.bc_abedInside);
  658. // add parts that are outside both in front and back to outside part
  659. bc_abedOutside.MoveArray(bcBackOutsideFront.bc_abedOutside);
  660. // add parts that are inside in front and outside back to on-border-inside-part
  661. bc_abedBorderInside.MoveArray(bcBackInsideFront.bc_abedOutside);
  662. // add parts that are outside in front and inside back to on-border-outside-part
  663. bc_abedBorderOutside.MoveArray(bcBackOutsideFront.bc_abedInside);
  664. }
  665. } else {
  666. ASSERTALWAYS("Bad node type");
  667. }
  668. }
  669. /*
  670. * Split a polygon with a plane.
  671. * -- returns FALSE if polygon is laying on the plane
  672. */
  673. template<class Type, int iDimensions>
  674. BOOL BSPCutter<Type, iDimensions>::SplitPolygon(BSPPolygon<Type, iDimensions> &bpoPolygon, const Plane<Type, iDimensions> &plSplitPlane, ULONG ulPlaneTag,
  675. BSPPolygon<Type, iDimensions> &bpoFront, BSPPolygon<Type, iDimensions> &bpoBack)
  676. {
  677. (Plane<Type, iDimensions> &)bpoFront = (Plane<Type, iDimensions> &)bpoPolygon;
  678. bpoFront.bpo_ulPlaneTag = bpoPolygon.bpo_ulPlaneTag;
  679. (Plane<Type, iDimensions> &)bpoBack = (Plane<Type, iDimensions> &)bpoPolygon;
  680. bpoBack.bpo_ulPlaneTag = bpoPolygon.bpo_ulPlaneTag;
  681. // calculate the direction of split line
  682. Vector<Type, iDimensions> vSplitDirection = ((Vector<Type, iDimensions> &)plSplitPlane) * (Vector<Type, iDimensions> &)bpoPolygon;
  683. // if the polygon is parallel with the split plane
  684. if (vSplitDirection.Length() < +BSP_EPSILON) {
  685. // calculate the distance of the polygon from the split plane
  686. Type fDistance = plSplitPlane.PlaneDistance(bpoPolygon);
  687. // if the polygon is in front of plane
  688. if (fDistance > +BSP_EPSILON) {
  689. // move all edges to front array
  690. bpoFront.bpo_abedPolygonEdges.MoveArray(bpoPolygon.bpo_abedPolygonEdges);
  691. // the polygon is not on the plane
  692. return FALSE;
  693. // if the polygon is behind the plane
  694. } else if (fDistance < -BSP_EPSILON) {
  695. // move all edges to back array
  696. bpoBack.bpo_abedPolygonEdges.MoveArray(bpoPolygon.bpo_abedPolygonEdges);
  697. // the polygon is not on the plane
  698. return FALSE;
  699. // if the polygon is on the plane
  700. } else {
  701. // just return so
  702. return TRUE;
  703. }
  704. // if the polygon is not parallel with the split plane
  705. } else {
  706. // initialize front and back vertex containers
  707. BSPVertexContainer<Type, iDimensions> bvcFront, bvcBack;
  708. bvcFront.Initialize(vSplitDirection);
  709. bvcBack.Initialize(-vSplitDirection);
  710. typedef BSPEdge<Type, iDimensions> edge_t; // local declaration, to fix macro expansion in FOREACHINDYNAMICARRAY
  711. // for each edge in polygon
  712. {FOREACHINDYNAMICARRAY(bpoPolygon.bpo_abedPolygonEdges, edge_t, itbed) {
  713. // split the edge
  714. SplitEdge(itbed->bed_vVertex0, itbed->bed_vVertex1, itbed->bed_ulEdgeTag, plSplitPlane,
  715. bpoFront, bpoBack, bvcFront, bvcBack);
  716. }}
  717. // sort vertex containers
  718. bvcFront.Sort();
  719. bvcBack.Sort();
  720. // elliminate paired vertices
  721. bvcFront.ElliminatePairedVertices();
  722. bvcBack.ElliminatePairedVertices();
  723. // create more front polygon edges from front vertex container
  724. bvcFront.CreateEdges(bpoFront.bpo_abedPolygonEdges, ulPlaneTag);
  725. // create more back polygon edges from back vertex container
  726. bvcBack.CreateEdges(bpoBack.bpo_abedPolygonEdges, ulPlaneTag);
  727. // the polygon is not on the plane
  728. return FALSE;
  729. }
  730. }
  731. /*
  732. * Split an edge with a plane.
  733. */
  734. template<class Type, int iDimensions>
  735. void BSPCutter<Type, iDimensions>::SplitEdge(const Vector<Type, iDimensions> &vPoint0, const Vector<Type, iDimensions> &vPoint1, ULONG ulEdgeTag,
  736. const Plane<Type, iDimensions> &plSplitPlane,
  737. BSPPolygon<Type, iDimensions> &bpoFront, BSPPolygon<Type, iDimensions> &bpoBack,
  738. BSPVertexContainer<Type, iDimensions> &bvcFront, BSPVertexContainer<Type, iDimensions> &bvcBack)
  739. {
  740. // calculate point distances from clip plane
  741. Type tDistance0 = plSplitPlane.PointDistance(vPoint0);
  742. Type tDistance1 = plSplitPlane.PointDistance(vPoint1);
  743. /* ---- first point behind plane ---- */
  744. if (tDistance0 < -BSP_EPSILON) {
  745. // if both are back
  746. if (tDistance1 < -BSP_EPSILON) {
  747. // add the whole edge to back node
  748. bpoBack.AddEdge(vPoint0, vPoint1, ulEdgeTag);
  749. // no split points
  750. // if first is back, second front
  751. } else if (tDistance1 > +BSP_EPSILON) {
  752. // calculate intersection coordinates
  753. Vector<Type, iDimensions> vPointMid = vPoint0-(vPoint0-vPoint1)*tDistance0/(tDistance0-tDistance1);
  754. // add front part to front node
  755. bpoFront.AddEdge(vPointMid, vPoint1, ulEdgeTag);
  756. // add back part to back node
  757. bpoBack.AddEdge(vPoint0, vPointMid, ulEdgeTag);
  758. // add split point to front _and_ back part of splitter
  759. bvcFront.AddVertex(vPointMid);
  760. bvcBack.AddVertex(vPointMid);
  761. // if first is back, second on the plane
  762. } else {
  763. // add the whole edge to back node
  764. bpoBack.AddEdge(vPoint0, vPoint1, ulEdgeTag);
  765. // add second point to back part of splitter
  766. bvcBack.AddVertex(vPoint1);
  767. }
  768. /* ---- first point in front of plane ---- */
  769. } else if (tDistance0 > +BSP_EPSILON) {
  770. // if first is front, second back
  771. if (tDistance1 < -BSP_EPSILON) {
  772. // calculate intersection coordinates
  773. Vector<Type, iDimensions> vPointMid = vPoint1-(vPoint1-vPoint0)*tDistance1/(tDistance1-tDistance0);
  774. // add front part to front node
  775. bpoFront.AddEdge(vPoint0, vPointMid, ulEdgeTag);
  776. // add back part to back node
  777. bpoBack.AddEdge(vPointMid, vPoint1, ulEdgeTag);
  778. // add split point to front _and_ back part of splitter
  779. bvcFront.AddVertex(vPointMid);
  780. bvcBack.AddVertex(vPointMid);
  781. // if both are front
  782. } else if (tDistance1 > +BSP_EPSILON) {
  783. // add the whole edge to front node
  784. bpoFront.AddEdge(vPoint0, vPoint1, ulEdgeTag);
  785. // no split points
  786. // if first is front, second on the plane
  787. } else {
  788. // add the whole edge to front node
  789. bpoFront.AddEdge(vPoint0, vPoint1, ulEdgeTag);
  790. // add second point to front part of splitter
  791. bvcFront.AddVertex(vPoint1);
  792. }
  793. /* ---- first point on the plane ---- */
  794. } else {
  795. // if first is on the plane, second back
  796. if (tDistance1 < -BSP_EPSILON) {
  797. // add the whole edge to back node
  798. bpoBack.AddEdge(vPoint0, vPoint1, ulEdgeTag);
  799. // add first point to back part of splitter
  800. bvcBack.AddVertex(vPoint0);
  801. // if first is on the plane, second in front of the plane
  802. } else if (tDistance1 > +BSP_EPSILON) {
  803. // add the whole edge to front node
  804. bpoFront.AddEdge(vPoint0, vPoint1, ulEdgeTag);
  805. // add first point to front part of splitter
  806. bvcFront.AddVertex(vPoint0);
  807. // if both are on the plane
  808. } else {
  809. // check the direction of the edge with the front direction of the splitter
  810. Type tDirection = (vPoint1-vPoint0)%bvcFront.bvc_vDirection;
  811. // if the directions are same
  812. if (tDirection > +BSP_EPSILON) {
  813. // add the whole edge to front node
  814. bpoFront.AddEdge(vPoint0, vPoint1, ulEdgeTag);
  815. // add both points to front part of the splitter
  816. bvcFront.AddVertex(vPoint0);
  817. bvcFront.AddVertex(vPoint1);
  818. // if the directions are opposite
  819. } else if (tDirection < -BSP_EPSILON) {
  820. // add the whole edge to back node
  821. bpoBack.AddEdge(vPoint0, vPoint1, ulEdgeTag);
  822. // add both points to back part of the splitter
  823. bvcBack.AddVertex(vPoint0);
  824. bvcBack.AddVertex(vPoint1);
  825. // if the directions are indeterminate
  826. } else {
  827. // that must mean that there is no edge in fact
  828. //ASSERT(Type(vPoint1-vPoint0) < 2*BSP_EPSILON); //!!!!
  829. }
  830. }
  831. }
  832. }
  833. /////////////////////////////////////////////////////////////////////
  834. // BSP tree
  835. /*
  836. * Default constructor.
  837. */
  838. template<class Type, int iDimensions>
  839. BSPTree<Type, iDimensions>::BSPTree(void)
  840. {
  841. bt_pbnRoot = NULL;
  842. }
  843. /*
  844. * Destructor.
  845. */
  846. template<class Type, int iDimensions>
  847. BSPTree<Type, iDimensions>::~BSPTree(void)
  848. {
  849. Destroy();
  850. }
  851. /*
  852. * Constructor with array of polygons oriented inwards.
  853. */
  854. template<class Type, int iDimensions>
  855. BSPTree<Type, iDimensions>::BSPTree(CDynamicArray<BSPPolygon<Type, iDimensions> > &abpoPolygons)
  856. {
  857. bt_pbnRoot = NULL;
  858. Create(abpoPolygons);
  859. }
  860. /*
  861. * Create bsp-subtree from array of polygons oriented inwards.
  862. */
  863. template<class Type, int iDimensions>
  864. BSPNode<Type, iDimensions> *BSPTree<Type, iDimensions>::CreateSubTree(CDynamicArray<BSPPolygon<Type, iDimensions> > &abpoPolygons)
  865. {
  866. // local declarations, to fix macro expansion in FOREACHINDYNAMICARRAY
  867. typedef BSPEdge<Type, iDimensions> edge_t;
  868. typedef BSPPolygon<Type, iDimensions> polygon_t;
  869. ASSERT(abpoPolygons.Count()>=1);
  870. // use first polygon as splitter
  871. abpoPolygons.Lock();
  872. BSPPolygon<Type, iDimensions> bpoSplitter = abpoPolygons[0];
  873. abpoPolygons.Unlock();
  874. // tags must be valid
  875. ASSERT(bpoSplitter.bpo_ulPlaneTag!=-1);
  876. // create two new polygon arrays - back and front
  877. CDynamicArray<BSPPolygon<Type, iDimensions> > abpoFront, abpoBack;
  878. // for each polygon in this array
  879. {FOREACHINDYNAMICARRAY(abpoPolygons, polygon_t, itbpo) {
  880. BSPPolygon<Type, iDimensions> bpoFront, bpoBack;
  881. // tags must be valid
  882. ASSERT(itbpo->bpo_ulPlaneTag!=-1);
  883. // if the polygon has plane tag same as the tag of the splitter
  884. if (itbpo->bpo_ulPlaneTag == bpoSplitter.bpo_ulPlaneTag) {
  885. // they are assumed coplanar, so skip it
  886. continue;
  887. }
  888. // split it by the plane of splitter polygon
  889. BOOL bOnPlane = BSPCutter<Type, iDimensions>::SplitPolygon(itbpo.Current(),
  890. bpoSplitter, bpoSplitter.bpo_ulPlaneTag, bpoFront, bpoBack);
  891. // if the polygon is not coplanar with the splitter
  892. if (!bOnPlane) {
  893. // if there are some parts that are front
  894. if (bpoFront.bpo_abedPolygonEdges.Count()>0) {
  895. // create a polygon in front array and add all inside parts to it
  896. BSPPolygon<Type, iDimensions> *pbpo = abpoFront.New(1);
  897. pbpo->bpo_abedPolygonEdges.MoveArray(bpoFront.bpo_abedPolygonEdges);
  898. *(Plane<Type, iDimensions> *)pbpo = itbpo.Current();
  899. pbpo->bpo_ulPlaneTag = itbpo->bpo_ulPlaneTag;
  900. }
  901. // if there are some parts that are back
  902. if (bpoBack.bpo_abedPolygonEdges.Count()>0) {
  903. // create a polygon in back array and add all outside parts to it
  904. BSPPolygon<Type, iDimensions> *pbpo = abpoBack.New(1);
  905. pbpo->bpo_abedPolygonEdges.MoveArray(bpoBack.bpo_abedPolygonEdges);
  906. *(Plane<Type, iDimensions> *)pbpo = itbpo.Current();
  907. pbpo->bpo_ulPlaneTag = itbpo->bpo_ulPlaneTag;
  908. }
  909. }
  910. }}
  911. // free this array (to not consume too much memory)
  912. abpoPolygons.Clear();
  913. BSPNode<Type, iDimensions> *pbnFront, *pbnBack;
  914. // if there is some polygon in front array
  915. if (abpoFront.Count()>0) {
  916. // create front subtree using front array
  917. pbnFront = CreateSubTree(abpoFront);
  918. // otherwise
  919. } else {
  920. // make front node an inside leaf node
  921. pbnFront = new BSPNode<Type, iDimensions>(BNL_INSIDE);
  922. }
  923. // if there is some polygon in back array
  924. if (abpoBack.Count()>0) {
  925. // create back subtree using back array
  926. pbnBack = CreateSubTree(abpoBack);
  927. // otherwise
  928. } else {
  929. // make back node an outside leaf node
  930. pbnBack = new BSPNode<Type, iDimensions>(BNL_OUTSIDE);
  931. }
  932. // make a splitter node with the front and back nodes
  933. return new BSPNode<Type, iDimensions>(bpoSplitter, bpoSplitter.bpo_ulPlaneTag, *pbnFront, *pbnBack);
  934. }
  935. /*
  936. * Create bsp-tree from array of polygons oriented inwards.
  937. */
  938. template<class Type, int iDimensions>
  939. void BSPTree<Type, iDimensions>::Create(CDynamicArray<BSPPolygon<Type, iDimensions> > &abpoPolygons)
  940. {
  941. typedef BSPPolygon<Type, iDimensions> polygon_t; // local declaration, to fix macro expansion in FOREACHINDYNAMICARRAY
  942. // free eventual existing tree
  943. Destroy();
  944. // create the tree using the recursive function
  945. bt_pbnRoot = CreateSubTree(abpoPolygons);
  946. // move the tree to array
  947. MoveNodesToArray();
  948. }
  949. /*
  950. * Destroy bsp-tree.
  951. */
  952. template<class Type, int iDimensions>
  953. void BSPTree<Type, iDimensions>::Destroy(void)
  954. {
  955. // if tree is in array
  956. if (bt_abnNodes.Count()>0) {
  957. // clear array
  958. bt_abnNodes.Clear();
  959. bt_pbnRoot = NULL;
  960. // if there is some free tree
  961. } else if (bt_pbnRoot != NULL) {
  962. // delete it
  963. bt_pbnRoot->DeleteBSPNodeRecursively();
  964. bt_pbnRoot = NULL;
  965. }
  966. }
  967. /* Test if a sphere could touch any of inside nodes. (Just a trivial rejection test) */
  968. template<class Type, int iDimensions>
  969. FLOAT BSPTree<Type, iDimensions>::TestSphere(const Vector<Type, iDimensions> &vSphereCenter, Type tSphereRadius) const
  970. {
  971. if (bt_pbnRoot==NULL) return FALSE;
  972. // just start recursive testing at root node
  973. return bt_pbnRoot->TestSphere(vSphereCenter, tSphereRadius);
  974. }
  975. /* Test if a box is inside, outside, or intersecting. (Just a trivial rejection test) */
  976. template<class Type, int iDimensions>
  977. FLOAT BSPTree<Type, iDimensions>::TestBox(const OBBox<Type> &box) const
  978. {
  979. if (bt_pbnRoot==NULL) return FALSE;
  980. // just start recursive testing at root node
  981. return bt_pbnRoot->TestBox(box);
  982. }
  983. // find minimum/maximum parameters of points on a line that are inside
  984. template<class Type, int iDimensions>
  985. void BSPTree<Type, iDimensions>::FindLineMinMax(
  986. const Vector<Type, iDimensions> &v0,
  987. const Vector<Type, iDimensions> &v1,
  988. Type &tMin,
  989. Type &tMax) const
  990. {
  991. // init line
  992. BSPLine<Type, iDimensions> bl;
  993. bl.bl_tMin = UpperLimit(Type(0));
  994. bl.bl_tMax = LowerLimit(Type(0));
  995. // recursively split it
  996. bt_pbnRoot->FindLineMinMax(bl, v0, v1, Type(0), Type(1));
  997. // return the min/max
  998. tMin = bl.bl_tMin;
  999. tMax = bl.bl_tMax;
  1000. }
  1001. static INDEX _ctNextIndex;
  1002. /* Move one subtree to array. */
  1003. template<class Type, int iDimensions>
  1004. void BSPTree<Type, iDimensions>::MoveSubTreeToArray(BSPNode<Type, iDimensions> *pbnSubtree)
  1005. {
  1006. // if this is no node
  1007. if (pbnSubtree==NULL) {
  1008. // do nothing
  1009. return;
  1010. }
  1011. // first move all subnodes
  1012. MoveSubTreeToArray(pbnSubtree->bn_pbnFront);
  1013. MoveSubTreeToArray(pbnSubtree->bn_pbnBack);
  1014. // get the node in array
  1015. BSPNode<Type, iDimensions> &bnInArray = bt_abnNodes[_ctNextIndex];
  1016. _ctNextIndex--;
  1017. // copy properties to the array node
  1018. (Plane<Type, iDimensions>&)bnInArray = (Plane<Type, iDimensions>&)*pbnSubtree;
  1019. bnInArray.bn_bnlLocation = pbnSubtree->bn_bnlLocation;
  1020. bnInArray.bn_ulPlaneTag = pbnSubtree->bn_ulPlaneTag;
  1021. // let plane tag hold pointer to node in array
  1022. pbnSubtree->bn_ulPlaneTag = (ULONG)&bnInArray;
  1023. // remap pointers to subnodes
  1024. if (pbnSubtree->bn_pbnFront==NULL) {
  1025. bnInArray.bn_pbnFront = NULL;
  1026. } else {
  1027. bnInArray.bn_pbnFront = (BSPNode<Type, iDimensions>*)pbnSubtree->bn_pbnFront->bn_ulPlaneTag;
  1028. }
  1029. if (pbnSubtree->bn_pbnBack==NULL) {
  1030. bnInArray.bn_pbnBack = NULL;
  1031. } else {
  1032. bnInArray.bn_pbnBack = (BSPNode<Type, iDimensions>*)pbnSubtree->bn_pbnBack->bn_ulPlaneTag;
  1033. }
  1034. }
  1035. /* Count nodes in subtree. */
  1036. template<class Type, int iDimensions>
  1037. INDEX BSPTree<Type, iDimensions>::CountNodes(BSPNode<Type, iDimensions> *pbnSubtree)
  1038. {
  1039. if (pbnSubtree==NULL) {
  1040. return 0;
  1041. } else {
  1042. return 1+
  1043. CountNodes(pbnSubtree->bn_pbnFront)+
  1044. CountNodes(pbnSubtree->bn_pbnBack);
  1045. }
  1046. }
  1047. /* Move all nodes to array. */
  1048. template<class Type, int iDimensions>
  1049. void BSPTree<Type, iDimensions>::MoveNodesToArray(void)
  1050. {
  1051. // if there is no tree
  1052. if (bt_pbnRoot == NULL) {
  1053. // do nothing
  1054. return;
  1055. }
  1056. // count nodes
  1057. INDEX ctNodes = CountNodes(bt_pbnRoot);
  1058. // allocate large enough array
  1059. bt_abnNodes.New(ctNodes);
  1060. // start at the end of array
  1061. _ctNextIndex = ctNodes-1;
  1062. // recusively remap all nodes
  1063. MoveSubTreeToArray(bt_pbnRoot);
  1064. // delete the old nodes
  1065. bt_pbnRoot->DeleteBSPNodeRecursively();
  1066. // first node is always at start of array
  1067. bt_pbnRoot = &bt_abnNodes[0];
  1068. }
  1069. /* Read/write entire bsp tree to disk. */
  1070. template<class Type, int iDimensions>
  1071. void BSPTree<Type, iDimensions>::Read_t(CTStream &strm) // throw char *
  1072. {
  1073. // free eventual existing tree
  1074. Destroy();
  1075. // read current version and size
  1076. INDEX iVersion;
  1077. SLONG slSize;
  1078. strm>>iVersion>>slSize;
  1079. ASSERT(iVersion==1);
  1080. // read count of nodes and create array
  1081. INDEX ctNodes;
  1082. strm>>ctNodes;
  1083. ASSERT(slSize==(SLONG)(sizeof(INDEX)+ctNodes*sizeof(BSPNode<Type, iDimensions>)));
  1084. bt_abnNodes.New(ctNodes);
  1085. // for each node
  1086. for(INDEX iNode=0; iNode<ctNodes; iNode++) {
  1087. BSPNode<Type, iDimensions> &bn = bt_abnNodes[iNode];
  1088. // read it from disk
  1089. strm.Read_t(&(Plane<Type, iDimensions>&)bn, sizeof(Plane<Type, iDimensions>));
  1090. strm>>(INDEX&)bn.bn_bnlLocation;
  1091. INDEX iFront;
  1092. strm>>iFront;
  1093. if (iFront==-1) {
  1094. bn.bn_pbnFront=NULL;
  1095. } else {
  1096. bn.bn_pbnFront = &bt_abnNodes[iFront];
  1097. }
  1098. INDEX iBack;
  1099. strm>>iBack;
  1100. if (iBack==-1) {
  1101. bn.bn_pbnBack=NULL;
  1102. } else {
  1103. bn.bn_pbnBack = &bt_abnNodes[iBack];
  1104. }
  1105. strm>>bn.bn_ulPlaneTag;
  1106. }
  1107. // check end id
  1108. strm.ExpectID_t("BSPE"); // bsp end
  1109. // first node is always at start of array
  1110. if (bt_abnNodes.Count()>0) {
  1111. bt_pbnRoot = &bt_abnNodes[0];
  1112. } else {
  1113. bt_pbnRoot = NULL;
  1114. }
  1115. }
  1116. template<class Type, int iDimensions>
  1117. void BSPTree<Type, iDimensions>::Write_t(CTStream &strm) // throw char *
  1118. {
  1119. INDEX ctNodes = bt_abnNodes.Count();
  1120. // calculate size of chunk to write
  1121. SLONG slSize = sizeof(INDEX)+ctNodes*sizeof(BSPNode<Type, iDimensions>);
  1122. // write current version and size
  1123. strm<<INDEX(1)<<slSize;
  1124. // write count of nodes
  1125. strm<<ctNodes;
  1126. // for each node
  1127. for(INDEX iNode=0; iNode<ctNodes; iNode++) {
  1128. BSPNode<Type, iDimensions> &bn = bt_abnNodes[iNode];
  1129. // write it to disk
  1130. strm.Write_t(&(Plane<Type, iDimensions>&)bn, sizeof(Plane<Type, iDimensions>));
  1131. strm<<(INDEX&)bn.bn_bnlLocation;
  1132. INDEX iFront;
  1133. if (bn.bn_pbnFront==NULL) {
  1134. iFront=-1;
  1135. } else {
  1136. iFront = bt_abnNodes.Index(bn.bn_pbnFront);
  1137. }
  1138. strm<<iFront;
  1139. INDEX iBack;
  1140. if (bn.bn_pbnBack==NULL) {
  1141. iBack=-1;
  1142. } else {
  1143. iBack = bt_abnNodes.Index(bn.bn_pbnBack);
  1144. }
  1145. strm<<iBack;
  1146. strm<<bn.bn_ulPlaneTag;
  1147. }
  1148. // write end id for checking
  1149. strm.WriteID_t("BSPE"); // bsp end
  1150. }
  1151. // instantiate template classes implemented here for needed types
  1152. #pragma warning (disable: 4660) // if already instantiated by some class
  1153. // remove templates
  1154. template DOUBLEbspvertex3D;
  1155. template DOUBLEbspvertexcontainer3D;
  1156. template DOUBLEbspedge3D;
  1157. template DOUBLEbspnode3D;
  1158. template DOUBLEbsppolygon3D;
  1159. template DOUBLEbsptree3D;
  1160. template DOUBLEbspcutter3D;
  1161. template FLOATbspvertex3D;
  1162. template FLOATbspvertexcontainer3D;
  1163. template FLOATbspedge3D;
  1164. template FLOATbspnode3D;
  1165. template FLOATbsppolygon3D;
  1166. template FLOATbsptree3D;
  1167. template FLOATbspcutter3D;
  1168. #pragma warning (default: 4660)