// Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors. // All rights reserved. // Code licensed under the BSD License. // http://www.anki3d.org/LICENSE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace anki { // Specialize newComponent(). Do that first #define ANKI_DEFINE_SCENE_COMPONENT(name, weight) \ template<> \ name##Component* SceneNode::newComponent() \ { \ auto it = SceneGraph::getSingleton().getComponentArrays().get##name##s().emplace(this); \ it->setArrayIndex(it.getArrayIndex()); \ newComponentInternal(&(*it)); \ return &(*it); \ } #include SceneNode::SceneNode(CString name) : m_uuid(SceneGraph::getSingleton().getNewUuid()) { if(name) { m_name = name; } // Add the implicit MoveComponent newComponent(); } SceneNode::~SceneNode() { for(SceneComponent* comp : m_components) { comp->onDestroy(*this); switch(comp->getType()) { #define ANKI_DEFINE_SCENE_COMPONENT(name, weight) \ case SceneComponentType::k##name: \ SceneGraph::getSingleton().getComponentArrays().get##name##s().erase(comp->getArrayIndex()); \ break; #include default: ANKI_ASSERT(0); } } } void SceneNode::setMarkedForDeletion() { // Mark for deletion only when it's not already marked because we don't want to increase the counter again if(!getMarkedForDeletion()) { m_markedForDeletion = true; SceneGraph::getSingleton().increaseObjectsMarkedForDeletion(); } [[maybe_unused]] const Error err = visitChildren([](SceneNode& obj) -> Error { obj.setMarkedForDeletion(); return Error::kNone; }); } void SceneNode::newComponentInternal(SceneComponent* newc) { m_componentTypeMask |= 1 << SceneComponentTypeMask(newc->getType()); // Inform all other components that some component was added for(SceneComponent* other : m_components) { other->onOtherComponentRemovedOrAdded(newc, true); } // Inform the current component about others for(SceneComponent* other : m_components) { newc->onOtherComponentRemovedOrAdded(other, true); } m_components.emplaceBack(newc); // Sort based on update weight std::sort(m_components.getBegin(), m_components.getEnd(), [](const SceneComponent* a, const SceneComponent* b) { const F32 weightA = SceneComponent::getUpdateOrderWeight(a->getType()); const F32 weightB = SceneComponent::getUpdateOrderWeight(b->getType()); if(weightA != weightB) { return weightA < weightB; } else { return a->getType() < b->getType(); } }); } Bool SceneNode::updateTransform() { const Bool needsUpdate = m_localTransformDirty; m_localTransformDirty = false; const Bool updatedLastFrame = m_transformUpdatedThisFrame; m_transformUpdatedThisFrame = needsUpdate; if(needsUpdate || updatedLastFrame) { m_prevWTrf = m_wtrf; } // Update world transform if(needsUpdate) { const SceneNode* parent = getParent(); if(parent == nullptr || m_ignoreParentNodeTransform) { m_wtrf = m_ltrf; } else { m_wtrf = parent->getWorldTransform().combineTransformations(m_ltrf); } // Make children dirty as well. Don't walk the whole tree because you will re-walk it later [[maybe_unused]] const Error err = visitChildrenMaxDepth(1, [](SceneNode& childNode) -> Error { if(!childNode.m_ignoreParentNodeTransform) { childNode.m_localTransformDirty = true; } return Error::kNone; }); } return needsUpdate; } } // end namespace anki