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 {