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             // idle, so don't waste CPU time
196             WaitMessage();
197     }
198 }
199
200
201 /// Resize window
202 void GLWindow::resize(int newWidth, int newHeight)
203 {
204     // store new window size
205     width  = newWidth;
206     height = newHeight;
207
208     // adjust OpenGL view
209     glViewport(0, 0, width, height);
210 }
211
212
213 /// Toggle fullscreen/windowed
214 void GLWindow::toggleFullscreen()
215 {
216     // default windowed size if programs starts in fullscreen mode
217     static int windowedWidth  = 512;
218     static int windowedHeight = 512;
219
220    
221     if (fullscreen)
222     {
223         // switch from fullscreen to windowed mode
224
225         // set new window styles
226         SetWindowLong(hWnd, GWL_STYLE,   WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
227         SetWindowLong(hWnd, GWL_EXSTYLE, WS_EX_APPWINDOW);
228
229         // from maximized to normal mode
230         ShowWindow(hWnd, SW_RESTORE);
231         UpdateWindow(hWnd);
232
233         // ensure window size
234         width  = windowedWidth;
235         height = windowedHeight;
236
237         RECT size;
238         size.left   = 0;
239         size.top    = 0;
240         size.right  = width;
241         size.bottom = height;
242         AdjustWindowRectEx(&size, WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, FALSE, WS_EX_APPWINDOW);
243
244         // restore old window size
245         SetWindowPos(hWnd, HWND_TOP, 256,128,
246                      size.right-size.left,
247                      size.bottom-size.top,
248                      SWP_SHOWWINDOW)
;
249
250         // show mouse cursor
251         ShowCursor(TRUE);
252     }
253     else     {
254         // switch from windowed mode to fullscreen
255         windowedWidth  = width;
256         windowedHeight = height;
257
258         // set new window styles
259         SetWindowLong(hWnd, GWL_STYLE,   WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
260         SetWindowLong(hWnd, GWL_EXSTYLE, WS_EX_APPWINDOW | WS_EX_WINDOWEDGE);
261
262         // show window maximized
263         ShowWindow(hWnd, SW_SHOWMAXIMIZED);
264         UpdateWindow(hWnd);
265
266         // hide mouse cursor
267         ShowCursor(FALSE);
268     }
269
270     fullscreen = !fullscreen;
271 }
272
273
274 /// Toggle active/stopped
275 void GLWindow::toggleActive()
276 {
277     setActive(!active);
278 }
279
280
281 /// Set active/stopped
282 void GLWindow::setActive(bool newState)
283 {
284     // same state ?
285     if (active == newState)
286         // do nothing ...
287         return;
288
289
290     // well, the state changed indeed
291     active = newState;
292
293     if (!active)
294         // entering inactive mode
295         inactiveSince = GetTickCount();
296     else         // going back to active mode, compute time spent being inactive
297         timeInactive += GetTickCount() - inactiveSince;
298 }
299
300
301 /// Paint window
302 void GLWindow::paint()
303 {
304     // redraw window contents
305     redraw();
306     // frame counter
307     frames++;
308     // double-buffering: switch front and back buffer
309     if (doublebuffer)
310         SwapBuffers(hDC);
311 }
312
313
314 /// Returns seconds since was was opened
315 float GLWindow::seconds() const {
316     if (active)
317         return (GetTickCount() - (timeStarted + timeInactive)) / 1000.0f;
318     else         return (inactiveSince - (timeStarted + timeInactive)) / 1000.0f;
319 }
320
321
322 /// Process message queue
323 LRESULT CALLBACK GLWindow::message(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
324 {
325     switch (uMsg)
326     {
327         case WM_SYSCOMMAND:
328         {
329             switch (wParam)
330             {
331                 // disable screensavers or monitor standby
332                 // idea taken from http://nehe.gamedev.net
333                 case SC_SCREENSAVE:
334                 case SC_MONITORPOWER:
335                 return 0;
336             }
337             break;
338         }
339
340         // restart/pause execution
341         //case WM_ACTIVATE:
342         //{
343         // singleton->setActive(!HIWORD(wParam));
344         // return 0;
345         //}
346
347         case WM_KEYDOWN:
348         {
349             switch (wParam)
350             {
351             // quit
352             case VK_ESCAPE:
353                 PostMessage(hWnd, WM_CLOSE, 0, 0);
354                 return 0;
355
356             // toggle fullscreen/windowed
357             case VK_F5:
358                 singleton->toggleFullscreen();
359                 return 0;
360
361             // pause execution
362             case VK_PAUSE:
363             case VK_SPACE:
364                 singleton->toggleActive();
365                 return 0;
366             }
367
368             break;
369         }
370
371         // quit
372         case WM_CLOSE:
373         {
374             PostQuitMessage(0);
375             return 0;
376         }
377
378         // redraw window
379         case WM_PAINT:
380         {
381             singleton->paint();
382
383             // required to avoid artefacts
384             static PAINTSTRUCT ps;
385             BeginPaint(hWnd, &ps);
386             EndPaint(hWnd, &ps);
387             break;
388         }
389
390         // resize
391         case WM_SIZE:
392         {
393             singleton->resize(LOWORD(lParam), HIWORD(lParam));
394             PostMessage(hWnd, WM_PAINT, 0, 0);
395             return 0;
396         }
397
398         // timer
399         case WM_TIMER:
400             // framerate timer
401             if(wParam == FPS_TIMER_ID)
402             {
403                 // compute current framerate
404                 float fps = (singleton->frames - framesAtLastFPSUpdate)
405                             * (1000.0f / FPS_TIMER_INTERVAL);
406                 framesAtLastFPSUpdate = singleton->frames;
407
408                 // update caption bar
409                 static char newCaption[257];
410                 sprintf(newCaption, "%s (%.0f fps)", singleton->title, fps);
411                 SetWindowText(hWnd, newCaption);
412
413                 return 0;
414             }
415             break;
416     }
417
418     // default handler
419     return DefWindowProc(hWnd, uMsg, wParam, lParam);
420 }
421