[deploy] Merge pull request #56 from KiwanoEngine/dev
Merge develop branch
This commit is contained in:
		
						commit
						2efd06ade3
					
				|  | @ -17,11 +17,13 @@ | ||||||
|     <ClInclude Include="..\..\src\kiwano\base\Director.h" /> |     <ClInclude Include="..\..\src\kiwano\base\Director.h" /> | ||||||
|     <ClInclude Include="..\..\src\kiwano\base\Module.h" /> |     <ClInclude Include="..\..\src\kiwano\base\Module.h" /> | ||||||
|     <ClInclude Include="..\..\src\kiwano\base\ObjectBase.h" /> |     <ClInclude Include="..\..\src\kiwano\base\ObjectBase.h" /> | ||||||
|  |     <ClInclude Include="..\..\src\kiwano\base\ObjectPool.h" /> | ||||||
|     <ClInclude Include="..\..\src\kiwano\base\RefCounter.h" /> |     <ClInclude Include="..\..\src\kiwano\base\RefCounter.h" /> | ||||||
|     <ClInclude Include="..\..\src\kiwano\core\Allocator.h" /> |     <ClInclude Include="..\..\src\kiwano\core\Allocator.h" /> | ||||||
|     <ClInclude Include="..\..\src\kiwano\core\Any.h" /> |     <ClInclude Include="..\..\src\kiwano\core\Any.h" /> | ||||||
|     <ClInclude Include="..\..\src\kiwano\core\Cloneable.h" /> |     <ClInclude Include="..\..\src\kiwano\core\Cloneable.h" /> | ||||||
|     <ClInclude Include="..\..\src\kiwano\core\Common.h" /> |     <ClInclude Include="..\..\src\kiwano\core\Common.h" /> | ||||||
|  |     <ClInclude Include="..\..\src\kiwano\core\Defer.h" /> | ||||||
|     <ClInclude Include="..\..\src\kiwano\core\Exception.h" /> |     <ClInclude Include="..\..\src\kiwano\core\Exception.h" /> | ||||||
|     <ClInclude Include="..\..\src\kiwano\core\Function.h" /> |     <ClInclude Include="..\..\src\kiwano\core\Function.h" /> | ||||||
|     <ClInclude Include="..\..\src\kiwano\core\IntrusiveList.h" /> |     <ClInclude Include="..\..\src\kiwano\core\IntrusiveList.h" /> | ||||||
|  | @ -132,6 +134,7 @@ | ||||||
|     <ClCompile Include="..\..\src\kiwano\base\Director.cpp" /> |     <ClCompile Include="..\..\src\kiwano\base\Director.cpp" /> | ||||||
|     <ClCompile Include="..\..\src\kiwano\base\Module.cpp" /> |     <ClCompile Include="..\..\src\kiwano\base\Module.cpp" /> | ||||||
|     <ClCompile Include="..\..\src\kiwano\base\ObjectBase.cpp" /> |     <ClCompile Include="..\..\src\kiwano\base\ObjectBase.cpp" /> | ||||||
|  |     <ClCompile Include="..\..\src\kiwano\base\ObjectPool.cpp" /> | ||||||
|     <ClCompile Include="..\..\src\kiwano\base\RefCounter.cpp" /> |     <ClCompile Include="..\..\src\kiwano\base\RefCounter.cpp" /> | ||||||
|     <ClCompile Include="..\..\src\kiwano\core\Allocator.cpp" /> |     <ClCompile Include="..\..\src\kiwano\core\Allocator.cpp" /> | ||||||
|     <ClCompile Include="..\..\src\kiwano\core\Exception.cpp" /> |     <ClCompile Include="..\..\src\kiwano\core\Exception.cpp" /> | ||||||
|  |  | ||||||
|  | @ -351,6 +351,12 @@ | ||||||
|     <ClInclude Include="..\..\src\kiwano\utils\ConfigIni.h"> |     <ClInclude Include="..\..\src\kiwano\utils\ConfigIni.h"> | ||||||
|       <Filter>utils</Filter> |       <Filter>utils</Filter> | ||||||
|     </ClInclude> |     </ClInclude> | ||||||
|  |     <ClInclude Include="..\..\src\kiwano\base\ObjectPool.h"> | ||||||
|  |       <Filter>base</Filter> | ||||||
|  |     </ClInclude> | ||||||
|  |     <ClInclude Include="..\..\src\kiwano\core\Defer.h"> | ||||||
|  |       <Filter>core</Filter> | ||||||
|  |     </ClInclude> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <ClCompile Include="..\..\src\kiwano\2d\Canvas.cpp"> |     <ClCompile Include="..\..\src\kiwano\2d\Canvas.cpp"> | ||||||
|  | @ -575,6 +581,9 @@ | ||||||
|     <ClCompile Include="..\..\src\kiwano\utils\ConfigIni.cpp"> |     <ClCompile Include="..\..\src\kiwano\utils\ConfigIni.cpp"> | ||||||
|       <Filter>utils</Filter> |       <Filter>utils</Filter> | ||||||
|     </ClCompile> |     </ClCompile> | ||||||
|  |     <ClCompile Include="..\..\src\kiwano\base\ObjectPool.cpp"> | ||||||
|  |       <Filter>base</Filter> | ||||||
|  |     </ClCompile> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <None Include="suppress_warning.ruleset" /> |     <None Include="suppress_warning.ruleset" /> | ||||||
|  |  | ||||||
|  | @ -68,11 +68,11 @@ public: | ||||||
| 
 | 
 | ||||||
|     void DestroyModule() override; |     void DestroyModule() override; | ||||||
| 
 | 
 | ||||||
|  |     ~AudioModule(); | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     AudioModule(); |     AudioModule(); | ||||||
| 
 | 
 | ||||||
|     ~AudioModule(); |  | ||||||
| 
 |  | ||||||
| private: | private: | ||||||
|     IXAudio2*               x_audio2_; |     IXAudio2*               x_audio2_; | ||||||
|     IXAudio2MasteringVoice* mastering_voice_; |     IXAudio2MasteringVoice* mastering_voice_; | ||||||
|  |  | ||||||
|  | @ -21,6 +21,8 @@ | ||||||
| #include <kiwano-physics/PhysicBody.h> | #include <kiwano-physics/PhysicBody.h> | ||||||
| #include <kiwano-physics/PhysicWorld.h> | #include <kiwano-physics/PhysicWorld.h> | ||||||
| 
 | 
 | ||||||
|  | #define KGE_PHYSIC_COMP_NAME "__KGE_PHYSIC_BODY__" | ||||||
|  | 
 | ||||||
