sources:
Cubemania.cpp (6.2k)
GLWindow.cpp (11.0k)
GLWindow.h (3.1k)


binaries:
Release/Cubemania.exe (7.0k)
Release/CubemaniaStephan.exe (6.5k)
Release/CubemaniaUPX.exe (4.5k)


website:
more info here


screenshot:
studies/game programming/Games-Code1/GLWindow.cpp
download file

  1 // //////////////////////////////////////////////////////////
  2 // GLWindow.cpp
  3 // Copyright (c) 2004 Stephan Brumme. All rights reserved.
  4 //
  5
  6 #include "GLWindow.h"
  7
  8 // ... and OpenGL itself !
  9 #include <gl/gl.h>
 10 // basic string processing
 11 #include <cstdio>
 12 // debugging
 13 #include <cassert>
 14
 15
 16 // Static variables
 17 /// Initialize singleton
 18 GLWindow* GLWindow::singleton = NULL;
 19 /// Number of frames drawn at last update
 20 /** Used to compute the number of frames drawn in the last interval: it's just (frames-framesAtLastFPSUpdate) **/
 21 unsigned int GLWindow::framesAtLastFPSUpdate = 0;
 22
 23
 24
 25 /// Set up a new window
 26 GLWindow::GLWindow(bool fullscreen_, const char* title_,
 27                    unsigned int width_, unsigned int height_,
 28                    bool doublebuffer_,
 29                    unsigned char colorbuffer_, unsigned char depthbuffer_,
 30                    unsigned char accumbuffer_)

 31     : fullscreen(fullscreen_),
 32       title(title_),
 33       width(width_), height(height_),
 34
 35       doublebuffer(doublebuffer_),
 36       accumbuffer(accumbuffer_),
 37       colorbuffer(colorbuffer_),
 38       depthbuffer(depthbuffer_),
 39
 40       active(true), timeInactive(0),
 41       frames(0)
 42 {
 43     // singleton pattern
 44     assert(singleton == NULL);
 45     singleton = this;
 46
 47     // create window
 48     hInstance = GetModuleHandle(NULL);
 49
 50     // register window class
 51     WNDCLASSEX window;
 52     window.cbSize        = sizeof(WNDCLASSEX);
 53     window.style         = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS;
 54     window.lpfnWndProc   = message;
 55     window.cbClsExtra    = 0;
 56     window.cbWndExtra    = 0;
 57     window.hInstance     = hInstance;
 58     window.hIcon         =
 59     window.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);
 60     window.hCursor       = LoadCursor(NULL, IDC_ARROW);
 61     window.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
 62     window.lpszMenuName  = NULL;
 63     window.lpszClassName = title;
 64
 65     // register my window
 66     bool registerClass = RegisterClassEx(&window) != 0;
 67     assert(registerClass);
 68
 69     // window style depends whether window is in fullscreen of windowed
 70     DWORD dwStyle   = WS_OVERLAPPEDWINDOW;
 71     DWORD dwExStyle = WS_EX_APPWINDOW;
 72     if (fullscreen)
 73     {
 74         dwStyle   = WS_POPUP | WS_MAXIMIZE;
 75         dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
 76     }
 77
 78     // ensure window size
 79     RECT size;
 80     size.left   = 0;
 81     size.top    = 0;
 82     size.right  = width;
 83     size.bottom = height;
 84     AdjustWindowRectEx(&size, dwStyle, FALSE, dwExStyle);
 85
 86     // create main window
 87     hWnd = CreateWindowEx(dwExStyle,
 88                           title, title,
 89                           dwStyle | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
 90                           256,128,
 91                           size.right-size.left,
 92                           size.bottom-size.top,
 93                           NULL, NULL, hInstance, NULL)
;
 94     assert(hWnd);
 95
 96
 97     // get the device context
 98     hDC = GetDC(hWnd);
 99     assert(hDC);
