1 //////////////////////////////////////////////////////////////////////////////////////////
3 // functions to set up an opengl capable window
4 // Downloaded from: www.paulsprojects.net
5 // Created: 21st June 2002
6 // Modified: 26th August 2002 - Added Input management
7 // 3rd September 2002 - Added WINDOW::MakeCurrent - to restore focus to
10 // Copyright (c) 2006, Paul Baker
11 // Distributed under the New BSD Licence. (See accompanying file License.txt or copy at
12 // http://www.paulsprojects.net/NewBSDLicense.txt)
13 //////////////////////////////////////////////////////////////////////////////////////////
23 bool WINDOW::Init(const char * windowTitle
,
24 int newWidth
, int newHeight
,
25 int newColorBits
, int newDepthBits
, int newStencilBits
,
29 WNDCLASS wc
; //windows class structure
30 DWORD dwExStyle
; //extended style info.
31 DWORD dwStyle
; //style info
33 //set class's member variables
37 colorBits
=newColorBits
;
38 depthBits
=newDepthBits
;
39 stencilBits
=newStencilBits
;
41 //set class's fullscreen flag
42 if(fullscreenflag
== FULL_SCREEN
)
47 if(fullscreenflag
== WINDOWED_SCREEN
)
52 if(fullscreenflag
== CHOOSE_SCREEN
) //Ask user if fullscreen
54 if(MessageBox(NULL
,"Would You Like To Run In Fullscreen Mode?","Start FullScreen",MB_YESNO
|MB_ICONQUESTION
)==IDNO
)
56 fullscreen
=false; //If answered no
60 fullscreen
=true; //if answered yes
64 RECT WindowRect
; //grab rect. upper left/lower right values
65 WindowRect
.left
=(long)0;
66 WindowRect
.right
=(long)width
;
67 WindowRect
.top
=(long)0;
68 WindowRect
.bottom
=(long)height
;
70 hInstance
= GetModuleHandle(NULL
); //Grab an instance for window
71 wc
.style
= CS_HREDRAW
| CS_VREDRAW
| CS_OWNDC
;
72 //window style: redraw on move, own DC
73 wc
.lpfnWndProc
= (WNDPROC
) WndProc
; //Wndproc handles messages
75 wc
.cbWndExtra
= 0; //no extra window data
76 wc
.hInstance
= hInstance
; //Set the instance
77 wc
.hIcon
= LoadIcon(NULL
, IDI_WINLOGO
); //load default icon
78 wc
.hCursor
= LoadCursor(NULL
, IDC_ARROW
); //Load arrow cursor
79 wc
.hbrBackground
=NULL
; //No background rqd for GL
80 wc
.lpszMenuName
=NULL
; //No menu
81 wc
.lpszClassName
="OpenGL"; //set class name
83 if(!RegisterClass(&wc
)) //try to register class
85 errorLog
.OutputError("Failed to register the window class");
89 errorLog
.OutputSuccess("Window Class Registered");
91 if(fullscreen
) //try to set up fullscreen?
93 DEVMODE dmScreenSettings
; //Device mode
94 memset(&dmScreenSettings
,0,sizeof(dmScreenSettings
));
96 dmScreenSettings
.dmSize
=sizeof(dmScreenSettings
);
97 //size of devmode structure
98 dmScreenSettings
.dmPelsWidth
=width
; //selected width
99 dmScreenSettings
.dmPelsHeight
=height
; //selected height
100 dmScreenSettings
.dmBitsPerPel
=colorBits
; //selected bpp
101 dmScreenSettings
.dmFields
=DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
103 if(ChangeDisplaySettings(&dmScreenSettings
, CDS_FULLSCREEN
)!=DISP_CHANGE_SUCCESSFUL
)
104 //try to set mode.CDS_FULLSCREEN removes start bar
106 //If mode fails, give 2 options, quit or run in window
107 if(MessageBox(NULL
, "The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?",title
, MB_YESNO
|MB_ICONEXCLAMATION
)==IDYES
)
109 fullscreen
=FALSE
; //if "yes", try windowed
113 //tell user program is closing
114 errorLog
.OutputError("Program Closed, As Fullscreen Mode Not Supported.");
115 return FALSE
; //exit and return FALSE
120 if (fullscreen
) //still fullscreen?
122 dwExStyle
=WS_EX_APPWINDOW
; //window extended style
123 dwStyle
=WS_POPUP
| WS_VISIBLE
; //window style (no border), visible
124 ShowCursor(FALSE
); //hide mouse pointer
128 dwExStyle
=WS_EX_CLIENTEDGE
; //window extended style(3d look)
129 dwStyle
=WS_SYSMENU
| WS_BORDER
| WS_CAPTION
| WS_VISIBLE
;
130 //window style (close button, title bar, border, visible)
133 AdjustWindowRectEx(&WindowRect
, dwStyle
, FALSE
, dwExStyle
);
134 //adjust window to actual requested size, rather than including borders in size. in fullscreen, no effect
136 if(!(hWnd
=CreateWindowEx( dwExStyle
, //extended style for window
137 "OpenGL", //class name
138 title
, //window title
139 WS_CLIPSIBLINGS
| //required style
140 WS_CLIPCHILDREN
| //required style
141 dwStyle
, //Selected style
142 0, 0, //window position
143 WindowRect
.right
-WindowRect
.left
, //calculate adjusted width
144 WindowRect
.bottom
-WindowRect
.top
, //calculate adjusted height
145 NULL
, // no parent window
147 hInstance
, //Instance
148 NULL
))) //Dont pass anything to WM_CREATE
150 Shutdown(); //if not set up, reset display
151 errorLog
.OutputError("Window Creation Error.");
152 //pop up error message
153 return FALSE
; //return false, to quit program
156 errorLog
.OutputSuccess("Window Created.");
158 //set up pixel format(openGL supporting, RGBA, correct bits
159 GLuint pixelFormat
; //holds result after searching for mode match
161 //calculate alpha bits
167 static PIXELFORMATDESCRIPTOR pfd
= //pfd tells windows how we want things to be
169 sizeof(PIXELFORMATDESCRIPTOR
), //size of Pixel format descriptor
171 PFD_DRAW_TO_WINDOW
| //must support window
172 PFD_SUPPORT_OPENGL
| //must support opengl
173 PFD_DOUBLEBUFFER
, //must support double buffer
174 PFD_TYPE_RGBA
, //request RGBA format
175 colorBits
, //select colour depth
176 0, 0, 0, 0, 0, 0, //colour bits ignored
177 alphaBits
, //alpha buffer bits
178 0, //shift bit ignored
179 0, //no accumulation buffer
180 0, 0, 0, 0, //accumulation bits ignored
181 depthBits
, //z buffer bits
182 stencilBits
, //stencil buffer bits
183 0, //no auxiliary buffer
184 PFD_MAIN_PLANE
, //main drawing layer
186 0, 0, 0 //layer masks ignored
189 if(!(hDC
=GetDC(hWnd
))) //did we get a device context?
191 Shutdown(); //Reset display
192 errorLog
.OutputError("Can't Create a GL Device context.");
193 return FALSE
; //return false, to exit
196 errorLog
.OutputSuccess("DC Created");
198 if(!(pixelFormat
=ChoosePixelFormat(hDC
,&pfd
))) //found a matching pixel format?
201 errorLog
.OutputError("Can't Find a Suitable PixelFormat.");
205 errorLog
.OutputSuccess("Pixel Format Found.");
207 if(!SetPixelFormat(hDC
, pixelFormat
,&pfd
)) //are we able to set pixel format?
210 errorLog
.OutputError("Can't set the pixelformat.");
214 errorLog
.OutputSuccess("Pixel Format set.");
216 if(!(hRC
=wglCreateContext(hDC
))) //are we able to get rendering context?
219 errorLog
.OutputError("Can't create a GL rendering context.");
223 errorLog
.OutputSuccess("GL Rendering Context Created.");
225 if(!MakeCurrent()) //are we able to activate rendering context?
231 errorLog
.OutputSuccess("GL Rendering Context Activated.");
233 //get pixel format parameters
234 static PIXELFORMATDESCRIPTOR finalPfd
;
235 DescribePixelFormat(hDC
, pixelFormat
, sizeof(PIXELFORMATDESCRIPTOR
), &finalPfd
);
237 //output window parameters
238 errorLog
.OutputNewline();
239 errorLog
.OutputSuccess("Window Size: (%d, %d)", width
, height
);
240 errorLog
.OutputSuccess("Color Buffer Bits (R, G, B, A): (%d, %d, %d, %d)",
244 finalPfd
.cAlphaBits
);
245 errorLog
.OutputSuccess("Depth Buffer Bits: %d", finalPfd
.cDepthBits
);
246 errorLog
.OutputSuccess("Stencil Buffer Bits: %d", finalPfd
.cStencilBits
);
247 errorLog
.OutputNewline();
249 ShowWindow(hWnd
,SW_SHOW
); //show window
250 SetForegroundWindow(hWnd
); //slightly higher priority
251 SetFocus(hWnd
); //Set keyboard focus to the window
253 errorLog
.OutputSuccess("Window Created!");
254 errorLog
.OutputNewline();
257 HFONT font
; //windows font ID
259 //create 96 display lists
260 base
= glGenLists(96);
262 font
= CreateFont( -18, //font height
264 0, 0, //angles - escapement, orientation
265 FW_BOLD
, //font weight, 0-1000, NORMAL, BOLD
269 ANSI_CHARSET
, //character set
270 OUT_TT_PRECIS
, //precision
271 CLIP_DEFAULT_PRECIS
, //clip precision
272 ANTIALIASED_QUALITY
, //output quality
273 FF_DONTCARE
| DEFAULT_PITCH
,//family and pitch
274 "Courier New"); //font name
277 SelectObject(hDC
, font
);
279 //create 96 display lists, starting at 32
280 wglUseFontBitmaps(hDC
, 32, 96, base
);
282 errorLog
.OutputSuccess("Font created successfully.");
284 return TRUE
; //success!
287 void WINDOW::Shutdown(void) //PROPERLY KILL WINDOW
289 //Delete font display lists
290 glDeleteLists(base
, 96);
294 ChangeDisplaySettings(NULL
, 0); //restore desktop mode
295 ShowCursor(TRUE
); //show mouse cursor
298 errorLog
.OutputNewline();
300 if(hRC
) //have a rendering context?
302 if(!wglMakeCurrent(NULL
, NULL
)) //try to release rend cont
304 errorLog
.OutputError("Release of DC and RC Failed.");
307 errorLog
.OutputSuccess("DC and RC released.");
309 if(!wglDeleteContext(hRC
)) //try to delete RC
311 errorLog
.OutputError("Release Rendering Context Failed.");
314 errorLog
.OutputSuccess("Rendering Context Released.");
316 hRC
=NULL
; //set RC to NULL
319 if(hDC
&& !ReleaseDC(hWnd
, hDC
)) //Are we able to release DC?
321 errorLog
.OutputError("Release of Device Context Failed.");
325 errorLog
.OutputSuccess("Device Context Released.");
327 if(hWnd
&& !DestroyWindow(hWnd
)) //Can we destroy window?
329 errorLog
.OutputError("Could not release hWnd");
333 errorLog
.OutputSuccess("hWnd released.");
335 if (!UnregisterClass("OpenGL", hInstance
)) //can we unreg. class?
337 errorLog
.OutputError("Could Not Unregister Class.");
341 errorLog
.OutputSuccess("Class unregistered.");
344 bool WINDOW::MakeCurrent()
346 if(!wglMakeCurrent(hDC
, hRC
))
348 errorLog
.OutputError("Unable to change current context");
356 //DEAL WITH ALL WINDOW MESSAGES
358 bool WINDOW::HandleMessages(void)
360 while(PeekMessage(&msg
,NULL
,0,0,PM_REMOVE
)) //Is there a message waiting?
362 if(msg
.message
==WM_QUIT
)
363 return false; //if a quit message, return false
366 if(msg
.message
==WM_KEYDOWN
)
367 SetKeyPressed(msg
.wParam
);
369 if(msg
.message
==WM_KEYUP
)
370 SetKeyReleased(msg
.wParam
);
372 if(msg
.message
==WM_LBUTTONDOWN
)
373 SetLeftButtonPressed();
375 if(msg
.message
==WM_RBUTTONDOWN
)
376 SetRightButtonPressed();
378 TranslateMessage(&msg
); //Translate Message
379 DispatchMessage(&msg
); //dispatch message
384 LRESULT CALLBACK
WINDOW::WndProc( HWND hWnd
, //handle for this window
385 UINT uMsg
, //Message for this window
386 WPARAM wParam
, //Additional message information
387 LPARAM lParam
) //Additional Message information
390 switch (uMsg
) //check for windows messages
392 case WM_SYSCOMMAND
: //Intercept system commands
394 switch (wParam
) //check system calls
396 case SC_SCREENSAVE
: //screensaver trying to start?
397 case SC_MONITORPOWER
: //monitor trying to enter powersave?
398 return 0; //prevent from happening
403 case WM_CLOSE
: //receive close message?
404 PostQuitMessage(0); //send quit message
405 return 0; //quit back
409 //pass all unhandled messages to DefWindowProc, windows can handle
410 return DefWindowProc(hWnd
,uMsg
,wParam
,lParam
);
413 void WINDOW::SwapBuffers(void)
415 ::SwapBuffers(hDC
); //swap buffers
418 //void WINDOW::CheckGLError - check for an opengl error
419 void WINDOW::CheckGLError(void)
423 if(!(error
==GL_NO_ERROR
))
425 errorLog
.OutputError("OpenGL Error:");
426 if(error
==GL_INVALID_ENUM
)
428 errorLog
.OutputError(" GL_INVALID_ENUM");
429 errorLog
.OutputError(" GLenum Argument out of range.");
431 if(error
==GL_INVALID_VALUE
)
433 errorLog
.OutputError(" GL_INVALID_VALUE");
434 errorLog
.OutputError(" Numeric Argument out of range.");
436 if(error
==GL_INVALID_OPERATION
)
438 errorLog
.OutputError(" GL_INVALID_OPERATION");
439 errorLog
.OutputError(" Invalid Operation in current state.");
441 if(error
==GL_STACK_UNDERFLOW
)
443 errorLog
.OutputError(" GL_STACK_UNDERFLOW");
444 errorLog
.OutputError(" Stack Underflow.");
446 if(error
==GL_STACK_OVERFLOW
)
448 errorLog
.OutputError(" GL_STACK_OVERFLOW");
449 errorLog
.OutputError(" Stack Overflow.");
451 if(error
==GL_OUT_OF_MEMORY
)
453 errorLog
.OutputError(" GL_OUT_OF_MEMORY");
454 errorLog
.OutputError(" Out of memory.");
459 void WINDOW::SaveScreenshot(void)
463 //first calculate the filename to save to
466 for(int i
=0; i
<1000; i
++)
468 sprintf(filename
, "screen%03d.tga", i
);
470 //try opening this file - if not possible, use this filename
471 file
=fopen(filename
, "rb");
478 //otherwise, the file exists, try next, except if this is the last one
483 errorLog
.OutputError("No space to save screenshot - 0-999 exist");
488 errorLog
.OutputSuccess("Saving %s", filename
);
490 GLubyte TGAheader
[12]={0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0}; //Uncompressed TGA header
491 GLubyte infoHeader
[6];
493 unsigned char * data
=new unsigned char[4*width
*height
];
496 errorLog
.OutputError("Unable to allocate memory for screen data");
500 //read in the screen data
501 glReadPixels(0, 0, width
, height
, GL_RGBA
, GL_UNSIGNED_BYTE
, data
);
503 //data needs to be in BGR format
505 for(int i
=0; i
<(int)width
*height
*4; i
+=4)
507 //repeated XOR to swap bytes 0 and 2
508 data
[i
] ^= data
[i
+2] ^= data
[i
] ^= data
[i
+2];
512 file
= fopen(filename
, "wb");
515 fwrite(TGAheader
, 1, sizeof(TGAheader
), file
);
518 infoHeader
[0]=(width
& 0x00FF);
519 infoHeader
[1]=(width
& 0xFF00) >> 8;
520 infoHeader
[2]=(height
& 0x00FF);
521 infoHeader
[3]=(height
& 0xFF00) >> 8;
526 fwrite(infoHeader
, 1, sizeof(infoHeader
), file
);
528 //save the image data
529 fwrite(data
, 1, width
*height
*4, file
);
533 errorLog
.OutputSuccess("Saved Screenshot: %s", filename
);
537 //Text writing functions
538 void WINDOW::StartTextMode(void)
540 //If not yet created, make display list
541 if(!startTextModeList
)
543 startTextModeList
=glGenLists(1);
544 glNewList(startTextModeList
, GL_COMPILE
);
547 glPushAttrib(GL_ALL_ATTRIB_BITS
);
548 glListBase(base
-32); //set the list base
550 //set modelview matrix
554 //set projection matrix
555 glMatrixMode(GL_PROJECTION
);
558 glOrtho(0.0f
, width
, height
, 0.0f
, -1.0f
, 1.0f
);
561 glDisable(GL_DEPTH_TEST
);
562 glDisable(GL_TEXTURE_2D
);
563 glDisable(GL_LIGHTING
);
565 glBlendFunc(GL_ONE
, GL_ONE
); //if blending, use additive
570 glCallList(startTextModeList
);
573 void WINDOW::Print(int x
, int y
, const char * string
, ...)
575 char text
[256]; //Holds our string
576 va_list va
; //pointer to list of arguments
578 if(string
==NULL
) //If there's no text
581 va_start(va
, string
); //parse string for variables
582 vsprintf(text
, string
, va
); //convert to actual numbers
583 va_end(va
); //results stored in text
585 glRasterPos2i(x
, y
); //go to correct raster position
587 glCallLists(strlen(text
), GL_UNSIGNED_BYTE
, text
); //call display lists
590 void WINDOW::EndTextMode(void)
594 glMatrixMode(GL_MODELVIEW
);
600 void WINDOW::Update()
602 //Mouse buttons are marked as pressed by windows messages
603 //see if any have been released
604 if(mouseLDown
&& !GetAsyncKeyState(VK_LBUTTON
))
607 if(mouseRDown
&& !GetAsyncKeyState(VK_RBUTTON
))
610 //Update the mouse position
611 static POINT mousePosition
;
612 GetCursorPos(&mousePosition
);
617 mouseX
=mousePosition
.x
;
618 mouseY
=mousePosition
.y
;