| namespace kiwano | namespace kiwano | ||||||
| { | { | ||||||
| namespace physics | namespace physics | ||||||
|  | @ -48,6 +50,25 @@ PhysicBodyPtr PhysicBody::Create(PhysicWorld* world, Type type) | ||||||
|     return nullptr; |     return nullptr; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | PhysicBody* PhysicBody::Get(Actor* actor) | ||||||
|  | { | ||||||
|  |     if (actor) | ||||||
|  |     { | ||||||
|  |         static size_t physic_comp_name_hash = 0; | ||||||
|  |         if (physic_comp_name_hash == 0) | ||||||
|  |         { | ||||||
|  |             physic_comp_name_hash = std::hash<String>{}(KGE_PHYSIC_COMP_NAME); | ||||||
|  |         } | ||||||
|  |         return (PhysicBody*)actor->GetComponent(physic_comp_name_hash); | ||||||
|  |     } | ||||||
|  |     return nullptr; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | PhysicBody* PhysicBody::Get(ActorPtr actor) | ||||||
|  | { | ||||||
|  |     return PhysicBody::Get(actor.Get()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| PhysicBody::PhysicBody() | PhysicBody::PhysicBody() | ||||||
|     : body_(nullptr) |     : body_(nullptr) | ||||||
|     , world_(nullptr) |     , world_(nullptr) | ||||||
|  | @ -56,7 +77,7 @@ PhysicBody::PhysicBody() | ||||||
|     , mask_bits_(0xFFFF) |     , mask_bits_(0xFFFF) | ||||||
|     , group_index_(0) |     , group_index_(0) | ||||||
| { | { | ||||||
|     SetName("KGE_PHYSIC_BODY"); |     SetName(KGE_PHYSIC_COMP_NAME); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| PhysicBody::~PhysicBody() {} | PhysicBody::~PhysicBody() {} | ||||||
|  | @ -65,8 +86,6 @@ void PhysicBody::InitComponent(Actor* actor) | ||||||
| { | { | ||||||
|     Component::InitComponent(actor); |     Component::InitComponent(actor); | ||||||
| 
 | 
 | ||||||
|     actor->SetPhysicBody(this); |  | ||||||
| 
 |  | ||||||
|     UpdateFromActor(actor); |     UpdateFromActor(actor); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -62,6 +62,16 @@ public: | ||||||
|     /// @param type ÎïÌåÀàÐÍ
 |     /// @param type ÎïÌåÀàÐÍ
 | ||||||
|     static PhysicBodyPtr Create(PhysicWorld* world, Type type); |     static PhysicBodyPtr Create(PhysicWorld* world, Type type); | ||||||
| 
 | 
 | ||||||
|  |     /// \~chinese
 | ||||||
|  |     /// @brief 获取角色的物理身体
 | ||||||
|  |     /// @param actor 角色
 | ||||||
|  |     static PhysicBody* Get(Actor* actor); | ||||||
|  | 
 | ||||||
|  |     /// \~chinese
 | ||||||
|  |     /// @brief 获取角色的物理身体
 | ||||||
|  |     /// @param actor 角色
 | ||||||
|  |     static PhysicBody* Get(ActorPtr actor); | ||||||
|  | 
 | ||||||
|     PhysicBody(); |     PhysicBody(); | ||||||
| 
 | 
 | ||||||
|     virtual ~PhysicBody(); |     virtual ~PhysicBody(); | ||||||
|  |  | ||||||
|  | @ -413,7 +413,7 @@ void PhysicWorld::BeforeSimulation(Actor* parent, const Matrix3x2& parent_to_wor | ||||||
|     { |     { | ||||||
|         Matrix3x2 child_to_world = child->GetTransformMatrixToParent() * parent_to_world; |         Matrix3x2 child_to_world = child->GetTransformMatrixToParent() * parent_to_world; | ||||||
| 
 | 
 | ||||||
|         PhysicBody* body = child->GetPhysicBody(); |         PhysicBody* body = PhysicBody::Get(child); | ||||||
|         if (body) |         if (body) | ||||||
|         { |         { | ||||||
|             body->BeforeSimulation(child.Get(), parent_to_world, child_to_world, parent_rotation); |             body->BeforeSimulation(child.Get(), parent_to_world, child_to_world, parent_rotation); | ||||||
|  | @ -428,7 +428,7 @@ void PhysicWorld::AfterSimulation(Actor* parent, const Matrix3x2& parent_to_worl | ||||||
| { | { | ||||||
|     for (auto child : parent->GetAllChildren()) |     for (auto child : parent->GetAllChildren()) | ||||||
|     { |     { | ||||||
|         PhysicBody* body = child->GetPhysicBody(); |         PhysicBody* body = PhysicBody::Get(child); | ||||||
|         if (body) |         if (body) | ||||||
|         { |         { | ||||||
|             body->AfterSimulation(child.Get(), parent_to_world, parent_rotation); |             body->AfterSimulation(child.Get(), parent_to_world, parent_rotation); | ||||||
|  |  | ||||||
|  | @ -59,6 +59,7 @@ Actor::Actor() | ||||||
|     , cascade_opacity_(false) |     , cascade_opacity_(false) | ||||||
|     , show_border_(false) |     , show_border_(false) | ||||||
|     , is_fast_transform_(true) |     , is_fast_transform_(true) | ||||||
|  |     , evt_dispatch_enabled_(true) | ||||||
|     , parent_(nullptr) |     , parent_(nullptr) | ||||||
|     , stage_(nullptr) |     , stage_(nullptr) | ||||||
|     , hash_name_(0) |     , hash_name_(0) | ||||||
|  | @ -66,7 +67,6 @@ Actor::Actor() | ||||||
|     , opacity_(1.f) |     , opacity_(1.f) | ||||||
|     , displayed_opacity_(1.f) |     , displayed_opacity_(1.f) | ||||||
|     , anchor_(default_anchor_x, default_anchor_y) |     , anchor_(default_anchor_x, default_anchor_y) | ||||||
|     , physic_body_(nullptr) |  | ||||||
| { | { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -192,7 +192,7 @@ bool Actor::CheckVisibility(RenderContext& ctx) const | ||||||
| 
 | 
 | ||||||
| bool Actor::DispatchEvent(Event* evt) | bool Actor::DispatchEvent(Event* evt) | ||||||
| { | { | ||||||
|     if (!visible_) |     if (!visible_ || !evt_dispatch_enabled_) | ||||||
|         return true; |         return true; | ||||||
| 
 | 
 | ||||||
|     // Dispatch to children those are greater than 0 in Z-Order
 |     // Dispatch to children those are greater than 0 in Z-Order
 | ||||||
|  | @ -221,6 +221,11 @@ bool Actor::DispatchEvent(Event* evt) | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void Actor::SetEventDispatchEnabled(bool enabled) | ||||||
|  | { | ||||||
|  |     evt_dispatch_enabled_ = enabled; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void Actor::DoSerialize(Serializer* serializer) const | void Actor::DoSerialize(Serializer* serializer) const | ||||||
| { | { | ||||||
|     ObjectBase::DoSerialize(serializer); |     ObjectBase::DoSerialize(serializer); | ||||||
|  |  | ||||||
|  | @ -33,11 +33,6 @@ class Stage; | ||||||
| class Director; | class Director; | ||||||
| class RenderContext; | class RenderContext; | ||||||
| 
 | 
 | ||||||
| namespace physics |  | ||||||
| { |  | ||||||
| class PhysicBody; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| KGE_DECLARE_SMART_PTR(Actor); | KGE_DECLARE_SMART_PTR(Actor); | ||||||
| 
 | 
 | ||||||
| /// \~chinese
 | /// \~chinese
 | ||||||
|  | @ -110,6 +105,10 @@ public: | ||||||
|     /// @brief 是否启用级联透明度
 |     /// @brief 是否启用级联透明度
 | ||||||
|     bool IsCascadeOpacityEnabled() const; |     bool IsCascadeOpacityEnabled() const; | ||||||
| 
 | 
 | ||||||
|  |     /// \~chinese
 | ||||||
|  |     /// @brief 是否启用事件分发
 | ||||||
|  |     bool IsEventDispatchEnabled() const; | ||||||
|  | 
 | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|     /// @brief 获取名称的 Hash 值
 |     /// @brief 获取名称的 Hash 值
 | ||||||
|     size_t GetHashName() const; |     size_t GetHashName() const; | ||||||
|  | @ -391,14 +390,6 @@ public: | ||||||
|     /// @brief 获取更新时的回调函数
 |     /// @brief 获取更新时的回调函数
 | ||||||
|     UpdateCallback GetCallbackOnUpdate() const; |     UpdateCallback GetCallbackOnUpdate() const; | ||||||
| 
 | 
 | ||||||
|     /// \~chinese
 |  | ||||||
|     /// @brief 获取物理身体,仅当kiwano-physics包启用时生效
 |  | ||||||
|     physics::PhysicBody* GetPhysicBody() const; |  | ||||||
| 
 |  | ||||||
|     /// \~chinese
 |  | ||||||
|     /// @brief 设置物理身体,仅当kiwano-physics包启用时生效
 |  | ||||||
|     void SetPhysicBody(physics::PhysicBody* body); |  | ||||||
| 
 |  | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|     /// @brief 判断点是否在角色内
 |     /// @brief 判断点是否在角色内
 | ||||||
|     virtual bool ContainsPoint(const Point& point) const; |     virtual bool ContainsPoint(const Point& point) const; | ||||||
|  | @ -421,6 +412,11 @@ public: | ||||||
|     /// @return 是否继续分发该事件
 |     /// @return 是否继续分发该事件
 | ||||||
|     virtual bool DispatchEvent(Event* evt); |     virtual bool DispatchEvent(Event* evt); | ||||||
| 
 | 
 | ||||||
|  |     /// \~chinese
 | ||||||
|  |     /// @brief 开启或关闭事件分发功能
 | ||||||
|  |     /// @param enabled 是否开启
 | ||||||
|  |     void SetEventDispatchEnabled(bool enabled); | ||||||
|  | 
 | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|     /// @brief 序列化
 |     /// @brief 序列化
 | ||||||
|     void DoSerialize(Serializer* serializer) const override; |     void DoSerialize(Serializer* serializer) const override; | ||||||
|  | @ -482,6 +478,7 @@ private: | ||||||
|     bool           hover_; |     bool           hover_; | ||||||
|     bool           pressed_; |     bool           pressed_; | ||||||
|     bool           responsible_; |     bool           responsible_; | ||||||
|  |     bool           evt_dispatch_enabled_; | ||||||
|     int            z_order_; |     int            z_order_; | ||||||
|     float          opacity_; |     float          opacity_; | ||||||
|     float          displayed_opacity_; |     float          displayed_opacity_; | ||||||
|  | @ -502,8 +499,6 @@ private: | ||||||
|     mutable Matrix3x2 transform_matrix_; |     mutable Matrix3x2 transform_matrix_; | ||||||
|     mutable Matrix3x2 transform_matrix_inverse_; |     mutable Matrix3x2 transform_matrix_inverse_; | ||||||
|     mutable Matrix3x2 transform_matrix_to_parent_; |     mutable Matrix3x2 transform_matrix_to_parent_; | ||||||
| 
 |  | ||||||
|     physics::PhysicBody* physic_body_; |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /** @} */ | /** @} */ | ||||||
|  | @ -533,6 +528,11 @@ inline bool Actor::IsCascadeOpacityEnabled() const | ||||||
|     return cascade_opacity_; |     return cascade_opacity_; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | inline bool Actor::IsEventDispatchEnabled() const | ||||||
|  | { | ||||||
|  |     return evt_dispatch_enabled_; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| inline size_t Actor::GetHashName() const | inline size_t Actor::GetHashName() const | ||||||
| { | { | ||||||
|     return hash_name_; |     return hash_name_; | ||||||
|  | @ -688,16 +688,6 @@ inline Actor::UpdateCallback Actor::GetCallbackOnUpdate() const | ||||||
|     return cb_update_; |     return cb_update_; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| inline physics::PhysicBody* Actor::GetPhysicBody() const |  | ||||||
| { |  | ||||||
|     return physic_body_; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| inline void Actor::SetPhysicBody(physics::PhysicBody* body) |  | ||||||
| { |  | ||||||
|     physic_body_ = body; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| inline void Actor::ShowBorder(bool show) | inline void Actor::ShowBorder(bool show) | ||||||
| { | { | ||||||
|     show_border_ = show; |     show_border_ = show; | ||||||
|  |  | ||||||
|  | @ -36,11 +36,9 @@ namespace kiwano | ||||||
| /// @brief 动画辅助类
 | /// @brief 动画辅助类
 | ||||||
| struct ActionHelper | struct ActionHelper | ||||||
| { | { | ||||||
|     using DoneCallback = Action::DoneCallback; |  | ||||||
| 
 |  | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|     /// @brief 设置循环次数
 |     /// @brief 设置循环次数
 | ||||||
|     inline ActionHelper& SetLoops(int loops) |     inline ActionHelper& Loops(int loops) | ||||||
|     { |     { | ||||||
|         ptr->SetLoops(loops); |         ptr->SetLoops(loops); | ||||||
|         return (*this); |         return (*this); | ||||||
|  | @ -48,7 +46,7 @@ struct ActionHelper | ||||||
| 
 | 
 | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|     /// @brief 设置动画延迟
 |     /// @brief 设置动画延迟
 | ||||||
|     inline ActionHelper& SetDelay(Duration delay) |     inline ActionHelper& Delay(Duration delay) | ||||||
|     { |     { | ||||||
|         ptr->SetDelay(delay); |         ptr->SetDelay(delay); | ||||||
|         return (*this); |         return (*this); | ||||||
|  | @ -56,7 +54,7 @@ struct ActionHelper | ||||||
| 
 | 
 | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|     /// @brief 设置动画结束回调函数
 |     /// @brief 设置动画结束回调函数
 | ||||||
|     inline ActionHelper& SetDoneCallback(const DoneCallback& cb) |     inline ActionHelper& DoneCallback(const Action::DoneCallback& cb) | ||||||
|     { |     { | ||||||
|         ptr->SetDoneCallback(cb); |         ptr->SetDoneCallback(cb); | ||||||
|         return (*this); |         return (*this); | ||||||
|  | @ -64,7 +62,7 @@ struct ActionHelper | ||||||
| 
 | 
 | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|     /// @brief 设置动画循环结束时的回调函数
 |     /// @brief 设置动画循环结束时的回调函数
 | ||||||
|     inline ActionHelper& SetLoopDoneCallback(const DoneCallback& cb) |     inline ActionHelper& LoopDoneCallback(const Action::DoneCallback& cb) | ||||||
|     { |     { | ||||||
|         ptr->SetLoopDoneCallback(cb); |         ptr->SetLoopDoneCallback(cb); | ||||||
|         return (*this); |         return (*this); | ||||||
|  | @ -80,7 +78,7 @@ struct ActionHelper | ||||||
| 
 | 
 | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|     /// @brief 设置名称
 |     /// @brief 设置名称
 | ||||||
|     inline ActionHelper& SetName(const String& name) |     inline ActionHelper& Name(const String& name) | ||||||
|     { |     { | ||||||
|         ptr->SetName(name); |         ptr->SetName(name); | ||||||
|         return (*this); |         return (*this); | ||||||
|  | @ -116,11 +114,9 @@ private: | ||||||
| /// @brief 补间动画辅助类
 | /// @brief 补间动画辅助类
 | ||||||
| struct TweenHelper | struct TweenHelper | ||||||
| { | { | ||||||
|     using DoneCallback = Action::DoneCallback; |  | ||||||
| 
 |  | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|     /// @brief 设置动画持续时长
 |     /// @brief 设置动画持续时长
 | ||||||
|     inline TweenHelper& SetDuration(Duration dur) |     inline TweenHelper& Dur(Duration dur) | ||||||
|     { |     { | ||||||
|         ptr->SetDuration(dur); |         ptr->SetDuration(dur); | ||||||
|         return (*this); |         return (*this); | ||||||
|  | @ -128,7 +124,7 @@ struct TweenHelper | ||||||
| 
 | 
 | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|     /// @brief 设置循环次数
 |     /// @brief 设置循环次数
 | ||||||
|     inline TweenHelper& SetLoops(int loops) |     inline TweenHelper& Loops(int loops) | ||||||
|     { |     { | ||||||
|         ptr->SetLoops(loops); |         ptr->SetLoops(loops); | ||||||
|         return (*this); |         return (*this); | ||||||
|  | @ -136,7 +132,7 @@ struct TweenHelper | ||||||
| 
 | 
 | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|     /// @brief 设置缓动函数
 |     /// @brief 设置缓动函数
 | ||||||
|     inline TweenHelper& SetEaseFunc(EaseFunc ease) |     inline TweenHelper& EaseFunc(EaseFunc ease) | ||||||
|     { |     { | ||||||
|         ptr->SetEaseFunc(ease); |         ptr->SetEaseFunc(ease); | ||||||
|         return (*this); |         return (*this); | ||||||
|  | @ -144,7 +140,7 @@ struct TweenHelper | ||||||
| 
 | 
 | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|     /// @brief 设置动画延迟
 |     /// @brief 设置动画延迟
 | ||||||
|     inline TweenHelper& SetDelay(Duration delay) |     inline TweenHelper& Delay(Duration delay) | ||||||
|     { |     { | ||||||
|         ptr->SetDelay(delay); |         ptr->SetDelay(delay); | ||||||
|         return (*this); |         return (*this); | ||||||
|  | @ -152,7 +148,7 @@ struct TweenHelper | ||||||
| 
 | 
 | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|     /// @brief 设置动画结束回调函数
 |     /// @brief 设置动画结束回调函数
 | ||||||
|     inline TweenHelper& SetDoneCallback(const DoneCallback& cb) |     inline TweenHelper& DoneCallback(const Action::DoneCallback& cb) | ||||||
|     { |     { | ||||||
|         ptr->SetDoneCallback(cb); |         ptr->SetDoneCallback(cb); | ||||||
|         return (*this); |         return (*this); | ||||||
|  | @ -160,7 +156,7 @@ struct TweenHelper | ||||||
| 
 | 
 | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|     /// @brief 设置动画循环结束时的回调函数
 |     /// @brief 设置动画循环结束时的回调函数
 | ||||||
|     inline TweenHelper& SetLoopDoneCallback(const DoneCallback& cb) |     inline TweenHelper& LoopDoneCallback(const Action::DoneCallback& cb) | ||||||
|     { |     { | ||||||
|         ptr->SetLoopDoneCallback(cb); |         ptr->SetLoopDoneCallback(cb); | ||||||
|         return (*this); |         return (*this); | ||||||
|  | @ -176,7 +172,7 @@ struct TweenHelper | ||||||
| 
 | 
 | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|     /// @brief 设置名称
 |     /// @brief 设置名称
 | ||||||
|     inline TweenHelper& SetName(const String& name) |     inline TweenHelper& Name(const String& name) | ||||||
|     { |     { | ||||||
|         ptr->SetName(name); |         ptr->SetName(name); | ||||||
|         return (*this); |         return (*this); | ||||||
|  | @ -220,7 +216,7 @@ struct Tween | ||||||
| public: | public: | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|     /// @brief 构造相对位移动画
 |     /// @brief 构造相对位移动画
 | ||||||
|     /// @param duration 动画时长
 |     /// @param dur 动画时长
 | ||||||
|     /// @param vector 移动向量
 |     /// @param vector 移动向量
 | ||||||
|     static inline TweenHelper MoveBy(Duration dur, const Point& vector) |     static inline TweenHelper MoveBy(Duration dur, const Point& vector) | ||||||
|     { |     { | ||||||
|  | @ -229,7 +225,7 @@ public: | ||||||
| 
 | 
 | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|     /// @brief 构造位移动画
 |     /// @brief 构造位移动画
 | ||||||
|     /// @param duration 动画时长
 |     /// @param dur 动画时长
 | ||||||
|     /// @param pos 目的坐标
 |     /// @param pos 目的坐标
 | ||||||
|     static inline TweenHelper MoveTo(Duration dur, const Point& pos) |     static inline TweenHelper MoveTo(Duration dur, const Point& pos) | ||||||
|     { |     { | ||||||
|  | @ -238,29 +234,29 @@ public: | ||||||
| 
 | 
 | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|     /// @brief 构造相对跳跃动画
 |     /// @brief 构造相对跳跃动画
 | ||||||
|     /// @param duration 动画时长
 |     /// @param dur 动画时长
 | ||||||
|     /// @param vec 跳跃位移向量
 |     /// @param vec 跳跃位移向量
 | ||||||
|     /// @param height 跳跃高度
 |     /// @param height 跳跃高度
 | ||||||
|     /// @param jumps 跳跃次数
 |     /// @param jumps 跳跃次数
 | ||||||
|     static inline TweenHelper JumpBy(Duration duration, const Vec2& vec, float height, int jumps = 1) |     static inline TweenHelper JumpBy(Duration dur, const Vec2& vec, float height, int jumps = 1) | ||||||
|     { |     { | ||||||
|         return TweenHelper(ActionJumpBy::Create(duration, vec, height, jumps)); |         return TweenHelper(ActionJumpBy::Create(dur, vec, height, jumps)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|     /// @brief 构造跳跃动画
 |     /// @brief 构造跳跃动画
 | ||||||
|     /// @param duration 动画时长
 |     /// @param dur 动画时长
 | ||||||
|     /// @param pos 目的坐标
 |     /// @param pos 目的坐标
 | ||||||
|     /// @param height 跳跃高度
 |     /// @param height 跳跃高度
 | ||||||
|     /// @param jumps 跳跃次数
 |     /// @param jumps 跳跃次数
 | ||||||
|     static inline TweenHelper JumpTo(Duration duration, const Point& pos, float height, int jumps = 1) |     static inline TweenHelper JumpTo(Duration dur, const Point& pos, float height, int jumps = 1) | ||||||
|     { |     { | ||||||
|         return TweenHelper(ActionJumpTo::Create(duration, pos, height, jumps)); |         return TweenHelper(ActionJumpTo::Create(dur, pos, height, jumps)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|     /// @brief 构造相对缩放动画
 |     /// @brief 构造相对缩放动画
 | ||||||
|     /// @param duration 动画时长
 |     /// @param dur 动画时长
 | ||||||
|     /// @param scale_x 横向缩放相对变化值
 |     /// @param scale_x 横向缩放相对变化值
 | ||||||
|     /// @param scale_y 纵向缩放相对变化值
 |     /// @param scale_y 纵向缩放相对变化值
 | ||||||
|     static inline TweenHelper ScaleBy(Duration dur, float scale_x, float scale_y) |     static inline TweenHelper ScaleBy(Duration dur, float scale_x, float scale_y) | ||||||
|  | @ -270,7 +266,7 @@ public: | ||||||
| 
 | 
 | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|     /// @brief 构造缩放动画
 |     /// @brief 构造缩放动画
 | ||||||
|     /// @param duration 动画时长
 |     /// @param dur 动画时长
 | ||||||
|     /// @param scale_x 横向缩放目标值
 |     /// @param scale_x 横向缩放目标值
 | ||||||
|     /// @param scale_y 纵向缩放目标值
 |     /// @param scale_y 纵向缩放目标值
 | ||||||
|     static inline TweenHelper ScaleTo(Duration dur, float scale_x, float scale_y) |     static inline TweenHelper ScaleTo(Duration dur, float scale_x, float scale_y) | ||||||
|  | @ -280,7 +276,7 @@ public: | ||||||
| 
 | 
 | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|     /// @brief 构造透明度渐变动画
 |     /// @brief 构造透明度渐变动画
 | ||||||
|     /// @param duration 动画时长
 |     /// @param dur 动画时长
 | ||||||
|     /// @param opacity 目标透明度
 |     /// @param opacity 目标透明度
 | ||||||
|     static inline TweenHelper FadeTo(Duration dur, float opacity) |     static inline TweenHelper FadeTo(Duration dur, float opacity) | ||||||
|     { |     { | ||||||
|  | @ -289,7 +285,7 @@ public: | ||||||
| 
 | 
 | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|     /// @brief 构造淡入动画
 |     /// @brief 构造淡入动画
 | ||||||
|     /// @param duration 动画时长
 |     /// @param dur 动画时长
 | ||||||
|     static inline TweenHelper FadeIn(Duration dur) |     static inline TweenHelper FadeIn(Duration dur) | ||||||
|     { |     { | ||||||
|         return TweenHelper(ActionFadeIn::Create(dur)); |         return TweenHelper(ActionFadeIn::Create(dur)); | ||||||
|  | @ -297,7 +293,7 @@ public: | ||||||
| 
 | 
 | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|     /// @brief 构造淡出动画
 |     /// @brief 构造淡出动画
 | ||||||
|     /// @param duration 动画时长
 |     /// @param dur 动画时长
 | ||||||
|     static inline TweenHelper FadeOut(Duration dur) |     static inline TweenHelper FadeOut(Duration dur) | ||||||
|     { |     { | ||||||
|         return TweenHelper(ActionFadeOut::Create(dur)); |         return TweenHelper(ActionFadeOut::Create(dur)); | ||||||
|  | @ -305,7 +301,7 @@ public: | ||||||
| 
 | 
 | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|     /// @brief 构造相对旋转动画
 |     /// @brief 构造相对旋转动画
 | ||||||
|     /// @param duration 动画时长
 |     /// @param dur 动画时长
 | ||||||
|     /// @param rotation 角度相对变化值
 |     /// @param rotation 角度相对变化值
 | ||||||
|     static inline TweenHelper RotateBy(Duration dur, float rotation) |     static inline TweenHelper RotateBy(Duration dur, float rotation) | ||||||
|     { |     { | ||||||
|  | @ -314,7 +310,7 @@ public: | ||||||
| 
 | 
 | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|     /// @brief 构造旋转动画
 |     /// @brief 构造旋转动画
 | ||||||
|     /// @param duration 动画时长
 |     /// @param dur 动画时长
 | ||||||
|     /// @param rotation 目标角度
 |     /// @param rotation 目标角度
 | ||||||
|     static inline TweenHelper RotateTo(Duration dur, float rotation) |     static inline TweenHelper RotateTo(Duration dur, float rotation) | ||||||
|     { |     { | ||||||
|  | @ -323,20 +319,20 @@ public: | ||||||
| 
 | 
 | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|     /// @brief 构造路径行走动画
 |     /// @brief 构造路径行走动画
 | ||||||
|     /// @param duration 持续时长
 |     /// @param dur 持续时长
 | ||||||
|     /// @param path 路径形状
 |     /// @param path 路径形状
 | ||||||
|     /// @param rotating 是否沿路径切线方向旋转
 |     /// @param rotating 是否沿路径切线方向旋转
 | ||||||
|     /// @param start 路径起点(百分比)
 |     /// @param start 路径起点(百分比)
 | ||||||
|     /// @param end 路径终点(百分比)
 |     /// @param end 路径终点(百分比)
 | ||||||
|     static inline TweenHelper Walk(Duration duration, ShapePtr path, bool rotating = false, float start = 0.f, |     static inline TweenHelper Walk(Duration dur, ShapePtr path, bool rotating = false, float start = 0.f, | ||||||
|                                    float end = 1.f) |                                    float end = 1.f) | ||||||
|     { |     { | ||||||
|         return TweenHelper(ActionWalk::Create(duration, path, rotating, start, end)); |         return TweenHelper(ActionWalk::Create(dur, path, rotating, start, end)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|     /// @brief 构建帧动画
 |     /// @brief 构建帧动画
 | ||||||
|     /// @param duration 动画时长
 |     /// @param dur 动画时长
 | ||||||
|     /// @param[in] frame_seq 序列帧
 |     /// @param[in] frame_seq 序列帧
 | ||||||
|     static inline TweenHelper Animation(Duration dur, FrameSequencePtr frames) |     static inline TweenHelper Animation(Duration dur, FrameSequencePtr frames) | ||||||
|     { |     { | ||||||
|  | @ -345,7 +341,7 @@ public: | ||||||
| 
 | 
 | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|     /// @brief 构造自定义动画
 |     /// @brief 构造自定义动画
 | ||||||
|     /// @param duration 动画时长
 |     /// @param dur 动画时长
 | ||||||
|     /// @param tween_func 动画回调函数
 |     /// @param tween_func 动画回调函数
 | ||||||
|     static inline TweenHelper Custom(Duration dur, ActionCustom::TweenFunc tween_func) |     static inline TweenHelper Custom(Duration dur, ActionCustom::TweenFunc tween_func) | ||||||
|     { |     { | ||||||
|  |  | ||||||
|  | @ -102,11 +102,11 @@ public: | ||||||
| 
 | 
 | ||||||
|     void HandleEvent(Event* evt) override; |     void HandleEvent(Event* evt) override; | ||||||
| 
 | 
 | ||||||
|  |     virtual ~Director(); | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     Director(); |     Director(); | ||||||
| 
 | 
 | ||||||
|     virtual ~Director(); |  | ||||||
| 
 |  | ||||||
| private: | private: | ||||||
|     bool            render_border_enabled_; |     bool            render_border_enabled_; | ||||||
|     Stack<StagePtr> stages_; |     Stack<StagePtr> stages_; | ||||||
|  |  | ||||||
|  | @ -19,6 +19,7 @@ | ||||||
| // THE SOFTWARE.
 | // THE SOFTWARE.
 | ||||||
| 
 | 
 | ||||||
| #include <kiwano/base/ObjectBase.h> | #include <kiwano/base/ObjectBase.h> | ||||||
|  | #include <kiwano/base/ObjectPool.h> | ||||||
| #include <kiwano/utils/Logger.h> | #include <kiwano/utils/Logger.h> | ||||||
| #include <kiwano/utils/Json.h> | #include <kiwano/utils/Json.h> | ||||||
| #include <typeinfo> | #include <typeinfo> | ||||||
|  | @ -56,6 +57,11 @@ ObjectBase::~ObjectBase() | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void ObjectBase::AutoRelease() | ||||||
|  | { | ||||||
|  |     ObjectPool::GetInstance().AddObject(this); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| const Any& ObjectBase::GetUserData() const | const Any& ObjectBase::GetUserData() const | ||||||
| { | { | ||||||
|     return user_data_; |     return user_data_; | ||||||
|  |  | ||||||
|  | @ -44,6 +44,10 @@ public: | ||||||
| 
 | 
 | ||||||
|     virtual ~ObjectBase(); |     virtual ~ObjectBase(); | ||||||
| 
 | 
 | ||||||
|  |     /// \~chinese
 | ||||||
|  |     /// @brief 自动释放
 | ||||||
|  |     void AutoRelease(); | ||||||
|  | 
 | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|     /// @brief 设置对象名
 |     /// @brief 设置对象名
 | ||||||
|     void SetName(const String& name); |     void SetName(const String& name); | ||||||
|  |  | ||||||
|  | @ -0,0 +1,86 @@ | ||||||
|  | // Copyright (c) 2016-2018 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.
 | ||||||
|  | 
 | ||||||
|  | #include <kiwano/base/ObjectPool.h> | ||||||
|  | 
 | ||||||
|  | namespace kiwano | ||||||
|  | { | ||||||
|  | 
 | ||||||
|  | List<ObjectPool*> ObjectPool::pools_; | ||||||
|  | 
 | ||||||
|  | ObjectPool& ObjectPool::GetInstance() | ||||||
|  | { | ||||||
|  |     static ObjectPool instance; | ||||||
|  |     return *pools_.back(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ObjectPool::ObjectPool() | ||||||
|  | { | ||||||
|  |     pools_.push_back(this); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ObjectPool::~ObjectPool() | ||||||
|  | { | ||||||
|  |     Clear(); | ||||||
|  | 
 | ||||||
|  |     auto iter = std::find(pools_.begin(), pools_.end(), this); | ||||||
|  |     if (iter != pools_.end()) | ||||||
|  |         pools_.erase(iter); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ObjectPool::AddObject(ObjectBase* obj) | ||||||
|  | { | ||||||
|  |     if (obj) | ||||||
|  |     { | ||||||
|  |         if (!Contains(obj)) | ||||||
|  |         { | ||||||
|  |             obj->Retain(); | ||||||
|  | 
 | ||||||
|  |             std::lock_guard<std::mutex> lock(mutex_); | ||||||
|  |             objects_.push_back(obj); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool ObjectPool::Contains(ObjectBase* obj) const | ||||||
|  | { | ||||||
|  |     std::lock_guard<std::mutex> lock(const_cast<std::mutex&>(mutex_)); | ||||||
|  | 
 | ||||||
|  |     for (auto iter = pools_.rbegin(); iter != pools_.rend(); iter++) | ||||||
|  |         for (const auto o : (*iter)->objects_) | ||||||
|  |             if (obj == o) | ||||||
|  |                 return true; | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ObjectPool::Clear() | ||||||
|  | { | ||||||
|  |     Vector<ObjectBase*> copied; | ||||||
|  | 
 | ||||||
|  |     { | ||||||
|  |         std::lock_guard<std::mutex> lock(mutex_); | ||||||
|  |         copied = std::move(objects_); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     for (auto obj : copied) | ||||||
|  |         obj->Release(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | }  // namespace kiwano
 | ||||||
|  | @ -0,0 +1,72 @@ | ||||||
|  | // Copyright (c) 2016-2018 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 <kiwano/base/ObjectBase.h> | ||||||
|  | #include <mutex> | ||||||
|  | 
 | ||||||
|  | namespace kiwano | ||||||
|  | { | ||||||
|  | /**
 | ||||||
|  |  * \~chinese | ||||||
|  |  * @brief 对象池 | ||||||
|  |  */ | ||||||
|  | class KGE_API ObjectPool | ||||||
|  |     : public Noncopyable | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |     static ObjectPool& GetInstance(); | ||||||
|  | 
 | ||||||
|  |     ObjectPool(); | ||||||
|  | 
 | ||||||
|  |     virtual ~ObjectPool(); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * \~chinese | ||||||
|  |      * @brief 添加对象到内存池 | ||||||
|  |      * @param[in] obj 基础对象 | ||||||
|  |      */ | ||||||
|  |     void AddObject(ObjectBase* obj); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * \~chinese | ||||||
|  |      * @brief 判断对象是否在对象池中 | ||||||
|  |      * @param[in] obj 基础对象 | ||||||
|  |      */ | ||||||
|  |     bool Contains(ObjectBase* obj) const; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * \~chinese | ||||||
|  |      * @brief 清空所有对象 | ||||||
|  |      */ | ||||||
|  |     void Clear(); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     ObjectPool(const ObjectPool&) = delete; | ||||||
|  | 
 | ||||||
|  |     ObjectPool& operator=(const ObjectPool&) = delete; | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     std::mutex          mutex_; | ||||||
|  |     Vector<ObjectBase*> objects_; | ||||||
|  | 
 | ||||||
|  |     static List<ObjectPool*> pools_; | ||||||
|  | }; | ||||||
|  | }  // namespace kiwano
 | ||||||
|  | @ -47,7 +47,7 @@ ButtonPtr Button::Create(const Callback& click, const Callback& pressed, const C | ||||||
| Button::Button() | Button::Button() | ||||||
|     : status_(Status::Normal) |     : status_(Status::Normal) | ||||||
| { | { | ||||||
|     SetName("KGE_BUTTON"); |     SetName("__KGE_BUTTON__"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Button::~Button() | Button::~Button() | ||||||
|  |  | ||||||
|  | @ -21,7 +21,6 @@ | ||||||
| #pragma once | #pragma once | ||||||
| #include <kiwano/core/Time.h> | #include <kiwano/core/Time.h> | ||||||
| #include <kiwano/base/ObjectBase.h> | #include <kiwano/base/ObjectBase.h> | ||||||
| #include <kiwano/core/IntrusiveList.h> |  | ||||||
| #include <kiwano/render/RenderContext.h> | #include <kiwano/render/RenderContext.h> | ||||||
| 
 | 
 | ||||||
| namespace kiwano | namespace kiwano | ||||||
|  | @ -49,10 +48,8 @@ KGE_DECLARE_SMART_PTR(Component); | ||||||
|  */ |  */ | ||||||
| class KGE_API Component | class KGE_API Component | ||||||
|     : public ObjectBase |     : public ObjectBase | ||||||
|     , protected IntrusiveListValue<ComponentPtr> |  | ||||||
| { | { | ||||||
|     friend class ComponentManager; |     friend class ComponentManager; | ||||||
|     friend IntrusiveList<ComponentPtr>; |  | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|  |  | ||||||
|  | @ -19,6 +19,7 @@ | ||||||
| // THE SOFTWARE.
 | // THE SOFTWARE.
 | ||||||
| 
 | 
 | ||||||
| #include <kiwano/base/component/ComponentManager.h> | #include <kiwano/base/component/ComponentManager.h> | ||||||
|  | #include <functional> | ||||||
| 
 | 
 | ||||||
| namespace kiwano | namespace kiwano | ||||||
| { | { | ||||||
|  | @ -34,46 +35,74 @@ Component* ComponentManager::AddComponent(ComponentPtr component) | ||||||
| 
 | 
 | ||||||
|     if (component) |     if (component) | ||||||
|     { |     { | ||||||
|         component->InitComponent(target_); |         size_t hash = std::hash<String>{}(component->GetName()); | ||||||
|         components_.PushBack(component); |         AddComponent(hash, component); | ||||||
|     } |     } | ||||||
|     return component.Get(); |     return component.Get(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ComponentList& ComponentManager::GetAllComponents() | Component* ComponentManager::AddComponent(size_t index, ComponentPtr component) | ||||||
|  | { | ||||||
|  |     KGE_ASSERT(component && "AddComponent failed, NULL pointer exception"); | ||||||
|  | 
 | ||||||
|  |     if (component) | ||||||
|  |     { | ||||||
|  |         component->InitComponent(target_); | ||||||
|  | 
 | ||||||
|  |         components_.insert(std::make_pair(index, component)); | ||||||
|  |     } | ||||||
|  |     return component.Get(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Component* ComponentManager::GetComponent(const String& name) | ||||||
|  | { | ||||||
|  |     size_t hash = std::hash<String>{}(name); | ||||||
|  |     return GetComponent(hash); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Component* ComponentManager::GetComponent(size_t name_hash) | ||||||
|  | { | ||||||
|  |     if (!components_.empty()) | ||||||
|  |     { | ||||||
|  |         auto   iter = components_.find(name_hash); | ||||||
|  |         if (iter != components_.end()) | ||||||
|  |         { | ||||||
|  |             return iter->second.Get(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return nullptr; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ComponentMap& ComponentManager::GetAllComponents() | ||||||
| { | { | ||||||
|     return components_; |     return components_; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const ComponentList& ComponentManager::GetAllComponents() const | const ComponentMap& ComponentManager::GetAllComponents() const | ||||||
| { | { | ||||||
|     return components_; |     return components_; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ComponentManager::RemoveComponent(ComponentPtr component) | void ComponentManager::RemoveComponent(ComponentPtr component) | ||||||
| { | { | ||||||
|     auto iter = std::find(components_.begin(), components_.end(), component); |     RemoveComponent(component->GetName()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ComponentManager::RemoveComponent(const String& name) | ||||||
|  | { | ||||||
|  |     size_t hash = std::hash<String>{}(name); | ||||||
|  |     RemoveComponent(hash); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ComponentManager::RemoveComponent(size_t name_hash) | ||||||
|  | { | ||||||
|  |     if (!components_.empty()) | ||||||
|  |     { | ||||||
|  |         auto iter = components_.find(name_hash); | ||||||
|         if (iter != components_.end()) |         if (iter != components_.end()) | ||||||
|         { |         { | ||||||
|         component->DestroyComponent(); |             iter->second->DestroyComponent(); | ||||||
|         components_.Remove(component); |             components_.erase(iter); | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void ComponentManager::RemoveComponents(const String& name) |  | ||||||
| { |  | ||||||
|     if (!components_.IsEmpty()) |  | ||||||
|     { |  | ||||||
|         ComponentPtr next; |  | ||||||
|         for (auto component = components_.GetFirst(); component; component = next) |  | ||||||
|         { |  | ||||||
|             next = component->GetNext(); |  | ||||||
| 
 |  | ||||||
|             if (component->IsName(name)) |  | ||||||
|             { |  | ||||||
|                 component->DestroyComponent(); |  | ||||||
|                 components_.Remove(component); |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -81,31 +110,28 @@ void ComponentManager::RemoveComponents(const String& name) | ||||||
| void ComponentManager::RemoveAllComponents() | void ComponentManager::RemoveAllComponents() | ||||||
| { | { | ||||||
|     // Destroy all components
 |     // Destroy all components
 | ||||||
|     if (!components_.IsEmpty()) |     if (!components_.empty()) | ||||||
|     { |     { | ||||||
|         ComponentPtr next; |         for (auto& p : components_) | ||||||
|         for (auto component = components_.GetFirst(); component; component = next) |  | ||||||
|         { |         { | ||||||
|             next = component->GetNext(); |             p.second->DestroyComponent(); | ||||||
| 
 |  | ||||||
|             component->DestroyComponent(); |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     components_.Clear(); |     components_.clear(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ComponentManager::Update(Duration dt) | void ComponentManager::Update(Duration dt) | ||||||
| { | { | ||||||
|     if (!components_.IsEmpty()) |     if (!components_.empty()) | ||||||
|     { |     { | ||||||
|         ComponentPtr next; |         if (!components_.empty()) | ||||||
|         for (auto component = components_.GetFirst(); component; component = next) |  | ||||||
|         { |         { | ||||||
|             next = component->GetNext(); |             for (auto& p : components_) | ||||||
| 
 |  | ||||||
|             if (component->IsEnable()) |  | ||||||
|             { |             { | ||||||
|                 component->OnUpdate(dt); |                 if (p.second->IsEnable()) | ||||||
|  |                 { | ||||||
|  |                     p.second->OnUpdate(dt); | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -113,16 +139,16 @@ void ComponentManager::Update(Duration dt) | ||||||
| 
 | 
 | ||||||
| void ComponentManager::Render(RenderContext& ctx) | void ComponentManager::Render(RenderContext& ctx) | ||||||
| { | { | ||||||
|     if (!components_.IsEmpty()) |     if (!components_.empty()) | ||||||
|     { |     { | ||||||
|         ComponentPtr next; |         if (!components_.empty()) | ||||||
|         for (auto component = components_.GetFirst(); component; component = next) |  | ||||||
|         { |         { | ||||||
|             next = component->GetNext(); |             for (auto& p : components_) | ||||||
| 
 |  | ||||||
|             if (component->IsEnable()) |  | ||||||
|             { |             { | ||||||
|                 component->OnRender(ctx); |                 if (p.second->IsEnable()) | ||||||
|  |                 { | ||||||
|  |                     p.second->OnRender(ctx); | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -130,16 +156,16 @@ void ComponentManager::Render(RenderContext& ctx) | ||||||
| 
 | 
 | ||||||
| void ComponentManager::DispatchToComponents(Event* evt) | void ComponentManager::DispatchToComponents(Event* evt) | ||||||
| { | { | ||||||
|     if (!components_.IsEmpty()) |     if (!components_.empty()) | ||||||
|     { |     { | ||||||
|         ComponentPtr next; |         if (!components_.empty()) | ||||||
|         for (auto component = components_.GetFirst(); component; component = next) |  | ||||||
|         { |         { | ||||||
|             next = component->GetNext(); |             for (auto& p : components_) | ||||||
| 
 |  | ||||||
|             if (component->IsEnable()) |  | ||||||
|             { |             { | ||||||
|                 component->HandleEvent(evt); |                 if (p.second->IsEnable()) | ||||||
|  |                 { | ||||||
|  |                     p.second->HandleEvent(evt); | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -31,8 +31,8 @@ namespace kiwano | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| /// \~chinese
 | /// \~chinese
 | ||||||
| /// @brief 组件列表
 | /// @brief 组件映射
 | ||||||
| typedef IntrusiveList<ComponentPtr> ComponentList; | typedef UnorderedMap<size_t, ComponentPtr> ComponentMap; | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * \~chinese |  * \~chinese | ||||||
|  | @ -47,12 +47,26 @@ public: | ||||||
|     Component* AddComponent(ComponentPtr component); |     Component* AddComponent(ComponentPtr component); | ||||||
| 
 | 
 | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|     /// @brief 获取所有组件
 |     /// @brief 添加组件
 | ||||||
|     ComponentList& GetAllComponents(); |     /// @param index 索引值
 | ||||||
|  |     /// @param component 组件
 | ||||||
|  |     Component* AddComponent(size_t index, ComponentPtr component); | ||||||
|  | 
 | ||||||
|  |     /// \~chinese
 | ||||||
|  |     /// @brief 获取组件
 | ||||||
|  |     Component* GetComponent(const String& name); | ||||||
|  | 
 | ||||||
|  |     /// \~chinese
 | ||||||
|  |     /// @brief 获取组件
 | ||||||
|  |     Component* GetComponent(size_t name_hash); | ||||||
| 
 | 
 | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|     /// @brief 获取所有组件
 |     /// @brief 获取所有组件
 | ||||||
|     const ComponentList& GetAllComponents() const; |     ComponentMap& GetAllComponents(); | ||||||
|  | 
 | ||||||
|  |     /// \~chinese
 | ||||||
|  |     /// @brief 获取所有组件
 | ||||||
|  |     const ComponentMap& GetAllComponents() const; | ||||||
| 
 | 
 | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|     /// @brief 移除组件
 |     /// @brief 移除组件
 | ||||||
|  | @ -61,7 +75,12 @@ public: | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|     /// @brief 移除组件
 |     /// @brief 移除组件
 | ||||||
|     /// @param name 组件名称
 |     /// @param name 组件名称
 | ||||||
|     void RemoveComponents(const String& name); |     void RemoveComponent(const String& name); | ||||||
|  | 
 | ||||||
|  |     /// \~chinese
 | ||||||
|  |     /// @brief 移除组件
 | ||||||
|  |     /// @param name_hash 组件名称hash值
 | ||||||
|  |     void RemoveComponent(size_t name_hash); | ||||||
| 
 | 
 | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|     /// @brief 移除所有组件
 |     /// @brief 移除所有组件
 | ||||||
|  | @ -84,7 +103,7 @@ protected: | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     Actor*       target_; |     Actor*       target_; | ||||||
|     ComponentList components_; |     ComponentMap components_; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /** @} */ | /** @} */ | ||||||
|  |  | ||||||
|  | @ -0,0 +1,69 @@ | ||||||
|  | // Copyright (c) 2016-2018 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 <kiwano/core/Function.h> | ||||||
|  | 
 | ||||||
|  | namespace kiwano | ||||||
|  | { | ||||||
|  | 
 | ||||||
|  | class Defer | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |     Defer() = default; | ||||||
|  | 
 | ||||||
|  |     Defer(const Function<void()>& func) | ||||||
|  |         : func_(func) | ||||||
|  |     { | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     Defer(Defer&& other) noexcept | ||||||
|  |         : func_(other.func_) | ||||||
|  |     { | ||||||
|  |         other.func_ = nullptr; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ~Defer() | ||||||
|  |     { | ||||||
|  |         if (func_) | ||||||
|  |             func_(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     Defer(const Defer&) = delete; | ||||||
|  |     Defer& operator=(const Defer&) = delete; | ||||||
|  | 
 | ||||||
|  |     Function<void()> func_; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | class __DeferHelper | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |     Defer operator-(const Function<void()>& func) const | ||||||
|  |     { | ||||||
|  |         return Defer{ func }; | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #define KGE_DEFER auto __KGE_DEFER_VAR(__defer_line_, __LINE__, __) = ::kiwano::__DeferHelper() - | ||||||
|  | #define __KGE_DEFER_VAR(a, b, c) __KGE_DEFER_TOKEN_CONNECT(a, b, c) | ||||||
|  | #define __KGE_DEFER_TOKEN_CONNECT(a, b, c) a##b##c | ||||||
|  | 
 | ||||||
|  | }  // namespace kiwano
 | ||||||
|  | @ -19,12 +19,13 @@ | ||||||
| // THE SOFTWARE.
 | // THE SOFTWARE.
 | ||||||
| 
 | 
 | ||||||
| #pragma once | #pragma once | ||||||
|  | #include <memory> | ||||||
| 
 | 
 | ||||||
| namespace kiwano | namespace kiwano | ||||||
| { | { | ||||||
| 
 | 
 | ||||||
| template <typename _Ty> | template <typename _Ty> | ||||||
| struct Singleton | class Singleton | ||||||
| { | { | ||||||
| protected: | protected: | ||||||
|     Singleton()                 = default; |     Singleton()                 = default; | ||||||
|  | @ -32,29 +33,47 @@ protected: | ||||||
|     Singleton& operator=(const Singleton&) = delete; |     Singleton& operator=(const Singleton&) = delete; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     struct ObjectCreator |     struct InstanceCreator | ||||||
|     { |     { | ||||||
|         ObjectCreator() |         InstanceCreator() | ||||||
|         { |         { | ||||||
|             (void)Singleton<_Ty>::GetInstance(); |             (void)Singleton<_Ty>::GetInstancePtr(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         inline void Dummy() const {} |         inline void Dummy() const {} | ||||||
|     }; |     }; | ||||||
|     static ObjectCreator creator_; |     static InstanceCreator creator_; | ||||||
| 
 | 
 | ||||||
| public: | public: | ||||||
|     using object_type = _Ty; |     using object_type = _Ty; | ||||||
| 
 | 
 | ||||||
|  |     static std::unique_ptr<object_type> instance_ptr_; | ||||||
|  | 
 | ||||||
|     static inline object_type& GetInstance() |     static inline object_type& GetInstance() | ||||||
|     { |     { | ||||||
|         static object_type instance; |         return *GetInstancePtr(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     static inline object_type* GetInstancePtr() | ||||||
|  |     { | ||||||
|         creator_.Dummy(); |         creator_.Dummy(); | ||||||
|         return instance; |         if (!instance_ptr_) | ||||||
|  |         { | ||||||
|  |             instance_ptr_.reset(new object_type); | ||||||
|  |         } | ||||||
|  |         return instance_ptr_.get(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     static inline void DestroyInstance() | ||||||
|  |     { | ||||||
|  |         instance_ptr_.reset(); | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| template <typename _Ty> | template <typename _Ty> | ||||||
| typename Singleton<_Ty>::ObjectCreator Singleton<_Ty>::creator_; | typename Singleton<_Ty>::InstanceCreator Singleton<_Ty>::creator_; | ||||||
|  | 
 | ||||||
|  | template <typename _Ty> | ||||||
|  | typename std::unique_ptr<_Ty> Singleton<_Ty>::instance_ptr_; | ||||||
| 
 | 
 | ||||||
| }  // namespace kiwano
 | }  // namespace kiwano
 | ||||||
|  |  | ||||||
|  | @ -54,7 +54,7 @@ public: | ||||||
| 
 | 
 | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|     /// @brief 判断事件类型
 |     /// @brief 判断事件类型
 | ||||||
|     /// @return 是否是指定事件类型
 |     /// @return 事件类型相同返回true,否则返回false
 | ||||||
|     template <typename _Ty> |     template <typename _Ty> | ||||||
|     bool IsType() const; |     bool IsType() const; | ||||||
| 
 | 
 | ||||||
|  | @ -75,19 +75,20 @@ private: | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /// \~chinese
 | /// \~chinese
 | ||||||
| /// @brief 事件特性:判断指定类型是否是事件
 | /// @brief 事件特性:判断是否是事件
 | ||||||
| template <typename _Ty> | template <typename _Ty> | ||||||
| struct IsEvent : public std::bool_constant<std::is_base_of<Event, _Ty>::value || std::is_same<Event, _Ty>::value> | struct IsBaseOfEvent : public std::bool_constant<std::is_base_of<Event, _Ty>::value || std::is_same<Event, _Ty>::value> | ||||||
| { | { | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /// \~chinese
 | /// \~chinese
 | ||||||
| /// @brief 事件特性:判断一个事件能否安全转换到另一事件类型
 | /// @brief 事件特性:判断事件类型是否相同
 | ||||||
| template <typename _Ty, typename = typename std::enable_if<IsEvent<_Ty>::value, int>::type> | template <typename _Ty> | ||||||
| struct IsEventType | struct IsSameEventType | ||||||
| { | { | ||||||
|     inline bool operator()(const Event* evt) const |     inline bool operator()(const Event* evt) const | ||||||
|     { |     { | ||||||
|  |         static_assert(kiwano::IsBaseOfEvent<_Ty>::value, "_Ty is not an event type."); | ||||||
|         return evt->GetType() == KGE_EVENT(_Ty); |         return evt->GetType() == KGE_EVENT(_Ty); | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
|  | @ -102,8 +103,8 @@ inline const EventType& Event::GetType() const | ||||||
| template <typename _Ty> | template <typename _Ty> | ||||||
| inline bool Event::IsType() const | inline bool Event::IsType() const | ||||||
| { | { | ||||||
|     static_assert(kiwano::IsEvent<_Ty>::value, "_Ty is not an event type."); |     static_assert(kiwano::IsBaseOfEvent<_Ty>::value, "_Ty is not an event type."); | ||||||
|     return kiwano::IsEventType<_Ty>()(this); |     return IsSameEventType<_Ty>()(this); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template <typename _Ty> | template <typename _Ty> | ||||||
|  |  | ||||||
|  | @ -59,7 +59,7 @@ public: | ||||||
|     template <typename _EventTy> |     template <typename _EventTy> | ||||||
|     EventListener* AddListener(EventListener::Callback callback) |     EventListener* AddListener(EventListener::Callback callback) | ||||||
|     { |     { | ||||||
|         static_assert(kiwano::IsEvent<_EventTy>::value, "_EventTy is not an event type."); |         static_assert(kiwano::IsBaseOfEvent<_EventTy>::value, "_EventTy is not an event type."); | ||||||
|         return AddListener(KGE_EVENT(_EventTy), callback); |         return AddListener(KGE_EVENT(_EventTy), callback); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -71,7 +71,7 @@ public: | ||||||
|     template <typename _EventTy> |     template <typename _EventTy> | ||||||
|     EventListener* AddListener(const String& name, EventListener::Callback callback) |     EventListener* AddListener(const String& name, EventListener::Callback callback) | ||||||
|     { |     { | ||||||
|         static_assert(kiwano::IsEvent<_EventTy>::value, "_EventTy is not an event type."); |         static_assert(kiwano::IsBaseOfEvent<_EventTy>::value, "_EventTy is not an event type."); | ||||||
|         return AddListener(name, KGE_EVENT(_EventTy), callback); |         return AddListener(name, KGE_EVENT(_EventTy), callback); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -58,4 +58,12 @@ EventListener::EventListener() | ||||||
| 
 | 
 | ||||||
| EventListener::~EventListener() {} | EventListener::~EventListener() {} | ||||||
| 
 | 
 | ||||||
|  | void EventListener::Receive(Event* evt) | ||||||
|  | { | ||||||
|  |     if (ShouldHandle(evt) && callback_) | ||||||
|  |     { | ||||||
|  |         callback_(evt); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| }  // namespace kiwano
 | }  // namespace kiwano
 | ||||||
|  |  | ||||||
|  | @ -67,7 +67,7 @@ public: | ||||||
|     template <typename _EventTy> |     template <typename _EventTy> | ||||||
|     static inline EventListenerPtr Create(const Callback& callback) |     static inline EventListenerPtr Create(const Callback& callback) | ||||||
|     { |     { | ||||||
|         static_assert(kiwano::IsEvent<_EventTy>::value, "_EventTy is not an event type."); |         static_assert(kiwano::IsBaseOfEvent<_EventTy>::value, "_EventTy is not an event type."); | ||||||
|         return EventListener::Create(KGE_EVENT(_EventTy), callback); |         return EventListener::Create(KGE_EVENT(_EventTy), callback); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -79,7 +79,7 @@ public: | ||||||
|     template <typename _EventTy> |     template <typename _EventTy> | ||||||
|     static inline EventListenerPtr Create(const String& name, const Callback& callback) |     static inline EventListenerPtr Create(const String& name, const Callback& callback) | ||||||
|     { |     { | ||||||
|         static_assert(kiwano::IsEvent<_EventTy>::value, "_EventTy is not an event type."); |         static_assert(kiwano::IsBaseOfEvent<_EventTy>::value, "_EventTy is not an event type."); | ||||||
|         return EventListener::Create(name, KGE_EVENT(_EventTy), callback); |         return EventListener::Create(name, KGE_EVENT(_EventTy), callback); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -132,12 +132,17 @@ public: | ||||||
|     /// @brief 设置监听的事件类型
 |     /// @brief 设置监听的事件类型
 | ||||||
|     void SetEventType(const EventType& type); |     void SetEventType(const EventType& type); | ||||||
| 
 | 
 | ||||||
|  |     /// \~chinese
 | ||||||
|  |     /// @brief ÅжÏÊÇ·ñ´¦Àíʼþ
 | ||||||
|  |     virtual bool ShouldHandle(Event* evt) const; | ||||||
|  | 
 | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|     /// @brief 设置监听的事件类型
 |     /// @brief 设置监听的事件类型
 | ||||||
|     /// @tparam _EventTy 事件类型
 |     /// @tparam _EventTy 事件类型
 | ||||||
|     template <typename _EventTy, typename = typename std::enable_if<IsEvent<_EventTy>::value, int>::type> |     template <typename _EventTy> | ||||||
|     inline void SetEventType() |     inline void SetEventType() | ||||||
|     { |     { | ||||||
|  |         static_assert(kiwano::IsBaseOfEvent<_EventTy>::value, "_EventTy is not an event type."); | ||||||
|         SetEventType(KGE_EVENT(_EventTy)); |         SetEventType(KGE_EVENT(_EventTy)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -208,13 +213,13 @@ inline void EventListener::SetEventType(const EventType& type) | ||||||
|     type_ = type; |     type_ = type; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| inline void EventListener::Receive(Event* evt) | inline bool EventListener::ShouldHandle(Event* evt) const | ||||||
| { | { | ||||||
|     KGE_ASSERT(evt != nullptr); |     if (evt) | ||||||
|  |     { | ||||||
|  |         return evt->GetType() == type_; | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
|     if (type_ == evt->GetType() && callback_) |  | ||||||
|     { |  | ||||||
|         callback_(evt); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| }  // namespace kiwano
 | }  // namespace kiwano
 | ||||||
|  |  | ||||||
|  | @ -72,10 +72,8 @@ public: | ||||||
|     KeyCharEvent(); |     KeyCharEvent(); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /** @} */ |  | ||||||
| 
 |  | ||||||
| template <> | template <> | ||||||
| struct IsEventType<KeyEvent> | struct IsSameEventType<KeyEvent> | ||||||
| { | { | ||||||
|     inline bool operator()(const Event* evt) const |     inline bool operator()(const Event* evt) const | ||||||
|     { |     { | ||||||
|  | @ -84,4 +82,6 @@ struct IsEventType<KeyEvent> | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | /** @} */ | ||||||
|  | 
 | ||||||
| }  // namespace kiwano
 | }  // namespace kiwano
 | ||||||
|  |  | ||||||
|  | @ -113,10 +113,8 @@ public: | ||||||
|     MouseWheelEvent(); |     MouseWheelEvent(); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /** @} */ |  | ||||||
| 
 |  | ||||||
| template <> | template <> | ||||||
| struct IsEventType<MouseEvent> | struct IsSameEventType<MouseEvent> | ||||||
| { | { | ||||||
|     inline bool operator()(const Event* evt) const |     inline bool operator()(const Event* evt) const | ||||||
|     { |     { | ||||||
|  | @ -127,4 +125,6 @@ struct IsEventType<MouseEvent> | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | /** @} */ | ||||||
|  | 
 | ||||||
| }  // namespace kiwano
 | }  // namespace kiwano
 | ||||||
|  |  | ||||||
|  | @ -93,10 +93,8 @@ public: | ||||||
|     WindowClosedEvent(); |     WindowClosedEvent(); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /** @} */ |  | ||||||
| 
 |  | ||||||
| template <> | template <> | ||||||
| struct IsEventType<WindowEvent> | struct IsSameEventType<WindowEvent> | ||||||
| { | { | ||||||
|     inline bool operator()(const Event* evt) const |     inline bool operator()(const Event* evt) const | ||||||
|     { |     { | ||||||
|  | @ -107,4 +105,6 @@ struct IsEventType<WindowEvent> | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | /** @} */ | ||||||
|  | 
 | ||||||
| }  // namespace kiwano
 | }  // namespace kiwano
 | ||||||
|  |  | ||||||
|  | @ -44,6 +44,7 @@ | ||||||
| //
 | //
 | ||||||
| 
 | 
 | ||||||
| #include <kiwano/core/Common.h> | #include <kiwano/core/Common.h> | ||||||
|  | #include <kiwano/core/Defer.h> | ||||||
| #include <kiwano/core/Resource.h> | #include <kiwano/core/Resource.h> | ||||||
| #include <kiwano/core/SmartPtr.hpp> | #include <kiwano/core/SmartPtr.hpp> | ||||||
| #include <kiwano/core/Time.h> | #include <kiwano/core/Time.h> | ||||||
|  |  | ||||||
|  | @ -19,11 +19,12 @@ | ||||||
| // THE SOFTWARE.
 | // THE SOFTWARE.
 | ||||||
| 
 | 
 | ||||||
| #include <kiwano/platform/Application.h> | #include <kiwano/platform/Application.h> | ||||||
| #include <kiwano/utils/Logger.h> | #include <kiwano/core/Defer.h> | ||||||
| #include <kiwano/base/Director.h> | #include <kiwano/base/Director.h> | ||||||
| #include <kiwano/render/Renderer.h> | #include <kiwano/render/Renderer.h> | ||||||
| #include <kiwano/render/TextureCache.h> | #include <kiwano/render/TextureCache.h> | ||||||
| #include <kiwano/utils/ResourceCache.h> | #include <kiwano/utils/ResourceCache.h> | ||||||
|  | #include <kiwano/utils/Logger.h> | ||||||
| 
 | 
 | ||||||
| namespace kiwano | namespace kiwano | ||||||
| { | { | ||||||
|  | @ -42,15 +43,15 @@ Application::Application() | ||||||
| 
 | 
 | ||||||
| Application::~Application() | Application::~Application() | ||||||
| { | { | ||||||
|     this->Destroy(); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Application::Run(RunnerPtr runner) | void Application::Run(RunnerPtr runner) | ||||||
| { | { | ||||||
|     KGE_ASSERT(runner); |     KGE_ASSERT(runner); | ||||||
|     runner_ = runner; |  | ||||||
|     running_   = true; |     running_   = true; | ||||||
|     is_paused_ = false; |     is_paused_ = false; | ||||||
|  |     runner_    = runner; | ||||||
|  |     timer_     = Timer::Create(); | ||||||
| 
 | 
 | ||||||
|     // Initialize runner
 |     // Initialize runner
 | ||||||
|     runner->InitSettings(); |     runner->InitSettings(); | ||||||
|  | @ -61,51 +62,43 @@ void Application::Run(RunnerPtr runner) | ||||||
|         c->SetupModule(); |         c->SetupModule(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     // Ensure resources are destroyed before exiting
 | ||||||
|  |     KGE_DEFER[=]() | ||||||
|  |     { | ||||||
|  |         this->Destroy(); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|     // Everything is ready
 |     // Everything is ready
 | ||||||
|     runner->OnReady(); |     runner->OnReady(); | ||||||
| 
 | 
 | ||||||
|  |     // Update everything
 | ||||||
|  |     this->Update(0); | ||||||
|  | 
 | ||||||
|  |     // Start the loop
 | ||||||
|     while (running_) |     while (running_) | ||||||
|     { |     { | ||||||
|         if (!frame_ticker_) |         timer_->Tick(); | ||||||
|         { |  | ||||||
|             frame_ticker_ = Ticker::Create(0); |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         if (frame_ticker_->Tick()) |  | ||||||
|         { |  | ||||||
|         // Execute main loop
 |         // Execute main loop
 | ||||||
|             if (!runner->MainLoop(frame_ticker_->GetDeltaTime())) |         if (!runner->MainLoop(timer_->GetDeltaTime())) | ||||||
|             running_ = false; |             running_ = false; | ||||||
|     } |     } | ||||||
|         else |  | ||||||
|         { |  | ||||||
|             // Releases CPU
 |  | ||||||
|             Duration total_dt = frame_ticker_->GetDeltaTime() + frame_ticker_->GetErrorTime(); |  | ||||||
|             Duration sleep_dt = frame_ticker_->GetInterval() - total_dt; |  | ||||||
|             if (sleep_dt.Milliseconds() > 1LL) |  | ||||||
|             { |  | ||||||
|                 sleep_dt.Sleep(); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     this->Destroy(); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Application::Pause() | void Application::Pause() | ||||||
| { | { | ||||||
|     is_paused_ = true; |     is_paused_ = true; | ||||||
| 
 | 
 | ||||||
|     if (frame_ticker_) |     if (timer_) | ||||||
|         frame_ticker_->Pause(); |         timer_->Pause(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Application::Resume() | void Application::Resume() | ||||||
| { | { | ||||||
|     is_paused_ = false; |     is_paused_ = false; | ||||||
| 
 | 
 | ||||||
|     if (frame_ticker_) |     if (timer_) | ||||||
|         frame_ticker_->Resume(); |         timer_->Resume(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Application::Quit() | void Application::Quit() | ||||||
|  | @ -113,6 +106,12 @@ void Application::Quit() | ||||||
|     running_ = false; |     running_ = false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void Application::UpdateFrame(Duration dt) | ||||||
|  | { | ||||||
|  |     this->Render(); | ||||||
|  |     this->Update(dt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void Application::Destroy() | void Application::Destroy() | ||||||
| { | { | ||||||
|     if (runner_) |     if (runner_) | ||||||
|  |  | ||||||
|  | @ -27,7 +27,7 @@ | ||||||
| #include <kiwano/event/Event.h> | #include <kiwano/event/Event.h> | ||||||
| #include <kiwano/platform/Runner.h> | #include <kiwano/platform/Runner.h> | ||||||
| #include <kiwano/platform/Window.h> | #include <kiwano/platform/Window.h> | ||||||
| #include <kiwano/utils/Ticker.h> | #include <kiwano/utils/Timer.h> | ||||||
| 
 | 
 | ||||||
| namespace kiwano | namespace kiwano | ||||||
| { | { | ||||||
|  | @ -103,18 +103,6 @@ public: | ||||||
|      */ |      */ | ||||||
|     WindowPtr GetWindow() const; |     WindowPtr GetWindow() const; | ||||||
| 
 | 
 | ||||||
|     /**
 |  | ||||||
|      * \~chinese |  | ||||||
|      * @brief 获取帧报时器 |  | ||||||
|      */ |  | ||||||
|     TickerPtr GetFrameTicker() const; |  | ||||||
| 
 |  | ||||||
|     /**
 |  | ||||||
|      * \~chinese |  | ||||||
|      * @brief 设置帧报时器 |  | ||||||
|      */ |  | ||||||
|     void SetFrameTicker(TickerPtr ticker); |  | ||||||
| 
 |  | ||||||
|     /**
 |     /**
 | ||||||
|      * \~chinese |      * \~chinese | ||||||
|      * @brief 设置时间缩放因子 |      * @brief 设置时间缩放因子 | ||||||
|  | @ -150,16 +138,10 @@ public: | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * \~chinese |      * \~chinese | ||||||
|      * @brief 更新所有模块 |      * @brief 更新一帧 | ||||||
|      * @param dt 时间间隔 |      * @param dt 时间间隔 | ||||||
|      */ |      */ | ||||||
|     void Update(Duration dt); |     void UpdateFrame(Duration dt); | ||||||
| 
 |  | ||||||
|     /**
 |  | ||||||
|      * \~chinese |  | ||||||
|      * @brief 创建渲染上下文并渲染画面 |  | ||||||
|      */ |  | ||||||
|     void Render(); |  | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * \~chinese |      * \~chinese | ||||||
|  | @ -167,12 +149,26 @@ public: | ||||||
|      */ |      */ | ||||||
|     void Destroy(); |     void Destroy(); | ||||||
| 
 | 
 | ||||||
|  | private: | ||||||
|  |     /**
 | ||||||
|  |      * \~chinese | ||||||
|  |      * @brief 更新所有模块 | ||||||
|  |      * @param dt 时间间隔 | ||||||
|  |      */ | ||||||
|  |     void Update(Duration dt); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * \~chinese | ||||||
|  |      * @brief 渲染画面 | ||||||
|  |      */ | ||||||
|  |     void Render(); | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     bool                    running_; |     bool                    running_; | ||||||
|     bool                    is_paused_; |     bool                    is_paused_; | ||||||
|     float                   time_scale_; |     float                   time_scale_; | ||||||
|     RunnerPtr               runner_; |     RunnerPtr               runner_; | ||||||
|     TickerPtr               frame_ticker_; |     TimerPtr                timer_; | ||||||
|     List<Module*>           modules_; |     List<Module*>           modules_; | ||||||
|     std::mutex              perform_mutex_; |     std::mutex              perform_mutex_; | ||||||
|     Queue<Function<void()>> functions_to_perform_; |     Queue<Function<void()>> functions_to_perform_; | ||||||
|  | @ -185,18 +181,9 @@ inline RunnerPtr Application::GetRunner() const | ||||||
| 
 | 
 | ||||||
| inline WindowPtr Application::GetWindow() const | inline WindowPtr Application::GetWindow() const | ||||||
| { | { | ||||||
|     KGE_ASSERT(runner_); |     if (runner_) | ||||||
|         return runner_->GetWindow(); |         return runner_->GetWindow(); | ||||||
| } |     return nullptr; | ||||||
| 
 |  | ||||||
| inline TickerPtr Application::GetFrameTicker() const |  | ||||||
| { |  | ||||||
|     return frame_ticker_; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| inline void Application::SetFrameTicker(TickerPtr ticker) |  | ||||||
| { |  | ||||||
|     frame_ticker_ = ticker; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| inline bool Application::IsPaused() const | inline bool Application::IsPaused() const | ||||||
|  |  | ||||||
|  | @ -102,11 +102,11 @@ public: | ||||||
|      */ |      */ | ||||||
|     bool ExtractResourceToFile(const Resource& res, const String& dest_file_name) const; |     bool ExtractResourceToFile(const Resource& res, const String& dest_file_name) const; | ||||||
| 
 | 
 | ||||||
|  |     ~FileSystem(); | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     FileSystem(); |     FileSystem(); | ||||||
| 
 | 
 | ||||||
|     ~FileSystem(); |  | ||||||
| 
 |  | ||||||
| private: | private: | ||||||
|     Vector<String>                       search_paths_; |     Vector<String>                       search_paths_; | ||||||
|     UnorderedMap<String, String>         file_lookup_dict_; |     UnorderedMap<String, String>         file_lookup_dict_; | ||||||
|  |  | ||||||
|  | @ -112,11 +112,11 @@ public: | ||||||
| 
 | 
 | ||||||
|     void HandleEvent(Event* evt) override; |     void HandleEvent(Event* evt) override; | ||||||
| 
 | 
 | ||||||
|  |     ~Input(); | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     Input(); |     Input(); | ||||||
| 
 | 
 | ||||||
|     ~Input(); |  | ||||||
| 
 |  | ||||||
|     void UpdateKey(KeyCode key, bool down); |     void UpdateKey(KeyCode key, bool down); | ||||||
| 
 | 
 | ||||||
|     void UpdateButton(MouseButton btn, bool down); |     void UpdateButton(MouseButton btn, bool down); | ||||||
|  |  | ||||||
|  | @ -82,8 +82,8 @@ void Runner::InitSettings() | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Create game window
 |     // Create game window
 | ||||||
|     WindowPtr window = |     WindowPtr window = Window::Create(settings_.title, settings_.width, settings_.height, settings_.icon, | ||||||
|         Window::Create(settings_.title, settings_.width, settings_.height, settings_.icon, settings_.resizable); |                                       settings_.resizable, settings_.fullscreen); | ||||||
|     SetWindow(window); |     SetWindow(window); | ||||||
| 
 | 
 | ||||||
|     // Update renderer settings
 |     // Update renderer settings
 | ||||||
|  | @ -101,6 +101,9 @@ void Runner::InitSettings() | ||||||
|         Director::GetInstance().ShowDebugInfo(true); |         Director::GetInstance().ShowDebugInfo(true); | ||||||
|         Renderer::GetInstance().GetContext().SetCollectingStatus(true); |         Renderer::GetInstance().GetContext().SetCollectingStatus(true); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     // Create frame ticker
 | ||||||
|  |     frame_ticker_ = Ticker::Create(settings_.frame_interval, -1); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool Runner::MainLoop(Duration dt) | bool Runner::MainLoop(Duration dt) | ||||||
|  | @ -118,9 +121,6 @@ bool Runner::MainLoop(Duration dt) | ||||||
| 
 | 
 | ||||||
|     Application& app = Application::GetInstance(); |     Application& app = Application::GetInstance(); | ||||||
| 
 | 
 | ||||||
|     // Update modules before poll events
 |  | ||||||
|     app.Update(dt); |  | ||||||
| 
 |  | ||||||
|     // Poll events
 |     // Poll events
 | ||||||
|     main_window_->PumpEvents(); |     main_window_->PumpEvents(); | ||||||
|     while (EventPtr evt = main_window_->PollEvent()) |     while (EventPtr evt = main_window_->PollEvent()) | ||||||
|  | @ -128,12 +128,27 @@ bool Runner::MainLoop(Duration dt) | ||||||
|         app.DispatchEvent(evt.Get()); |         app.DispatchEvent(evt.Get()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     app.Render(); |     // Update frame ticker
 | ||||||
| 
 |     if (frame_ticker_) | ||||||
|     if (app.IsPaused()) |  | ||||||
|     { |     { | ||||||
|         // Slow down when the application is paused
 |         if (frame_ticker_->Tick(dt)) | ||||||
|         Duration(5).Sleep(); |         { | ||||||
|  |             app.UpdateFrame(frame_ticker_->GetDeltaTime()); | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             // Releases CPU
 | ||||||
|  |             Duration total_dt = frame_ticker_->GetDeltaTime() + frame_ticker_->GetErrorTime(); | ||||||
|  |             Duration sleep_dt = frame_ticker_->GetInterval() - total_dt; | ||||||
|  |             if (sleep_dt.Milliseconds() > 1LL) | ||||||
|  |             { | ||||||
|  |                 sleep_dt.Sleep(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         app.UpdateFrame(dt); | ||||||
|     } |     } | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -24,6 +24,8 @@ | ||||||
| #include <kiwano/platform/Window.h> | #include <kiwano/platform/Window.h> | ||||||
| #include <kiwano/render/Color.h> | #include <kiwano/render/Color.h> | ||||||
| #include <kiwano/render/Texture.h> | #include <kiwano/render/Texture.h> | ||||||
|  | #include <kiwano/utils/Ticker.h> | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| namespace kiwano | namespace kiwano | ||||||
| { | { | ||||||
|  | @ -43,7 +45,9 @@ struct Settings | ||||||
|     String   title;           ///< 窗口标题
 |     String   title;           ///< 窗口标题
 | ||||||
|     uint32_t icon;            ///< 窗口图标
 |     uint32_t icon;            ///< 窗口图标
 | ||||||
|     bool     resizable;       ///< 窗口大小可调整
 |     bool     resizable;       ///< 窗口大小可调整
 | ||||||
|  |     bool     fullscreen;      ///< 窗口全屏
 | ||||||
|     Color    bg_color;        ///< 窗口背景色
 |     Color    bg_color;        ///< 窗口背景色
 | ||||||
|  |     Duration frame_interval;  ///< 帧间隔
 | ||||||
|     bool     vsync_enabled;   ///< 垂直同步
 |     bool     vsync_enabled;   ///< 垂直同步
 | ||||||
|     bool     debug_mode;      ///< 调试模式
 |     bool     debug_mode;      ///< 调试模式
 | ||||||
| 
 | 
 | ||||||
|  | @ -53,8 +57,10 @@ struct Settings | ||||||
|         , title("Kiwano") |         , title("Kiwano") | ||||||
|         , icon() |         , icon() | ||||||
|         , resizable(false) |         , resizable(false) | ||||||
|  |         , fullscreen(false) | ||||||
|         , bg_color(Color::Black) |         , bg_color(Color::Black) | ||||||
|         , vsync_enabled(true) |         , frame_interval(16) | ||||||
|  |         , vsync_enabled(false) | ||||||
|         , debug_mode(false) |         , debug_mode(false) | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
|  | @ -118,6 +124,14 @@ public: | ||||||
|     /// @brief 获取设置
 |     /// @brief 获取设置
 | ||||||
|     Settings GetSettings() const; |     Settings GetSettings() const; | ||||||
| 
 | 
 | ||||||
|  |     /// \~chinese
 | ||||||
|  |     /// @brief 获取帧报时器
 | ||||||
|  |     TickerPtr GetFrameTicker() const; | ||||||
|  | 
 | ||||||
|  |     /// \~chinese
 | ||||||
|  |     /// @brief 设置帧报时器
 | ||||||
|  |     void SetFrameTicker(TickerPtr ticker); | ||||||
|  | 
 | ||||||
| protected: | protected: | ||||||
|     /// \~chinese
 |     /// \~chinese
 | ||||||
|     /// @brief 修改设置
 |     /// @brief 修改设置
 | ||||||
|  | @ -131,6 +145,7 @@ private: | ||||||
| private: | private: | ||||||
|     Settings  settings_; |     Settings  settings_; | ||||||
|     WindowPtr main_window_; |     WindowPtr main_window_; | ||||||
|  |     TickerPtr frame_ticker_; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| inline void Runner::OnReady() {} | inline void Runner::OnReady() {} | ||||||
|  | @ -162,4 +177,14 @@ inline void Runner::SetSettings(Settings settings) | ||||||
|     settings_ = settings; |     settings_ = settings; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | inline TickerPtr Runner::GetFrameTicker() const | ||||||
|  | { | ||||||
|  |     return frame_ticker_; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | inline void Runner::SetFrameTicker(TickerPtr ticker) | ||||||
|  | { | ||||||
|  |     frame_ticker_ = ticker; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| }  // namespace kiwano
 | }  // namespace kiwano
 | ||||||
|  |  | ||||||
|  | @ -71,6 +71,11 @@ uint32_t Window::GetHeight() const | ||||||
|     return height_; |     return height_; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | Resolution Window::GetCurrentResolution() const | ||||||
|  | { | ||||||
|  |     return resolution_; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| WindowHandle Window::GetHandle() const | WindowHandle Window::GetHandle() const | ||||||
| { | { | ||||||
|     return handle_; |     return handle_; | ||||||
|  |  | ||||||
|  | @ -80,7 +80,7 @@ public: | ||||||
|      * @throw kiwano::SystemError 窗口创建失败时抛出 |      * @throw kiwano::SystemError 窗口创建失败时抛出 | ||||||
|      */ |      */ | ||||||
|     static WindowPtr Create(const String& title, uint32_t width, uint32_t height, uint32_t icon = 0, |     static WindowPtr Create(const String& title, uint32_t width, uint32_t height, uint32_t icon = 0, | ||||||
|                             bool resizable = false); |                             bool resizable = false, bool fullscreen = false); | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * \~chinese |      * \~chinese | ||||||
|  | @ -110,6 +110,12 @@ public: | ||||||
|      */ |      */ | ||||||
|     uint32_t GetHeight() const; |     uint32_t GetHeight() const; | ||||||
| 
 | 
 | ||||||
|  |     /**
 | ||||||
|  |      * \~chinese | ||||||
|  |      * @brief 获取当前分辨率 | ||||||
|  |      */ | ||||||
|  |     Resolution GetCurrentResolution() const; | ||||||
|  | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * \~chinese |      * \~chinese | ||||||
|      * @brief 获取窗口句柄 |      * @brief 获取窗口句柄 | ||||||
|  | @ -214,6 +220,7 @@ protected: | ||||||
|     uint32_t             min_height_; |     uint32_t             min_height_; | ||||||
|     uint32_t             max_width_; |     uint32_t             max_width_; | ||||||
|     uint32_t             max_height_; |     uint32_t             max_height_; | ||||||
|  |     Resolution           resolution_; | ||||||
|     WindowHandle         handle_; |     WindowHandle         handle_; | ||||||
|     String               title_; |     String               title_; | ||||||
|     std::queue<EventPtr> event_queue_; |     std::queue<EventPtr> event_queue_; | ||||||
|  |  | ||||||
|  | @ -30,7 +30,6 @@ | ||||||
| #include <kiwano/event/Events.h> | #include <kiwano/event/Events.h> | ||||||
| #include <kiwano/platform/Application.h> | #include <kiwano/platform/Application.h> | ||||||
| #include <kiwano/render/Renderer.h> | #include <kiwano/render/Renderer.h> | ||||||
| #include <kiwano/render/DirectX/D3DDeviceResources.h> |  | ||||||
| #include <Windowsx.h>  // GET_X_LPARAM, GET_Y_LPARAM
 | #include <Windowsx.h>  // GET_X_LPARAM, GET_Y_LPARAM
 | ||||||
| #include <imm.h>       // ImmAssociateContext
 | #include <imm.h>       // ImmAssociateContext
 | ||||||
| #pragma comment(lib, "imm32.lib") | #pragma comment(lib, "imm32.lib") | ||||||
|  | @ -49,7 +48,7 @@ public: | ||||||
| 
 | 
 | ||||||
|     virtual ~WindowWin32Impl(); |     virtual ~WindowWin32Impl(); | ||||||
| 
 | 
 | ||||||
|     void Init(const String& title, uint32_t width, uint32_t height, uint32_t icon, bool resizable); |     void Init(const String& title, uint32_t width, uint32_t height, uint32_t icon, bool resizable, bool fullscreen); | ||||||
| 
 | 
 | ||||||
|     void SetTitle(const String& title) override; |     void SetTitle(const String& title) override; | ||||||
| 
 | 
 | ||||||
|  | @ -69,6 +68,8 @@ public: | ||||||
| 
 | 
 | ||||||
|     DWORD GetStyle() const; |     DWORD GetStyle() const; | ||||||
| 
 | 
 | ||||||
|  |     void SetActive(bool active); | ||||||
|  | 
 | ||||||
|     void UpdateCursor(); |     void UpdateCursor(); | ||||||
| 
 | 
 | ||||||
|     LRESULT MessageProc(HWND, UINT32, WPARAM, LPARAM); |     LRESULT MessageProc(HWND, UINT32, WPARAM, LPARAM); | ||||||
|  | @ -86,12 +87,13 @@ private: | ||||||
|     std::array<KeyCode, 256> key_map_; |     std::array<KeyCode, 256> key_map_; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| WindowPtr Window::Create(const String& title, uint32_t width, uint32_t height, uint32_t icon, bool resizable) | WindowPtr Window::Create(const String& title, uint32_t width, uint32_t height, uint32_t icon, bool resizable, | ||||||
|  |                          bool fullscreen) | ||||||
| { | { | ||||||
|     WindowWin32ImplPtr ptr = memory::New<WindowWin32Impl>(); |     WindowWin32ImplPtr ptr = memory::New<WindowWin32Impl>(); | ||||||
|     if (ptr) |     if (ptr) | ||||||
|     { |     { | ||||||
|         ptr->Init(title, width, height, icon, resizable); |         ptr->Init(title, width, height, icon, resizable, fullscreen); | ||||||
|     } |     } | ||||||
|     return ptr; |     return ptr; | ||||||
| } | } | ||||||
|  | @ -103,6 +105,7 @@ namespace kiwano | ||||||
| 
 | 
 | ||||||
| #define WINDOW_FIXED_STYLE WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | #define WINDOW_FIXED_STYLE WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | ||||||
| #define WINDOW_RESIZABLE_STYLE WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_SIZEBOX | WS_MAXIMIZEBOX | #define WINDOW_RESIZABLE_STYLE WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_SIZEBOX | WS_MAXIMIZEBOX | ||||||
|  | #define WINDOW_FULLSCREEN_STYLE WS_CLIPCHILDREN | WS_POPUP | ||||||
| 
 | 
 | ||||||
| namespace | namespace | ||||||
| { | { | ||||||
|  | @ -202,7 +205,8 @@ WindowWin32Impl::~WindowWin32Impl() | ||||||
|     ::timeEndPeriod(0); |     ::timeEndPeriod(0); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void WindowWin32Impl::Init(const String& title, uint32_t width, uint32_t height, uint32_t icon, bool resizable) | void WindowWin32Impl::Init(const String& title, uint32_t width, uint32_t height, uint32_t icon, bool resizable, | ||||||
|  |                            bool fullscreen) | ||||||
| { | { | ||||||
|     HINSTANCE  hinst   = GetModuleHandle(nullptr); |     HINSTANCE  hinst   = GetModuleHandle(nullptr); | ||||||
|     WNDCLASSEXA wcex   = { 0 }; |     WNDCLASSEXA wcex   = { 0 }; | ||||||
|  | @ -252,6 +256,9 @@ void WindowWin32Impl::Init(const String& title, uint32_t width, uint32_t height, | ||||||
|     width_         = width; |     width_         = width; | ||||||
|     height_        = height; |     height_        = height; | ||||||
|     resizable_     = resizable; |     resizable_     = resizable; | ||||||
|  |     is_fullscreen_ = fullscreen; | ||||||
|  |     resolution_    = Resolution{ width_, height_, 0 }; | ||||||
|  | 
 | ||||||
|     handle_ = ::CreateWindowExA(0, "KiwanoAppWnd", title.c_str(), GetStyle(), left, top, width, height, nullptr, |     handle_ = ::CreateWindowExA(0, "KiwanoAppWnd", title.c_str(), GetStyle(), left, top, width, height, nullptr, | ||||||
|                                 nullptr, hinst, nullptr); |                                 nullptr, hinst, nullptr); | ||||||
| 
 | 
 | ||||||
|  | @ -269,6 +276,19 @@ void WindowWin32Impl::Init(const String& title, uint32_t width, uint32_t height, | ||||||
| 
 | 
 | ||||||
|     ::ShowWindow(handle_, SW_SHOWNORMAL); |     ::ShowWindow(handle_, SW_SHOWNORMAL); | ||||||
|     ::UpdateWindow(handle_); |     ::UpdateWindow(handle_); | ||||||
|  | 
 | ||||||
|  |     if (is_fullscreen_) | ||||||
|  |     { | ||||||
|  |         MONITORINFOEXA info = GetMoniterInfoEx(handle_); | ||||||
|  |         int            x    = (int)info.rcMonitor.left; | ||||||
|  |         int            y    = (int)info.rcMonitor.top; | ||||||
|  |         int            cx   = (int)(info.rcMonitor.right - info.rcMonitor.left); | ||||||
|  |         int            cy   = (int)(info.rcMonitor.bottom - info.rcMonitor.top); | ||||||
|  | 
 | ||||||
|  |         // Top the window
 | ||||||
|  |         ::SetWindowPos(handle_, HWND_TOPMOST, x, y, cx, cy, SWP_NOACTIVATE); | ||||||
|  |         ::ShowWindow(handle_, SW_SHOWNORMAL); | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void WindowWin32Impl::PumpEvents() | void WindowWin32Impl::PumpEvents() | ||||||
|  | @ -318,71 +338,78 @@ void WindowWin32Impl::SetCursor(CursorType cursor) | ||||||
| 
 | 
 | ||||||
| void WindowWin32Impl::SetResolution(uint32_t width, uint32_t height, bool fullscreen) | void WindowWin32Impl::SetResolution(uint32_t width, uint32_t height, bool fullscreen) | ||||||
| { | { | ||||||
|     auto d3d = kiwano::graphics::directx::GetD3DDeviceResources(); |     if (is_fullscreen_ != fullscreen) | ||||||
| 
 |  | ||||||
|     if (fullscreen) |  | ||||||
|     { |     { | ||||||
|         HRESULT hr = d3d->ResizeTarget(width, height); |         is_fullscreen_ = fullscreen; | ||||||
|         KGE_THROW_IF_FAILED(hr, "DXGI ResizeTarget failed!"); |  | ||||||
| 
 | 
 | ||||||
|         hr = d3d->SetFullscreenState(fullscreen); |         // Reset window style
 | ||||||
|         KGE_THROW_IF_FAILED(hr, "DXGI SetFullscreenState failed!"); |         ::SetWindowLongPtrA(handle_, GWL_STYLE, GetStyle()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (is_fullscreen_) | ||||||
|  |     { | ||||||
|  |         MONITORINFOEXA info = GetMoniterInfoEx(handle_); | ||||||
|  |         int            x    = (int)info.rcMonitor.left; | ||||||
|  |         int            y    = (int)info.rcMonitor.top; | ||||||
|  |         int            cx   = (int)(info.rcMonitor.right - info.rcMonitor.left); | ||||||
|  |         int            cy   = (int)(info.rcMonitor.bottom - info.rcMonitor.top); | ||||||
|  | 
 | ||||||
|  |         // Top the window
 | ||||||
|  |         ::SetWindowPos(handle_, HWND_TOPMOST, x, y, cx, cy, SWP_NOACTIVATE); | ||||||
|  |         ::ShowWindow(handle_, SW_SHOWNORMAL); | ||||||
|     } |     } | ||||||
|     else |     else | ||||||
|     { |     { | ||||||
|         HRESULT hr = d3d->SetFullscreenState(fullscreen); |         // Adjust the rect of client area
 | ||||||
|         KGE_THROW_IF_FAILED(hr, "DXGI SetFullscreenState failed!"); |         RECT rc = { 0, 0, LONG(width), LONG(height) }; | ||||||
|  |         ::AdjustWindowRect(&rc, GetStyle(), false); | ||||||
| 
 | 
 | ||||||
|         hr = d3d->ResizeTarget(width, height); |         width  = uint32_t(rc.right - rc.left); | ||||||
|         KGE_THROW_IF_FAILED(hr, "DXGI ResizeTarget failed!"); |         height = uint32_t(rc.bottom - rc.top); | ||||||
|  | 
 | ||||||
|  |         MONITORINFOEXA info    = GetMoniterInfoEx(handle_); | ||||||
|  |         uint32_t       screenw = uint32_t(info.rcWork.right - info.rcWork.left); | ||||||
|  |         uint32_t       screenh = uint32_t(info.rcWork.bottom - info.rcWork.top); | ||||||
|  |         int            left    = screenw > width ? ((screenw - width) / 2) : 0; | ||||||
|  |         int            top     = screenh > height ? ((screenh - height) / 2) : 0; | ||||||
|  | 
 | ||||||
|  |         // Reset window style
 | ||||||
|  |         ::SetWindowLongPtrA(handle_, GWL_STYLE, GetStyle()); | ||||||
|  | 
 | ||||||
|  |         // Unpin the window
 | ||||||
|  |         ::SetWindowPos(handle_, HWND_NOTOPMOST, left, top, width, height, SWP_DRAWFRAME | SWP_FRAMECHANGED); | ||||||
|  |         ::ShowWindow(handle_, SW_SHOWNORMAL); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     is_fullscreen_ = fullscreen; |     resolution_ = Resolution{ width, height, 0 }; | ||||||
|  | 
 | ||||||
|  |     // Resize render target
 | ||||||
|  |     Renderer::GetInstance().Resize(width, height); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Vector<Resolution> WindowWin32Impl::GetResolutions() | Vector<Resolution> WindowWin32Impl::GetResolutions() | ||||||
| { | { | ||||||
|     if (resolutions_.empty()) |     if (resolutions_.empty()) | ||||||
|     { |     { | ||||||
|         auto d3d = kiwano::graphics::directx::GetD3DDeviceResources(); |         Set<String> resolution_list; | ||||||
| 
 | 
 | ||||||
|         DXGI_MODE_DESC* mode_descs = nullptr; |         DEVMODEA dmi; | ||||||
|         int             mode_num   = 0; |         ZeroMemory(&dmi, sizeof(dmi)); | ||||||
|  |         dmi.dmSize = sizeof(dmi); | ||||||
| 
 | 
 | ||||||
|         HRESULT hr = d3d->GetDisplaySettings(&mode_descs, &mode_num); |         DWORD mode_count = 0; | ||||||
|         if (SUCCEEDED(hr)) |         while (EnumDisplaySettingsA(device_name_.c_str(), mode_count++, &dmi) != 0) | ||||||
|         { |         { | ||||||
|             std::unique_ptr<DXGI_MODE_DESC[]> mode_list(mode_descs); |             StringStream ss; | ||||||
|  |             ss << dmi.dmPelsWidth << 'x' << dmi.dmPelsHeight << ':' << dmi.dmDisplayFrequency; | ||||||
| 
 | 
 | ||||||
|             if (mode_list) |             if (resolution_list.find(ss.str()) == resolution_list.end()) | ||||||
|             { |             { | ||||||
|                 for (int i = 0; i < mode_num; i++) |                 resolution_list.insert(ss.str()); | ||||||
|                 { |                 resolutions_.push_back(Resolution{ uint32_t(dmi.dmPelsWidth), uint32_t(dmi.dmPelsHeight), | ||||||
|                     Resolution res; |                                                    uint32_t(dmi.dmDisplayFrequency) }); | ||||||
|                     res.width        = mode_descs[i].Width; |  | ||||||
|                     res.height       = mode_descs[i].Height; |  | ||||||
|                     res.refresh_rate = 0; |  | ||||||
| 
 |  | ||||||
|                     if (mode_descs[i].RefreshRate.Denominator > 0) |  | ||||||
|                     { |  | ||||||
|                         res.refresh_rate = mode_descs[i].RefreshRate.Numerator / mode_descs[i].RefreshRate.Denominator; |  | ||||||
|             } |             } | ||||||
| 
 |             ZeroMemory(&dmi, sizeof(dmi)); | ||||||
|                     if (!resolutions_.empty()) |  | ||||||
|                     { |  | ||||||
|                         auto& back = resolutions_.back(); |  | ||||||
|                         if (back.width == res.width && back.height == res.height |  | ||||||
|                             && back.refresh_rate == res.refresh_rate) |  | ||||||
|                             continue; |  | ||||||
|                     } |  | ||||||
| 
 |  | ||||||
|                     resolutions_.push_back(res); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|             KGE_THROW_IF_FAILED(hr, "DXGI GetDisplaySettings failed!"); |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     return resolutions_; |     return resolutions_; | ||||||
|  | @ -390,7 +417,30 @@ Vector<Resolution> WindowWin32Impl::GetResolutions() | ||||||
| 
 | 
 | ||||||
| DWORD WindowWin32Impl::GetStyle() const | DWORD WindowWin32Impl::GetStyle() const | ||||||
| { | { | ||||||
|     return (resizable_ ? (WINDOW_RESIZABLE_STYLE) : (WINDOW_FIXED_STYLE)); |     if (is_fullscreen_) | ||||||
|  |         return WINDOW_FULLSCREEN_STYLE; | ||||||
|  |     if (resizable_) | ||||||
|  |         return WINDOW_RESIZABLE_STYLE; | ||||||
|  |     return WINDOW_FIXED_STYLE; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void WindowWin32Impl::SetActive(bool active) | ||||||
|  | { | ||||||
|  |     if (!handle_) | ||||||
|  |         return; | ||||||
|  | 
 | ||||||
|  |     if (is_fullscreen_) | ||||||
|  |     { | ||||||
|  |         // Hide window when it is not active
 | ||||||
|  |         if (active) | ||||||
|  |         { | ||||||
|  |             ::SetWindowPos(handle_, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             ::SetWindowPos(handle_, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void WindowWin32Impl::UpdateCursor() | void WindowWin32Impl::UpdateCursor() | ||||||
|  | @ -658,8 +708,7 @@ LRESULT WindowWin32Impl::MessageProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA | ||||||
|     { |     { | ||||||
|         if (is_fullscreen_) |         if (is_fullscreen_) | ||||||
|         { |         { | ||||||
|             // TODO restore to fullscreen mode
 |             SetActive(true); | ||||||
|             // SetResolution();
 |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     break; |     break; | ||||||
|  | @ -668,8 +717,7 @@ LRESULT WindowWin32Impl::MessageProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA | ||||||
|     { |     { | ||||||
|         if (is_fullscreen_) |         if (is_fullscreen_) | ||||||
|         { |         { | ||||||
|             // TODO exit fullscreen mode
 |             SetActive(false); | ||||||
|             // ::ShowWindow(handle_, SW_MINIMIZE);
 |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     break; |     break; | ||||||
|  | @ -695,18 +743,6 @@ LRESULT WindowWin32Impl::MessageProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA | ||||||
|     case WM_DISPLAYCHANGE: |     case WM_DISPLAYCHANGE: | ||||||
|     { |     { | ||||||
|         KGE_SYS_LOG("The display resolution has changed"); |         KGE_SYS_LOG("The display resolution has changed"); | ||||||
| 
 |  | ||||||
|         // Check fullscreen state
 |  | ||||||
|         auto d3d_res = graphics::directx::GetD3DDeviceResources(); |  | ||||||
|         auto swap_chain = d3d_res->GetDXGISwapChain(); |  | ||||||
|         if (swap_chain) |  | ||||||
|         { |  | ||||||
|             BOOL is_fullscreen = FALSE; |  | ||||||
|             if (SUCCEEDED(swap_chain->GetFullscreenState(&is_fullscreen, nullptr))) |  | ||||||
|             { |  | ||||||
|                 is_fullscreen_ = !!is_fullscreen; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|     break; |     break; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -68,7 +68,7 @@ inline bool SdkLayersAvailable() | ||||||
| struct D3D10DeviceResources : public ID3D10DeviceResources | struct D3D10DeviceResources : public ID3D10DeviceResources | ||||||
| { | { | ||||||
| public: | public: | ||||||
|     HRESULT Initialize(HWND hwnd) override; |     HRESULT Initialize(HWND hwnd, Size logical_size) override; | ||||||
| 
 | 
 | ||||||
|     HRESULT Present(bool vsync) override; |     HRESULT Present(bool vsync) override; | ||||||
| 
 | 
 | ||||||
|  | @ -138,14 +138,10 @@ D3D10DeviceResources::~D3D10DeviceResources() | ||||||
|     DiscardResources(); |     DiscardResources(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| HRESULT D3D10DeviceResources::Initialize(HWND hwnd) | HRESULT D3D10DeviceResources::Initialize(HWND hwnd, Size logical_size) | ||||||
| { | { | ||||||
|     RECT rc; |  | ||||||
|     ::GetClientRect(hwnd, &rc); |  | ||||||
| 
 |  | ||||||
|     this->hwnd_           = hwnd; |     this->hwnd_           = hwnd; | ||||||
|     this->logical_size_.x = float(rc.right - rc.left); |     this->logical_size_ = logical_size; | ||||||
|     this->logical_size_.y = float(rc.bottom - rc.top); |  | ||||||
| 
 | 
 | ||||||
|     HRESULT hr = this->CreateDeviceResources(); |     HRESULT hr = this->CreateDeviceResources(); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -60,7 +60,7 @@ inline bool SdkLayersAvailable() | ||||||
| struct D3D11DeviceResources : public ID3D11DeviceResources | struct D3D11DeviceResources : public ID3D11DeviceResources | ||||||
| { | { | ||||||
| public: | public: | ||||||
|     HRESULT Initialize(HWND hwnd) override; |     HRESULT Initialize(HWND hwnd, Size logical_size) override; | ||||||
| 
 | 
 | ||||||
|     HRESULT Present(bool vsync) override; |     HRESULT Present(bool vsync) override; | ||||||
| 
 | 
 | ||||||
|  | @ -133,14 +133,10 @@ D3D11DeviceResources::~D3D11DeviceResources() | ||||||
|     DiscardResources(); |     DiscardResources(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| HRESULT D3D11DeviceResources::Initialize(HWND hwnd) | HRESULT D3D11DeviceResources::Initialize(HWND hwnd, Size logical_size) | ||||||
| { | { | ||||||
|     RECT rc; |  | ||||||
|     ::GetClientRect(hwnd, &rc); |  | ||||||
| 
 |  | ||||||
|     this->hwnd_           = hwnd; |     this->hwnd_           = hwnd; | ||||||
|     this->logical_size_.x = float(rc.right - rc.left); |     this->logical_size_   = logical_size; | ||||||
|     this->logical_size_.y = float(rc.bottom - rc.top); |  | ||||||
| 
 | 
 | ||||||
|     HRESULT hr = this->CreateDeviceResources(); |     HRESULT hr = this->CreateDeviceResources(); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -32,7 +32,7 @@ MIDL_INTERFACE("fb99fa64-d9cf-4e0e-9c75-90514797b01d") | ||||||
| ID3DDeviceResourcesBase : public IUnknown | ID3DDeviceResourcesBase : public IUnknown | ||||||
| { | { | ||||||
| public: | public: | ||||||
|     virtual HRESULT Initialize(HWND hwnd) = 0; |     virtual HRESULT Initialize(HWND hwnd, Size logical_size) = 0; | ||||||
| 
 | 
 | ||||||
|     virtual HRESULT Present(bool vsync) = 0; |     virtual HRESULT Present(bool vsync) = 0; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -56,16 +56,17 @@ void RendererImpl::MakeContextForWindow(WindowPtr window) | ||||||
|     KGE_THROW_IF_FAILED(::CoInitialize(nullptr), "CoInitialize failed"); |     KGE_THROW_IF_FAILED(::CoInitialize(nullptr), "CoInitialize failed"); | ||||||
| 
 | 
 | ||||||
|     HWND       target_window = window->GetHandle(); |     HWND       target_window = window->GetHandle(); | ||||||
|     output_size_       = window->GetSize(); |     Resolution resolution    = window->GetCurrentResolution(); | ||||||
| 
 |  | ||||||
|     HRESULT    hr            = target_window ? S_OK : E_FAIL; |     HRESULT    hr            = target_window ? S_OK : E_FAIL; | ||||||
| 
 | 
 | ||||||
|  |     output_size_ = Size{ float(resolution.width), float(resolution.height) }; | ||||||
|  | 
 | ||||||
|     // Initialize Direct3D resources
 |     // Initialize Direct3D resources
 | ||||||
|     if (SUCCEEDED(hr)) |     if (SUCCEEDED(hr)) | ||||||
|     { |     { | ||||||
|         auto d3d_res = graphics::directx::GetD3DDeviceResources(); |         auto d3d_res = graphics::directx::GetD3DDeviceResources(); | ||||||
| 
 | 
 | ||||||
|         hr = d3d_res->Initialize(target_window); |         hr = d3d_res->Initialize(target_window, output_size_); | ||||||
|         if (FAILED(hr)) |         if (FAILED(hr)) | ||||||
|         { |         { | ||||||
|             d3d_res->DiscardResources(); |             d3d_res->DiscardResources(); | ||||||
|  |  | ||||||
|  | @ -74,11 +74,11 @@ public: | ||||||
|     /// @brief 헌왕뻠닸
 |     /// @brief 헌왕뻠닸
 | ||||||
|     void Clear(); |     void Clear(); | ||||||
| 
 | 
 | ||||||
|  |     virtual ~TextureCache(); | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     TextureCache(); |     TextureCache(); | ||||||
| 
 | 
 | ||||||
|     virtual ~TextureCache(); |  | ||||||
| 
 |  | ||||||
| private: | private: | ||||||
|     using TextureMap = UnorderedMap<size_t, TexturePtr>; |     using TextureMap = UnorderedMap<size_t, TexturePtr>; | ||||||
|     TextureMap texture_cache_; |     TextureMap texture_cache_; | ||||||
|  |  | ||||||
|  | @ -126,11 +126,11 @@ public: | ||||||
|     /// @note 此操作会重定向输出流到标准输出流
 |     /// @note 此操作会重定向输出流到标准输出流
 | ||||||
|     void ShowConsole(bool show); |     void ShowConsole(bool show); | ||||||
| 
 | 
 | ||||||
|  |     ~Logger(); | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     Logger(); |     Logger(); | ||||||
| 
 | 
 | ||||||
|     ~Logger(); |  | ||||||
| 
 |  | ||||||
|     void Prepare(Level level, StringStream& sstream); |     void Prepare(Level level, StringStream& sstream); | ||||||
| 
 | 
 | ||||||
|     void Output(Level level, StringStream& sstream); |     void Output(Level level, StringStream& sstream); | ||||||
|  |  | ||||||
|  | @ -88,11 +88,11 @@ public: | ||||||
|     /// @brief 清空所有资源
 |     /// @brief 清空所有资源
 | ||||||
|     void Clear(); |     void Clear(); | ||||||
| 
 | 
 | ||||||
|  |     virtual ~ResourceCache(); | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     ResourceCache(); |     ResourceCache(); | ||||||
| 
 | 
 | ||||||
|     virtual ~ResourceCache(); |  | ||||||
| 
 |  | ||||||
| private: | private: | ||||||
|     UnorderedMap<String, ObjectBasePtr> object_cache_; |     UnorderedMap<String, ObjectBasePtr> object_cache_; | ||||||
| }; | }; | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue