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

Merge develop branch
This commit is contained in:
Haibo 2020-05-31 22:36:33 +08:00 committed by GitHub
commit a8c13b49c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 386 additions and 176 deletions

View File

@ -28,7 +28,7 @@ void ImGuiModule::SetupModule()
// Setup Dear ImGui style
ImGui::StyleColorsDark();
window_ = Application::GetInstance().GetMainWindow();
window_ = Application::GetInstance().GetWindow();
// Setup Platform/Renderer bindings
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)

View File

@ -26,7 +26,7 @@ namespace kiwano
CanvasPtr Canvas::Create(const Size& size)
{
void* mem = memory::Alloc<Canvas>();
void* mem = memory::Alloc(sizeof(Canvas));
CanvasPtr ptr = ::new (mem) Canvas;
if (ptr)
{

View File

@ -62,14 +62,14 @@ void Button::SetStatus(Status status)
if (status == Status::Normal)
{
Application::GetInstance().GetMainWindow()->SetCursor(CursorType::Arrow);
Application::GetInstance().GetWindow()->SetCursor(CursorType::Arrow);
if (mouse_out_callback_)
mouse_out_callback_(this, GetBoundActor());
}
else if (status == Status::Hover)
{
Application::GetInstance().GetMainWindow()->SetCursor(CursorType::Hand);
Application::GetInstance().GetWindow()->SetCursor(CursorType::Hand);
if (old_status != Status::Pressed)
{

View File

@ -27,6 +27,26 @@ namespace memory
MemoryAllocator* current_allocator_ = nullptr;
MemoryAllocator* GetGlobalAllocator()
{
class KGE_API GlobalAllocator : public MemoryAllocator
{
public:
virtual void* Alloc(size_t size) override
{
return ::operator new(size);
}
virtual void Free(void* ptr, size_t size) override
{
::operator delete(ptr, size);
}
};
static GlobalAllocator global_allocator;
return &global_allocator;
}
MemoryAllocator* GetAllocator()
{
if (!current_allocator_)
@ -42,21 +62,5 @@ void SetAllocator(MemoryAllocator* allocator)
current_allocator_ = allocator;
}
GlobalAllocator* GetGlobalAllocator()
{
static GlobalAllocator global_allocator;
return &global_allocator;
}
void* GlobalAllocator::Alloc(size_t size)
{
return ::malloc(size);
}
void GlobalAllocator::Free(void* ptr)
{
::free(ptr);
}
} // namespace memory
} // namespace kiwano

View File

@ -19,8 +19,9 @@
// THE SOFTWARE.
#pragma once
#include <utility>
#include <type_traits>
#include <utility> // std::forward
#include <limits> // std::numeric_limits
#include <memory> // std::addressof
#include <kiwano/macros.h>
namespace kiwano
@ -39,7 +40,7 @@ public:
/// \~chinese
/// @brief 释放内存
virtual void Free(void* ptr) = 0;
virtual void Free(void* ptr, size_t size) = 0;
};
/// \~chinese
@ -52,30 +53,32 @@ void SetAllocator(MemoryAllocator* allocator);
/// \~chinese
/// @brief 使用当前内存分配器分配内存
template <typename _Ty>
inline void* Alloc()
inline void* Alloc(size_t size)
{
return memory::GetAllocator()->Alloc(sizeof(_Ty));
return memory::GetAllocator()->Alloc(size);
}
/// \~chinese
/// @brief 使用当前内存分配器释放内存
inline void Free(void* ptr)
inline void Free(void* ptr, size_t size)
{
return memory::GetAllocator()->Free(ptr);
memory::GetAllocator()->Free(ptr, size);
}
/// \~chinese
/// @brief 使用当前内存分配器创建对象
template <typename _Ty>
inline _Ty* New()
/// @brief 构造对象
template <typename _Ty, typename... _Args>
inline _Ty* Construct(void* ptr, _Args&&... args)
{
void* ptr = memory::Alloc<_Ty>();
if (ptr)
{
return ::new (ptr) _Ty;
}
return nullptr;
return ::new (ptr) _Ty(std::forward<_Args>(args)...);
}
/// \~chinese
/// @brief 销毁对象
template <typename _Ty, typename... _Args>
inline void Destroy(_Ty* ptr)
{
ptr->~_Ty();
}
/// \~chinese
@ -83,10 +86,10 @@ inline _Ty* New()
template <typename _Ty, typename... _Args>
inline _Ty* New(_Args&&... args)
{
void* ptr = memory::Alloc<_Ty>();
void* ptr = memory::Alloc(sizeof(_Ty));
if (ptr)
{
return ::new (ptr) _Ty(std::forward<_Args>(args)...);
return memory::Construct<_Ty>(ptr, std::forward<_Args>(args)...);
}
return nullptr;
}
@ -98,28 +101,119 @@ inline void Delete(_Ty* ptr)
{
if (ptr)
{
ptr->~_Ty();
memory::Free(ptr);
memory::Destroy<_Ty>(ptr);
memory::Free(ptr, sizeof(_Ty));
}
}
/// \~chinese
/// @brief 全局内存分配器使用malloc和free分配内存
class KGE_API GlobalAllocator : public MemoryAllocator
/// @brief 分配器
template <typename _Ty>
class Allocator
{
public:
/// \~chinese
/// @brief 申请内存
virtual void* Alloc(size_t size) override;
typedef _Ty value_type;
typedef _Ty* pointer;
typedef const _Ty* const_pointer;
typedef _Ty& reference;
typedef const _Ty& const_reference;
/// \~chinese
/// @brief 释放内存
virtual void Free(void* ptr) override;
using size_type = size_t;
using difference_type = ptrdiff_t;
template <class _Other>
struct rebind
{
using other = Allocator<_Other>;
};
Allocator() noexcept {}
Allocator(const Allocator&) noexcept = default;
template <class _Other>
Allocator(const Allocator<_Other>&) noexcept
{
}
inline _Ty* allocate(size_t count)
{
if (count > 0)
{
return static_cast<_Ty*>(memory::Alloc(sizeof(_Ty) * count));
}
return nullptr;
}
inline void* allocate(size_t count, const void*)
{
return allocate(count);
}
inline void deallocate(void* ptr, size_t count)
{
memory::Free(ptr, sizeof(_Ty) * count);
}
template <typename _UTy, typename... _Args>
inline void construct(_UTy* ptr, _Args&&... args)
{
memory::Construct<_UTy>(ptr, std::forward<_Args>(args)...);
}
template <typename _UTy>
inline void destroy(_UTy* ptr)
{
memory::Destroy<_UTy>(ptr);
}
size_t max_size() const noexcept
{
return std::numeric_limits<size_t>::max() / sizeof(_Ty);
}
_Ty* address(_Ty& val) const noexcept
{
return std::addressof(val);
}
const _Ty* address(const _Ty& val) const noexcept
{
return std::addressof(val);
}
};
/// \~chinese
/// @brief 获取全局内存分配器
GlobalAllocator* GetGlobalAllocator();
// Allocator<void>
template <>
class Allocator<void>
{
public:
using value_type = void;
typedef void* pointer;
typedef const void* const_pointer;
using size_type = size_t;
using difference_type = ptrdiff_t;
template <class _Other>
struct rebind
{
using other = Allocator<_Other>;
};
};
template <class _Ty, class _Other>
bool operator==(const Allocator<_Ty>&, const Allocator<_Other>&) noexcept
{
return true;
}
template <class _Ty, class _Other>
bool operator!=(const Allocator<_Ty>&, const Allocator<_Other>&) noexcept
{
return false;
}
} // namespace memory
} // namespace kiwano

