Skip to content

Borderless Fullscreen Implementation #26

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion LuaSTG/Core/Graphics/Window.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ namespace Core::Graphics
virtual float getDPIScaling() = 0;

virtual void setWindowMode(Vector2U size) = 0;
virtual void setFullScreenMode() = 0;
virtual void setExclusiveFullScreenMode() = 0;
virtual void setBorderlessFullScreenMode() = 0;

virtual uint32_t getMonitorCount() = 0;
virtual RectI getMonitorRect(uint32_t index) = 0;
Expand Down
62 changes: 61 additions & 1 deletion LuaSTG/Core/Graphics/Window_Win32.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ constexpr int const LUASTG_WM_RECREATE = LUASTG_WM_UPDAE_TITLE + 1;
constexpr int const LUASTG_WM_SETICON = LUASTG_WM_RECREATE + 1;
constexpr int const LUASTG_WM_SET_WINDOW_MODE = LUASTG_WM_SETICON + 1;
constexpr int const LUASTG_WM_SET_FULLSCREEN_MODE = LUASTG_WM_SET_WINDOW_MODE + 1;
constexpr int const LUASTG_WM_SET_BORDERLESS_FULLSCREEN_MODE = LUASTG_WM_SET_FULLSCREEN_MODE + 1;

namespace Core::Graphics
{
Expand Down Expand Up @@ -238,6 +239,9 @@ namespace Core::Graphics
case LUASTG_WM_SET_WINDOW_MODE:
_setWindowMode(Vector2U(LOWORD(arg1), HIWORD(arg1)), arg2);
return 0;
case LUASTG_WM_SET_BORDERLESS_FULLSCREEN_MODE:
_setBorderlessFullscreenMode();
return 0;
case LUASTG_WM_SET_FULLSCREEN_MODE:
_setFullScreenMode();
return 0;
Expand Down Expand Up @@ -420,6 +424,58 @@ namespace Core::Graphics
assert(set_placement_result); (void)set_placement_result;
}
}
void Window_Win32::_setBorderlessFullscreenMode()
{
HMONITOR win32_monitor = MonitorFromWindow(win32_window, MONITOR_DEFAULTTONEAREST);
assert(win32_monitor);
MONITORINFO monitor_info = {};
monitor_info.cbSize = sizeof(monitor_info);
BOOL const get_monitor_info_result = GetMonitorInfoW(win32_monitor, &monitor_info);
assert(get_monitor_info_result); (void)get_monitor_info_result;
assert(monitor_info.rcMonitor.right > monitor_info.rcMonitor.left);
assert(monitor_info.rcMonitor.bottom > monitor_info.rcMonitor.top);

// RECT rect = { 0, 0, (int32_t)size.x, (int32_t)size.y };
// Platform::HighDPI::AdjustWindowRectExForDpi(
// &rect, WS_OVERLAPPEDWINDOW, FALSE, 0,
// Platform::HighDPI::GetDpiForWindow(win32_window));

//m_ignore_size_message = TRUE;
SetLastError(0);
SetWindowLongPtrW(win32_window, GWL_STYLE, WS_POPUP);
DWORD const set_style_result = GetLastError();
assert(set_style_result == 0); (void)set_style_result;
//SetLastError(0);
//SetWindowLongPtrW(win32_window, GWL_EXSTYLE, 0);
//DWORD const set_style_ex_result = GetLastError();
//assert(set_style_ex_result == 0); (void)set_style_ex_result;
//m_ignore_size_message = FALSE;

BOOL const set_window_pos_result = SetWindowPos(
win32_window,
HWND_NOTOPMOST,
monitor_info.rcMonitor.left,
monitor_info.rcMonitor.top,
monitor_info.rcMonitor.right - monitor_info.rcMonitor.left,
monitor_info.rcMonitor.bottom - monitor_info.rcMonitor.top,
SWP_FRAMECHANGED | SWP_SHOWWINDOW);
assert(set_window_pos_result); (void)set_window_pos_result;

RECT client_rect = {};
BOOL get_client_rect_result = GetClientRect(win32_window, &client_rect);
assert(get_client_rect_result); (void)get_client_rect_result;

m_framestyle = WindowFrameStyle::None;
m_fullscreen_mode = false;
win32_window_style = WS_POPUP;
win32_window_style_ex = 0;
win32_window_width = UINT(monitor_info.rcMonitor.right - monitor_info.rcMonitor.left);
win32_window_height = UINT(monitor_info.rcMonitor.bottom - monitor_info.rcMonitor.top);

EventData event_data{};
event_data.window_fullscreen_state = false;
dispatchEvent(EventType::WindowFullscreenStateChange, event_data);
}
void Window_Win32::_setFullScreenMode()
{
if (!m_fullscreen_mode)
Expand Down Expand Up @@ -787,10 +843,14 @@ namespace Core::Graphics
{
SendMessageW(win32_window, LUASTG_WM_SET_WINDOW_MODE, MAKEWPARAM(size.x, size.y), FALSE);
}
void Window_Win32::setFullScreenMode()
void Window_Win32::setExclusiveFullScreenMode()
{
SendMessageW(win32_window, LUASTG_WM_SET_FULLSCREEN_MODE, 0, 0);
}
void Window_Win32::setBorderlessFullScreenMode()
{
SendMessageW(win32_window, LUASTG_WM_SET_BORDERLESS_FULLSCREEN_MODE, 0, 0);
}

uint32_t Window_Win32::getMonitorCount()
{
Expand Down
4 changes: 3 additions & 1 deletion LuaSTG/Core/Graphics/Window_Win32.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ namespace Core::Graphics
bool recreateWindow();
void _toggleFullScreenMode();
void _setWindowMode(Vector2U size, bool ignore_size);
void _setBorderlessFullscreenMode();
void _setFullScreenMode();

void implSetApplicationModel(IApplicationModel* p_framework) { m_framework = p_framework; }
Expand Down Expand Up @@ -137,7 +138,8 @@ namespace Core::Graphics
float getDPIScaling();

void setWindowMode(Vector2U size);
void setFullScreenMode();
void setExclusiveFullScreenMode();
void setBorderlessFullScreenMode();

uint32_t getMonitorCount();
RectI getMonitorRect(uint32_t index);
Expand Down
6 changes: 4 additions & 2 deletions LuaSTG/LuaSTG/AppFrame.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,10 +169,12 @@ namespace LuaSTGPlus

// 以窗口模式显示
// 当 monitor_rect 为空矩形时,窗口自动挑选最近的显示器来居中,否则根据显示器矩形选择匹配的显示器居中
bool SetDisplayModeWindow(Core::Vector2U window_size, bool vsync, Core::RectI monitor_rect, bool borderless);
// bool SetDisplayModeWindow(Core::Vector2U window_size, bool vsync, Core::RectI monitor_rect, bool borderless);
bool SetDisplayModeWindow(Core::Vector2U window_size, bool vsync, uint32_t monitor_idx, bool borderless);

// 以全屏无边框窗口显示
bool SetDisplayModeFullscreen(Core::RectI monitor_rect, bool vsync);
// bool SetDisplayModeFullscreen(Core::RectI monitor_rect, bool vsync);
bool SetDisplayModeBorderlessFullscreen(Core::Vector2U window_size, uint32_t monitor_idx, bool vsync);

// 以独占全屏显示
// 当 refresh_rate 为全 0 时,自动选择合适的匹配的刷新率
Expand Down
137 changes: 104 additions & 33 deletions LuaSTG/LuaSTG/AppFrameDisplayMode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,37 @@ namespace LuaSTGPlus
spdlog::error("[luastg] 显示模式切换失败:{} -> {}", getFullscreenTypeString(from_mode), to_mode);
}

bool AppFrame::SetDisplayModeWindow(Core::Vector2U window_size, bool vsync, Core::RectI monitor_rect, bool borderless)
// bool AppFrame::SetDisplayModeWindow(Core::Vector2U window_size, bool vsync, Core::RectI monitor_rect, bool borderless)
// {
// auto* window = GetAppModel()->getWindow();
// auto* swapchain = GetAppModel()->getSwapChain();

// swapchain->setVSync(vsync);
// bool const result = swapchain->setCanvasSize(window_size);

// window->setWindowMode(window_size);
// if (!isRectEmpty(monitor_rect))
// {
// bool find_result = false;
// uint32_t const index = matchMonitorIndex(window, monitor_rect, find_result);
// std::ignore = find_result; // 对于窗口模式,即使找不到对应的显示器用于居中也无所谓
// window->setMonitorCentered(index);
// }
// if (!borderless)
// {
// window->setNativeIcon((void*)(ptrdiff_t)IDI_APPICON);
// }

// logResult(result, m_Setting, MODE_NAME_WINDOW);

// m_Setting.canvas_size = window_size;
// m_Setting.fullscreen = false;
// m_Setting.vsync = vsync;

// return result;
// }

bool AppFrame::SetDisplayModeWindow(Core::Vector2U window_size, bool vsync, uint32_t monitor_idx, bool borderless)
{
auto* window = GetAppModel()->getWindow();
auto* swapchain = GetAppModel()->getSwapChain();
Expand All @@ -84,13 +114,14 @@ namespace LuaSTGPlus
bool const result = swapchain->setCanvasSize(window_size);

window->setWindowMode(window_size);
if (!isRectEmpty(monitor_rect))
{
bool find_result = false;
uint32_t const index = matchMonitorIndex(window, monitor_rect, find_result);
std::ignore = find_result; // 对于窗口模式,即使找不到对应的显示器用于居中也无所谓
window->setMonitorCentered(index);
}
// if (!isRectEmpty(monitor_rect))
// {
// bool find_result = false;
// uint32_t const index = matchMonitorIndex(window, monitor_rect, find_result);
// std::ignore = find_result; // 对于窗口模式,即使找不到对应的显示器用于居中也无所谓
// window->setMonitorCentered(index);
// }
window->setMonitorCentered(monitor_idx);
if (!borderless)
{
window->setNativeIcon((void*)(ptrdiff_t)IDI_APPICON);
Expand All @@ -105,39 +136,78 @@ namespace LuaSTGPlus
return result;
}

bool AppFrame::SetDisplayModeFullscreen(Core::RectI monitor_rect, bool vsync)
// bool AppFrame::SetDisplayModeFullscreen(Core::RectI monitor_rect, bool vsync)
// {
// auto* window = GetAppModel()->getWindow();
// auto* swapchain = GetAppModel()->getSwapChain();

// if (isRectEmpty(monitor_rect))
// {
// // 对于全屏无边框窗口模式,显示器矩形为空,将会失败
// logResult(false, m_Setting, MODE_NAME_FULLSCREEN);
// return false;
// }

// bool find_result = false;
// uint32_t const index = matchMonitorIndex(window, monitor_rect, find_result);
// if (!find_result)
// {
// // 对于全屏无边框窗口模式,如果找不到对应的显示器,将会失败
// logResult(find_result, m_Setting, MODE_NAME_FULLSCREEN);
// return false;
// }
// Core::Vector2I const window_size = getMonitorSize(window, index);

// auto const size = Core::Vector2U(uint32_t(window_size.x), uint32_t(window_size.y));

// swapchain->setVSync(vsync);
// bool const result = swapchain->setCanvasSize(size);

// window->setFullScreenMode();
// window->setMonitorFullScreen(index);

// logResult(result, m_Setting, MODE_NAME_FULLSCREEN);

// m_Setting.canvas_size = size;
// m_Setting.fullscreen = true;
// m_Setting.vsync = vsync;

// return result;
// }

bool AppFrame::SetDisplayModeBorderlessFullscreen(Core::Vector2U window_size, uint32_t monitor_idx, bool vsync)
{
auto* window = GetAppModel()->getWindow();
auto* swapchain = GetAppModel()->getSwapChain();

if (isRectEmpty(monitor_rect))
{
// 对于全屏无边框窗口模式,显示器矩形为空,将会失败
logResult(false, m_Setting, MODE_NAME_FULLSCREEN);
return false;
}

bool find_result = false;
uint32_t const index = matchMonitorIndex(window, monitor_rect, find_result);
if (!find_result)
{
// 对于全屏无边框窗口模式,如果找不到对应的显示器,将会失败
logResult(find_result, m_Setting, MODE_NAME_FULLSCREEN);
return false;
}
Core::Vector2I const window_size = getMonitorSize(window, index);

auto const size = Core::Vector2U(uint32_t(window_size.x), uint32_t(window_size.y));
// if (isRectEmpty(monitor_rect))
// {
// // 对于全屏无边框窗口模式,显示器矩形为空,将会失败
// logResult(false, m_Setting, MODE_NAME_FULLSCREEN);
// return false;
// }

// bool find_result = false;
// uint32_t const index = matchMonitorIndex(window, monitor_rect, find_result);
// if (!find_result)
// {
// // 对于全屏无边框窗口模式,如果找不到对应的显示器,将会失败
// logResult(find_result, m_Setting, MODE_NAME_FULLSCREEN);
// return false;
// }
Core::Vector2I const monitor_size = getMonitorSize(window, monitor_idx);

// auto const size = Core::Vector2U(uint32_t(window_size.x), uint32_t(window_size.y));

swapchain->setVSync(vsync);
bool const result = swapchain->setCanvasSize(size);
bool const result = swapchain->setCanvasSize(window_size);

window->setFullScreenMode();
window->setMonitorFullScreen(index);
window->setBorderlessFullScreenMode();
window->setMonitorFullScreen(monitor_idx);

logResult(result, m_Setting, MODE_NAME_FULLSCREEN);

m_Setting.canvas_size = size;
m_Setting.canvas_size = window_size;
m_Setting.fullscreen = true;
m_Setting.vsync = vsync;

Expand All @@ -154,7 +224,7 @@ namespace LuaSTGPlus
bool const result = swapchain->setCanvasSize(window_size);

window->setWindowMode(window_size);
window->setFullScreenMode();
window->setExclusiveFullScreenMode();

logResult(result, m_Setting, MODE_NAME_FULLSCREEN);

Expand All @@ -176,7 +246,8 @@ namespace LuaSTGPlus
return SetDisplayModeWindow(
m_Setting.canvas_size,
m_Setting.vsync,
Core::RectI(),
// Core::RectI(),
0,
false);
}

Expand Down
46 changes: 45 additions & 1 deletion LuaSTG/LuaSTG/LuaBinding/LW_LuaSTG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ void LuaSTGPlus::BuiltInFunctionWrapper::Register(lua_State* L)noexcept

if (windowed)
{
bool const result = LAPP.SetDisplayModeWindow(size, vsync, Core::RectI(), false);
bool const result = LAPP.SetDisplayModeWindow(size, vsync, 0, false);
lua_pushboolean(L, result);
}
else
Expand All @@ -129,6 +129,47 @@ void LuaSTGPlus::BuiltInFunctionWrapper::Register(lua_State* L)noexcept

return 1;
}
static int VideoModeWindowed(lua_State* L)noexcept
{
uint32_t const width = (uint32_t)luaL_checkinteger(L, 1);
uint32_t const height = (uint32_t)luaL_checkinteger(L, 2);
bool const vsync = lua_toboolean(L, 3);
uint32_t const monitor = (uint32_t)luaL_optinteger(L, 4, 0);

auto const size = Core::Vector2U(width, height);

bool const result = LAPP.SetDisplayModeWindow(size, vsync, monitor, false);
lua_pushboolean(L, result);

return 1;
}
static int VideoModeFSExclusive(lua_State* L)noexcept
{
uint32_t const width = (uint32_t)luaL_checkinteger(L, 1);
uint32_t const height = (uint32_t)luaL_checkinteger(L, 2);
bool const vsync = lua_toboolean(L, 3);

auto const size = Core::Vector2U(width, height);

bool const result = LAPP.SetDisplayModeExclusiveFullscreen(size, vsync, 60);
lua_pushboolean(L, result);

return 1;
}
static int VideoModeFSBorderless(lua_State* L)noexcept
{
uint32_t const width = (uint32_t)luaL_checkinteger(L, 1);
uint32_t const height = (uint32_t)luaL_checkinteger(L, 2);
bool const vsync = lua_toboolean(L, 3);
uint32_t const monitor = (uint32_t)luaL_optinteger(L, 4, 0);

auto const size = Core::Vector2U(width, height);

bool const result = LAPP.SetDisplayModeBorderlessFullscreen(size, monitor, vsync);
lua_pushboolean(L, result);

return 1;
}
static int EnumResolutions(lua_State* L)
{
lua_createtable(L, 5, 0); // t
Expand Down Expand Up @@ -225,6 +266,9 @@ void LuaSTGPlus::BuiltInFunctionWrapper::Register(lua_State* L)noexcept

#pragma region 窗口与交换链控制函数
{ "ChangeVideoMode", &WrapperImplement::ChangeVideoMode },
{ "VideoModeWindowed", &WrapperImplement::VideoModeWindowed },
{ "VideoModeFSExclusive", &WrapperImplement::VideoModeFSExclusive },
{ "VideoModeFSBorderless", &WrapperImplement::VideoModeFSBorderless },
{ "EnumResolutions", &WrapperImplement::EnumResolutions },
{ "EnumGPUs", &WrapperImplement::EnumGPUs },
{ "ChangeGPU", &WrapperImplement::ChangeGPU },
Expand Down