#pragma once #include #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> { public: typedef std::function UpdateCallback; typedef IntrusiveList> NodeList; using IntrusiveListValue>::GetNext; using IntrusiveListValue>::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 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 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 child); /// \~chinese /// @brief 获取全部子角色 NodeList &GetAllChildren(); /// \~chinese /// @brief 获取全部子角色 const NodeList &GetAllChildren() const; /// \~chinese /// @brief 移除子角色 void RemoveChild(RefPtr 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 next; for (RefPtr 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(); } }