Files
DNF_DEV/source/EngineFrame/Base/Node.cpp
2026-02-08 16:20:50 +08:00

421 lines
9.0 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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");
}
}