704 lines
15 KiB
C++
704 lines
15 KiB
C++
#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();
|
||
}
|
||
} |