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, bool pbuffer) :
104 Drawable(vis, width, height, pbuffer)
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);
248 create(WglDrawable *wglDrawable) {
250 hglrc = wglCreateContext(wglDrawable->hDC);
252 std::cerr << "error: wglCreateContext failed\n";
257 if (shareContext->create(wglDrawable)) {
259 bRet = wglShareLists(shareContext->hglrc,
263 << "warning: wglShareLists failed: "
264 << std::hex << GetLastError() << std::dec
280 * OpenGL library must be loaded by the time we call GDI.
283 const char * libgl_filename = getenv("TRACE_LIBGL");
285 if (libgl_filename) {
286 pfnChoosePixelFormat = &wglChoosePixelFormat;
287 pfnSetPixelFormat = &wglSetPixelFormat;
288 pfnSwapBuffers = &wglSwapBuffers;
290 libgl_filename = "OPENGL32";
293 _libGlHandle = LoadLibraryA(libgl_filename);
295 std::cerr << "error: unable to open " << libgl_filename << "\n";
305 createVisual(bool doubleBuffer, Profile profile) {
306 if (profile != PROFILE_COMPAT &&
307 profile != PROFILE_CORE) {
311 Visual *visual = new Visual();
313 visual->doubleBuffer = doubleBuffer;
319 createDrawable(const Visual *visual, int width, int height, bool pbuffer)
321 return new WglDrawable(visual, width, height, pbuffer);
325 createContext(const Visual *visual, Context *shareContext, Profile profile, bool debug)
327 if (profile != PROFILE_COMPAT &&
328 profile != PROFILE_CORE) {
332 if (profile == PROFILE_CORE) {
333 std::cerr << "warning: ignoring OpenGL core profile request\n";
336 return new WglContext(visual, profile, static_cast<WglContext *>(shareContext));
340 makeCurrent(Drawable *drawable, Context *context)
342 if (!drawable || !context) {
343 return wglMakeCurrent(NULL, NULL);
345 WglDrawable *wglDrawable = static_cast<WglDrawable *>(drawable);
346 WglContext *wglContext = static_cast<WglContext *>(context);
348 wglContext->create(wglDrawable);
350 return wglMakeCurrent(wglDrawable->hDC, wglContext->hglrc);
355 processEvents(void) {
357 while (PeekMessage(&uMsg, NULL, 0, 0, PM_REMOVE)) {
358 if (uMsg.message == WM_QUIT) {
362 if (!TranslateAccelerator(uMsg.hwnd, NULL, &uMsg)) {
363 TranslateMessage(&uMsg);
364 DispatchMessage(&uMsg);
371 } /* namespace glws */