Есть ли изящный способ обработки переключения между полноэкранным и оконным режимами в приложении Windows OpenGL?
Мне интересно, можно ли переключаться между полноэкранным режимом и оконным режимом в окне OpenGL (я пишу для Windows с использованием С++ и win32) без разрушения контекста OpenGL и, следовательно, для перезагрузки активов (Текстуры, VBOs и т.д.) В процессе?
Это нежелательно, потому что он вводит задержку при переключении между полноэкранным и оконным режимами, потенциально длинным, а также облегчает вникновение в вещи, забывая повторно инициализировать что-то.
В качестве продолжения этого, есть ли определенные визуальные эффекты, которые нарушаются, управляя этим?
В течение последних нескольких дней я немного поработал над поиском и чтением и, несмотря на много пылающих SDL и других фреймворков, для той же проблемы (я все равно их не использую, но...), лучшее, что мне удалось найти, - это возможное начало открытия окна 1x1 в фоновом режиме, чтобы сохранить контекст, в то время как вторичное окно будет уничтожено или создано по своему усмотрению. И это кажущееся ненадежным из комментариев, которые я нашел по этому поводу, и кажется очень неуключенным.
Есть ли правильный способ сделать это, или это правильный способ уничтожения вашего окна с часто заданными примерами, а также воссоздать его, в том числе уничтожить ваш контекст OpenGL и воссоздать его?
Ответы
Ответ 1
В основном это просто изменение размера окна и указание флагов, что граница невидима.
SetWindowLongPtr(hWnd, GWL_STYLE,
WS_SYSMENU | WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE);
MoveWindow(hWnd, 0, 0, width, height, TRUE);
чтобы установить его обратно:
RECT rect;
rect.left = 0;
rect.top = 0;
rect.right = width;
rect.bottom = height;
SetWindowLongPtr(hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE);
AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
MoveWindow(hWnd, 0, 0, rect.right-rect.left, rect.bottom-rect.top, TRUE);
или для окна без изменения:
SetWindowLongPtr(hWnd, GWL_STYLE, WS_CAPTION | WS_POPUPWINDOW | WS_VISIBLE);
AdjustWindowRect(&rect, WS_CAPTION | WS_POPUPWINDOW, FALSE);
MoveWindow(hWnd, 0, 0, rect.right-rect.left, rect.bottom-rect.top, TRUE);
а затем просто измените размеры ваших настроек в OpenGL.
Если вы также хотите установить режим отображения, используйте это:
// change display mode if destination mode is fullscreen
if (fullscreen) {
DEVMODE dm;
dm.dmSize = sizeof(DEVMODE);
dm.dmPelsWidth = width;
dm.dmPelsHeight = height;
dm.dmBitsPerPel = bitsPerPixel;
dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
success = ChangeDisplaySettings(&dm, 0) == DISP_CHANGE_SUCCESSFUL;
}
// reset display mode if destination mode is windowed
if (!fullscreen)
success = ChangeDisplaySettings(0, 0) == DISP_CHANGE_SUCCESSFUL;
Ответ 2
Здесь я использую код, который использует SetWindowPos()
а не MoveWindow()
, как обсуждалось в комментариях к другому ответу.
void enter_fullscreen(application* App)
{
POINT Point = {0};
HMONITOR Monitor = MonitorFromPoint(Point, MONITOR_DEFAULTTONEAREST);
MONITORINFO MonitorInfo = { sizeof(MonitorInfo) };
if (GetMonitorInfo(Monitor, &MonitorInfo)) {
DWORD Style = WS_POPUP | WS_VISIBLE;
SetWindowLongPtr(App->Window, GWL_STYLE, Style);
SetWindowPos(App->Window, 0, MonitorInfo.rcMonitor.left, MonitorInfo.rcMonitor.top,
MonitorInfo.rcMonitor.right - MonitorInfo.rcMonitor.left, MonitorInfo.rcMonitor.bottom - MonitorInfo.rcMonitor.top,
SWP_FRAMECHANGED | SWP_SHOWWINDOW);
}
App->IsFullscreen = true;
}
void exit_fullscreen(application* App)
{
bool WasMaximized = App->IsMaximized;
DWORD Style = WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN;
if (WasMaximized) {
Style = Style | WS_MAXIMIZE;
}
ivec2 WindowPosition = WasMaximized ? App->WindowPosition : App->NormalWindowPosition;
ivec2 WindowSize = WasMaximized ? App->WindowSize : App->NormalWindowSize;
SetWindowLongPtr(App->Window, GWL_STYLE, Style);
SetWindowPos(App->Window, 0,
WindowPosition.X, WindowPosition.Y, WindowSize.X, WindowSize.Y,
SWP_FRAMECHANGED | SWP_SHOWWINDOW);
App->IsFullscreen = false;
}
Я звоню на F11, но также на WM_ACTIVATE
. В противном случае окно иногда будет отображаться поверх Windows 7, даже если другое приложение получит все сообщения, включая мышь и клавиатуру.