100
101     // set pixel format
102     PIXELFORMATDESCRIPTOR pfd;
103     ZeroMemory(&pfd, sizeof(pfd));
104     pfd.nSize      = sizeof(pfd);
105     pfd.nVersion   = 1;
106     pfd.dwFlags    = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | (doublebuffer ? PFD_DOUBLEBUFFER : 0);
107     pfd.iPixelType = PFD_TYPE_RGBA;
108     pfd.cColorBits = colorbuffer;
109     pfd.cDepthBits = depthbuffer;
110     pfd.cAccumBits = accumbuffer;
111     pfd.iLayerType = PFD_MAIN_PLANE;
112    
113     // set buffers' depths
114     int format = ChoosePixelFormat(hDC, &pfd);
115     assert(format > 0);
116     bool setPixelFormat = SetPixelFormat(hDC, format, &pfd) != 0;
117     assert(setPixelFormat);
118
119     // create and enable the render context
120     hRC = wglCreateContext(hDC);
121     assert(hRC);
122     wglMakeCurrent(hDC, hRC);
123
124     // start timer
125     SetTimer(hWnd, FPS_TIMER_ID, FPS_TIMER_INTERVAL, 0);
126
127     // disable mouse cursor in fullscreen mode
128     if (fullscreen)
129         ShowCursor(FALSE);
130
131     // show window
132     AnimateWindow(hWnd, 200, AW_BLEND | AW_ACTIVATE);
133     SetForegroundWindow(hWnd);
134     SetFocus(hWnd);
135
136     // switch off vsync if possible
137     typedef GLboolean (__stdcall * SwapProc) (GLint interval);
138     SwapProc wglSwapIntervalEXT =
139         (SwapProc) wglGetProcAddress("wglSwapIntervalEXT");
140     if (wglSwapIntervalEXT)
141         wglSwapIntervalEXT(0);
142
143
144     // ensure proper timing
145     timeStarted = GetTickCount();
146 }
147
148
149 /// Destroy window
150 GLWindow::~GLWindow()
151 {
152     // yeah, it's time to say good-bye ...
153
154     // delete timer
155     KillTimer(hWnd, FPS_TIMER_ID);
156
157     // free device context
158     wglMakeCurrent(NULL, NULL);
159     wglDeleteContext(hRC);
160     ReleaseDC(hWnd, hDC);
161
162     // show cursor
163     if (fullscreen)
164         ShowCursor(TRUE);
165
166     // properly remove window from screen
167     AnimateWindow(hWnd, 500, AW_BLEND | AW_HIDE);
168     DestroyWindow(hWnd);
169     UnregisterClass(title, hInstance);
170 }
171
172
173 /// Main loop
174 int GLWindow::run()
175 {
176     // run forever :-)
177     while (true)
178     {
179         MSG msg;
180         // quit ?
181         while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
182         {
183             // window closed, the only way of escaping the "run" method
184             if (msg.message == WM_QUIT)
185                 return (int)msg.wParam;
186
187             // keep message pipeline alive
188             TranslateMessage(&msg);
189             DispatchMessage(&msg);
190         }
191
192         // redraw window
193         if (active)
194             paint();
195         else
196             // idle, so don't waste CPU time
197             WaitMessage();
198     }
199 }
200
201
202 /// Resize window
203 void GLWindow::resize(int newWidth, int newHeight)
204 {
205     // store new window size
206     width  = newWidth;
207     height = newHeight;
208
209     // adjust OpenGL view
210     glViewport(0, 0, width, height);
211 }
212
213
214 /// Toggle fullscreen/windowed
215 void GLWindow::toggleFullscreen()
216 {
217     // default windowed size if programs starts in fullscreen mode
218     static int windowedWidth  = 512;
219     static int windowedHeight = 512;
220
221    
222     if (fullscreen)
223     {
224         // switch from fullscreen to windowed mode
225
226         // set new window styles
227         SetWindowLong(hWnd, GWL_STYLE,   WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
228         SetWindowLong(hWnd, GWL_EXSTYLE, WS_EX_APPWINDOW);
229
230         // from maximized to normal mode
231         ShowWindow(hWnd, SW_RESTORE);
232         UpdateWindow(hWnd);
233
234         // ensure window size
235         width  = windowedWidth;
236         height = windowedHeight;
237
238         RECT size;
239         size.left   = 0;
240         size.top    = 0;
241         size.right  = width;
242         size.bottom = height;
243         AdjustWindowRectEx(&size, WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, FALSE, WS_EX_APPWINDOW);
244
245         // restore old window size
246         SetWindowPos(hWnd, HWND_TOP, 256,128,
247                      size.right-size.left,
248                      size.bottom-size.top,
249                      SWP_SHOWWINDOW)
;
250
251         // show mouse cursor
252         ShowCursor(TRUE);
253     }
254     else
255     {
256         // switch from windowed mode to fullscreen
257         windowedWidth  = width;
258         windowedHeight = height;
259
260         // set new window styles
261         SetWindowLong(hWnd, GWL_STYLE,   WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
262         SetWindowLong(hWnd, GWL_EXSTYLE, WS_EX_APPWINDOW | WS_EX_WINDOWEDGE);
263
264         // show window maximized
265         ShowWindow(hWnd, SW_SHOWMAXIMIZED);
266         UpdateWindow(hWnd);
267
268         // hide mouse cursor
269         ShowCursor(FALSE);
270     }
271
272     fullscreen = !fullscreen;
273 }
274
275
276 /// Toggle active/stopped
277 void GLWindow::toggleActive()
278 {
279     setActive(!active);
280 }
281
282
283 /// Set active/stopped
284 void GLWindow::setActive(bool newState)
285 {
286     // same state ?
287     if (active == newState)
288         // do nothing ...
289         return;
290
291
292     // well, the state changed indeed
293     active = newState;
294
295     if (!active)
296         // entering inactive mode
297         inactiveSince = GetTickCount();
298     else
299         // going back to active mode, compute time spent being inactive
300         timeInactive += GetTickCount() - inactiveSince;
301 }
302
303
304 /// Paint window
305 void GLWindow::paint()
306 {
307     // redraw window contents
308     redraw();
309     // frame counter
310     frames++;
311     // double-buffering: switch front and back buffer
312     if (doublebuffer)
313         SwapBuffers(hDC);
314 }
315
316
317 /// Returns seconds since was was opened
318 float GLWindow::seconds() const
319 {
320     if (active)
321         return (GetTickCount() - (timeStarted + timeInactive)) / 1000.0f;
322     else
323         return (inactiveSince - (timeStarted + timeInactive)) / 1000.0f;
324 }
325
326
327 /// Process message queue
328 LRESULT CALLBACK GLWindow::message(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
329 {
330     switch (uMsg)
331     {
332         case WM_SYSCOMMAND:
333         {
334             switch (wParam)
335             {
336                 // disable screensavers or monitor standby
337                 // idea taken from http://nehe.gamedev.net
338                 case SC_SCREENSAVE:
339                 case SC_MONITORPOWER:
340                 return 0;
341             }
342             break;
343         }
344
345         // restart/pause execution
346         //case WM_ACTIVATE:
347         //{
348         // singleton->setActive(!HIWORD(wParam));
349         // return 0;
350         //}
351
352         case WM_KEYDOWN:
353         {
354             switch (wParam)
355             {
356             // quit
357             case VK_ESCAPE:
358                 PostMessage(hWnd, WM_CLOSE, 0, 0);
359                 return 0;
360
361             // toggle fullscreen/windowed
362             case VK_F5:
363                 singleton->toggleFullscreen();
364                 return 0;
365
366             // pause execution
367             case VK_PAUSE:
368             case VK_SPACE:
369                 singleton->toggleActive();
370                 return 0;
371             }
372
373             break;
374         }
375
376         // quit
377         case WM_CLOSE:
378         {
379             PostQuitMessage(0);
380             return 0;
381         }
382
383         // redraw window
384         case WM_PAINT:
385         {
386             singleton->paint();
387
388             // required to avoid artefacts
389             static PAINTSTRUCT ps;
390             BeginPaint(hWnd, &ps);
391             EndPaint(hWnd, &ps);
392             break;
393         }
394
395         // resize
396         case WM_SIZE:
397         {
398             singleton->resize(LOWORD(lParam), HIWORD(lParam));
399             PostMessage(hWnd, WM_PAINT, 0, 0);
400             return 0;
401         }
402
403         // timer
404         case WM_TIMER:
405             // framerate timer
406             if(wParam == FPS_TIMER_ID)
407             {
408                 // compute current framerate
409                 float fps = (singleton->frames - framesAtLastFPSUpdate)
410                             * (1000.0f / FPS_TIMER_INTERVAL);
411                 framesAtLastFPSUpdate = singleton->frames;
412
413                 // update caption bar
414                 static char newCaption[257];
415                 sprintf(newCaption, "%s (%.0f fps)", singleton->title, fps);
416                 SetWindowText(hWnd, newCaption);
417
418                 return 0;
419             }
420             break;
421     }
422
423     // default handler
424     return DefWindowProc(hWnd, uMsg, wParam, lParam);
425 }
426