From ec65e788e0bd97b23b68cbfd2364a80cbd7244c1 Mon Sep 17 00:00:00 2001 From: kearwood Date: Thu, 22 Sep 2022 22:32:17 -0700 Subject: [PATCH] Scene nodes now persist their order. Implemented error handling and insertion logic for KRContext::createNode Refactored KRNode::m_childNodes to be a std::list rather than a std::set Added stub function, KRNode::createNode, which accepts a KrCreateNodeInfo structure --- kraken/KRContext.cpp | 56 ++++++++++++++++++++++- kraken/KRLODSet.cpp | 6 +-- kraken/KRNode.cpp | 65 ++++++++++++++++++++++----- kraken/KRNode.h | 14 +++--- kraken/KRResource+fbx.cpp | 6 +-- kraken/KRScene.cpp | 6 +-- kraken/public/kraken.h | 7 +-- tests/smoke/hello_cube/hello_cube.cpp | 3 +- 8 files changed, 131 insertions(+), 32 deletions(-) diff --git a/kraken/KRContext.cpp b/kraken/KRContext.cpp index 6e734c6..b8ada8b 100755 --- a/kraken/KRContext.cpp +++ b/kraken/KRContext.cpp @@ -753,19 +753,71 @@ KrResult KRContext::deleteNodeChildren(const KrDeleteNodeChildrenInfo* pDeleteNo KrResult KRContext::createNode(const KrCreateNodeInfo* pCreateNodeInfo) { + if (pCreateNodeInfo->sceneHandle < 0 || pCreateNodeInfo->sceneHandle >= m_resourceMapSize) { + return KR_ERROR_OUT_OF_BOUNDS; + } + KRResource* sceneResource = m_resourceMap[pCreateNodeInfo->sceneHandle]; + if (sceneResource == nullptr) { + return KR_ERROR_NOT_MAPPED; + } + KRScene* scene = dynamic_cast(sceneResource); + if (scene == nullptr) { + return KR_ERROR_INCORRECT_TYPE; + } if (pCreateNodeInfo->newNodeHandle < 0 || pCreateNodeInfo->newNodeHandle >= m_nodeMapSize) { return KR_ERROR_OUT_OF_BOUNDS; } if (pCreateNodeInfo->relativeNodeHandle < 0 || pCreateNodeInfo->relativeNodeHandle >= m_nodeMapSize) { return KR_ERROR_OUT_OF_BOUNDS; } + if (pCreateNodeInfo->location < 0 || pCreateNodeInfo->location >= KR_SCENE_NODE_INSERT_MAX_ENUM) { + return KR_ERROR_OUT_OF_BOUNDS; + } KRNode* relativeNode = nullptr; - if (pCreateNodeInfo->relativeNodeHandle != KR_NULL_HANDLE) { + if (pCreateNodeInfo->relativeNodeHandle == KR_NULL_HANDLE) { + relativeNode = scene->getRootNode(); + } else { // TODO - Handle node deletions by deleting nodes from m_nodeMap relativeNode = m_nodeMap[pCreateNodeInfo->relativeNodeHandle]; + if (relativeNode == nullptr) { + return KR_ERROR_NOT_FOUND; + } } - return KR_ERROR_NOT_IMPLEMENTED; + if (pCreateNodeInfo->location == KR_SCENE_NODE_INSERT_BEFORE || + pCreateNodeInfo->location == KR_SCENE_NODE_INSERT_AFTER) { + // There can only be one root node + if (relativeNode->getParent() == nullptr) { + return KR_ERROR_UNEXPECTED; + } + } + + KRNode* newNode = nullptr; + KrResult res = KRNode::createNode(pCreateNodeInfo, &newNode); + if (res != KR_SUCCESS) { + return res; + } + + if (relativeNode) { + switch (pCreateNodeInfo->location) { + case KR_SCENE_NODE_INSERT_BEFORE: + relativeNode->insertBefore(newNode); + break; + case KR_SCENE_NODE_INSERT_AFTER: + relativeNode->insertAfter(newNode); + break; + case KR_SCENE_NODE_PREPEND_CHILD: + relativeNode->prependChild(newNode); + break; + case KR_SCENE_NODE_APPEND_CHILD: + relativeNode->appendChild(newNode); + break; + default: + assert(false); + return KR_ERROR_NOT_IMPLEMENTED; + } + } + return KR_SUCCESS; } KrResult KRContext::updateNode(const KrUpdateNodeInfo* pUpdateNodeInfo) diff --git a/kraken/KRLODSet.cpp b/kraken/KRLODSet.cpp index 4835875..c2dd333 100755 --- a/kraken/KRLODSet.cpp +++ b/kraken/KRLODSet.cpp @@ -75,7 +75,7 @@ void KRLODSet::updateLODVisibility(const KRViewport& viewport) */ // Upgrade and downgrade LOD groups as needed - for (std::set::iterator itr = m_childNodes.begin(); itr != m_childNodes.end(); ++itr) { + for (std::list::iterator itr = m_childNodes.begin(); itr != m_childNodes.end(); ++itr) { KRLODGroup* lod_group = dynamic_cast(*itr); assert(lod_group != NULL); LodVisibility group_lod_visibility = KRMIN(lod_group->calcLODVisibility(viewport), m_lod_visible); @@ -101,7 +101,7 @@ void KRLODSet::updateLODVisibility(const KRViewport& viewport) if (streamer_ready) { // Upgrade and downgrade LOD groups as needed - for (std::set::iterator itr = m_childNodes.begin(); itr != m_childNodes.end(); ++itr) { + for (std::list::iterator itr = m_childNodes.begin(); itr != m_childNodes.end(); ++itr) { KRLODGroup* lod_group = dynamic_cast(*itr); assert(lod_group != NULL); LodVisibility group_lod_visibility = KRMIN(lod_group->calcLODVisibility(viewport), m_lod_visible); @@ -131,7 +131,7 @@ kraken_stream_level KRLODSet::getStreamLevel(const KRViewport& viewport) KRLODGroup* new_active_lod_group = NULL; // Upgrade and downgrade LOD groups as needed - for (std::set::iterator itr = m_childNodes.begin(); itr != m_childNodes.end(); ++itr) { + for (std::list::iterator itr = m_childNodes.begin(); itr != m_childNodes.end(); ++itr) { KRLODGroup* lod_group = dynamic_cast(*itr); assert(lod_group != NULL); if (lod_group->calcLODVisibility(viewport) == LOD_VISIBILITY_VISIBLE) { diff --git a/kraken/KRNode.cpp b/kraken/KRNode.cpp index 68b492f..2fe9b3d 100755 --- a/kraken/KRNode.cpp +++ b/kraken/KRNode.cpp @@ -145,16 +145,52 @@ bool KRNode::getScaleCompensation() void KRNode::childDeleted(KRNode* child_node) { - m_childNodes.erase(child_node); + // TODO - We should give KRNode's linked list pointers directly and eliminate m_childNodes so that we don't need + // to perform slow std::find operations like this one. + // TODO - FIXME - This is a slow operation... + std::list::iterator itr = std::find(m_childNodes.begin(), m_childNodes.end(), child_node); + if (itr != m_childNodes.end()) { + m_childNodes.erase(itr); + } invalidateBounds(); getScene().notify_sceneGraphModify(this); } -void KRNode::addChild(KRNode* child) +void KRNode::appendChild(KRNode* child) { assert(child->m_parentNode == NULL); child->m_parentNode = this; - m_childNodes.insert(child); + m_childNodes.push_back(child); + child->setLODVisibility(m_lod_visible); // Child node inherits LOD visibility status from parent +} + +void KRNode::prependChild(KRNode* child) +{ + assert(child->m_parentNode == NULL); + child->m_parentNode = this; + m_childNodes.push_front(child); + child->setLODVisibility(m_lod_visible); // Child node inherits LOD visibility status from parent +} +void KRNode::insertBefore(KRNode* child) +{ + assert(m_parentNode != NULL); // There can only be one root node + assert(child->m_parentNode == NULL); + child->m_parentNode = m_parentNode; + std::list::iterator itr = std::find(m_parentNode->m_childNodes.begin(), m_parentNode->m_childNodes.end(), this); + assert(itr != m_parentNode->m_childNodes.end()); + + m_parentNode->m_childNodes.insert(itr, child); + child->setLODVisibility(m_lod_visible); // Child node inherits LOD visibility status from parent +} +void KRNode::insertAfter(KRNode* child) +{ + assert(m_parentNode != NULL); // There can only be one root node + assert(child->m_parentNode == NULL); + child->m_parentNode = m_parentNode; + std::list::iterator itr = std::find(m_parentNode->m_childNodes.begin(), m_parentNode->m_childNodes.end(), this); + assert(itr != m_parentNode->m_childNodes.end()); + itr++; + m_parentNode->m_childNodes.insert(itr, child); child->setLODVisibility(m_lod_visible); // Child node inherits LOD visibility status from parent } @@ -174,13 +210,18 @@ tinyxml2::XMLElement* KRNode::saveXML(tinyxml2::XMLNode* parent) kraken::setXMLAttribute("pre_rotate", e, (m_preRotation * (180.0f / (float)M_PI)), Vector3::Zero()); kraken::setXMLAttribute("post_rotate", e, (m_postRotation * (180.0f / (float)M_PI)), Vector3::Zero()); - for (std::set::iterator itr = m_childNodes.begin(); itr != m_childNodes.end(); ++itr) { + for (std::list::iterator itr = m_childNodes.begin(); itr != m_childNodes.end(); ++itr) { KRNode* child = (*itr); child->saveXML(n); } return e; } +KrResult KRNode::createNode(const KrCreateNodeInfo* pCreateNodeInfo, KRNode** node) +{ + return KR_ERROR_NOT_IMPLEMENTED; +} + void KRNode::loadXML(tinyxml2::XMLElement* e) { m_name = e->Attribute("name"); @@ -227,7 +268,7 @@ void KRNode::loadXML(tinyxml2::XMLElement* e) KRNode* child_node = KRNode::LoadXML(getScene(), child_element); if (child_node) { - addChild(child_node); + appendChild(child_node); } } } @@ -515,7 +556,7 @@ void KRNode::render(const RenderInfo& ri) m_lastRenderFrame = getContext().getCurrentFrame(); } -const std::set& KRNode::getChildren() +const std::list& KRNode::getChildren() { return m_childNodes; } @@ -541,7 +582,7 @@ AABB KRNode::getBounds() AABB bounds = AABB::Zero(); bool first_child = true; - for (std::set::iterator itr = m_childNodes.begin(); itr != m_childNodes.end(); ++itr) { + for (std::list::iterator itr = m_childNodes.begin(); itr != m_childNodes.end(); ++itr) { KRNode* child = (*itr); if (child->getBounds() != AABB::Zero()) { if (first_child) { @@ -564,7 +605,7 @@ void KRNode::invalidateModelMatrix() m_modelMatrixValid = false; m_activePoseMatrixValid = false; m_inverseModelMatrixValid = false; - for (std::set::iterator itr = m_childNodes.begin(); itr != m_childNodes.end(); ++itr) { + for (std::list::iterator itr = m_childNodes.begin(); itr != m_childNodes.end(); ++itr) { KRNode* child = (*itr); child->invalidateModelMatrix(); } @@ -577,7 +618,7 @@ void KRNode::invalidateBindPoseMatrix() { m_bindPoseMatrixValid = false; m_inverseBindPoseMatrixValid = false; - for (std::set::iterator itr = m_childNodes.begin(); itr != m_childNodes.end(); ++itr) { + for (std::list::iterator itr = m_childNodes.begin(); itr != m_childNodes.end(); ++itr) { KRNode* child = (*itr); child->invalidateBindPoseMatrix(); } @@ -956,7 +997,7 @@ void KRNode::addToOctreeNode(KROctreeNode* octree_node) void KRNode::updateLODVisibility(const KRViewport& viewport) { if (m_lod_visible >= LOD_VISIBILITY_PRESTREAM) { - for (std::set::iterator itr = m_childNodes.begin(); itr != m_childNodes.end(); ++itr) { + for (std::list::iterator itr = m_childNodes.begin(); itr != m_childNodes.end(); ++itr) { (*itr)->updateLODVisibility(viewport); } } @@ -973,7 +1014,7 @@ void KRNode::setLODVisibility(KRNode::LodVisibility lod_visibility) m_lod_visible = lod_visibility; - for (std::set::iterator itr = m_childNodes.begin(); itr != m_childNodes.end(); ++itr) { + for (std::list::iterator itr = m_childNodes.begin(); itr != m_childNodes.end(); ++itr) { (*itr)->setLODVisibility(lod_visibility); } } @@ -1010,7 +1051,7 @@ kraken_stream_level KRNode::getStreamLevel(const KRViewport& viewport) { kraken_stream_level stream_level = kraken_stream_level::STREAM_LEVEL_IN_HQ; - for (std::set::iterator itr = m_childNodes.begin(); itr != m_childNodes.end(); ++itr) { + for (std::list::iterator itr = m_childNodes.begin(); itr != m_childNodes.end(); ++itr) { stream_level = KRMIN(stream_level, (*itr)->getStreamLevel(viewport)); } diff --git a/kraken/KRNode.h b/kraken/KRNode.h index 14e017b..0de7e19 100755 --- a/kraken/KRNode.h +++ b/kraken/KRNode.h @@ -115,13 +115,17 @@ public: virtual tinyxml2::XMLElement* saveXML(tinyxml2::XMLNode* parent); static KRNode* LoadXML(KRScene& scene, tinyxml2::XMLElement* e); + static KrResult createNode(const KrCreateNodeInfo* pCreateNodeInfo, KRNode** node); virtual void loadXML(tinyxml2::XMLElement* e); virtual std::string getElementName(); const std::string& getName() const; - void addChild(KRNode* child); - const std::set& getChildren(); + void appendChild(KRNode* child); + void prependChild(KRNode* child); + void insertBefore(KRNode* child); + void insertAfter(KRNode* child); + const std::list& getChildren(); KRNode* getParent(); void setLocalTranslation(const Vector3& v, bool set_original = false); @@ -262,7 +266,7 @@ protected: LodVisibility m_lod_visible; KRNode* m_parentNode; - std::set m_childNodes; + std::list m_childNodes; bool m_animation_mask[KRENGINE_NODE_ATTRIBUTE_COUNT]; @@ -319,7 +323,7 @@ public: return match; } - for (std::set::const_iterator itr = m_childNodes.begin(); itr != m_childNodes.end(); ++itr) { + for (std::list::const_iterator itr = m_childNodes.begin(); itr != m_childNodes.end(); ++itr) { match = (*itr)->find(); if (match) { return match; @@ -338,7 +342,7 @@ public: } } - for (std::set::const_iterator itr = m_childNodes.begin(); itr != m_childNodes.end(); ++itr) { + for (std::list::const_iterator itr = m_childNodes.begin(); itr != m_childNodes.end(); ++itr) { match = (*itr)->find(name); if (match) { return match; diff --git a/kraken/KRResource+fbx.cpp b/kraken/KRResource+fbx.cpp index 7e7bb59..f45810b 100755 --- a/kraken/KRResource+fbx.cpp +++ b/kraken/KRResource+fbx.cpp @@ -966,7 +966,7 @@ void LoadNode(FbxScene* pFbxScene, KRNode* parent_node, FbxGeometryConverter* pG } KRLODSet* lod_set = new KRLODSet(parent_node->getScene(), name); - parent_node->addChild(lod_set); + parent_node->appendChild(lod_set); AABB reference_bounds; // Create a lod_group node for each fbx child node @@ -1026,7 +1026,7 @@ void LoadNode(FbxScene* pFbxScene, KRNode* parent_node, FbxGeometryConverter* pG new_node->setPostRotation(node_post_rotation); new_node->setUseWorldUnits(use_world_space_units); - lod_set->addChild(new_node); + lod_set->appendChild(new_node); LoadNode(pFbxScene, new_node, pGeometryConverter, pNode->GetChild(i)); @@ -1087,7 +1087,7 @@ void LoadNode(FbxScene* pFbxScene, KRNode* parent_node, FbxGeometryConverter* pG new_node->setScalingPivot(node_scaling_pivot); new_node->setPreRotation(node_pre_rotation); new_node->setPostRotation(node_post_rotation); - parent_node->addChild(new_node); + parent_node->appendChild(new_node); // Load child nodes for (int i = 0; i < pNode->GetChildCount(); i++) { diff --git a/kraken/KRScene.cpp b/kraken/KRScene.cpp index 6db3a01..4700da0 100755 --- a/kraken/KRScene.cpp +++ b/kraken/KRScene.cpp @@ -62,7 +62,7 @@ void KRScene::renderFrame(VkCommandBuffer& commandBuffer, KRSurface& surface, fl if (camera == NULL) { // Add a default camera if none are present camera = new KRCamera(*this, "default_camera"); - m_pRootNode->addChild(camera); + m_pRootNode->appendChild(camera); } // FINDME - This should be moved to de-couple Siren from the Rendering pipeline @@ -409,7 +409,7 @@ KRScene* KRScene::Load(KRContext& context, const std::string& name, KRDataBlock* KRNode* n = KRNode::LoadXML(*new_scene, scene_element->FirstChildElement()); if (n) { - new_scene->getRootNode()->addChild(n); + new_scene->getRootNode()->appendChild(n); } @@ -554,7 +554,7 @@ void KRScene::addDefaultLights() KRDirectionalLight* light1 = new KRDirectionalLight(*this, "default_light1"); light1->setLocalRotation((Quaternion::Create(Vector3::Create(0.0f, (float)M_PI * 0.10f, 0.0f)) * Quaternion::Create(Vector3::Create(0.0f, 0.0f, (float)-M_PI * 0.15f))).eulerXYZ()); - m_pRootNode->addChild(light1); + m_pRootNode->appendChild(light1); } AABB KRScene::getRootOctreeBounds() diff --git a/kraken/public/kraken.h b/kraken/public/kraken.h index 3cdfe83..59576cf 100644 --- a/kraken/public/kraken.h +++ b/kraken/public/kraken.h @@ -109,10 +109,11 @@ typedef enum typedef enum { - KR_SCENE_NODE_INSERT_BEFORE, + KR_SCENE_NODE_INSERT_BEFORE = 0, KR_SCENE_NODE_INSERT_AFTER, - KR_SCENE_NODE_INSERT_FIRST_CHILD, - KR_SCENE_NODE_INSERT_LAST_CHILD, + KR_SCENE_NODE_PREPEND_CHILD, + KR_SCENE_NODE_APPEND_CHILD, + KR_SCENE_NODE_INSERT_MAX_ENUM } KrSceneNodeInsertLocation; typedef int KrResourceMapIndex; diff --git a/tests/smoke/hello_cube/hello_cube.cpp b/tests/smoke/hello_cube/hello_cube.cpp index 0731316..a2c6ce1 100644 --- a/tests/smoke/hello_cube/hello_cube.cpp +++ b/tests/smoke/hello_cube/hello_cube.cpp @@ -65,7 +65,8 @@ void smoke_load() KrCreateNodeInfo create_camera_info = { KR_STRUCTURE_TYPE_CREATE_NODE }; res = KrInitNodeInfo(&create_camera_info.node, KR_STRUCTURE_TYPE_NODE_CAMERA); assert(res == KR_SUCCESS); - create_camera_info.relativeNodeHandle = -1; + create_camera_info.relativeNodeHandle = KR_NULL_HANDLE; + create_camera_info.location = KR_SCENE_NODE_APPEND_CHILD; create_camera_info.newNodeHandle = kCameraNodeHandle; create_camera_info.sceneHandle = kSceneResourceHandle; create_camera_info.node.pName = "my_camera";