Add WindowImpl-Win32

This commit is contained in:
Nomango 2020-01-17 11:24:24 +08:00
parent 831c6c83e9
commit bcc92abbef
31 changed files with 872 additions and 766 deletions

View File

@ -20,6 +20,7 @@
<ClInclude Include="..\..\src\kiwano\core\event\MouseEvent.h" /> <ClInclude Include="..\..\src\kiwano\core\event\MouseEvent.h" />
<ClInclude Include="..\..\src\kiwano\core\event\WindowEvent.h" /> <ClInclude Include="..\..\src\kiwano\core\event\WindowEvent.h" />
<ClInclude Include="..\..\src\kiwano\core\Library.h" /> <ClInclude Include="..\..\src\kiwano\core\Library.h" />
<ClInclude Include="..\..\src\kiwano\core\Singleton.h" />
<ClInclude Include="..\..\src\kiwano\kiwano.h" /> <ClInclude Include="..\..\src\kiwano\kiwano.h" />
<ClInclude Include="..\..\src\kiwano\config.h" /> <ClInclude Include="..\..\src\kiwano\config.h" />
<ClInclude Include="..\..\src\kiwano\macros.h" /> <ClInclude Include="..\..\src\kiwano\macros.h" />
@ -131,6 +132,7 @@
<ClCompile Include="..\..\src\kiwano\platform\Input.cpp" /> <ClCompile Include="..\..\src\kiwano\platform\Input.cpp" />
<ClCompile Include="..\..\src\kiwano\platform\win32\libraries.cpp" /> <ClCompile Include="..\..\src\kiwano\platform\win32\libraries.cpp" />
<ClCompile Include="..\..\src\kiwano\platform\win32\StackWalker.cpp" /> <ClCompile Include="..\..\src\kiwano\platform\win32\StackWalker.cpp" />
<ClCompile Include="..\..\src\kiwano\platform\win32\WindowImpl.cpp" />
<ClCompile Include="..\..\src\kiwano\platform\Window.cpp" /> <ClCompile Include="..\..\src\kiwano\platform\Window.cpp" />
<ClCompile Include="..\..\src\kiwano\renderer\Brush.cpp" /> <ClCompile Include="..\..\src\kiwano\renderer\Brush.cpp" />
<ClCompile Include="..\..\src\kiwano\renderer\Color.cpp" /> <ClCompile Include="..\..\src\kiwano\renderer\Color.cpp" />

View File

@ -282,6 +282,9 @@
<ClInclude Include="..\..\src\kiwano\core\Director.h"> <ClInclude Include="..\..\src\kiwano\core\Director.h">
<Filter>core</Filter> <Filter>core</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\src\kiwano\core\Singleton.h">
<Filter>core</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\..\src\kiwano\2d\Canvas.cpp"> <ClCompile Include="..\..\src\kiwano\2d\Canvas.cpp">
@ -479,5 +482,8 @@
<ClCompile Include="..\..\src\kiwano\core\Director.cpp"> <ClCompile Include="..\..\src\kiwano\core\Director.cpp">
<Filter>core</Filter> <Filter>core</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\src\kiwano\platform\win32\WindowImpl.cpp">
<Filter>platform\win32</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -42,7 +42,7 @@ namespace kiwano
bool Sound::Load(String const& file_path) bool Sound::Load(String const& file_path)
{ {
if (!FileSystem::instance().IsFileExists(file_path)) if (!FileSystem::Instance().IsFileExists(file_path))
{ {
KGE_WARN(L"Media file '%s' not found", file_path.c_str()); KGE_WARN(L"Media file '%s' not found", file_path.c_str());
return false; return false;
@ -53,7 +53,7 @@ namespace kiwano
Close(); Close();
} }
String full_path = FileSystem::instance().GetFullPathForFile(file_path); String full_path = FileSystem::Instance().GetFullPathForFile(file_path);
HRESULT hr = transcoder_.LoadMediaFile(full_path); HRESULT hr = transcoder_.LoadMediaFile(full_path);
if (FAILED(hr)) if (FAILED(hr))
@ -62,7 +62,7 @@ namespace kiwano
return false; return false;
} }
if (!AudioEngine::instance().CreateSound(*this, transcoder_.GetBuffer())) if (!AudioEngine::Instance().CreateSound(*this, transcoder_.GetBuffer()))
{ {
Close(); Close();
return false; return false;
@ -86,7 +86,7 @@ namespace kiwano
return false; return false;
} }
if (!AudioEngine::instance().CreateSound(*this, transcoder_.GetBuffer())) if (!AudioEngine::Instance().CreateSound(*this, transcoder_.GetBuffer()))
{ {
Close(); Close();
return false; return false;

View File

@ -29,7 +29,7 @@ namespace kiwano
ImGui::StyleColorsDark(); ImGui::StyleColorsDark();
// Setup Platform/Renderer bindings // Setup Platform/Renderer bindings
target_window_ = Renderer::instance().GetTargetWindow(); target_window_ = Renderer::Instance().GetTargetWindow();
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
@ -54,7 +54,7 @@ namespace kiwano
io.KeyMap[ImGuiKey_Y] = KeyCode::Y; io.KeyMap[ImGuiKey_Y] = KeyCode::Y;
io.KeyMap[ImGuiKey_Z] = KeyCode::Z; io.KeyMap[ImGuiKey_Z] = KeyCode::Z;
ImGui_Impl_Init(Renderer::instance()); ImGui_Impl_Init(Renderer::Instance());
} }
void ImGuiModule::DestroyComponent() void ImGuiModule::DestroyComponent()
@ -71,10 +71,10 @@ namespace kiwano
io.DeltaTime = dt.Seconds(); io.DeltaTime = dt.Seconds();
// Read keyboard modifiers inputs // Read keyboard modifiers inputs
io.KeyCtrl = Input::instance().IsDown(KeyCode::Ctrl); io.KeyCtrl = Input::Instance().IsDown(KeyCode::Ctrl);
io.KeyShift = Input::instance().IsDown(KeyCode::Shift); io.KeyShift = Input::Instance().IsDown(KeyCode::Shift);
io.KeyAlt = Input::instance().IsDown(KeyCode::Alt); io.KeyAlt = Input::Instance().IsDown(KeyCode::Alt);
io.KeySuper = Input::instance().IsDown(KeyCode::Super); io.KeySuper = Input::Instance().IsDown(KeyCode::Super);
// io.KeysDown[], io.MousePos, io.MouseDown[], io.MouseWheel: filled by the HandleEvent function below. // io.KeysDown[], io.MousePos, io.MouseDown[], io.MouseWheel: filled by the HandleEvent function below.
// Update OS mouse position // Update OS mouse position
@ -155,7 +155,7 @@ namespace kiwano
KGE_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built!"); KGE_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built!");
// Setup display size (every frame to accommodate for window resizing) // Setup display size (every frame to accommodate for window resizing)
Size display_size = Renderer::instance().GetOutputSize(); Size display_size = Renderer::Instance().GetOutputSize();
io.DisplaySize = ImVec2(display_size.x, display_size.y); io.DisplaySize = ImVec2(display_size.x, display_size.y);
ImGui::NewFrame(); ImGui::NewFrame();
@ -180,7 +180,7 @@ namespace kiwano
::SetCursorPos(pos.x, pos.y); ::SetCursorPos(pos.x, pos.y);
} }
Point pos = Input::instance().GetMousePos(); Point pos = Input::Instance().GetMousePos();
io.MousePos = ImVec2(pos.x, pos.y); io.MousePos = ImVec2(pos.x, pos.y);
} }
@ -202,7 +202,7 @@ namespace kiwano
case ImGuiMouseCursor_Hand: cursor = CursorType::Hand; break; case ImGuiMouseCursor_Hand: cursor = CursorType::Hand; break;
} }
Window::instance().SetCursor(cursor); Window::Instance().SetCursor(cursor);
} }
} }

View File

