| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616 |
- /*
- ** Command & Conquer Generals(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** 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, see <http://www.gnu.org/licenses/>.
- */
- /***********************************************************************************************
- *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
- ***********************************************************************************************
- * *
- * Project Name : WWMath *
- * *
- * $Archive:: /Commando/Code/wwmath/aabtreecull.cpp $*
- * *
- * Author:: Greg Hjelstrom *
- * *
- * $Modtime:: 8/26/01 2:18p $*
- * *
- * $Revision:: 25 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include "aabtreecull.h"
- #include "chunkio.h"
- #include "iostruct.h"
- #include <string.h>
- #include "sphere.h"
- #include "colmath.h"
- #include "colmathinlines.h"
- /*
- ** Declare the pools
- */
- DEFINE_AUTO_POOL(AABTreeLinkClass,256);
- DEFINE_AUTO_POOL(AABTreeNodeClass,256);
- /*
- ** Current version of the file format
- */
- const uint32 AABTREE_CURRENT_VERSION = 0x00010000;
- /*
- ** Chunk Id's used by the aabtree code to save itself into a file
- */
- enum
- {
- AABTREE_CHUNK_VERSION = 0x00000001, // version wrapper, contains 32bit version #
- AABTREE_CHUNK_AABNODE = 0x00000101, // generic aab-node wrapper
- AABTREE_CHUNK_AABNODE_INFO, // OBSOLETE! generic aab-node definition (IOAABNodeStruct)
- AABTREE_CHUNK_AABNODE_CONTENTS, // wrapper around contents of the node
- AABTREE_CHUNK_AABNODE_VARIABLES, // wrapper around variables for a node
- AABTREE_CHUNK_NODE_INDEX = 0x00000200, // wrapper around the node index for an object
- AABTREE_VARIABLE_NODESTRUCT = 0x00,
- AABTREE_VARIABLE_USERDATA
- };
- /*
- ** IOAABNodeStruct
- ** Data structure for the contents of a node in the AAB-Tree
- */
- #define AABNODE_ATTRIBUTE_FRONT_CHILD 0x00000001
- #define AABNODE_ATTRIBUTE_BACK_CHILD 0x00000002
- struct IOAABNodeStruct
- {
- IOVector3Struct Center;
- IOVector3Struct Extent;
- uint32 Attributes;
- };
- /*************************************************************************
- **
- ** Utility functions for walking the object list in an AABTree Node
- **
- *************************************************************************/
- static inline CullableClass * get_first_object(AABTreeNodeClass * node)
- {
- return node->Object;
- }
- static inline CullableClass * get_next_object(CullableClass * obj)
- {
- return ((AABTreeLinkClass *)obj->Get_Cull_Link())->NextObject;
- }
- /*************************************************************************
- **
- ** AABTreeCullSystemClass Implementation
- **
- *************************************************************************/
- AABTreeCullSystemClass::AABTreeCullSystemClass(void) :
- ObjectCount(0),
- NodeCount(0),
- IndexedNodes(NULL)
- {
- RootNode = new AABTreeNodeClass;
- Re_Index_Nodes();
- }
- AABTreeCullSystemClass::~AABTreeCullSystemClass(void)
- {
- // Delete all links and release-ref all cullables:
- int nidx;
- for (nidx = 0; nidx < NodeCount; nidx++) {
- while(IndexedNodes[nidx]->Object) Remove_Object_Internal(IndexedNodes[nidx]->Object);
- }
- // Delete node tree (deleting the root recursively deletes all nodes)
- delete RootNode;
- // Delete indexed node pointer array
- if (IndexedNodes) {
- delete[] IndexedNodes;
- IndexedNodes = NULL;
- }
- }
- void AABTreeCullSystemClass::Add_Object_Internal(CullableClass * obj,int node_index)
- {
- WWASSERT_PRINT
- (
- (obj->Get_Culling_System() == NULL),
- "AABTreeCullSystemClass::Add -- Object is already in another culling system!\n"
- );
- AABTreeLinkClass * new_link = new AABTreeLinkClass(this);
- obj->Set_Cull_Link(new_link);
- if (node_index == -1) {
- Add_Object_Recursive(RootNode,obj);
- } else {
- WWASSERT(node_index < NodeCount);
- IndexedNodes[node_index]->Add_Object(obj,false);
- ObjectCount++;
- }
- obj->Add_Ref();
- }
- void AABTreeCullSystemClass::Remove_Object_Internal(CullableClass * obj)
- {
- WWASSERT(obj);
- WWASSERT(obj->Get_Culling_System() == this);
- AABTreeLinkClass * link = (AABTreeLinkClass *)obj->Get_Cull_Link();
- WWASSERT(link);
- AABTreeNodeClass * node = link->Node;
- WWASSERT(node);
- node->Remove_Object(obj);
- link->Set_Culling_System(NULL);
- delete link;
- obj->Set_Cull_Link(NULL);
-
- ObjectCount--;
- WWASSERT(ObjectCount >= 0);
- obj->Release_Ref();
- }
- void AABTreeCullSystemClass::Update_Culling(CullableClass * obj)
- {
- WWASSERT(obj);
- WWASSERT(obj->Get_Culling_System() == this);
- // unlink it from the node it is currently in
- AABTreeLinkClass * link = (AABTreeLinkClass *)obj->Get_Cull_Link();
- WWASSERT(link);
- AABTreeNodeClass * node = link->Node;
- WWASSERT(node);
- node->Remove_Object(obj);
- // decrement the object counter, the node can't
- // decrement it for us...
- ObjectCount--;
- // drop it into the tree again
- Add_Object_Recursive(RootNode,obj);
- }
- void AABTreeCullSystemClass::Collect_Objects(const Vector3 & point)
- {
- Collect_Objects_Recursive(RootNode,point);
- }
- void AABTreeCullSystemClass::Collect_Objects(const AABoxClass & box)
- {
- Collect_Objects_Recursive(RootNode,box);
- }
- void AABTreeCullSystemClass::Collect_Objects(const OBBoxClass & box)
- {
- Collect_Objects_Recursive(RootNode,box);
- }
- void AABTreeCullSystemClass::Collect_Objects(const FrustumClass & frustum)
- {
- Collect_Objects_Recursive(RootNode,frustum,0);
- }
- void AABTreeCullSystemClass::Collect_Objects(const SphereClass & sphere)
- {
- Collect_Objects_Recursive(RootNode,sphere);
- }
- int AABTreeCullSystemClass::Partition_Node_Count(void) const
- {
- return Partition_Node_Count_Recursive(RootNode);
- }
- int AABTreeCullSystemClass::Partition_Tree_Depth(void) const
- {
- int get_max_depth = 0;
- Partition_Tree_Depth_Recursive(RootNode,0,get_max_depth);
- return get_max_depth;
- }
- int AABTreeCullSystemClass::Object_Count(void) const
- {
- return ObjectCount;
- }
- int AABTreeCullSystemClass::Partition_Node_Count_Recursive(AABTreeNodeClass * node) const
- {
- int curcount = 1;
- if (node->Front) {
- curcount += Partition_Node_Count_Recursive(node->Front);
- }
- if (node->Back) {
- curcount += Partition_Node_Count_Recursive(node->Back);
- }
- return curcount;
- }
- void AABTreeCullSystemClass::Partition_Tree_Depth_Recursive(AABTreeNodeClass * node,int cur_depth,int & max_depth) const
- {
- cur_depth++;
- if (cur_depth > max_depth) {
- max_depth = cur_depth;
- }
- if (node->Front) {
- Partition_Tree_Depth_Recursive(node->Front,cur_depth,max_depth);
- }
- if (node->Back) {
- Partition_Tree_Depth_Recursive(node->Back,cur_depth,max_depth);
- }
- }
- void AABTreeCullSystemClass::Add_Object_Recursive(AABTreeNodeClass * node,CullableClass * obj)
- {
- // order the children in terms of size
- AABTreeNodeClass * big_child = node->Front;
- AABTreeNodeClass * small_child = node->Back;
- if (big_child && small_child && (big_child->Compute_Volume() < small_child->Compute_Volume())) {
- AABTreeNodeClass * tmp = big_child;
- big_child = small_child;
- small_child = tmp;
- }
-
- // Can we fit in the smaller child?
- if (small_child && small_child->Box.Contains(obj->Get_Cull_Box())) {
- Add_Object_Recursive(small_child,obj);
- return;
- }
- // Can we fit in the bigger child?
- if (big_child && big_child->Box.Contains(obj->Get_Cull_Box())) {
- Add_Object_Recursive(big_child,obj);
- return;
- }
- // Ok, we have to fit in this node.
- node->Add_Object(obj);
- ObjectCount++;
- }
- void AABTreeCullSystemClass::Add_Loaded_Object(AABTreeNodeClass * node,CullableClass * obj)
- {
- WWASSERT(node);
- WWASSERT(obj);
- WWASSERT_PRINT
- (
- (obj->Get_Culling_System() == NULL),
- "AABTreeCullSystemClass::Add_Loaded_Object -- Object is already in another culling system!\n"
- );
- AABTreeLinkClass * new_link = new AABTreeLinkClass(this);
- obj->Set_Cull_Link(new_link);
- node->Add_Object(obj);
- ObjectCount++;
- obj->Add_Ref();
- }
- void AABTreeCullSystemClass::Re_Partition(void)
- {
- /*
- ** transfer all objects to a temporary node
- */
- AABTreeNodeClass * dummy_node = new AABTreeNodeClass;
- RootNode->Transfer_Objects(dummy_node);
- /*
- ** delete the old tree and make the dummy node the new root
- */
- delete RootNode;
- RootNode = dummy_node;
- /*
- ** partition the objects
- */
- RootNode->Partition();
- /*
- ** re-index the nodes
- */
- Re_Index_Nodes();
- /*
- ** reset the statistics
- */
- Reset_Statistics();
- }
- void AABTreeCullSystemClass::Re_Partition(const AABoxClass & bounds,SimpleDynVecClass<AABoxClass> & boxes)
- {
- /*
- ** transfer all objects to a temporary node
- */
- AABTreeNodeClass * dummy_node = new AABTreeNodeClass;
- RootNode->Transfer_Objects(dummy_node);
- /*
- ** delete the old tree
- */
- delete RootNode;
- /*
- ** allocate a new root node and tell it to partition the given array of boxes
- */
- RootNode = new AABTreeNodeClass;
- RootNode->Partition(bounds,boxes);
- /*
- ** re-index the nodes
- */
- Re_Index_Nodes();
- /*
- ** reset statistics
- */
- Reset_Statistics();
- /*
- ** re-insert all objects and delete the temporary node
- */
- dummy_node->Box.Extent.Set(0,0,0);
- CullableClass * obj = get_first_object(dummy_node);
- while (obj != NULL) {
- Update_Culling(obj);
- obj = get_first_object(dummy_node);
- }
- delete dummy_node;
- /*
- ** Modify the root node so that any object can be added into the tree
- */
- RootNode->Box.Extent.Set(FLT_MAX,FLT_MAX,FLT_MAX);
- }
- void AABTreeCullSystemClass::Update_Bounding_Boxes(void)
- {
- Update_Bounding_Boxes_Recursive(RootNode);
- }
- const AABoxClass & AABTreeCullSystemClass::Get_Bounding_Box(void)
- {
- WWASSERT(RootNode);
- return RootNode->Box;
- }
- void AABTreeCullSystemClass::Get_Node_Bounds(int node_id,AABoxClass * set_bounds)
- {
- if ((node_id >= 0) && (node_id < NodeCount)) {
- *set_bounds = IndexedNodes[node_id]->Box;
- } else {
- *set_bounds = IndexedNodes[0]->Box;
- }
- }
- void AABTreeCullSystemClass::Reset_Statistics(void)
- {
- Stats.NodeCount = NodeCount;
- Stats.NodesAccepted = 0;
- Stats.NodesTriviallyAccepted = 0;
- Stats.NodesRejected = 0;
- }
- const AABTreeCullSystemClass::StatsStruct & AABTreeCullSystemClass::Get_Statistics(void)
- {
- return Stats;
- }
- void AABTreeCullSystemClass::Collect_Objects_Recursive(AABTreeNodeClass * node)
- {
- /*
- ** Collect any objects in this node
- */
- if (node->Object) {
- CullableClass * obj = get_first_object(node);
- while (obj) {
- Add_To_Collection(obj);
- obj = get_next_object(obj);
- }
- }
- /*
- ** Statistics
- */
- NODE_TRIVIALLY_ACCEPTED();
- /*
- ** Descend into the children
- */
- if (node->Back) {
- Collect_Objects_Recursive(node->Back);
- }
- if (node->Front) {
- Collect_Objects_Recursive(node->Front);
- }
- }
- void AABTreeCullSystemClass::Collect_Objects_Recursive(AABTreeNodeClass * node,const Vector3 & point)
- {
- /*
- ** Is the point inside this volume?
- */
- if (node->Box.Contains(point) == false) {
- NODE_REJECTED();
- return;
- }
- NODE_ACCEPTED();
- /*
- ** Collect any objects in this node
- */
- if (node->Object) {
- CullableClass * obj = get_first_object(node);
- while (obj) {
- if (obj->Get_Cull_Box().Contains(point)) {
- Add_To_Collection(obj);
- }
- obj = get_next_object(obj);
- }
- }
- /*
- ** Descend into the children
- */
- if (node->Back) {
- Collect_Objects_Recursive(node->Back,point);
- }
- if (node->Front) {
- Collect_Objects_Recursive(node->Front,point);
- }
- }
- void AABTreeCullSystemClass::Collect_Objects_Recursive(AABTreeNodeClass * node,const AABoxClass & box)
- {
- /*
- ** Cull the given box against the bounding volume of this node
- ** If it is culled, stop descending the tree. If the current node is
- ** completely contained inside the given box, jump into the collection function
- ** that doesn't do any more volume checking...
- */
- CollisionMath::OverlapType overlap = CollisionMath::Overlap_Test(box,node->Box);
- if (overlap == CollisionMath::OUTSIDE) {
- NODE_REJECTED();
- return;
- } else if (overlap == CollisionMath::INSIDE) {
- Collect_Objects_Recursive(node);
- return;
- }
-
- NODE_ACCEPTED();
- /*
- ** Test any objects in this node
- */
- if (node->Object) {
- CullableClass * obj = get_first_object(node);
- while (obj) {
- if (CollisionMath::Overlap_Test(box,obj->Get_Cull_Box()) != CollisionMath::OUTSIDE) {
- Add_To_Collection(obj);
- }
- obj = get_next_object(obj);
- }
- }
- /*
- ** Recurse into any children
- */
- if (node->Back) {
- Collect_Objects_Recursive(node->Back,box);
- }
- if (node->Front) {
- Collect_Objects_Recursive(node->Front,box);
- }
- }
- void AABTreeCullSystemClass::Collect_Objects_Recursive(AABTreeNodeClass * node,const OBBoxClass & box)
- {
- /*
- ** Cull the given box against the bounding volume of this node
- ** If it is culled, stop descending the tree. If the current node is
- ** completely contained inside the given box, jump into the collection function
- ** that doesn't do any more volume checking...
- */
- CollisionMath::OverlapType overlap = CollisionMath::Overlap_Test(box,node->Box);
- if (overlap == CollisionMath::OUTSIDE) {
- NODE_REJECTED();
- return;
- } else if (overlap == CollisionMath::INSIDE) {
- Collect_Objects_Recursive(node);
- return;
- }
-
- NODE_ACCEPTED();
- /*
- ** Test any objects in this node
- */
- if (node->Object) {
- CullableClass * obj = get_first_object(node);
- while (obj) {
- if (CollisionMath::Overlap_Test(box,obj->Get_Cull_Box()) != CollisionMath::OUTSIDE) {
- Add_To_Collection(obj);
- }
- obj = get_next_object(obj);
- }
- }
- /*
- ** Recurse into any children
- */
- if (node->Back) {
- Collect_Objects_Recursive(node->Back,box);
- }
- if (node->Front) {
- Collect_Objects_Recursive(node->Front,box);
- }
- }
- void AABTreeCullSystemClass::Collect_Objects_Recursive
- (
- AABTreeNodeClass * node,
- const FrustumClass & frustum,
- int planes_passed
- )
- {
- /*
- ** Cull the bounding volume of this node against the frustum.
- ** If it is culled, stop descending the tree.
- */
- CollisionMath::OverlapType overlap = CollisionMath::Overlap_Test(frustum,node->Box,planes_passed);
- if (overlap == CollisionMath::OUTSIDE) {
- NODE_REJECTED();
- return;
- } else if (overlap == CollisionMath::INSIDE) {
- Collect_Objects_Recursive(node);
- return;
- }
- NODE_ACCEPTED();
-
- /*
- ** Test any objects in this node
- */
- if (node->Object) {
- CullableClass * obj = get_first_object(node);
- while (obj) {
- if (CollisionMath::Overlap_Test(frustum,obj->Get_Cull_Box()) != CollisionMath::OUTSIDE) {
- Add_To_Collection(obj);
- }
- obj = get_next_object(obj);
- }
- }
- /*
- ** Recurse into any children
- */
- if (node->Back) {
- Collect_Objects_Recursive(node->Back,frustum,planes_passed);
- }
- if (node->Front) {
- Collect_Objects_Recursive(node->Front,frustum,planes_passed);
- }
- }
- void AABTreeCullSystemClass::Collect_Objects_Recursive(AABTreeNodeClass * node,const SphereClass & sphere)
- {
- /*
- ** Is the point inside this volume?
- */
- if (CollisionMath::Overlap_Test (node->Box, sphere) == CollisionMath::OUTSIDE) {
- NODE_REJECTED();
- return;
- }
- NODE_ACCEPTED();
- /*
- ** Collect any objects in this node
- */
- if (node->Object) {
- CullableClass * obj = get_first_object(node);
- while (obj) {
- if (CollisionMath::Overlap_Test (obj->Get_Cull_Box(), sphere) != CollisionMath::OUTSIDE) {
- Add_To_Collection(obj);
- }
- obj = get_next_object(obj);
- }
- }
- /*
- ** Descend into the children
- */
- if (node->Back) {
- Collect_Objects_Recursive(node->Back,sphere);
- }
- if (node->Front) {
- Collect_Objects_Recursive(node->Front,sphere);
- }
- }
- void AABTreeCullSystemClass::Update_Bounding_Boxes_Recursive(AABTreeNodeClass * node)
- {
- MinMaxAABoxClass minmaxbox(node->Box);
- /*
- ** Update child boxes first and ensure that we bound them
- */
- if (node->Front) {
- Update_Bounding_Boxes_Recursive(node->Front);
- minmaxbox.Add_Box(node->Front->Box);
- }
- if (node->Back) {
- Update_Bounding_Boxes_Recursive(node->Back);
- minmaxbox.Add_Box(node->Back->Box);
- }
- /*
- ** Make sure we bound our contained objects
- */
- if (node->Object) {
- CullableClass * obj = get_first_object(node);
- while (obj) {
- minmaxbox.Add_Box(obj->Get_Cull_Box());
- obj = get_next_object(obj);
- }
- }
- node->Box.Init_Min_Max(minmaxbox.MinCorner,minmaxbox.MaxCorner);
- }
- void AABTreeCullSystemClass::Load(ChunkLoadClass & cload)
- {
- WWASSERT_PRINT(Object_Count() == 0, "Remove all objects from AAB-Culling system before loading!\n");
-
- delete RootNode;
- RootNode = new AABTreeNodeClass;
- // The first chunk should be a version chunk
- cload.Open_Chunk();
- if (cload.Cur_Chunk_ID() != AABTREE_CHUNK_VERSION) {
- WWDEBUG_ERROR(("Attempting to read an obsolete AAB-Tree!"));
- cload.Close_Chunk();
- return;
- }
- // read in the version and verify that it is the current version
- uint32 version;
- cload.Read(&version,sizeof(version));
- if (version != AABTREE_CURRENT_VERSION) {
- WWDEBUG_ERROR(("Attempting to read an obsolete AAB-Tree!"));
- cload.Close_Chunk();
- return;
- }
- cload.Close_Chunk();
- // read in the tree
- Load_Nodes(RootNode,cload);
- // re-index all nodes
- Re_Index_Nodes();
- // reset the statistics
- Reset_Statistics();
- }
- void AABTreeCullSystemClass::Load_Nodes(AABTreeNodeClass * node,ChunkLoadClass & cload)
- {
- // Open the node description
- cload.Open_Chunk();
- WWASSERT(cload.Cur_Chunk_ID() == AABTREE_CHUNK_AABNODE);
-
- // Load the node description.
- // Older files will contain a chunk named AABTREE_CHUNK_AABNODE_INFO while newer
- // files will contain AABTREE_CHUNK_AABNODE_VARIABLES which contains the IOAABNodeStruct
- // in a micro-chunk.
- IOAABNodeStruct node_desc;
- memset(&node_desc,0,sizeof(IOAABNodeStruct));
-
- cload.Open_Chunk();
- if (cload.Cur_Chunk_ID() == AABTREE_CHUNK_AABNODE_INFO) {
- // Loading the legacy format...
- WWASSERT(cload.Cur_Chunk_ID() == AABTREE_CHUNK_AABNODE_INFO);
- cload.Read(&node_desc,sizeof(node_desc));
- } else if (cload.Cur_Chunk_ID() == AABTREE_CHUNK_AABNODE_VARIABLES) {
-
- // Loading the new format, contains micro chunks...
- while (cload.Open_Micro_Chunk()) {
- switch(cload.Cur_Micro_Chunk_ID()) {
- READ_MICRO_CHUNK(cload,AABTREE_VARIABLE_NODESTRUCT,node_desc);
- READ_MICRO_CHUNK(cload,AABTREE_VARIABLE_USERDATA,node->UserData);
- }
- cload.Close_Micro_Chunk();
- }
- }
- cload.Close_Chunk();
- // Initialize the node bounds.
- node->Box.Center.X = node_desc.Center.X;
- node->Box.Center.Y = node_desc.Center.Y;
- node->Box.Center.Z = node_desc.Center.Z;
- node->Box.Extent.X = node_desc.Extent.X;
- node->Box.Extent.Y = node_desc.Extent.Y;
- node->Box.Extent.Z = node_desc.Extent.Z;
- // Load the contents of the node.
- cload.Open_Chunk();
- WWASSERT(cload.Cur_Chunk_ID() == AABTREE_CHUNK_AABNODE_CONTENTS);
- Load_Node_Contents(node,cload);
- cload.Close_Chunk();
- // Close the node description
- cload.Close_Chunk();
- // if we are supposed to have a front child, load it
- if (node_desc.Attributes & AABNODE_ATTRIBUTE_FRONT_CHILD) {
- WWASSERT(node->Front == NULL);
- node->Front = new AABTreeNodeClass();
- node->Front->Parent = node;
- Load_Nodes(node->Front,cload);
- }
-
- // if we have a back child, load it
- if (node_desc.Attributes & AABNODE_ATTRIBUTE_BACK_CHILD) {
- WWASSERT(node->Back == NULL);
- node->Back = new AABTreeNodeClass();
- node->Back->Parent = node;
- Load_Nodes(node->Back,cload);
- }
- }
- void AABTreeCullSystemClass::Save(ChunkSaveClass & csave)
- {
- csave.Begin_Chunk(AABTREE_CHUNK_VERSION);
- uint32 version = AABTREE_CURRENT_VERSION;
- csave.Write(&version,sizeof(uint32));
- csave.End_Chunk();
- Save_Nodes(RootNode,csave);
- }
- void AABTreeCullSystemClass::Save_Nodes(AABTreeNodeClass * node,ChunkSaveClass & csave)
- {
- WWASSERT(node);
- csave.Begin_Chunk(AABTREE_CHUNK_AABNODE);
- csave.Begin_Chunk(AABTREE_CHUNK_AABNODE_VARIABLES);
- IOAABNodeStruct node_desc;
- memset(&node_desc,0,sizeof(node_desc));
- node_desc.Center.X = node->Box.Center.X;
- node_desc.Center.Y = node->Box.Center.Y;
- node_desc.Center.Z = node->Box.Center.Z;
- node_desc.Extent.X = node->Box.Extent.X;
- node_desc.Extent.Y = node->Box.Extent.Y;
- node_desc.Extent.Z = node->Box.Extent.Z;
- if (node->Front) {
- node_desc.Attributes |= AABNODE_ATTRIBUTE_FRONT_CHILD;
- }
- if (node->Back) {
- node_desc.Attributes |= AABNODE_ATTRIBUTE_BACK_CHILD;
- }
-
- WRITE_MICRO_CHUNK(csave,AABTREE_VARIABLE_NODESTRUCT,node_desc);
- WRITE_MICRO_CHUNK(csave,AABTREE_VARIABLE_USERDATA,node->UserData);
- csave.End_Chunk();
- csave.Begin_Chunk(AABTREE_CHUNK_AABNODE_CONTENTS);
- Save_Node_Contents(node,csave);
- csave.End_Chunk();
- csave.End_Chunk();
- if (node->Front) {
- Save_Nodes(node->Front,csave);
- }
- if (node->Back) {
- Save_Nodes(node->Back,csave);
- }
- }
- void AABTreeCullSystemClass::Load_Object_Linkage(ChunkLoadClass & cload,CullableClass * obj)
- {
- uint32 index;
- cload.Open_Chunk();
- WWASSERT(cload.Cur_Chunk_ID() == AABTREE_CHUNK_NODE_INDEX);
- cload.Read(&index,sizeof(index));
- cload.Close_Chunk();
- Add_Object_Internal(obj,index);
- }
- void AABTreeCullSystemClass::Save_Object_Linkage(ChunkSaveClass & csave,CullableClass * obj)
- {
- WWASSERT(obj);
- WWASSERT(obj->Get_Culling_System() == this);
- AABTreeLinkClass * link = (AABTreeLinkClass *)obj->Get_Cull_Link();
- WWASSERT(link);
- AABTreeNodeClass * node = link->Node;
- WWASSERT(node);
- uint32 index = node->Index;
- csave.Begin_Chunk(AABTREE_CHUNK_NODE_INDEX);
- csave.Write(&index,sizeof(index));
- csave.End_Chunk();
- }
- void AABTreeCullSystemClass::Re_Index_Nodes(void)
- {
- if (IndexedNodes != NULL) {
- delete[] IndexedNodes;
- IndexedNodes = NULL;
- }
- NodeCount = Partition_Node_Count();
- WWASSERT(NodeCount > 0);
- IndexedNodes = new AABTreeNodeClass *[NodeCount];
-
- int counter = 0;
- Re_Index_Nodes_Recursive(RootNode,counter);
- WWASSERT(counter == NodeCount);
- }
- void AABTreeCullSystemClass::Re_Index_Nodes_Recursive(AABTreeNodeClass * node,int & counter)
- {
- node->Index = counter;
- IndexedNodes[counter] = node;
- counter++;
- if (node->Front) {
- Re_Index_Nodes_Recursive(node->Front,counter);
- }
- if (node->Back) {
- Re_Index_Nodes_Recursive(node->Back,counter);
- }
- }
- /*************************************************************************
- **
- ** AABTreeNodeClass Implementation
- **
- *************************************************************************/
- AABTreeNodeClass::AABTreeNodeClass(void) :
- Index(0),
- Box(Vector3(0,0,0),Vector3(0,0,0)),
- Parent(NULL),
- Front(NULL),
- Back(NULL),
- Object(NULL),
- UserData(0)
- {
- }
- AABTreeNodeClass::~AABTreeNodeClass(void)
- {
- // objects should be removed before deleting the partition tree
- WWASSERT(Object == NULL);
-
- // delete our children
- if (Front) {
- delete Front;
- Front = NULL;
- }
- if (Back) {
- delete Back;
- Back = NULL;
- }
- }
- void AABTreeNodeClass::Compute_Bounding_Box(void)
- {
- /*
- ** make the children update their boxes first
- */
- if (Front) {
- Front->Compute_Bounding_Box();
- }
- if (Back) {
- Back->Compute_Bounding_Box();
- }
- Compute_Local_Bounding_Box();
- }
- void AABTreeNodeClass::Compute_Local_Bounding_Box(void)
- {
- /*
- ** Now make sure we bound our children
- */
- MinMaxAABoxClass box(Vector3(FLT_MAX,FLT_MAX,FLT_MAX),Vector3(-FLT_MAX,-FLT_MAX,-FLT_MAX));
-
- if (Front) {
- box.Add_Box(Front->Box);
- }
- if (Back) {
- box.Add_Box(Back->Box);
- }
- /*
- ** bound the objects in this node
- */
- CullableClass * obj = Object;
- while (obj) {
- box.Add_Box(obj->Get_Cull_Box());
- AABTreeLinkClass * link = (AABTreeLinkClass *)obj->Get_Cull_Link();
- obj = link->NextObject;
- }
- Box.Init(box);
- }
- float AABTreeNodeClass::Compute_Volume(void)
- {
- return Box.Volume();
- }
- void AABTreeNodeClass::Add_Object(CullableClass * obj,bool update_bounds)
- {
- AABTreeLinkClass * link = (AABTreeLinkClass *)obj->Get_Cull_Link();
- WWASSERT(link);
-
- link->Node = this;
- link->NextObject = Object;
- Object = obj;
- if (update_bounds) {
- // if this is the only object and we have no children, just copy
- // the object's bounding box, otherwise, add it to what we have
- if ((Object_Count() == 1) && (Front == NULL) && (Back == NULL)) {
- Box = obj->Get_Cull_Box();
- } else {
- Box.Add_Box(obj->Get_Cull_Box());
- }
- }
- }
- void AABTreeNodeClass::Remove_Object(CullableClass * obj)
- {
- WWASSERT(obj);
- // find the given object in our linked list
- CullableClass * prevobj = NULL;
- CullableClass * curobj = Object;
-
- while (curobj) {
- AABTreeLinkClass * link = (AABTreeLinkClass *)curobj->Get_Cull_Link();
- if (curobj == obj) {
- // found the object, unlink it.
- if (prevobj) {
- AABTreeLinkClass * prevlink = (AABTreeLinkClass *)prevobj->Get_Cull_Link();
- prevlink->NextObject = link->NextObject;
- } else {
- Object = link->NextObject;
- }
- link->NextObject = NULL;
- link->Node = NULL;
- return;
- }
- // move to the next object
- prevobj = curobj;
- curobj = link->NextObject;
- }
- }
- void AABTreeNodeClass::Transfer_Objects(AABTreeNodeClass * dummy_node)
- {
- // unlink all of our objects, relinking them to the dummy_node
- while (Object) {
- CullableClass * obj = Object;
- Remove_Object(obj);
- dummy_node->Add_Object(obj);
- }
- // do the same with our children
- if (Front) {
- Front->Transfer_Objects(dummy_node);
- }
-
- if (Back) {
- Back->Transfer_Objects(dummy_node);
- }
- }
- int AABTreeNodeClass::Object_Count(void)
- {
- CullableClass * obj = Object;
- int count = 0;
- while (obj) {
- count++;
- obj = ((AABTreeLinkClass *)obj->Get_Cull_Link())->NextObject;
- }
- return count;
- }
- CullableClass * AABTreeNodeClass::Peek_Object(int index)
- {
- int count = 0;
- CullableClass * obj = Object;
- WWASSERT(obj != NULL);
- while (obj && (count != index)) {
- count++;
- obj = ((AABTreeLinkClass *)obj->Get_Cull_Link())->NextObject;
- }
- WWASSERT(count == index);
- return obj;
- }
- /******************************************************************************************
- **
- ** Partitioning code which partitions the objects in the tree and passes them into
- ** the new children
- **
- ******************************************************************************************/
- void AABTreeNodeClass::Partition(void)
- {
- /*
- ** if we're down to only 2 objects, we're done
- */
- int obj_count = Object_Count();
- if (obj_count <= 2) return;
- /*
- ** Create an array of the bounding boxes of our objects
- */
- SimpleDynVecClass<AABoxClass> boxes(obj_count);
- CullableClass * obj = Object;
- while (obj != NULL) {
- boxes.Add(obj->Get_Cull_Box());
- obj = get_next_object(obj);
- }
- /*
- ** Select and assign the splitting plane
- ** De-allocate the array of boxes to conserve memory
- */
- SplitChoiceStruct sc;
- Select_Splitting_Plane(&sc,boxes);
- boxes.Resize(0);
-
- /*
- ** If there was no good split, just leave all of
- ** the objects in this node
- */
- if (sc.Cost == FLT_MAX) {
- return;
- }
- /*
- ** Split the tiles
- */
- AABTreeNodeClass * front = new AABTreeNodeClass;
- AABTreeNodeClass * back = new AABTreeNodeClass;
- Split_Objects(sc,front,back);
- /*
- ** Build a front tree if necessary.
- */
- if (front->Object_Count() > 0) {
- Front = front;
- Front->Parent = this;
- Front->Partition();
- } else {
- delete front;
- front = NULL;
- }
-
- /*
- ** Build a back tree if necessary.
- */
- if (back->Object_Count() > 0) {
- Back = back;
- Back->Parent = this;
- Back->Partition();
- } else {
- delete back;
- back = NULL;
- }
- }
- void AABTreeNodeClass::Split_Objects(const AABTreeNodeClass::SplitChoiceStruct & sc,AABTreeNodeClass * front,AABTreeNodeClass * back)
- {
- // This function assumes that this node is a leaf
- WWASSERT(Front == NULL);
- WWASSERT(Back == NULL);
- WWASSERT(Object_Count() == sc.FrontCount + sc.BackCount);
- int fcount = 0;
- int bcount = 0;
-
- // unlink all of our objects, relinking them to the appropriate node
- while (Object) {
-
- // pull the object out of this node
- CullableClass * obj = Object;
- Remove_Object(Object);
-
- // decide which node to add the object to,
- // NOTE: we have to use the same convention as Compute_Score!
- const AABoxClass & box = obj->Get_Cull_Box();
- if (CollisionMath::Overlap_Test(sc.Plane,box.Center) == CollisionMath::FRONT) {
- front->Add_Object(obj);
- fcount++;
- } else {
- back->Add_Object(obj);
- bcount++;
- }
- }
- // copy the bounding boxes
- front->Box = sc.FrontBox;
- front->Box.Extent += Vector3(WWMATH_EPSILON,WWMATH_EPSILON,WWMATH_EPSILON);
- back->Box = sc.BackBox;
- back->Box.Extent += Vector3(WWMATH_EPSILON,WWMATH_EPSILON,WWMATH_EPSILON);
- // when we are all done, the counts should match.
- WWASSERT(fcount == sc.FrontCount);
- WWASSERT(bcount == sc.BackCount);
- }
- /******************************************************************************************
- **
- ** Partitioning code which generates the tree based on a set of input boxes
- **
- ******************************************************************************************/
- void AABTreeNodeClass::Partition(const AABoxClass & bounds,SimpleDynVecClass<AABoxClass> & boxes)
- {
- Box = bounds;
- /*
- ** if we're down to only 1 box, we're done
- */
- if (boxes.Count() <= 1) return;
- /*
- ** Select and assign the splitting plane
- */
- SplitChoiceStruct sc;
- Select_Splitting_Plane(&sc,boxes);
-
- /*
- ** If there was no good split, just leave all of
- ** the objects in this node
- */
- if (sc.Cost == FLT_MAX) {
- return;
- }
- /*
- ** Split the boxes
- ** Deallocate the input box array to conserve RAM
- */
- SimpleDynVecClass<AABoxClass> frontboxes(sc.FrontCount);
- SimpleDynVecClass<AABoxClass> backboxes(sc.BackCount);
- Split_Boxes(sc,boxes,frontboxes,backboxes);
- boxes.Delete_All();
- /*
- ** Build a front tree if necessary.
- */
- if (frontboxes.Count() > 0) {
- Front = new AABTreeNodeClass;
- Front->Parent = this;
- Front->Partition(sc.FrontBox,frontboxes);
- } else {
- Front = NULL;
- }
-
- /*
- ** Build a back tree if necessary.
- */
- if (backboxes.Count() > 0) {
- Back = new AABTreeNodeClass;
- Back->Parent = this;
- Back->Partition(sc.BackBox,backboxes);
- } else {
- Back = NULL;
- }
- }
- void AABTreeNodeClass::Split_Boxes
- (
- const AABTreeNodeClass::SplitChoiceStruct & sc,
- SimpleDynVecClass<AABoxClass> & boxes,
- SimpleDynVecClass<AABoxClass> & frontboxes,
- SimpleDynVecClass<AABoxClass> & backboxes
- )
- {
- WWASSERT(boxes.Count() == sc.FrontCount + sc.BackCount);
- // copy each box in the input array into the appropriate output array
- for (int i=0; i<boxes.Count(); i++) {
-
- const AABoxClass & box = boxes[i];
- if (CollisionMath::Overlap_Test(sc.Plane,box.Center) == CollisionMath::FRONT) {
- frontboxes.Add(box);
- } else {
- backboxes.Add(box);
- }
- }
- // when we are all done, the counts should match.
- WWASSERT(frontboxes.Count() == sc.FrontCount);
- WWASSERT(backboxes.Count() == sc.BackCount);
- }
- /******************************************************************************************
- **
- ** Partitioning code which searches for the best split for a given set of boxes. This
- ** code is re-used by both types of partitioning (partitioning contained objects or
- ** partitioning based on a set of "seed" boxes.)
- **
- ******************************************************************************************/
- void AABTreeNodeClass::Select_Splitting_Plane
- (
- SplitChoiceStruct * sc,
- SimpleDynVecClass<AABoxClass> & boxes
- )
- {
- const int NUM_TRYS = 300;
- /*
- ** Try putting axis-aligned planes through some random vertices
- */
- int objcount = boxes.Count();
- int trys = 0;
- for (trys = 0; trys < MIN(NUM_TRYS,objcount); trys++) {
- int obj_index;
- SplitChoiceStruct test;
-
- /*
- ** Select a random object
- */
- obj_index = rand() % objcount;
- const AABoxClass & box = boxes[obj_index];
- /*
- ** Select a random plane which co-incides with one of the faces
- ** of the object's bounding box
- */
- switch(rand() % 6) {
- case 0: test.Plane.Set(AAPlaneClass::XNORMAL,box.Center.X + box.Extent.X); break;
- case 1: test.Plane.Set(AAPlaneClass::XNORMAL,box.Center.X - box.Extent.X); break;
- case 2: test.Plane.Set(AAPlaneClass::YNORMAL,box.Center.Y + box.Extent.Y); break;
- case 3: test.Plane.Set(AAPlaneClass::YNORMAL,box.Center.Y - box.Extent.Y); break;
- case 4: test.Plane.Set(AAPlaneClass::ZNORMAL,box.Center.Z + box.Extent.Z); break;
- case 5: test.Plane.Set(AAPlaneClass::ZNORMAL,box.Center.Z - box.Extent.Z); break;
- };
- /*
- ** Get the score for this plane
- */
- Compute_Score(&test,boxes);
- if (test.Cost < sc->Cost) {
- *sc = test;
- }
- }
- /*
- ** Still haven't found a valid splitting plane, uh-oh.
- */
- if ((trys >= MIN(NUM_TRYS,objcount)) && (sc->Cost == FLT_MAX)) {
- Select_Splitting_Plane_Brute_Force(sc,boxes);
- return;
- }
- }
- void AABTreeNodeClass::Select_Splitting_Plane_Brute_Force
- (
- AABTreeNodeClass::SplitChoiceStruct * sc,
- SimpleDynVecClass<AABoxClass> & boxes
- )
- {
- /*
- ** Try putting axis-aligned planes along each face of each box
- */
- int objcount = boxes.Count();
- for (int obj_index = 0; obj_index < objcount; obj_index++) {
- AAPlaneClass plane;
- const AABoxClass & box = boxes[obj_index];
- /*
- ** Try each face of this box
- */
- for (int plane_index = 0; plane_index < 6; plane_index++) {
- SplitChoiceStruct test;
- switch(plane_index % 6) {
- case 0: test.Plane.Set(AAPlaneClass::XNORMAL,box.Center.X + box.Extent.X); break;
- case 1: test.Plane.Set(AAPlaneClass::XNORMAL,box.Center.X - box.Center.Y); break;
- case 2: test.Plane.Set(AAPlaneClass::YNORMAL,box.Center.Y + box.Center.Y); break;
- case 3: test.Plane.Set(AAPlaneClass::YNORMAL,box.Center.Y - box.Center.Y); break;
- case 4: test.Plane.Set(AAPlaneClass::ZNORMAL,box.Center.Z + box.Center.Z); break;
- case 5: test.Plane.Set(AAPlaneClass::ZNORMAL,box.Center.Z - box.Center.Z); break;
- };
- test.FrontBox.Init_Empty();
- test.BackBox.Init_Empty();
- /*
- ** Get the score for this plane
- */
- Compute_Score(&test,boxes);
- if (test.Cost < sc->Cost) {
- *sc = test;
- }
- }
- }
- /*
- ** Notify user that we couldn't split this node
- */
- #ifdef WWDEBUG
- if (sc->Cost == FLT_MAX) {
- WWDEBUG_SAY(("Unable to split node! objcount = %d. (%.2f,%.2f,%.2f)\r\n",objcount,Box.Center.X, Box.Center.Y, Box.Center.Z));
- }
- #endif
- }
- void AABTreeNodeClass::Compute_Score
- (
- AABTreeNodeClass::SplitChoiceStruct * sc,
- SimpleDynVecClass<AABoxClass> & boxes
- )
- {
- /*
- ** Suitability of a plane as a partition plane is based on the following factors:
- ** - How many "tiles" are on each side of the plane,
- */
- for (int i=0; i<boxes.Count(); i++) {
- const AABoxClass & box = boxes[i];
- if (CollisionMath::Overlap_Test(sc->Plane,box.Center) == CollisionMath::FRONT) {
- sc->FrontCount++;
- sc->FrontBox.Add_Box(box);
- } else {
-
- sc->BackCount++;
- sc->BackBox.Add_Box(box);
- }
- }
- /*
- ** Compute the cost.
- */
- float back_cost = sc->BackBox.Volume() * sc->BackCount;
- float front_cost = sc->FrontBox.Volume() * sc->FrontCount;
-
- sc->Cost = front_cost + back_cost;
-
- if ((sc->FrontCount == 0) || (sc->BackCount == 0)) {
- sc->Cost = FLT_MAX;
- }
- }
- /**************************************************************************************
- AABTreeIterator Implemenation
- **************************************************************************************/
- AABTreeIterator::AABTreeIterator(AABTreeCullSystemClass * tree) :
- Tree(tree),
- CurNodeIndex(0)
- {
- WWASSERT(Tree != NULL);
- }
-
- void AABTreeIterator::Reset(void)
- {
- CurNodeIndex = 0;
- }
- bool AABTreeIterator::Enter_Parent(void)
- {
- validate();
- if (CurNodeIndex != 0) {
- CurNodeIndex = Tree->IndexedNodes[CurNodeIndex]->Parent->Index;
- return true;
- } else {
- return false;
- }
- }
- bool AABTreeIterator::Enter_Sibling(void)
- {
- validate();
- if (CurNodeIndex != 0) {
-
- /*
- ** find which child of our parent we are
- */
- AABTreeNodeClass * parent = Tree->IndexedNodes[CurNodeIndex]->Parent;
- AABTreeNodeClass * parent_front = parent->Front;
- AABTreeNodeClass * parent_back = parent->Back;
- /*
- ** if our parent doesn't have two children, we don't have a sibling
- */
- if ((parent_front == NULL) || (parent_back == NULL)) {
- return false;
- }
- /*
- ** if we our our parent's front child, go to its back child
- */
- if ((int)parent_front->Index == CurNodeIndex) {
- CurNodeIndex = parent_back->Index;
- return true;
- }
- /*
- ** if we our our parent's back child, go to its front child
- */
- if ((int)parent_back->Index == (int)CurNodeIndex) {
- CurNodeIndex = parent_front->Index;
- return true;
- }
- }
- return false;
- }
- bool AABTreeIterator::Has_Front_Child(void)
- {
- validate();
- return (Tree->IndexedNodes[CurNodeIndex]->Front != NULL);
- }
- bool AABTreeIterator::Enter_Front_Child(void)
- {
- validate();
- if (Has_Front_Child()) {
- CurNodeIndex = Tree->IndexedNodes[CurNodeIndex]->Front->Index;
- return true;
- }
- return false;
- }
- bool AABTreeIterator::Has_Back_Child(void)
- {
- validate();
- return (Tree->IndexedNodes[CurNodeIndex]->Back != NULL);
- }
- bool AABTreeIterator::Enter_Back_Child(void)
- {
- if (Has_Back_Child()) {
- CurNodeIndex = Tree->IndexedNodes[CurNodeIndex]->Back->Index;
- return true;
- }
- return false;
- }
- int AABTreeIterator::Get_Current_Node_Index(void)
- {
- return CurNodeIndex;
- }
- void AABTreeIterator::Get_Current_Box(AABoxClass * set_box)
- {
- Tree->Get_Node_Bounds(CurNodeIndex,set_box);
- }
- void AABTreeIterator::validate(void)
- {
- if ((CurNodeIndex < 0) || (CurNodeIndex >= Tree->NodeCount)) {
- CurNodeIndex = 0;
- }
- }
- /*
- Can we make a more compact AABTree?
- Here is the existing data in each Node:
- uint32 Index; // Index of this node
- AABoxClass Box; // Bounding box of the node
- AABTreeNodeClass * Parent; // parent of this node
- AABTreeNodeClass * Front; // front node
- AABTreeNodeClass * Back; // back node
- CullableClass * Object; // objects in this node
- uint32 UserData; // 32bit field for the user, initialized to 0
- Total Size: 48 bytes
- Here is a possible replacement:
- uint16 Index;
- short x,y,z,w,l,h; // Need origin and scale factors for the boxes stored in tree
- uint16 ParentIndex;
- uint16 FrontIndex;
- uint16 BackIndex;
- CullableClass * Object;
- uint32 UserData;
-
- Total Size: 28 bytes
- */
|