421 lines
9.0 KiB
C++
421 lines
9.0 KiB
C++
#include "Node.h"
|
||
#include "EngineCore/Game.h"
|
||
void Node::Init()
|
||
{
|
||
}
|
||
void Node::HandleEvents(SDL_Event *e)
|
||
{
|
||
RefPtr<Node> child = children_.GetFirst();
|
||
while (child)
|
||
{
|
||
child->HandleEvents(e);
|
||
child = child->GetNext();
|
||
}
|
||
}
|
||
inline void Node::Update(float deltaTime)
|
||
{
|
||
if (children_.IsEmpty())
|
||
{
|
||
UpdateSelf(deltaTime);
|
||
return;
|
||
}
|
||
|
||
RefPtr<Node> child = children_.GetFirst();
|
||
while (child)
|
||
{
|
||
if (child->GetZOrder() >= 0)
|
||
break;
|
||
|
||
child->Update(deltaTime);
|
||
child = child->GetNext();
|
||
}
|
||
|
||
UpdateSelf(deltaTime);
|
||
|
||
|
||
while (child)
|
||
{
|
||
child->Update(deltaTime);
|
||
child = child->GetNext();
|
||
}
|
||
}
|
||
inline void Node::PreRender()
|
||
{
|
||
if (!visible_)
|
||
return;
|
||
UpdateTransform();
|
||
UpdateOpacity();
|
||
|
||
if (children_.IsEmpty())
|
||
{
|
||
if (CheckVisibility())
|
||
{
|
||
OnPreRender();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
RefPtr<Node> child = children_.GetFirst();
|
||
while (child)
|
||
{
|
||
if (child->GetZOrder() >= 0)
|
||
break;
|
||
|
||
child->PreRender();
|
||
child = child->GetNext();
|
||
}
|
||
|
||
if (CheckVisibility())
|
||
{
|
||
OnPreRender();
|
||
}
|
||
|
||
while (child)
|
||
{
|
||
child->PreRender();
|
||
child = child->GetNext();
|
||
}
|
||
}
|
||
}
|
||
inline void Node::Render()
|
||
{
|
||
if (!visible_)
|
||
return;
|
||
if (children_.IsEmpty())
|
||
{
|
||
if (visible_in_rt_)
|
||
{
|
||
PrepareToRender();
|
||
OnRender();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
RefPtr<Node> child = children_.GetFirst();
|
||
while (child)
|
||
{
|
||
if (child->GetZOrder() >= 0)
|
||
break;
|
||
|
||
child->Render();
|
||
child = child->GetNext();
|
||
}
|
||
|
||
if (visible_in_rt_)
|
||
{
|
||
PrepareToRender();
|
||
OnRender();
|
||
}
|
||
|
||
while (child)
|
||
{
|
||
child->Render();
|
||
child = child->GetNext();
|
||
}
|
||
}
|
||
}
|
||
void Node::Clear()
|
||
{
|
||
}
|
||
|
||
void Node::OnPreRender()
|
||
{
|
||
}
|
||
|
||
void Node::OnRender()
|
||
{
|
||
}
|
||
|
||
void Node::OnUpdate(float deltaTime)
|
||
{
|
||
}
|
||
|
||
void Node::UpdateSelf(float deltaTime)
|
||
{
|
||
if (!update_pausing_)
|
||
{
|
||
OnUpdate(deltaTime);
|
||
|
||
// 如果有回调函数,则调用回调函数
|
||
if (cb_update_.size() > 0)
|
||
{
|
||
for (auto &cb : cb_update_)
|
||
{
|
||
cb.second(deltaTime);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void Node::PrepareToRender()
|
||
{
|
||
Game::GetInstance().GetRenderer()->SetMatrix(render_matrix_);
|
||
Game::GetInstance().GetRenderer()->SetOpacity(displayed_opacity_);
|
||
}
|
||
|
||
void Node::RemoveFromParent()
|
||
{
|
||
if (parent_)
|
||
{
|
||
parent_->RemoveChild(this);
|
||
}
|
||
}
|
||
inline void Node::PauseUpdating()
|
||
{
|
||
update_pausing_ = true;
|
||
}
|
||
inline void Node::ResumeUpdating()
|
||
{
|
||
update_pausing_ = false;
|
||
}
|
||
inline bool Node::IsUpdatePausing() const
|
||
{
|
||
return update_pausing_;
|
||
}
|
||
|
||
void Node::SetCallbackOnUpdate(std::string Key, const UpdateCallback &cb)
|
||
{
|
||
cb_update_[Key] = cb;
|
||
}
|
||
|
||
void Node::RemoveCallbackOnUpdate(std::string Key)
|
||
{
|
||
cb_update_.erase(Key);
|
||
}
|
||
|
||
bool Node::ContainsPoint(const glm::vec2 &point) const
|
||
{
|
||
// if (size_.x == 0.f || size_.y == 0.f)
|
||
return false;
|
||
// glm::vec2 local = ConvertToLocal(point);
|
||
// return local.x >= 0 && local.y >= 0 && local.x <= size_.x && local.y <= size_.y;
|
||
}
|
||
|
||
glm::vec2 Node::ConvertToLocal(const glm::vec2 &point) const
|
||
{
|
||
glm::vec2 local = GetTransformInverseMatrix().Transform(point);
|
||
return local;
|
||
}
|
||
|
||
glm::vec2 Node::ConvertToWorld(const glm::vec2 &point) const
|
||
{
|
||
glm::vec2 world = GetTransformMatrix().Transform(point);
|
||
return world;
|
||
}
|
||
|
||
void Node::ShowBorder(bool show)
|
||
{
|
||
show_border_ = show;
|
||
}
|
||
|
||
Node::Node() : visible_(true), update_pausing_(false), show_border_(false), parent_(nullptr), anchor_(0.0f, 0.0f), z_order_(0), opacity_(1.f), name_("Node"), displayed_opacity_(1.f), cascade_opacity_(true)
|
||
{
|
||
Game::GetInstance().m_nodeCount++;
|
||
}
|
||
|
||
Node::~Node()
|
||
{
|
||
Game::GetInstance().m_nodeCount--;
|
||
RemoveAllChildren();
|
||
}
|
||
|
||
void Node::UpdateTransform() const
|
||
{
|
||
if (!dirty_flag_.Has(DirtyFlag::DirtyTransform))
|
||
return;
|
||
dirty_flag_.Unset(DirtyFlag::DirtyTransform);
|
||
dirty_flag_.Set(DirtyFlag::DirtyTransformInverse);
|
||
dirty_flag_.Set(DirtyFlag::DirtyVisibility);
|
||
|
||
if (transform_.IsFast())
|
||
{
|
||
transform_matrix_to_parent_ = Matrix3x2::Translation(transform_.position);
|
||
}
|
||
else
|
||
{
|
||
transform_matrix_to_parent_ = transform_.ToMatrix();
|
||
}
|
||
|
||
glm::vec2 anchor_offset(-size_.width * anchor_.x, -size_.height * anchor_.y);
|
||
transform_matrix_to_parent_.Translate(anchor_offset);
|
||
|
||
transform_matrix_ = transform_matrix_to_parent_;
|
||
if (parent_)
|
||
{
|
||
transform_matrix_ *= parent_->transform_matrix_;
|
||
}
|
||
|
||
GenerateRenderMatrix();
|
||
|
||
for (const auto &child : children_)
|
||
child->dirty_flag_.Set(DirtyFlag::DirtyTransform);
|
||
}
|
||
|
||
void Node::UpdateTransformUpwards() const
|
||
{
|
||
if (parent_)
|
||
{
|
||
parent_->UpdateTransformUpwards();
|
||
|
||
if (parent_->dirty_flag_.Has(DirtyFlag::DirtyTransform))
|
||
{
|
||
dirty_flag_.Set(DirtyFlag::DirtyTransform);
|
||
}
|
||
}
|
||
|
||
UpdateTransform();
|
||
}
|
||
|
||
void Node::UpdateOpacity()
|
||
{
|
||
if (!dirty_flag_.Has(DirtyFlag::DirtyOpacity))
|
||
return;
|
||
|
||
dirty_flag_.Unset(DirtyFlag::DirtyOpacity);
|
||
|
||
if (parent_ && parent_->IsCascadeOpacityEnabled())
|
||
{
|
||
displayed_opacity_ = opacity_ * parent_->displayed_opacity_;
|
||
}
|
||
else
|
||
{
|
||
displayed_opacity_ = opacity_;
|
||
}
|
||
|
||
for (const auto &child : children_)
|
||
child->dirty_flag_.Set(DirtyFlag::DirtyOpacity);
|
||
}
|
||
|
||
const Matrix3x2 &Node::GetTransformMatrix() const
|
||
{
|
||
UpdateTransformUpwards();
|
||
return transform_matrix_;
|
||
}
|
||
|
||
const Matrix3x2 &Node::GetTransformInverseMatrix() const
|
||
{
|
||
UpdateTransformUpwards();
|
||
if (dirty_flag_.Has(DirtyFlag::DirtyTransformInverse))
|
||
{
|
||
dirty_flag_.Unset(DirtyFlag::DirtyTransformInverse);
|
||
transform_matrix_inverse_ = transform_matrix_.Invert();
|
||
}
|
||
return transform_matrix_inverse_;
|
||
}
|
||
|
||
const Matrix3x2 &Node::GetTransformMatrixToParent() const
|
||
{
|
||
UpdateTransformUpwards();
|
||
return transform_matrix_to_parent_;
|
||
}
|
||
|
||
void Node::GenerateRenderMatrix() const
|
||
{
|
||
// 构造OpenGl渲染矩阵
|
||
render_matrix_ = glm::mat4(1.0f);
|
||
// 填充旋转+缩放分量(2D 变换核心,对应 4x4 矩阵左上 2x2 区域)
|
||
render_matrix_[0][0] = transform_matrix_[0]; // _11 → x轴缩放+旋转
|
||
render_matrix_[0][1] = transform_matrix_[1]; // _12 → 影响y轴方向的旋转分量
|
||
render_matrix_[1][0] = transform_matrix_[2]; // _21 → 影响x轴方向的旋转分量
|
||
render_matrix_[1][1] = transform_matrix_[3]; // _22 → y轴缩放+旋转
|
||
// 填充平移分量(对应 4x4 矩阵最后一行前两列,z轴平移为0)
|
||
render_matrix_[3][0] = transform_matrix_[4]; // _31 → x方向平移(世界坐标)
|
||
render_matrix_[3][1] = transform_matrix_[5]; // _32 → y方向平移(世界坐标)
|
||
}
|
||
|
||
void Node::Reorder()
|
||
{
|
||
if (parent_)
|
||
{
|
||
RefPtr<Node> me = this;
|
||
|
||
parent_->children_.Remove(me);
|
||
|
||
RefPtr<Node> sibling = parent_->children_.GetLast();
|
||
|
||
if (sibling && sibling->GetZOrder() > z_order_)
|
||
{
|
||
sibling = sibling->GetPrev();
|
||
while (sibling)
|
||
{
|
||
if (sibling->GetZOrder() <= z_order_)
|
||
break;
|
||
sibling = sibling->GetPrev();
|
||
}
|
||
}
|
||
|
||
if (sibling)
|
||
{
|
||
parent_->children_.InsertAfter(me, sibling);
|
||
}
|
||
else
|
||
{
|
||
parent_->children_.PushFront(me);
|
||
}
|
||
}
|
||
}
|
||
|
||
bool Node::CheckVisibility() const
|
||
{
|
||
if (dirty_flag_.Has(DirtyFlag::DirtyVisibility))
|
||
{
|
||
dirty_flag_.Unset(DirtyFlag::DirtyVisibility);
|
||
|
||
if (size_.width == 0.f && size_.height == 0.f)
|
||
{
|
||
visible_in_rt_ = false;
|
||
}
|
||
else
|
||
{
|
||
// TODO
|
||
// visible_in_rt_ = ctx.CheckVisibility(GetBounds(), transform_matrix_ /* GetTransformMatrix() */);
|
||
visible_in_rt_ = true;
|
||
}
|
||
}
|
||
return visible_in_rt_;
|
||
}
|
||
|
||
void Node::AddChild(RefPtr<Node> child)
|
||
{
|
||
if (child)
|
||
{
|
||
assert(!child->parent_ && "Actor::AddChild failed, the actor to be added already has a parent");
|
||
|
||
children_.PushBack(child);
|
||
child->parent_ = this;
|
||
|
||
child->dirty_flag_.Set(DirtyFlag::DirtyTransform);
|
||
child->dirty_flag_.Set(DirtyFlag::DirtyOpacity);
|
||
child->Reorder();
|
||
}
|
||
else
|
||
{
|
||
SDL_LogError(0, "Actor::AddChild failed, NULL pointer exception");
|
||
}
|
||
}
|
||
|
||
Node::NodeList &Node::GetAllChildren()
|
||
{
|
||
return children_;
|
||
}
|
||
|
||
const Node::NodeList &Node::GetAllChildren() const
|
||
{
|
||
return children_;
|
||
}
|
||
|
||
void Node::RemoveChild(RefPtr<Node> child)
|
||
{
|
||
if (children_.IsEmpty())
|
||
return;
|
||
|
||
if (child)
|
||
{
|
||
child->parent_ = nullptr;
|
||
children_.Remove(child);
|
||
}
|
||
else
|
||
{
|
||
SDL_LogError(0, "Actor::RemoveChild failed, NULL pointer exception");
|
||
}
|
||
} |