12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316 |
- /* Copyright (c) 2002-2012 Croteam Ltd.
- This program is free software; you can redistribute it and/or modify
- it under the terms of version 2 of the GNU General Public License as published by
- the Free Software Foundation
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
- #include "stdh.h"
- #include <Engine/Templates/BSP.h>
- #include <Engine/Templates/BSP_internal.h>
- #include <Engine/Base/Stream.h>
- #include <Engine/Math/Vector.h>
- #include <Engine/Math/Plane.h>
- #include <Engine/Math/OBBox.h>
- #include <Engine/Math/Functions.h>
- #include <Engine/Templates/StaticStackArray.cpp>
- #include <Engine/Templates/DynamicArray.cpp>
- // epsilon value used for BSP cutting
- //#define BSP_EPSILON ((Type) 0.015625) // 1/2^6 ~= 1.5 cm
- #define BSP_EPSILON Type((1.0/65536.0)*4*mth_fCSGEpsilon) // 1/2^16
- //#define BSP_EPSILON Type(0.00390625) // 1/2^8
- //#define EPSILON (1.0f/8388608.0f) // 1/2^23
- //#define EPSILON 0.0009765625f // 1/2^10
- //#define EPSILON 0.03125f // 1/2^5
- //#define EPSILON 0.00390625f // 1/2^8
- template <class Type>
- inline BOOL EpsilonEq(const Type &a, const Type &b) { return Abs(a-b)<=BSP_EPSILON; };
- template <class Type>
- inline BOOL EpsilonNe(const Type &a, const Type &b) { return Abs(a-b)> BSP_EPSILON; };
- /////////////////////////////////////////////////////////////////////
- // BSP vertex
- /*
- * Assignment operator with coordinates only.
- */
- template<class Type, int iDimensions>
- BSPVertex<Type, iDimensions> &BSPVertex<Type, iDimensions>::operator=(const Vector<Type, iDimensions> &vCoordinates)
- {
- *(Vector<Type, iDimensions> *)this = vCoordinates;
- return *this;
- }
- /////////////////////////////////////////////////////////////////////
- // BSP vertex container
- /*
- * Default constructor.
- */
- template<class Type, int iDimensions>
- BSPVertexContainer<Type, iDimensions>::BSPVertexContainer(void)
- {
- }
- template<class Type, int iDimensions>
- void BSPVertexContainer<Type, iDimensions>::AddVertex(const Vector<Type, iDimensions> &vPoint)
- {
- bvc_aVertices.Push() = vPoint;
- }
- /*
- * Initialize for a direction.
- */
- template<class Type, int iDimensions>
- void BSPVertexContainer<Type, iDimensions>::Initialize(const Vector<Type, iDimensions> &vDirection)
- {
- bvc_vDirection = vDirection;
- // init array of vertices
- bvc_aVertices.SetAllocationStep(32);
- // find largest axis of direction vector
- INDEX iMaxAxis = 0;
- Type tMaxAxis = (Type)0;//vDirection(1);
- for( INDEX iAxis=1; iAxis<=iDimensions; iAxis++) {
- if( Abs(vDirection(iAxis)) > Abs(tMaxAxis) ) {
- tMaxAxis = vDirection(iAxis);
- iMaxAxis = iAxis;
- }
- }
- /* This assert would seem natural here, but it is not possible because of parallel planes!
- // must be greater or equal than minimal max axis of any normalized vector in that space
- ASSERT( Abs(tMaxAxis) > (1.0/sqrt(double(iDimensions))-0.01) );
- */
- // remember that axis index and sign for sorting
- bvc_iMaxAxis = iMaxAxis;
- bvc_tMaxAxisSign = Sgn(tMaxAxis);
- }
- /*
- * Unnitialize.
- */
- template<class Type, int iDimensions>
- void BSPVertexContainer<Type, iDimensions>::Uninitialize(void)
- {
- // delete array of vertices
- bvc_aVertices.Delete();
- // destroy axis index and sign
- bvc_iMaxAxis = -1;
- bvc_tMaxAxisSign = (Type)0;
- }
- static INDEX qsort_iCompareAxis;
- template<class Type, int iDimensions>
- class CVertexComparator {
- public:
- /*
- * Compare two vertices.
- */
- static inline int CompareVertices(const Vector<Type, iDimensions> &vx0, const Vector<Type, iDimensions> &vx1, INDEX iAxis)
- {
- if (vx0(iAxis)<vx1(iAxis)) return -1;
- else if (vx0(iAxis)>vx1(iAxis)) return 1;
- else return 0;
- }
- /*
- * Compare two vertices for quick-sort.
- */
- static int qsort_CompareVertices_plus( const void *pvVertex0, const void *pvVertex1)
- {
- BSPVertex<Type, iDimensions> &vx0 = *(BSPVertex<Type, iDimensions> *)pvVertex0;
- BSPVertex<Type, iDimensions> &vx1 = *(BSPVertex<Type, iDimensions> *)pvVertex1;
- return +CompareVertices(vx0, vx1, qsort_iCompareAxis);
- }
- static int qsort_CompareVertices_minus( const void *pvVertex0, const void *pvVertex1)
- {
- BSPVertex<Type, iDimensions> &vx0 = *(BSPVertex<Type, iDimensions> *)pvVertex0;
- BSPVertex<Type, iDimensions> &vx1 = *(BSPVertex<Type, iDimensions> *)pvVertex1;
- return -CompareVertices(vx0, vx1, qsort_iCompareAxis);
- }
- };
- /*
- * Sort vertices in this container along the largest axis of container direction.
- */
- template<class Type, int iDimensions>
- void BSPVertexContainer<Type, iDimensions>::Sort(void)
- {
- // if there are no vertices, or the container is not line
- if (bvc_aVertices.Count()==0 || IsPlannar()) {
- // do not attempt to sort
- return;
- }
- // sort by max. axis
- qsort_iCompareAxis = bvc_iMaxAxis;
- // if the sign of axis is positive
- if (bvc_tMaxAxisSign>0) {
- // sort them normally
- if (bvc_aVertices.Count()>0) {
- qsort(&bvc_aVertices[0], bvc_aVertices.Count(), sizeof(BSPVertex<Type, iDimensions>),
- CVertexComparator<Type, iDimensions>::qsort_CompareVertices_plus);
- }
- // if it is negative
- } else {
- // sort them inversely
- if (bvc_aVertices.Count()>0) {
- qsort(&bvc_aVertices[0], bvc_aVertices.Count(), sizeof(BSPVertex<Type, iDimensions>),
- CVertexComparator<Type, iDimensions>::qsort_CompareVertices_minus);
- }
- }
- }
- /*
- * Elliminate paired vertices.
- */
- template<class Type, int iDimensions>
- void BSPVertexContainer<Type, iDimensions>::ElliminatePairedVertices(void)
- {
- // if there are no vertices, or the container is not line
- if (bvc_aVertices.Count()==0 || IsPlannar()) {
- // do not attempt to sort
- return;
- }
- // initially, last vertices are far away
- Type tLastInside; tLastInside = (Type)32000;
- BSPVertex<Type, iDimensions> *pbvxLastInside = NULL;
- // for all vertices in container
- for (INDEX iVertex=0; iVertex<bvc_aVertices.Count(); iVertex++) {
- BSPVertex<Type, iDimensions> &bvx = bvc_aVertices[iVertex]; // reference to this vertex
- Type t = bvx(bvc_iMaxAxis); // coordinate along max. axis
- // if last inside vertex is next to this one
- if ( EpsilonEq(t, tLastInside) ) {
- // last vertex is far away
- tLastInside = (Type)32000;
- IFDEBUG(pbvxLastInside = NULL);
- // otherwise
- } else {
- // make this last inside vertex
- tLastInside = t;
- pbvxLastInside = &bvx;
- }
- }
- }
- /*
- * Create edges from vertices in one container -- must be sorted before.
- */
- template<class Type, int iDimensions>
- void BSPVertexContainer<Type, iDimensions>::CreateEdges(CDynamicArray<BSPEdge<Type, iDimensions> > &abed, ULONG ulEdgeTag)
- {
- // if there are no vertices, or the container is not line
- if (bvc_aVertices.Count()==0 || IsPlannar()) {
- // do not attempt to sort
- return;
- }
- // initially, edge is inactive
- BOOL bActive = FALSE;
- BSPEdge<Type, iDimensions> *pbed = NULL;
- // for all vertices in container
- for (INDEX iVertex=0; iVertex<bvc_aVertices.Count(); iVertex++) {
- BSPVertex<Type, iDimensions> &bvx = bvc_aVertices[iVertex]; // reference to this vertex
- // if edge is inactive
- if (!bActive) {
- // create new edge
- pbed = abed.New();
- pbed->bed_ulEdgeTag = ulEdgeTag;
- // set start vertex
- pbed->bed_vVertex0 = bvx;
- } else {
- // set end vertex
- pbed->bed_vVertex1 = bvx;
- // trash edge pointer
- IFDEBUG(pbed = NULL);
- }
- // toggle edge
- bActive = !bActive;
- }
- }
- /////////////////////////////////////////////////////////////////////
- // BSP edge
- /*
- * Constructor with two vectors.
- */
- template<class Type, int iDimensions>
- BSPEdge<Type, iDimensions>::BSPEdge(const Vector<Type, iDimensions> &vVertex0, const Vector<Type, iDimensions> &vVertex1, ULONG ulTag)
- : bed_vVertex0(vVertex0)
- , bed_vVertex1(vVertex1)
- , bed_ulEdgeTag(ulTag)
- {}
- // remove all edges marked for removal
- template<class Type, int iDimensions>
- void BSPEdge<Type, iDimensions>::RemoveMarkedBSPEdges(CDynamicArray<BSPEdge<Type, iDimensions> > &abed)
- {
- typedef BSPEdge<Type, iDimensions> edge_t; // local declaration, to fix macro expansion in FOREACHINDYNAMICARRAY
- // conut edges left
- INDEX ctEdgesLeft = 0;
- {FOREACHINDYNAMICARRAY(abed, edge_t, itbed) {
- if (itbed->bed_ulEdgeTag != 0) {
- ctEdgesLeft++;
- }
- }}
- // make a copy of array without removed edges
- CDynamicArray<BSPEdge<Type, iDimensions> > abed2;
- abed2.New(ctEdgesLeft);
- abed2.Lock();
- INDEX iedNew = 0;
- {FOREACHINDYNAMICARRAY(abed, edge_t, itbed) {
- edge_t &bed = *itbed;
- if (bed.bed_ulEdgeTag != 0) {
- abed2[iedNew] = bed;
- iedNew++;
- }
- }}
- abed2.Unlock();
- // use that copy instead the original array
- abed.Clear();
- abed.MoveArray(abed2);
- }
- // optimize a polygon made out of BSP edges using tag information
- template<class Type, int iDimensions>
- void BSPEdge<Type, iDimensions>::OptimizeBSPEdges(CDynamicArray<BSPEdge<Type, iDimensions> > &abed)
- {
- typedef BSPEdge<Type, iDimensions> edge_t; // local declaration, to fix macro expansion in FOREACHINDYNAMICARRAY
- // if there are no edges
- if (abed.Count()==0) {
- // do nothing
- return;
- }
- BOOL bSomeJoined;
- // repeat
- do {
- bSomeJoined = FALSE;
- // for each edge
- {FOREACHINDYNAMICARRAY(abed, edge_t, itbed1) {
- edge_t &bed1 = *itbed1;
- // if it is already marked
- if (bed1.bed_ulEdgeTag == 0) {
- // skip it
- continue;
- }
- // if it is dummy edge
- if (bed1.bed_vVertex0==bed1.bed_vVertex1) {
- // mark it for removal
- bSomeJoined = TRUE;
- bed1.bed_ulEdgeTag = 0;
- // skip it
- continue;
- }
- // for each other edge
- {FOREACHINDYNAMICARRAY(abed, edge_t, itbed2) {
- edge_t &bed2 = *itbed2;
- if (&bed1==&bed2) {
- continue;
- }
- // if it is already marked
- if (bed2.bed_ulEdgeTag == 0) {
- // skip it
- continue;
- }
- // if they originate from same edge (plane)
- if (bed1.bed_ulEdgeTag == bed2.bed_ulEdgeTag) {
- // if they are complemented
- if (bed1.bed_vVertex0==bed2.bed_vVertex1 && bed1.bed_vVertex1==bed2.bed_vVertex0) {
- // marked them both
- bSomeJoined = TRUE;
- bed1.bed_ulEdgeTag = 0;
- bed2.bed_ulEdgeTag = 0;
- // skip them both
- break;
- }
- // if second one continues after first one
- if (bed1.bed_vVertex1==bed2.bed_vVertex0) {
- // extend end of first edge to the end of second one
- bed1.bed_vVertex1=bed2.bed_vVertex1;
- bSomeJoined = TRUE;
- // marked second edge
- bed2.bed_ulEdgeTag = 0;
- // if second one continues before first one
- } else if (bed1.bed_vVertex0==bed2.bed_vVertex1) {
- // extend start of first edge to the start of second one
- bed1.bed_vVertex0=bed2.bed_vVertex0;
- bSomeJoined = TRUE;
- // marked second edge
- bed2.bed_ulEdgeTag = 0;
- }
- }
- }}
- }}
- // while some edges can be joined
- } while(bSomeJoined);
- // remove all marked edges
- RemoveMarkedBSPEdges(abed);
- }
- /////////////////////////////////////////////////////////////////////
- // BSP polygon
- /*
- * Add an edge to the polygon.
- */
- template<class Type, int iDimensions>
- inline void BSPPolygon<Type, iDimensions>::AddEdge(const Vector<Type, iDimensions> &vPoint0, const Vector<Type, iDimensions> &vPoint1, ULONG ulTag)
- {
- *bpo_abedPolygonEdges.New() = BSPEdge<Type, iDimensions>(vPoint0, vPoint1, ulTag);
- }
- /////////////////////////////////////////////////////////////////////
- // BSP node
- /*
- * Recursive destructor.
- */
- template<class Type, int iDimensions>
- void BSPNode<Type, iDimensions>::DeleteBSPNodeRecursively(void)
- {
- // delete sub-trees first, before deleting this node
- if (bn_pbnFront!=NULL) {
- bn_pbnFront->DeleteBSPNodeRecursively();
- }
- if (bn_pbnBack!=NULL) {
- bn_pbnBack->DeleteBSPNodeRecursively();
- }
- delete this;
- }
- /*
- * Constructor for a leaf node.
- */
- template<class Type, int iDimensions>
- BSPNode<Type, iDimensions>::BSPNode(enum BSPNodeLocation bnl)
- : bn_bnlLocation(bnl)
- , bn_pbnFront(NULL)
- , bn_pbnBack(NULL)
- {
- ASSERT(bnl == BNL_INSIDE || bnl == BNL_OUTSIDE);
- }
- /*
- * Constructor for a branch node.
- */
- template<class Type, int iDimensions>
- BSPNode<Type, iDimensions>::BSPNode(const Plane<Type, iDimensions> &plSplitPlane, ULONG ulPlaneTag,
- BSPNode<Type, iDimensions> &bnFront, BSPNode<Type, iDimensions> &bnBack)
- : Plane<Type, iDimensions>(plSplitPlane)
- , bn_pbnFront(&bnFront)
- , bn_pbnBack(&bnBack)
- , bn_bnlLocation(BNL_BRANCH)
- , bn_ulPlaneTag(ulPlaneTag)
- {
- }
- /*
- * Constructor for cloning a bsp (sub)tree.
- */
- template<class Type, int iDimensions>
- BSPNode<Type, iDimensions>::BSPNode(BSPNode<Type, iDimensions> &bnRoot)
- : Plane<Type, iDimensions>(bnRoot) // copy the plane
- , bn_bnlLocation(bnRoot.bn_bnlLocation) // copy the location
- , bn_ulPlaneTag(bnRoot.bn_ulPlaneTag) // copy the plane tag
- {
- // if this has a front child
- if (bnRoot.bn_pbnFront != NULL) {
- // clone front sub tree
- bn_pbnFront = new BSPNode<Type, iDimensions>(*bnRoot.bn_pbnFront);
- // otherwise
- } else {
- // no front sub tree
- bn_pbnFront = NULL;
- }
- // if this has a back child
- if (bnRoot.bn_pbnBack != NULL) {
- // clone back sub tree
- bn_pbnBack = new BSPNode<Type, iDimensions>(*bnRoot.bn_pbnBack);
- // otherwise
- } else {
- // no back sub tree
- bn_pbnBack = NULL;
- }
- }
- /* Test if a sphere is inside, outside, or intersecting. (Just a trivial rejection test) */
- template<class Type, int iDimensions>
- FLOAT BSPNode<Type, iDimensions>::TestSphere(const Vector<Type, iDimensions> &vSphereCenter, Type tSphereRadius) const
- {
- // if this is an inside node
- if (bn_bnlLocation == BNL_INSIDE) {
- // it is inside
- return 1;
- // if this is an outside node
- } else if (bn_bnlLocation == BNL_OUTSIDE) {
- // it is outside
- return -1;
- // if this is a branch
- } else {
- ASSERT(bn_bnlLocation == BNL_BRANCH);
- // test the sphere against the split plane
- Type tCenterDistance = PointDistance(vSphereCenter);
- // if the sphere is in front of the plane
- if (tCenterDistance > +tSphereRadius) {
- // recurse down the front node
- return bn_pbnFront->TestSphere(vSphereCenter, tSphereRadius);
- // if the sphere is behind the plane
- } else if (tCenterDistance < -tSphereRadius) {
- // recurse down the back node
- return bn_pbnBack->TestSphere(vSphereCenter, tSphereRadius);
- // if the sphere is split by the plane
- } else {
- // if front node touches
- FLOAT fFront = bn_pbnFront->TestSphere(vSphereCenter, tSphereRadius);
- if (fFront==0) {
- // it touches
- return 0;
- }
- // if back node touches
- FLOAT fBack = bn_pbnBack->TestSphere(vSphereCenter, tSphereRadius);
- if (fBack==0) {
- // it touches
- return 0;
- }
- // if front and back have same classification
- if (fFront==fBack) {
- // return it
- return fFront;
- // if front and back have different classification
- } else {
- // it touches
- return 0;
- }
- }
- }
- }
- /* Test if a box is inside, outside, or intersecting. (Just a trivial rejection test) */
- template<class Type, int iDimensions>
- FLOAT BSPNode<Type, iDimensions>::TestBox(const OBBox<Type> &box) const
- {
- // if this is an inside node
- if (bn_bnlLocation == BNL_INSIDE) {
- // it is inside
- return 1;
- // if this is an outside node
- } else if (bn_bnlLocation == BNL_OUTSIDE) {
- // it is outside
- return -1;
- // if this is a branch
- } else {
- ASSERT(bn_bnlLocation == BNL_BRANCH);
- // test the box against the split plane
- Type tTest = box.TestAgainstPlane(*this);
- // if the sphere is in front of the plane
- if (tTest>0) {
- // recurse down the front node
- return bn_pbnFront->TestBox(box);
- // if the sphere is behind the plane
- } else if (tTest<0) {
- // recurse down the back node
- return bn_pbnBack->TestBox(box);
- // if the sphere is split by the plane
- } else {
- // if front node touches
- FLOAT fFront = bn_pbnFront->TestBox(box);
- if (fFront==0) {
- // it touches
- return 0;
- }
- // if back node touches
- FLOAT fBack = bn_pbnBack->TestBox(box);
- if (fBack==0) {
- // it touches
- return 0;
- }
- // if front and back have same classification
- if (fFront==fBack) {
- // return it
- return fFront;
- // if front and back have different classification
- } else {
- // it touches
- return 0;
- }
- }
- }
- }
- // find minimum/maximum parameters of points on a line that are inside - recursive
- template<class Type, int iDimensions>
- void BSPNode<Type, iDimensions>::FindLineMinMax(
- BSPLine<Type, iDimensions> &bl,
- const Vector<Type, iDimensions> &v0,
- const Vector<Type, iDimensions> &v1,
- Type t0, Type t1)
- {
- // if this is an inside node
- if (bn_bnlLocation == BNL_INSIDE) {
- // just update min/max
- bl.bl_tMin = Min(bl.bl_tMin, t0);
- bl.bl_tMax = Max(bl.bl_tMax, t1);
- return;
- // if this is an outside node
- } else if (bn_bnlLocation == BNL_OUTSIDE) {
- // do nothing
- return;
- // if this is a branch
- } else {
- ASSERT(bn_bnlLocation == BNL_BRANCH);
- // test the points against the split plane
- Type tD0 = PointDistance(v0);
- Type tD1 = PointDistance(v1);
- // if both are front
- if (tD0>=0 && tD1>=0) {
- // recurse down the front node
- bn_pbnFront->FindLineMinMax(bl, v0, v1, t0, t1);
- return;
- // if both are back
- } else if (tD0<0 && tD1<0) {
- // recurse down the back node
- bn_pbnBack->FindLineMinMax(bl, v0, v1, t0, t1);
- return;
- // if on different sides
- } else {
- // find split point
- Type tFraction = tD0/(tD0-tD1);
- Vector<Type, iDimensions> vS = v0+(v1-v0)*tFraction;
- Type tS = t0+(t1-t0)*tFraction;
- // if first is front
- if (tD0>=0) {
- // recurse first part down the front node
- bn_pbnFront->FindLineMinMax(bl, v0, vS, t0, tS);
- // recurse second part down the back node
- bn_pbnBack->FindLineMinMax(bl, vS, v1, tS, t1);
- return;
- // if first is back
- } else {
- // recurse first part down the back node
- bn_pbnBack->FindLineMinMax(bl, v0, vS, t0, tS);
- // recurse second part down the front node
- bn_pbnFront->FindLineMinMax(bl, vS, v1, tS, t1);
- return;
- }
- }
- }
- }
- /////////////////////////////////////////////////////////////////////
- // BSP cutter
- /*
- * Constructor for splitting a polygon with a BSP tree.
- */
- template<class Type, int iDimensions>
- BSPCutter<Type, iDimensions>::BSPCutter(BSPPolygon<Type, iDimensions> &bpoPolygon, BSPNode<Type, iDimensions> &bnRoot)
- {
- // cut the polygon with entire tree
- CutPolygon(bpoPolygon, bnRoot);
- }
- /*
- * Destructor.
- */
- template<class Type, int iDimensions>
- BSPCutter<Type, iDimensions>::~BSPCutter(void)
- {
- }
- /*
- * Cut a polygon with a BSP tree.
- */
- template<class Type, int iDimensions>
- void BSPCutter<Type, iDimensions>::CutPolygon(BSPPolygon<Type, iDimensions> &bpoPolygon, BSPNode<Type, iDimensions> &bn)
- {
- // if the polygon has no edges
- if (bpoPolygon.bpo_abedPolygonEdges.Count()==0) {
- // skip cutting
- return;
- }
- // if this node is inside node
- if (bn.bn_bnlLocation == BNL_INSIDE) {
- // add entire polygon to inside part
- bc_abedInside.MoveArray(bpoPolygon.bpo_abedPolygonEdges);
- // if this node is outside node
- } else if (bn.bn_bnlLocation == BNL_OUTSIDE) {
- // add entire polygon to outside part
- bc_abedOutside.MoveArray(bpoPolygon.bpo_abedPolygonEdges);
- // if this node is a branch
- } else if (bn.bn_bnlLocation == BNL_BRANCH) {
- BSPPolygon<Type, iDimensions> bpoFront; // part of polygon in front of this splitter
- BSPPolygon<Type, iDimensions> bpoBack; // part of polygon behind this splitter
- // split the polygon with split plane of this node
- BOOL bOnPlane = SplitPolygon(bpoPolygon, (Plane<Type, iDimensions> &)bn, bn.bn_ulPlaneTag, bpoFront, bpoBack);
- // if the polygon is not on the split plane
- if (!bOnPlane) {
- // recursively split front part with front part of bsp
- CutPolygon(bpoFront, *bn.bn_pbnFront);
- // recursively split back part with back part of bsp
- CutPolygon(bpoBack, *bn.bn_pbnBack);
- // if the polygon is on the split plane
- } else {
- BSPNode<Type, iDimensions> *pbnFront; // front node (relative to the polygon orientation)
- BSPNode<Type, iDimensions> *pbnBack; // back node (relative to the polygon orientation)
- // check the direction of the polygon with the front direction of the split plane
- Type tDirection = (Vector<Type, iDimensions> &)bpoPolygon%(Vector<Type, iDimensions> &)bn;
- // if the directions are same
- if (tDirection > +BSP_EPSILON) {
- // make nodes relative to polygon same as relative to the split plane
- pbnFront = bn.bn_pbnFront;
- pbnBack = bn.bn_pbnBack;
- // if the directions are opposite
- } else if (tDirection < -BSP_EPSILON) {
- // make nodes relative to polygon opposite as relative to the split plane
- pbnFront = bn.bn_pbnBack;
- pbnBack = bn.bn_pbnFront;
- // if the directions are indeterminate
- } else {
- // that must not be
- ASSERT(FALSE);
- }
- // cut it with front part of bsp
- BSPCutter<Type, iDimensions> bcFront(bpoPolygon, *pbnFront);
- // there must be no on-border parts
- ASSERT(bcFront.bc_abedBorderInside.Count()==0 && bcFront.bc_abedBorderOutside.Count()==0);
- // make a polygon from parts that are inside in front part of BSP
- BSPPolygon<Type, iDimensions> bpoInsideFront((Plane<Type, iDimensions> &)bpoPolygon, bcFront.bc_abedInside, bpoPolygon.bpo_ulPlaneTag);
- // cut them with back part of bsp
- BSPCutter<Type, iDimensions> bcBackInsideFront(bpoInsideFront, *pbnBack);
- // make a polygon from parts that are outside in front part of BSP
- BSPPolygon<Type, iDimensions> bpoOutsideFront((Plane<Type, iDimensions> &)bpoPolygon, bcFront.bc_abedOutside, bpoPolygon.bpo_ulPlaneTag);
- // cut them with back part of bsp
- BSPCutter<Type, iDimensions> bcBackOutsideFront(bpoOutsideFront, *pbnBack);
- // add parts that are inside both in front and back to inside part
- bc_abedInside.MoveArray(bcBackInsideFront.bc_abedInside);
- // add parts that are outside both in front and back to outside part
- bc_abedOutside.MoveArray(bcBackOutsideFront.bc_abedOutside);
- // add parts that are inside in front and outside back to on-border-inside-part
- bc_abedBorderInside.MoveArray(bcBackInsideFront.bc_abedOutside);
- // add parts that are outside in front and inside back to on-border-outside-part
- bc_abedBorderOutside.MoveArray(bcBackOutsideFront.bc_abedInside);
- }
- } else {
- ASSERTALWAYS("Bad node type");
- }
- }
- /*
- * Split a polygon with a plane.
- * -- returns FALSE if polygon is laying on the plane
- */
- template<class Type, int iDimensions>
- BOOL BSPCutter<Type, iDimensions>::SplitPolygon(BSPPolygon<Type, iDimensions> &bpoPolygon, const Plane<Type, iDimensions> &plSplitPlane, ULONG ulPlaneTag,
- BSPPolygon<Type, iDimensions> &bpoFront, BSPPolygon<Type, iDimensions> &bpoBack)
- {
- (Plane<Type, iDimensions> &)bpoFront = (Plane<Type, iDimensions> &)bpoPolygon;
- bpoFront.bpo_ulPlaneTag = bpoPolygon.bpo_ulPlaneTag;
- (Plane<Type, iDimensions> &)bpoBack = (Plane<Type, iDimensions> &)bpoPolygon;
- bpoBack.bpo_ulPlaneTag = bpoPolygon.bpo_ulPlaneTag;
- // calculate the direction of split line
- Vector<Type, iDimensions> vSplitDirection = ((Vector<Type, iDimensions> &)plSplitPlane) * (Vector<Type, iDimensions> &)bpoPolygon;
- // if the polygon is parallel with the split plane
- if (vSplitDirection.Length() < +BSP_EPSILON) {
- // calculate the distance of the polygon from the split plane
- Type fDistance = plSplitPlane.PlaneDistance(bpoPolygon);
- // if the polygon is in front of plane
- if (fDistance > +BSP_EPSILON) {
- // move all edges to front array
- bpoFront.bpo_abedPolygonEdges.MoveArray(bpoPolygon.bpo_abedPolygonEdges);
- // the polygon is not on the plane
- return FALSE;
- // if the polygon is behind the plane
- } else if (fDistance < -BSP_EPSILON) {
- // move all edges to back array
- bpoBack.bpo_abedPolygonEdges.MoveArray(bpoPolygon.bpo_abedPolygonEdges);
- // the polygon is not on the plane
- return FALSE;
- // if the polygon is on the plane
- } else {
- // just return so
- return TRUE;
- }
- // if the polygon is not parallel with the split plane
- } else {
- // initialize front and back vertex containers
- BSPVertexContainer<Type, iDimensions> bvcFront, bvcBack;
- bvcFront.Initialize(vSplitDirection);
- bvcBack.Initialize(-vSplitDirection);
- typedef BSPEdge<Type, iDimensions> edge_t; // local declaration, to fix macro expansion in FOREACHINDYNAMICARRAY
- // for each edge in polygon
- {FOREACHINDYNAMICARRAY(bpoPolygon.bpo_abedPolygonEdges, edge_t, itbed) {
- // split the edge
- SplitEdge(itbed->bed_vVertex0, itbed->bed_vVertex1, itbed->bed_ulEdgeTag, plSplitPlane,
- bpoFront, bpoBack, bvcFront, bvcBack);
- }}
- // sort vertex containers
- bvcFront.Sort();
- bvcBack.Sort();
- // elliminate paired vertices
- bvcFront.ElliminatePairedVertices();
- bvcBack.ElliminatePairedVertices();
- // create more front polygon edges from front vertex container
- bvcFront.CreateEdges(bpoFront.bpo_abedPolygonEdges, ulPlaneTag);
- // create more back polygon edges from back vertex container
- bvcBack.CreateEdges(bpoBack.bpo_abedPolygonEdges, ulPlaneTag);
- // the polygon is not on the plane
- return FALSE;
- }
- }
- /*
- * Split an edge with a plane.
- */
- template<class Type, int iDimensions>
- void BSPCutter<Type, iDimensions>::SplitEdge(const Vector<Type, iDimensions> &vPoint0, const Vector<Type, iDimensions> &vPoint1, ULONG ulEdgeTag,
- const Plane<Type, iDimensions> &plSplitPlane,
- BSPPolygon<Type, iDimensions> &bpoFront, BSPPolygon<Type, iDimensions> &bpoBack,
- BSPVertexContainer<Type, iDimensions> &bvcFront, BSPVertexContainer<Type, iDimensions> &bvcBack)
- {
- // calculate point distances from clip plane
- Type tDistance0 = plSplitPlane.PointDistance(vPoint0);
- Type tDistance1 = plSplitPlane.PointDistance(vPoint1);
- /* ---- first point behind plane ---- */
- if (tDistance0 < -BSP_EPSILON) {
- // if both are back
- if (tDistance1 < -BSP_EPSILON) {
- // add the whole edge to back node
- bpoBack.AddEdge(vPoint0, vPoint1, ulEdgeTag);
- // no split points
- // if first is back, second front
- } else if (tDistance1 > +BSP_EPSILON) {
- // calculate intersection coordinates
- Vector<Type, iDimensions> vPointMid = vPoint0-(vPoint0-vPoint1)*tDistance0/(tDistance0-tDistance1);
- // add front part to front node
- bpoFront.AddEdge(vPointMid, vPoint1, ulEdgeTag);
- // add back part to back node
- bpoBack.AddEdge(vPoint0, vPointMid, ulEdgeTag);
- // add split point to front _and_ back part of splitter
- bvcFront.AddVertex(vPointMid);
- bvcBack.AddVertex(vPointMid);
- // if first is back, second on the plane
- } else {
- // add the whole edge to back node
- bpoBack.AddEdge(vPoint0, vPoint1, ulEdgeTag);
- // add second point to back part of splitter
- bvcBack.AddVertex(vPoint1);
- }
- /* ---- first point in front of plane ---- */
- } else if (tDistance0 > +BSP_EPSILON) {
- // if first is front, second back
- if (tDistance1 < -BSP_EPSILON) {
- // calculate intersection coordinates
- Vector<Type, iDimensions> vPointMid = vPoint1-(vPoint1-vPoint0)*tDistance1/(tDistance1-tDistance0);
- // add front part to front node
- bpoFront.AddEdge(vPoint0, vPointMid, ulEdgeTag);
- // add back part to back node
- bpoBack.AddEdge(vPointMid, vPoint1, ulEdgeTag);
- // add split point to front _and_ back part of splitter
- bvcFront.AddVertex(vPointMid);
- bvcBack.AddVertex(vPointMid);
- // if both are front
- } else if (tDistance1 > +BSP_EPSILON) {
- // add the whole edge to front node
- bpoFront.AddEdge(vPoint0, vPoint1, ulEdgeTag);
- // no split points
- // if first is front, second on the plane
- } else {
- // add the whole edge to front node
- bpoFront.AddEdge(vPoint0, vPoint1, ulEdgeTag);
- // add second point to front part of splitter
- bvcFront.AddVertex(vPoint1);
- }
- /* ---- first point on the plane ---- */
- } else {
- // if first is on the plane, second back
- if (tDistance1 < -BSP_EPSILON) {
- // add the whole edge to back node
- bpoBack.AddEdge(vPoint0, vPoint1, ulEdgeTag);
- // add first point to back part of splitter
- bvcBack.AddVertex(vPoint0);
- // if first is on the plane, second in front of the plane
- } else if (tDistance1 > +BSP_EPSILON) {
- // add the whole edge to front node
- bpoFront.AddEdge(vPoint0, vPoint1, ulEdgeTag);
- // add first point to front part of splitter
- bvcFront.AddVertex(vPoint0);
- // if both are on the plane
- } else {
- // check the direction of the edge with the front direction of the splitter
- Type tDirection = (vPoint1-vPoint0)%bvcFront.bvc_vDirection;
- // if the directions are same
- if (tDirection > +BSP_EPSILON) {
- // add the whole edge to front node
- bpoFront.AddEdge(vPoint0, vPoint1, ulEdgeTag);
- // add both points to front part of the splitter
- bvcFront.AddVertex(vPoint0);
- bvcFront.AddVertex(vPoint1);
- // if the directions are opposite
- } else if (tDirection < -BSP_EPSILON) {
- // add the whole edge to back node
- bpoBack.AddEdge(vPoint0, vPoint1, ulEdgeTag);
- // add both points to back part of the splitter
- bvcBack.AddVertex(vPoint0);
- bvcBack.AddVertex(vPoint1);
- // if the directions are indeterminate
- } else {
- // that must mean that there is no edge in fact
- //ASSERT(Type(vPoint1-vPoint0) < 2*BSP_EPSILON); //!!!!
- }
- }
- }
- }
- /////////////////////////////////////////////////////////////////////
- // BSP tree
- /*
- * Default constructor.
- */
- template<class Type, int iDimensions>
- BSPTree<Type, iDimensions>::BSPTree(void)
- {
- bt_pbnRoot = NULL;
- }
- /*
- * Destructor.
- */
- template<class Type, int iDimensions>
- BSPTree<Type, iDimensions>::~BSPTree(void)
- {
- Destroy();
- }
- /*
- * Constructor with array of polygons oriented inwards.
- */
- template<class Type, int iDimensions>
- BSPTree<Type, iDimensions>::BSPTree(CDynamicArray<BSPPolygon<Type, iDimensions> > &abpoPolygons)
- {
- bt_pbnRoot = NULL;
- Create(abpoPolygons);
- }
- /*
- * Create bsp-subtree from array of polygons oriented inwards.
- */
- template<class Type, int iDimensions>
- BSPNode<Type, iDimensions> *BSPTree<Type, iDimensions>::CreateSubTree(CDynamicArray<BSPPolygon<Type, iDimensions> > &abpoPolygons)
- {
- // local declarations, to fix macro expansion in FOREACHINDYNAMICARRAY
- typedef BSPEdge<Type, iDimensions> edge_t;
- typedef BSPPolygon<Type, iDimensions> polygon_t;
- ASSERT(abpoPolygons.Count()>=1);
- // use first polygon as splitter
- abpoPolygons.Lock();
- BSPPolygon<Type, iDimensions> bpoSplitter = abpoPolygons[0];
- abpoPolygons.Unlock();
- // tags must be valid
- ASSERT(bpoSplitter.bpo_ulPlaneTag!=-1);
- // create two new polygon arrays - back and front
- CDynamicArray<BSPPolygon<Type, iDimensions> > abpoFront, abpoBack;
- // for each polygon in this array
- {FOREACHINDYNAMICARRAY(abpoPolygons, polygon_t, itbpo) {
- BSPPolygon<Type, iDimensions> bpoFront, bpoBack;
- // tags must be valid
- ASSERT(itbpo->bpo_ulPlaneTag!=-1);
- // if the polygon has plane tag same as the tag of the splitter
- if (itbpo->bpo_ulPlaneTag == bpoSplitter.bpo_ulPlaneTag) {
- // they are assumed coplanar, so skip it
- continue;
- }
- // split it by the plane of splitter polygon
- BOOL bOnPlane = BSPCutter<Type, iDimensions>::SplitPolygon(itbpo.Current(),
- bpoSplitter, bpoSplitter.bpo_ulPlaneTag, bpoFront, bpoBack);
- // if the polygon is not coplanar with the splitter
- if (!bOnPlane) {
- // if there are some parts that are front
- if (bpoFront.bpo_abedPolygonEdges.Count()>0) {
- // create a polygon in front array and add all inside parts to it
- BSPPolygon<Type, iDimensions> *pbpo = abpoFront.New(1);
- pbpo->bpo_abedPolygonEdges.MoveArray(bpoFront.bpo_abedPolygonEdges);
- *(Plane<Type, iDimensions> *)pbpo = itbpo.Current();
- pbpo->bpo_ulPlaneTag = itbpo->bpo_ulPlaneTag;
- }
- // if there are some parts that are back
- if (bpoBack.bpo_abedPolygonEdges.Count()>0) {
- // create a polygon in back array and add all outside parts to it
- BSPPolygon<Type, iDimensions> *pbpo = abpoBack.New(1);
- pbpo->bpo_abedPolygonEdges.MoveArray(bpoBack.bpo_abedPolygonEdges);
- *(Plane<Type, iDimensions> *)pbpo = itbpo.Current();
- pbpo->bpo_ulPlaneTag = itbpo->bpo_ulPlaneTag;
- }
- }
- }}
- // free this array (to not consume too much memory)
- abpoPolygons.Clear();
- BSPNode<Type, iDimensions> *pbnFront, *pbnBack;
- // if there is some polygon in front array
- if (abpoFront.Count()>0) {
- // create front subtree using front array
- pbnFront = CreateSubTree(abpoFront);
- // otherwise
- } else {
- // make front node an inside leaf node
- pbnFront = new BSPNode<Type, iDimensions>(BNL_INSIDE);
- }
- // if there is some polygon in back array
- if (abpoBack.Count()>0) {
- // create back subtree using back array
- pbnBack = CreateSubTree(abpoBack);
- // otherwise
- } else {
- // make back node an outside leaf node
- pbnBack = new BSPNode<Type, iDimensions>(BNL_OUTSIDE);
- }
- // make a splitter node with the front and back nodes
- return new BSPNode<Type, iDimensions>(bpoSplitter, bpoSplitter.bpo_ulPlaneTag, *pbnFront, *pbnBack);
- }
- /*
- * Create bsp-tree from array of polygons oriented inwards.
- */
- template<class Type, int iDimensions>
- void BSPTree<Type, iDimensions>::Create(CDynamicArray<BSPPolygon<Type, iDimensions> > &abpoPolygons)
- {
- typedef BSPPolygon<Type, iDimensions> polygon_t; // local declaration, to fix macro expansion in FOREACHINDYNAMICARRAY
- // free eventual existing tree
- Destroy();
- // create the tree using the recursive function
- bt_pbnRoot = CreateSubTree(abpoPolygons);
- // move the tree to array
- MoveNodesToArray();
- }
- /*
- * Destroy bsp-tree.
- */
- template<class Type, int iDimensions>
- void BSPTree<Type, iDimensions>::Destroy(void)
- {
- // if tree is in array
- if (bt_abnNodes.Count()>0) {
- // clear array
- bt_abnNodes.Clear();
- bt_pbnRoot = NULL;
- // if there is some free tree
- } else if (bt_pbnRoot != NULL) {
- // delete it
- bt_pbnRoot->DeleteBSPNodeRecursively();
- bt_pbnRoot = NULL;
- }
- }
- /* Test if a sphere could touch any of inside nodes. (Just a trivial rejection test) */
- template<class Type, int iDimensions>
- FLOAT BSPTree<Type, iDimensions>::TestSphere(const Vector<Type, iDimensions> &vSphereCenter, Type tSphereRadius) const
- {
- if (bt_pbnRoot==NULL) return FALSE;
- // just start recursive testing at root node
- return bt_pbnRoot->TestSphere(vSphereCenter, tSphereRadius);
- }
- /* Test if a box is inside, outside, or intersecting. (Just a trivial rejection test) */
- template<class Type, int iDimensions>
- FLOAT BSPTree<Type, iDimensions>::TestBox(const OBBox<Type> &box) const
- {
- if (bt_pbnRoot==NULL) return FALSE;
- // just start recursive testing at root node
- return bt_pbnRoot->TestBox(box);
- }
- // find minimum/maximum parameters of points on a line that are inside
- template<class Type, int iDimensions>
- void BSPTree<Type, iDimensions>::FindLineMinMax(
- const Vector<Type, iDimensions> &v0,
- const Vector<Type, iDimensions> &v1,
- Type &tMin,
- Type &tMax) const
- {
- // init line
- BSPLine<Type, iDimensions> bl;
- bl.bl_tMin = UpperLimit(Type(0));
- bl.bl_tMax = LowerLimit(Type(0));
- // recursively split it
- bt_pbnRoot->FindLineMinMax(bl, v0, v1, Type(0), Type(1));
- // return the min/max
- tMin = bl.bl_tMin;
- tMax = bl.bl_tMax;
- }
- static INDEX _ctNextIndex;
- /* Move one subtree to array. */
- template<class Type, int iDimensions>
- void BSPTree<Type, iDimensions>::MoveSubTreeToArray(BSPNode<Type, iDimensions> *pbnSubtree)
- {
- // if this is no node
- if (pbnSubtree==NULL) {
- // do nothing
- return;
- }
- // first move all subnodes
- MoveSubTreeToArray(pbnSubtree->bn_pbnFront);
- MoveSubTreeToArray(pbnSubtree->bn_pbnBack);
- // get the node in array
- BSPNode<Type, iDimensions> &bnInArray = bt_abnNodes[_ctNextIndex];
- _ctNextIndex--;
- // copy properties to the array node
- (Plane<Type, iDimensions>&)bnInArray = (Plane<Type, iDimensions>&)*pbnSubtree;
- bnInArray.bn_bnlLocation = pbnSubtree->bn_bnlLocation;
- bnInArray.bn_ulPlaneTag = pbnSubtree->bn_ulPlaneTag;
- // let plane tag hold pointer to node in array
- pbnSubtree->bn_ulPlaneTag = (ULONG)&bnInArray;
- // remap pointers to subnodes
- if (pbnSubtree->bn_pbnFront==NULL) {
- bnInArray.bn_pbnFront = NULL;
- } else {
- bnInArray.bn_pbnFront = (BSPNode<Type, iDimensions>*)pbnSubtree->bn_pbnFront->bn_ulPlaneTag;
- }
- if (pbnSubtree->bn_pbnBack==NULL) {
- bnInArray.bn_pbnBack = NULL;
- } else {
- bnInArray.bn_pbnBack = (BSPNode<Type, iDimensions>*)pbnSubtree->bn_pbnBack->bn_ulPlaneTag;
- }
- }
- /* Count nodes in subtree. */
- template<class Type, int iDimensions>
- INDEX BSPTree<Type, iDimensions>::CountNodes(BSPNode<Type, iDimensions> *pbnSubtree)
- {
- if (pbnSubtree==NULL) {
- return 0;
- } else {
- return 1+
- CountNodes(pbnSubtree->bn_pbnFront)+
- CountNodes(pbnSubtree->bn_pbnBack);
- }
- }
- /* Move all nodes to array. */
- template<class Type, int iDimensions>
- void BSPTree<Type, iDimensions>::MoveNodesToArray(void)
- {
- // if there is no tree
- if (bt_pbnRoot == NULL) {
- // do nothing
- return;
- }
- // count nodes
- INDEX ctNodes = CountNodes(bt_pbnRoot);
- // allocate large enough array
- bt_abnNodes.New(ctNodes);
- // start at the end of array
- _ctNextIndex = ctNodes-1;
- // recusively remap all nodes
- MoveSubTreeToArray(bt_pbnRoot);
- // delete the old nodes
- bt_pbnRoot->DeleteBSPNodeRecursively();
- // first node is always at start of array
- bt_pbnRoot = &bt_abnNodes[0];
- }
- /* Read/write entire bsp tree to disk. */
- template<class Type, int iDimensions>
- void BSPTree<Type, iDimensions>::Read_t(CTStream &strm) // throw char *
- {
- // free eventual existing tree
- Destroy();
- // read current version and size
- INDEX iVersion;
- SLONG slSize;
- strm>>iVersion>>slSize;
- ASSERT(iVersion==1);
- // read count of nodes and create array
- INDEX ctNodes;
- strm>>ctNodes;
- ASSERT(slSize==(SLONG)(sizeof(INDEX)+ctNodes*sizeof(BSPNode<Type, iDimensions>)));
- bt_abnNodes.New(ctNodes);
- // for each node
- for(INDEX iNode=0; iNode<ctNodes; iNode++) {
- BSPNode<Type, iDimensions> &bn = bt_abnNodes[iNode];
- // read it from disk
- strm.Read_t(&(Plane<Type, iDimensions>&)bn, sizeof(Plane<Type, iDimensions>));
- strm>>(INDEX&)bn.bn_bnlLocation;
- INDEX iFront;
- strm>>iFront;
- if (iFront==-1) {
- bn.bn_pbnFront=NULL;
- } else {
- bn.bn_pbnFront = &bt_abnNodes[iFront];
- }
- INDEX iBack;
- strm>>iBack;
- if (iBack==-1) {
- bn.bn_pbnBack=NULL;
- } else {
- bn.bn_pbnBack = &bt_abnNodes[iBack];
- }
- strm>>bn.bn_ulPlaneTag;
- }
- // check end id
- strm.ExpectID_t("BSPE"); // bsp end
- // first node is always at start of array
- if (bt_abnNodes.Count()>0) {
- bt_pbnRoot = &bt_abnNodes[0];
- } else {
- bt_pbnRoot = NULL;
- }
- }
- template<class Type, int iDimensions>
- void BSPTree<Type, iDimensions>::Write_t(CTStream &strm) // throw char *
- {
- INDEX ctNodes = bt_abnNodes.Count();
- // calculate size of chunk to write
- SLONG slSize = sizeof(INDEX)+ctNodes*sizeof(BSPNode<Type, iDimensions>);
- // write current version and size
- strm<<INDEX(1)<<slSize;
- // write count of nodes
- strm<<ctNodes;
- // for each node
- for(INDEX iNode=0; iNode<ctNodes; iNode++) {
- BSPNode<Type, iDimensions> &bn = bt_abnNodes[iNode];
- // write it to disk
- strm.Write_t(&(Plane<Type, iDimensions>&)bn, sizeof(Plane<Type, iDimensions>));
- strm<<(INDEX&)bn.bn_bnlLocation;
- INDEX iFront;
- if (bn.bn_pbnFront==NULL) {
- iFront=-1;
- } else {
- iFront = bt_abnNodes.Index(bn.bn_pbnFront);
- }
- strm<<iFront;
- INDEX iBack;
- if (bn.bn_pbnBack==NULL) {
- iBack=-1;
- } else {
- iBack = bt_abnNodes.Index(bn.bn_pbnBack);
- }
- strm<<iBack;
- strm<<bn.bn_ulPlaneTag;
- }
- // write end id for checking
- strm.WriteID_t("BSPE"); // bsp end
- }
- // instantiate template classes implemented here for needed types
- #pragma warning (disable: 4660) // if already instantiated by some class
- // remove templates
- template DOUBLEbspvertex3D;
- template DOUBLEbspvertexcontainer3D;
- template DOUBLEbspedge3D;
- template DOUBLEbspnode3D;
- template DOUBLEbsppolygon3D;
- template DOUBLEbsptree3D;
- template DOUBLEbspcutter3D;
- template FLOATbspvertex3D;
- template FLOATbspvertexcontainer3D;
- template FLOATbspedge3D;
- template FLOATbspnode3D;
- template FLOATbsppolygon3D;
- template FLOATbsptree3D;
- template FLOATbspcutter3D;
- #pragma warning (default: 4660)
|