Есть ли изящный способ обработки переключения между полноэкранным и оконным режимами в приложении Windows OpenGL? - PullRequest
14 голосов
/ 25 августа 2011

Мне интересно, можно ли переключаться между полноэкранным режимом и оконным режимом в окне OpenGL (я пишу для Windows, используя C ++ и win32), не разрушая контекст OpenGL и, следовательно, не нужно перезагружать ресурсы(Текстуры, VBO и т. Д.) В процессе?

Это нежелательно, поскольку вводит задержку переключения между полноэкранным и оконным режимами, потенциально долгую, а также облегчает процесс запутывания, забываядля повторной инициализации чего-либо.

В качестве продолжения этого, есть ли определенные визуальные эффекты, которые нарушаются при попытке сделать это?

Я провел немало поисков и прочтения прошлогонесколько дней, и, несмотря на то, что SDL и другие фреймворки часто сталкиваются с такой же проблемой (я все равно ими не пользуюсь, но ...), лучшее, что мне удалось найти, - это возможное преимущество при открытии 1x1окно в фоновом режиме, чтобы сохранить контекст, в то время как вторичное окно уничтожается или создается по прихоти.И это кажется ненадежным из комментариев, которые я нашел относительно этого, и кажется очень капризным, несмотря на это.

Есть ли правильный способ сделать это, или это правильный метод, часто приводимый в качестве примерауничтожить ваше окно и воссоздать его, включая уничтожение контекста OpenGL и воссоздание его?

Ответы [ 2 ]

16 голосов
/ 25 августа 2011

По сути, это просто изменение размера окна и указание флагов, чтобы граница была невидимой.

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;
0 голосов
/ 04 мая 2019

Вот код, который я использую, который использует 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, даже если другое приложение получит все сообщения, включая мышь и клавиатуру.

...