diff --git a/projects/kiwano/kiwano.vcxproj b/projects/kiwano/kiwano.vcxproj
index eb83575f..a136bf40 100644
--- a/projects/kiwano/kiwano.vcxproj
+++ b/projects/kiwano/kiwano.vcxproj
@@ -20,10 +20,12 @@
+
+
@@ -32,6 +34,7 @@
+
diff --git a/projects/kiwano/kiwano.vcxproj.filters b/projects/kiwano/kiwano.vcxproj.filters
index e13e15a7..bd437330 100644
--- a/projects/kiwano/kiwano.vcxproj.filters
+++ b/projects/kiwano/kiwano.vcxproj.filters
@@ -357,6 +357,15 @@
render
+
+ core
+
+
+ core
+
+
+ core
+
diff --git a/src/kiwano/2d/Actor.cpp b/src/kiwano/2d/Actor.cpp
index 80935bba..e1ded17a 100644
--- a/src/kiwano/2d/Actor.cpp
+++ b/src/kiwano/2d/Actor.cpp
@@ -47,13 +47,10 @@ Actor::Actor()
, hover_(false)
, pressed_(false)
, responsible_(false)
- , dirty_visibility_(true)
- , dirty_transform_(false)
- , dirty_transform_inverse_(false)
, cascade_opacity_(true)
, show_border_(false)
- , is_fast_transform_(true)
, evt_dispatch_enabled_(true)
+ , dirty_flag_(DirtyFlag::DirtyVisibility)
, parent_(nullptr)
, stage_(nullptr)
, physic_body_(nullptr)
@@ -102,6 +99,7 @@ void Actor::Render(RenderContext& ctx)
return;
UpdateTransform();
+ UpdateOpacity();
if (children_.IsEmpty())
{
@@ -172,9 +170,9 @@ void Actor::RenderBorder(RenderContext& ctx)
bool Actor::CheckVisibility(RenderContext& ctx) const
{
- if (dirty_visibility_)
+ if (dirty_flag_.Has(DirtyFlag::DirtyVisibility))
{
- dirty_visibility_ = false;
+ dirty_flag_.Unset(DirtyFlag::DirtyVisibility);
if (size_.IsOrigin())
{
@@ -305,10 +303,10 @@ const Matrix3x2& Actor::GetTransformMatrix() const
const Matrix3x2& Actor::GetTransformInverseMatrix() const
{
UpdateTransform();
- if (dirty_transform_inverse_)
+ if (dirty_flag_.Has(DirtyFlag::DirtyTransformInverse))
{
+ dirty_flag_.Unset(DirtyFlag::DirtyTransformInverse);
transform_matrix_inverse_ = transform_matrix_.Invert();
- dirty_transform_inverse_ = false;
}
return transform_matrix_inverse_;
}
@@ -321,14 +319,14 @@ const Matrix3x2& Actor::GetTransformMatrixToParent() const
void Actor::UpdateTransform() const
{
- if (!dirty_transform_)
+ if (!dirty_flag_.Has(DirtyFlag::DirtyTransform))
return;
- dirty_transform_ = false;
- dirty_transform_inverse_ = true;
- dirty_visibility_ = true;
+ dirty_flag_.Unset(DirtyFlag::DirtyTransform);
+ dirty_flag_.Set(DirtyFlag::DirtyTransformInverse);
+ dirty_flag_.Set(DirtyFlag::DirtyVisibility);
- if (is_fast_transform_)
+ if (transform_.IsFast())
{
transform_matrix_to_parent_ = Matrix3x2::Translation(transform_.position);
}
@@ -349,11 +347,16 @@ void Actor::UpdateTransform() const
// update children's transform
for (const auto& child : children_)
- child->dirty_transform_ = true;
+ child->dirty_flag_.Set(DirtyFlag::DirtyTransform);
}
void Actor::UpdateOpacity()
{
+ if (!dirty_flag_.Has(DirtyFlag::DirtyOpacity))
+ return;
+
+ dirty_flag_.Unset(DirtyFlag::DirtyOpacity);
+
if (parent_ && parent_->IsCascadeOpacityEnabled())
{
displayed_opacity_ = opacity_ * parent_->displayed_opacity_;
@@ -363,10 +366,8 @@ void Actor::UpdateOpacity()
displayed_opacity_ = opacity_;
}
- for (auto& child : children_)
- {
- child->UpdateOpacity();
- }
+ for (const auto& child : children_)
+ child->dirty_flag_.Set(DirtyFlag::DirtyOpacity);
}
void Actor::SetStage(Stage* stage)
@@ -428,7 +429,7 @@ void Actor::SetOpacity(float opacity)
return;
displayed_opacity_ = opacity_ = std::min(std::max(opacity, 0.f), 1.f);
- UpdateOpacity();
+ dirty_flag_.Set(DirtyFlag::DirtyOpacity);
}
void Actor::SetCascadeOpacityEnabled(bool enabled)
@@ -437,7 +438,7 @@ void Actor::SetCascadeOpacityEnabled(bool enabled)
return;
cascade_opacity_ = enabled;
- UpdateOpacity();
+ dirty_flag_.Set(DirtyFlag::DirtyOpacity);
}
void Actor::SetAnchor(const Vec2& anchor)
@@ -445,8 +446,8 @@ void Actor::SetAnchor(const Vec2& anchor)
if (anchor_ == anchor)
return;
- anchor_ = anchor;
- dirty_transform_ = true;
+ anchor_ = anchor;
+ dirty_flag_.Set(DirtyFlag::DirtyTransform);
}
void Actor::SetSize(const Size& size)
@@ -454,15 +455,14 @@ void Actor::SetSize(const Size& size)
if (size_ == size)
return;
- size_ = size;
- dirty_transform_ = true;
+ size_ = size;
+ dirty_flag_.Set(DirtyFlag::DirtyTransform);
}
void Actor::SetTransform(const Transform& transform)
{
- transform_ = transform;
- dirty_transform_ = true;
- is_fast_transform_ = false;
+ transform_ = transform;
+ dirty_flag_.Set(DirtyFlag::DirtyTransform);
}
void Actor::SetVisible(bool val)
@@ -472,11 +472,8 @@ void Actor::SetVisible(bool val)
void Actor::SetName(const String& name)
{
- if (!IsName(name))
- {
- ObjectBase::SetName(name);
- hash_name_ = std::hash{}(name);
- }
+ ObjectBase::SetName(name);
+ hash_name_ = std::hash{}(name);
}
void Actor::SetPosition(const Point& pos)
@@ -485,7 +482,7 @@ void Actor::SetPosition(const Point& pos)
return;
transform_.position = pos;
- dirty_transform_ = true;
+ dirty_flag_.Set(DirtyFlag::DirtyTransform);
}
void Actor::SetScale(const Vec2& scale)
@@ -493,9 +490,8 @@ void Actor::SetScale(const Vec2& scale)
if (transform_.scale == scale)
return;
- transform_.scale = scale;
- dirty_transform_ = true;
- is_fast_transform_ = false;
+ transform_.scale = scale;
+ dirty_flag_.Set(DirtyFlag::DirtyTransform);
}
void Actor::SetSkew(const Vec2& skew)
@@ -503,9 +499,8 @@ void Actor::SetSkew(const Vec2& skew)
if (transform_.skew == skew)
return;
- transform_.skew = skew;
- dirty_transform_ = true;
- is_fast_transform_ = false;
+ transform_.skew = skew;
+ dirty_flag_.Set(DirtyFlag::DirtyTransform);
}
void Actor::SetRotation(float angle)
@@ -514,8 +509,7 @@ void Actor::SetRotation(float angle)
return;
transform_.rotation = angle;
- dirty_transform_ = true;
- is_fast_transform_ = false;
+ dirty_flag_.Set(DirtyFlag::DirtyTransform);
}
void Actor::AddChild(ActorPtr child)
@@ -541,9 +535,9 @@ void Actor::AddChild(ActorPtr child)
child->parent_ = this;
child->SetStage(this->stage_);
- child->dirty_transform_ = true;
+ child->dirty_flag_.Set(DirtyFlag::DirtyTransform);
+ child->dirty_flag_.Set(DirtyFlag::DirtyOpacity);
child->Reorder();
- child->UpdateOpacity();
}
else
{
diff --git a/src/kiwano/2d/Actor.h b/src/kiwano/2d/Actor.h
index f6aeb6ea..839add72 100644
--- a/src/kiwano/2d/Actor.h
+++ b/src/kiwano/2d/Actor.h
@@ -446,6 +446,62 @@ public:
/// @brief 设置默认锚点
static void SetDefaultAnchor(float anchor_x, float anchor_y);
+ /// \~chinese
+ /// @brief 获取可见性属性
+ inline Property VisibleProperty()
+ {
+ return Property(&visible_);
+ }
+
+ /// \~chinese
+ /// @brief 获取不透明度属性
+ inline Property OpacityProperty()
+ {
+ return Property(&opacity_, &dirty_flag_, DirtyFlag::DirtyOpacity);
+ }
+
+ /// \~chinese
+ /// @brief 获取锚点属性
+ inline Property AnchorProperty()
+ {
+ return Property(&anchor_, &dirty_flag_, DirtyFlag::DirtyTransform);
+ }
+
+ /// \~chinese
+ /// @brief 获取大小属性
+ inline Property SizeProperty()
+ {
+ return Property(&size_, &dirty_flag_, DirtyFlag::DirtyTransform);
+ }
+
+ /// \~chinese
+ /// @brief 获取位置属性
+ inline Property PositionProperty()
+ {
+ return Property(&transform_.position, &dirty_flag_, DirtyFlag::DirtyTransform);
+ }
+
+ /// \~chinese
+ /// @brief 获取旋转角度属性
+ inline Property RotationProperty()
+ {
+ return Property(&transform_.rotation, &dirty_flag_, DirtyFlag::DirtyTransform);
+ }
+
+ /// \~chinese
+ /// @brief 获取缩放属性
+ inline Property ScaleProperty()
+ {
+ return Property(&transform_.scale, &dirty_flag_, DirtyFlag::DirtyTransform);
+ }
+
+ /// \~chinese
+ /// @brief 获取错切角度属性
+ inline Property SkewProperty()
+ {
+ return Property(&transform_.skew, &dirty_flag_, DirtyFlag::DirtyTransform);
+ }
+
protected:
/// \~chinese
/// @brief 更新自身和所有子角色
@@ -494,33 +550,39 @@ protected:
friend physics::PhysicBody;
private:
- bool visible_;
- bool update_pausing_;
- bool cascade_opacity_;
- bool show_border_;
- bool hover_;
- bool pressed_;
- bool responsible_;
- bool evt_dispatch_enabled_;
- int z_order_;
- float opacity_;
- float displayed_opacity_;
- Actor* parent_;
- Stage* stage_;
- size_t hash_name_;
- Point anchor_;
- Size size_;
- ActorList children_;
- UpdateCallback cb_update_;
- Transform transform_;
+ bool visible_;
+ bool update_pausing_;
+ bool cascade_opacity_;
+ bool show_border_;
+ bool hover_;
+ bool pressed_;
+ bool responsible_;
+ bool evt_dispatch_enabled_;
+ mutable bool visible_in_rt_;
+ enum DirtyFlag : uint8_t
+ {
+ Clean = 0,
+ DirtyTransform = 1,
+ DirtyTransformInverse = 1 << 1,
+ DirtyOpacity = 1 << 2,
+ DirtyVisibility = 1 << 3
+ };
+ mutable Flag dirty_flag_;
+
+ int z_order_;
+ float opacity_;
+ float displayed_opacity_;
+ Actor* parent_;
+ Stage* stage_;
physics::PhysicBody* physic_body_;
+ size_t hash_name_;
+ Point anchor_;
+ Size size_;
+ ActorList children_;
+ UpdateCallback cb_update_;
+ Transform transform_;
- bool is_fast_transform_;
- mutable bool visible_in_rt_;
- mutable bool dirty_visibility_;
- mutable bool dirty_transform_;
- mutable bool dirty_transform_inverse_;
mutable Matrix3x2 transform_matrix_;
mutable Matrix3x2 transform_matrix_inverse_;
mutable Matrix3x2 transform_matrix_to_parent_;
diff --git a/src/kiwano/core/BitOperator.h b/src/kiwano/core/BitOperator.h
new file mode 100644
index 00000000..b834c4ee
--- /dev/null
+++ b/src/kiwano/core/BitOperator.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2019-2020 Kiwano - Nomango
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#pragma once
+#include // std::is_arithmetic
+
+namespace kiwano
+{
+namespace bits
+{
+
+template
+inline void Set(_Ty& old, _Ty flag)
+{
+ static_assert(std::is_arithmetic<_Ty>::value, "_Ty must be an arithmetic type");
+ old |= flag;
+}
+
+template
+inline void Unset(_Ty& old, _Ty flag)
+{
+ static_assert(std::is_arithmetic<_Ty>::value, "_Ty must be an arithmetic type");
+ old &= ~flag;
+}
+
+template
+inline bool Has(_Ty old, _Ty flag)
+{
+ static_assert(std::is_arithmetic<_Ty>::value, "_Ty must be an arithmetic type");
+ return !!(old & flag);
+}
+
+} // namespace bits
+} // namespace kiwano
diff --git a/src/kiwano/core/Common.h b/src/kiwano/core/Common.h
index 5a1eaf00..7fd87a30 100644
--- a/src/kiwano/core/Common.h
+++ b/src/kiwano/core/Common.h
@@ -29,6 +29,9 @@
#include
#include
#include
+#include
+#include
+#include
#include
#include
#include
diff --git a/src/kiwano/core/Flag.h b/src/kiwano/core/Flag.h
new file mode 100644
index 00000000..731334b5
--- /dev/null
+++ b/src/kiwano/core/Flag.h
@@ -0,0 +1,234 @@
+// Copyright (c) 2019-2020 Kiwano - Nomango
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#pragma once
+#include
+#include // uint8_t
+
+namespace kiwano
+{
+
+template
+class Flag
+{
+public:
+ static_assert(std::is_arithmetic<_Ty>::value, "_Ty must be an arithmetic type");
+
+ typedef _Ty value_type;
+
+ _Ty value;
+
+ inline Flag()
+ : value()
+ {
+ }
+
+ inline Flag(_Ty value)
+ : value(value)
+ {
+ }
+
+ inline void Set(_Ty value)
+ {
+ bits::Set(this->value, value);
+ }
+
+ inline void Unset(_Ty value)
+ {
+ bits::Unset(this->value, value);
+ }
+
+ inline bool Has(_Ty value) const
+ {
+ return bits::Has(this->value, value);
+ }
+};
+
+template
+struct IsFlag : public std::false_type
+{
+};
+
+template
+struct IsFlag> : public std::true_type
+{
+};
+
+typedef Flag FlagUint8;
+typedef Flag FlagUint16;
+typedef Flag FlagUint32;
+typedef Flag FlagUint64;
+typedef Flag FlagInt8;
+typedef Flag FlagInt16;
+typedef Flag FlagInt32;
+typedef Flag FlagInt64;
+
+namespace bits
+{
+
+template <>
+inline void Set(FlagUint8& old, FlagUint8 flag)
+{
+ old.Set(flag.value);
+}
+
+template <>
+inline void Set(FlagUint16& old, FlagUint16 flag)
+{
+ old.Set(flag.value);
+}
+
+template <>
+inline void Set(FlagUint32& old, FlagUint32 flag)
+{
+ old.Set(flag.value);
+}
+
+template <>
+inline void Set(FlagUint64& old, FlagUint64 flag)
+{
+ old.Set(flag.value);
+}
+
+template <>
+inline void Set(FlagInt8& old, FlagInt8 flag)
+{
+ old.Set(flag.value);
+}
+
+template <>
+inline void Set(FlagInt16& old, FlagInt16 flag)
+{
+ old.Set(flag.value);
+}
+
+template <>
+inline void Set(FlagInt32& old, FlagInt32 flag)
+{
+ old.Set(flag.value);
+}
+
+template <>
+inline void Set(FlagInt64& old, FlagInt64 flag)
+{
+ old.Set(flag.value);
+}
+
+
+template <>
+inline void Unset(FlagUint8& old, FlagUint8 flag)
+{
+ old.Unset(flag.value);
+}
+
+template <>
+inline void Unset(FlagUint16& old, FlagUint16 flag)
+{
+ old.Unset(flag.value);
+}
+
+template <>
+inline void Unset(FlagUint32& old, FlagUint32 flag)
+{
+ old.Unset(flag.value);
+}
+
+template <>
+inline void Unset(FlagUint64& old, FlagUint64 flag)
+{
+ old.Unset(flag.value);
+}
+
+template <>
+inline void Unset(FlagInt8& old, FlagInt8 flag)
+{
+ old.Unset(flag.value);
+}
+
+template <>
+inline void Unset(FlagInt16& old, FlagInt16 flag)
+{
+ old.Unset(flag.value);
+}
+
+template <>
+inline void Unset(FlagInt32& old, FlagInt32 flag)
+{
+ old.Unset(flag.value);
+}
+
+template <>
+inline void Unset(FlagInt64& old, FlagInt64 flag)
+{
+ old.Unset(flag.value);
+}
+
+
+template <>
+inline bool Has(FlagUint8 old, FlagUint8 flag)
+{
+ return old.Has(flag.value);
+}
+
+template <>
+inline bool Has(FlagUint16 old, FlagUint16 flag)
+{
+ return old.Has(flag.value);
+}
+
+template <>
+inline bool Has(FlagUint32 old, FlagUint32 flag)
+{
+ return old.Has(flag.value);
+}
+
+template <>
+inline bool Has(FlagUint64 old, FlagUint64 flag)
+{
+ return old.Has(flag.value);
+}
+
+template <>
+inline bool Has(FlagInt8 old, FlagInt8 flag)
+{
+ return old.Has(flag.value);
+}
+
+template <>
+inline bool Has(FlagInt16 old, FlagInt16 flag)
+{
+ return old.Has(flag.value);
+}
+
+template <>
+inline bool Has(FlagInt32 old, FlagInt32 flag)
+{
+ return old.Has(flag.value);
+}
+
+template <>
+inline bool Has(FlagInt64 old, FlagInt64 flag)
+{
+ return old.Has(flag.value);
+}
+
+
+} // namespace bits
+} // namespace kiwano
diff --git a/src/kiwano/core/Property.h b/src/kiwano/core/Property.h
new file mode 100644
index 00000000..bffc126b
--- /dev/null
+++ b/src/kiwano/core/Property.h
@@ -0,0 +1,99 @@
+// Copyright (c) 2019-2020 Kiwano - Nomango
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#pragma once
+#include
+#include
+
+namespace kiwano
+{
+
+template
+class Property;
+
+
+template
+class Property<_Ty, void>
+{
+public:
+ typedef _Ty value_type;
+
+ inline Property(_Ty* ptr)
+ : ptr_(ptr)
+ {
+ }
+
+ inline _Ty Get() const
+ {
+ return *ptr_;
+ }
+
+ inline void Set(const _Ty& value)
+ {
+ *ptr_ = value;
+ }
+
+private:
+ _Ty* ptr_;
+};
+
+
+template
+class Property
+{
+public:
+ typedef _Ty value_type;
+ typedef _NotifierTy notifier_type;
+
+ inline Property(_Ty* ptr)
+ : ptr_(ptr)
+ , notifier_(nullptr)
+ , notify_value_()
+ {
+ }
+
+ inline Property(_Ty* ptr, _NotifierTy* notifier, _NotifierTy notify_value)
+ : ptr_(ptr)
+ , notifier_(notifier)
+ , notify_value_(notify_value)
+ {
+ }
+
+ inline _Ty Get() const
+ {
+ return *ptr_;
+ }
+
+ inline void Set(const _Ty& value)
+ {
+ *ptr_ = value;
+ if (notifier_)
+ {
+ bits::Set(*notifier_, notify_value_);
+ }
+ }
+
+private:
+ _Ty* ptr_;
+ _NotifierTy* notifier_;
+ _NotifierTy notify_value_;
+};
+
+}
diff --git a/src/kiwano/math/Transform.hpp b/src/kiwano/math/Transform.hpp
index 4616aefd..9849ec8b 100644
--- a/src/kiwano/math/Transform.hpp
+++ b/src/kiwano/math/Transform.hpp
@@ -49,6 +49,8 @@ public:
/// @brief 将二维放射变换转换为矩阵
Matrix3x2T ToMatrix() const;
+ bool IsFast() const;
+
bool operator==(const TransformT& rhs) const;
};
@@ -71,6 +73,12 @@ Matrix3x2T<_Ty> TransformT<_Ty>::ToMatrix() const
return Matrix3x2T<_Ty>::SRT(position, scale, rotation);
}
+template
+inline bool TransformT<_Ty>::IsFast() const
+{
+ return skew.x == 0.f && skew.y == 0.f && scale.x == 1.f && scale.y == 1.f && rotation == 0.f;
+}
+
template
bool TransformT<_Ty>::operator==(const TransformT& rhs) const
{