#include "Node.h" #include "EngineCore/Game.h" void Node::Init() { } void Node::HandleEvents(SDL_Event *e) { RefPtr child = children_.GetFirst(); while (child) { child->HandleEvents(e); child = child->GetNext(); } } inline void Node::Update(float deltaTime) { if (children_.IsEmpty()) { UpdateSelf(deltaTime); return; } RefPtr 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 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 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 me = this; parent_->children_.Remove(me); RefPtr 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 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 child) { if (children_.IsEmpty()) return; if (child) { child->parent_ = nullptr; children_.Remove(child); } else { SDL_LogError(0, "Actor::RemoveChild failed, NULL pointer exception"); } }