Files
2026-02-08 16:20:50 +08:00

704 lines
15 KiB
C++
Raw Permalink 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.
#pragma once
#include <SDL.h>
#include "EngineFrame/Attribute/Y_Transform.h"
#include "EngineFrame/Attribute/Flag.h"
#include "math/Math.h"
#include "Tool/RefObject.h"
#include "Tool/RefPtr.h"
#include "Tool/IntrusiveList.hpp"
class Node : public RefObject, protected IntrusiveListValue<RefPtr<Node>>
{
public:
typedef std::function<void(float deltaTime)> UpdateCallback;
typedef IntrusiveList<RefPtr<Node>> NodeList;
using IntrusiveListValue<RefPtr<Node>>::GetNext;
using IntrusiveListValue<RefPtr<Node>>::GetPrev;
protected:
/**渲染矩阵 */
mutable glm::mat4 render_matrix_;
/**变换属性 */
Y_Transform transform_;
/**变换矩阵 */
mutable Matrix3x2 transform_matrix_;
mutable Matrix3x2 transform_matrix_inverse_;
mutable Matrix3x2 transform_matrix_to_parent_;
private:
/**更新时的回调函数 */
std::map<std::string, UpdateCallback> cb_update_;
/**锚点 */
glm::vec2 anchor_;
/**Z轴显示层级 */
int z_order_;
/**大小 */
VecSize size_;
/**透明度 */
float opacity_;
/**显示透明度 */
float displayed_opacity_;
/**是否可见 */
bool visible_;
/**是否暂停更新 */
bool update_pausing_;
/**是否显示边界 */
bool show_border_;
/**是否在渲染区域中 */
mutable bool visible_in_rt_;
/**联级透明度 */
bool cascade_opacity_;
/**名称 */
std::string name_;
/**父对象 */
Node *parent_;
/**子对象链表 */
NodeList children_;
/**标志 */
mutable Flag<uint8_t> dirty_flag_;
public:
virtual void Init();
virtual void HandleEvents(SDL_Event *e);
virtual void Update(float deltaTime);
virtual void PreRender();
virtual void Render();
virtual void Clear();
virtual void OnPreRender();
virtual void OnRender();
virtual void OnUpdate(float deltaTime);
void UpdateSelf(float dt);
void PrepareToRender();
public:
/// \~chinese
/// @brief 获取显示状态
bool IsVisible() const;
/// \~chinese
/// @brief 是否启用级联透明度
bool IsCascadeOpacityEnabled() const;
/// \~chinese
/// @brief 获取 Z 轴顺序
int GetZOrder() const;
/// \~chinese
/// @brief 获取坐标
glm::vec2 GetPosition() const;
/// \~chinese
/// @brief 获取 x 坐标
float GetPositionX() const;
/// \~chinese
/// @brief 获取 y 坐标
float GetPositionY() const;
/// \~chinese
/// @brief 获取大小
virtual VecSize GetSize() const;
/// \~chinese
/// @brief 获取宽度
float GetWidth() const;
/// \~chinese
/// @brief 获取高度
float GetHeight() const;
/// \~chinese
/// @brief 获取缩放后的宽度
float GetScaledWidth() const;
/// \~chinese
/// @brief 获取缩放后的高度
float GetScaledHeight() const;
/// \~chinese
/// @brief 获取缩放后的大小
VecSize GetScaledSize() const;
/// \~chinese
/// @brief 获取锚点
glm::vec2 GetAnchor() const;
/// \~chinese
/// @brief 获取 x 方向锚点
float GetAnchorX() const;
/// \~chinese
/// @brief 获取 y 方向锚点
float GetAnchorY() const;
/// \~chinese
/// @brief 获取透明度
float GetOpacity() const;
/// \~chinese
/// @brief 获取旋转角度
float GetRotation() const;
/// \~chinese
/// @brief 获取缩放比例
glm::vec2 GetScale() const;
/// \~chinese
/// @brief 获取横向缩放比例
float GetScaleX() const;
/// \~chinese
/// @brief 获取纵向缩放比例
float GetScaleY() const;
/// \~chinese
/// @brief 获取错切角度
glm::vec2 GetSkew() const;
/// \~chinese
/// @brief 获取横向错切角度
float GetSkewX() const;
/// \~chinese
/// @brief 获取纵向错切角度
float GetSkewY() const;
/// \~chinese
/// @brief 获取变换
Y_Transform GetTransform() const;
/// \~chinese
/// @brief 获取父角色
Node *GetParent() const;
/// \~chinese
/// @brief 设置角色是否可见
virtual void SetVisible(bool val);
virtual void OnSetPosition();
/// \~chinese
/// @brief 设置名称
void SetName(std::string name);
/// \~chinese
/// @brief 获取名称
std::string GetName() const;
/// \~chinese
/// @brief 设置坐标
void SetPosition(const glm::vec2 &pos);
/// \~chinese
/// @brief 设置坐标
void SetPosition(float x, float y);
/// \~chinese
/// @brief 设置横坐标
void SetPositionX(float x);
/// \~chinese
/// @brief 设置纵坐标
void SetPositionY(float y);
/// \~chinese
/// @brief 移动至坐标
void MoveTo(const glm::vec2 &p);
/// \~chinese
/// @brief 移动至坐标
void MoveTo(float x, float y);
/// \~chinese
/// @brief 移动相对坐标
void MoveBy(const glm::vec2 &trans);
/// \~chinese
/// @brief 移动相对坐标
void MoveBy(float trans_x, float trans_y);
/// \~chinese
/// @brief 设置缩放比例,默认为 (1.0, 1.0)
void SetScale(const glm::vec2 &scale);
/// \~chinese
/// @brief 设置缩放比例,默认为 (1.0, 1.0)
void SetScale(float scalex, float scaley);
/// \~chinese
/// @brief 设置错切角度,默认为 (0, 0)
void SetSkew(const glm::vec2 &skew);
/// \~chinese
/// @brief 设置错切角度,默认为 (0, 0)
void SetSkew(float skewx, float skewy);
/// \~chinese
/// @brief 设置旋转角度,默认为 0
void SetRotation(float rotation);
/// \~chinese
/// @brief 设置锚点位置,默认为 (0, 0), 范围 [0, 1]
void SetAnchor(const glm::vec2 &anchor);
/// \~chinese
/// @brief 设置锚点位置,默认为 (0, 0), 范围 [0, 1]
void SetAnchor(float anchorx, float anchory);
/// \~chinese
/// @brief 修改大小
void SetSize(const VecSize &size);
/// \~chinese
/// @brief 修改大小
void SetSize(float width, float height);
/// \~chinese
/// @brief 修改宽度
void SetWidth(float width);
/// \~chinese
/// @brief 修改高度
void SetHeight(float height);
/// \~chinese
/// @brief 设置透明度,默认为 1.0, 范围 [0, 1]
void SetOpacity(float opacity);
/// \~chinese
/// @brief 启用或禁用级联透明度
void SetCascadeOpacityEnabled(bool enabled);
/// \~chinese
/// @brief 设置二维仿射变换
void SetTransform(const Y_Transform &transform);
/// \~chinese
/// @brief 设置 Z 轴顺序,默认为 0
void SetZOrder(int zorder);
/// \~chinese
/// @brief 添加子角色
void AddChild(RefPtr<Node> child);
/// \~chinese
/// @brief 获取全部子角色
NodeList &GetAllChildren();
/// \~chinese
/// @brief 获取全部子角色
const NodeList &GetAllChildren() const;
/// \~chinese
/// @brief 移除子角色
void RemoveChild(RefPtr<Node> child);
/// \~chinese
/// @brief 移除所有节点
void RemoveAllChildren();
/// \~chinese
/// @brief 从父角色移除
void RemoveFromParent();
/// \~chinese
/// @brief 暂停角色更新
void PauseUpdating();
/// \~chinese
/// @brief 继续角色更新
void ResumeUpdating();
/// \~chinese
/// @brief 角色更新是否暂停
bool IsUpdatePausing() const;
/// \~chinese
/// @brief 设置更新时的回调函数
void SetCallbackOnUpdate(std::string Key, const UpdateCallback &cb);
/// \~chinese
/// @brief 移除更新时的回调函数
void RemoveCallbackOnUpdate(std::string Key);
/// \~chinese
/// @brief 判断点是否在角色内
virtual bool ContainsPoint(const glm::vec2 &point) const;
/// \~chinese
/// @brief 将世界坐标系点转换为局部坐标系点
glm::vec2 ConvertToLocal(const glm::vec2 &point) const;
/// \~chinese
/// @brief 将局部坐标系点转换为世界坐标系点
glm::vec2 ConvertToWorld(const glm::vec2 &point) const;
/// \~chinese
/// @brief 渲染角色边界
void ShowBorder(bool show);
public:
Node(/* args */);
~Node();
/// \~chinese
/// @brief 更新自己的二维变换,并通知所有子角色
void UpdateTransform() const;
/// \~chinese
/// @brief 向上追溯更新
/// @details 对于节点树 A->B(dirty)->C->D当对 D 执行 UpdateTransformUpwards 时会对 B、C、D 从上到下依次更新
void UpdateTransformUpwards() const;
/// \~chinese
/// @brief 更新自己和所有子角色的透明度
void UpdateOpacity();
/// \~chinese
/// @brief 获取二维变换矩阵
const Matrix3x2 &GetTransformMatrix() const;
/// \~chinese
/// @brief 获取二维变换的逆矩阵
const Matrix3x2 &GetTransformInverseMatrix() const;
/// \~chinese
/// @brief 获取变换到父角色的二维变换矩阵
const Matrix3x2 &GetTransformMatrixToParent() const;
/// \~chinese
/// @brief 生成用于OpenGL渲染的矩阵
virtual void GenerateRenderMatrix() const;
/// \~chinese
/// @brief 将所有子角色按Z轴顺序排序
void Reorder();
/// \~chinese
/// @brief 检查是否在渲染上下文的视区内
virtual bool CheckVisibility() const;
enum DirtyFlag : uint8_t
{
Clean = 0,
DirtyTransform = 1,
DirtyTransformInverse = 1 << 1,
DirtyOpacity = 1 << 2,
DirtyVisibility = 1 << 3
};
};
inline void Node::RemoveAllChildren()
{
RefPtr<Node> next;
for (RefPtr<Node> child = children_.GetFirst(); child; child = next)
{
next = child->GetNext();
RemoveChild(child);
}
}
inline bool Node::IsVisible() const
{
return visible_;
}
inline bool Node::IsCascadeOpacityEnabled() const
{
return cascade_opacity_;
}
inline int Node::GetZOrder() const
{
return z_order_;
}
inline glm::vec2 Node::GetPosition() const
{
return transform_.position;
}
inline float Node::GetPositionX() const
{
return GetPosition().x;
}
inline float Node::GetPositionY() const
{
return GetPosition().y;
}
inline VecSize Node::GetSize() const
{
return size_;
}
inline float Node::GetWidth() const
{
return GetSize().width;
}
inline float Node::GetHeight() const
{
return GetSize().height;
}
inline float Node::GetScaledWidth() const
{
return GetWidth() * GetScaleX();
}
inline float Node::GetScaledHeight() const
{
return GetHeight() * GetScaleY();
}
inline VecSize Node::GetScaledSize() const
{
return VecSize{GetScaledWidth(), GetScaledHeight()};
}
inline glm::vec2 Node::GetAnchor() const
{
return anchor_;
}
inline float Node::GetAnchorX() const
{
return GetAnchor().x;
}
inline float Node::GetAnchorY() const
{
return GetAnchor().y;
}
inline float Node::GetOpacity() const
{
return opacity_;
}
inline float Node::GetRotation() const
{
return transform_.rotation;
}
inline glm::vec2 Node::GetScale() const
{
return transform_.scale;
}
inline float Node::GetScaleX() const
{
return GetScale().x;
}
inline float Node::GetScaleY() const
{
return GetScale().y;
}
inline glm::vec2 Node::GetSkew() const
{
return transform_.skew;
}
inline float Node::GetSkewX() const
{
return GetSkew().x;
}
inline float Node::GetSkewY() const
{
return GetSkew().y;
}
inline Y_Transform Node::GetTransform() const
{
return transform_;
}
inline Node *Node::GetParent() const
{
return parent_;
}
inline void Node::SetVisible(bool val)
{
visible_ = val;
}
inline void Node::OnSetPosition()
{
}
inline void Node::SetName(std::string name)
{
name_ = name;
}
inline std::string Node::GetName() const
{
return name_;
}
inline void Node::SetPosition(const glm::vec2 &pos)
{
if (transform_.position == pos)
return;
transform_.position = pos;
dirty_flag_.Set(DirtyFlag::DirtyTransform);
OnSetPosition();
}
inline void Node::SetPosition(float x, float y)
{
this->SetPosition(glm::vec2(x, y));
}
inline void Node::SetPositionX(float x)
{
this->SetPosition(glm::vec2(x, GetPosition().y));
}
inline void Node::SetPositionY(float y)
{
this->SetPosition(glm::vec2(GetPosition().x, y));
}
inline void Node::MoveTo(const glm::vec2 &p)
{
this->SetPosition(p);
}
inline void Node::MoveTo(float x, float y)
{
this->SetPosition(glm::vec2(x, y));
}
inline void Node::MoveBy(const glm::vec2 &trans)
{
this->SetPosition(transform_.position.x + trans.x, transform_.position.y + trans.y);
}
inline void Node::MoveBy(float trans_x, float trans_y)
{
this->MoveBy(glm::vec2(trans_x, trans_y));
}
inline void Node::SetScale(const glm::vec2 &scale)
{
if (transform_.scale == scale)
return;
transform_.scale = scale;
dirty_flag_.Set(DirtyFlag::DirtyTransform);
}
inline void Node::SetScale(float scalex, float scaley)
{
this->SetScale(glm::vec2(scalex, scaley));
}
inline void Node::SetSkew(const glm::vec2 &skew)
{
if (transform_.skew == skew)
return;
transform_.skew = skew;
dirty_flag_.Set(DirtyFlag::DirtyTransform);
}
inline void Node::SetSkew(float skewx, float skewy)
{
this->SetSkew(glm::vec2(skewx, skewy));
}
inline void Node::SetRotation(float rotation)
{
if (transform_.rotation == rotation)
return;
transform_.rotation = rotation;
dirty_flag_.Set(DirtyFlag::DirtyTransform);
}
inline void Node::SetAnchor(const glm::vec2 &anchor)
{
if (anchor_ == anchor)
return;
anchor_ = anchor;
dirty_flag_.Set(DirtyFlag::DirtyTransform);
}
inline void Node::SetAnchor(float anchorx, float anchory)
{
this->SetAnchor(glm::vec2(anchorx, anchory));
}
inline void Node::SetSize(const VecSize &size)
{
if (size_ == size)
return;
size_ = size;
dirty_flag_.Set(DirtyFlag::DirtyTransform);
}
inline void Node::SetSize(float width, float height)
{
this->SetSize(VecSize{width, height});
}
inline void Node::SetWidth(float width)
{
this->SetSize(width, GetHeight());
}
inline void Node::SetHeight(float height)
{
this->SetSize(GetWidth(), height);
}
inline void Node::SetOpacity(float opacity)
{
if (opacity_ == opacity)
return;
opacity_ = std::min(std::max(opacity, 0.f), 1.f);
dirty_flag_.Set(DirtyFlag::DirtyOpacity);
}
inline void Node::SetCascadeOpacityEnabled(bool enabled)
{
if (cascade_opacity_ == enabled)
return;
cascade_opacity_ = enabled;
dirty_flag_.Set(DirtyFlag::DirtyOpacity);
}
inline void Node::SetTransform(const Y_Transform &transform)
{
transform_ = transform;
dirty_flag_.Set(DirtyFlag::DirtyTransform);
}
inline void Node::SetZOrder(int zorder)
{
if (z_order_ != zorder)
{
z_order_ = zorder;
Reorder();
}
}