在WinAPI中创建流畅的可调整大小的OpenGL窗口的最佳方法是什么?

时间:2016-12-20 20:13:30

标签: windows winapi opengl resizable createwindowex

多年来,我一直在阅读很多Stack Overflow,因为我正在努力理解微软Windows的奇怪世界CreateWindowEx()等等。

我一直在努力让WinAPI创建一个窗口:

  • 有一个OpenGL上下文
  • 在“窗口”模式或“全屏”模式下,在多显示器和单显示器显示器中都正确居中
  • 具有固定的内部客户端屏幕尺寸
  • 可以流畅地调整大小,但不会更改内部“客户端大小”(意味着它会将OpenGL内容拉伸到新屏幕大小的固定大小,而不更新内部,基于由设置的任意分辨率大小用户)因为我的框架不处理Resized()事件
  • 正确处理来自screen_size的鼠标事件转换 - > client_size等效于screen->客户比率

在我自己开发的App框架中,我必须设置显示大小,即使这样,Windows也没有给我正确大小的窗口。此外,最近从2010 EE(Win32 / Windows 7)迁移到2015(win32 / Windows 10)时,我不得不更改参数以重新定位视图,因为它在主显示屏上偏离中心。

我可以通过提供以下命令行参数来玩这些东西:

  • -bordered(默认,实际上没有效果,是默认的窗口模式)
  • -borderless(似乎进入全屏模式,应用程序偏离中心,其中win 0,0实际上在屏幕中心)
  • -windowed(或-window)

如果我不提供-window,则默认为“全屏”分辨率调整(但只有在我假设支持的情况下,否则可能会引发错误)。

无论如何,所有这些都非常糟糕,因为 a)我必须为我正在使用的每个分辨率写一个bajillion案例,而不是为1080p编写所有内容并将其调整为显示大小,这就是我想要的 b)我不能流畅地调整窗口大小 c)不支持1920x1080的用户将无法使用全屏模式

有人在另一个问题(window border width and height in Win32 - how do I get it?)中指出了这篇文章: https://web.archive.org/web/20120716062211/http://suite101.com/article/client-area-size-with-movewindow-a17846

我已经读完了这一点,了解到AdjustWindowRectEx()存在一些问题: AdjustWindowRectEx() and GetWindowRect() give wrong size with WS_OVERLAPPED

我不使用WS_OVERLAPPED,所以这只是中等帮助: AdjustWindowRectEx() and GetWindowRect() give wrong size with WS_OVERLAPPED

以下是我现在的表现:

display.Resized(display.w,display.h);

if (CmdLine.Option("-trapdoor")) {
 gl.escTrapdoor = true;
 OUTPUT("The emergency exit is unlocked.\n");
}

// Fill in the window class structure for testing display type.

winclass.cbSize = sizeof(WNDCLASSEX);
winclass.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
winclass.lpfnWndProc = WinProc;
winclass.cbClsExtra = 0;
winclass.cbWndExtra = 0;
winclass.hInstance = hinstance;
winclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
winclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
winclass.hCursor = LoadCursor(NULL, IDC_ARROW);
winclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
winclass.lpszMenuName = NULL;
winclass.lpszClassName = WINDOW_CLASS_NAME;

// Save the game instance handle
display.hinstance = game_instance = hinstance;

// Register the window class
if (!RegisterClassEx(&winclass)) return(0);

if (!gl.Init(hinstance, display.bits)) {
 return(0);
}

// Detect the display size and create the final display profile 

DWORD winStyle=
 WS_EX_APPWINDOW |
 WS_EX_TOPMOST /*|
 WS_EX_ACCEPTFILES*/ ;

// Adjust Window, Account For Window Borders
int xPos = GetSystemMetrics(SM_CXSCREEN) - display.w;
int yPos = GetSystemMetrics(SM_CYSCREEN) - display.h;
RECT windowRect = {0, 0, display.w, display.h}; // Define Our Window Coordinates
AdjustWindowRectEx (&windowRect, WS_POPUP, 0, winStyle );
// Create the window
if (!(hwnd = CreateWindowEx(
 winStyle,                    // extended style
 WINDOW_CLASS_NAME, // class
 gl.winTitle.c_str(),          // title
 ( gl.borderless || CmdLine.Option("-borderless") ) ? (WS_POPUPWINDOW | WS_VISIBLE)
 : (gl.noFullscreen ? ((CmdLine.Option("-bordered") ? WS_BORDER : 0) | WS_VISIBLE)
                    : (WS_POPUP | WS_VISIBLE)),  // use POPUP for full screen
   gl.noFullscreen && !CmdLine.Option("-recenter") ? xPos / 2 : 0,
   gl.noFullscreen && !CmdLine.Option("-recenter") ? yPos / 2 : 0,     // initial game window x,y
   display.w,         // initial game width
   display.h,         // initial game height
   HWND_DESKTOP,      // handle to parent
   NULL,              // handle to menu
   hinstance,         // instance of this application
   NULL)
  )         // extra creation parms
 ) {
 OUTPUT("WinAPI ERROR: Could not open window.\n");
 return(0);
}