View File

@ -19,9 +19,8 @@
// THE SOFTWARE.
#include <kiwano/platform/Application.h>
#include <kiwano/platform/Input.h>
#include <kiwano/base/Director.h>
#include <kiwano/utils/Logger.h>
#include <kiwano/base/Director.h>
#include <kiwano/render/Renderer.h>
#include <kiwano/render/TextureCache.h>
#include <kiwano/utils/ResourceCache.h>
@ -39,9 +38,6 @@ Application::Application()
, is_paused_(false)
, time_scale_(1.f)
{
Use(Renderer::GetInstance());
Use(Input::GetInstance());
Use(Director::GetInstance());
}
Application::~Application()
@ -49,25 +45,22 @@ Application::~Application()
this->Destroy();
}
void Application::Run(RunnerPtr runner, bool debug)
void Application::Run(RunnerPtr runner)
{
KGE_ASSERT(runner);
runner_ = runner;
running_ = true;
is_paused_ = false;
// Initialize runner
runner->InitSettings();
// Setup all modules
for (auto c : modules_)
{
c->SetupModule();
}
if (debug)
{
Director::GetInstance().ShowDebugInfo(true);
Renderer::GetInstance().GetContext().SetCollectingStatus(true);
}
// Everything is ready
runner->OnReady();
@ -128,16 +121,19 @@ void Application::Destroy()
runner_ = nullptr;
}
// Clear all resources
// Clear user resources
Director::GetInstance().ClearStages();
ResourceCache::GetInstance().Clear();
TextureCache::GetInstance().Clear();
for (auto iter = modules_.rbegin(); iter != modules_.rend(); ++iter)
{
(*iter)->DestroyModule();
}
modules_.clear();
// Clear device resources
TextureCache::GetInstance().Clear();
Renderer::GetInstance().Destroy();
}
void Application::Use(Module& module)

