[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 // Setup Dear ImGui style
ImGui::StyleColorsDark(); ImGui::StyleColorsDark();
window_ = Application::GetInstance().GetMainWindow(); window_ = Application::GetInstance().GetWindow();
// Setup Platform/Renderer bindings // Setup Platform/Renderer bindings
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)

View File

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

View File

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

View File

@ -27,6 +27,26 @@ namespace memory
MemoryAllocator* current_allocator_ = nullptr; 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() MemoryAllocator* GetAllocator()
{ {
if (!current_allocator_) if (!current_allocator_)
@ -42,21 +62,5 @@ void SetAllocator(MemoryAllocator* allocator)
current_allocator_ = 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 memory
} // namespace kiwano } // namespace kiwano

View File

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

View File

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

View File

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

View File

@ -20,24 +20,25 @@
#include <kiwano/utils/Logger.h> #include <kiwano/utils/Logger.h>
#include <kiwano/platform/Runner.h> #include <kiwano/platform/Runner.h>
#include <kiwano/platform/Input.h>
#include <kiwano/platform/Application.h> #include <kiwano/platform/Application.h>
#include <kiwano/render/Renderer.h>
#define KGE_MAX_SKIP_FRAMES 10 #include <kiwano/base/Director.h>
namespace kiwano namespace kiwano
{ {
RunnerPtr Runner::Create(WindowPtr main_window) RunnerPtr Runner::Create(Settings settings)
{ {
RunnerPtr ptr = memory::New<Runner>(); RunnerPtr ptr = memory::New<Runner>();
if (ptr) if (ptr)
{ {
ptr->SetMainWindow(main_window); ptr->SetSettings(settings);
} }
return ptr; 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 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_ready = on_ready;
ptr->on_destroy = on_destroy; ptr->on_destroy = on_destroy;
ptr->SetMainWindow(main_window); ptr->SetSettings(settings);
} }
return ptr; return ptr;
} }
@ -72,6 +73,36 @@ Runner::Runner() {}
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) bool Runner::MainLoop(Duration dt)
{ {
if (!main_window_) if (!main_window_)
@ -79,7 +110,7 @@ bool Runner::MainLoop(Duration dt)
if (main_window_->ShouldClose()) if (main_window_->ShouldClose())
{ {
if (this->OnClosing()) if (this->OnClose())
return false; return false;
main_window_->SetShouldClose(false); main_window_->SetShouldClose(false);

View File

@ -22,6 +22,8 @@
#include <kiwano/core/Common.h> #include <kiwano/core/Common.h>
#include <kiwano/core/Time.h> #include <kiwano/core/Time.h>
#include <kiwano/platform/Window.h> #include <kiwano/platform/Window.h>
#include <kiwano/render/Color.h>
#include <kiwano/render/Texture.h>
namespace kiwano namespace kiwano
{ {
@ -30,26 +32,52 @@ class Application;
KGE_DECLARE_SMART_PTR(Runner); 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 * \~chinese
* @brief * @brief
*/ */
class KGE_API Runner : public ObjectBase class KGE_API Runner : public ObjectBase
{ {
friend class Application;
public: public:
/// \~chinese /// \~chinese
/// @brief 创建程序运行器 /// @brief 创建程序运行器
/// @param main_window 主窗口 /// @param main_window 主窗口
static RunnerPtr Create(WindowPtr main_window); static RunnerPtr Create(Settings settings);
/// \~chinese /// \~chinese
/// @brief 创建程序运行器 /// @brief 创建程序运行器
/// @param main_window 主窗口 /// @param main_window 主窗口
/// @param on_ready 应用程序初始化完成后执行的回调函数 /// @param on_ready 应用程序初始化完成后执行的回调函数
/// @param on_destroy 应用程序销毁时执行的回调函数 /// @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(); Runner();
@ -69,7 +97,7 @@ public:
/// @brief 应用程序关闭处理 /// @brief 应用程序关闭处理
/// @details 重载该函数以处理用户关闭应用程序时的行为,如保存用户数据等 /// @details 重载该函数以处理用户关闭应用程序时的行为,如保存用户数据等
/// @return 返回true允许用户关闭程序否则阻止程序关闭 /// @return 返回true允许用户关闭程序否则阻止程序关闭
virtual bool OnClosing(); virtual bool OnClose();
/// \~chinese /// \~chinese
/// @brief 应用程序主循环 /// @brief 应用程序主循环
@ -79,14 +107,29 @@ public:
virtual bool MainLoop(Duration dt); virtual bool MainLoop(Duration dt);
/// \~chinese /// \~chinese
/// @brief »ñÈ¡Ö÷´°¿Ú /// @brief 获取窗口
WindowPtr GetMainWindow() const; WindowPtr GetWindow() const;
/// \~chinese /// \~chinese
/// @brief ÉèÖÃÖ÷´°¿Ú /// @brief 设置窗口
void SetMainWindow(WindowPtr window); void SetWindow(WindowPtr window);
/// \~chinese
/// @brief 获取设置
Settings GetSettings() const;
protected:
/// \~chinese
/// @brief 修改设置
void SetSettings(Settings settings);
private: private:
friend class Application;
void InitSettings();
private:
Settings settings_;
WindowPtr main_window_; WindowPtr main_window_;
}; };
@ -94,19 +137,29 @@ inline void Runner::OnReady() {}
inline void Runner::OnDestroy() {} inline void Runner::OnDestroy() {}
inline bool Runner::OnClosing() inline bool Runner::OnClose()
{ {
return true; return true;
} }
inline WindowPtr Runner::GetMainWindow() const inline WindowPtr Runner::GetWindow() const
{ {
return main_window_; return main_window_;
} }
inline void Runner::SetMainWindow(WindowPtr window) inline void Runner::SetWindow(WindowPtr window)
{ {
main_window_ = window; main_window_ = window;
} }
inline Settings Runner::GetSettings() const
{
return settings_;
}
inline void Runner::SetSettings(Settings settings)
{
settings_ = settings;
}
} // namespace kiwano } // namespace kiwano

View File

@ -269,21 +269,6 @@ void WindowWin32Impl::Init(const String& title, uint32_t width, uint32_t height,
::ShowWindow(handle_, SW_SHOWNORMAL); ::ShowWindow(handle_, SW_SHOWNORMAL);
::UpdateWindow(handle_); ::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() void WindowWin32Impl::PumpEvents()

View File

@ -58,11 +58,41 @@ void RendererImpl::MakeContextForWindow(WindowPtr window)
HWND target_window = window->GetHandle(); HWND target_window = window->GetHandle();
output_size_ = window->GetSize(); output_size_ = window->GetSize();
d2d_res_ = graphics::directx::GetD2DDeviceResources();
d3d_res_ = graphics::directx::GetD3DDeviceResources();
HRESULT hr = target_window ? S_OK : E_FAIL; 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 // Initialize other device resources
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
@ -114,15 +144,23 @@ void RendererImpl::Destroy()
{ {
KGE_SYS_LOG("Destroying device resources"); KGE_SYS_LOG("Destroying device resources");
d2d_res_->GetDWriteFactory()->UnregisterFontFileLoader(res_font_file_loader_.Get()); if (d2d_res_)
res_font_file_loader_.Reset(); {
d2d_res_->GetDWriteFactory()->UnregisterFontFileLoader(res_font_file_loader_.Get());
res_font_file_loader_.Reset();
d2d_res_->GetDWriteFactory()->UnregisterFontCollectionLoader(res_font_collection_loader_.Get()); d2d_res_->GetDWriteFactory()->UnregisterFontCollectionLoader(res_font_collection_loader_.Get());
res_font_collection_loader_.Reset(); res_font_collection_loader_.Reset();
render_ctx_.Reset(); render_ctx_.Reset();
d2d_res_.Reset(); d2d_res_->DiscardResources();
d3d_res_.Reset(); }
if (d3d_res_)
{
d3d_res_->DiscardResources();
d3d_res_.Reset();
}
::CoUninitialize(); ::CoUninitialize();
} }

View File

@ -79,13 +79,13 @@ public:
void Resize(uint32_t width, uint32_t height) override; void Resize(uint32_t width, uint32_t height) override;
protected:
RendererImpl();
void MakeContextForWindow(WindowPtr window) override; void MakeContextForWindow(WindowPtr window) override;
void Destroy() override; void Destroy() override;
protected:
RendererImpl();
private: private:
using ID2DDeviceResources = kiwano::graphics::directx::ID2DDeviceResources; using ID2DDeviceResources = kiwano::graphics::directx::ID2DDeviceResources;
using ID3DDeviceResources = kiwano::graphics::directx::ID3DDeviceResources; 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() void Renderer::BeginDraw()
{ {
KGE_ASSERT(render_ctx_); KGE_ASSERT(render_ctx_);

View File

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

View File

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

View File

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