00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include "map-kdtree.h"
00035
00036 #include "glut/frustum.h"
00037 #include "glut/renderable.h"
00038 #include "model-loader/model-loader.h"
00039 #include "perf/perf.h"
00040 #include "util/free_list.h"
00041
00042
00043 namespace aesop {
00044
00045
00046
00047 MapKdTree::~MapKdTree(void) throw() { }
00048
00049
00050 typedef free_list_t<kdtree::Node::dynamic_entry_t> free_type_t;
00051
00052 static const int s_maxFreeListSize = 256;
00053
00054
00055 struct node_data_t {
00056
00057 node_data_t(void) throw() { this->clear(); }
00058 void clear(void) throw() {
00059 leafzone = NULL;
00060 }
00061
00062
00063 LeafZone * leafzone;
00064 };
00065
00066
00067
00068 class KdTree;
00069
00070 struct add_static_context_t {
00071
00072 KdTree * pThis;
00073 LeafZone * leafzone;
00074 };
00075
00076
00077
00078 struct add_virtual_context_t {
00079
00080 kdtree::Node * node;
00081 LeafZone * leafzone;
00082 };
00083
00084
00085
00086 struct add_dynamic_context_t {
00087 add_dynamic_context_t(void) throw() { this->clear(); }
00088 void clear(void) throw() {
00089 root = NULL;
00090 viewerZone = NULL;
00091 rootZone = NULL;
00092 frustum.clear();
00093 freeList = NULL;
00094 }
00095
00096
00097 kdtree::Node * root;
00098 LeafZone * viewerZone;
00099 Zone * rootZone;
00100 frustum_t frustum;
00101 free_type_t * freeList;
00102 };
00103
00104
00105
00106 struct entry_t : public kdtree::Entry {
00107
00108 smart_ptr<glut::Renderable> model;
00109 placement_t placement;
00110 LeafZone * leafzone;
00111 };
00112
00113
00114
00115
00116 struct sort_entry_t {
00117 smart_ptr<entry_t> entry;
00118 float d2;
00119 };
00120
00121
00123
00124
00125
00127
00128 static void
00129 determineZone
00130 (
00131 IN kdtree::Node * node,
00132 IN Zone * root
00133 )
00134 {
00135 ASSERT(node, "null");
00136 ASSERT(root, "null");
00137
00138 smart_ptr<node_data_t> nd = new node_data_t;
00139 ASSERT(nd, "out of memory");
00140
00141 const rect3d_t& nodeRect = node->getRect();
00142 LeafZone * lz = root->getLeafZone(nodeRect.getMidpoint());
00143 if (!lz) {
00144
00145 } else {
00146
00147 rect3d_t zoneRect;
00148 lz->getBoundingRect(zoneRect);
00149 if (zoneRect.containsRect(nodeRect)) {
00150
00151
00152 nd->leafzone = lz;
00153 }
00154 }
00155
00156
00157 node->setUserPointer(nd.disown());
00158
00159
00160 kdtree::Node * left = node->getLeftChild();
00161 kdtree::Node * right = node->getRightChild();
00162
00163 if (left) {
00164 determineZone(left, root);
00165 }
00166 if (right) {
00167 determineZone(right, root);
00168 }
00169 }
00170
00171
00172
00173 static void
00174 deletePointers
00175 (
00176 IN kdtree::Node * node
00177 )
00178 throw()
00179 {
00180 ASSERT(node, "null");
00181
00182 void * user = node->getUserPointer();
00183 if (user) {
00184 node->setUserPointer(NULL);
00185 node_data_t * nd = (node_data_t *) user;
00186 delete nd;
00187 }
00188
00189 kdtree::Node * left = node->getLeftChild();
00190 kdtree::Node * right = node->getRightChild();
00191 if (left)
00192 deletePointers(left);
00193 if (right)
00194 deletePointers(right);
00195 }
00196
00197
00198
00199 static void
00200 deleteAllEntries
00201 (
00202 IN kdtree::Node * node
00203 )
00204 throw()
00205 {
00206 ASSERT(node, "null");
00207
00208
00209 while (true) {
00210 kdtree::Node::vec_entries_t& vec = node->getStaticEntries();
00211 int nEntries = vec.size();
00212 if (nEntries < 1)
00213 break;
00214
00215
00216 kdtree::Entry * entry = vec[nEntries - 1].entry;
00217 ASSERT(entry, "null entry in list?");
00218 node->removeStaticEntry(entry);
00219 }
00220
00221
00222 kdtree::Node * left = node->getLeftChild();
00223 kdtree::Node * right = node->getRightChild();
00224 if (left)
00225 deleteAllEntries(left);
00226 if (right)
00227 deleteAllEntries(right);
00228 }
00229
00230
00231
00232 static void
00233 walkTree
00234 (
00235 IN kdtree::Node * node,
00236 IN int depth,
00237 IN kdtree_callback_fn callback,
00238 IN void * context
00239 )
00240 {
00241 ASSERT(node, "null");
00242 ASSERT(depth >= 0, "bad depth: %d", depth);
00243 ASSERT(callback, "null");
00244
00245
00246 kd_node_t kn;
00247 kn.rect = node->getRect();
00248 kn.depth = depth;
00249 callback(kn, context);
00250
00251
00252 kdtree::Node * left = node->getLeftChild();
00253 kdtree::Node * right = node->getRightChild();
00254 if (left)
00255 walkTree(left, depth + 1, callback, context);
00256 if (right)
00257 walkTree(right, depth + 1, callback, context);
00258 }
00259
00260
00261
00262 static int
00263 compareEntries
00264 (
00265 IN const void * p1,
00266 IN const void * p2
00267 )
00268 throw()
00269 {
00270 const sort_entry_t * se1 = (const sort_entry_t *) p1;
00271 const sort_entry_t * se2 = (const sort_entry_t *) p2;
00272 ASSERT(se1 && se2, "null");
00273
00274 if (se1->d2 < se2->d2) {
00275 return -1;
00276 } else if (se1->d2 > se2->d2) {
00277 return +1;
00278 }
00279
00280
00281 return 0;
00282 }
00283
00284
00285
00286 static void
00287 walkFrontToBack
00288 (
00289 IN kdtree::Node * node,
00290 IN free_type_t& freeList,
00291 IN const glut::render_context_t& rc,
00292 IN glut::RenderQueue * rq,
00293 IN const frustum_t * f,
00294 IN LeafZone * viewerZone,
00295 IN kdtree_object_fn callback,
00296 IN void * context
00297 )
00298 {
00299 ASSERT(node, "null");
00300 ASSERT(rq, "null");
00301
00302
00303 ASSERT(callback, "null");
00304
00305
00306
00307 if (viewerZone) {
00308 const node_data_t * nd = (const node_data_t *) node->getUserPointer();
00309 ASSERT(nd, "map kd node with no user pointer?");
00310
00311
00312 if (nd->leafzone) {
00313
00314 if (viewerZone->isLeafVisible(nd->leafzone)) {
00315
00316
00317
00318 viewerZone = NULL;
00319 } else {
00320
00321 return;
00322 }
00323 }
00324 }
00325
00326
00327 if (f) {
00328 const rect3d_t& r = node->getRect();
00329 switch (f->containsRect(r)) {
00330 case eContains_None:
00331 return;
00332
00333 case eContains_Fully:
00334 f = NULL;
00335 break;
00336
00337 default:
00338
00339 break;
00340 }
00341 }
00342
00343
00344 const point3d_t& start = rc.viewer.getPosition();
00345
00346 const kdtree::plane_t& plane = node->getSortPlane();
00347 kdtree::eSort sort = kdtree::sortPoint(plane, start);
00348
00349 kdtree::Node * left = node->getLeftChild();
00350 kdtree::Node * right = node->getRightChild();
00351
00352 kdtree::Node * closest = left;
00353 kdtree::Node * farthest = right;
00354 if (kdtree::eSort_Right == sort) {
00355 closest = right;
00356 farthest = left;
00357 }
00358
00359
00360 if (closest) {
00361 walkFrontToBack(closest, freeList, rc, rq, f, viewerZone, callback, context);
00362 }
00363
00364
00365 const int nMaxEntries = 256;
00366 sort_entry_t sortArray[nMaxEntries];
00367 int nEntries = 0;
00368
00369
00370 const kdtree::Node::vec_entries_t& vec = node->getStaticEntries();
00371
00372
00373 for (kdtree::Node::vec_entries_t::const_iterator i = vec.begin();
00374 i != vec.end(); ++i) {
00375 const kdtree::Node::entry_rec_t& er = *i;
00376
00377 smart_ptr<entry_t> entry = er.entry;
00378 ASSERT(entry, "failed to upcast");
00379
00380
00381 if (viewerZone &&
00382 !viewerZone->isLeafVisible(entry->leafzone))
00383 continue;
00384
00385
00386 sort_entry_t se;
00387 se.entry = entry;
00388
00389
00390 point3d_t diff = entry->placement.position - start;
00391 se.d2 = dotProduct(diff, diff);
00392
00393
00394 sortArray[nEntries] = se;
00395 ++nEntries;
00396 if (nEntries > nMaxEntries) {
00397
00398 DPRINTF("ERROR: too many entries (%d) in node!",
00399 nEntries);
00400 DPRINTF(" Giving up rendering remaining entries");
00401 break;
00402 }
00403 }
00404
00405
00406 while (smart_ptr<kdtree::Node::dynamic_entry_t> pde =
00407 node->popDynamicEntry()) {
00408
00409 sort_entry_t se;
00410 se.entry = pde->entry;
00411
00412
00413 point3d_t diff = se.entry->placement.position - start;
00414 se.d2 = dotProduct(diff, diff);
00415
00416
00417 sortArray[nEntries] = se;
00418 ++nEntries;
00419 if (nEntries > nMaxEntries) {
00420 DPRINTF("ERROR: too many entries (%d) in node!",
00421 nEntries);
00422 DPRINTF(" Giving up rendering remaining entries");
00423 break;
00424 }
00425
00426
00427 freeList.returnElement(pde);
00428 }
00429
00430 ASSERT(nEntries <= nMaxEntries, "should have at most nMaxEntries visible");
00431 if (nEntries > 32) {
00432
00433 DPRINTF("WARNING: many entries (%d) in node!", nEntries);
00434 }
00435
00436
00437 qsort(sortArray, nEntries, sizeof(sort_entry_t), compareEntries);
00438
00439
00440 for (int i = 0; i < nEntries; ++i) {
00441 entry_t * entry = sortArray[i].entry;
00442 ASSERT(entry, "null entry in sort array?");
00443
00444
00445 glut::render_context_t rc2 = rc;
00446 rc2.placement = entry->placement;
00447
00448
00449 callback(entry->model, rc2, rq, context);
00450 }
00451
00452
00453 if (farthest) {
00454 walkFrontToBack(farthest, freeList, rc, rq, f, viewerZone, callback, context);
00455 }
00456 }
00457
00458
00459
00460 static void
00461 addInstanceToNode
00462 (
00463 IN smart_ptr<Instance>& instance,
00464 IN LeafZone * lz,
00465 IN kdtree::Node * node
00466 )
00467 {
00468 ASSERT(instance, "null");
00469 ASSERT(lz, "null");
00470 ASSERT(node, "null");
00471
00472
00473 smart_ptr<glut::Renderable> model = getModel(instance);
00474 if (!model) {
00475 DPRINTF("No model for instance of type '%s'",
00476 instance->getTypeId());
00477 return;
00478 }
00479
00480 rect3d_t r = model->getBoundingBox();
00481 r.translate(instance->getPlacement().position);
00482
00483
00484
00485
00486 smart_ptr<entry_t> entry = new entry_t;
00487 entry->model = model;
00488 entry->placement = instance->getPlacement();
00489 entry->leafzone = lz;
00490
00491
00492 smart_ptr<kdtree::Entry> kEntry = entry;
00493 node->addStaticEntry(kEntry, r);
00494 }
00495
00496
00497
00498 static void
00499 addDynamicObject
00500 (
00501 IN smart_ptr<Instance>& instance,
00502 IN smart_ptr<PhysicsObject>& obj,
00503 IN void * context
00504 )
00505 {
00506 ASSERT(instance, "null");
00507 ASSERT(obj, "null");
00508 add_dynamic_context_t * padc = (add_dynamic_context_t *) context;
00509 ASSERT(padc, "null");
00510 ASSERT(padc->root, "null");
00511 ASSERT(padc->rootZone, "null");
00512
00513 ASSERT(padc->freeList, "null");
00514
00515
00516 if (PhysicsObject::eFlag_Static & obj->getFlags()) {
00517
00518 return;
00519 }
00520
00521
00522 const point3d_t pos = instance->getPlacement().position;
00523 LeafZone * lz = padc->rootZone->getLeafZone(pos);
00524 if (lz && padc->viewerZone &&
00525 !padc->viewerZone->isLeafVisible(lz)) {
00526
00527 return;
00528 }
00529
00530
00531 smart_ptr<glut::Renderable> model = getModel(instance);
00532 if (!model) {
00533 DPRINTF("No model for instance of type '%s'",
00534 instance->getTypeId());
00535 return;
00536 }
00537 rect3d_t r = model->getBoundingBox();
00538 r.translate(pos);
00539
00540
00541 if (eContains_None == padc->frustum.containsRect(r)) {
00542 return;
00543 }
00544
00545
00546
00547 smart_ptr<kdtree::Node::dynamic_entry_t> pde;
00548
00549
00550 pde = padc->freeList->getElement();
00551 if (!pde->entry) {
00552 pde->entry = new entry_t;
00553 ASSERT(pde->entry, "null");
00554 }
00555 ASSERT(!pde->next, "should be null");
00556
00557
00558 entry_t * entry = dynamic_cast<entry_t *>((kdtree::Entry *) pde->entry);
00559 ASSERT(entry, "failed to upcast");
00560 entry->model = model;
00561 entry->placement = instance->getPlacement();
00562 entry->leafzone = lz;
00563
00564
00565 padc->root->addDynamicEntry(pde);
00566 }
00567
00568
00569
00570 static void
00571 nukeAllDynamicEntries
00572 (
00573 IN kdtree::Node * node,
00574 free_type_t& freeList
00575 )
00576 {
00577 ASSERT(node, "null");
00578
00579
00580 while (smart_ptr<kdtree::Node::dynamic_entry_t> pde =
00581 node->popDynamicEntry()) {
00582 freeList.returnElement(pde);
00583 }
00584
00585
00586 kdtree::Node * left = node->getLeftChild();
00587 kdtree::Node * right = node->getRightChild();
00588
00589 if (left) {
00590 nukeAllDynamicEntries(left, freeList);
00591 }
00592 if (right) {
00593 nukeAllDynamicEntries(right, freeList);
00594 }
00595 }
00596
00597
00598
00600
00601
00602
00604
00605 class KdTree : public MapKdTree {
00606 public:
00607 KdTree(void) throw();
00608 ~KdTree(void) throw();
00609
00610
00611 void initialize(IN smart_ptr<MapDynamics>& map);
00612
00613
00614 MapDynamics * getMapDynamics(void) throw() { return m_map; }
00615 void walkNodes(IN kdtree_callback_fn callback,
00616 IN void * context);
00617 void walkFrontToBack(IN const glut::render_context_t& rc,
00618 IN glut::RenderQueue * rq,
00619 IN kdtree_object_fn callback,
00620 IN void * context);
00621 void update(void);
00622
00623 private:
00624
00625 typedef std::vector<smart_ptr<kdtree::Node> > node_vec_t;
00626
00627 struct dyn_rec_t {
00628 entry_t * entry;
00629 bool updated;
00630 };
00631
00632
00633 static void addZones(IN Zone * zone, IN void * context);
00634 static void addObjectsFromZone(IN Zone * zone, IN void * context);
00635 static void addStaticInstance(IN smart_ptr<Instance>& instance,
00636 IN void * context);
00637 static void addVirtualLeafInstance(IN smart_ptr<Instance>& instance,
00638 IN void * context);
00639 void addStaticInstance(IN smart_ptr<Instance>& instance,
00640 IN LeafZone * lz);
00641 void addVirtualLeaf(IN LeafZone * lz);
00642
00643
00644 smart_ptr<MapDynamics> m_map;
00645 smart_ptr<kdtree::Node> m_root;
00646 free_type_t m_freeList;
00647 node_vec_t m_virtuals;
00648 };
00649
00650
00651
00652 KdTree::KdTree
00653 (
00654 void
00655 )
00656 throw() :
00657 m_freeList(s_maxFreeListSize)
00658 {
00659 }
00660
00661
00662
00663 KdTree::~KdTree
00664 (
00665 void
00666 )
00667 throw()
00668 {
00669
00670 if (m_root) {
00671 deletePointers(m_root);
00672 }
00673
00674
00675 for (node_vec_t::iterator i = m_virtuals.begin(); i != m_virtuals.end();
00676 ++i) {
00677 kdtree::Node * node = *i;
00678 ASSERT(node, "null node in virtual list");
00679 void * user = node->getUserPointer();
00680 if (user) {
00681 node->setUserPointer(NULL);
00682 node_data_t * nd = (node_data_t *) user;
00683 delete nd;
00684 }
00685 }
00686 }
00687
00688
00689
00691
00692
00693
00695
00696 void
00697 KdTree::initialize
00698 (
00699 IN smart_ptr<MapDynamics>& map
00700 )
00701 {
00702 perf::Timer timer("MapKdTree::initialize");
00703 ASSERT(map, "null");
00704
00705
00706 m_map = map;
00707
00708
00709 smart_ptr<Map> romap = map->getMap();
00710 ASSERT(romap, "null map in map dynamics");
00711
00712
00713 Zone * rz = romap->getRootZone();
00714 ASSERT(rz, "map contains null root zone?");
00715 rect3d_t mapBounds;
00716 rz->getBoundingRect(mapBounds);
00717
00718
00719
00720 ASSERT(!m_root, "already have a root node");
00721 m_root = kdtree::Node::create(mapBounds);
00722 ASSERT(m_root, "failed to create kdtree root node");
00723
00724
00725 romap->iterateZones(addZones, this);
00726
00727
00728 DPRINTF("Assembling rendering kdtree, pass 1: zones");
00729 int nMaxEntriesPerNode = 1;
00730 {
00731 perf::Timer timer("MapKdTree::subdivide pass 1");
00732 m_root->subdivide(kdtree::eStrategy_Balance,
00733 nMaxEntriesPerNode);
00734 }
00735 DPRINTF(" pass 1 tree depth: %d", m_root->getTreeDepth());
00736 DPRINTF(" pass 1 nodes in tree: %d", m_root->getNodeCount());
00737 DPRINTF(" pass 1 entries in tree: %d", m_root->getStaticEntryCount());
00738
00739
00740 deleteAllEntries(m_root);
00741
00742
00743 romap->iterateZones(addObjectsFromZone, this);
00744
00745
00746 DPRINTF("Loaded %d entries into root of kdtree, subdividing...",
00747 m_root->getStaticEntryCount());
00748 nMaxEntriesPerNode = 7;
00749 {
00750 perf::Timer timer("MapKdTree::subdivide pass 2");
00751 m_root->subdivide(kdtree::eStrategy_Balance,
00752 nMaxEntriesPerNode);
00753 }
00754 DPRINTF(" pass 2 tree depth: %d", m_root->getTreeDepth());
00755 DPRINTF(" pass 2 nodes in tree: %d", m_root->getNodeCount());
00756 DPRINTF(" pass 2 entries in tree: %d", m_root->getStaticEntryCount());
00757
00758
00759 determineZone(m_root, rz);
00760 }
00761
00762
00763
00765
00766
00767
00769
00770 void
00771 KdTree::walkNodes
00772 (
00773 IN kdtree_callback_fn callback,
00774 IN void * context
00775 )
00776 {
00777 ASSERT(callback, "null");
00778
00779
00780 walkTree(m_root, 0, callback, context);
00781 }
00782
00783
00784
00785 void
00786 KdTree::walkFrontToBack
00787 (
00788 IN const glut::render_context_t& rc,
00789 IN glut::RenderQueue * rq,
00790 IN kdtree_object_fn callback,
00791 IN void * context
00792 )
00793 {
00794 perf::Timer timer("MapKdTree::walkFrontToBack");
00795 ASSERT(callback, "null");
00796
00797
00798
00799 frustum_t f;
00800 glut::getViewFrustum(rc.camera, rc.viewer, f);
00801
00802
00803 Map * map = m_map->getMap();
00804 ASSERT(map, "null map in map dynamics?");
00805 Zone * rz = map->getRootZone();
00806 ASSERT(rz, "null root zone in map?");
00807 LeafZone * viewerZone = rz->getLeafZone(rc.viewer.getPosition());
00808 if (!viewerZone) {
00809 DPRINTF("WARNING: viewer is not in a leaf zone! Drawing everything...");
00810 }
00811
00812
00813 nukeAllDynamicEntries(m_root, m_freeList);
00814
00815
00816 add_dynamic_context_t adc;
00817 adc.root = m_root;
00818 adc.frustum = f;
00819 adc.viewerZone = viewerZone;
00820 adc.rootZone = rz;
00821 adc.freeList = &m_freeList;
00822 m_map->iterateInstancesInZone(rz, addDynamicObject, &adc);
00823
00824
00825 {
00826 perf::Timer timer("MapKdTree::walkFtB (regular zones)");
00827 aesop::walkFrontToBack(m_root, m_freeList, rc, rq, &f, viewerZone, callback, context);
00828 }
00829
00830
00831
00832 {
00833 perf::Timer timer("MapKdTree::walkFtB (virtual zones)");
00834 for (node_vec_t::iterator i = m_virtuals.begin();
00835 i != m_virtuals.end(); ++i) {
00836 kdtree::Node * node = *i;
00837 ASSERT(node, "null node in virtuals list");
00838
00839 node_data_t * nd = (node_data_t *) node->getUserPointer();
00840 ASSERT(nd, "null node data in virtual node");
00841
00842 if (!viewerZone->isLeafVisible(nd->leafzone)) {
00843
00844 continue;
00845 }
00846
00847
00848 aesop::walkFrontToBack(node, m_freeList, rc, rq, &f, NULL, callback, context);
00849 }
00850 }
00851 }
00852
00853
00854
00855 void
00856 KdTree::update
00857 (
00858 void
00859 )
00860 {
00861 perf::Timer timer("MapKdTree::update");
00862
00863 }
00864
00865
00866
00868
00869
00870
00872
00873 void
00874 KdTree::addZones
00875 (
00876 IN Zone * zone,
00877 IN void * context
00878 )
00879 {
00880 ASSERT(zone, "null");
00881 KdTree * pThis = (KdTree *) context;
00882 ASSERT(pThis, "null");
00883 ASSERT(pThis->m_root, "need to create kdtree root node first");
00884
00885 LeafZone * lz = dynamic_cast<LeafZone *>(zone);
00886 if (!lz) {
00887 return;
00888 }
00889 if (Zone::eType_VirtualLeaf == zone->getType()) {
00890 pThis->addVirtualLeaf(lz);
00891 return;
00892 }
00893
00894
00895 smart_ptr<entry_t> entry = new entry_t;
00896 ASSERT(entry, "out of memory");
00897
00898 rect3d_t r;
00899 lz->getBoundingRect(r);
00900
00901
00902 smart_ptr<kdtree::Entry> kEntry = entry;
00903 ASSERT(kEntry, "failed to downcast");
00904 pThis->m_root->addStaticEntry(kEntry, r);
00905 }
00906
00907
00908
00909 void
00910 KdTree::addObjectsFromZone
00911 (
00912 IN Zone * zone,
00913 IN void * context
00914 )
00915 {
00916 ASSERT(zone, "null");
00917 ASSERT(context, "null");
00918
00919 if (Zone::eType_Leaf != zone->getType()) {
00920 return;
00921 }
00922 LeafZone * lz = dynamic_cast<LeafZone *>(zone);
00923 if (!lz) {
00924 DPRINTF("ERROR: leaf zone can't be upcasted?");
00925 return;
00926 }
00927
00928 add_static_context_t asc;
00929 asc.pThis = (KdTree *) context;
00930 asc.leafzone = lz;
00931 lz->iterateStaticInstances(addStaticInstance, &asc);
00932 }
00933
00934
00935
00936 void
00937 KdTree::addStaticInstance
00938 (
00939 IN smart_ptr<Instance>& instance,
00940 IN void * context
00941 )
00942 {
00943 ASSERT(instance, "null");
00944 add_static_context_t * pasc = (add_static_context_t *) context;
00945 ASSERT(pasc, "null context");
00946 ASSERT(pasc->pThis, "null");
00947 ASSERT(pasc->leafzone, "null");
00948
00949
00950 pasc->pThis->addStaticInstance(instance, pasc->leafzone);
00951 }
00952
00953
00954
00955 void
00956 KdTree::addVirtualLeafInstance
00957 (
00958 IN smart_ptr<Instance>& instance,
00959 IN void * context
00960 )
00961 {
00962 ASSERT(instance, "null");
00963 add_virtual_context_t * pavc = (add_virtual_context_t *) context;
00964 ASSERT(pavc, "null context");
00965 ASSERT(pavc->node, "null");
00966 ASSERT(pavc->leafzone, "null");
00967
00968 addInstanceToNode(instance, pavc->leafzone, pavc->node);
00969 }
00970
00971
00972
00973 void
00974 KdTree::addStaticInstance
00975 (
00976 IN smart_ptr<Instance>& instance,
00977 IN LeafZone * lz
00978 )
00979 {
00980 ASSERT(instance, "null");
00981 ASSERT(lz, "null");
00982 ASSERT(m_root, "need to create kdtree root first");
00983
00984 addInstanceToNode(instance, lz, m_root);
00985 }
00986
00987
00988
00989 void
00990 KdTree::addVirtualLeaf
00991 (
00992 IN LeafZone * lz
00993 )
00994 {
00995 ASSERT(lz, "null");
00996 ASSERT(Zone::eType_VirtualLeaf == lz->getType(),
00997 "zone is not a virtual leaf");
00998
00999
01000 DPRINTF("Adding virtual leaf...");
01001 rect3d_t r;
01002 lz->getBoundingRect(r);
01003 r.dump(" virtual leaf dimensions");
01004
01005
01006 smart_ptr<kdtree::Node> node = kdtree::Node::create(r);
01007 ASSERT(node, "out of memory");
01008
01009
01010 smart_ptr<node_data_t> nd = new node_data_t;
01011 ASSERT(nd, "out of memory");
01012 nd->leafzone = lz;
01013 node->setUserPointer(nd.disown());
01014
01015
01016
01017 add_virtual_context_t avc;
01018 avc.node = node;
01019 avc.leafzone = lz;
01020 lz->iterateStaticInstances(addVirtualLeafInstance, &avc);
01021 DPRINTF("Virtual leaf node contains %d entries",
01022 node->getStaticEntryCount());
01023
01024
01025 m_virtuals.push_back(node);
01026 }
01027
01028
01029
01031
01032
01033
01035
01036 smart_ptr<MapKdTree>
01037 MapKdTree::create
01038 (
01039 IN smart_ptr<MapDynamics>& map
01040 )
01041 {
01042 ASSERT(map, "null");
01043
01044 smart_ptr<KdTree> local = new KdTree;
01045 ASSERT(local, "out of memory");
01046
01047 local->initialize(map);
01048
01049 return local;
01050 }
01051
01052
01053
01054 };
01055