View File

@ -58,7 +58,7 @@ public:
* @param debug
* @note
*/
void Run(RunnerPtr runner, bool debug = false);
void Run(RunnerPtr runner);
/**
* \~chinese
@ -99,9 +99,9 @@ public:
/**
* \~chinese
* @brief »ñÈ¡Ö÷´°¿Ú
* @brief »ñÈ¡´°¿Ú
*/
WindowPtr GetMainWindow() const;
WindowPtr GetWindow() const;
/**
* \~chinese
@ -183,10 +183,10 @@ inline RunnerPtr Application::GetRunner() const
return runner_;
}
inline WindowPtr Application::GetMainWindow() const
inline WindowPtr Application::GetWindow() const
{
KGE_ASSERT(runner_);
return runner_->GetMainWindow();
return runner_->GetWindow();
}
inline TickerPtr Application::GetFrameTicker() const

View File

@ -20,24 +20,25 @@
#include <kiwano/utils/Logger.h>
#include <kiwano/platform/Runner.h>
#include <kiwano/platform/Input.h>
#include <kiwano/platform/Application.h>
#define KGE_MAX_SKIP_FRAMES 10
#include <kiwano/render/Renderer.h>
#include <kiwano/base/Director.h>
namespace kiwano
{
RunnerPtr Runner::Create(WindowPtr main_window)
RunnerPtr Runner::Create(Settings settings)
{
RunnerPtr ptr = memory::New<Runner>();
if (ptr)
{
ptr->SetMainWindow(main_window);
ptr->SetSettings(settings);
}
return ptr;
}
RunnerPtr Runner::Create(WindowPtr main_window, Function<void()> on_ready, Function<void()> on_destroy)
RunnerPtr Runner::Create(Settings settings, Function<void()> on_ready, Function<void()> on_destroy)
{
class CallbackRunner : public Runner
{
@ -63,7 +64,7 @@ RunnerPtr Runner::Create(WindowPtr main_window, Function<void()> on_ready, Funct
{
ptr->on_ready = on_ready;
ptr->on_destroy = on_destroy;
ptr->SetMainWindow(main_window);
ptr->SetSettings(settings);
}
return ptr;
}
@ -72,6 +73,36 @@ Runner::Runner() {}
Runner::~Runner() {}
void Runner::InitSettings()
{
if (settings_.debug_mode)
{
// Show console window before creating main window
Logger::GetInstance().ShowConsole(true);
}
// Create game window
WindowPtr window =
Window::Create(settings_.title, settings_.width, settings_.height, settings_.icon, settings_.resizable);
SetWindow(window);
// Update renderer settings
Renderer::GetInstance().MakeContextForWindow(window);
Renderer::GetInstance().SetClearColor(settings_.bg_color);
Renderer::GetInstance().SetVSyncEnabled(settings_.vsync_enabled);
// Use defaut modules
Application::GetInstance().Use(Input::GetInstance());
Application::GetInstance().Use(Director::GetInstance());
// Enable debug mode
if (settings_.debug_mode)
{
Director::GetInstance().ShowDebugInfo(true);
Renderer::GetInstance().GetContext().SetCollectingStatus(true);
}
}
bool Runner::MainLoop(Duration dt)
{
if (!main_window_)
@ -79,7 +110,7 @@ bool Runner::MainLoop(Duration dt)
if (main_window_->ShouldClose())
{
if (this->OnClosing())
if (this->OnClose())
return false;
main_window_->SetShouldClose(false);

View File

@ -22,6 +22,8 @@
#include <kiwano/core/Common.h>
#include <kiwano/core/Time.h>
#include <kiwano/platform/Window.h>
#include <kiwano/render/Color.h>
#include <kiwano/render/Texture.h>
namespace kiwano
{
@ -30,26 +32,52 @@ class Application;
KGE_DECLARE_SMART_PTR(Runner);
/**
* \~chinese
* @brief
*/
struct Settings
{
uint32_t width; ///< 窗口宽度
uint32_t height; ///< 窗口高度
String title; ///< 窗口标题
uint32_t icon; ///< 窗口图标
bool resizable; ///< 窗口大小可调整
Color bg_color; ///< 窗口背景色
bool vsync_enabled; ///< 垂直同步
bool debug_mode; ///< 调试模式
Settings()
: width(800)
, height(600)
, title("Kiwano")
, icon()
, resizable(false)
, bg_color(Color::Black)
, vsync_enabled(true)
, debug_mode(false)
{
}
};
/**
* \~chinese
* @brief
*/
class KGE_API Runner : public ObjectBase
{
friend class Application;
public:
/// \~chinese
/// @brief 创建程序运行器
/// @param main_window 主窗口
static RunnerPtr Create(WindowPtr main_window);
static RunnerPtr Create(Settings settings);
/// \~chinese
/// @brief 创建程序运行器
/// @param main_window 主窗口
/// @param on_ready 应用程序初始化完成后执行的回调函数
/// @param on_destroy 应用程序销毁时执行的回调函数
static RunnerPtr Create(WindowPtr main_window, Function<void()> on_ready, Function<void()> on_destroy = nullptr);
static RunnerPtr Create(Settings settings, Function<void()> on_ready, Function<void()> on_destroy = nullptr);
Runner();
@ -69,7 +97,7 @@ public:
/// @brief 应用程序关闭处理
/// @details 重载该函数以处理用户关闭应用程序时的行为,如保存用户数据等
/// @return 返回true允许用户关闭程序否则阻止程序关闭
virtual bool OnClosing();
virtual bool OnClose();
/// \~chinese
/// @brief 应用程序主循环
@ -79,14 +107,29 @@ public:
virtual bool MainLoop(Duration dt);
/// \~chinese
/// @brief »ñÈ¡Ö÷´°¿Ú
WindowPtr GetMainWindow() const;
/// @brief 获取窗口
WindowPtr GetWindow() const;
/// \~chinese
/// @brief ÉèÖÃÖ÷´°¿Ú
void SetMainWindow(WindowPtr window);
/// @brief 设置窗口
void SetWindow(WindowPtr window);
/// \~chinese
/// @brief 获取设置
Settings GetSettings() const;
protected:
/// \~chinese
/// @brief 修改设置
void SetSettings(Settings settings);
private:
friend class Application;
void InitSettings();
private:
Settings settings_;
WindowPtr main_window_;
};
@ -94,19 +137,29 @@ inline void Runner::OnReady() {}
inline void Runner::OnDestroy() {}
inline bool Runner::OnClosing()
inline bool Runner::OnClose()
{
return true;
}
inline WindowPtr Runner::GetMainWindow() const
inline WindowPtr Runner::GetWindow() const
{
return main_window_;
}
inline void Runner::SetMainWindow(WindowPtr window)
inline void Runner::SetWindow(WindowPtr window)
{
main_window_ = window;
}
inline Settings Runner::GetSettings() const
{
return settings_;
}
inline void Runner::SetSettings(Settings settings)
{
settings_ = settings;
}
} // namespace kiwano

