[deploy] Merge pull request #56 from KiwanoEngine/dev

Merge develop branch
This commit is contained in:
Haibo 2020-06-22 00:16:40 +08:00 committed by GitHub
commit 2efd06ade3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 765 additions and 353 deletions

View File

@ -17,11 +17,13 @@
<ClInclude Include="..\..\src\kiwano\base\Director.h" />
<ClInclude Include="..\..\src\kiwano\base\Module.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\core\Allocator.h" />
<ClInclude Include="..\..\src\kiwano\core\Any.h" />
<ClInclude Include="..\..\src\kiwano\core\Cloneable.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\Function.h" />
<ClInclude Include="..\..\src\kiwano\core\IntrusiveList.h" />
@ -132,6 +134,7 @@
<ClCompile Include="..\..\src\kiwano\base\Director.cpp" />
<ClCompile Include="..\..\src\kiwano\base\Module.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\core\Allocator.cpp" />
<ClCompile Include="..\..\src\kiwano\core\Exception.cpp" />

View File

@ -351,6 +351,12 @@
<ClInclude Include="..\..\src\kiwano\utils\ConfigIni.h">
<Filter>utils</Filter>
</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>
<ClCompile Include="..\..\src\kiwano\2d\Canvas.cpp">
@ -575,6 +581,9 @@
<ClCompile Include="..\..\src\kiwano\utils\ConfigIni.cpp">
<Filter>utils</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kiwano\base\ObjectPool.cpp">
<Filter>base</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="suppress_warning.ruleset" />

View File

@ -68,11 +68,11 @@ public:
void DestroyModule() override;
~AudioModule();
private:
AudioModule();
~AudioModule();
private:
IXAudio2* x_audio2_;
IXAudio2MasteringVoice* mastering_voice_;

View File

