commit
						3885c44938
					
				|  | @ -45,6 +45,7 @@ private: | ||||||
| }  // namespace
 | }  // namespace
 | ||||||
| 
 | 
 | ||||||
| DebugActor::DebugActor() | DebugActor::DebugActor() | ||||||
|  |     : frame_buffer_(70 /* pre-alloc for 70 frames */) | ||||||
| { | { | ||||||
|     SetName("kiwano-debug-actor"); |     SetName("kiwano-debug-actor"); | ||||||
|     SetPosition(Point{ 10, 10 }); |     SetPosition(Point{ 10, 10 }); | ||||||
|  | @ -77,10 +78,10 @@ void DebugActor::OnRender(RenderContext& ctx) | ||||||
|     ctx.FillRoundedRectangle(GetBounds(), Vec2{ 5.f, 5.f }); |     ctx.FillRoundedRectangle(GetBounds(), Vec2{ 5.f, 5.f }); | ||||||
|     ctx.DrawTextLayout(debug_text_, Point(10, 10)); |     ctx.DrawTextLayout(debug_text_, Point(10, 10)); | ||||||
| 
 | 
 | ||||||
|     frame_time_.push_back(Time::Now()); |     frame_buffer_.PushBack(Time::Now()); | ||||||
|     while (frame_time_.back() - frame_time_.front() >= Duration::Second) |     while (frame_buffer_.Back() - frame_buffer_.Front() >= Duration::Second) | ||||||
|     { |     { | ||||||
|         frame_time_.erase(frame_time_.begin()); |         frame_buffer_.PopFront(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -93,7 +94,7 @@ void DebugActor::OnUpdate(Duration dt) | ||||||
|     // For formatting integers with commas
 |     // For formatting integers with commas
 | ||||||
|     (void)ss.imbue(comma_locale_); |     (void)ss.imbue(comma_locale_); | ||||||
| 
 | 
 | ||||||
|     ss << "Fps: " << frame_time_.size() << std::endl; |     ss << "Fps: " << frame_buffer_.Size() << std::endl; | ||||||
| 
 | 
 | ||||||
| #if defined(KGE_DEBUG) | #if defined(KGE_DEBUG) | ||||||
|     if (ObjectBase::IsTracingLeaks()) |     if (ObjectBase::IsTracingLeaks()) | ||||||
|  | @ -106,7 +107,7 @@ void DebugActor::OnUpdate(Duration dt) | ||||||
| 
 | 
 | ||||||
|     ss << "Render: " << status.duration.Milliseconds() << "ms" << std::endl; |     ss << "Render: " << status.duration.Milliseconds() << "ms" << std::endl; | ||||||
| 
 | 
 | ||||||
|     ss << "Primitives / sec: " << std::fixed << status.primitives * frame_time_.size() << std::endl; |     ss << "Primitives / sec: " << std::fixed << status.primitives * frame_buffer_.Size() << std::endl; | ||||||
| 
 | 
 | ||||||
|     ss << "Memory: "; |     ss << "Memory: "; | ||||||
|     { |     { | ||||||
|  |  | ||||||
|  | @ -24,6 +24,99 @@ | ||||||
| 
 | 
 | ||||||
| namespace kiwano | namespace kiwano | ||||||
| { | { | ||||||
|  | 
 | ||||||
|  | template <typename T> | ||||||
|  | class SimpleRingBuffer | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |     SimpleRingBuffer(size_t capcity) | ||||||
|  |     { | ||||||
|  |         Reserve(capcity); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void PushBack(const T& val) | ||||||
|  |     { | ||||||
|  |         if (IsFull()) | ||||||
|  |             Reserve(Capacity() * 2); | ||||||
|  |         buffer_[rear_] = val; | ||||||
|  |         IncreaseRear(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void PopFront() | ||||||
|  |     { | ||||||
|  |         IncreaseFront(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const T& Front() const | ||||||
|  |     { | ||||||
|  |         return buffer_[front_]; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     T& Front() | ||||||
|  |     { | ||||||
|  |         return buffer_[front_]; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const T& Back() const | ||||||
|  |     { | ||||||
|  |         return buffer_[ClampCursor(rear_, 1)]; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     T& Back() | ||||||
|  |     { | ||||||
|  |         return buffer_[ClampCursor(rear_, 1)]; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     bool IsEmpty() const noexcept | ||||||
|  |     { | ||||||
|  |         return front_ = rear_; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     bool IsFull() const noexcept | ||||||
|  |     { | ||||||
|  |         return front_ == (rear_ + 1) % Capacity(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     size_t Size() const | ||||||
|  |     { | ||||||
|  |         return ClampCursor(rear_, front_); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     size_t Capacity() const | ||||||
|  |     { | ||||||
|  |         return buffer_.size(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void Reserve(size_t capacity) | ||||||
|  |     { | ||||||
|  |         buffer_.resize(capacity); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     void IncreaseFront() | ||||||
|  |     { | ||||||
|  |         if (buffer_.empty()) | ||||||
|  |             return; | ||||||
|  |         front_ = (front_ + 1) % Capacity(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void IncreaseRear() | ||||||
|  |     { | ||||||
|  |         rear_ = (rear_ + 1) % Capacity(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     size_t ClampCursor(size_t cursor, size_t off) const | ||||||
|  |     { | ||||||
|  |         return (cursor + Capacity() - off) % Capacity(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     Vector<T> buffer_; | ||||||
|  |     size_t    front_ = 0; | ||||||
|  |     size_t    rear_  = 0; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * \addtogroup Actors |  * \addtogroup Actors | ||||||
|  * @{ |  * @{ | ||||||
|  | @ -52,7 +145,8 @@ private: | ||||||
|     BrushPtr    background_brush_; |     BrushPtr    background_brush_; | ||||||
|     TextStyle   debug_text_style_; |     TextStyle   debug_text_style_; | ||||||
|     TextLayout  debug_text_; |     TextLayout  debug_text_; | ||||||
|     List<Time>  frame_time_; | 
 | ||||||
|  |     SimpleRingBuffer<Time> frame_buffer_; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /** @} */ | /** @} */ | ||||||
|  |  | ||||||
|  | @ -82,8 +82,7 @@ void Runner::InitSettings() | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Create game window
 |     // Create game window
 | ||||||
|     WindowPtr window = Window::Create(settings_.title, settings_.width, settings_.height, settings_.icon, |     WindowPtr window = Window::Create(settings_.window); | ||||||
|                                       settings_.resizable, settings_.fullscreen); |  | ||||||
|     SetWindow(window); |     SetWindow(window); | ||||||
| 
 | 
 | ||||||
|     // Update renderer settings
 |     // Update renderer settings
 | ||||||
|  | @ -131,9 +130,9 @@ bool Runner::MainLoop(Duration dt) | ||||||
|         app.DispatchEvent(evt.Get()); |         app.DispatchEvent(evt.Get()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Update frame ticker
 |  | ||||||
|     if (frame_ticker_) |     if (frame_ticker_) | ||||||
|     { |     { | ||||||
|  |         // Update frame ticker
 | ||||||
|         if (frame_ticker_->Tick(dt)) |         if (frame_ticker_->Tick(dt)) | ||||||
|         { |         { | ||||||
|             app.UpdateFrame(frame_ticker_->GetDeltaTime()); |             app.UpdateFrame(frame_ticker_->GetDeltaTime()); | ||||||
|  |  | ||||||
|  | @ -40,25 +40,14 @@ KGE_DECLARE_SMART_PTR(Runner); | ||||||
|  */ |  */ | ||||||
| struct Settings | struct Settings | ||||||
| { | { | ||||||
|     uint32_t width;           ///< 窗口宽度
 |     WindowConfig window;          ///< ´°¿ÚÉèÖÃ
 | ||||||
|     uint32_t height;          ///< 窗口高度
 |     Color        bg_color;        ///< ±³¾°É«
 | ||||||
|     String   title;           ///< 窗口标题
 |     Duration     frame_interval;  ///< Ö¡¼ä¸ô
 | ||||||
|     Icon     icon;            ///< 窗口图标
 |     bool         vsync_enabled;   ///< ´¹Ö±Í¬²½
 | ||||||
|     bool     resizable;       ///< 窗口大小可调整
 |     bool         debug_mode;      ///< µ÷ÊÔģʽ
 | ||||||
|     bool     fullscreen;      ///< 窗口全屏
 |  | ||||||
|     Color    bg_color;        ///< 窗口背景色
 |  | ||||||
|     Duration frame_interval;  ///< 帧间隔
 |  | ||||||
|     bool     vsync_enabled;   ///< 垂直同步
 |  | ||||||
|     bool     debug_mode;      ///< 调试模式
 |  | ||||||
| 
 | 
 | ||||||
|     Settings() |     Settings() | ||||||
|         : width(800) |         : bg_color(Color::Black) | ||||||
|         , height(600) |  | ||||||
|         , title("Kiwano") |  | ||||||
|         , icon() |  | ||||||
|         , resizable(false) |  | ||||||
|         , fullscreen(false) |  | ||||||
|         , bg_color(Color::Black) |  | ||||||
|         , frame_interval(0) |         , frame_interval(0) | ||||||
|         , vsync_enabled(true) |         , vsync_enabled(true) | ||||||
|         , debug_mode(false) |         , debug_mode(false) | ||||||
|  |  | ||||||
|  | @ -82,6 +82,21 @@ struct Icon | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * \~chinese | ||||||
|  |  * @brief 窗口设置 | ||||||
|  |  */ | ||||||
|  | struct WindowConfig | ||||||
|  | { | ||||||
|  |     uint32_t width  = 640;            ///< 窗口宽度
 | ||||||
|  |     uint32_t height = 480;            ///< 窗口高度
 | ||||||
|  |     String   title  = "Kiwano Game";  ///< 窗口标题
 | ||||||
|  |     Icon     icon;                    ///< 窗口图标
 | ||||||
|  |     bool     resizable  = false;      ///< 窗口大小可调整
 | ||||||
|  |     bool     fullscreen = false;      ///< 窗口全屏
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| #if defined(KGE_PLATFORM_WINDOWS) | #if defined(KGE_PLATFORM_WINDOWS) | ||||||
| typedef HWND WindowHandle; | typedef HWND WindowHandle; | ||||||
| #endif | #endif | ||||||
|  | @ -97,15 +112,10 @@ public: | ||||||
|     /**
 |     /**
 | ||||||
|      * \~chinese |      * \~chinese | ||||||
|      * @brief 初始化窗口 |      * @brief 初始化窗口 | ||||||
|      * @param title 标题 |      * @param config 窗口设置 | ||||||
|      * @param width 宽度 |  | ||||||
|      * @param height 高度 |  | ||||||
|      * @param icon 图标资源ID |  | ||||||
|      * @param resizable 窗口大小可拉伸 |  | ||||||
|      * @throw kiwano::SystemError 窗口创建失败时抛出 |      * @throw kiwano::SystemError 窗口创建失败时抛出 | ||||||
|      */ |      */ | ||||||
|     static WindowPtr Create(const String& title, uint32_t width, uint32_t height, Icon icon = Icon(), |     static WindowPtr Create(const WindowConfig& config); | ||||||
|                             bool resizable = false, bool fullscreen = false); |  | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * \~chinese |      * \~chinese | ||||||
|  |  | ||||||
|  | @ -49,7 +49,7 @@ public: | ||||||
| 
 | 
 | ||||||
|     virtual ~WindowWin32Impl(); |     virtual ~WindowWin32Impl(); | ||||||
| 
 | 
 | ||||||
|     void Init(const String& title, uint32_t width, uint32_t height, Icon icon, bool resizable, bool fullscreen); |     void Init(const WindowConfig& config); | ||||||
| 
 | 
 | ||||||
|     void SetTitle(const String& title) override; |     void SetTitle(const String& title) override; | ||||||
| 
 | 
 | ||||||
|  | @ -88,13 +88,12 @@ private: | ||||||
|     std::array<KeyCode, 256> key_map_; |     std::array<KeyCode, 256> key_map_; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| WindowPtr Window::Create(const String& title, uint32_t width, uint32_t height, Icon icon, bool resizable, | WindowPtr Window::Create(const WindowConfig& config) | ||||||
|                          bool fullscreen) |  | ||||||
| { | { | ||||||
|     WindowWin32ImplPtr ptr = memory::New<WindowWin32Impl>(); |     WindowWin32ImplPtr ptr = memory::New<WindowWin32Impl>(); | ||||||
|     if (ptr) |     if (ptr) | ||||||
|     { |     { | ||||||
|         ptr->Init(title, width, height, icon, resizable, fullscreen); |         ptr->Init(config); | ||||||
|     } |     } | ||||||
|     return ptr; |     return ptr; | ||||||
| } | } | ||||||
|  | @ -142,6 +141,28 @@ void AdjustWindow(uint32_t width, uint32_t height, DWORD style, uint32_t* win_wi | ||||||
|         *win_height = screenh; |         *win_height = screenh; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | HICON Icon2HIcon(const Icon& icon) | ||||||
|  | { | ||||||
|  |     HICON hicon = NULL; | ||||||
|  |     if (icon.resource_id != 0 && IS_INTRESOURCE(icon.resource_id)) | ||||||
|  |     { | ||||||
|  |         HINSTANCE hinstance = ::GetModuleHandle(nullptr); | ||||||
|  | 
 | ||||||
|  |         hicon = (HICON)::LoadImage(hinstance, MAKEINTRESOURCE(icon.resource_id), IMAGE_ICON, 0, 0, | ||||||
|  |                                    LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE); | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         String full_path = FileSystem::GetInstance().GetFullPathForFile(icon.file_path); | ||||||
|  |         if (!full_path.empty()) | ||||||
|  |         { | ||||||
|  |             hicon = (HICON)::LoadImageA(NULL, full_path.c_str(), IMAGE_ICON, 0, 0, | ||||||
|  |                                         LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return hicon; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| }  // namespace
 | }  // namespace
 | ||||||
| 
 | 
 | ||||||
| WindowWin32Impl::WindowWin32Impl() | WindowWin32Impl::WindowWin32Impl() | ||||||
|  | @ -206,16 +227,15 @@ WindowWin32Impl::~WindowWin32Impl() | ||||||
|     ::timeEndPeriod(0); |     ::timeEndPeriod(0); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void WindowWin32Impl::Init(const String& title, uint32_t width, uint32_t height, Icon icon, bool resizable, | void WindowWin32Impl::Init(const WindowConfig& config) | ||||||
|                            bool fullscreen) |  | ||||||
| { | { | ||||||
|     HINSTANCE  hinst   = GetModuleHandle(nullptr); |     HINSTANCE   hinst  = GetModuleHandle(nullptr); | ||||||
|     WNDCLASSEXA wcex   = { 0 }; |     WNDCLASSEXA wcex   = { 0 }; | ||||||
|     wcex.cbSize        = sizeof(WNDCLASSEX); |     wcex.cbSize        = sizeof(WNDCLASSEX); | ||||||
|     wcex.lpszClassName = "KiwanoAppWnd"; |     wcex.lpszClassName = "KiwanoAppWnd"; | ||||||
|     wcex.style         = CS_HREDRAW | CS_VREDRAW /* | CS_DBLCLKS */; |     wcex.style         = CS_HREDRAW | CS_VREDRAW /* | CS_DBLCLKS */; | ||||||
|     wcex.lpfnWndProc   = WindowWin32Impl::StaticWndProc; |     wcex.lpfnWndProc   = WindowWin32Impl::StaticWndProc; | ||||||
|     wcex.hIcon         = nullptr; |     wcex.hIcon         = Icon2HIcon(config.icon); | ||||||
|     wcex.cbClsExtra    = 0; |     wcex.cbClsExtra    = 0; | ||||||
|     wcex.cbWndExtra    = sizeof(LONG_PTR); |     wcex.cbWndExtra    = sizeof(LONG_PTR); | ||||||
|     wcex.hInstance     = hinst; |     wcex.hInstance     = hinst; | ||||||
|  | @ -223,21 +243,6 @@ void WindowWin32Impl::Init(const String& title, uint32_t width, uint32_t height, | ||||||
|     wcex.lpszMenuName  = nullptr; |     wcex.lpszMenuName  = nullptr; | ||||||
|     wcex.hCursor       = ::LoadCursor(hinst, IDC_ARROW); |     wcex.hCursor       = ::LoadCursor(hinst, IDC_ARROW); | ||||||
| 
 | 
 | ||||||
|     if (icon.resource_id != 0 && IS_INTRESOURCE(icon.resource_id)) |  | ||||||
|     { |  | ||||||
|         wcex.hIcon = (HICON)::LoadImage(hinst, MAKEINTRESOURCE(icon.resource_id), IMAGE_ICON, 0, 0, |  | ||||||
|                                         LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE); |  | ||||||
|     } |  | ||||||
|     else |  | ||||||
|     { |  | ||||||
|         String full_path = FileSystem::GetInstance().GetFullPathForFile(icon.file_path); |  | ||||||
|         if (!full_path.empty()) |  | ||||||
|         { |  | ||||||
|             wcex.hIcon = (HICON)::LoadImageA(NULL, full_path.c_str(), IMAGE_ICON, 0, 0, |  | ||||||
|                                              LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     ::RegisterClassExA(&wcex); |     ::RegisterClassExA(&wcex); | ||||||
| 
 | 
 | ||||||
|     // Get the nearest monitor to this window
 |     // Get the nearest monitor to this window
 | ||||||
|  | @ -256,21 +261,19 @@ void WindowWin32Impl::Init(const String& title, uint32_t width, uint32_t height, | ||||||
|     uint32_t screenh = monitor_info_ex.rcWork.bottom - monitor_info_ex.rcWork.top; |     uint32_t screenh = monitor_info_ex.rcWork.bottom - monitor_info_ex.rcWork.top; | ||||||
| 
 | 
 | ||||||
|     uint32_t win_width, win_height; |     uint32_t win_width, win_height; | ||||||
|     AdjustWindow(width, height, GetStyle(), &win_width, &win_height); |     AdjustWindow(config.width, config.height, GetStyle(), &win_width, &win_height); | ||||||
| 
 | 
 | ||||||
|     int left = monitor_info_ex.rcWork.left + (screenw - win_width) / 2; |     int left = monitor_info_ex.rcWork.left + (screenw - win_width) / 2; | ||||||
|     int top  = monitor_info_ex.rcWork.top + (screenh - win_height) / 2; |     int top  = monitor_info_ex.rcWork.top + (screenh - win_height) / 2; | ||||||
|     width  = win_width; |  | ||||||
|     height = win_height; |  | ||||||
| 
 | 
 | ||||||
|     width_         = width; |     width_         = win_width; | ||||||
|     height_        = height; |     height_        = win_height; | ||||||
|     resizable_     = resizable; |     resizable_     = config.resizable; | ||||||
|     is_fullscreen_ = fullscreen; |     is_fullscreen_ = config.fullscreen; | ||||||
|     resolution_    = Resolution{ width_, height_, 0 }; |     resolution_    = Resolution{ width_, height_, 0 }; | ||||||
| 
 | 
 | ||||||
|     handle_ = ::CreateWindowExA(0, "KiwanoAppWnd", title.c_str(), GetStyle(), left, top, width, height, nullptr, |     handle_ = ::CreateWindowExA(0, "KiwanoAppWnd", config.title.c_str(), GetStyle(), left, top, width_, height_, | ||||||
|                                 nullptr, hinst, nullptr); |                                 nullptr, nullptr, hinst, nullptr); | ||||||
| 
 | 
 | ||||||
|     if (handle_ == nullptr) |     if (handle_ == nullptr) | ||||||
|     { |     { | ||||||
|  | @ -321,24 +324,7 @@ void WindowWin32Impl::SetIcon(Icon icon) | ||||||
| { | { | ||||||
|     KGE_ASSERT(handle_); |     KGE_ASSERT(handle_); | ||||||
| 
 | 
 | ||||||
|     HICON hicon = NULL; |     HICON hicon = Icon2HIcon(icon); | ||||||
|     if (icon.resource_id != 0 && IS_INTRESOURCE(icon.resource_id)) |  | ||||||
|     { |  | ||||||
|         HINSTANCE hinstance = ::GetModuleHandle(nullptr); |  | ||||||
| 
 |  | ||||||
|         hicon = (HICON)::LoadImage(hinstance, MAKEINTRESOURCE(icon.resource_id), IMAGE_ICON, 0, 0, |  | ||||||
|                                    LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE); |  | ||||||
|     } |  | ||||||
|     else |  | ||||||
|     { |  | ||||||
|         String full_path = FileSystem::GetInstance().GetFullPathForFile(icon.file_path); |  | ||||||
|         if (!full_path.empty()) |  | ||||||
|         { |  | ||||||
|             hicon = (HICON)::LoadImageA(NULL, full_path.c_str(), IMAGE_ICON, 0, 0, |  | ||||||
|                                         LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     ::SendMessage(handle_, WM_SETICON, ICON_BIG, (LPARAM)hicon); |     ::SendMessage(handle_, WM_SETICON, ICON_BIG, (LPARAM)hicon); | ||||||
|     ::SendMessage(handle_, WM_SETICON, ICON_SMALL, (LPARAM)hicon); |     ::SendMessage(handle_, WM_SETICON, ICON_SMALL, (LPARAM)hicon); | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue