1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
|
//////////////////////////////////////////////////////////////////////////////////////////
// WINDOW.cpp
// functions to set up an opengl capable window
// Downloaded from: www.paulsprojects.net
// Created: 21st June 2002
// Modified: 26th August 2002 - Added Input management
// 3rd September 2002 - Added WINDOW::MakeCurrent - to restore focus to
// window after switch
//
// Copyright (c) 2006, Paul Baker
// Distributed under the New BSD Licence. (See accompanying file License.txt or copy at
// http://www.paulsprojects.net/NewBSDLicense.txt)
//////////////////////////////////////////////////////////////////////////////////////////
#include "windows.h"
#include "GL/gl.h"
#include "GL/glu.h"
#include "log.h"
#include "window.h"
extern LOG errorLog;
bool WINDOW::Init(char * windowTitle,
int newWidth, int newHeight,
int newColorBits, int newDepthBits, int newStencilBits,
int fullscreenflag)
//CREATE WINDOW
{
WNDCLASS wc; //windows class structure
DWORD dwExStyle; //extended style info.
DWORD dwStyle; //style info
//set class's member variables
title=windowTitle;
width=newWidth;
height=newHeight;
colorBits=newColorBits;
depthBits=newDepthBits;
stencilBits=newStencilBits;
//set class's fullscreen flag
if(fullscreenflag == FULL_SCREEN)
{
fullscreen=true;
}
if(fullscreenflag == WINDOWED_SCREEN)
{
fullscreen=false;
}
if(fullscreenflag == CHOOSE_SCREEN) //Ask user if fullscreen
{
if(MessageBox(NULL,"Would You Like To Run In Fullscreen Mode?","Start FullScreen",MB_YESNO|MB_ICONQUESTION)==IDNO)
{
fullscreen=false; //If answered no
}
else
{
fullscreen=true; //if answered yes
}
}
RECT WindowRect; //grab rect. upper left/lower right values
WindowRect.left=(long)0;
WindowRect.right=(long)width;
WindowRect.top=(long)0;
WindowRect.bottom=(long)height;
hInstance= GetModuleHandle(NULL); //Grab an instance for window
wc.style= CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
//window style: redraw on move, own DC
wc.lpfnWndProc= (WNDPROC) WndProc; //Wndproc handles messages
wc.cbClsExtra= 0;
wc.cbWndExtra= 0; //no extra window data
wc.hInstance= hInstance; //Set the instance
wc.hIcon= LoadIcon(NULL, IDI_WINLOGO); //load default icon
wc.hCursor= LoadCursor(NULL, IDC_ARROW); //Load arrow cursor
wc.hbrBackground=NULL; //No background rqd for GL
wc.lpszMenuName=NULL; //No menu
wc.lpszClassName="OpenGL"; //set class name
if(!RegisterClass(&wc)) //try to register class
{
errorLog.OutputError("Failed to register the window class");
return FALSE;
}
else
errorLog.OutputSuccess("Window Class Registered");
if(fullscreen) //try to set up fullscreen?
{
DEVMODE dmScreenSettings; //Device mode
memset(&dmScreenSettings,0,sizeof(dmScreenSettings));
//clear memory
dmScreenSettings.dmSize=sizeof(dmScreenSettings);
//size of devmode structure
dmScreenSettings.dmPelsWidth=width; //selected width
dmScreenSettings.dmPelsHeight=height; //selected height
dmScreenSettings.dmBitsPerPel=colorBits; //selected bpp
dmScreenSettings.dmFields=DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
if(ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
//try to set mode.CDS_FULLSCREEN removes start bar
{
//If mode fails, give 2 options, quit or run in window
if(MessageBox(NULL, "The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?",title, MB_YESNO|MB_ICONEXCLAMATION)==IDYES)
{
fullscreen=FALSE; //if "yes", try windowed
}
else
{
//tell user program is closing
errorLog.OutputError("Program Closed, As Fullscreen Mode Not Supported.");
return FALSE; //exit and return FALSE
}
}
}
if (fullscreen) //still fullscreen?
{
dwExStyle=WS_EX_APPWINDOW; //window extended style
dwStyle=WS_POPUP | WS_VISIBLE; //window style (no border), visible
ShowCursor(FALSE); //hide mouse pointer
}
else
{
dwExStyle=WS_EX_CLIENTEDGE; //window extended style(3d look)
dwStyle=WS_SYSMENU | WS_BORDER | WS_CAPTION | WS_VISIBLE;
//window style (close button, title bar, border, visible)
}
AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);
//adjust window to actual requested size, rather than including borders in size. in fullscreen, no effect
if(!(hWnd=CreateWindowEx( dwExStyle, //extended style for window
"OpenGL", //class name
title, //window title
WS_CLIPSIBLINGS | //required style
WS_CLIPCHILDREN | //required style
dwStyle, //Selected style
0, 0, //window position
WindowRect.right-WindowRect.left, //calculate adjusted width
WindowRect.bottom-WindowRect.top, //calculate adjusted height
NULL, // no parent window
NULL, //No Menu
hInstance, //Instance
NULL))) //Dont pass anything to WM_CREATE
{
Shutdown(); //if not set up, reset display
errorLog.OutputError("Window Creation Error.");
//pop up error message
return FALSE; //return false, to quit program
}
else
errorLog.OutputSuccess("Window Created.");
//set up pixel format(openGL supporting, RGBA, correct bits
GLuint pixelFormat; //holds result after searching for mode match
//calculate alpha bits
int alphaBits=0;
if(colorBits==32)
alphaBits=8;
static PIXELFORMATDESCRIPTOR pfd= //pfd tells windows how we want things to be
{
sizeof(PIXELFORMATDESCRIPTOR), //size of Pixel format descriptor
1, //Version Number
PFD_DRAW_TO_WINDOW | //must support window
PFD_SUPPORT_OPENGL | //must support opengl
PFD_DOUBLEBUFFER, //must support double buffer
PFD_TYPE_RGBA, //request RGBA format
colorBits, //select colour depth
0, 0, 0, 0, 0, 0, //colour bits ignored
alphaBits, //alpha buffer bits
0, //shift bit ignored
0, //no accumulation buffer
0, 0, 0, 0, //accumulation bits ignored
depthBits, //z buffer bits
stencilBits, //stencil buffer bits
0, //no auxiliary buffer
PFD_MAIN_PLANE, //main drawing layer
0, //reserved
0, 0, 0 //layer masks ignored
};
if(!(hDC=GetDC(hWnd))) //did we get a device context?
{ //if not
Shutdown(); //Reset display
errorLog.OutputError("Can't Create a GL Device context.");
return FALSE; //return false, to exit
}
else
errorLog.OutputSuccess("DC Created");
if(!(pixelFormat=ChoosePixelFormat(hDC,&pfd))) //found a matching pixel format?
{ //if not
Shutdown();
errorLog.OutputError("Can't Find a Suitable PixelFormat.");
return FALSE;
}
else
errorLog.OutputSuccess("Pixel Format Found.");
if(!SetPixelFormat(hDC, pixelFormat,&pfd)) //are we able to set pixel format?
{ //if not
Shutdown();
errorLog.OutputError("Can't set the pixelformat.");
return FALSE;
}
else
errorLog.OutputSuccess("Pixel Format set.");
if(!(hRC=wglCreateContext(hDC))) //are we able to get rendering context?
{ //if not
Shutdown();
errorLog.OutputError("Can't create a GL rendering context.");
return FALSE;
}
else
errorLog.OutputSuccess("GL Rendering Context Created.");
if(!MakeCurrent()) //are we able to activate rendering context?
{ //if not
Shutdown();
return FALSE;
}
else
errorLog.OutputSuccess("GL Rendering Context Activated.");
//get pixel format parameters
static PIXELFORMATDESCRIPTOR finalPfd;
DescribePixelFormat(hDC, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &finalPfd);
//output window parameters
errorLog.OutputNewline();
errorLog.OutputSuccess("Window Size: (%d, %d)", width, height);
errorLog.OutputSuccess("Color Buffer Bits (R, G, B, A): (%d, %d, %d, %d)",
finalPfd.cRedBits,
finalPfd.cGreenBits,
finalPfd.cBlueBits,
finalPfd.cAlphaBits);
errorLog.OutputSuccess("Depth Buffer Bits: %d", finalPfd.cDepthBits);
errorLog.OutputSuccess("Stencil Buffer Bits: %d", finalPfd.cStencilBits);
errorLog.OutputNewline();
ShowWindow(hWnd,SW_SHOW); //show window
SetForegroundWindow(hWnd); //slightly higher priority
SetFocus(hWnd); //Set keyboard focus to the window
errorLog.OutputSuccess("Window Created!");
errorLog.OutputNewline();
//Init the font
HFONT font; //windows font ID
//create 96 display lists
base = glGenLists(96);
font = CreateFont( -18, //font height
0, //default width
0, 0, //angles - escapement, orientation
FW_BOLD, //font weight, 0-1000, NORMAL, BOLD
false, //italic
false, //underline
false, //strikeout
ANSI_CHARSET, //character set
OUT_TT_PRECIS, //precision
CLIP_DEFAULT_PRECIS, //clip precision
ANTIALIASED_QUALITY, //output quality
FF_DONTCARE | DEFAULT_PITCH,//family and pitch
"Courier New"); //font name
//select the font
SelectObject(hDC, font);
//create 96 display lists, starting at 32
wglUseFontBitmaps(hDC, 32, 96, base);
errorLog.OutputSuccess("Font created successfully.");
return TRUE; //success!
}
void WINDOW::Shutdown(void) //PROPERLY KILL WINDOW
{
//Delete font display lists
glDeleteLists(base, 96);
if (fullscreen)
{
ChangeDisplaySettings(NULL, 0); //restore desktop mode
ShowCursor(TRUE); //show mouse cursor
}
errorLog.OutputNewline();
if(hRC) //have a rendering context?
{
if(!wglMakeCurrent(NULL, NULL)) //try to release rend cont
{
errorLog.OutputError("Release of DC and RC Failed.");
}
else
errorLog.OutputSuccess("DC and RC released.");
if(!wglDeleteContext(hRC)) //try to delete RC
{
errorLog.OutputError("Release Rendering Context Failed.");
}
else
errorLog.OutputSuccess("Rendering Context Released.");
hRC=NULL; //set RC to NULL
}
if(hDC && !ReleaseDC(hWnd, hDC)) //Are we able to release DC?
{
errorLog.OutputError("Release of Device Context Failed.");
hDC=NULL;
}
else
errorLog.OutputSuccess("Device Context Released.");
if(hWnd && !DestroyWindow(hWnd)) //Can we destroy window?
{
errorLog.OutputError("Could not release hWnd");
hWnd=NULL;
}
else
errorLog.OutputSuccess("hWnd released.");
if (!UnregisterClass("OpenGL", hInstance)) //can we unreg. class?
{
errorLog.OutputError("Could Not Unregister Class.");
hInstance=NULL;
}
else
errorLog.OutputSuccess("Class unregistered.");
}
bool WINDOW::MakeCurrent()
{
if(!wglMakeCurrent(hDC, hRC))
{
errorLog.OutputError("Unable to change current context");
return false;
}
return true;
}
//DEAL WITH ALL WINDOW MESSAGES
//Message Pump
bool WINDOW::HandleMessages(void)
{
while(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) //Is there a message waiting?
{
if(msg.message==WM_QUIT)
return false; //if a quit message, return false
//handle input
if(msg.message==WM_KEYDOWN)
SetKeyPressed(msg.wParam);
if(msg.message==WM_KEYUP)
SetKeyReleased(msg.wParam);
if(msg.message==WM_LBUTTONDOWN)
SetLeftButtonPressed();
if(msg.message==WM_RBUTTONDOWN)
SetRightButtonPressed();
TranslateMessage(&msg); //Translate Message
DispatchMessage(&msg); //dispatch message
}
return true;
}
LRESULT CALLBACK WINDOW::WndProc( HWND hWnd, //handle for this window
UINT uMsg, //Message for this window
WPARAM wParam, //Additional message information
LPARAM lParam) //Additional Message information
{
switch (uMsg) //check for windows messages
{
case WM_SYSCOMMAND: //Intercept system commands
{
switch (wParam) //check system calls
{
case SC_SCREENSAVE: //screensaver trying to start?
case SC_MONITORPOWER: //monitor trying to enter powersave?
return 0; //prevent from happening
}
break;
}
case WM_CLOSE: //receive close message?
PostQuitMessage(0); //send quit message
return 0; //quit back
break;
}
//pass all unhandled messages to DefWindowProc, windows can handle
return DefWindowProc(hWnd,uMsg,wParam,lParam);
}
void WINDOW::SwapBuffers(void)
{
::SwapBuffers(hDC); //swap buffers
}
//void WINDOW::CheckGLError - check for an opengl error
void WINDOW::CheckGLError(void)
{
GLenum error;
error=glGetError();
if(!(error==GL_NO_ERROR))
{
errorLog.OutputError("OpenGL Error:");
if(error==GL_INVALID_ENUM)
{
errorLog.OutputError(" GL_INVALID_ENUM");
errorLog.OutputError(" GLenum Argument out of range.");
}
if(error==GL_INVALID_VALUE)
{
errorLog.OutputError(" GL_INVALID_VALUE");
errorLog.OutputError(" Numeric Argument out of range.");
}
if(error==GL_INVALID_OPERATION)
{
errorLog.OutputError(" GL_INVALID_OPERATION");
errorLog.OutputError(" Invalid Operation in current state.");
}
if(error==GL_STACK_UNDERFLOW)
{
errorLog.OutputError(" GL_STACK_UNDERFLOW");
errorLog.OutputError(" Stack Underflow.");
}
if(error==GL_STACK_OVERFLOW)
{
errorLog.OutputError(" GL_STACK_OVERFLOW");
errorLog.OutputError(" Stack Overflow.");
}
if(error==GL_OUT_OF_MEMORY)
{
errorLog.OutputError(" GL_OUT_OF_MEMORY");
errorLog.OutputError(" Out of memory.");
}
}
}
void WINDOW::SaveScreenshot(void)
{
FILE * file;
//first calculate the filename to save to
char filename[32];
for(int i=0; i<1000; i++)
{
sprintf(filename, "screen%03d.tga", i);
//try opening this file - if not possible, use this filename
file=fopen(filename, "rb");
if(!file)
{
break;
}
//otherwise, the file exists, try next, except if this is the last one
fclose(file);
if(i==999)
{
errorLog.OutputError("No space to save screenshot - 0-999 exist");
return;
}
}
errorLog.OutputSuccess("Saving %s", filename);
GLubyte TGAheader[12]={0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0}; //Uncompressed TGA header
GLubyte infoHeader[6];
unsigned char * data=new unsigned char[4*width*height];
if(!data)
{
errorLog.OutputError("Unable to allocate memory for screen data");
return;
}
//read in the screen data
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data);
//data needs to be in BGR format
//swap b and r
for(int i=0; i<(int)width*height*4; i+=4)
{
//repeated XOR to swap bytes 0 and 2
data[i] ^= data[i+2] ^= data[i] ^= data[i+2];
}
//open the file
file = fopen(filename, "wb");
//save header
fwrite(TGAheader, 1, sizeof(TGAheader), file);
//save info header
infoHeader[0]=(width & 0x00FF);
infoHeader[1]=(width & 0xFF00) >> 8;
infoHeader[2]=(height & 0x00FF);
infoHeader[3]=(height & 0xFF00) >> 8;
infoHeader[4]=32;
infoHeader[5]=0;
//save info header
fwrite(infoHeader, 1, sizeof(infoHeader), file);
//save the image data
fwrite(data, 1, width*height*4, file);
fclose(file);
errorLog.OutputSuccess("Saved Screenshot: %s", filename);
return;
}
//Text writing functions
void WINDOW::StartTextMode(void)
{
//If not yet created, make display list
if(!startTextModeList)
{
startTextModeList=glGenLists(1);
glNewList(startTextModeList, GL_COMPILE);
{
//save states
glPushAttrib(GL_ALL_ATTRIB_BITS);
glListBase(base-32); //set the list base
//set modelview matrix
glPushMatrix();
glLoadIdentity();
//set projection matrix
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0.0f, width, height, 0.0f, -1.0f, 1.0f);
//set states
glDisable(GL_DEPTH_TEST);
glDisable(GL_TEXTURE_2D);
glDisable(GL_LIGHTING);
glBlendFunc(GL_ONE, GL_ONE); //if blending, use additive
}
glEndList();
}
glCallList(startTextModeList);
}
void WINDOW::Print(int x, int y, const char * string, ...)
{
char text[256]; //Holds our string
va_list va; //pointer to list of arguments
if(string==NULL) //If there's no text
return; //Do nothing
va_start(va, string); //parse string for variables
vsprintf(text, string, va); //convert to actual numbers
va_end(va); //results stored in text
glRasterPos2i(x, y); //go to correct raster position
glCallLists(strlen(text), GL_UNSIGNED_BYTE, text); //call display lists
}
void WINDOW::EndTextMode(void)
{
//restore states
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glPopAttrib();
}
//Update input
void WINDOW::Update()
{
//Mouse buttons are marked as pressed by windows messages
//see if any have been released
if(mouseLDown && !GetAsyncKeyState(VK_LBUTTON))
mouseLDown=false;
if(mouseRDown && !GetAsyncKeyState(VK_RBUTTON))
mouseRDown=false;
//Update the mouse position
static POINT mousePosition;
GetCursorPos(&mousePosition);
oldMouseX=mouseX;
oldMouseY=mouseY;
mouseX=mousePosition.x;
mouseY=mousePosition.y;
}
|