@ -21,6 +21,8 @@
#include <kiwano-physics/PhysicBody.h>
#include <kiwano-physics/PhysicWorld.h>
#define KGE_PHYSIC_COMP_NAME "__KGE_PHYSIC_BODY__"
namespace kiwano
{
namespace physics
@ -48,6 +50,25 @@ PhysicBodyPtr PhysicBody::Create(PhysicWorld* world, Type type)
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()
: body_(nullptr)
, world_(nullptr)
@ -56,7 +77,7 @@ PhysicBody::PhysicBody()
, mask_bits_(0xFFFF)
, group_index_(0)
{
SetName("KGE_PHYSIC_BODY");
SetName(KGE_PHYSIC_COMP_NAME);
}
PhysicBody::~PhysicBody() {}
@ -65,8 +86,6 @@ void PhysicBody::InitComponent(Actor* actor)
{
Component::InitComponent(actor);
actor->SetPhysicBody(this);
UpdateFromActor(actor);
}

View File

@ -62,6 +62,16 @@ public:
/// @param 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();
virtual ~PhysicBody();

View File

@ -413,7 +413,7 @@ void PhysicWorld::BeforeSimulation(Actor* parent, const Matrix3x2& parent_to_wor
{
Matrix3x2 child_to_world = child->GetTransformMatrixToParent() * parent_to_world;
PhysicBody* body = child->GetPhysicBody();
PhysicBody* body = PhysicBody::Get(child);
if (body)
{
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())
{
PhysicBody* body = child->GetPhysicBody();
PhysicBody* body = PhysicBody::Get(child);
if (body)
{
body->AfterSimulation(child.Get(), parent_to_world, parent_rotation);

View File

@ -59,6 +59,7 @@ Actor::Actor()
, cascade_opacity_(false)
, show_border_(false)
, is_fast_transform_(true)
, evt_dispatch_enabled_(true)
, parent_(nullptr)
, stage_(nullptr)
, hash_name_(0)
@ -66,7 +67,6 @@ Actor::Actor()
, opacity_(1.f)
, displayed_opacity_(1.f)
, 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)
{
if (!visible_)
if (!visible_ || !evt_dispatch_enabled_)
return true;
// Dispatch to children those are greater than 0 in Z-Order
@ -221,6 +221,11 @@ bool Actor::DispatchEvent(Event* evt)
return true;
}
void Actor::SetEventDispatchEnabled(bool enabled)
{
evt_dispatch_enabled_ = enabled;
}
void Actor::DoSerialize(Serializer* serializer) const
{
ObjectBase::DoSerialize(serializer);

View File

@ -33,11 +33,6 @@ class Stage;
class Director;
class RenderContext;
namespace physics
{
class PhysicBody;
}
KGE_DECLARE_SMART_PTR(Actor);
/// \~chinese
@ -110,6 +105,10 @@ public:
/// @brief 是否启用级联透明度
bool IsCascadeOpacityEnabled() const;
/// \~chinese
/// @brief 是否启用事件分发
bool IsEventDispatchEnabled() const;
/// \~chinese
/// @brief 获取名称的 Hash 值
size_t GetHashName() const;
@ -391,14 +390,6 @@ public:
/// @brief 获取更新时的回调函数
UpdateCallback GetCallbackOnUpdate() const;
/// \~chinese
/// @brief 获取物理身体仅当kiwano-physics包启用时生效
physics::PhysicBody* GetPhysicBody() const;
/// \~chinese
/// @brief 设置物理身体仅当kiwano-physics包启用时生效
void SetPhysicBody(physics::PhysicBody* body);
/// \~chinese
/// @brief 判断点是否在角色内
virtual bool ContainsPoint(const Point& point) const;
@ -421,6 +412,11 @@ public:
/// @return 是否继续分发该事件
virtual bool DispatchEvent(Event* evt);
/// \~chinese
/// @brief 开启或关闭事件分发功能
/// @param enabled 是否开启
void SetEventDispatchEnabled(bool enabled);
/// \~chinese
/// @brief 序列化
void DoSerialize(Serializer* serializer) const override;
@ -482,6 +478,7 @@ private:
bool hover_;
bool pressed_;
bool responsible_;
bool evt_dispatch_enabled_;
int z_order_;
float opacity_;
float displayed_opacity_;
@ -502,8 +499,6 @@ private:
mutable Matrix3x2 transform_matrix_;
mutable Matrix3x2 transform_matrix_inverse_;
mutable Matrix3x2 transform_matrix_to_parent_;
physics::PhysicBody* physic_body_;
};
/** @} */
@ -533,6 +528,11 @@ inline bool Actor::IsCascadeOpacityEnabled() const
return cascade_opacity_;
}
inline bool Actor::IsEventDispatchEnabled() const
{
return evt_dispatch_enabled_;
}
inline size_t Actor::GetHashName() const
{
return hash_name_;
@ -688,16 +688,6 @@ inline Actor::UpdateCallback Actor::GetCallbackOnUpdate() const
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)
{
show_border_ = show;

View File

@ -36,11 +36,9 @@ namespace kiwano
/// @brief 动画辅助类
struct ActionHelper
{
using DoneCallback = Action::DoneCallback;
/// \~chinese
/// @brief 设置循环次数
inline ActionHelper& SetLoops(int loops)
inline ActionHelper& Loops(int loops)
{
ptr->SetLoops(loops);
return (*this);
@ -48,7 +46,7 @@ struct ActionHelper
/// \~chinese
/// @brief 设置动画延迟
inline ActionHelper& SetDelay(Duration delay)
inline ActionHelper& Delay(Duration delay)
{
ptr->SetDelay(delay);
return (*this);
@ -56,7 +54,7 @@ struct ActionHelper
/// \~chinese
/// @brief 设置动画结束回调函数
inline ActionHelper& SetDoneCallback(const DoneCallback& cb)
inline ActionHelper& DoneCallback(const Action::DoneCallback& cb)
{
ptr->SetDoneCallback(cb);
return (*this);
@ -64,7 +62,7 @@ struct ActionHelper
/// \~chinese
/// @brief 设置动画循环结束时的回调函数
inline ActionHelper& SetLoopDoneCallback(const DoneCallback& cb)
inline ActionHelper& LoopDoneCallback(const Action::DoneCallback& cb)
{
ptr->SetLoopDoneCallback(cb);
return (*this);
@ -80,7 +78,7 @@ struct ActionHelper
/// \~chinese
/// @brief 设置名称
inline ActionHelper& SetName(const String& name)
inline ActionHelper& Name(const String& name)
{
ptr->SetName(name);
return (*this);
@ -116,11 +114,9 @@ private:
/// @brief 补间动画辅助类
struct TweenHelper
{
using DoneCallback = Action::DoneCallback;
/// \~chinese
/// @brief 设置动画持续时长
inline TweenHelper& SetDuration(Duration dur)
inline TweenHelper& Dur(Duration dur)
{
ptr->SetDuration(dur);
return (*this);
@ -128,7 +124,7 @@ struct TweenHelper
/// \~chinese
/// @brief 设置循环次数
inline TweenHelper& SetLoops(int loops)
inline TweenHelper& Loops(int loops)
{
ptr->SetLoops(loops);
return (*this);
@ -136,7 +132,7 @@ struct TweenHelper
/// \~chinese
/// @brief 设置缓动函数
inline TweenHelper& SetEaseFunc(EaseFunc ease)
inline TweenHelper& EaseFunc(EaseFunc ease)
{
ptr->SetEaseFunc(ease);
return (*this);
@ -144,7 +140,7 @@ struct TweenHelper
/// \~chinese
/// @brief 设置动画延迟
inline TweenHelper& SetDelay(Duration delay)
inline TweenHelper& Delay(Duration delay)
{
ptr->SetDelay(delay);
return (*this);
@ -152,7 +148,7 @@ struct TweenHelper
/// \~chinese
/// @brief 设置动画结束回调函数
inline TweenHelper& SetDoneCallback(const DoneCallback& cb)
inline TweenHelper& DoneCallback(const Action::DoneCallback& cb)
{
ptr->SetDoneCallback(cb);
return (*this);
@ -160,7 +156,7 @@ struct TweenHelper
/// \~chinese
/// @brief 设置动画循环结束时的回调函数
inline TweenHelper& SetLoopDoneCallback(const DoneCallback& cb)
inline TweenHelper& LoopDoneCallback(const Action::DoneCallback& cb)
{
ptr->SetLoopDoneCallback(cb);
return (*this);
@ -176,7 +172,7 @@ struct TweenHelper
/// \~chinese
/// @brief 设置名称
inline TweenHelper& SetName(const String& name)
inline TweenHelper& Name(const String& name)
{
ptr->SetName(name);
return (*this);
@ -220,7 +216,7 @@ struct Tween
public:
/// \~chinese
/// @brief 构造相对位移动画
/// @param duration 动画时长
/// @param dur 动画时长
/// @param vector 移动向量
static inline TweenHelper MoveBy(Duration dur, const Point& vector)
{
@ -229,7 +225,7 @@ public:
/// \~chinese
/// @brief 构造位移动画
/// @param duration 动画时长
/// @param dur 动画时长
/// @param pos 目的坐标
static inline TweenHelper MoveTo(Duration dur, const Point& pos)
{
@ -238,29 +234,29 @@ public:
/// \~chinese
/// @brief 构造相对跳跃动画
/// @param duration 动画时长
/// @param dur 动画时长
/// @param vec 跳跃位移向量
/// @param height 跳跃高度
/// @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
/// @brief 构造跳跃动画
/// @param duration 动画时长
/// @param dur 动画时长
/// @param pos 目的坐标
/// @param height 跳跃高度
/// @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
/// @brief 构造相对缩放动画
/// @param duration 动画时长
/// @param dur 动画时长
/// @param scale_x 横向缩放相对变化值
/// @param scale_y 纵向缩放相对变化值
static inline TweenHelper ScaleBy(Duration dur, float scale_x, float scale_y)
@ -270,7 +266,7 @@ public:
/// \~chinese
/// @brief 构造缩放动画
/// @param duration 动画时长
/// @param dur 动画时长
/// @param scale_x 横向缩放目标值
/// @param scale_y 纵向缩放目标值
static inline TweenHelper ScaleTo(Duration dur, float scale_x, float scale_y)
@ -280,7 +276,7 @@ public:
/// \~chinese
/// @brief 构造透明度渐变动画
/// @param duration 动画时长
/// @param dur 动画时长
/// @param opacity 目标透明度
static inline TweenHelper FadeTo(Duration dur, float opacity)
{
@ -289,7 +285,7 @@ public:
/// \~chinese
/// @brief 构造淡入动画
/// @param duration 动画时长
/// @param dur 动画时长
static inline TweenHelper FadeIn(Duration dur)
{
return TweenHelper(ActionFadeIn::Create(dur));
@ -297,7 +293,7 @@ public:
/// \~chinese
/// @brief 构造淡出动画
/// @param duration 动画时长
/// @param dur 动画时长
static inline TweenHelper FadeOut(Duration dur)
{
return TweenHelper(ActionFadeOut::Create(dur));
@ -305,7 +301,7 @@ public:
/// \~chinese
/// @brief 构造相对旋转动画
/// @param duration 动画时长
/// @param dur 动画时长
/// @param rotation 角度相对变化值
static inline TweenHelper RotateBy(Duration dur, float rotation)
{
@ -314,7 +310,7 @@ public:
/// \~chinese
/// @brief 构造旋转动画
/// @param duration 动画时长
/// @param dur 动画时长
/// @param rotation 目标角度
static inline TweenHelper RotateTo(Duration dur, float rotation)
{
@ -323,20 +319,20 @@ public:
/// \~chinese
/// @brief 构造路径行走动画
/// @param duration 持续时长
/// @param dur 持续时长
/// @param path 路径形状
/// @param rotating 是否沿路径切线方向旋转
/// @param start 路径起点(百分比)
/// @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)
{
return TweenHelper(ActionWalk::Create(duration, path, rotating, start, end));
return TweenHelper(ActionWalk::Create(dur, path, rotating, start, end));
}
/// \~chinese
/// @brief 构建帧动画
/// @param duration 动画时长
/// @param dur 动画时长
/// @param[in] frame_seq 序列帧
static inline TweenHelper Animation(Duration dur, FrameSequencePtr frames)
{
@ -345,7 +341,7 @@ public:
/// \~chinese
/// @brief 构造自定义动画
/// @param duration 动画时长
/// @param dur 动画时长
/// @param tween_func 动画回调函数
static inline TweenHelper Custom(Duration dur, ActionCustom::TweenFunc tween_func)
{

View File

@ -102,11 +102,11 @@ public:
void HandleEvent(Event* evt) override;
virtual ~Director();
private:
Director();
virtual ~Director();
private:
bool render_border_enabled_;
Stack<StagePtr> stages_;

View File

@ -19,6 +19,7 @@
// THE SOFTWARE.
#include <kiwano/base/ObjectBase.h>
#include <kiwano/base/ObjectPool.h>
#include <kiwano/utils/Logger.h>
#include <kiwano/utils/Json.h>
#include <typeinfo>
@ -56,6 +57,11 @@ ObjectBase::~ObjectBase()
#endif
}
void ObjectBase::AutoRelease()
{
ObjectPool::GetInstance().AddObject(this);
}
const Any& ObjectBase::GetUserData() const
{
return user_data_;

View File

@ -44,6 +44,10 @@ public:
virtual ~ObjectBase();
/// \~chinese
/// @brief 自动释放
void AutoRelease();
/// \~chinese
/// @brief 设置对象名
void SetName(const String& name);

View File

@ -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

View File

@ -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

View File

@ -47,7 +47,7 @@ ButtonPtr Button::Create(const Callback& click, const Callback& pressed, const C
Button::Button()
: status_(Status::Normal)
{
SetName("KGE_BUTTON");
SetName("__KGE_BUTTON__");
}
Button::~Button()

View File

@ -21,7 +21,6 @@
#pragma once
#include <kiwano/core/Time.h>
#include <kiwano/base/ObjectBase.h>
#include <kiwano/core/IntrusiveList.h>
#include <kiwano/render/RenderContext.h>
namespace kiwano
@ -49,10 +48,8 @@ KGE_DECLARE_SMART_PTR(Component);
*/
class KGE_API Component
: public ObjectBase
, protected IntrusiveListValue<ComponentPtr>
{
friend class ComponentManager;
friend IntrusiveList<ComponentPtr>;
public:
/// \~chinese

View File

@ -19,6 +19,7 @@
// THE SOFTWARE.
#include <kiwano/base/component/ComponentManager.h>
#include <functional>
namespace kiwano
{
@ -34,46 +35,74 @@ Component* ComponentManager::AddComponent(ComponentPtr component)
if (component)
{
component->InitComponent(target_);
components_.PushBack(component);
size_t hash = std::hash<String>{}(component->GetName());
AddComponent(hash, component);
}
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_;
}
const ComponentList& ComponentManager::GetAllComponents() const
const ComponentMap& ComponentManager::GetAllComponents() const
{
return components_;
}
void ComponentManager::RemoveComponent(ComponentPtr component)
{
auto iter = std::find(components_.begin(), components_.end(), component);
if (iter != components_.end())
{
component->DestroyComponent();
components_.Remove(component);
}
RemoveComponent(component->GetName());
}
void ComponentManager::RemoveComponents(const String& name)
void ComponentManager::RemoveComponent(const String& name)
{
if (!components_.IsEmpty())
{
ComponentPtr next;
for (auto component = components_.GetFirst(); component; component = next)
{
next = component->GetNext();
size_t hash = std::hash<String>{}(name);
RemoveComponent(hash);
}
if (component->IsName(name))
{
component->DestroyComponent();
components_.Remove(component);
}
void ComponentManager::RemoveComponent(size_t name_hash)
{
if (!components_.empty())
{
auto iter = components_.find(name_hash);
if (iter != components_.end())
{
iter->second->DestroyComponent();
components_.erase(iter);
}
}
}
@ -81,31 +110,28 @@ void ComponentManager::RemoveComponents(const String& name)
void ComponentManager::RemoveAllComponents()
{
// Destroy all components
if (!components_.IsEmpty())
if (!components_.empty())
{
ComponentPtr next;
for (auto component = components_.GetFirst(); component; component = next)
for (auto& p : components_)
{
next = component->GetNext();
component->DestroyComponent();
p.second->DestroyComponent();
}
}
components_.Clear();
components_.clear();
}
void ComponentManager::Update(Duration dt)
{
if (!components_.IsEmpty())
if (!components_.empty())
{
ComponentPtr next;
for (auto component = components_.GetFirst(); component; component = next)
if (!components_.empty())
{
next = component->GetNext();
if (component->IsEnable())
for (auto& p : components_)
{
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)
{
if (!components_.IsEmpty())
if (!components_.empty())
{
ComponentPtr next;
for (auto component = components_.GetFirst(); component; component = next)
if (!components_.empty())
{
next = component->GetNext();
if (component->IsEnable())
for (auto& p : components_)
{
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)
{
if (!components_.IsEmpty())
if (!components_.empty())
{
ComponentPtr next;
for (auto component = components_.GetFirst(); component; component = next)
if (!components_.empty())
{
next = component->GetNext();
if (component->IsEnable())
for (auto& p : components_)
{
component->HandleEvent(evt);
if (p.second->IsEnable())
{
p.second->HandleEvent(evt);
}
}
}
}

View File

@ -31,8 +31,8 @@ namespace kiwano
*/
/// \~chinese
/// @brief 组件列表
typedef IntrusiveList<ComponentPtr> ComponentList;
/// @brief 组件映射
typedef UnorderedMap<size_t, ComponentPtr> ComponentMap;
/**
* \~chinese
@ -47,12 +47,26 @@ public:
Component* AddComponent(ComponentPtr component);
/// \~chinese
/// @brief 获取所有组件
ComponentList& GetAllComponents();
/// @brief 添加组件
/// @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
/// @brief 获取所有组件
const ComponentList& GetAllComponents() const;
ComponentMap& GetAllComponents();
/// \~chinese
/// @brief 获取所有组件
const ComponentMap& GetAllComponents() const;
/// \~chinese
/// @brief 移除组件
@ -61,7 +75,12 @@ public:
/// \~chinese
/// @brief 移除组件
/// @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
/// @brief 移除所有组件
@ -83,8 +102,8 @@ protected:
ComponentManager(Actor* target);
private:
Actor* target_;
ComponentList components_;
Actor* target_;
ComponentMap components_;
};
/** @} */

69
src/kiwano/core/Defer.h Normal file
View File

@ -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

View File

@ -19,12 +19,13 @@
// THE SOFTWARE.
#pragma once
#include <memory>
namespace kiwano
{
template <typename _Ty>
struct Singleton
class Singleton
{
protected:
Singleton() = default;
@ -32,29 +33,47 @@ protected:
Singleton& operator=(const Singleton&) = delete;
private:
struct ObjectCreator
struct InstanceCreator
{
ObjectCreator()
InstanceCreator()
{
(void)Singleton<_Ty>::GetInstance();
(void)Singleton<_Ty>::GetInstancePtr();
}
inline void Dummy() const {}
};
static ObjectCreator creator_;
static InstanceCreator creator_;
public:
using object_type = _Ty;
static std::unique_ptr<object_type> instance_ptr_;
static inline object_type& GetInstance()
{
static object_type instance;
return *GetInstancePtr();
}
static inline object_type* GetInstancePtr()
{
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>
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

View File

@ -54,7 +54,7 @@ public:
/// \~chinese
/// @brief 判断事件类型
/// @return 是否是指定事件类型
/// @return 事件类型相同返回true否则返回false
template <typename _Ty>
bool IsType() const;
@ -75,19 +75,20 @@ private:
};
/// \~chinese
/// @brief 事件特性:判断指定类型是否是事件
/// @brief 事件特性:判断是否是事件
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
/// @brief 事件特性:判断一个事件能否安全转换到另一事件类型
template <typename _Ty, typename = typename std::enable_if<IsEvent<_Ty>::value, int>::type>
struct IsEventType
/// @brief 事件特性:判断事件类型是否相同
template <typename _Ty>
struct IsSameEventType
{
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);
}
};
@ -102,8 +103,8 @@ inline const EventType& Event::GetType() const
template <typename _Ty>
inline bool Event::IsType() const
{
static_assert(kiwano::IsEvent<_Ty>::value, "_Ty is not an event type.");
return kiwano::IsEventType<_Ty>()(this);
static_assert(kiwano::IsBaseOfEvent<_Ty>::value, "_Ty is not an event type.");
return IsSameEventType<_Ty>()(this);
}
template <typename _Ty>

View File

@ -59,7 +59,7 @@ public:
template <typename _EventTy>
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);
}
@ -71,7 +71,7 @@ public:
template <typename _EventTy>
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);
}

View File

@ -58,4 +58,12 @@ EventListener::EventListener()
EventListener::~EventListener() {}
void EventListener::Receive(Event* evt)
{
if (ShouldHandle(evt) && callback_)
{
callback_(evt);
}
}
} // namespace kiwano

View File

@ -67,7 +67,7 @@ public:
template <typename _EventTy>
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);
}
@ -79,7 +79,7 @@ public:
template <typename _EventTy>
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);
}
@ -132,12 +132,17 @@ public:
/// @brief 设置监听的事件类型
void SetEventType(const EventType& type);
/// \~chinese
/// @brief ÅжÏÊÇ·ñ´¦Àíʼþ
virtual bool ShouldHandle(Event* evt) const;
/// \~chinese
/// @brief 设置监听的事件类型
/// @tparam _EventTy 事件类型
template <typename _EventTy, typename = typename std::enable_if<IsEvent<_EventTy>::value, int>::type>
template <typename _EventTy>
inline void SetEventType()
{
static_assert(kiwano::IsBaseOfEvent<_EventTy>::value, "_EventTy is not an event type.");
SetEventType(KGE_EVENT(_EventTy));
}
@ -208,13 +213,13 @@ inline void EventListener::SetEventType(const EventType& type)
type_ = type;
}
inline void EventListener::Receive(Event* evt)
inline bool EventListener::ShouldHandle(Event* evt) const
{
KGE_ASSERT(evt != nullptr);
if (type_ == evt->GetType() && callback_)
if (evt)
{
callback_(evt);
return evt->GetType() == type_;
}
return false;
}
} // namespace kiwano

View File

@ -72,10 +72,8 @@ public:
KeyCharEvent();
};
/** @} */
template <>
struct IsEventType<KeyEvent>
struct IsSameEventType<KeyEvent>
{
inline bool operator()(const Event* evt) const
{
@ -84,4 +82,6 @@ struct IsEventType<KeyEvent>
}
};
/** @} */
} // namespace kiwano

View File

@ -113,10 +113,8 @@ public:
MouseWheelEvent();
};
/** @} */
template <>
struct IsEventType<MouseEvent>
struct IsSameEventType<MouseEvent>
{
inline bool operator()(const Event* evt) const
{
@ -127,4 +125,6 @@ struct IsEventType<MouseEvent>
}
};
/** @} */
} // namespace kiwano

View File

@ -93,10 +93,8 @@ public:
WindowClosedEvent();
};
/** @} */
template <>
struct IsEventType<WindowEvent>
struct IsSameEventType<WindowEvent>
{
inline bool operator()(const Event* evt) const
{
@ -107,4 +105,6 @@ struct IsEventType<WindowEvent>
}
};
/** @} */
} // namespace kiwano

View File

@ -44,6 +44,7 @@
//
#include <kiwano/core/Common.h>
#include <kiwano/core/Defer.h>
#include <kiwano/core/Resource.h>
#include <kiwano/core/SmartPtr.hpp>
#include <kiwano/core/Time.h>

View File

@ -19,11 +19,12 @@
// THE SOFTWARE.
#include <kiwano/platform/Application.h>
#include <kiwano/utils/Logger.h>
#include <kiwano/core/Defer.h>
#include <kiwano/base/Director.h>
#include <kiwano/render/Renderer.h>
#include <kiwano/render/TextureCache.h>
#include <kiwano/utils/ResourceCache.h>
#include <kiwano/utils/Logger.h>
namespace kiwano
{
@ -42,15 +43,15 @@ Application::Application()
Application::~Application()
{
this->Destroy();
}
void Application::Run(RunnerPtr runner)
{
KGE_ASSERT(runner);
runner_ = runner;
running_ = true;
running_ = true;
is_paused_ = false;
runner_ = runner;
timer_ = Timer::Create();
// Initialize runner
runner->InitSettings();
@ -61,51 +62,43 @@ void Application::Run(RunnerPtr runner)
c->SetupModule();
}
// Ensure resources are destroyed before exiting
KGE_DEFER[=]()
{
this->Destroy();
};
// Everything is ready
runner->OnReady();
// Update everything
this->Update(0);
// Start the loop
while (running_)
{
if (!frame_ticker_)
{
frame_ticker_ = Ticker::Create(0);
}
timer_->Tick();
if (frame_ticker_->Tick())
{
// Execute main loop
if (!runner->MainLoop(frame_ticker_->GetDeltaTime()))
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();
}
}
// Execute main loop
if (!runner->MainLoop(timer_->GetDeltaTime()))
running_ = false;
}
this->Destroy();
}
void Application::Pause()
{
is_paused_ = true;
if (frame_ticker_)
frame_ticker_->Pause();
if (timer_)
timer_->Pause();
}
void Application::Resume()
{
is_paused_ = false;
if (frame_ticker_)
frame_ticker_->Resume();
if (timer_)
timer_->Resume();
}
void Application::Quit()
@ -113,6 +106,12 @@ void Application::Quit()
running_ = false;
}
void Application::UpdateFrame(Duration dt)
{
this->Render();
this->Update(dt);
}
void Application::Destroy()
{
if (runner_)

View File

@ -27,7 +27,7 @@
#include <kiwano/event/Event.h>
#include <kiwano/platform/Runner.h>
#include <kiwano/platform/Window.h>
#include <kiwano/utils/Ticker.h>
#include <kiwano/utils/Timer.h>
namespace kiwano
{
@ -103,18 +103,6 @@ public:
*/
WindowPtr GetWindow() const;
/**
* \~chinese
* @brief
*/
TickerPtr GetFrameTicker() const;
/**
* \~chinese
* @brief
*/
void SetFrameTicker(TickerPtr ticker);
/**
* \~chinese
* @brief
@ -150,16 +138,10 @@ public:
/**
* \~chinese
* @brief
* @brief
* @param dt
*/
void Update(Duration dt);
/**
* \~chinese
* @brief
*/
void Render();
void UpdateFrame(Duration dt);
/**
* \~chinese
@ -167,12 +149,26 @@ public:
*/
void Destroy();
private:
/**
* \~chinese
* @brief
* @param dt
*/
void Update(Duration dt);
/**
* \~chinese
* @brief
*/
void Render();
private:
bool running_;
bool is_paused_;
float time_scale_;
RunnerPtr runner_;
TickerPtr frame_ticker_;
TimerPtr timer_;
List<Module*> modules_;
std::mutex perform_mutex_;
Queue<Function<void()>> functions_to_perform_;
@ -185,18 +181,9 @@ inline RunnerPtr Application::GetRunner() const
inline WindowPtr Application::GetWindow() const
{
KGE_ASSERT(runner_);
return runner_->GetWindow();
}
inline TickerPtr Application::GetFrameTicker() const
{
return frame_ticker_;
}
inline void Application::SetFrameTicker(TickerPtr ticker)
{
frame_ticker_ = ticker;
if (runner_)
return runner_->GetWindow();
return nullptr;
}
inline bool Application::IsPaused() const

View File

@ -102,11 +102,11 @@ public:
*/
bool ExtractResourceToFile(const Resource& res, const String& dest_file_name) const;
~FileSystem();
private:
FileSystem();
~FileSystem();
private:
Vector<String> search_paths_;
UnorderedMap<String, String> file_lookup_dict_;

View File

@ -112,11 +112,11 @@ public:
void HandleEvent(Event* evt) override;
~Input();
private:
Input();
~Input();
void UpdateKey(KeyCode key, bool down);
void UpdateButton(MouseButton btn, bool down);

View File

@ -82,8 +82,8 @@ void Runner::InitSettings()
}
// Create game window
WindowPtr window =
Window::Create(settings_.title, settings_.width, settings_.height, settings_.icon, settings_.resizable);
WindowPtr window = Window::Create(settings_.title, settings_.width, settings_.height, settings_.icon,
settings_.resizable, settings_.fullscreen);
SetWindow(window);
// Update renderer settings
@ -101,6 +101,9 @@ void Runner::InitSettings()
Director::GetInstance().ShowDebugInfo(true);
Renderer::GetInstance().GetContext().SetCollectingStatus(true);
}
// Create frame ticker
frame_ticker_ = Ticker::Create(settings_.frame_interval, -1);
}
bool Runner::MainLoop(Duration dt)
@ -118,9 +121,6 @@ bool Runner::MainLoop(Duration dt)
Application& app = Application::GetInstance();
// Update modules before poll events
app.Update(dt);
// Poll events
main_window_->PumpEvents();
while (EventPtr evt = main_window_->PollEvent())
@ -128,12 +128,27 @@ bool Runner::MainLoop(Duration dt)
app.DispatchEvent(evt.Get());
}
app.Render();
if (app.IsPaused())
// Update frame ticker
if (frame_ticker_)
{
// Slow down when the application is paused
Duration(5).Sleep();
if (frame_ticker_->Tick(dt))
{
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;
}

View File

@ -24,6 +24,8 @@
#include <kiwano/platform/Window.h>
#include <kiwano/render/Color.h>
#include <kiwano/render/Texture.h>
#include <kiwano/utils/Ticker.h>
namespace kiwano
{
@ -38,14 +40,16 @@ KGE_DECLARE_SMART_PTR(Runner);
*/
struct Settings
{
uint32_t width; ///< 窗口宽度
uint32_t height; ///< 窗口高度
String title; ///< 窗口标题
uint32_t icon; ///< 窗口图标
bool resizable; ///< 窗口大小可调整
Color bg_color; ///< 窗口背景色
bool vsync_enabled; ///< 垂直同步
bool debug_mode; ///< 调试模式
uint32_t width; ///< 窗口宽度
uint32_t height; ///< 窗口高度
String title; ///< 窗口标题
uint32_t icon; ///< 窗口图标
bool resizable; ///< 窗口大小可调整
bool fullscreen; ///< 窗口全屏
Color bg_color; ///< 窗口背景色
Duration frame_interval; ///< 帧间隔
bool vsync_enabled; ///< 垂直同步
bool debug_mode; ///< 调试模式
Settings()
: width(800)
@ -53,8 +57,10 @@ struct Settings
, title("Kiwano")
, icon()
, resizable(false)
, fullscreen(false)
, bg_color(Color::Black)
, vsync_enabled(true)
, frame_interval(16)
, vsync_enabled(false)
, debug_mode(false)
{
}
@ -118,6 +124,14 @@ public:
/// @brief »ñÈ¡ÉèÖÃ
Settings GetSettings() const;
/// \~chinese
/// @brief 获取帧报时器
TickerPtr GetFrameTicker() const;
/// \~chinese
/// @brief 设置帧报时器
void SetFrameTicker(TickerPtr ticker);
protected:
/// \~chinese
/// @brief ÐÞ¸ÄÉèÖÃ
@ -131,6 +145,7 @@ private:
private:
Settings settings_;
WindowPtr main_window_;
TickerPtr frame_ticker_;
};
inline void Runner::OnReady() {}
@ -162,4 +177,14 @@ inline void Runner::SetSettings(Settings settings)
settings_ = settings;
}
inline TickerPtr Runner::GetFrameTicker() const
{
return frame_ticker_;
}
inline void Runner::SetFrameTicker(TickerPtr ticker)
{
frame_ticker_ = ticker;
}
} // namespace kiwano

View File

@ -71,6 +71,11 @@ uint32_t Window::GetHeight() const
return height_;
}
Resolution Window::GetCurrentResolution() const
{
return resolution_;
}
WindowHandle Window::GetHandle() const
{
return handle_;

View File

@ -80,7 +80,7 @@ public:
* @throw kiwano::SystemError
*/
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
@ -110,6 +110,12 @@ public:
*/
uint32_t GetHeight() const;
/**
* \~chinese
* @brief
*/
Resolution GetCurrentResolution() const;
/**
* \~chinese
* @brief
@ -214,6 +220,7 @@ protected:
uint32_t min_height_;
uint32_t max_width_;
uint32_t max_height_;
Resolution resolution_;
WindowHandle handle_;
String title_;
std::queue<EventPtr> event_queue_;

View File

@ -30,7 +30,6 @@
#include <kiwano/event/Events.h>
#include <kiwano/platform/Application.h>
#include <kiwano/render/Renderer.h>
#include <kiwano/render/DirectX/D3DDeviceResources.h>
#include <Windowsx.h> // GET_X_LPARAM, GET_Y_LPARAM
#include <imm.h> // ImmAssociateContext
#pragma comment(lib, "imm32.lib")
@ -49,7 +48,7 @@ public:
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;
@ -69,6 +68,8 @@ public:
DWORD GetStyle() const;
void SetActive(bool active);
void UpdateCursor();
LRESULT MessageProc(HWND, UINT32, WPARAM, LPARAM);
@ -86,12 +87,13 @@ private:
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>();
if (ptr)
{
ptr->Init(title, width, height, icon, resizable);
ptr->Init(title, width, height, icon, resizable, fullscreen);
}
return ptr;
}
@ -103,6 +105,7 @@ namespace kiwano
#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_FULLSCREEN_STYLE WS_CLIPCHILDREN | WS_POPUP
namespace
{
@ -202,7 +205,8 @@ WindowWin32Impl::~WindowWin32Impl()
::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);
WNDCLASSEXA wcex = { 0 };
@ -249,10 +253,13 @@ void WindowWin32Impl::Init(const String& title, uint32_t width, uint32_t height,
width = win_width;
height = win_height;
width_ = width;
height_ = height;
resizable_ = resizable;
handle_ = ::CreateWindowExA(0, "KiwanoAppWnd", title.c_str(), GetStyle(), left, top, width, height, nullptr,
width_ = width;
height_ = height;
resizable_ = resizable;
is_fullscreen_ = fullscreen;
resolution_ = Resolution{ width_, height_, 0 };
handle_ = ::CreateWindowExA(0, "KiwanoAppWnd", title.c_str(), GetStyle(), left, top, width, height, nullptr,
nullptr, hinst, nullptr);
if (handle_ == nullptr)
@ -269,6 +276,19 @@ void WindowWin32Impl::Init(const String& title, uint32_t width, uint32_t height,
::ShowWindow(handle_, SW_SHOWNORMAL);
::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()
@ -318,71 +338,78 @@ void WindowWin32Impl::SetCursor(CursorType cursor)
void WindowWin32Impl::SetResolution(uint32_t width, uint32_t height, bool fullscreen)
{
auto d3d = kiwano::graphics::directx::GetD3DDeviceResources();
if (fullscreen)
if (is_fullscreen_ != fullscreen)
{
HRESULT hr = d3d->ResizeTarget(width, height);
KGE_THROW_IF_FAILED(hr, "DXGI ResizeTarget failed!");
is_fullscreen_ = fullscreen;
hr = d3d->SetFullscreenState(fullscreen);
KGE_THROW_IF_FAILED(hr, "DXGI SetFullscreenState failed!");
// Reset window style
::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
{
HRESULT hr = d3d->SetFullscreenState(fullscreen);
KGE_THROW_IF_FAILED(hr, "DXGI SetFullscreenState failed!");
// Adjust the rect of client area
RECT rc = { 0, 0, LONG(width), LONG(height) };
::AdjustWindowRect(&rc, GetStyle(), false);
hr = d3d->ResizeTarget(width, height);
KGE_THROW_IF_FAILED(hr, "DXGI ResizeTarget failed!");
width = uint32_t(rc.right - rc.left);
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()
{
if (resolutions_.empty())
{
auto d3d = kiwano::graphics::directx::GetD3DDeviceResources();
Set<String> resolution_list;
DXGI_MODE_DESC* mode_descs = nullptr;
int mode_num = 0;
DEVMODEA dmi;
ZeroMemory(&dmi, sizeof(dmi));
dmi.dmSize = sizeof(dmi);
HRESULT hr = d3d->GetDisplaySettings(&mode_descs, &mode_num);
if (SUCCEEDED(hr))
DWORD mode_count = 0;
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 res;
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;
}
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);
}
resolution_list.insert(ss.str());
resolutions_.push_back(Resolution{ uint32_t(dmi.dmPelsWidth), uint32_t(dmi.dmPelsHeight),
uint32_t(dmi.dmDisplayFrequency) });
}
}
else
{
KGE_THROW_IF_FAILED(hr, "DXGI GetDisplaySettings failed!");
ZeroMemory(&dmi, sizeof(dmi));
}
}
return resolutions_;
@ -390,7 +417,30 @@ Vector<Resolution> WindowWin32Impl::GetResolutions()
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()
@ -658,8 +708,7 @@ LRESULT WindowWin32Impl::MessageProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA
{
if (is_fullscreen_)
{
// TODO restore to fullscreen mode
// SetResolution();
SetActive(true);
}
}
break;
@ -668,8 +717,7 @@ LRESULT WindowWin32Impl::MessageProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA
{
if (is_fullscreen_)
{
// TODO exit fullscreen mode
// ::ShowWindow(handle_, SW_MINIMIZE);
SetActive(false);
}
}
break;
@ -695,18 +743,6 @@ LRESULT WindowWin32Impl::MessageProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA
case WM_DISPLAYCHANGE:
{
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;

View File

@ -68,7 +68,7 @@ inline bool SdkLayersAvailable()
struct D3D10DeviceResources : public ID3D10DeviceResources
{
public:
HRESULT Initialize(HWND hwnd) override;
HRESULT Initialize(HWND hwnd, Size logical_size) override;
HRESULT Present(bool vsync) override;
@ -138,14 +138,10 @@ D3D10DeviceResources::~D3D10DeviceResources()
DiscardResources();
}
HRESULT D3D10DeviceResources::Initialize(HWND hwnd)
HRESULT D3D10DeviceResources::Initialize(HWND hwnd, Size logical_size)
{
RECT rc;
::GetClientRect(hwnd, &rc);
this->hwnd_ = hwnd;
this->logical_size_.x = float(rc.right - rc.left);
this->logical_size_.y = float(rc.bottom - rc.top);
this->logical_size_ = logical_size;
HRESULT hr = this->CreateDeviceResources();

View File

@ -60,7 +60,7 @@ inline bool SdkLayersAvailable()
struct D3D11DeviceResources : public ID3D11DeviceResources
{
public:
HRESULT Initialize(HWND hwnd) override;
HRESULT Initialize(HWND hwnd, Size logical_size) override;
HRESULT Present(bool vsync) override;
@ -133,14 +133,10 @@ D3D11DeviceResources::~D3D11DeviceResources()
DiscardResources();
}
HRESULT D3D11DeviceResources::Initialize(HWND hwnd)
HRESULT D3D11DeviceResources::Initialize(HWND hwnd, Size logical_size)
{
RECT rc;
::GetClientRect(hwnd, &rc);
this->hwnd_ = hwnd;
this->logical_size_.x = float(rc.right - rc.left);
this->logical_size_.y = float(rc.bottom - rc.top);
this->logical_size_ = logical_size;
HRESULT hr = this->CreateDeviceResources();

View File

@ -32,7 +32,7 @@ MIDL_INTERFACE("fb99fa64-d9cf-4e0e-9c75-90514797b01d")
ID3DDeviceResourcesBase : public IUnknown
{
public:
virtual HRESULT Initialize(HWND hwnd) = 0;
virtual HRESULT Initialize(HWND hwnd, Size logical_size) = 0;
virtual HRESULT Present(bool vsync) = 0;

View File

@ -55,17 +55,18 @@ void RendererImpl::MakeContextForWindow(WindowPtr window)
KGE_THROW_IF_FAILED(::CoInitialize(nullptr), "CoInitialize failed");
HWND target_window = window->GetHandle();
output_size_ = window->GetSize();
HWND target_window = window->GetHandle();
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
if (SUCCEEDED(hr))
{
auto d3d_res = graphics::directx::GetD3DDeviceResources();
hr = d3d_res->Initialize(target_window);
hr = d3d_res->Initialize(target_window, output_size_);
if (FAILED(hr))
{
d3d_res->DiscardResources();

View File

@ -74,11 +74,11 @@ public:
/// @brief 헌왕뻠닸
void Clear();
virtual ~TextureCache();
private:
TextureCache();
virtual ~TextureCache();
private:
using TextureMap = UnorderedMap<size_t, TexturePtr>;
TextureMap texture_cache_;

View File

@ -126,11 +126,11 @@ public:
/// @note 此操作会重定向输出流到标准输出流
void ShowConsole(bool show);
~Logger();
private:
Logger();
~Logger();
void Prepare(Level level, StringStream& sstream);
void Output(Level level, StringStream& sstream);

View File

@ -88,11 +88,11 @@ public:
/// @brief 清空所有资源
void Clear();
virtual ~ResourceCache();
private:
ResourceCache();
virtual ~ResourceCache();
private:
UnorderedMap<String, ObjectBasePtr> object_cache_;
};