View File

@ -269,21 +269,6 @@ void WindowWin32Impl::Init(const String& title, uint32_t width, uint32_t height,
::ShowWindow(handle_, SW_SHOWNORMAL);
::UpdateWindow(handle_);
// Initialize Direct3D resources
auto d3d_res = graphics::directx::GetD3DDeviceResources();
HRESULT hr = d3d_res->Initialize(handle_);
// Initialize Direct2D resources
if (SUCCEEDED(hr))
{
auto d2d_res = graphics::directx::GetD2DDeviceResources();
hr = d2d_res->Initialize(d3d_res->GetDXGIDevice(), d3d_res->GetDXGISwapChain());
}
KGE_THROW_IF_FAILED(hr, "Create DirectX resources failed");
}
void WindowWin32Impl::PumpEvents()

View File

@ -58,11 +58,41 @@ void RendererImpl::MakeContextForWindow(WindowPtr window)
HWND target_window = window->GetHandle();
output_size_ = window->GetSize();
d2d_res_ = graphics::directx::GetD2DDeviceResources();
d3d_res_ = graphics::directx::GetD3DDeviceResources();
HRESULT hr = target_window ? S_OK : E_FAIL;
// Initialize Direct3D resources
if (SUCCEEDED(hr))
{
auto d3d_res = graphics::directx::GetD3DDeviceResources();
hr = d3d_res->Initialize(target_window);
if (FAILED(hr))
{
d3d_res->DiscardResources();
}
else
{
d3d_res_ = d3d_res;
}
}
// Initialize Direct2D resources
if (SUCCEEDED(hr))
{
auto d2d_res = graphics::directx::GetD2DDeviceResources();
hr = d2d_res->Initialize(d3d_res_->GetDXGIDevice(), d3d_res_->GetDXGISwapChain());
if (FAILED(hr))
{
d2d_res->DiscardResources();
}
else
{
d2d_res_ = d2d_res;
}
}
// Initialize other device resources
if (SUCCEEDED(hr))
{
@ -114,6 +144,8 @@ void RendererImpl::Destroy()
{
KGE_SYS_LOG("Destroying device resources");
if (d2d_res_)
{
d2d_res_->GetDWriteFactory()->UnregisterFontFileLoader(res_font_file_loader_.Get());
res_font_file_loader_.Reset();
@ -121,8 +153,14 @@ void RendererImpl::Destroy()
res_font_collection_loader_.Reset();
render_ctx_.Reset();
d2d_res_.Reset();
d2d_res_->DiscardResources();
}
if (d3d_res_)
{
d3d_res_->DiscardResources();
d3d_res_.Reset();
}
::CoUninitialize();
}

View File

@ -79,13 +79,13 @@ public:
void Resize(uint32_t width, uint32_t height) override;
protected:
RendererImpl();
void MakeContextForWindow(WindowPtr window) override;
void Destroy() override;
protected:
RendererImpl();
private:
using ID2DDeviceResources = kiwano::graphics::directx::ID2DDeviceResources;
using ID3DDeviceResources = kiwano::graphics::directx::ID3DDeviceResources;

View File

@ -31,22 +31,6 @@ Renderer::Renderer()
{
}
void Renderer::SetupModule()
{
WindowPtr window = Application::GetInstance().GetMainWindow();
MakeContextForWindow(window);
}
void Renderer::DestroyModule()
{
Destroy();
}
void Renderer::HandleEvent(Event* evt)
{
// DO NOTHING
}
void Renderer::BeginDraw()
{
KGE_ASSERT(render_ctx_);

View File

@ -44,7 +44,7 @@ namespace kiwano
* \~chinese
* @brief
*/
class KGE_API Renderer : public EventModule
class KGE_API Renderer : public Noncopyable
{
public:
/// \~chinese
@ -235,20 +235,17 @@ public:
/// @throw kiwano::SystemError 呈现失败时抛出
virtual void Present() = 0;
public:
void SetupModule() override;
/// \~chinese
/// @brief 为窗口创建渲染上下文
virtual void MakeContextForWindow(WindowPtr window) = 0;
void DestroyModule() override;
void HandleEvent(Event* evt) override;
/// \~chinese
/// @brief 销毁渲染器资源
virtual void Destroy() = 0;
protected:
Renderer();
virtual void MakeContextForWindow(WindowPtr window) = 0;
virtual void Destroy() = 0;
protected:
bool vsync_;
Color clear_color_;

View File

@ -39,7 +39,7 @@ StringView Trim(StringView str)
while (std::isspace(str[end - 1]))
--end;
if (end - start)
if (end > start)
return StringView(str.Data() + start, end - start);
}
return StringView();
@ -158,6 +158,9 @@ bool ConfigIni::Save(std::ostream& os)
std::sort(keys.begin(), keys.end());
// Output to ini
std::ostream::sentry ok(os);
if (ok)
{
for (const auto& key : keys)
{
os << '[' << key << ']' << std::endl;
@ -167,7 +170,8 @@ bool ConfigIni::Save(std::ostream& os)
}
os << std::endl;
}
return false;
}
return !os.fail();
}
ConfigIni::SectionMap ConfigIni::GetSectionMap() const
@ -177,23 +181,20 @@ ConfigIni::SectionMap ConfigIni::GetSectionMap() const
ConfigIni::ValueMap ConfigIni::GetSection(const String& section) const
{
auto iter = sections_.find(section);
if (iter != sections_.end())
return iter->second;
if (HasSection(section))
{
return sections_.at(section);
}
return ValueMap();
}
String ConfigIni::GetString(const String& section_name, const String& key) const
String ConfigIni::GetString(const String& section, const String& key, const String& default_value) const
{
if (HasSection(section_name))
if (HasKey(section, key))
{
const auto& section = sections_.at(section_name);
auto iter_key = section.find(key);
if (iter_key != section.end())
return iter_key->second;
return sections_.at(section).at(key);
}
return String();
return default_value;
}
float ConfigIni::GetFloat(const String& section, const String& key, float default_value) const
@ -274,7 +275,7 @@ bool ConfigIni::HasSection(const String& section) const
return !!sections_.count(section);
}
bool ConfigIni::HasValue(const String& section, const String& key) const
bool ConfigIni::HasKey(const String& section, const String& key) const
{
if (HasSection(section))
{
@ -324,6 +325,22 @@ void ConfigIni::SetBool(const String& section, const String& key, bool value)
SetString(section, key, value ? "true" : "false");
}
void ConfigIni::DeleteSection(const String& section)
{
if (HasSection(section))
{
sections_.erase(section);
}
}
void ConfigIni::DeleteKey(const String& section, const String& key)
{
if (HasKey(section, key))
{
sections_.at(section).erase(key);
}
}
ConfigIni::ValueMap& ConfigIni::operator[](const String& section)
{
if (!HasSection(section))

View File

@ -39,7 +39,7 @@ public:
/// \~chinese
/// @brief 键值字典
typedef Map<String, String> ValueMap;
typedef UnorderedMap<String, String> ValueMap;
/// \~chinese
/// @brief Section字典
@ -65,6 +65,17 @@ public:
/// @param os 输出流
bool Save(std::ostream& os);
/// \~chinese
/// @brief 是否存在section
/// @param section section的名称
bool HasSection(const String& section) const;
/// \~chinese
/// @brief 是否存在值
/// @param section section的名称
/// @param key key的名称
bool HasKey(const String& section, const String& key) const;
/// \~chinese
/// @brief 获取所有section
SectionMap GetSectionMap() const;
@ -78,7 +89,7 @@ public:
/// @brief 获取值
/// @param section section的名称
/// @param key key的名称
String GetString(const String& section, const String& key) const;
String GetString(const String& section, const String& key, const String& default_value = String()) const;
/// \~chinese
/// @brief 获取值
@ -108,17 +119,6 @@ public:
/// @param default_value 不存在时的默认值
bool GetBool(const String& section, const String& key, bool default_value = false) const;
/// \~chinese
/// @brief 是否存在section
/// @param section section的名称
bool HasSection(const String& section) const;
/// \~chinese
/// @brief 是否存在值
/// @param section section的名称
/// @param key key的名称
bool HasValue(const String& section, const String& key) const;
/// \~chinese
/// @brief 设置所有section
/// @param sections section字典
@ -165,6 +165,17 @@ public:
/// @param value 值
void SetBool(const String& section, const String& key, bool value);
/// \~chinese
/// @brief 删除section
/// @param section section的名称
void DeleteSection(const String& section);
/// \~chinese
/// @brief 删除值
/// @param section section的名称
/// @param key key的名称
void DeleteKey(const String& section, const String& key);
ValueMap& operator[](const String& section);
const ValueMap& operator[](const String& section) const;