Windows 在WinAPI中,如何使用正确的鼠标制作一个可伸缩的OpenGL窗口,使其适合游戏?
多年来,我在努力理解Microsoft Windows的Windows 在WinAPI中,如何使用正确的鼠标制作一个可伸缩的OpenGL窗口,使其适合游戏?,windows,winapi,opengl,resizable,createwindowex,Windows,Winapi,Opengl,Resizable,Createwindowex,多年来,我在努力理解Microsoft Windows的CreateWindowEx()这个奇怪的世界时,读到了很多关于堆栈溢出的文章。。当最初被问到“在WinAPI中创建可流动调整大小的OpenGL窗口的最佳方法是什么?” 我一直在努力让WinAPI制作一个窗口: 具有OpenGL上下文 在“窗口”模式或“全屏”模式下,在多监视器和单监视器显示中,正确居中于主监视器(或由命令行信号确定的任何监视器)上 具有固定的内部客户端屏幕大小(视口2d) 不允许您在错误的时间或在多显示器的特殊情况下单击
CreateWindowEx()
这个奇怪的世界时,读到了很多关于堆栈溢出的文章。。当最初被问到“在WinAPI中创建可流动调整大小的OpenGL窗口的最佳方法是什么?”
我一直在努力让WinAPI制作一个窗口:
- 具有OpenGL上下文
- 在“窗口”模式或“全屏”模式下,在多监视器和单监视器显示中,正确居中于主监视器(或由命令行信号确定的任何监视器)上
- 具有固定的内部客户端屏幕大小(视口2d)
- 不允许您在错误的时间或在多显示器的特殊情况下单击外部,导致其失去焦点
- 可以流畅地调整大小,但不会更改内部“客户端大小”(这意味着它将固定大小的OpenGL内容拉伸为新的屏幕大小)。。。这里的想法是添加一层虚拟化,以便所有像素都以相同的1920x1080(1080p)坐标系表示。这部分对我来说没问题
- 通过屏幕->客户端比率正确处理屏幕大小->客户端大小等效项的鼠标事件转换
- -带边框(默认,实际上没有效果,是带有标题栏等的默认窗口模式)
- -无边界(似乎进入全屏模式,应用程序偏离中心,win 0,0实际上位于屏幕中心)
- -窗口化(或-窗口化)
display.Resized(display.w,display.h);
// 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顺序的后面。我总是使用一个参数打开我的窗口,该参数将display.w设置为1920,display.h设置为1080,可以是全屏模式,也可以是窗口模式。然后调用WM_SIZE将其调整到客户端区域
请注意,以下WM_大小在我设置display.Resized(w,h)的初始时间之后的WinProc期间调用:
这在应用程序加载期间只执行一次,在第一种情况下,它的值看起来是:19181078
更新:如果我在这里使用GetWindowRect()的结果,或者如下图所示使用GetClientRect()的结果,窗口会神秘地移动到屏幕的中心X,中心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);
我需要采取哪些步骤使窗口可伸缩,以便根据视图调整上下文大小,并根据屏幕比例适当调整鼠标 基本上,有太多的边缘案例来解释所有这些。自从两年前我问这个问题以来,随着时间的推移,我发现在全屏和视窗显示之间还有其他不一致之处 据我所知,基本上有3种类型的窗口:
- 用于窗口化GUI的常规屏幕上可移动/可调整大小的窗口,如此浏览器窗口(如果您不在移动设备上)
- 一个与显示器的分辨率支持相匹配(包括比其本机分辨率小的分辨率)——我们称之为“全屏”(或全屏,甚至不是一个单词)
- 一个普通的屏幕窗口,但缺少标题栏、边框和滚动条,显示与屏幕一样大。将“街上”称为“无边界窗口”
// 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);