blob: 5743576c755a2ea532cea44a1e8d1e8e007a7581 [file] [log] [blame]
#include "ActorNode.hpp"
#include "BlockReader.hpp"
#include <algorithm>
#include <cassert>
using namespace nima;
ActorNode::ActorNode(Actor* actor) : ActorNode(actor, ComponentType::ActorNode)
{
}
ActorNode::ActorNode(ComponentType type) : ActorNode(nullptr, type)
{
}
ActorNode::ActorNode(Actor* actor, ComponentType type) :
ActorComponent(actor, type),
m_Rotation(0.0f),
m_Scale(1.0f, 1.0f),
m_Opacity(1.0f),
m_RenderOpacity(1.0f),
m_IsDirty(true),
m_IsWorldDirty(true),
m_SuppressMarkDirty(false),
m_OverrideWorldTransform(false),
m_OverrideRotation(false),
m_OverrideRotationValue(0.0f)
{
}
ActorNode::ActorNode() : ActorNode(nullptr, ComponentType::ActorNode)
{
}
ActorNode::~ActorNode()
{
}
bool ActorNode::suppressMarkDirty() const
{
return m_SuppressMarkDirty;
}
void ActorNode::suppressMarkDirty(bool suppress)
{
m_SuppressMarkDirty = suppress;
}
bool ActorNode::isWorldDirty() const
{
return m_IsWorldDirty;
}
bool ActorNode::isDirty() const
{
return m_IsDirty;
}
const Mat2D& ActorNode::transform()
{
if(m_IsDirty)
{
updateTransform();
}
return m_Transform;
}
const Mat2D& ActorNode::worldTransform()
{
if(m_IsWorldDirty)
{
updateWorldTransform();
}
return m_WorldTransform;
}
void ActorNode::overrideWorldTransform(const Mat2D& transform)
{
m_OverrideWorldTransform = true;
Mat2D::copy(m_WorldTransform, transform);
markWorldDirty();
}
void ActorNode::clearWorldTransformOverride()
{
if(!m_OverrideWorldTransform)
{
return;
}
m_OverrideWorldTransform = false;
markWorldDirty();
}
float ActorNode::x() const
{
return m_Translation[0];
}
void ActorNode::x(float v)
{
if(m_Translation[0] == v)
{
return;
}
m_Translation[0] = v;
markDirty();
markWorldDirty();
}
float ActorNode::y() const
{
return m_Translation[1];
}
void ActorNode::y(float v)
{
if(m_Translation[1] == v)
{
return;
}
m_Translation[1] = v;
markDirty();
markWorldDirty();
}
float ActorNode::scaleX() const
{
return m_Scale[0];
}
void ActorNode::scaleX(float v)
{
if(m_Scale[0] == v)
{
return;
}
m_Scale[0] = v;
markDirty();
markWorldDirty();
}
float ActorNode::scaleY() const
{
return m_Scale[1];
}
void ActorNode::scaleY(float v)
{
if(m_Scale[1] == v)
{
return;
}
m_Scale[1] = v;
markDirty();
markWorldDirty();
}
float ActorNode::rotation() const
{
return m_Rotation;
}
void ActorNode::rotation(float v)
{
if(m_Rotation == v)
{
return;
}
m_Rotation = v;
markDirty();
markWorldDirty();
}
float ActorNode::opacity() const
{
return m_Opacity;
}
void ActorNode::opacity(float v)
{
if(m_Opacity == v)
{
return;
}
m_Opacity = v;
markWorldDirty();
}
float ActorNode::renderOpacity() const
{
return m_RenderOpacity;
}
void ActorNode::markDirty()
{
if(m_IsDirty)
{
return;
}
m_IsDirty = true;
}
void ActorNode::markWorldDirty()
{
if(m_IsWorldDirty || m_SuppressMarkDirty)
{
return;
}
m_IsWorldDirty = true;
for(ActorNode* node : m_Children)
{
node->markWorldDirty();
}
for(ActorNode* node : m_Dependents)
{
node->markWorldDirty();
}
}
void ActorNode::addDependent(ActorNode* node)
{
// Make sure it's not already a dependent.
assert(std::find(m_Dependents.begin(), m_Dependents.end(), node) == m_Dependents.end());
m_Dependents.push_back(node);
}
void ActorNode::removeDependent(ActorNode* node)
{
auto itr = std::find(m_Dependents.begin(), m_Dependents.end(), node);
if(itr == m_Dependents.end())
{
return;
}
m_Dependents.erase(itr);
}
Vec2D ActorNode::worldTranslation()
{
Vec2D result;
if(m_IsWorldDirty)
{
updateWorldTransform();
}
result[0] = m_WorldTransform[4];
result[1] = m_WorldTransform[5];
return result;
}
void ActorNode::worldTranslation(Vec2D& result)
{
if(m_IsWorldDirty)
{
updateWorldTransform();
}
result[0] = m_WorldTransform[4];
result[1] = m_WorldTransform[5];
}
void ActorNode::setRotationOverride(float v)
{
if(!m_OverrideRotation || m_OverrideRotationValue != v)
{
m_OverrideRotation = true;
m_OverrideRotationValue = v;
markDirty();
markWorldDirty();
}
}
void ActorNode::clearRotationOverride()
{
if(m_OverrideRotation)
{
m_OverrideRotation = false;
markDirty();
markWorldDirty();
}
}
float ActorNode::overrideRotationValue() const
{
return m_OverrideRotationValue;
}
void ActorNode::updateTransform()
{
m_IsDirty = false;
Mat2D::fromRotation(m_Transform, m_OverrideRotation ? m_OverrideRotationValue : m_Rotation);
m_Transform[4] = m_Translation[0];
m_Transform[5] = m_Translation[1];
Mat2D::scale(m_Transform, m_Transform, m_Scale);
}
void ActorNode::updateTransforms()
{
if(m_IsDirty)
{
updateTransform();
}
if(m_IsWorldDirty)
{
updateWorldTransform();
}
}
void ActorNode::updateWorldTransform()
{
m_IsWorldDirty = false;
if(m_IsDirty)
{
updateTransform();
}
m_RenderOpacity = m_Opacity;
if(m_Parent != nullptr)
{
m_Parent->updateTransforms();
m_RenderOpacity *= m_Parent->renderOpacity();
if(!m_OverrideWorldTransform)
{
Mat2D::multiply(m_WorldTransform, m_Parent->m_WorldTransform, m_Transform);
}
}
else if(!m_OverrideWorldTransform)
{
Mat2D::copy(m_WorldTransform, m_Transform);
}
}
void ActorNode::addChild(ActorNode* node)
{
assert(node != nullptr);
if(node->m_Parent != nullptr)
{
node->m_Parent->removeChild(node);
}
node->m_Parent = this;
m_Children.push_back(node);
}
void ActorNode::removeChild(ActorNode* node)
{
auto itr = std::find(m_Children.begin(), m_Children.end(), node);
if(itr == m_Children.end())
{
return;
}
m_Children.erase(itr);
node->m_Parent = nullptr;
}
void ActorNode::resolveComponentIndices(ActorComponent** components)
{
Base::resolveComponentIndices(components);
}
ActorComponent* ActorNode::makeInstance(Actor* resetActor)
{
ActorNode* instanceNode = new ActorNode();
instanceNode->copy(this, resetActor);
return instanceNode;
}
void ActorNode::copy(ActorNode* node, Actor* resetActor)
{
Base::copy(node, resetActor);
m_IsDirty = true;
m_IsWorldDirty = true;
Mat2D::copy(m_Transform, node->m_Transform);
Mat2D::copy(m_WorldTransform, node->m_WorldTransform);
Vec2D::copy(m_Translation, node->m_Translation);
Vec2D::copy(m_Scale, node->m_Scale);
m_Rotation = node->m_Rotation;
m_Opacity = node->m_Opacity;
m_RenderOpacity = node->m_RenderOpacity;
m_OverrideWorldTransform = node->m_OverrideWorldTransform;
m_OverrideRotation = node->m_OverrideRotation;
m_OverrideRotationValue = node->m_OverrideRotationValue;
}
ActorNode* ActorNode::read(Actor* actor, BlockReader* reader, ActorNode* node)
{
if(node == nullptr)
{
node = new ActorNode();
}
Base::read(actor, reader, node);
reader->read(node->m_Translation);
node->m_Rotation = reader->readFloat();
reader->read(node->m_Scale);
node->m_Opacity = reader->readFloat();
return node;
}