From cd3627c3d3c0b4501015318f9bef15362e3bcb2d Mon Sep 17 00:00:00 2001 From: Kearwood Gilbert Date: Thu, 21 Feb 2013 16:22:56 -0800 Subject: [PATCH] Fixed bug that caused the application to crash when deleting or moving nodes in the Octree Changes to the Octruee due to adding and updating object positions is now delayed until after the end of the frame --- KREngine/kraken/KRHitInfo.h | 3 +- KREngine/kraken/KRNode.cpp | 23 +++++++++++++ KREngine/kraken/KRNode.h | 6 ++++ KREngine/kraken/KROctree.cpp | 9 +++-- KREngine/kraken/KROctree.h | 1 - KREngine/kraken/KROctreeNode.cpp | 29 ++++++++++++---- KREngine/kraken/KROctreeNode.h | 7 ++-- KREngine/kraken/KRScene.cpp | 58 ++++++++++++++++++-------------- 8 files changed, 94 insertions(+), 42 deletions(-) diff --git a/KREngine/kraken/KRHitInfo.h b/KREngine/kraken/KRHitInfo.h index e63c5a6..ecadc52 100644 --- a/KREngine/kraken/KRHitInfo.h +++ b/KREngine/kraken/KRHitInfo.h @@ -33,7 +33,8 @@ #define KRHITINFO_H #include "KRVector3.h" -#include "KRNode.h" + +class KRNode; class KRHitInfo { public: diff --git a/KREngine/kraken/KRNode.cpp b/KREngine/kraken/KRNode.cpp index 3bd5546..d118a41 100644 --- a/KREngine/kraken/KRNode.cpp +++ b/KREngine/kraken/KRNode.cpp @@ -409,3 +409,26 @@ void KRNode::SetAttribute(node_attribute_type attrib, float v) } } +void KRNode::removeFromOctreeNodes() +{ + for(std::set::iterator itr=m_octree_nodes.begin(); itr != m_octree_nodes.end(); itr++) { + KROctreeNode *octree_node = *itr; + octree_node->remove(this); + + // FINDME, TODO - This should be moved to the KROctree class + while(octree_node) { + octree_node->trim(); + if(octree_node->isEmpty()) { + octree_node = octree_node->getParent(); + } else { + octree_node = NULL; + } + } + } + m_octree_nodes.clear(); +} + +void KRNode::addToOctreeNode(KROctreeNode *octree_node) +{ + m_octree_nodes.insert(octree_node); +} diff --git a/KREngine/kraken/KRNode.h b/KREngine/kraken/KRNode.h index cff71f4..4992d38 100644 --- a/KREngine/kraken/KRNode.h +++ b/KREngine/kraken/KRNode.h @@ -13,6 +13,7 @@ #include "KRVector3.h" #include "KRViewport.h" #include "tinyxml2.h" +#include "KROctreeNode.h" class KRCamera; class KRShaderManager; @@ -131,8 +132,13 @@ private: KRScene *m_pScene; + std::set m_octree_nodes; + public: + void removeFromOctreeNodes(); + void addToOctreeNode(KROctreeNode *octree_node); + template T *find() { T *match = dynamic_cast(this); diff --git a/KREngine/kraken/KROctree.cpp b/KREngine/kraken/KROctree.cpp index 18b1045..ffc22f4 100644 --- a/KREngine/kraken/KROctree.cpp +++ b/KREngine/kraken/KROctree.cpp @@ -32,8 +32,7 @@ void KROctree::add(KRNode *pNode) } else { if(m_pRootNode == NULL) { // First item inserted, create a node large enough to fit it - m_pRootNode = new KROctreeNode(nodeBounds); - //m_pRootNode = new KROctreeNode(KRAABB(nodeBounds.min - nodeBounds.size() * 0.25f, nodeBounds.max + nodeBounds.size() * 0.25f)); + m_pRootNode = new KROctreeNode(NULL, nodeBounds); m_pRootNode->add(pNode); } else { // Keep encapsulating the root node until the new root contains the inserted node @@ -42,9 +41,9 @@ void KROctree::add(KRNode *pNode) KRAABB rootBounds = m_pRootNode->getBounds(); KRVector3 rootSize = rootBounds.size(); if(nodeBounds.min.x < rootBounds.min.x || nodeBounds.min.y < rootBounds.min.y || nodeBounds.min.z < rootBounds.min.z) { - m_pRootNode = new KROctreeNode(KRAABB(rootBounds.min - rootSize, rootBounds.max), 7, m_pRootNode); + m_pRootNode = new KROctreeNode(NULL, KRAABB(rootBounds.min - rootSize, rootBounds.max), 7, m_pRootNode); } else if(nodeBounds.max.x > rootBounds.max.x || nodeBounds.max.y > rootBounds.max.y || nodeBounds.max.z > rootBounds.max.z) { - m_pRootNode = new KROctreeNode(KRAABB(rootBounds.min, rootBounds.max + rootSize), 0, m_pRootNode); + m_pRootNode = new KROctreeNode(NULL, KRAABB(rootBounds.min, rootBounds.max + rootSize), 0, m_pRootNode); } else { bInsideRoot = true; } @@ -58,7 +57,7 @@ void KROctree::remove(KRNode *pNode) { if(!m_outerSceneNodes.erase(pNode)) { if(m_pRootNode) { - m_pRootNode->remove(pNode); + pNode->removeFromOctreeNodes(); } } diff --git a/KREngine/kraken/KROctree.h b/KREngine/kraken/KROctree.h index 5a97c5e..7f0cd12 100644 --- a/KREngine/kraken/KROctree.h +++ b/KREngine/kraken/KROctree.h @@ -34,7 +34,6 @@ public: private: KROctreeNode *m_pRootNode; std::set m_outerSceneNodes; - //std::set visibleMVPs; void shrink(); }; diff --git a/KREngine/kraken/KROctreeNode.cpp b/KREngine/kraken/KROctreeNode.cpp index e71c6c0..490b7f7 100644 --- a/KREngine/kraken/KROctreeNode.cpp +++ b/KREngine/kraken/KROctreeNode.cpp @@ -10,8 +10,10 @@ #include "KRNode.h" #include "KRCollider.h" -KROctreeNode::KROctreeNode(const KRAABB &bounds) : m_bounds(bounds) +KROctreeNode::KROctreeNode(KROctreeNode *parent, const KRAABB &bounds) : m_bounds(bounds) { + m_parent = parent; + for(int i=0; i<8; i++) m_children[i] = NULL; m_occlusionQuery = 0; @@ -19,11 +21,14 @@ KROctreeNode::KROctreeNode(const KRAABB &bounds) : m_bounds(bounds) m_activeQuery = false; } -KROctreeNode::KROctreeNode(const KRAABB &bounds, int iChild, KROctreeNode *pChild) : m_bounds(bounds) +KROctreeNode::KROctreeNode(KROctreeNode *parent, const KRAABB &bounds, int iChild, KROctreeNode *pChild) : m_bounds(bounds) { // This constructor is used when expanding the octree and replacing the root node with a new root that encapsulates it + m_parent = parent; + for(int i=0; i<8; i++) m_children[i] = NULL; m_children[iChild] = pChild; + pChild->m_parent = this; m_occlusionQuery = 0; m_occlusionTested = false; @@ -81,9 +86,10 @@ void KROctreeNode::add(KRNode *pNode) int iChild = getChildIndex(pNode); if(iChild == -1) { m_sceneNodes.insert(pNode); + pNode->addToOctreeNode(this); } else { if(m_children[iChild] == NULL) { - m_children[iChild] = new KROctreeNode(getChildBounds(iChild)); + m_children[iChild] = new KROctreeNode(this, getChildBounds(iChild)); } m_children[iChild]->add(pNode); } @@ -115,12 +121,10 @@ int KROctreeNode::getChildIndex(KRNode *pNode) return -1; } -void KROctreeNode::remove(KRNode *pNode) +void KROctreeNode::trim() { - if(!m_sceneNodes.erase(pNode)) { - int iChild = getChildIndex(pNode); + for(int iChild = 0; iChild < 8; iChild++) { if(m_children[iChild]) { - m_children[iChild]->remove(pNode); if(m_children[iChild]->isEmpty()) { delete m_children[iChild]; m_children[iChild] = NULL; @@ -129,6 +133,11 @@ void KROctreeNode::remove(KRNode *pNode) } } +void KROctreeNode::remove(KRNode *pNode) +{ + m_sceneNodes.erase(pNode); +} + void KROctreeNode::update(KRNode *pNode) { @@ -162,6 +171,7 @@ KROctreeNode *KROctreeNode::stripChild() for(int i=0; i<8; i++) { if(m_children[i]) { KROctreeNode *child = m_children[i]; + child->m_parent = NULL; m_children[i] = NULL; return child; } @@ -170,6 +180,11 @@ KROctreeNode *KROctreeNode::stripChild() } +KROctreeNode *KROctreeNode::getParent() +{ + return m_parent; +} + KROctreeNode **KROctreeNode::getChildren() { return m_children; diff --git a/KREngine/kraken/KROctreeNode.h b/KREngine/kraken/KROctreeNode.h index b33ab65..c1bb7cf 100644 --- a/KREngine/kraken/KROctreeNode.h +++ b/KREngine/kraken/KROctreeNode.h @@ -18,8 +18,8 @@ class KRNode; class KROctreeNode { public: - KROctreeNode(const KRAABB &bounds); - KROctreeNode(const KRAABB &bounds, int iChild, KROctreeNode *pChild); + KROctreeNode(KROctreeNode *parent, const KRAABB &bounds); + KROctreeNode(KROctreeNode *parent, const KRAABB &bounds, int iChild, KROctreeNode *pChild); ~KROctreeNode(); KROctreeNode **getChildren(); @@ -31,9 +31,11 @@ public: KRAABB getBounds(); + KROctreeNode *getParent(); void setChildNode(int iChild, KROctreeNode *pChild); int getChildIndex(KRNode *pNode); KRAABB getChildBounds(int iChild); + void trim(); bool isEmpty() const; bool canShrinkRoot() const; @@ -53,6 +55,7 @@ private: KRAABB m_bounds; + KROctreeNode *m_parent; KROctreeNode *m_children[8]; std::setm_sceneNodes; diff --git a/KREngine/kraken/KRScene.cpp b/KREngine/kraken/KRScene.cpp index c4d0ea9..acd8b51 100644 --- a/KREngine/kraken/KRScene.cpp +++ b/KREngine/kraken/KRScene.cpp @@ -73,7 +73,7 @@ void KRScene::renderFrame(float deltaTime, int width, int height) { } void KRScene::render(KRCamera *pCamera, std::map &visibleBounds, const KRViewport &viewport, KRNode::RenderPass renderPass, bool new_frame) { - + updateOctree(); if(new_frame) { @@ -97,7 +97,6 @@ void KRScene::render(KRCamera *pCamera, std::map &visibleBounds, co std::vector lights; - updateOctree(); pCamera->settings.setSkyBox(m_skyBoxName); // This is temporary until the camera is moved into the scene graph @@ -383,40 +382,47 @@ KRLight *KRScene::getFirstLight() void KRScene::notify_sceneGraphCreate(KRNode *pNode) { - m_nodeTree.add(pNode); - if(pNode->hasPhysics()) { - m_physicsNodes.insert(pNode); - } -// m_newNodes.insert(pNode); +// m_nodeTree.add(pNode); +// if(pNode->hasPhysics()) { +// m_physicsNodes.insert(pNode); +// } + m_newNodes.insert(pNode); +} + +void KRScene::notify_sceneGraphModify(KRNode *pNode) +{ + // m_nodeTree.update(pNode); + m_modifiedNodes.insert(pNode); } void KRScene::notify_sceneGraphDelete(KRNode *pNode) { m_nodeTree.remove(pNode); m_physicsNodes.erase(pNode); -// -// m_modifiedNodes.erase(pNode); -// if(!m_newNodes.erase(pNode)) { -// m_nodeTree.remove(pNode); -// } -} - -void KRScene::notify_sceneGraphModify(KRNode *pNode) -{ - m_nodeTree.update(pNode); -// m_modifiedNodes.insert(pNode); + m_modifiedNodes.erase(pNode); + if(!m_newNodes.erase(pNode)) { + m_nodeTree.remove(pNode); + } } void KRScene::updateOctree() { -// for(std::set::iterator itr=m_newNodes.begin(); itr != m_newNodes.end(); itr++) { -// m_nodeTree.add(*itr); -// } -// for(std::set::iterator itr=m_modifiedNodes.begin(); itr != m_modifiedNodes.end(); itr++) { -// m_nodeTree.update(*itr); -// } -// m_newNodes.clear(); -// m_modifiedNodes.clear(); + std::set newNodes = m_newNodes; + std::set modifiedNodes = m_modifiedNodes; + m_newNodes.clear(); + m_modifiedNodes.clear(); + + for(std::set::iterator itr=newNodes.begin(); itr != newNodes.end(); itr++) { + KRNode *node = *itr; + m_nodeTree.add(node); + if(node->hasPhysics()) { + m_physicsNodes.insert(node); + } + } + for(std::set::iterator itr=modifiedNodes.begin(); itr != modifiedNodes.end(); itr++) { + KRNode *node = *itr; + m_nodeTree.update(node); + } } void KRScene::physicsUpdate(float deltaTime)