@ -95,14 +95,14 @@ namespace kiwano
if (status == Status::Normal) if (status == Status::Normal)
{ {
Window::instance().SetCursor(CursorType::Arrow); Window::Instance().SetCursor(CursorType::Arrow);
if (mouse_out_callback_) if (mouse_out_callback_)
mouse_out_callback_(this); mouse_out_callback_(this);
} }
else if (status == Status::Hover) else if (status == Status::Hover)
{ {
Window::instance().SetCursor(CursorType::Hand); Window::Instance().SetCursor(CursorType::Hand);
if (old_status == Status::Pressed) if (old_status == Status::Pressed)
{ {

View File

@ -318,7 +318,7 @@ namespace kiwano
{ {
if (!ctx_) if (!ctx_)
{ {
Renderer::instance().CreateTextureRenderTarget(ctx_); Renderer::Instance().CreateTextureRenderTarget(ctx_);
} }
if (!stroke_brush_) if (!stroke_brush_)

View File

@ -106,9 +106,9 @@ namespace kiwano
} }
#endif #endif
ss << "Render: " << Renderer::instance().GetStatus().duration.Milliseconds() << "ms" << std::endl; ss << "Render: " << Renderer::Instance().GetStatus().duration.Milliseconds() << "ms" << std::endl;
ss << "Primitives / sec: " << std::fixed << Renderer::instance().GetStatus().primitives * frame_time_.size() << std::endl; ss << "Primitives / sec: " << std::fixed << Renderer::Instance().GetStatus().primitives * frame_time_.size() << std::endl;
ss << "Memory: "; ss << "Memory: ";
{ {

View File

@ -29,7 +29,7 @@ namespace kiwano
bool Frame::Load(String const& file_path) bool Frame::Load(String const& file_path)
{ {
TexturePtr texture = TextureCache::instance().AddOrGetTexture(file_path); TexturePtr texture = TextureCache::Instance().AddOrGetTexture(file_path);
if (texture->IsValid()) if (texture->IsValid())
{ {
SetTexture(texture); SetTexture(texture);
@ -40,7 +40,7 @@ namespace kiwano
bool Frame::Load(Resource const& res) bool Frame::Load(Resource const& res)
{ {
TexturePtr texture = TextureCache::instance().AddOrGetTexture(res); TexturePtr texture = TextureCache::Instance().AddOrGetTexture(res);
if (texture->IsValid()) if (texture->IsValid())
{ {
SetTexture(texture); SetTexture(texture);

View File

@ -34,13 +34,13 @@ namespace kiwano
bool GifSprite::Load(String const& file_path) bool GifSprite::Load(String const& file_path)
{ {
GifImagePtr image = TextureCache::instance().AddOrGetGifImage(file_path); GifImagePtr image = TextureCache::Instance().AddOrGetGifImage(file_path);
return Load(image); return Load(image);
} }
bool GifSprite::Load(Resource const& res) bool GifSprite::Load(Resource const& res)
{ {
GifImagePtr image = TextureCache::instance().AddOrGetGifImage(res); GifImagePtr image = TextureCache::Instance().AddOrGetGifImage(res);
return Load(image); return Load(image);
} }
@ -58,7 +58,7 @@ namespace kiwano
if (!frame_rt_) if (!frame_rt_)
{ {
Renderer::instance().CreateTextureRenderTarget(frame_rt_); Renderer::Instance().CreateTextureRenderTarget(frame_rt_);
} }
if (gif_->GetFramesCount() > 0) if (gif_->GetFramesCount() > 0)

View File

@ -29,7 +29,7 @@ namespace kiwano
SetStage(this); SetStage(this);
SetAnchor(Vec2{ 0, 0 }); SetAnchor(Vec2{ 0, 0 });
SetSize(Renderer::instance().GetOutputSize()); SetSize(Renderer::Instance().GetOutputSize());
} }
Stage::~Stage() Stage::~Stage()

View File

@ -60,7 +60,7 @@ namespace kiwano
out_stage_ = prev; out_stage_ = prev;
in_stage_ = next; in_stage_ = next;
window_size_ = Renderer::instance().GetOutputSize(); window_size_ = Renderer::Instance().GetOutputSize();
if (in_stage_) if (in_stage_)
{ {

View File

@ -26,52 +26,66 @@
namespace namespace
{ {
std::streambuf* cout_buffer, * cerr_buffer; std::streambuf* cin_buffer, * cout_buffer, * cerr_buffer;
std::fstream console_output, console_error; std::fstream console_input, console_output, console_error;
std::wstreambuf* wcout_buffer, * wcerr_buffer; std::wstreambuf* wcin_buffer, * wcout_buffer, * wcerr_buffer;
std::wfstream wconsole_output, wconsole_error; std::wfstream wconsole_input, wconsole_output, wconsole_error;
void RedirectStdIO() void RedirectStdIO()
{ {
cin_buffer = std::cin.rdbuf();
cout_buffer = std::cout.rdbuf(); cout_buffer = std::cout.rdbuf();
cerr_buffer = std::cerr.rdbuf(); cerr_buffer = std::cerr.rdbuf();
wcin_buffer = std::wcin.rdbuf();
wcout_buffer = std::wcout.rdbuf(); wcout_buffer = std::wcout.rdbuf();
wcerr_buffer = std::wcerr.rdbuf(); wcerr_buffer = std::wcerr.rdbuf();
console_input.open("CONIN$", std::ios::in);
console_output.open("CONOUT$", std::ios::out); console_output.open("CONOUT$", std::ios::out);
console_error.open("CONOUT$", std::ios::out); console_error.open("CONOUT$", std::ios::out);
wconsole_input.open("CONIN$", std::ios::in);
wconsole_output.open("CONOUT$", std::ios::out); wconsole_output.open("CONOUT$", std::ios::out);
wconsole_error.open("CONOUT$", std::ios::out); wconsole_error.open("CONOUT$", std::ios::out);
FILE* dummy; FILE* dummy;
freopen_s(&dummy, "CONOUT$", "w+t", stdout); freopen_s(&dummy, "CONOUT$", "w+t", stdout);
freopen_s(&dummy, "CONIN$", "r+t", stdin);
freopen_s(&dummy, "CONOUT$", "w+t", stderr); freopen_s(&dummy, "CONOUT$", "w+t", stderr);
(void)dummy; (void)dummy;
std::cin.rdbuf(console_input.rdbuf());
std::cout.rdbuf(console_output.rdbuf()); std::cout.rdbuf(console_output.rdbuf());
std::cerr.rdbuf(console_error.rdbuf()); std::cerr.rdbuf(console_error.rdbuf());
std::wcin.rdbuf(wconsole_input.rdbuf());
std::wcout.rdbuf(wconsole_output.rdbuf()); std::wcout.rdbuf(wconsole_output.rdbuf());
std::wcerr.rdbuf(wconsole_error.rdbuf()); std::wcerr.rdbuf(wconsole_error.rdbuf());
} }
void ResetStdIO() void ResetStdIO()
{ {
console_input.close();
console_output.close(); console_output.close();
console_error.close(); console_error.close();
wconsole_input.close();
wconsole_output.close(); wconsole_output.close();
wconsole_error.close(); wconsole_error.close();
std::cin.rdbuf(cin_buffer);
std::cout.rdbuf(cout_buffer); std::cout.rdbuf(cout_buffer);
std::cerr.rdbuf(cerr_buffer); std::cerr.rdbuf(cerr_buffer);
std::wcin.rdbuf(wcin_buffer);
std::wcout.rdbuf(wcout_buffer); std::wcout.rdbuf(wcout_buffer);
std::wcerr.rdbuf(wcerr_buffer); std::wcerr.rdbuf(wcerr_buffer);
fclose(stdout); fclose(stdout);
fclose(stdin);
fclose(stderr); fclose(stderr);
cin_buffer = nullptr;
cout_buffer = nullptr; cout_buffer = nullptr;
cerr_buffer = nullptr; cerr_buffer = nullptr;
wcin_buffer = nullptr;
wcout_buffer = nullptr; wcout_buffer = nullptr;
wcerr_buffer = nullptr; wcerr_buffer = nullptr;
} }

View File

@ -26,26 +26,26 @@
#ifndef KGE_SYS_LOG #ifndef KGE_SYS_LOG
# ifdef KGE_DEBUG # ifdef KGE_DEBUG
# define KGE_SYS_LOG(FORMAT, ...) ::kiwano::Logger::instance().Printf(::kiwano::Logger::Level::System, FORMAT, __VA_ARGS__) # define KGE_SYS_LOG(FORMAT, ...) ::kiwano::Logger::Instance().Printf(::kiwano::Logger::Level::System, FORMAT, __VA_ARGS__)
# else # else
# define KGE_SYS_LOG __noop # define KGE_SYS_LOG __noop
# endif # endif
#endif #endif
#ifndef KGE_WARN #ifndef KGE_WARN
# define KGE_WARN(FORMAT, ...) ::kiwano::Logger::instance().Printf(::kiwano::Logger::Level::Warning, FORMAT, __VA_ARGS__) # define KGE_WARN(FORMAT, ...) ::kiwano::Logger::Instance().Printf(::kiwano::Logger::Level::Warning, FORMAT, __VA_ARGS__)
#endif #endif
#ifndef KGE_ERROR #ifndef KGE_ERROR
# define KGE_ERROR(FORMAT, ...) ::kiwano::Logger::instance().Printf(::kiwano::Logger::Level::Error, FORMAT, __VA_ARGS__) # define KGE_ERROR(FORMAT, ...) ::kiwano::Logger::Instance().Printf(::kiwano::Logger::Level::Error, FORMAT, __VA_ARGS__)
#endif #endif
#ifndef KGE_LOG #ifndef KGE_LOG
# define KGE_LOG(...) ::kiwano::Logger::instance().Println(::kiwano::Logger::Level::Info, __VA_ARGS__) # define KGE_LOG(...) ::kiwano::Logger::Instance().Println(::kiwano::Logger::Level::Info, __VA_ARGS__)
#endif #endif
#ifndef KGE_LOGF #ifndef KGE_LOGF
# define KGE_LOGF(FORMAT, ...) ::kiwano::Logger::instance().Printf(::kiwano::Logger::Level::Info, FORMAT, __VA_ARGS__) # define KGE_LOGF(FORMAT, ...) ::kiwano::Logger::Instance().Printf(::kiwano::Logger::Level::Info, FORMAT, __VA_ARGS__)
#endif #endif
namespace kiwano namespace kiwano

View File

@ -0,0 +1,61 @@
// Copyright (c) 2016-2020 Kiwano - Nomango
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#pragma once
namespace kiwano
{
template <typename _Ty>
struct Singleton
{
protected:
Singleton() = default;
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
private:
struct ObjectCreator
{
ObjectCreator()
{
(void)Singleton<_Ty>::Instance();
}
inline void Dummy() const {}
};
static ObjectCreator creator_;
public:
using object_type = _Ty;
static inline object_type& Instance()
{
static object_type instance;
creator_.Dummy();
return instance;
}
};
template <typename _Ty>
typename Singleton<_Ty>::ObjectCreator Singleton<_Ty>::creator_;
} // namespace kiwano

View File

@ -30,6 +30,7 @@
#include <3rd-party/OuterC/oc/oc.h> #include <3rd-party/OuterC/oc/oc.h>
#include <kiwano/macros.h> #include <kiwano/macros.h>
#include <kiwano/core/Singleton.h>
namespace kiwano namespace kiwano
{ {
@ -113,11 +114,6 @@ namespace kiwano
/// @brief JSON对象容器 /// @brief JSON对象容器
using Json = oc::basic_json<Map, Vector, String, int, double, bool, std::allocator>; using Json = oc::basic_json<Map, Vector, String, int, double, bool, std::allocator>;
/// \~chinese
/// @brief 데절친겼
template <typename _Ty>
using Singleton = oc::singleton<_Ty>;
/// \~chinese /// \~chinese
/// @brief 侵入式链表容器 /// @brief 侵入式链表容器
template <typename _Ty> template <typename _Ty>

View File

@ -36,31 +36,12 @@ namespace kiwano
Queue<FunctionToPerform> functions_to_perform_; Queue<FunctionToPerform> functions_to_perform_;
} }
Config::Config(String const& title, uint32_t width, uint32_t height, uint32_t icon)
: debug(false)
{
window.title = title;
window.width = width;
window.height = height;
window.icon = icon;
}
Config::Config(WindowConfig const& wnd_config, RenderConfig const& render_config)
: debug(false)
{
window = wnd_config;
render = render_config;
}
}
namespace kiwano
{
Application::Application() Application::Application()
: time_scale_(1.f) : time_scale_(1.f)
{ {
Use(&Renderer::instance()); Use(&Renderer::Instance());
Use(&Input::instance()); Use(&Input::Instance());
Use(&Director::instance()); Use(&Director::Instance());
} }
Application::~Application() Application::~Application()
@ -68,21 +49,18 @@ namespace kiwano
Destroy(); Destroy();
} }
void Application::Run(const Config& config) void Application::Run(bool debug)
{ {
Window::instance().Init(config.window);
Renderer::instance().Init(config.render);
// Setup all components // Setup all components
for (auto c : comps_) for (auto c : comps_)
{ {
c->SetupComponent(); c->SetupComponent();
} }
if (config.debug) if (debug)
{ {
Director::instance().ShowDebugInfo(true); Director::Instance().ShowDebugInfo(true);
Renderer::instance().SetCollectingStatus(true); Renderer::Instance().SetCollectingStatus(true);
} }
// Everything is ready // Everything is ready
@ -90,7 +68,7 @@ namespace kiwano
last_update_time_ = Time::Now(); last_update_time_ = Time::Now();
Window& window = Window::instance(); Window& window = Window::Instance();
while (!window.ShouldClose()) while (!window.ShouldClose())
{ {
while (EventPtr evt = window.PollEvent()) while (EventPtr evt = window.PollEvent())
@ -105,20 +83,23 @@ namespace kiwano
void Application::Quit() void Application::Quit()
{ {
Window::instance().Destroy(); Window::Instance().Destroy();
} }
void Application::Destroy() void Application::Destroy()
{ {
// Clear all resources // Clear all resources
Director::instance().ClearStages(); Director::Instance().ClearStages();
ResourceCache::instance().Clear(); ResourceCache::Instance().Clear();
TextureCache::instance().Clear(); TextureCache::Instance().Clear();
for (auto iter = comps_.rbegin(); iter != comps_.rend(); ++iter) for (auto iter = comps_.rbegin(); iter != comps_.rend(); ++iter)
{ {
(*iter)->DestroyComponent(); (*iter)->DestroyComponent();
} }
render_comps_.clear();
update_comps_.clear();
event_comps_.clear();
comps_.clear(); comps_.clear();
} }
@ -209,7 +190,7 @@ namespace kiwano
} }
// Rendering // Rendering
Renderer& renderer = Renderer::instance(); Renderer& renderer = Renderer::Instance();
for (auto c : render_comps_) for (auto c : render_comps_)
{ {
c->OnRender(renderer); c->OnRender(renderer);

View File

@ -31,43 +31,6 @@
namespace kiwano namespace kiwano
{ {
/**
* \~chinese
* @brief
* @details Kiwano
*/
struct Config
{
WindowConfig window; ///< 窗口配置
RenderConfig render; ///< 渲染配置
bool debug; ///< 启用调试模式
/**
* \~chinese
* @param title
* @param width
* @param height
* @param icon ID
*/
Config(
String const& title = L"Kiwano Game",
uint32_t width = 640,
uint32_t height = 480,
uint32_t icon = 0
);
/**
* \~chinese
* @param wnd_config
* @param render_config
*/
Config(
WindowConfig const& wnd_config,
RenderConfig const& render_config = RenderConfig()
);
};
/** /**
* \~chinese * \~chinese
* @brief * @brief
@ -85,23 +48,23 @@ namespace kiwano
* @brief * @brief
* @details * @details
*/ */
virtual void OnReady() {} virtual void OnReady();
/** /**
* \~chinese * \~chinese
* @brief * @brief
* @details * @details
*/ */
virtual void OnDestroy() {} virtual void OnDestroy();
/** /**
* \~chinese * \~chinese
* @brief * @brief
* @details OnReady * @details OnReady
* @param config * @param debug
* @note * @note
*/ */
void Run(Config const& config = Config()); void Run(bool debug = false);
/** /**
* \~chinese * \~chinese
@ -148,10 +111,18 @@ namespace kiwano
static void PreformInMainThread(Function<void()> func); static void PreformInMainThread(Function<void()> func);
private: private:
void Render(); /**
* \~chinese
* @brief
*/
void Update(); void Update();
/**
* \~chinese
* @brief
*/
void Render();
private: private:
float time_scale_; float time_scale_;
Time last_update_time_; Time last_update_time_;
@ -160,4 +131,12 @@ namespace kiwano
Vector<UpdateComponent*> update_comps_; Vector<UpdateComponent*> update_comps_;
Vector<EventComponent*> event_comps_; Vector<EventComponent*> event_comps_;
}; };
inline void Application::OnReady()
{
}
inline void Application::OnDestroy()
{
}
} }

View File

@ -19,32 +19,9 @@
// THE SOFTWARE. // THE SOFTWARE.
#include <kiwano/platform/Window.h> #include <kiwano/platform/Window.h>
#include <kiwano/platform/Application.h>
#include <kiwano/core/event/MouseEvent.h>
#include <kiwano/core/event/KeyEvent.h>
#include <kiwano/core/event/WindowEvent.h>
#include <kiwano/core/Logger.h>
#include <imm.h> // ImmAssociateContext
#pragma comment(lib, "imm32.lib")
#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
#define KGE_WND_CLASS_NAME L"KiwanoAppWnd"
namespace kiwano namespace kiwano
{ {
namespace
{
MONITORINFOEX GetMoniterInfoEx(HWND hwnd);
void AdjustWindow(uint32_t width, uint32_t height, DWORD style, uint32_t* win_width, uint32_t* win_height);
void ChangeFullScreenResolution(int width, int height, WCHAR* device_name);
void RestoreResolution(WCHAR* device_name);
}
WindowConfig::WindowConfig(String const& title, uint32_t width, uint32_t height, uint32_t icon, bool resizable, bool fullscreen) WindowConfig::WindowConfig(String const& title, uint32_t width, uint32_t height, uint32_t icon, bool resizable, bool fullscreen)
: title(title) : title(title)
@ -57,13 +34,9 @@ namespace kiwano
} }
Window::Window() Window::Window()
: handle_(nullptr) : should_close_(false)
, width_(0) , width_(0)
, height_(0) , height_(0)
, device_name_(nullptr)
, is_fullscreen_(false)
, resizable_(false)
, mouse_cursor_(CursorType::Arrow)
{ {
} }
@ -71,125 +44,9 @@ namespace kiwano
{ {
} }
void Window::Init(WindowConfig const& config)
{
HINSTANCE hinst = GetModuleHandleW(nullptr);
WNDCLASSEX wcex = { 0 };
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.lpszClassName = KGE_WND_CLASS_NAME;
wcex.style = CS_HREDRAW | CS_VREDRAW /* | CS_DBLCLKS */;
wcex.lpfnWndProc = Window::WndProc;
wcex.hIcon = nullptr;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = sizeof(LONG_PTR);
wcex.hInstance = hinst;
wcex.hbrBackground = (HBRUSH)(::GetStockObject(BLACK_BRUSH));
wcex.lpszMenuName = nullptr;
wcex.hCursor = ::LoadCursorW(hinst, IDC_ARROW);
if (config.icon)
{
wcex.hIcon = (HICON)::LoadImageW(hinst, MAKEINTRESOURCE(config.icon), IMAGE_ICON, 0, 0,
LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE);
}
::RegisterClassExW(&wcex);
// Get the nearest monitor to this window
HMONITOR monitor = ::MonitorFromPoint(POINT{ 0, 0 }, MONITOR_DEFAULTTOPRIMARY);
// Get the target monitor info
MONITORINFOEX monitor_info_ex;
memset(&monitor_info_ex, 0, sizeof(MONITORINFOEX));
monitor_info_ex.cbSize = sizeof(MONITORINFOEX);
::GetMonitorInfoW(monitor, &monitor_info_ex);
// Save the device name
int len = lstrlenW(monitor_info_ex.szDevice);
device_name_ = new wchar_t[len + 1];
lstrcpyW(device_name_, monitor_info_ex.szDevice);
uint32_t width = config.width;
uint32_t height = config.height;
int left = -1;
int top = -1;
resizable_ = config.resizable;
is_fullscreen_ = config.fullscreen;
if (is_fullscreen_)
{
top = monitor_info_ex.rcMonitor.top;
left = monitor_info_ex.rcMonitor.left;
if (width > static_cast<uint32_t>(monitor_info_ex.rcWork.right - left))
width = static_cast<uint32_t>(monitor_info_ex.rcWork.right - left);
if (height > static_cast<uint32_t>(monitor_info_ex.rcWork.bottom - top))
height = static_cast<uint32_t>(monitor_info_ex.rcWork.bottom - top);
}
else
{
uint32_t screenw = monitor_info_ex.rcWork.right - monitor_info_ex.rcWork.left;
uint32_t screenh = monitor_info_ex.rcWork.bottom - monitor_info_ex.rcWork.top;
uint32_t win_width, win_height;
AdjustWindow(width, height, GetWindowStyle(), &win_width, &win_height);
left = monitor_info_ex.rcWork.left + (screenw - win_width) / 2;
top = monitor_info_ex.rcWork.top + (screenh - win_height) / 2;
width = win_width;
height = win_height;
}
handle_ = ::CreateWindowExW(
is_fullscreen_ ? WS_EX_TOPMOST : 0,
KGE_WND_CLASS_NAME,
config.title.c_str(),
GetWindowStyle(),
left,
top,
width,
height,
nullptr,
nullptr,
hinst,
nullptr
);
if (handle_ == nullptr)
{
::UnregisterClass(KGE_WND_CLASS_NAME, hinst);
win32::ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError()));
return;
}
width_ = width;
height_ = height;
// disable imm
::ImmAssociateContext(handle_, nullptr);
// use Application instance in message loop
::SetWindowLongPtr(handle_, GWLP_USERDATA, LONG_PTR(this));
::ShowWindow(handle_, SW_SHOWNORMAL);
::UpdateWindow(handle_);
if (is_fullscreen_)
{
ChangeFullScreenResolution(width_, height_, device_name_);
}
}
EventPtr Window::PollEvent() EventPtr Window::PollEvent()
{ {
MSG msg; PumpEvents();
while (::PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE))
{
::TranslateMessage(&msg);
::DispatchMessageW(&msg);
}
EventPtr evt; EventPtr evt;
if (!event_queue_.empty()) if (!event_queue_.empty())
@ -202,135 +59,27 @@ namespace kiwano
String Window::GetTitle() const String Window::GetTitle() const
{ {
if (handle_) return title_;
{
wchar_t title[256];
::GetWindowTextW(handle_, title, 256);
return title;
}
return String();
}
void Window::SetTitle(String const& title)
{
if (handle_)
::SetWindowTextW(handle_, title.c_str());
} }
Size Window::GetSize() const Size Window::GetSize() const
{ {
return Size{ return Size(float(width_), float(height_));
static_cast<float>(width_),
static_cast<float>(height_)
};
} }
float Window::GetWidth() const uint32_t Window::GetWidth() const
{ {
return static_cast<float>(width_); return width_;
} }
float Window::GetHeight() const uint32_t Window::GetHeight() const
{ {
return static_cast<float>(height_); return height_;
}
void Window::SetIcon(uint32_t icon_resource)
{
if (handle_)
{
HINSTANCE hinstance = GetModuleHandle(nullptr);
HICON icon = (HICON)::LoadImageW(
hinstance,
MAKEINTRESOURCE(icon_resource),
IMAGE_ICON,
0,
0,
LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE
);
::SendMessage(handle_, WM_SETICON, ICON_BIG, (LPARAM)icon);
::SendMessage(handle_, WM_SETICON, ICON_SMALL, (LPARAM)icon);
}
}
void Window::Resize(int width, int height)
{
if (handle_ && !is_fullscreen_)
{
RECT rc = { 0, 0, int(width), int(height) };
::AdjustWindowRect(&rc, GetWindowStyle(), false);
width = rc.right - rc.left;
height = rc.bottom - rc.top;
::SetWindowPos(handle_, 0, 0, 0, width, height, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
}
}
void Window::SetFullscreen(bool fullscreen, int width, int height)
{
if (is_fullscreen_ != fullscreen || width != width_ || height != height_)
{
is_fullscreen_ = fullscreen;
if (is_fullscreen_)
{
// move window to (0, 0) before display switch
::SetWindowPos(handle_, HWND_TOPMOST, 0, 0, width_, height_, SWP_NOACTIVATE);
ChangeFullScreenResolution(width, height, device_name_);
MONITORINFOEX info = GetMoniterInfoEx(handle_);
::SetWindowLongPtr(handle_, GWL_STYLE, GetWindowStyle());
::SetWindowPos(handle_, HWND_TOPMOST, info.rcMonitor.top, info.rcMonitor.left, width, height, SWP_NOACTIVATE);
width_ = width;
height_ = height;
}
else
{
RestoreResolution(device_name_);
MONITORINFOEX info = GetMoniterInfoEx(handle_);
uint32_t screenw = info.rcWork.right - info.rcWork.left;
uint32_t screenh = info.rcWork.bottom - info.rcWork.top;
uint32_t win_width, win_height;
AdjustWindow(width, height, GetWindowStyle(), &win_width, &win_height);
int left = screenw > win_width ? ((screenw - win_width) / 2) : 0;
int top = screenh > win_height ? ((screenh - win_height) / 2) : 0;
::SetWindowLongPtr(handle_, GWL_STYLE, GetWindowStyle());
::SetWindowPos(handle_, HWND_NOTOPMOST, left, top, win_width, win_height, SWP_DRAWFRAME | SWP_FRAMECHANGED);
// Update window rect
RECT rc;
::GetClientRect(handle_, &rc);
width_ = static_cast<uint32_t>(rc.right - rc.left);
height_ = static_cast<uint32_t>(rc.bottom - rc.top);
}
::ShowWindow(handle_, SW_SHOWNORMAL);
}
}
void Window::SetCursor(CursorType cursor)
{
mouse_cursor_ = cursor;
}
WindowHandle Window::GetHandle() const
{
return handle_;
} }
bool Window::ShouldClose() bool Window::ShouldClose()
{ {
return handle_ == nullptr; return should_close_;
} }
void Window::PushEvent(EventPtr evt) void Window::PushEvent(EventPtr evt)
@ -340,306 +89,12 @@ namespace kiwano
void Window::Destroy() void Window::Destroy()
{ {
if (is_fullscreen_) while (!event_queue_.empty())
RestoreResolution(device_name_);
if (device_name_)
{ {
delete[] device_name_; event_queue_.pop();
device_name_ = nullptr;
} }
if (handle_) should_close_ = true;
{
::DestroyWindow(handle_);
handle_ = nullptr;
}
} }
#if defined(KGE_WIN32)
DWORD Window::GetWindowStyle() const
{
return is_fullscreen_ ? (WINDOW_FULLSCREEN_STYLE) : (resizable_ ? (WINDOW_RESIZABLE_STYLE) : (WINDOW_FIXED_STYLE));
}
void Window::UpdateCursor()
{
LPTSTR win32_cursor = IDC_ARROW;
switch (mouse_cursor_)
{
case CursorType::Arrow: win32_cursor = IDC_ARROW; break;
case CursorType::TextInput: win32_cursor = IDC_IBEAM; break;
case CursorType::SizeAll: win32_cursor = IDC_SIZEALL; break;
case CursorType::SizeWE: win32_cursor = IDC_SIZEWE; break;
case CursorType::SizeNS: win32_cursor = IDC_SIZENS; break;
case CursorType::SizeNESW: win32_cursor = IDC_SIZENESW; break;
case CursorType::SizeNWSE: win32_cursor = IDC_SIZENWSE; break;
case CursorType::Hand: win32_cursor = IDC_HAND; break;
}
::SetCursor(::LoadCursorW(nullptr, win32_cursor));
}
void Window::SetActive(bool actived)
{
if (!handle_)
return;
if (is_fullscreen_)
{
if (actived)
{
ChangeFullScreenResolution(width_, height_, device_name_);
MONITORINFOEX info = GetMoniterInfoEx(handle_);
::SetWindowPos(handle_, HWND_TOPMOST, info.rcMonitor.top, info.rcMonitor.left, width_, height_, SWP_NOACTIVATE);
}
else
{
RestoreResolution(device_name_);
::SetWindowPos(handle_, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
::ShowWindow(handle_, SW_MINIMIZE);
}
}
}
LRESULT CALLBACK Window::WndProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARAM lparam)
{
Window* window = reinterpret_cast<Window*>(static_cast<LONG_PTR>(::GetWindowLongPtrW(hwnd, GWLP_USERDATA)));
if (window == nullptr)
{
return ::DefWindowProcW(hwnd, msg, wparam, lparam);
}
switch (msg)
{
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
{
KeyDownEventPtr evt = new KeyDownEvent;
evt->code = static_cast<int>(wparam);
window->PushEvent(evt);
}
break;
case WM_KEYUP:
case WM_SYSKEYUP:
{
KeyUpEventPtr evt = new KeyUpEvent;
evt->code = static_cast<int>(wparam);
window->PushEvent(evt);
}
break;
case WM_CHAR:
{
KeyCharEventPtr evt = new KeyCharEvent;
evt->value = static_cast<char>(wparam);
window->PushEvent(evt);
}
break;
case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK:
case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK:
case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK:
{
MouseDownEventPtr evt = new MouseDownEvent;
evt->pos = Point(((float)(int)(short)LOWORD(lparam)), ((float)(int)(short)HIWORD(lparam)));
if (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONDBLCLK) { evt->button = MouseButton::Left; }
else if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONDBLCLK) { evt->button = MouseButton::Right; }
else if (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONDBLCLK) { evt->button = MouseButton::Middle; }
window->PushEvent(evt);
}
break;
case WM_LBUTTONUP:
case WM_MBUTTONUP:
case WM_RBUTTONUP:
{
MouseUpEventPtr evt = new MouseUpEvent;
evt->pos = Point(((float)(int)(short)LOWORD(lparam)), ((float)(int)(short)HIWORD(lparam)));
if (msg == WM_LBUTTONUP) { evt->button = MouseButton::Left; }
else if (msg == WM_RBUTTONUP) { evt->button = MouseButton::Right; }
else if (msg == WM_MBUTTONUP) { evt->button = MouseButton::Middle; }
window->PushEvent(evt);
}
break;
case WM_MOUSEMOVE:
{
MouseMoveEventPtr evt = new MouseMoveEvent;
evt->pos = Point(((float)(int)(short)LOWORD(lparam)), ((float)(int)(short)HIWORD(lparam)));
window->PushEvent(evt);
}
break;
case WM_MOUSEWHEEL:
{
MouseWheelEventPtr evt = new MouseWheelEvent;
evt->pos = Point(((float)(int)(short)LOWORD(lparam)), ((float)(int)(short)HIWORD(lparam)));
evt->wheel = GET_WHEEL_DELTA_WPARAM(wparam) / (float)WHEEL_DELTA;
window->PushEvent(evt);
}
break;
case WM_SIZE:
{
if (SIZE_MAXHIDE == wparam || SIZE_MINIMIZED == wparam)
{
KGE_SYS_LOG(L"Window minimized");
}
else
{
// KGE_SYS_LOG(L"Window resized");
window->width_ = ((uint32_t)(short)LOWORD(lparam));
window->height_ = ((uint32_t)(short)HIWORD(lparam));
WindowResizedEventPtr evt = new WindowResizedEvent;
evt->width = window->width_;
evt->height = window->height_;
window->PushEvent(evt);
}
}
break;
case WM_MOVE:
{
int x = ((int)(short)LOWORD(lparam));
int y = ((int)(short)HIWORD(lparam));
WindowMovedEventPtr evt = new WindowMovedEvent;
evt->x = x;
evt->y = y;
window->PushEvent(evt);
}
break;
case WM_ACTIVATE:
{
bool active = (LOWORD(wparam) != WA_INACTIVE);
window->SetActive(active);
WindowFocusChangedEventPtr evt = new WindowFocusChangedEvent;
evt->focus = active;
window->PushEvent(evt);
}
break;
case WM_SETTEXT:
{
KGE_SYS_LOG(L"Window title changed");
WindowTitleChangedEventPtr evt = new WindowTitleChangedEvent;
evt->title.assign(reinterpret_cast<const wchar_t*>(lparam));
window->PushEvent(evt);
}
break;
case WM_SETICON:
{
KGE_SYS_LOG(L"Window icon changed");
}
break;
case WM_DISPLAYCHANGE:
{
KGE_SYS_LOG(L"The display resolution has changed");
::InvalidateRect(hwnd, nullptr, FALSE);
}
break;
case WM_SETCURSOR:
{
window->UpdateCursor();
}
break;
case WM_CLOSE:
{
KGE_SYS_LOG(L"Window is closing");
WindowClosedEventPtr evt = new WindowClosedEvent;
window->PushEvent(evt);
window->Destroy();
}
break;
case WM_DESTROY:
{
KGE_SYS_LOG(L"Window was destroyed");
::PostQuitMessage(0);
return 0;
}
break;
}
return ::DefWindowProcW(hwnd, msg, wparam, lparam);
}
namespace
{
MONITORINFOEX GetMoniterInfoEx(HWND hwnd)
{
HMONITOR monitor = ::MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
MONITORINFOEX monitor_info;
memset(&monitor_info, 0, sizeof(MONITORINFOEX));
monitor_info.cbSize = sizeof(MONITORINFOEX);
::GetMonitorInfoW(monitor, &monitor_info);
return monitor_info;
}
void AdjustWindow(uint32_t width, uint32_t height, DWORD style, uint32_t* win_width, uint32_t* win_height)
{
RECT rc;
::SetRect(&rc, 0, 0, (int)width, (int)height);
::AdjustWindowRect(&rc, style, false);
*win_width = rc.right - rc.left;
*win_height = rc.bottom - rc.top;
MONITORINFOEX info = GetMoniterInfoEx(NULL);
uint32_t screenw = info.rcWork.right - info.rcWork.left;
uint32_t screenh = info.rcWork.bottom - info.rcWork.top;
if (*win_width > screenw)
*win_width = screenw;
if (*win_height > screenh)
*win_height = screenh;
}
void ChangeFullScreenResolution(int width, int height, WCHAR* device_name)
{
DEVMODE mode;
memset(&mode, 0, sizeof(mode));
mode.dmSize = sizeof(DEVMODE);
mode.dmBitsPerPel = ::GetDeviceCaps(::GetDC(0), BITSPIXEL);;
mode.dmPelsWidth = width;
mode.dmPelsHeight = height;
mode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
if (::ChangeDisplaySettingsExW(device_name, &mode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL)
KGE_ERROR(L"ChangeDisplaySettings failed");
}
void RestoreResolution(WCHAR* device_name)
{
::ChangeDisplaySettingsExW(device_name, NULL, NULL, 0, NULL);
}
}
#endif
} }

View File

@ -79,23 +79,26 @@ namespace kiwano
typedef HWND WindowHandle; typedef HWND WindowHandle;
#endif #endif
/** /**
* \~chinese * \~chinese
* @brief * @brief
*/ */
class KGE_API Window class KGE_API Window
: public Singleton<Window> : protected Noncopyable
{ {
friend Singleton<Window>;
public: public:
/**
* \~chinese
* @brief
*/
static Window& Instance();
/** /**
* \~chinese * \~chinese
* @brief * @brief
* @param config * @param config
*/ */
void Init(WindowConfig const& config); virtual bool Create(WindowConfig const& config) = 0;
/** /**
* \~chinese * \~chinese
@ -116,28 +119,34 @@ namespace kiwano
* @brief * @brief
* @return * @return
*/ */
float GetWidth() const; uint32_t GetWidth() const;
/** /**
* \~chinese * \~chinese
* @brief * @brief
* @return * @return
*/ */
float GetHeight() const; uint32_t GetHeight() const;
/**
* \~chinese
* @brief
*/
virtual WindowHandle GetHandle() const = 0;
/** /**
* \~chinese * \~chinese
* @brief * @brief
* @param title * @param title
*/ */
void SetTitle(String const& title); virtual void SetTitle(String const& title) = 0;
/** /**
* \~chinese * \~chinese
* @brief * @brief
* @param icon_resource ID * @param icon_resource ID
*/ */
void SetIcon(uint32_t icon_resource); virtual void SetIcon(uint32_t icon_resource) = 0;
/** /**
* \~chinese * \~chinese
@ -145,7 +154,7 @@ namespace kiwano
* @param width * @param width
* @param height * @param height
*/ */
void Resize(int width, int height); virtual void Resize(uint32_t width, uint32_t height) = 0;
/** /**
* \~chinese * \~chinese
@ -154,14 +163,14 @@ namespace kiwano
* @param width * @param width
* @param height * @param height
*/ */
void SetFullscreen(bool fullscreen, int width, int height); virtual void SetFullscreen(bool fullscreen) = 0;
/** /**
* \~chinese * \~chinese
* @brief * @brief
* @param cursor * @param cursor
*/ */
void SetCursor(CursorType cursor); virtual void SetCursor(CursorType cursor) = 0;
/** /**
* \~chinese * \~chinese
@ -170,49 +179,48 @@ namespace kiwano
*/ */
EventPtr PollEvent(); EventPtr PollEvent();
/**
* \~chinese
* @brief »ñÈ¡´°¿Ú¾ä±ú
*/
WindowHandle GetHandle() const;
/** /**
* \~chinese * \~chinese
* @brief * @brief
*/ */
bool ShouldClose(); virtual bool ShouldClose() = 0;
/** /**
* \~chinese * \~chinese
* @brief * @brief
*/ */
void Destroy(); virtual void Destroy();
private: protected:
Window(); Window();
~Window(); ~Window();
void PushEvent(EventPtr evt); void PushEvent(EventPtr evt);
#if defined(KGE_WIN32) void SetInternalSize(uint32_t width, uint32_t height);
DWORD GetWindowStyle() const;
void UpdateCursor(); void SetInternalTitle(String const& title);
void SetActive(bool actived); virtual void PumpEvents() = 0;
static LRESULT CALLBACK WndProc(HWND, UINT32, WPARAM, LPARAM);
#endif
private: private:
bool resizable_; bool should_close_;
bool is_fullscreen_;
WindowHandle handle_;
uint32_t width_; uint32_t width_;
uint32_t height_; uint32_t height_;
wchar_t* device_name_; String title_;
CursorType mouse_cursor_;
std::queue<EventPtr> event_queue_; std::queue<EventPtr> event_queue_;
}; };
inline void Window::SetInternalSize(uint32_t width, uint32_t height)
{
width_ = width;
height_ = height;
}
inline void Window::SetInternalTitle(String const& title)
{
title_ = title;
}
} }

View File

@ -0,0 +1,632 @@
// Copyright (c) 2016-2020 Kiwano - Nomango
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include <kiwano/platform/Window.h>
#if defined(KGE_WIN32)
#include <kiwano/platform/Application.h>
#include <kiwano/core/event/MouseEvent.h>
#include <kiwano/core/event/KeyEvent.h>
#include <kiwano/core/event/WindowEvent.h>
#include <kiwano/core/Logger.h>
#include <imm.h> // ImmAssociateContext
#pragma comment(lib, "imm32.lib")
#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
#define KGE_WND_CLASS_NAME L"KiwanoAppWnd"
namespace kiwano
{
namespace win32
{
namespace
{
MONITORINFOEX GetMoniterInfoEx(HWND hwnd)
{
HMONITOR monitor = ::MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
MONITORINFOEX monitor_info;
memset(&monitor_info, 0, sizeof(MONITORINFOEX));
monitor_info.cbSize = sizeof(MONITORINFOEX);
::GetMonitorInfoW(monitor, &monitor_info);
return monitor_info;
}
void AdjustWindow(uint32_t width, uint32_t height, DWORD style, uint32_t* win_width, uint32_t* win_height)
{
RECT rc;
::SetRect(&rc, 0, 0, (int)width, (int)height);
::AdjustWindowRect(&rc, style, false);
*win_width = rc.right - rc.left;
*win_height = rc.bottom - rc.top;
MONITORINFOEX info = GetMoniterInfoEx(NULL);
uint32_t screenw = info.rcWork.right - info.rcWork.left;
uint32_t screenh = info.rcWork.bottom - info.rcWork.top;
if (*win_width > screenw)
*win_width = screenw;
if (*win_height > screenh)
*win_height = screenh;
}
void ChangeFullScreenResolution(uint32_t width, uint32_t height, WCHAR* device_name)
{
DEVMODE mode;
memset(&mode, 0, sizeof(mode));
mode.dmSize = sizeof(DEVMODE);
mode.dmBitsPerPel = ::GetDeviceCaps(::GetDC(0), BITSPIXEL);;
mode.dmPelsWidth = width;
mode.dmPelsHeight = height;
mode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
if (::ChangeDisplaySettingsExW(device_name, &mode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL)
KGE_ERROR(L"ChangeDisplaySettings failed");
}
void RestoreResolution(WCHAR* device_name)
{
::ChangeDisplaySettingsExW(device_name, NULL, NULL, 0, NULL);
}
}
class KGE_API WindowImpl
: public kiwano::Window
{
public:
WindowImpl();
~WindowImpl();
bool Create(WindowConfig const& config) override;
WindowHandle GetHandle() const override;
void SetTitle(String const& title) override;
void SetIcon(uint32_t icon_resource) override;
void Resize(uint32_t width, uint32_t height) override;
void SetFullscreen(bool fullscreen) override;
void SetCursor(CursorType cursor) override;
bool ShouldClose() override;
void Destroy() override;
private:
void PumpEvents() override;
DWORD GetWindowStyle() const;
void UpdateCursor();
void SetActive(bool actived);
static LRESULT CALLBACK WndProc(HWND, UINT32, WPARAM, LPARAM);
private:
bool resizable_;
bool is_fullscreen_;
wchar_t* device_name_;
WindowHandle handle_;
CursorType mouse_cursor_;
};
WindowImpl::WindowImpl()
: handle_(nullptr)
, device_name_(nullptr)
, is_fullscreen_(false)
, resizable_(false)
, mouse_cursor_(CursorType::Arrow)
{
}
WindowImpl::~WindowImpl()
{
}
bool WindowImpl::Create(WindowConfig const& config)
{
HINSTANCE hinst = GetModuleHandleW(nullptr);
WNDCLASSEX wcex = { 0 };
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.lpszClassName = KGE_WND_CLASS_NAME;
wcex.style = CS_HREDRAW | CS_VREDRAW /* | CS_DBLCLKS */;
wcex.lpfnWndProc = WindowImpl::WndProc;
wcex.hIcon = nullptr;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = sizeof(LONG_PTR);
wcex.hInstance = hinst;
wcex.hbrBackground = (HBRUSH)(::GetStockObject(BLACK_BRUSH));
wcex.lpszMenuName = nullptr;
wcex.hCursor = ::LoadCursorW(hinst, IDC_ARROW);
if (config.icon)
{
wcex.hIcon = (HICON)::LoadImageW(hinst, MAKEINTRESOURCE(config.icon), IMAGE_ICON, 0, 0,
LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE);
}
::RegisterClassExW(&wcex);
// Get the nearest monitor to this window
HMONITOR monitor = ::MonitorFromPoint(POINT{ 0, 0 }, MONITOR_DEFAULTTOPRIMARY);
// Get the target monitor info
MONITORINFOEX monitor_info_ex;
memset(&monitor_info_ex, 0, sizeof(MONITORINFOEX));
monitor_info_ex.cbSize = sizeof(MONITORINFOEX);
::GetMonitorInfoW(monitor, &monitor_info_ex);
// Save the device name
int len = lstrlenW(monitor_info_ex.szDevice);
device_name_ = new wchar_t[len + 1];
lstrcpyW(device_name_, monitor_info_ex.szDevice);
uint32_t width = config.width;
uint32_t height = config.height;
int left = -1;
int top = -1;
resizable_ = config.resizable;
is_fullscreen_ = config.fullscreen;
if (is_fullscreen_)
{
top = monitor_info_ex.rcMonitor.top;
left = monitor_info_ex.rcMonitor.left;
if (width > static_cast<uint32_t>(monitor_info_ex.rcWork.right - left))
width = static_cast<uint32_t>(monitor_info_ex.rcWork.right - left);
if (height > static_cast<uint32_t>(monitor_info_ex.rcWork.bottom - top))
height = static_cast<uint32_t>(monitor_info_ex.rcWork.bottom - top);
}
else
{
uint32_t screenw = monitor_info_ex.rcWork.right - monitor_info_ex.rcWork.left;
uint32_t screenh = monitor_info_ex.rcWork.bottom - monitor_info_ex.rcWork.top;
uint32_t win_width, win_height;
AdjustWindow(width, height, GetWindowStyle(), &win_width, &win_height);
left = monitor_info_ex.rcWork.left + (screenw - win_width) / 2;
top = monitor_info_ex.rcWork.top + (screenh - win_height) / 2;
width = win_width;
height = win_height;
}
handle_ = ::CreateWindowExW(
is_fullscreen_ ? WS_EX_TOPMOST : 0,
KGE_WND_CLASS_NAME,
config.title.c_str(),
GetWindowStyle(),
left,
top,
width,
height,
nullptr,
nullptr,
hinst,
nullptr
);
if (handle_ == nullptr)
{
::UnregisterClass(KGE_WND_CLASS_NAME, hinst);
KGE_ERROR(L"Failed with HRESULT of %08X", HRESULT_FROM_WIN32(GetLastError()));
return false;
}
SetInternalSize(width, height);
// disable imm
::ImmAssociateContext(handle_, nullptr);
// use Application instance in message loop
::SetWindowLongPtr(handle_, GWLP_USERDATA, LONG_PTR(this));
::ShowWindow(handle_, SW_SHOWNORMAL);
::UpdateWindow(handle_);
if (is_fullscreen_)
{
ChangeFullScreenResolution(width, height, device_name_);
}
return true;
}
WindowHandle WindowImpl::GetHandle() const
{
return handle_;
}
void WindowImpl::PumpEvents()
{
MSG msg;
while (::PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE))
{
::TranslateMessage(&msg);
::DispatchMessageW(&msg);
}
}
void WindowImpl::SetTitle(String const& title)
{
if (handle_)
::SetWindowTextW(handle_, title.c_str());
}
void WindowImpl::SetIcon(uint32_t icon_resource)
{
if (handle_)
{
HINSTANCE hinstance = GetModuleHandle(nullptr);
HICON icon = (HICON)::LoadImageW(
hinstance,
MAKEINTRESOURCE(icon_resource),
IMAGE_ICON,
0,
0,
LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE
);
::SendMessage(handle_, WM_SETICON, ICON_BIG, (LPARAM)icon);
::SendMessage(handle_, WM_SETICON, ICON_SMALL, (LPARAM)icon);
}
}
void WindowImpl::Resize(uint32_t width, uint32_t height)
{
if (handle_ && !is_fullscreen_)
{
RECT rc = { 0, 0, LONG(width), LONG(height) };
::AdjustWindowRect(&rc, GetWindowStyle(), false);
width = rc.right - rc.left;
height = rc.bottom - rc.top;
::SetWindowPos(handle_, 0, 0, 0, width, height, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
}
}
void WindowImpl::SetFullscreen(bool fullscreen)
{
if (is_fullscreen_ != fullscreen)
{
is_fullscreen_ = fullscreen;
uint32_t width = GetWidth();
uint32_t height = GetHeight();
if (is_fullscreen_)
{
// move window to (0, 0) before display switch
::SetWindowPos(handle_, HWND_TOPMOST, 0, 0, width, height, SWP_NOACTIVATE);
ChangeFullScreenResolution(width, height, device_name_);
MONITORINFOEX info = GetMoniterInfoEx(handle_);
::SetWindowLongPtr(handle_, GWL_STYLE, GetWindowStyle());
::SetWindowPos(handle_, HWND_TOPMOST, info.rcMonitor.top, info.rcMonitor.left, width, height, SWP_NOACTIVATE);
}
else
{
RestoreResolution(device_name_);
MONITORINFOEX 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;
::SetWindowLongPtr(handle_, GWL_STYLE, GetWindowStyle());
::SetWindowPos(handle_, HWND_NOTOPMOST, left, top, width, height, SWP_DRAWFRAME | SWP_FRAMECHANGED);
}
::ShowWindow(handle_, SW_SHOWNORMAL);
}
}
void WindowImpl::SetCursor(CursorType cursor)
{
mouse_cursor_ = cursor;
}
bool WindowImpl::ShouldClose()
{
return handle_ == nullptr;
}
void WindowImpl::Destroy()
{
if (is_fullscreen_)
RestoreResolution(device_name_);
if (device_name_)
{
delete[] device_name_;
device_name_ = nullptr;
}
if (handle_)
{
::DestroyWindow(handle_);
handle_ = nullptr;
}
Window::Destroy();
}
DWORD WindowImpl::GetWindowStyle() const
{
return is_fullscreen_ ? (WINDOW_FULLSCREEN_STYLE) : (resizable_ ? (WINDOW_RESIZABLE_STYLE) : (WINDOW_FIXED_STYLE));
}
void WindowImpl::UpdateCursor()
{
LPTSTR win32_cursor = IDC_ARROW;
switch (mouse_cursor_)
{
case CursorType::Arrow: win32_cursor = IDC_ARROW; break;
case CursorType::TextInput: win32_cursor = IDC_IBEAM; break;
case CursorType::SizeAll: win32_cursor = IDC_SIZEALL; break;
case CursorType::SizeWE: win32_cursor = IDC_SIZEWE; break;
case CursorType::SizeNS: win32_cursor = IDC_SIZENS; break;
case CursorType::SizeNESW: win32_cursor = IDC_SIZENESW; break;
case CursorType::SizeNWSE: win32_cursor = IDC_SIZENWSE; break;
case CursorType::Hand: win32_cursor = IDC_HAND; break;
}
::SetCursor(::LoadCursorW(nullptr, win32_cursor));
}
void WindowImpl::SetActive(bool actived)
{
if (!handle_)
return;
if (is_fullscreen_)
{
if (actived)
{
ChangeFullScreenResolution(GetWidth(), GetHeight(), device_name_);
MONITORINFOEX info = GetMoniterInfoEx(handle_);
::SetWindowPos(handle_, HWND_TOPMOST, info.rcMonitor.top, info.rcMonitor.left, GetWidth(), GetHeight(), SWP_NOACTIVATE);
}
else
{
RestoreResolution(device_name_);
::SetWindowPos(handle_, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
::ShowWindow(handle_, SW_MINIMIZE);
}
}
}
LRESULT CALLBACK WindowImpl::WndProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARAM lparam)
{
WindowImpl* window = reinterpret_cast<WindowImpl*>(static_cast<LONG_PTR>(::GetWindowLongPtrW(hwnd, GWLP_USERDATA)));
if (window == nullptr)
{
return ::DefWindowProcW(hwnd, msg, wparam, lparam);
}
switch (msg)
{
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
{
KeyDownEventPtr evt = new KeyDownEvent;
evt->code = static_cast<int>(wparam);
window->PushEvent(evt);
}
break;
case WM_KEYUP:
case WM_SYSKEYUP:
{
KeyUpEventPtr evt = new KeyUpEvent;
evt->code = static_cast<int>(wparam);
window->PushEvent(evt);
}
break;
case WM_CHAR:
{
KeyCharEventPtr evt = new KeyCharEvent;
evt->value = static_cast<char>(wparam);
window->PushEvent(evt);
}
break;
case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK:
case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK:
case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK:
{
MouseDownEventPtr evt = new MouseDownEvent;
evt->pos = Point(((float)(int)(short)LOWORD(lparam)), ((float)(int)(short)HIWORD(lparam)));
if (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONDBLCLK) { evt->button = MouseButton::Left; }
else if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONDBLCLK) { evt->button = MouseButton::Right; }
else if (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONDBLCLK) { evt->button = MouseButton::Middle; }
window->PushEvent(evt);
}
break;
case WM_LBUTTONUP:
case WM_MBUTTONUP:
case WM_RBUTTONUP:
{
MouseUpEventPtr evt = new MouseUpEvent;
evt->pos = Point(((float)(int)(short)LOWORD(lparam)), ((float)(int)(short)HIWORD(lparam)));
if (msg == WM_LBUTTONUP) { evt->button = MouseButton::Left; }
else if (msg == WM_RBUTTONUP) { evt->button = MouseButton::Right; }
else if (msg == WM_MBUTTONUP) { evt->button = MouseButton::Middle; }
window->PushEvent(evt);
}
break;
case WM_MOUSEMOVE:
{
MouseMoveEventPtr evt = new MouseMoveEvent;
evt->pos = Point(((float)(int)(short)LOWORD(lparam)), ((float)(int)(short)HIWORD(lparam)));
window->PushEvent(evt);
}
break;
case WM_MOUSEWHEEL:
{
MouseWheelEventPtr evt = new MouseWheelEvent;
evt->pos = Point(((float)(int)(short)LOWORD(lparam)), ((float)(int)(short)HIWORD(lparam)));
evt->wheel = GET_WHEEL_DELTA_WPARAM(wparam) / (float)WHEEL_DELTA;
window->PushEvent(evt);
}
break;
case WM_SIZE:
{
if (SIZE_MAXHIDE == wparam || SIZE_MINIMIZED == wparam)
{
KGE_SYS_LOG(L"Window minimized");
}
else
{
// KGE_SYS_LOG(L"WindowImpl resized");
window->SetInternalSize(((uint32_t)(short)LOWORD(lparam)), ((uint32_t)(short)HIWORD(lparam)));
WindowResizedEventPtr evt = new WindowResizedEvent;
evt->width = window->GetWidth();
evt->height = window->GetHeight();
window->PushEvent(evt);
}
}
break;
case WM_MOVE:
{
int x = ((int)(short)LOWORD(lparam));
int y = ((int)(short)HIWORD(lparam));
WindowMovedEventPtr evt = new WindowMovedEvent;
evt->x = x;
evt->y = y;
window->PushEvent(evt);
}
break;
case WM_ACTIVATE:
{
bool active = (LOWORD(wparam) != WA_INACTIVE);
window->SetActive(active);
WindowFocusChangedEventPtr evt = new WindowFocusChangedEvent;
evt->focus = active;
window->PushEvent(evt);
}
break;
case WM_SETTEXT:
{
KGE_SYS_LOG(L"Window title changed");
String title = String::cstr(reinterpret_cast<LPCWSTR>(lparam));
window->SetInternalTitle(title);
WindowTitleChangedEventPtr evt = new WindowTitleChangedEvent;
evt->title = title;
window->PushEvent(evt);
}
break;
case WM_SETICON:
{
KGE_SYS_LOG(L"Window icon changed");
}
break;
case WM_DISPLAYCHANGE:
{
KGE_SYS_LOG(L"The display resolution has changed");
::InvalidateRect(hwnd, nullptr, FALSE);
}
break;
case WM_SETCURSOR:
{
window->UpdateCursor();
}
break;
case WM_CLOSE:
{
KGE_SYS_LOG(L"Window is closing");
WindowClosedEventPtr evt = new WindowClosedEvent;
window->PushEvent(evt);
window->Destroy();
}
break;
case WM_DESTROY:
{
KGE_SYS_LOG(L"Window was destroyed");
::PostQuitMessage(0);
return 0;
}
break;
}
return ::DefWindowProcW(hwnd, msg, wparam, lparam);
}
} // namespace win32
} // namespace kiwano
namespace kiwano
{
Window& Window::Instance()
{
static win32::WindowImpl instance;
return instance;
}
}
#endif

View File

@ -90,17 +90,17 @@ namespace kiwano
return; return;
} }
} }
Renderer::instance().CreateSolidBrush(*this, color); Renderer::Instance().CreateSolidBrush(*this, color);
} }
void Brush::SetStyle(LinearGradientStyle const& style) void Brush::SetStyle(LinearGradientStyle const& style)
{ {
Renderer::instance().CreateLinearGradientBrush(*this, style); Renderer::Instance().CreateLinearGradientBrush(*this, style);
} }
void Brush::SetStyle(RadialGradientStyle const& style) void Brush::SetStyle(RadialGradientStyle const& style)
{ {
Renderer::instance().CreateRadialGradientBrush(*this, style); Renderer::Instance().CreateRadialGradientBrush(*this, style);
} }
void Brush::SetBrush(ComPtr<ID2D1Brush> brush, Type type) void Brush::SetBrush(ComPtr<ID2D1Brush> brush, Type type)

View File

@ -41,7 +41,7 @@ namespace kiwano
{ {
try try
{ {
Renderer::instance().CreateFontCollection(*this, files); Renderer::Instance().CreateFontCollection(*this, files);
} }
catch (std::runtime_error&) catch (std::runtime_error&)
{ {
@ -54,7 +54,7 @@ namespace kiwano
{ {
try try
{ {
Renderer::instance().CreateFontCollection(*this, resources); Renderer::Instance().CreateFontCollection(*this, resources);
} }
catch (std::runtime_error&) catch (std::runtime_error&)
{ {

View File

@ -118,35 +118,35 @@ namespace kiwano
Geometry Geometry::CreateLine(Point const& begin, Point const& end) Geometry Geometry::CreateLine(Point const& begin, Point const& end)
{ {
Geometry output; Geometry output;
Renderer::instance().CreateLineGeometry(output, begin, end); Renderer::Instance().CreateLineGeometry(output, begin, end);
return output; return output;
} }
Geometry Geometry::CreateRect(Rect const& rect) Geometry Geometry::CreateRect(Rect const& rect)
{ {
Geometry output; Geometry output;
Renderer::instance().CreateRectGeometry(output, rect); Renderer::Instance().CreateRectGeometry(output, rect);
return output; return output;
} }
Geometry Geometry::CreateRoundedRect(Rect const& rect, Vec2 const& radius) Geometry Geometry::CreateRoundedRect(Rect const& rect, Vec2 const& radius)
{ {
Geometry output; Geometry output;
Renderer::instance().CreateRoundedRectGeometry(output, rect, radius); Renderer::Instance().CreateRoundedRectGeometry(output, rect, radius);
return output; return output;
} }
Geometry Geometry::CreateCircle(Point const& center, float radius) Geometry Geometry::CreateCircle(Point const& center, float radius)
{ {
Geometry output; Geometry output;
Renderer::instance().CreateEllipseGeometry(output, center, Vec2{ radius, radius }); Renderer::Instance().CreateEllipseGeometry(output, center, Vec2{ radius, radius });
return output; return output;
} }
Geometry Geometry::CreateEllipse(Point const& center, Vec2 const& radius) Geometry Geometry::CreateEllipse(Point const& center, Vec2 const& radius)
{ {
Geometry output; Geometry output;
Renderer::instance().CreateEllipseGeometry(output, center, radius); Renderer::Instance().CreateEllipseGeometry(output, center, radius);
return output; return output;
} }

View File

@ -38,7 +38,7 @@ namespace kiwano
if (!IsOpened()) if (!IsOpened())
{ {
path_geo_.reset(); path_geo_.reset();
Renderer::instance().CreateGeometrySink(*this); Renderer::Instance().CreateGeometrySink(*this);
win32::ThrowIfFailed(path_geo_->Open(&sink_)); win32::ThrowIfFailed(path_geo_->Open(&sink_));
} }

View File

@ -33,7 +33,7 @@ namespace kiwano
bool GifImage::Load(String const& file_path) bool GifImage::Load(String const& file_path)
{ {
Renderer::instance().CreateGifImage(*this, file_path); Renderer::Instance().CreateGifImage(*this, file_path);
if (IsValid()) if (IsValid())
{ {
@ -49,7 +49,7 @@ namespace kiwano
bool GifImage::Load(Resource const& res) bool GifImage::Load(Resource const& res)
{ {
Renderer::instance().CreateGifImage(*this, res); Renderer::Instance().CreateGifImage(*this, res);
if (IsValid()) if (IsValid())
{ {
@ -71,7 +71,7 @@ namespace kiwano
GifImage::Frame GifImage::GetFrame(uint32_t index) GifImage::Frame GifImage::GetFrame(uint32_t index)
{ {
Frame frame; Frame frame;
Renderer::instance().CreateGifImageFrame(frame, *this, index); Renderer::Instance().CreateGifImageFrame(frame, *this, index);
return frame; return frame;
} }

View File

@ -26,11 +26,6 @@
namespace kiwano namespace kiwano
{ {
RenderConfig::RenderConfig(Color clear_color, bool vsync)
: clear_color(clear_color)
, vsync(vsync)
{
}
Renderer::Renderer() Renderer::Renderer()
: target_window_(nullptr) : target_window_(nullptr)
@ -43,20 +38,14 @@ namespace kiwano
{ {
} }
void Renderer::Init(RenderConfig const& config)
{
SetClearColor(config.clear_color);
SetVSyncEnabled(config.vsync);
}
void Renderer::SetupComponent() void Renderer::SetupComponent()
{ {
KGE_SYS_LOG(L"Creating device resources"); KGE_SYS_LOG(L"Creating device resources");
win32::ThrowIfFailed(::CoInitialize(nullptr)); win32::ThrowIfFailed(::CoInitialize(nullptr));
target_window_ = Window::instance().GetHandle(); target_window_ = Window::Instance().GetHandle();
output_size_ = Window::instance().GetSize(); output_size_ = Window::Instance().GetSize();
d2d_res_ = nullptr; d2d_res_ = nullptr;
d3d_res_ = nullptr; d3d_res_ = nullptr;
@ -210,7 +199,7 @@ namespace kiwano
hr = E_UNEXPECTED; hr = E_UNEXPECTED;
} }
if (!FileSystem::instance().IsFileExists(file_path)) if (!FileSystem::Instance().IsFileExists(file_path))
{ {
KGE_WARN(L"Texture file '%s' not found!", file_path.c_str()); KGE_WARN(L"Texture file '%s' not found!", file_path.c_str());
hr = E_FAIL; hr = E_FAIL;
@ -218,7 +207,7 @@ namespace kiwano
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
String full_path = FileSystem::instance().GetFullPathForFile(file_path); String full_path = FileSystem::Instance().GetFullPathForFile(file_path);
ComPtr<IWICBitmapDecoder> decoder; ComPtr<IWICBitmapDecoder> decoder;
hr = d2d_res_->CreateBitmapDecoderFromFile(decoder, full_path); hr = d2d_res_->CreateBitmapDecoderFromFile(decoder, full_path);
@ -328,7 +317,7 @@ namespace kiwano
hr = E_UNEXPECTED; hr = E_UNEXPECTED;
} }
if (!FileSystem::instance().IsFileExists(file_path)) if (!FileSystem::Instance().IsFileExists(file_path))
{ {
KGE_WARN(L"Gif texture file '%s' not found!", file_path.c_str()); KGE_WARN(L"Gif texture file '%s' not found!", file_path.c_str());
hr = E_FAIL; hr = E_FAIL;
@ -336,7 +325,7 @@ namespace kiwano
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
String full_path = FileSystem::instance().GetFullPathForFile(file_path); String full_path = FileSystem::Instance().GetFullPathForFile(file_path);
ComPtr<IWICBitmapDecoder> decoder; ComPtr<IWICBitmapDecoder> decoder;
hr = d2d_res_->CreateBitmapDecoderFromFile(decoder, full_path); hr = d2d_res_->CreateBitmapDecoderFromFile(decoder, full_path);
@ -560,13 +549,13 @@ namespace kiwano
{ {
for (auto& file_path : full_paths) for (auto& file_path : full_paths)
{ {
if (!FileSystem::instance().IsFileExists(file_path)) if (!FileSystem::Instance().IsFileExists(file_path))
{ {
KGE_WARN(L"Font file '%s' not found!", file_path.c_str()); KGE_WARN(L"Font file '%s' not found!", file_path.c_str());
hr = E_FAIL; hr = E_FAIL;
} }
file_path = FileSystem::instance().GetFullPathForFile(file_path); file_path = FileSystem::Instance().GetFullPathForFile(file_path);
} }
} }

View File

@ -52,21 +52,6 @@ namespace kiwano
* @{ * @{
*/ */
/**
* \~chinese
* @brief <EFBFBD>
*/
struct RenderConfig
{
Color clear_color; ///< 헌팁奈<ED8C81>
bool vsync; ///< 뉩殮谿꼍
RenderConfig(
Color clear_color = Color::Black,
bool vsync = true
);
};
/** /**
* \~chinese * \~chinese
@ -294,8 +279,6 @@ namespace kiwano
ID3DDeviceResources* GetD3DDeviceResources(); ID3DDeviceResources* GetD3DDeviceResources();
public: public:
void Init(RenderConfig const& config);
void SetupComponent() override; void SetupComponent() override;
void DestroyComponent() override; void DestroyComponent() override;

View File

@ -70,7 +70,7 @@ namespace kiwano
StrokeStyle StrokeStyle::Create(CapStyle cap, LineJoinStyle line_join, const float* dash_array, size_t dash_size, float dash_offset) StrokeStyle StrokeStyle::Create(CapStyle cap, LineJoinStyle line_join, const float* dash_array, size_t dash_size, float dash_offset)
{ {
StrokeStyle stroke_style; StrokeStyle stroke_style;
Renderer::instance().CreateStrokeStyle(stroke_style, cap, line_join, dash_array, dash_size, dash_offset); Renderer::Instance().CreateStrokeStyle(stroke_style, cap, line_join, dash_array, dash_size, dash_offset);
return stroke_style; return stroke_style;
} }

View File

@ -42,12 +42,12 @@ namespace kiwano
if (!text_format_ || (dirty_flag_ & DirtyFlag::DirtyFormat)) if (!text_format_ || (dirty_flag_ & DirtyFlag::DirtyFormat))
{ {
Renderer::instance().CreateTextFormat(*this); Renderer::Instance().CreateTextFormat(*this);
} }
if (dirty_flag_ & DirtyFlag::DirtyLayout) if (dirty_flag_ & DirtyFlag::DirtyLayout)
{ {
Renderer::instance().CreateTextLayout(*this); Renderer::Instance().CreateTextLayout(*this);
if (text_layout_) if (text_layout_)
{ {

View File

@ -36,13 +36,13 @@ namespace kiwano
bool Texture::Load(String const& file_path) bool Texture::Load(String const& file_path)
{ {
Renderer::instance().CreateTexture(*this, file_path); Renderer::Instance().CreateTexture(*this, file_path);
return IsValid(); return IsValid();
} }
bool Texture::Load(Resource const& res) bool Texture::Load(Resource const& res)
{ {
Renderer::instance().CreateTexture(*this, res); Renderer::Instance().CreateTexture(*this, res);
return IsValid(); return IsValid();
} }

View File

@ -55,7 +55,7 @@ namespace kiwano
bool ResourceCache::LoadFromJsonFile(String const& file_path) bool ResourceCache::LoadFromJsonFile(String const& file_path)
{ {
if (!FileSystem::instance().IsFileExists(file_path)) if (!FileSystem::Instance().IsFileExists(file_path))
{ {
KGE_ERROR(L"ResourceCache::LoadFromJsonFile failed: File not found."); KGE_ERROR(L"ResourceCache::LoadFromJsonFile failed: File not found.");
return false; return false;
@ -67,7 +67,7 @@ namespace kiwano
try try
{ {
String full_path = FileSystem::instance().GetFullPathForFile(file_path); String full_path = FileSystem::Instance().GetFullPathForFile(file_path);
ifs.open(full_path.c_str()); ifs.open(full_path.c_str());
ifs >> json_data; ifs >> json_data;
ifs.close(); ifs.close();
@ -115,13 +115,13 @@ namespace kiwano
bool ResourceCache::LoadFromXmlFile(String const& file_path) bool ResourceCache::LoadFromXmlFile(String const& file_path)
{ {
if (!FileSystem::instance().IsFileExists(file_path)) if (!FileSystem::Instance().IsFileExists(file_path))
{ {
KGE_ERROR(L"ResourceCache::LoadFromXmlFile failed: File not found."); KGE_ERROR(L"ResourceCache::LoadFromXmlFile failed: File not found.");
return false; return false;
} }
String full_path = FileSystem::instance().GetFullPathForFile(file_path); String full_path = FileSystem::Instance().GetFullPathForFile(file_path);
pugi::xml_document doc; pugi::xml_document doc;
pugi::xml_parse_result result = doc.load_file(full_path.c_str(), pugi::parse_default, pugi::encoding_auto); pugi::xml_parse_result result = doc.load_file(full_path.c_str(), pugi::parse_default, pugi::encoding_auto);