/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #include "Node.hpp" #include "Base/Utils.hpp" #include "Base/Logger.hpp" #include namespace OpenVulkano::Scene { Node::Node() : localMat(1), worldMat(1), enabled(true) {} Node::Node(const Math::Matrix4f& pose) : localMat(pose), worldMat(pose), enabled(true) {} Node::~Node() noexcept { if (parent || scene || !children.empty() || !drawables.empty()) { Node::Close(); } } void Node::Init() { if (parent || scene || !children.empty() || !drawables.empty()) throw std::runtime_error("Node already initialized"); localMat = worldMat = Math::Matrix4f(1); enabled = true; } void Node::Close() { children.clear(); GetRenderResource().Release(); parent = nullptr; scene = nullptr; enabled = false; if (!children.empty()) Logger::SCENE->warn("Closing Node that has children!"); for (Node* child : children) { child->SetParent(nullptr); } children.clear(); for(Drawable* drawable : drawables) { drawable->RemoveNode(this); } drawables.clear(); } void Node::AddChild(Node* node) { node->SetParent(this); children.push_back(node); node->UpdateWorldMatrix(worldMat); } void Node::AddChildIfParentless(Node* node) { if (!node->parent) AddChild(node); } void Node::RemoveChild(Node* node) { if (node->parent == this) { Utils::Remove(children, node); node->SetParent(nullptr); } } void Node::RemoveChildNodes() { for (Node* node : children) { node->SetParent(nullptr); } children.clear(); } void Node::AddDrawable(Drawable* drawable) { if (scene) drawable->SetScene(scene); else if (drawable->GetScene()) Logger::SCENE->warn("Drawable is already associated with a scene, but the node it was added to is not!"); drawable->AddNode(this); drawables.push_back(drawable); } void Node::AddDrawableIfParentless(Drawable* drawable) { if (drawable->GetNodes().empty()) AddDrawable(drawable); } void Node::RemoveDrawable(Drawable* drawable) { drawable->RemoveNode(this); Utils::Remove(drawables, drawable); } void Node::SetMatrix(const Math::Matrix4f& mat) { localMat = mat; UpdateWorldMatrix(parent ? parent->GetWorldMatrix() : Math::Matrix4f(1)); } Node* Node::GetRoot() { if (IsRoot() || !parent) { return this; } return parent->GetRoot(); } void Node::UpdateWorldMatrix(const Math::Matrix4f& parentWorldMat) { worldMat = parentWorldMat * localMat; for (const auto& node : children) { node->UpdateWorldMatrix(worldMat); } } void Node::SetParent(Node* parent) { if (this->parent && parent) throw std::runtime_error("Node already has a parent! Nodes must not be used multiple times!"); this->parent = parent; if(parent && parent != this) SetScene(parent->scene); if (!parent) SetScene(nullptr); } void Node::SetScene(Scene* scene) { if (this->scene && scene) throw std::runtime_error("Node already has a scene!"); this->scene = scene; for (const auto& node : children) { node->SetScene(scene); } for (auto& drawable : drawables) { if (scene) { Scene* drawableScene = drawable->GetScene(); if(drawableScene && drawableScene != scene) [[unlikely]] { throw std::runtime_error("Drawable is already associated with a scene! Creating copy."); } } drawable->SetScene(scene); } } }