1 /**************************************************************************
3 * Copyright 2011 Jose Fonseca
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 **************************************************************************/
42 * Several WGL functions come in two flavors:
43 * - GDI (ChoosePixelFormat, SetPixelFormat, SwapBuffers, etc)
44 * - WGL (wglChoosePixelFormat, wglSetPixelFormat, wglSwapBuffers, etc)
46 * The GDI entrypoints will inevitably dispatch to the first module named
47 * "OPENGL32", loading "C:\Windows\System32\opengl32.dll" if none was loaded so
50 * In order to use a implementation other than the one installed in the system
51 * (when specified via the TRACE_LIBGL environment variable), we need to use
55 * - http://www.opengl.org/archives/resources/faq/technical/mswindows.htm
57 static PFN_WGLCHOOSEPIXELFORMAT pfnChoosePixelFormat = &ChoosePixelFormat;
58 static PFN_WGLSETPIXELFORMAT pfnSetPixelFormat = &SetPixelFormat;
59 static PFN_WGLSWAPBUFFERS pfnSwapBuffers = &SwapBuffers;
62 static LRESULT CALLBACK
63 WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
70 PostMessage(hWnd, WM_CLOSE, 0, 0);
74 case WM_GETMINMAXINFO:
75 // Allow to create a window bigger than the desktop
76 pMMI = (MINMAXINFO *)lParam;
77 pMMI->ptMaxSize.x = 60000;
78 pMMI->ptMaxSize.y = 60000;
79 pMMI->ptMaxTrackSize.x = 60000;
80 pMMI->ptMaxTrackSize.y = 60000;
89 return DefWindowProc(hWnd, uMsg, wParam, lParam);
93 class WglDrawable : public Drawable
100 PIXELFORMATDESCRIPTOR pfd;
103 WglDrawable(const Visual *vis, int width, int height) :
104 Drawable(vis, width, height)
106 static bool first = TRUE;
112 memset(&wc, 0, sizeof wc);
113 wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
114 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
115 wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
116 wc.lpfnWndProc = WndProc;
117 wc.lpszClassName = "glretrace";
118 wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
124 dwStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW;
130 rect.right = rect.left + width;
131 rect.bottom = rect.top + height;
133 AdjustWindowRectEx(&rect, dwStyle, FALSE, dwExStyle);
135 hWnd = CreateWindowEx(dwExStyle,
136 "glretrace", /* wc.lpszClassName */
141 rect.right - rect.left, /* width */
142 rect.bottom - rect.top, /* height */
149 memset(&pfd, 0, sizeof pfd);
156 pfd.cStencilBits = 1;
157 pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
158 pfd.iLayerType = PFD_MAIN_PLANE;
159 pfd.iPixelType = PFD_TYPE_RGBA;
160 pfd.nSize = sizeof(pfd);
163 if (visual->doubleBuffer) {
164 pfd.dwFlags |= PFD_DOUBLEBUFFER;
167 iPixelFormat = pfnChoosePixelFormat(hDC, &pfd);
168 if (iPixelFormat <= 0) {
169 std::cerr << "error: ChoosePixelFormat failed\n";
173 bRet = pfnSetPixelFormat(hDC, iPixelFormat, &pfd);
175 std::cerr << "error: SetPixelFormat failed\n";
181 ReleaseDC(hWnd, hDC);
186 resize(int w, int h) {
187 if (w == width && h == height) {
191 RECT rClient, rWindow;
192 GetClientRect(hWnd, &rClient);
193 GetWindowRect(hWnd, &rWindow);
194 w += (rWindow.right - rWindow.left) - rClient.right;
195 h += (rWindow.bottom - rWindow.top) - rClient.bottom;
196 SetWindowPos(hWnd, NULL, rWindow.left, rWindow.top, w, h, SWP_NOMOVE);
198 Drawable::resize(w, h);
206 ShowWindow(hWnd, SW_SHOW);
211 void swapBuffers(void) {
213 bRet = pfnSwapBuffers(hDC);
215 std::cerr << "warning: SwapBuffers failed\n";
218 // Drain message queue to prevent window from being considered
221 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
222 TranslateMessage(&msg);
223 DispatchMessage(&msg);
229 class WglContext : public Context
233 WglContext *shareContext;
235 WglContext(const Visual *vis, Profile prof, WglContext *share) :
243 wglDeleteContext(hglrc);
252 * OpenGL library must be loaded by the time we call GDI.
255 const char * libgl_filename = getenv("TRACE_LIBGL");
257 if (libgl_filename) {
258 pfnChoosePixelFormat = &wglChoosePixelFormat;
259 pfnSetPixelFormat = &wglSetPixelFormat;
260 pfnSwapBuffers = &wglSwapBuffers;
262 libgl_filename = "OPENGL32";
265 _libGlHandle = LoadLibraryA(libgl_filename);
267 std::cerr << "error: unable to open " << libgl_filename << "\n";
277 createVisual(bool doubleBuffer, Profile profile) {
278 if (profile != PROFILE_COMPAT) {
282 Visual *visual = new Visual();
284 visual->doubleBuffer = doubleBuffer;
290 createDrawable(const Visual *visual, int width, int height)
292 return new WglDrawable(visual, width, height);
296 createContext(const Visual *visual, Context *shareContext, Profile profile, bool debug)
298 if (profile != PROFILE_COMPAT) {
302 return new WglContext(visual, profile, static_cast<WglContext *>(shareContext));
306 makeCurrent(Drawable *drawable, Context *context)
308 if (!drawable || !context) {
309 return wglMakeCurrent(NULL, NULL);
311 WglDrawable *wglDrawable = static_cast<WglDrawable *>(drawable);
312 WglContext *wglContext = static_cast<WglContext *>(context);
314 if (!wglContext->hglrc) {
315 wglContext->hglrc = wglCreateContext(wglDrawable->hDC);
316 if (!wglContext->hglrc) {
317 std::cerr << "error: wglCreateContext failed\n";
321 if (wglContext->shareContext) {
323 bRet = wglShareLists(wglContext->shareContext->hglrc,
326 std::cerr << "warning: wglShareLists failed\n";
331 return wglMakeCurrent(wglDrawable->hDC, wglContext->hglrc);
336 processEvents(void) {
338 while (PeekMessage(&uMsg, NULL, 0, 0, PM_REMOVE)) {
339 if (uMsg.message == WM_QUIT) {
343 if (!TranslateAccelerator(uMsg.hwnd, NULL, &uMsg)) {
344 TranslateMessage(&uMsg);
345 DispatchMessage(&uMsg);
352 } /* namespace glws */