Magic_Game/src/core/window.cpp

298 lines
7.4 KiB
C++
Raw Normal View History

// Copyright (c) 2016-2018 Easy2D - 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 "window.h"
#include "render.h"
2018-11-15 17:59:18 +08:00
#include "logs.h"
#include "../math/scalar.hpp"
2019-01-25 01:45:03 +08:00
#define WINDOW_STYLE WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX
#define WINDOW_FULLSCREEN_STYLE WS_CLIPCHILDREN | WS_POPUP
#define E2D_WND_CLASS_NAME L"Easy2DAppWnd"
namespace easy2d
{
2018-11-12 20:46:54 +08:00
namespace
{
2018-11-12 20:46:54 +08:00
void GetContentScale(float* scale_x, float* scale_y);
2019-01-25 01:45:03 +08:00
void AdjustWindow(UINT width, UINT height, DWORD style, float scalex, float scaley, UINT* win_width, UINT* win_height);
2018-11-12 20:46:54 +08:00
}
2019-01-24 12:21:01 +08:00
Window::Window()
2018-11-12 20:46:54 +08:00
: handle(nullptr)
, scale_x(1.f)
, scale_y(1.f)
{
}
2019-01-24 12:21:01 +08:00
Window::~Window()
2018-11-12 20:46:54 +08:00
{
E2D_LOG(L"Destroying window");
2018-11-12 20:46:54 +08:00
}
2019-01-25 01:45:03 +08:00
HRESULT Window::Init(String title, int width, int height, LPCWSTR icon, bool fullscreen, WNDPROC proc, bool debug)
2018-11-12 20:46:54 +08:00
{
E2D_LOG(L"Creating window");
2019-01-25 01:45:03 +08:00
2018-11-12 20:46:54 +08:00
HINSTANCE hinstance = GetModuleHandle(nullptr);
WNDCLASSEX wcex = { 0 };
wcex.cbSize = sizeof(WNDCLASSEX);
2019-01-25 01:45:03 +08:00
wcex.lpszClassName = E2D_WND_CLASS_NAME;
wcex.style = CS_HREDRAW | CS_VREDRAW /* | CS_DBLCLKS */;
wcex.lpfnWndProc = proc;
2018-11-12 20:46:54 +08:00
wcex.hIcon = nullptr;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = sizeof(LONG_PTR);
wcex.hInstance = hinstance;
wcex.hbrBackground = nullptr;
wcex.lpszMenuName = nullptr;
wcex.hCursor = ::LoadCursor(nullptr, IDC_ARROW);
if (icon)
{
2019-01-25 01:45:03 +08:00
wcex.hIcon = (HICON)::LoadImageW(
hinstance,
2018-11-12 20:46:54 +08:00
icon,
IMAGE_ICON,
0,
0,
LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE
);
}
2019-01-24 12:21:01 +08:00
else
{
2019-01-25 01:45:03 +08:00
wcex.hIcon = ::LoadIconW(nullptr, IDI_APPLICATION);
2019-01-24 12:21:01 +08:00
}
2019-01-25 01:45:03 +08:00
::RegisterClassExW(&wcex);
int left = -1;
int top = -1;
HMONITOR monitor = nullptr;
MONITORINFOEX monitor_info_ex;
// Get the nearest monitor to this window
POINT anchor;
anchor.x = left;
anchor.y = top;
monitor = MonitorFromPoint(anchor, MONITOR_DEFAULTTOPRIMARY);
// Get the target monitor info
memset(&monitor_info_ex, 0, sizeof(MONITORINFOEX));
monitor_info_ex.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfoW(monitor, &monitor_info_ex);
2018-11-12 20:46:54 +08:00
GetContentScale(&scale_x, &scale_y);
2019-01-25 01:45:03 +08:00
if (fullscreen)
{
top = monitor_info_ex.rcMonitor.top;
left = monitor_info_ex.rcMonitor.left;
}
else
{
UINT screenw = monitor_info_ex.rcWork.right - monitor_info_ex.rcWork.left;
UINT screenh = monitor_info_ex.rcWork.bottom - monitor_info_ex.rcWork.top;
UINT win_width, win_height;
AdjustWindow(
width,
height,
fullscreen ? (WINDOW_FULLSCREEN_STYLE) : (WINDOW_STYLE),
scale_x,
scale_y,
&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;
}
if (width > monitor_info_ex.rcWork.right - left)
width = monitor_info_ex.rcWork.right - left;
if (height > monitor_info_ex.rcWork.bottom - top)
height = monitor_info_ex.rcWork.bottom - top;
if (fullscreen)
{
DEVMODE mode;
memset(&mode, 0, sizeof(mode));
mode.dmSize = sizeof(DEVMODE);
mode.dmBitsPerPel = fullscreen ? 32 : (::GetDeviceCaps(GetDC(0), BITSPIXEL));
mode.dmPelsWidth = width;
mode.dmPelsHeight = height;
mode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
if (DISP_CHANGE_SUCCESSFUL != ::ChangeDisplaySettingsExW(monitor_info_ex.szDevice, &mode, NULL, CDS_FULLSCREEN, NULL))
logs::Errorln(L"ChangeDisplaySettings failed");
}
2019-01-21 21:24:45 +08:00
handle = ::CreateWindowExW(
2019-01-25 01:45:03 +08:00
fullscreen ? (WS_EX_TOPMOST) : 0,
E2D_WND_CLASS_NAME,
2018-11-12 20:46:54 +08:00
title.c_str(),
2019-01-25 01:45:03 +08:00
fullscreen ? (WINDOW_FULLSCREEN_STYLE) : (WINDOW_STYLE),
left,
top,
width,
height,
2018-11-12 20:46:54 +08:00
nullptr,
nullptr,
hinstance,
2019-01-21 21:24:45 +08:00
nullptr
2018-11-12 20:46:54 +08:00
);
if (handle == nullptr)
{
2019-01-25 01:45:03 +08:00
::UnregisterClass(E2D_WND_CLASS_NAME, hinstance);
2018-11-21 19:24:18 +08:00
return HRESULT_FROM_WIN32(GetLastError());
}
2018-11-21 19:24:18 +08:00
return S_OK;
2018-11-12 20:46:54 +08:00
}
2019-01-24 12:21:01 +08:00
String Window::GetTitle() const
2018-11-12 20:46:54 +08:00
{
if (handle)
{
2018-11-12 20:46:54 +08:00
wchar_t title[256];
GetWindowTextW(handle, title, 256);
return title;
}
2019-01-21 21:24:45 +08:00
return String();
2018-11-12 20:46:54 +08:00
}
2019-01-24 12:21:01 +08:00
void Window::SetTitle(String const& title)
2018-11-12 20:46:54 +08:00
{
if (handle)
::SetWindowText(handle, title.c_str());
}
2019-01-24 12:21:01 +08:00
Size Window::GetSize() const
2018-11-12 20:46:54 +08:00
{
if (handle)
{
2018-11-12 20:46:54 +08:00
RECT rect;
GetClientRect(handle, &rect);
2019-01-21 21:24:45 +08:00
return Size{
2018-11-12 20:46:54 +08:00
static_cast<float>(rect.right - rect.left),
static_cast<float>(rect.bottom - rect.top)
2019-01-21 21:24:45 +08:00
};
}
2019-01-21 21:24:45 +08:00
return Size{};
2018-11-12 20:46:54 +08:00
}
2019-01-24 12:21:01 +08:00
float Window::GetWidth() const
2018-11-12 20:46:54 +08:00
{
2018-11-25 15:00:15 +08:00
return GetSize().x;
2018-11-12 20:46:54 +08:00
}
2019-01-24 12:21:01 +08:00
float Window::GetHeight() const
2018-11-12 20:46:54 +08:00
{
2018-11-25 15:00:15 +08:00
return GetSize().y;
2018-11-12 20:46:54 +08:00
}
2019-01-24 12:21:01 +08:00
void Window::SetIcon(LPCWSTR icon_resource)
2018-11-12 20:46:54 +08:00
{
if (handle)
{
2018-11-12 20:46:54 +08:00
HINSTANCE hinstance = GetModuleHandle(nullptr);
HICON icon = (HICON)::LoadImage(
hinstance,
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);
}
2018-11-12 20:46:54 +08:00
}
2019-01-24 12:21:01 +08:00
HWND Window::GetHandle() const
2018-11-12 20:46:54 +08:00
{
return handle;
}
2019-01-24 12:21:01 +08:00
float Window::GetContentScaleX() const
2018-11-12 20:46:54 +08:00
{
return scale_x;
}
2019-01-24 12:21:01 +08:00
float Window::GetContentScaleY() const
2018-11-12 20:46:54 +08:00
{
return scale_y;
}
2019-01-24 12:21:01 +08:00
void Window::Destroy()
2018-11-22 19:31:44 +08:00
{
if (handle)
::DestroyWindow(handle);
}
2018-11-12 20:46:54 +08:00
namespace
{
void GetContentScale(float* scale_x, float* scale_y)
{
2018-11-12 20:46:54 +08:00
const float DEFAULT_SCREEN_DPI = 96.f;
const HDC dc = GetDC(NULL);
float xdpi = static_cast<float>(GetDeviceCaps(dc, LOGPIXELSX));
float ydpi = static_cast<float>(GetDeviceCaps(dc, LOGPIXELSY));
ReleaseDC(NULL, dc);
if (scale_x)
*scale_x = xdpi / DEFAULT_SCREEN_DPI;
if (scale_y)
*scale_y = ydpi / DEFAULT_SCREEN_DPI;
}
2019-01-25 01:45:03 +08:00
void AdjustWindow(UINT width, UINT height, DWORD style, float scalex, float scaley, UINT* win_width, UINT* win_height)
{
2019-01-25 01:45:03 +08:00
RECT rc;
::SetRect(&rc, 0, 0, (int)math::Ceil(width * scalex), (int)math::Ceil(height * scaley));
::AdjustWindowRect(&rc, style, false);
*win_width = rc.right - rc.left;
*win_height = rc.bottom - rc.top;
HMONITOR monitor = ::MonitorFromWindow(NULL, MONITOR_DEFAULTTONEAREST);
MONITORINFO monitor_info;
::memset(&monitor_info, 0, sizeof(MONITORINFO));
monitor_info.cbSize = sizeof(MONITORINFO);
::GetMonitorInfoW(monitor, &monitor_info);
long max_width = monitor_info.rcWork.right - monitor_info.rcWork.left;
long max_height = monitor_info.rcWork.bottom - monitor_info.rcWork.top;
if (*win_width > static_cast<UINT>(max_width))
*win_width = max_width;
if (*win_height > static_cast<UINT>(max_height))
*win_height = max_height;
}
}
2018-11-12 20:46:54 +08:00
}