I want to create a borderless, fullscreen OpenGL window with the Windows API. This is seen in many games so that you can quickly tab between your game and another application.
My problem is that when I create my window (which works) and I tab out, it does tab out, because I see my cursor change to the text cursor for my text editor, but the screen is still completely red from my OpenGL application, thus I cannot see anything.
The issue however is resolved when I set a breakpoint (Visual Studio) in the main loop (or before the main loop but after window creation), before I swap the buffers, and let it resume after that. Below is my mainloop. I am using my own window class.
while(window.Running())
{
window.PollEvents();
glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
window.SwapBuffers();
Sleep(10);
}
My question is: What happens when I pause my application before the swapping of buffers that makes the window behave differently (for me correctly)?
The inside of window.SwapBuffers()
is the following:
void GLWindowImpWin32::swapBuffers()
{
SwapBuffers(handleDeviceContext);
}
Where handleDeviceContext
is my HDC
.
Also pressing the Windows button does not visually bring up the taskbar in front of the application.
Here's my minimized source code which behaves the same as my original code, it also works if you put a breakpoint before swapping the buffers. If you are compiling, don't forget to link to opengl32.lib
:
#include <Windows.h>
#include <gl/GL.h>
WNDCLASSEX windowClass;
HWND handleWindow;
HDC handleDeviceContext;
HGLRC handleGLRenderingContext;
bool running = false;
// set this to your screen size
const int windowWidth = 1680;
const int windowHeight = 1050;
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
{
handleDeviceContext = GetDC(hWnd);
PIXELFORMATDESCRIPTOR pfd =
{
sizeof(PIXELFORMATDESCRIPTOR),
1,
PFD_SUPPORT_OPENGL |
PFD_DRAW_TO_WINDOW |
PFD_DOUBLEBUFFER,
PFD_TYPE_RGBA,
32,
0, 0, 0, 0, 0, 0,
0,
0,
0,
0, 0, 0, 0,
16,
8,
0,
PFD_MAIN_PLANE,
0,
0, 0, 0
};
int pixelFormat = ChoosePixelFormat(handleDeviceContext, &pfd);
SetPixelFormat(handleDeviceContext, pixelFormat, &pfd);
handleGLRenderingContext = wglCreateContext(handleDeviceContext);
wglMakeCurrent(handleDeviceContext, handleGLRenderingContext);
running = true;
break;
}
case WM_DESTROY:
case WM_CLOSE:
{
wglMakeCurrent(handleDeviceContext, NULL);
wglDeleteContext(handleGLRenderingContext);
running = false;
break;
}
default:
break;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, LPSTR cmdLine, int cmdShow)
{
memset(&windowClass, 0, sizeof(WNDCLASSEX));
windowClass.cbSize = sizeof(WNDCLASSEX);
windowClass.style = CS_VREDRAW | CS_HREDRAW | CS_OWNDC;
windowClass.cbClsExtra = 0;
windowClass.cbWndExtra = 0;
windowClass.hInstance = hInstance;
windowClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
windowClass.hIconSm = LoadIcon(NULL, IDI_WINLOGO);
windowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
windowClass.hbrBackground = NULL;
windowClass.lpszMenuName = NULL;
windowClass.lpszClassName = "GLWindowClass";
windowClass.lpfnWndProc = WndProc;
if(!RegisterClassEx(&windowClass))
{
return false;
}
DWORD windowStyleEx = WS_EX_APPWINDOW;
DWORD windowStyle = WS_POPUP;
handleWindow = CreateWindow(
"GLWindowClass",
"title",
windowStyle | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
CW_USEDEFAULT,
CW_USEDEFAULT,
windowWidth,
windowHeight,
NULL,
NULL,
hInstance,
NULL);
if(!handleWindow)
{
return false;
}
handleDeviceContext = GetDC(handleWindow);
ShowWindow(handleWindow, SW_SHOW);
while(running)
{
MSG msg;
while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
SwapBuffers(handleDeviceContext);
Sleep(10);
}
PostQuitMessage(0);
return 0;
}