Octree.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662
  1. //
  2. // Urho3D Engine
  3. // Copyright (c) 2008-2011 Lasse Öörni
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. //
  23. #include "Precompiled.h"
  24. #include "Context.h"
  25. #include "DebugRenderer.h"
  26. #include "Profiler.h"
  27. #include "Octree.h"
  28. #include "Scene.h"
  29. #include "Sort.h"
  30. #include "WorkQueue.h"
  31. #include "DebugNew.h"
  32. #ifdef _MSC_VER
  33. #pragma warning(disable:4355)
  34. #endif
  35. static const float DEFAULT_OCTREE_SIZE = 1000.0f;
  36. static const int DEFAULT_OCTREE_LEVELS = 8;
  37. static const int RAYCASTS_PER_WORK_ITEM = 4;
  38. void RaycastDrawablesWork(const WorkItem* item, unsigned threadIndex)
  39. {
  40. Octree* octree = reinterpret_cast<Octree*>(item->aux_);
  41. Drawable** start = reinterpret_cast<Drawable**>(item->start_);
  42. Drawable** end = reinterpret_cast<Drawable**>(item->end_);
  43. const RayOctreeQuery& query = *octree->rayQuery_;
  44. PODVector<RayQueryResult>& results = octree->rayQueryResults_[threadIndex];
  45. while (start != end)
  46. {
  47. Drawable* drawable = *start;
  48. drawable->ProcessRayQuery(query, results);
  49. ++start;
  50. }
  51. }
  52. void UpdateDrawablesWork(const WorkItem* item, unsigned threadIndex)
  53. {
  54. const FrameInfo& frame = *(reinterpret_cast<FrameInfo*>(item->aux_));
  55. Drawable** start = reinterpret_cast<Drawable**>(item->start_);
  56. Drawable** end = reinterpret_cast<Drawable**>(item->end_);
  57. while (start != end)
  58. {
  59. Drawable* drawable = *start;
  60. drawable->Update(frame);
  61. drawable->updateQueued_ = false;
  62. ++start;
  63. }
  64. }
  65. inline bool CompareRayQueryResults(const RayQueryResult& lhs, const RayQueryResult& rhs)
  66. {
  67. return lhs.distance_ < rhs.distance_;
  68. }
  69. Octant::Octant(const BoundingBox& box, unsigned level, Octant* parent, Octree* root) :
  70. worldBoundingBox_(box),
  71. level_(level),
  72. parent_(parent),
  73. root_(root),
  74. numDrawables_(0)
  75. {
  76. center_ = worldBoundingBox_.Center();
  77. halfSize_ = worldBoundingBox_.Size() * 0.5f;
  78. cullingBox_ = BoundingBox(worldBoundingBox_.min_ - halfSize_, worldBoundingBox_.max_ + halfSize_);
  79. for (unsigned i = 0; i < NUM_OCTANTS; ++i)
  80. children_[i] = 0;
  81. }
  82. Octant::~Octant()
  83. {
  84. Release();
  85. }
  86. Octant* Octant::GetOrCreateChild(unsigned index)
  87. {
  88. if (children_[index])
  89. return children_[index];
  90. Vector3 newMin = worldBoundingBox_.min_;
  91. Vector3 newMax = worldBoundingBox_.max_;
  92. Vector3 oldCenter = worldBoundingBox_.Center();
  93. if (index & 1)
  94. newMin.x_ = oldCenter.x_;
  95. else
  96. newMax.x_ = oldCenter.x_;
  97. if (index & 2)
  98. newMin.y_ = oldCenter.y_;
  99. else
  100. newMax.y_ = oldCenter.y_;
  101. if (index & 4)
  102. newMin.z_ = oldCenter.z_;
  103. else
  104. newMax.z_ = oldCenter.z_;
  105. children_[index] = new Octant(BoundingBox(newMin, newMax), level_ + 1, this, root_);
  106. return children_[index];
  107. }
  108. void Octant::DeleteChild(unsigned index)
  109. {
  110. delete children_[index];
  111. children_[index] = 0;
  112. }
  113. void Octant::DeleteChild(Octant* octant)
  114. {
  115. for (unsigned i = 0; i < NUM_OCTANTS; ++i)
  116. {
  117. if (children_[i] == octant)
  118. {
  119. delete octant;
  120. children_[i] = 0;
  121. return;
  122. }
  123. }
  124. }
  125. void Octant::InsertDrawable(Drawable* drawable, const Vector3& boxCenter, const Vector3& boxSize)
  126. {
  127. // If size OK or outside, stop recursion & insert here
  128. if (CheckDrawableSize(boxSize) || cullingBox_.IsInside(drawable->GetWorldBoundingBox()) != INSIDE)
  129. {
  130. Octant* oldOctant = drawable->octant_;
  131. if (oldOctant != this)
  132. {
  133. // Add first, then remove, because drawable count going to zero deletes the octree branch in question
  134. AddDrawable(drawable);
  135. if (oldOctant)
  136. oldOctant->RemoveDrawable(drawable, false);
  137. }
  138. return;
  139. }
  140. unsigned x = boxCenter.x_ < center_.x_ ? 0 : 1;
  141. unsigned y = boxCenter.y_ < center_.y_ ? 0 : 2;
  142. unsigned z = boxCenter.z_ < center_.z_ ? 0 : 4;
  143. GetOrCreateChild(x + y + z)->InsertDrawable(drawable, boxCenter, boxSize);
  144. }
  145. bool Octant::CheckDrawableSize(const Vector3& boxSize) const
  146. {
  147. // If max split level, size always OK
  148. if (level_ != root_->GetNumLevels())
  149. return boxSize.x_ >= halfSize_.x_ || boxSize.y_ >= halfSize_.y_ || boxSize.z_ >= halfSize_.z_;
  150. else
  151. return true;
  152. }
  153. void Octant::ResetRoot()
  154. {
  155. root_ = 0;
  156. for (unsigned i = 0; i < NUM_OCTANTS; ++i)
  157. {
  158. if (children_[i])
  159. children_[i]->ResetRoot();
  160. }
  161. }
  162. void Octant::DrawDebugGeometry(DebugRenderer* debug, bool depthTest)
  163. {
  164. debug->AddBoundingBox(worldBoundingBox_, Color(0.25f, 0.25f, 0.25f), depthTest);
  165. for (unsigned i = 0; i < NUM_OCTANTS; ++i)
  166. {
  167. if (children_[i])
  168. children_[i]->DrawDebugGeometry(debug, depthTest);
  169. }
  170. }
  171. void Octant::GetDrawablesInternal(OctreeQuery& query, bool inside) const
  172. {
  173. if (this != root_)
  174. {
  175. Intersection res = query.TestOctant(cullingBox_, inside);
  176. if (res == OUTSIDE)
  177. // Fully outside, so cull this octant, its children & drawables
  178. return;
  179. if (res == INSIDE)
  180. inside = true;
  181. }
  182. for (PODVector<Drawable*>::ConstIterator i = drawables_.Begin(); i != drawables_.End(); ++i)
  183. {
  184. Drawable* drawable = *i;
  185. if (!(drawable->GetDrawableFlags() & query.drawableFlags_) || !(drawable->GetViewMask() & query.viewMask_) ||
  186. (query.shadowCastersOnly_ && !drawable->GetCastShadows()) ||
  187. !drawable->IsVisible())
  188. continue;
  189. if (query.TestDrawable(drawable->GetWorldBoundingBox(), inside) != OUTSIDE)
  190. query.result_.Push(drawable);
  191. }
  192. for (unsigned i = 0; i < NUM_OCTANTS; ++i)
  193. {
  194. if (children_[i])
  195. children_[i]->GetDrawablesInternal(query, inside);
  196. }
  197. }
  198. void Octant::GetDrawablesInternal(RayOctreeQuery& query) const
  199. {
  200. if (!numDrawables_)
  201. return;
  202. float octantDist = query.ray_.HitDistance(cullingBox_);
  203. if (octantDist > query.maxDistance_)
  204. return;
  205. for (PODVector<Drawable*>::ConstIterator i = drawables_.Begin(); i != drawables_.End(); ++i)
  206. {
  207. Drawable* drawable = *i;
  208. unsigned drawableFlags = drawable->GetDrawableFlags();
  209. if (!(drawable->GetDrawableFlags() & query.drawableFlags_) || !(drawable->GetViewMask() & query.viewMask_) ||
  210. !drawable->IsVisible() || (query.shadowCastersOnly_ && !drawable->GetCastShadows()))
  211. continue;
  212. drawable->ProcessRayQuery(query, query.result_);
  213. }
  214. for (unsigned i = 0; i < NUM_OCTANTS; ++i)
  215. {
  216. if (children_[i])
  217. children_[i]->GetDrawablesInternal(query);
  218. }
  219. }
  220. void Octant::GetDrawablesOnlyInternal(RayOctreeQuery& query, PODVector<Drawable*>& drawables) const
  221. {
  222. if (!numDrawables_)
  223. return;
  224. float octantDist = query.ray_.HitDistance(cullingBox_);
  225. if (octantDist > query.maxDistance_)
  226. return;
  227. for (PODVector<Drawable*>::ConstIterator i = drawables_.Begin(); i != drawables_.End(); ++i)
  228. {
  229. Drawable* drawable = *i;
  230. unsigned drawableFlags = drawable->GetDrawableFlags();
  231. if (!(drawable->GetDrawableFlags() & query.drawableFlags_) || !(drawable->GetViewMask() & query.viewMask_) ||
  232. !drawable->IsVisible() || (query.shadowCastersOnly_ && !drawable->GetCastShadows()))
  233. continue;
  234. drawables.Push(drawable);
  235. }
  236. for (unsigned i = 0; i < NUM_OCTANTS; ++i)
  237. {
  238. if (children_[i])
  239. children_[i]->GetDrawablesOnlyInternal(query, drawables);
  240. }
  241. }
  242. void Octant::Release()
  243. {
  244. if (root_ && this != root_)
  245. {
  246. // Remove the drawables (if any) from this octant to the root octant
  247. for (PODVector<Drawable*>::Iterator i = drawables_.Begin(); i != drawables_.End(); ++i)
  248. {
  249. (*i)->SetOctant(root_);
  250. root_->drawables_.Push(*i);
  251. root_->QueueReinsertion(*i);
  252. }
  253. drawables_.Clear();
  254. numDrawables_ = 0;
  255. }
  256. else if (!root_)
  257. {
  258. // If the whole octree is being destroyed, just detach the drawables
  259. for (PODVector<Drawable*>::Iterator i = drawables_.Begin(); i != drawables_.End(); ++i)
  260. (*i)->SetOctant(0);
  261. }
  262. for (unsigned i = 0; i < NUM_OCTANTS; ++i)
  263. DeleteChild(i);
  264. }
  265. OBJECTTYPESTATIC(Octree);
  266. Octree::Octree(Context* context) :
  267. Component(context),
  268. Octant(BoundingBox(-DEFAULT_OCTREE_SIZE, DEFAULT_OCTREE_SIZE), 0, 0, this),
  269. scene_(0),
  270. numLevels_(DEFAULT_OCTREE_LEVELS)
  271. {
  272. // Resize threaded ray query intermediate result vector according to number of worker threads
  273. rayQueryResults_.Resize(GetSubsystem<WorkQueue>()->GetNumThreads() + 1);
  274. }
  275. Octree::~Octree()
  276. {
  277. // Reset root pointer from all child octants now so that they do not move their drawables to root
  278. ResetRoot();
  279. }
  280. void Octree::RegisterObject(Context* context)
  281. {
  282. context->RegisterFactory<Octree>();
  283. Vector3 defaultBoundsMin = Vector3::ONE * DEFAULT_OCTREE_SIZE;
  284. Vector3 defaultBoundsMax = -Vector3::ONE * DEFAULT_OCTREE_SIZE;
  285. ATTRIBUTE(Octree, VAR_VECTOR3, "Bounding Box Min", worldBoundingBox_.min_, defaultBoundsMin, AM_DEFAULT);
  286. ATTRIBUTE(Octree, VAR_VECTOR3, "Bounding Box Max", worldBoundingBox_.max_, defaultBoundsMax, AM_DEFAULT);
  287. ATTRIBUTE(Octree, VAR_INT, "Number of Levels", numLevels_, DEFAULT_OCTREE_LEVELS, AM_DEFAULT);
  288. }
  289. void Octree::OnSetAttribute(const AttributeInfo& attr, const Variant& src)
  290. {
  291. // If any of the (size) attributes change, resize the octree
  292. Serializable::OnSetAttribute(attr, src);
  293. Resize(worldBoundingBox_, numLevels_);
  294. }
  295. void Octree::Resize(const BoundingBox& box, unsigned numLevels)
  296. {
  297. PROFILE(ResizeOctree);
  298. numLevels = Max((int)numLevels, 1);
  299. // If drawables exist, they are temporarily moved to the root
  300. Release();
  301. Vector3 halfSize = box.Size() * 0.5f;
  302. worldBoundingBox_ = box;
  303. cullingBox_ = BoundingBox(worldBoundingBox_.min_ - halfSize, worldBoundingBox_.max_ + halfSize);
  304. numDrawables_ = drawables_.Size();
  305. numLevels_ = numLevels;
  306. }
  307. void Octree::Update(const FrameInfo& frame)
  308. {
  309. UpdateDrawables(frame);
  310. ReinsertDrawables(frame);
  311. }
  312. void Octree::AddManualDrawable(Drawable* drawable, bool culling)
  313. {
  314. if (!drawable || drawable->GetOctant())
  315. return;
  316. if (culling)
  317. AddDrawable(drawable);
  318. else
  319. {
  320. for (Vector<WeakPtr<Drawable> >::ConstIterator i = unculledDrawables_.Begin(); i != unculledDrawables_.End(); ++i)
  321. {
  322. if ((*i) == drawable)
  323. return;
  324. }
  325. unculledDrawables_.Push(WeakPtr<Drawable>(drawable));
  326. }
  327. }
  328. void Octree::RemoveManualDrawable(Drawable* drawable)
  329. {
  330. if (!drawable)
  331. return;
  332. Octant* octant = drawable->GetOctant();
  333. if (octant && octant->GetRoot() == this)
  334. {
  335. CancelUpdate(drawable);
  336. CancelReinsertion(drawable);
  337. octant->RemoveDrawable(drawable);
  338. }
  339. else
  340. {
  341. for (Vector<WeakPtr<Drawable> >::Iterator i = unculledDrawables_.Begin(); i != unculledDrawables_.End(); ++i)
  342. {
  343. if ((*i) == drawable)
  344. {
  345. unculledDrawables_.Erase(i);
  346. return;
  347. }
  348. }
  349. }
  350. }
  351. void Octree::GetDrawables(OctreeQuery& query) const
  352. {
  353. query.result_.Clear();
  354. GetDrawablesInternal(query, false);
  355. }
  356. void Octree::GetUnculledDrawables(PODVector<Drawable*>& dest, unsigned char drawableFlags) const
  357. {
  358. for (Vector<WeakPtr<Drawable> >::ConstIterator i = unculledDrawables_.Begin(); i != unculledDrawables_.End(); ++i)
  359. {
  360. if (*i && (*i)->IsVisible() && (*i)->GetDrawableFlags() & drawableFlags)
  361. dest.Push(*i);
  362. }
  363. }
  364. void Octree::Raycast(RayOctreeQuery& query) const
  365. {
  366. PROFILE(Raycast);
  367. query.result_.Clear();
  368. WorkQueue* queue = GetSubsystem<WorkQueue>();
  369. // If no worker threads or no triangle-level testing, do not create work items
  370. if (!queue->GetNumThreads() || query.level_ < RAY_TRIANGLE)
  371. GetDrawablesInternal(query);
  372. else
  373. {
  374. // Threaded ray query: first get the drawables
  375. rayQuery_ = &query;
  376. rayGetDrawables_.Clear();
  377. GetDrawablesOnlyInternal(query, rayGetDrawables_);
  378. // Check that amount of drawables is large enough to justify threading
  379. if (rayGetDrawables_.Size() > RAYCASTS_PER_WORK_ITEM)
  380. {
  381. for (unsigned i = 0; i < rayQueryResults_.Size(); ++i)
  382. rayQueryResults_[i].Clear();
  383. WorkItem item;
  384. item.workFunction_ = RaycastDrawablesWork;
  385. item.aux_ = const_cast<Octree*>(this);
  386. PODVector<Drawable*>::Iterator start = rayGetDrawables_.Begin();
  387. while (start != rayGetDrawables_.End())
  388. {
  389. PODVector<Drawable*>::Iterator end = rayGetDrawables_.End();
  390. if (end - start > RAYCASTS_PER_WORK_ITEM)
  391. end = start + RAYCASTS_PER_WORK_ITEM;
  392. item.start_ = &(*start);
  393. item.end_ = &(*end);
  394. queue->AddWorkItem(item);
  395. start = end;
  396. }
  397. // Merge per-thread results
  398. queue->Complete();
  399. for (unsigned i = 0; i < rayQueryResults_.Size(); ++i)
  400. query.result_.Insert(query.result_.End(), rayQueryResults_[i].Begin(), rayQueryResults_[i].End());
  401. }
  402. else
  403. {
  404. for (PODVector<Drawable*>::Iterator i = rayGetDrawables_.Begin(); i != rayGetDrawables_.End(); ++i)
  405. (*i)->ProcessRayQuery(query, query.result_);
  406. }
  407. }
  408. Sort(query.result_.Begin(), query.result_.End(), CompareRayQueryResults);
  409. }
  410. void Octree::RaycastSingle(RayOctreeQuery& query) const
  411. {
  412. PROFILE(Raycast);
  413. query.result_.Clear();
  414. rayGetDrawables_.Clear();
  415. GetDrawablesOnlyInternal(query, rayGetDrawables_);
  416. // Sort by increasing hit distance to AABB
  417. for (PODVector<Drawable*>::Iterator i = rayGetDrawables_.Begin(); i != rayGetDrawables_.End(); ++i)
  418. {
  419. Drawable* drawable = *i;
  420. drawable->SetSortValue(query.ray_.HitDistance(drawable->GetWorldBoundingBox()));
  421. }
  422. Sort(rayGetDrawables_.Begin(), rayGetDrawables_.End(), CompareDrawables);
  423. // Then do the actual test according to the query, and early-out as possible
  424. float closestHit = M_INFINITY;
  425. for (PODVector<Drawable*>::Iterator i = rayGetDrawables_.Begin(); i != rayGetDrawables_.End(); ++i)
  426. {
  427. Drawable* drawable = *i;
  428. if (drawable->GetSortValue() <= Min(closestHit, query.maxDistance_))
  429. {
  430. unsigned oldSize = query.result_.Size();
  431. drawable->ProcessRayQuery(query, query.result_);
  432. if (query.result_.Size() > oldSize)
  433. closestHit = Min(closestHit, query.result_.Back().distance_);
  434. }
  435. else
  436. break;
  437. }
  438. if (query.result_.Size() > 1)
  439. {
  440. Sort(query.result_.Begin(), query.result_.End(), CompareRayQueryResults);
  441. query.result_.Resize(1);
  442. }
  443. }
  444. void Octree::QueueUpdate(Drawable* drawable)
  445. {
  446. drawableUpdates_.Push(drawable);
  447. drawable->updateQueued_ = true;
  448. }
  449. void Octree::QueueReinsertion(Drawable* drawable)
  450. {
  451. if (scene_ && scene_->IsThreadedUpdate())
  452. {
  453. MutexLock lock(octreeMutex_);
  454. drawableReinsertions_.Push(drawable);
  455. }
  456. else
  457. drawableReinsertions_.Push(drawable);
  458. drawable->reinsertionQueued_ = true;
  459. }
  460. void Octree::CancelUpdate(Drawable* drawable)
  461. {
  462. PODVector<Drawable*>::Iterator i = drawableUpdates_.Find(drawable);
  463. if (i != drawableUpdates_.End())
  464. {
  465. (*i)->updateQueued_ = false;
  466. drawableUpdates_.Erase(i);
  467. }
  468. }
  469. void Octree::CancelReinsertion(Drawable* drawable)
  470. {
  471. PODVector<Drawable*>::Iterator i = drawableReinsertions_.Find(drawable);
  472. if (i != drawableReinsertions_.End())
  473. {
  474. (*i)->reinsertionQueued_ = false;
  475. drawableReinsertions_.Erase(i);
  476. }
  477. }
  478. void Octree::DrawDebugGeometry(bool depthTest)
  479. {
  480. PROFILE(OctreeDrawDebug);
  481. DebugRenderer* debug = GetComponent<DebugRenderer>();
  482. if (!debug)
  483. return;
  484. Octant::DrawDebugGeometry(debug, depthTest);
  485. }
  486. void Octree::OnNodeSet(Node* node)
  487. {
  488. scene_ = node ? node->GetScene() : 0;
  489. }
  490. void Octree::UpdateDrawables(const FrameInfo& frame)
  491. {
  492. // Let drawables update themselves before reinsertion
  493. if (drawableUpdates_.Empty())
  494. return;
  495. PROFILE(UpdateDrawables);
  496. Scene* scene = node_->GetScene();
  497. WorkQueue* queue = GetSubsystem<WorkQueue>();
  498. scene->BeginThreadedUpdate();
  499. WorkItem item;
  500. item.workFunction_ = UpdateDrawablesWork;
  501. item.aux_ = const_cast<FrameInfo*>(&frame);
  502. PODVector<Drawable*>::Iterator start = drawableUpdates_.Begin();
  503. while (start != drawableUpdates_.End())
  504. {
  505. PODVector<Drawable*>::Iterator end = drawableUpdates_.End();
  506. if (end - start > DRAWABLES_PER_WORK_ITEM)
  507. end = start + DRAWABLES_PER_WORK_ITEM;
  508. item.start_ = &(*start);
  509. item.end_ = &(*end);
  510. queue->AddWorkItem(item);
  511. start = end;
  512. }
  513. queue->Complete();
  514. scene->EndThreadedUpdate();
  515. drawableUpdates_.Clear();
  516. for (unsigned i = unculledDrawables_.Size() - 1; i < unculledDrawables_.Size(); --i)
  517. {
  518. // Remove expired unculled drawables at this point
  519. if (!unculledDrawables_[i])
  520. unculledDrawables_.Erase(i, 1);
  521. }
  522. }
  523. void Octree::ReinsertDrawables(const FrameInfo& frame)
  524. {
  525. if (drawableReinsertions_.Empty())
  526. return;
  527. PROFILE(ReinsertDrawables);
  528. // Reinsert drawables into the octree
  529. for (PODVector<Drawable*>::Iterator i = drawableReinsertions_.Begin(); i != drawableReinsertions_.End(); ++i)
  530. {
  531. Drawable* drawable = *i;
  532. const BoundingBox& box = drawable->GetWorldBoundingBox();
  533. Vector3 boxCenter = box.Center();
  534. Vector3 boxSize = box.Size();
  535. Octant* octant = drawable->GetOctant();
  536. if (octant)
  537. {
  538. if (octant == this)
  539. {
  540. // Handle root octant as special case: if outside the root, do not reinsert
  541. if (GetCullingBox().IsInside(box) == INSIDE && !CheckDrawableSize(boxSize))
  542. InsertDrawable(drawable, boxCenter, boxSize);
  543. }
  544. else
  545. {
  546. // Otherwise reinsert if outside current octant or if size does not fit octant size
  547. if (octant->GetCullingBox().IsInside(box) != INSIDE || !octant->CheckDrawableSize(boxSize))
  548. InsertDrawable(drawable, boxCenter, boxSize);
  549. }
  550. }
  551. else
  552. InsertDrawable(drawable, boxCenter, boxSize);
  553. drawable->reinsertionQueued_ = false;
  554. }
  555. drawableReinsertions_.Clear();
  556. }