summaryrefslogtreecommitdiff
path: root/src/wgl/rtotex/window.cpp
blob: ce2c8179ef05536090f1550dfa36098e141dfd8d (plain)
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;
}