#include "scenenode.h" #include "scenetree.h" #include "glm/ext.hpp" #include #include #include #include #include Engine &SceneNode::getEngine() { return m_scene->getEngine(); } void SceneNode::setParent(SceneNode* parent) { if(m_toDestroy && parent == nullptr) delete this; else m_parent = parent; } SceneNode::SceneNode(Script* script) : m_toDestroy(false), m_parentVisible(true), m_visible(true), m_enabled(true), m_transformChanged(true), m_parent(nullptr), m_scene(nullptr), m_geometry(nullptr, glm::mat4()), m_light(nullptr), m_transform(glm::mat4()), m_script(script), m_rigidBody(nullptr), m_motionState(this) { if(m_script != nullptr) m_script->begin(this); } SceneNode::~SceneNode() { if(m_script != nullptr) m_script->end(this); setVisible(false); setSceneTree(nullptr); for(SceneNode* child : m_children) delete child; } void SceneNode::updateLightSource() { switch(m_light->getType()) { case Light::DIRECTIONNAL : { DirectionnalLight *l = (DirectionnalLight*)m_light; l->setDir(glm::mat3(m_geometry.modelMatrix) * l->getDir()); if(l->isShadowCaster()) l->updateShadowMap(getScene()); } break; case Light::POINT : { PointLight *l = (PointLight*)m_light; l->setPos(l->getPos() + glm::vec3(m_geometry.modelMatrix[3])); } break; case Light::SPOT : // TODO break; case Light::AMBIENT : default: break; } } void SceneNode::update() { for(SceneNode* node : m_nodesToRemove) { for(auto it = m_children.begin(); it != m_children.end();) { if(*it == node) { it = m_children.erase(it); node->setSceneTree(nullptr); node->setParent(nullptr); } else ++it; } } m_nodesToRemove.clear(); for(SceneNode* node : m_nodesToAdd) { if(m_scene != nullptr) node->setSceneTree(m_scene); m_children.push_back(node); node->setParent(this); node->setParentTransform(m_transform); node->setParentVisible(isVisible()); } m_nodesToAdd.clear(); if(m_enabled) { if(m_transformChanged) { m_geometry.modelMatrix = m_parentTransform * m_transform; if(m_light != nullptr) updateLightSource(); } if(m_script != nullptr) m_script->update(this); for(SceneNode* child : m_children) { if(m_transformChanged) child->setParentTransform(m_geometry.modelMatrix); child->update(); } } } void SceneNode::setSceneTree(SceneTree *tree) { if(isVisible()) { if(m_scene != nullptr) m_scene->removeFromIndex(this); if(tree != nullptr) tree->addToIndex(this); } m_scene = tree; if(m_scene != nullptr && m_geometry.mesh != nullptr) m_scene->registerMeshType(m_geometry.mesh->getFlags()); if(m_scene != nullptr && m_light != nullptr) m_scene->registerLightType(m_light->getFlags()); for(SceneNode* child : m_children) child->setSceneTree(tree); } void SceneNode::resetTransform() { setTransform(glm::mat4()); } // tools void SceneNode::moveTo(const glm::vec3 &position) { m_transform = glm::translate(glm::mat4(), position); m_transformChanged = true; } void SceneNode::translate(const glm::vec3 &vector) { m_transform = glm::translate(m_transform, vector); m_transformChanged = true; } void SceneNode::lookAt(const glm::vec3 &target, const glm::vec3 &upVector) { glm::vec3 pos = glm::vec3(m_transform[3]); m_transform = glm::lookAt(pos, target, upVector); m_transformChanged = true; } void SceneNode::rotate(float angle, const glm::vec3 &vector) { m_transform = glm::rotate(m_transform, angle, vector); m_transformChanged = true; } void SceneNode::scale(const glm::vec3 &scaleFactor) { m_transform = glm::scale(m_transform, scaleFactor); m_transformChanged = true; } float SceneNode::getDepth() { m_geometry.mesh->getDepth(); } void SceneNode::setDepth(float depth) { m_geometry.mesh->setDepth(depth); } // setters void SceneNode::setTransform(const glm::mat4 &transform) { m_transform = transform; m_transformChanged = true; } // could be optimised by just storing a pointer, but unexpected behavior may happen ? void SceneNode::setParentTransform(const glm::mat4 &transform) { m_parentTransform = transform; m_transformChanged = true; } void SceneNode::setVisible(bool visible) { if(m_parentVisible) { if(m_visible && !visible) updateVisibility(false); if(visible && !m_visible) updateVisibility(true); } m_visible = visible; } void SceneNode::setParentVisible(bool visible) { if(m_visible) { if(m_parentVisible && !visible) updateVisibility(false); if(visible && !m_parentVisible) updateVisibility(true); } m_parentVisible = visible; } void SceneNode::addChild(SceneNode *node) { if(node != nullptr) m_nodesToAdd.push_back(node); } void SceneNode::removeChild(SceneNode *node) { if(node != nullptr) m_nodesToRemove.push_back(node); } void SceneNode::updateVisibility(bool visible) { for(SceneNode* child : m_children) child->setParentVisible(visible); if(m_scene != nullptr) { if(visible) m_scene->addToIndex(this); else m_scene->removeFromIndex(this); } } void SceneNode::SparrowMotionState::getWorldTransform(btTransform& worldTrans ) const { worldTrans.setFromOpenGLMatrix(glm::value_ptr(m_node->getTransform())); } void SceneNode::SparrowMotionState::setWorldTransform(const btTransform& worldTrans) { glm::mat4 t; worldTrans.getOpenGLMatrix(glm::value_ptr(t)); m_node->setTransform(t); } void SceneNode::setRigidBody(btRigidBody* body) { m_rigidBody = body; if(m_rigidBody != nullptr) m_rigidBody->setUserPointer(this); }