]> git.cworth.org Git - apitrace/blob - retrace/glws_wgl.cpp
Don't abuse double-underscore prefix.
[apitrace] / retrace / glws_wgl.cpp
1 /**************************************************************************
2  *
3  * Copyright 2011 Jose Fonseca
4  * All Rights Reserved.
5  *
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:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
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
22  * THE SOFTWARE.
23  *
24  **************************************************************************/
25
26
27 /*
28  * WGL bindings.
29  */
30
31
32 #include <iostream>
33
34 #include "glproc.hpp"
35 #include "glws.hpp"
36
37
38 namespace glws {
39
40
41 /*
42  * Several WGL functions come in two flavors:
43  * - GDI (ChoosePixelFormat, SetPixelFormat, SwapBuffers, etc)
44  * - WGL (wglChoosePixelFormat, wglSetPixelFormat, wglSwapBuffers, etc)
45  *
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
48  * far.
49  *
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
52  * WGL entrypoints.
53  *
54  * See also:
55  * - http://www.opengl.org/archives/resources/faq/technical/mswindows.htm
56  */
57 static PFN_WGLCHOOSEPIXELFORMAT pfnChoosePixelFormat = &ChoosePixelFormat;
58 static PFN_WGLSETPIXELFORMAT pfnSetPixelFormat = &SetPixelFormat;
59 static PFN_WGLSWAPBUFFERS pfnSwapBuffers = &SwapBuffers;
60
61
62 static LRESULT CALLBACK
63 WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
64 {
65     MINMAXINFO *pMMI;
66     switch (uMsg) {
67     case WM_GETMINMAXINFO:
68         // Allow to create a window bigger than the desktop
69         pMMI = (MINMAXINFO *)lParam;
70         pMMI->ptMaxSize.x = 60000;
71         pMMI->ptMaxSize.y = 60000;
72         pMMI->ptMaxTrackSize.x = 60000;
73         pMMI->ptMaxTrackSize.y = 60000;
74         break;
75     default:
76         break;
77     }
78
79     return DefWindowProc(hWnd, uMsg, wParam, lParam);
80 }
81
82
83 class WglDrawable : public Drawable
84 {
85 public:
86     DWORD dwExStyle;
87     DWORD dwStyle;
88     HWND hWnd;
89     HDC hDC;
90     PIXELFORMATDESCRIPTOR pfd;
91     int iPixelFormat;
92
93     WglDrawable(const Visual *vis, int width, int height) :
94         Drawable(vis, width, height)
95     {
96         static bool first = TRUE;
97         RECT rect;
98         BOOL bRet;
99
100         if (first) {
101             WNDCLASS wc;
102             memset(&wc, 0, sizeof wc);
103             wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
104             wc.hCursor = LoadCursor(NULL, IDC_ARROW);
105             wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
106             wc.lpfnWndProc = WndProc;
107             wc.lpszClassName = "glretrace";
108             wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
109             RegisterClass(&wc);
110             first = FALSE;
111         }
112
113         dwExStyle = 0;
114         dwStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW;
115
116         int x = 0, y = 0;
117
118         rect.left = x;
119         rect.top = y;
120         rect.right = rect.left + width;
121         rect.bottom = rect.top + height;
122
123         AdjustWindowRectEx(&rect, dwStyle, FALSE, dwExStyle);
124
125         hWnd = CreateWindowEx(dwExStyle,
126                               "glretrace", /* wc.lpszClassName */
127                               NULL,
128                               dwStyle,
129                               0, /* x */
130                               0, /* y */
131                               rect.right - rect.left, /* width */
132                               rect.bottom - rect.top, /* height */
133                               NULL,
134                               NULL,
135                               NULL,
136                               NULL);
137         hDC = GetDC(hWnd);
138    
139         memset(&pfd, 0, sizeof pfd);
140         pfd.cColorBits = 4;
141         pfd.cRedBits = 1;
142         pfd.cGreenBits = 1;
143         pfd.cBlueBits = 1;
144         pfd.cAlphaBits = 1;
145         pfd.cDepthBits = 1;
146         pfd.cStencilBits = 1;
147         pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
148         pfd.iLayerType = PFD_MAIN_PLANE;
149         pfd.iPixelType = PFD_TYPE_RGBA;
150         pfd.nSize = sizeof(pfd);
151         pfd.nVersion = 1;
152
153         if (visual->doubleBuffer) {
154            pfd.dwFlags |= PFD_DOUBLEBUFFER;
155         }
156
157         iPixelFormat = pfnChoosePixelFormat(hDC, &pfd);
158         if (iPixelFormat <= 0) {
159             std::cerr << "error: ChoosePixelFormat failed\n";
160             exit(1);
161         }
162
163         bRet = pfnSetPixelFormat(hDC, iPixelFormat, &pfd);
164         if (!bRet) {
165             std::cerr << "error: SetPixelFormat failed\n";
166             exit(1);
167         }
168     }
169
170     ~WglDrawable() {
171         ReleaseDC(hWnd, hDC);
172         DestroyWindow(hWnd);
173     }
174     
175     void
176     resize(int w, int h) {
177         if (w == width && h == height) {
178             return;
179         }
180
181         RECT rClient, rWindow;
182         GetClientRect(hWnd, &rClient);
183         GetWindowRect(hWnd, &rWindow);
184         w += (rWindow.right  - rWindow.left) - rClient.right;
185         h += (rWindow.bottom - rWindow.top)  - rClient.bottom;
186         SetWindowPos(hWnd, NULL, rWindow.left, rWindow.top, w, h, SWP_NOMOVE);
187
188         Drawable::resize(w, h);
189     }
190
191     void show(void) {
192         if (visible) {
193             return;
194         }
195
196         ShowWindow(hWnd, SW_SHOW);
197
198         Drawable::show();
199     }
200
201     void swapBuffers(void) {
202         BOOL bRet;
203         bRet = pfnSwapBuffers(hDC);
204         if (!bRet) {
205             std::cerr << "warning: SwapBuffers failed\n";
206         }
207
208         // Drain message queue to prevent window from being considered
209         // non-responsive
210         MSG msg;
211         while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
212             TranslateMessage(&msg);
213             DispatchMessage(&msg);
214         }
215     }
216 };
217
218
219 class WglContext : public Context
220 {
221 public:
222     HGLRC hglrc;
223     WglContext *shareContext;
224
225     WglContext(const Visual *vis, Profile prof, WglContext *share) :
226         Context(vis, prof),
227         hglrc(0),
228         shareContext(share)
229     {}
230
231     ~WglContext() {
232         if (hglrc) {
233             wglDeleteContext(hglrc);
234         }
235     }
236 };
237
238
239 void
240 init(void) {
241     /*
242      * OpenGL library must be loaded by the time we call GDI.
243      */
244
245     const char * libgl_filename = getenv("TRACE_LIBGL");
246
247     if (libgl_filename) {
248         pfnChoosePixelFormat = &wglChoosePixelFormat;
249         pfnSetPixelFormat = &wglSetPixelFormat;
250         pfnSwapBuffers = &wglSwapBuffers;
251     } else {
252         libgl_filename = "OPENGL32";
253     }
254
255     _libGlHandle = LoadLibraryA(libgl_filename);
256     if (!_libGlHandle) {
257         std::cerr << "error: unable to open " << libgl_filename << "\n";
258         exit(1);
259     }
260 }
261
262 void
263 cleanup(void) {
264 }
265
266 Visual *
267 createVisual(bool doubleBuffer, Profile profile) {
268     if (profile != PROFILE_COMPAT) {
269         return NULL;
270     }
271
272     Visual *visual = new Visual();
273
274     visual->doubleBuffer = doubleBuffer;
275
276     return visual;
277 }
278
279 Drawable *
280 createDrawable(const Visual *visual, int width, int height)
281 {
282     return new WglDrawable(visual, width, height);
283 }
284
285 Context *
286 createContext(const Visual *visual, Context *shareContext, Profile profile)
287 {
288     if (profile != PROFILE_COMPAT) {
289         return NULL;
290     }
291
292     return new WglContext(visual, profile, static_cast<WglContext *>(shareContext));
293 }
294
295 bool
296 makeCurrent(Drawable *drawable, Context *context)
297 {
298     if (!drawable || !context) {
299         return wglMakeCurrent(NULL, NULL);
300     } else {
301         WglDrawable *wglDrawable = static_cast<WglDrawable *>(drawable);
302         WglContext *wglContext = static_cast<WglContext *>(context);
303
304         if (!wglContext->hglrc) {
305             wglContext->hglrc = wglCreateContext(wglDrawable->hDC);
306             if (!wglContext->hglrc) {
307                 std::cerr << "error: wglCreateContext failed\n";
308                 exit(1);
309                 return false;
310             }
311             if (wglContext->shareContext) {
312                 BOOL bRet;
313                 bRet = wglShareLists(wglContext->shareContext->hglrc,
314                                      wglContext->hglrc);
315                 if (!bRet) {
316                     std::cerr << "warning: wglShareLists failed\n";
317                 }
318             }
319         }
320
321         return wglMakeCurrent(wglDrawable->hDC, wglContext->hglrc);
322     }
323 }
324
325 bool
326 processEvents(void) {
327     // TODO
328     return true;
329 }
330
331
332 } /* namespace glws */