SparrowEngine/src/scene/scenenode.cpp
2018-01-31 23:40:51 +01:00

276 lines
6.3 KiB
C++

#include "scenenode.h"
#include "scenetree.h"
#include "glm/ext.hpp"
#include <iostream>
#include <imgui/imgui.h>
#include <SparrowRenderer/mesh.h>
#include <bullet/btBulletCollisionCommon.h>
#include <bullet/btBulletDynamicsCommon.h>
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);
}