if (gl.borderless || CmdLine.Option("-borderless") ) {
  LONG lStyle = GetWindowLong(hwnd, GWL_STYLE);
  lStyle &= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU);
  SetWindowLong(hwnd, GWL_STYLE, lStyle);
  LONG lExStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
  lExStyle &= ~(WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE);
  SetWindowLong(hwnd, GWL_EXSTYLE, lExStyle);
  SetWindowPos(hwnd, NULL, 0, 0, display.w, display.h, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER);
  }

  // Temporary change to full screen mode
  ZeroMemory(&game_screen, sizeof(game_screen)); // clear out size of DEVMODE    struct
game_screen.dmSize = sizeof(game_screen);
game_screen.dmPelsWidth = display.w;
game_screen.dmPelsHeight = display.h;
game_screen.dmBitsPerPel = display.bits;
game_screen.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
ChangeDisplaySettings(&game_screen, CDS_FULLSCREEN);

// save the game window handle
display.hwnd = game_window = hwnd;
display.hdc = game_dc = GetDC(display.hwnd = game_window); // get the GDI device context
                                                         // set up the pixel format desc struct

pfd = {
 sizeof(PIXELFORMATDESCRIPTOR),   // size of this PFD
 1,                               // version number
 PFD_DRAW_TO_WINDOW |             // supports window
 PFD_SUPPORT_OPENGL |             // supports OpenGL
 PFD_DOUBLEBUFFER,                // support double buff
 PFD_TYPE_RGBA,                   // request RGBA format
 (BYTE)display.bits,              // select color depth
 0, 0, 0, 0, 0, 0,                // color bits ignored
 0,                               // no alpha buff
 0,                               // shift bit ignored
 0,                               // no accum buff
 0, 0, 0, 0,                      // accum bits ignored
 16,                              // 16-bit Z-buff (depth buff)
 0,                               // no stencil buff
 0,                               // no aux buff
 PFD_MAIN_PLANE,                  // main drawing layer
 0,                               // reserved
 0, 0, 0                          // layer masks ignored
};
int pf;  // pixel format

if (!gl.arbMultisampleSupported) {
 if (!(pf = ChoosePixelFormat(game_dc, &pfd)))  // match the pixel format
 {
  MessageBox(game_window, "OpenGL could not be initialized -- ChoosePixelFormat Error ; report this to program authors for help!", "OpenGL Error", MB_OK);
  return FALSE; // error returned
 }
} else {
 pf = gl.arbMultisampleFormat;
}
if (!SetPixelFormat(game_dc, pf, &pfd))        // set the pixel format
{
 MessageBox(game_window, "OpenGL could not be initialized -- SetPixelFormat Error ; report this to program authors for help!", "OpenGL Error", MB_OK);
 return FALSE; // error returned
}

if (!(game_rc = wglCreateContext(game_dc)))    // create the rendering context
{
 MessageBox(game_window, "OpenGL could not be initialized -- CreateContext Error ; report this to program authors for help!", "OpenGL Error", MB_OK);
 return FALSE; // error returned
}

if (!(upload_rc = wglCreateContext(game_dc)))    // create the rendering context
{
 MessageBox(game_window, "Multiple OpenGL contexts could not be initialized -- CreateContext Error ; report this to program authors for help!", "OpenGL Error", MB_OK);
 return FALSE; // error returned
} else { // Share as much as you can between two contexts
 if (!wglShareLists(game_rc, upload_rc)) {
  // could use GetLastError here
  MessageBox(game_window, "wglShareLists -- Error ; report this to program authors for help!", "OpenGL Error", MB_OK);
  return FALSE; // error returned
 }
}

if (!wglMakeCurrent(game_dc, display.hglrc = game_rc))         // make it  current
{
 MessageBox(game_window, "OpenGL could not be initialized -- MakeCurrent Error ; report this to program authors for help!", "OpenGL Error", MB_OK);
 return FALSE; // error returned
}

ShowCursor(false);
ShowWindow(game_window, SW_SHOWNORMAL);
SetForegroundWindow(game_window);

在上面的代码中,我得到的是一个没有调整大小功能的窗口,隐藏了操作系统鼠标光标,只能用ALT-TAB(或ALT-F4)进行退出,当它退出时出现在Windows Z-order的后面。我总是打开我的窗口,使用一个参数将display.w设置为1920并将display.h设置为1080,无论是全屏模式还是窗口模式。然后调用WM_SIZE将其调整到客户区。

请注意,在我设置display.Resized(w,h)的初始时间之后,WinProc期间会调用以下WM_SIZE:

case WM_SIZE:
{
 display.Resized(LOWORD(lparam), HIWORD(lparam));
 return (0);
}
break;

在app加载期间执行一次,在第一种情况下,它看起来像值:1918,1078

更新:如果我在这里使用GetWindowRect()的结果,或者如下所示使用GetClientRect(),窗口会神秘地移动到屏幕的Center-X,Center-Y!是什么赋予了??

//  RECT rect;
//  if ( GetClientRect(hwnd,&rect) ) {
//   display.Resized((int)rect.right,(int)rect.bottom);
//  }
  //if ( GetWindowRect( hwnd, &rect ) ) {
  // display.Resized((int)ADIFF(rect.left,rect.right),(int)ADIFF(rect.top,rect.bottom));
  //}
  display.Resized(LOWORD(lparam), HIWORD(lparam));
  return (0);

我需要采取哪些步骤才能使窗口可伸缩,以便将上下文调整为视图大小,并根据屏幕比例正确调整鼠标?

0 个答案:

没有答案