1 #ifndef NO_OGL
2 
3 //OpenGL library
4 #pragma comment( lib, "OpenGL32" )
5 
6 // MFC
7 #include "stdafx.h"
8 
9 //GUI
10 #include "MainWnd.h"
11 #include "FullscreenSettings.h"
12 
13 // Internals
14 #include "../System.h"
15 #include "../gba/GBA.h"
16 #include "../gba/Globals.h"
17 #include "../Util.h"
18 #include "../gb/gbGlobals.h"
19 #include "../common/memgzio.h"
20 
21 //Math
22 #include <cmath>
23 #include <sys/stat.h>
24 
25 // OpenGL
26 #include <gl/GL.h> // main include file
27 #include <GL/glu.h>
28 #include "glFont.h"
29 #include <gl/glext.h>
30 typedef BOOL (APIENTRY *PFNWGLSWAPINTERVALFARPROC)( int );
31 extern int Init_2xSaI(u32);
32 extern void winlog(const char *,...);
33 extern int systemSpeed;
34 
35 #ifdef _DEBUG
36 #define new DEBUG_NEW
37 #undef THIS_FILE
38 static char THIS_FILE[] = __FILE__;
39 #endif
40 
41 #ifdef MMX
42 extern "C" bool cpu_mmx;
43 extern bool detectMMX();
44 #endif
45 
46 
47 class OpenGLDisplay : public IDisplay {
48 private:
49 	HDC hDC;
50 	HGLRC hRC;
51 	GLuint texture;
52 	int width,height;
53 	float size;
54 	u8 *filterData;
55 	RECT destRect;
56 	bool failed;
57 	GLFONT font;
58 	int pitch;
59 	u8 *data;
60 	DWORD currentAdapter;
61 
62 	void initializeMatrices( int w, int h );
63 	bool initializeTexture( int w, int h );
64 	void updateFiltering( int value );
65 	void setVSync( int interval = 1 );
66 	void calculateDestRect( int w, int h );
67 	void initializeFont();
68 
69 public:
70 	OpenGLDisplay();
71 	virtual ~OpenGLDisplay();
getType()72 	virtual DISPLAY_TYPE getType() { return OPENGL; };
73 
74 	virtual void EnableOpenGL();
75 	virtual void DisableOpenGL();
76 	virtual bool initialize();
77 	virtual void cleanup();
78 	virtual void clear();
79 	virtual void render();
80 	virtual bool changeRenderSize( int w, int h );
81 	virtual void resize( int w, int h );
82 	virtual void setOption( const char *, int );
83 	virtual bool selectFullScreenMode( VIDEO_MODE &mode );
84 };
85 
86 #include "gzglfont.h"
87 //Load GL font
initializeFont()88 void OpenGLDisplay::initializeFont()
89 {
90     int ret;
91     z_stream strm;
92 	char *buf = (char *)malloc(GZGLFONT_SIZE);
93 
94     /* allocate inflate state */
95     strm.zalloc = Z_NULL;
96     strm.zfree = Z_NULL;
97     strm.opaque = Z_NULL;
98     strm.avail_in = 0;
99     strm.next_in = Z_NULL;
100     ret = inflateInit2(&strm, 16+MAX_WBITS);
101     if (ret != Z_OK)
102         return;
103 
104     strm.avail_in = sizeof(gzglfont);
105     strm.next_in = gzglfont;
106     strm.avail_out = GZGLFONT_SIZE;
107 	strm.next_out = (Bytef *)buf;
108     ret = inflate(&strm, Z_NO_FLUSH);
109 	if (ret==Z_STREAM_END)
110 	{
111 		glGenTextures( 1, &texture );
112 		glFontCreate(&font, (char *)buf, texture);
113 		texture=0;
114 	}
115 	free(buf);
116     (void)inflateEnd(&strm);
117 }
118 
119 //OpenGL class constructor
OpenGLDisplay()120 OpenGLDisplay::OpenGLDisplay()
121 {
122 	hDC = NULL;
123 	hRC = NULL;
124 	texture = 0;
125 	width = 0;
126 	height = 0;
127 	size = 0.0f;
128 	failed = false;
129 	filterData = NULL;
130 	currentAdapter = 0;
131 }
132 
133 //OpenGL class destroyer
~OpenGLDisplay()134 OpenGLDisplay::~OpenGLDisplay()
135 {
136 	cleanup();
137 }
138 
139 //Set OpenGL PFD and contexts
EnableOpenGL()140 void OpenGLDisplay::EnableOpenGL()
141 {
142 	PIXELFORMATDESCRIPTOR pfd;
143 	// get the device context (DC)
144 	hDC = GetDC( theApp.m_pMainWnd->GetSafeHwnd() );
145 	// set the pixel format for the DC
146 	ZeroMemory( &pfd, sizeof( pfd ) );
147 	pfd.nSize = sizeof( pfd );
148 	pfd.nVersion = 1;
149 	pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
150 	pfd.iPixelType = PFD_TYPE_RGBA;
151 	pfd.cColorBits = 24;
152 	pfd.cDepthBits = 16;
153 	pfd.iLayerType = PFD_MAIN_PLANE;
154     SetPixelFormat (GetDC (theApp.m_pMainWnd->GetSafeHwnd()), ChoosePixelFormat ( GetDC (theApp.m_pMainWnd->GetSafeHwnd()), &pfd), &pfd);
155     wglMakeCurrent (GetDC (theApp.m_pMainWnd->GetSafeHwnd()), wglCreateContext(GetDC (theApp.m_pMainWnd->GetSafeHwnd()) ) );
156 }
157 //Remove contexts
DisableOpenGL()158 void OpenGLDisplay::DisableOpenGL()
159 {
160 	wglMakeCurrent( NULL, NULL );
161 	wglDeleteContext( hRC );
162 	ReleaseDC( theApp.m_pMainWnd->GetSafeHwnd(), hDC );
163 }
164 //Remove resources used
cleanup()165 void OpenGLDisplay::cleanup()
166 {
167 	if(texture != 0) {
168 		glDeleteTextures(1, &texture);
169 		texture = 0;
170 	}
171 
172 	DisableOpenGL();
173 	if(filterData) {
174 		free(filterData);
175 		filterData = NULL;
176 	}
177 	width = 0;
178 	height = 0;
179 	size = 0.0f;
180 
181 	DISPLAY_DEVICE dev;
182 	ZeroMemory( &dev, sizeof(dev) );
183 	dev.cb = sizeof(dev);
184 	EnumDisplayDevices( NULL, currentAdapter, &dev, 0 );
185 	// restore default video mode
186 	ChangeDisplaySettingsEx( dev.DeviceName, NULL, NULL, 0, NULL );
187 }
188 
189 //init renderer
initialize()190 bool OpenGLDisplay::initialize()
191 {
192 	switch( theApp.cartridgeType )
193 	{
194 	case IMAGE_GBA:
195 		sizeX = 240;
196 		sizeY = 160;
197 		break;
198 	case IMAGE_GB:
199 		if ( gbBorderOn )
200 		{
201 			sizeX = 256;
202 			sizeY = 224;
203 		}
204 		else
205 		{
206 			sizeX = 160;
207 			sizeY = 144;
208 		}
209 		break;
210 	}
211 
212 
213 	switch(videoOption)
214 	{
215 	case VIDEO_1X:
216 		surfaceSizeX = sizeX;
217 		surfaceSizeY = sizeY;
218 		break;
219 	case VIDEO_2X:
220 		surfaceSizeX = sizeX * 2;
221 		surfaceSizeY = sizeY * 2;
222 		break;
223 	case VIDEO_3X:
224 		surfaceSizeX = sizeX * 3;
225 		surfaceSizeY = sizeY * 3;
226 		break;
227 	case VIDEO_4X:
228 		surfaceSizeX = sizeX * 4;
229 		surfaceSizeY = sizeY * 4;
230 		break;
231 	case VIDEO_5X:
232 		surfaceSizeX = sizeX * 5;
233 		surfaceSizeY = sizeY * 5;
234 		break;
235 	case VIDEO_6X:
236 		surfaceSizeX = sizeX * 6;
237 		surfaceSizeY = sizeY * 6;
238 		break;
239 	case VIDEO_320x240:
240 	case VIDEO_640x480:
241 	case VIDEO_800x600:
242 	case VIDEO_1024x768:
243 	case VIDEO_1280x1024:
244 	case VIDEO_OTHER:
245 		{
246 			if( fullScreenStretch ) {
247 				surfaceSizeX = fsWidth;
248 				surfaceSizeY = fsHeight;
249 			} else {
250 				float scaleX = (float)fsWidth / (float)sizeX;
251 				float scaleY = (float)fsHeight / (float)sizeY;
252 				float min = ( scaleX < scaleY ) ? scaleX : scaleY;
253 				if( maxScale )
254 					min = ( min > (float)maxScale ) ? (float)maxScale : min;
255 				surfaceSizeX = (int)((float)sizeX * min);
256 				surfaceSizeY = (int)((float)sizeY * min);
257 			}
258 		}
259 		break;
260 	}
261 
262 	theApp.rect.left = 0;
263 	theApp.rect.top = 0;
264 	theApp.rect.right = sizeX;
265 	theApp.rect.bottom = sizeY;
266 
267 	theApp.dest.left = 0;
268 	theApp.dest.top = 0;
269 	theApp.dest.right = surfaceSizeX;
270 	theApp.dest.bottom = surfaceSizeY;
271 
272 	DWORD style = WS_POPUP | WS_VISIBLE;
273 	DWORD styleEx = 0;
274 
275 	if( videoOption <= VIDEO_6X )
276 		style |= WS_OVERLAPPEDWINDOW;
277 	else
278 		styleEx = 0;
279 
280 	if( videoOption <= VIDEO_6X )
281 		AdjustWindowRectEx( &theApp.dest, style, TRUE, styleEx );
282 	else
283 		AdjustWindowRectEx( &theApp.dest, style, FALSE, styleEx );
284 
285 	int winSizeX = theApp.dest.right - theApp.dest.left;
286 	int winSizeY = theApp.dest.bottom - theApp.dest.top;
287 	int x = 0, y = 0;
288 
289 	if( videoOption <= VIDEO_6X ) {
290 		x = windowPositionX;
291 		y = windowPositionY;
292 	} else {
293 		winSizeX = fsWidth;
294 		winSizeY = fsHeight;
295 	}
296 
297 
298 
299 	theApp.updateMenuBar();
300 
301 	theApp.adjustDestRect();
302 
303 	currentAdapter = fsAdapter;
304 	DISPLAY_DEVICE dev;
305 	ZeroMemory( &dev, sizeof(dev) );
306 	dev.cb = sizeof(dev);
307 	EnumDisplayDevices( NULL, currentAdapter, &dev, 0 );
308 	if( videoOption >= VIDEO_320x240 ) {
309 		// enter full screen mode
310 		DEVMODE mode;
311 		ZeroMemory( &mode, sizeof(mode) );
312 		mode.dmSize = sizeof(mode);
313 		mode.dmBitsPerPel = fsColorDepth;
314 		mode.dmPelsWidth = fsWidth;
315 		mode.dmPelsHeight = fsHeight;
316 		mode.dmDisplayFrequency = fsFrequency;
317 		mode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY;
318 		LONG ret = ChangeDisplaySettingsEx( dev.DeviceName, &mode, NULL, CDS_FULLSCREEN, NULL );
319 		if( ret != DISP_CHANGE_SUCCESSFUL ) {
320 			systemMessage( 0, "Can not change display mode!" );
321 			failed = true;
322 		}
323 	} else {
324 		// restore default mode
325 		ChangeDisplaySettingsEx( dev.DeviceName, NULL, NULL, 0, NULL );
326 	}
327 
328 	EnableOpenGL();
329 	initializeFont();
330 	glPushAttrib( GL_ENABLE_BIT );
331 	glDisable( GL_DEPTH_TEST );
332 	glDisable( GL_CULL_FACE );
333 	glEnable( GL_TEXTURE_2D );
334 	glEnable(GL_BLEND);
335 	glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
336 
337 	initializeMatrices( surfaceSizeX, surfaceSizeY );
338 
339 	setVSync( vsync && !gba_joybus_active );
340 
341 #ifdef MMX
342 	if(!disableMMX)
343 		cpu_mmx = theApp.detectMMX();
344 	else
345 		cpu_mmx = 0;
346 #endif
347 
348 	systemRedShift = 19;
349 	systemGreenShift = 11;
350 	systemBlueShift = 3;
351 	systemColorDepth = 32;
352 	fsColorDepth = 32;
353 
354 	Init_2xSaI(32);
355 
356 	utilUpdateSystemColorMaps(theApp.cartridgeType == IMAGE_GBA && gbColorOption == 1);
357 	theApp.updateFilter();
358 	theApp.updateIFB();
359 	pitch = filterWidth * (systemColorDepth>>3) + 4;
360 	data = pix + ( sizeX + 1 ) * 4;
361 
362 	if(failed)
363 		return false;
364 
365 	return true;
366 }
367 
368 //clear colour buffer
clear()369 void OpenGLDisplay::clear()
370 {
371 	glClearColor(0.0,0.0,0.0,1.0);
372 	glClear( GL_COLOR_BUFFER_BIT );
373 }
374 
375 //main render func
render()376 void OpenGLDisplay::render()
377 {
378 	clear();
379 
380 	pitch = filterWidth * (systemColorDepth>>3) + 4;
381 	data = pix + ( sizeX + 1 ) * 4;
382 
383 	// apply pixel filter
384 	if(theApp.filterFunction) {
385 		data = filterData;
386 		theApp.filterFunction(
387 			pix + pitch,
388 			pitch,
389 			(u8*)theApp.delta,
390 			(u8*)filterData,
391 			width * 4 ,
392 			filterWidth,
393 			filterHeight);
394 	}
395 
396 	// Texturemap complete texture to surface
397 	// so we have free scaling and antialiasing
398 
399 	if( theApp.filterFunction ) {
400 		glPixelStorei( GL_UNPACK_ROW_LENGTH, width);
401 	} else {
402 		glPixelStorei( GL_UNPACK_ROW_LENGTH, sizeX + 1 );
403 	}
404     glTexSubImage2D(GL_TEXTURE_2D,0,0,0,width,height,GL_BGRA,GL_UNSIGNED_BYTE,data );
405 
406 
407 	glBegin( GL_QUADS );
408 
409 	glTexCoord2f( 0.0f, 0.0f );
410 	glVertex3i( 0, 0, 0 );
411 
412 	glTexCoord2f( (float)(width) / size, 0.0f );
413 	glVertex3i( surfaceSizeX, 0, 0 );
414 
415 	glTexCoord2f( (float)(width) / size, (float)(height) / size );
416 	glVertex3i( surfaceSizeX, surfaceSizeY, 0 );
417 
418 	glTexCoord2f( 0.0f, (float)(height) / size );
419 	glVertex3i( 0, surfaceSizeY, 0 );
420 	glEnd();
421 
422 
423 	if( showSpeed ) { // && ( videoOption > VIDEO_6X ) ) {
424 		char buffer[30];
425 		if( showSpeed == 1 ) {
426 			sprintf( buffer, "%3d%%", systemSpeed );
427 		} else {
428 			sprintf( buffer, "%3d%%(%d, %d fps)", systemSpeed, systemFrameSkip, showRenderedFrames );
429 		}
430 		glFontBegin(&font);
431 		glPushMatrix();
432 		float fontscale = (float)surfaceSizeX / 100.0f;
433 		glScalef(fontscale, fontscale, fontscale);
434 		glColor4f(1.0f, 0.25f, 0.25f, 1.0f);
435 		glFontTextOut(buffer, (surfaceSizeX-(strlen(buffer)*11))/(fontscale*2), (surfaceSizeY-20)/fontscale, 0);
436 		glPopMatrix();
437 		glFontEnd();
438 		glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
439 		glBindTexture( GL_TEXTURE_2D, texture );
440 	}
441 	if( screenMessage ) {
442 		if( ( ( GetTickCount() - theApp.screenMessageTime ) < 3000 ) && !disableStatusMessages ) {
443 			glFontBegin(&font);
444 			glPushMatrix();
445 
446 			float fontscale = (float)surfaceSizeX / 100.0f;
447 			glScalef(fontscale, fontscale, fontscale);
448 			glColor4f(1.0f, 0.25f, 0.25f, 1.0f);
449 			glFontTextOut((char *)((const char *)theApp.screenMessageBuffer), (surfaceSizeX-(theApp.screenMessageBuffer.GetLength()*11))/(fontscale*2), (surfaceSizeY-40)/fontscale, 0);
450 			glPopMatrix();
451 			glFontEnd();
452 			glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
453 			glBindTexture( GL_TEXTURE_2D, texture );
454 		} else {
455 			screenMessage = false;
456 		}
457 	}
458 
459 	glFlush();
460 	SwapBuffers( hDC );
461 	// since OpenGL draws on the back buffer,
462 	// we have to swap it to the front buffer to see the content
463 
464 }
465 
466 //resize screen
resize(int w,int h)467 void OpenGLDisplay::resize( int w, int h )
468 {
469 	initializeMatrices( w, h );
470 }
471 
472 //update filtering methods
updateFiltering(int value)473 void OpenGLDisplay::updateFiltering( int value )
474 {
475 	switch( value )
476 	{
477 	case 0:
478 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
479 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
480 		break;
481 	case 1:
482 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
483 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
484 		break;
485 	}
486 
487 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
488 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
489 }
490 
491 //init projection matrixes and viewports
initializeMatrices(int w,int h)492 void OpenGLDisplay::initializeMatrices( int w, int h )
493 {
494 	if( fullScreenStretch ) {
495 		glViewport( 0, 0, w, h );
496 	} else {
497 		calculateDestRect( w, h );
498 		glViewport(
499 			destRect.left,
500 			destRect.top,
501 			destRect.right - destRect.left,
502 			destRect.bottom - destRect.top );
503 	}
504 
505 	glMatrixMode( GL_PROJECTION );
506 	glLoadIdentity();
507 	glOrtho(
508 		/* left   */ 1.0f,
509 		/* right  */ (GLdouble)(w - 1),
510 		/* bottom */ (GLdouble)(h - 1),
511 		/* top    */ 1.0f,
512 		0.0f,
513 		1.0f );
514 
515 	glMatrixMode(GL_MODELVIEW);
516 	glLoadIdentity();
517 
518 }
519 
520 //init font texture
initializeTexture(int w,int h)521 bool OpenGLDisplay::initializeTexture( int w, int h )
522 {
523 	// size = 2^n
524 	// w = 24  > size = 256 = 2^8
525 	// w = 255 > size = 256 = 2^8
526 	// w = 256 > size = 512 = 2^9
527 	// w = 300 > size = 512 = 2^9
528 	// OpenGL textures have to be square and a power of 2
529 	// We could use methods that allow tex's to not be powers of two
530 	// but that requires extra OGL extensions
531 
532 	float n1 = log10( (float)w ) / log10( 2.0f );
533 	float n2 = log10( (float)h ) / log10( 2.0f );
534 	float n = ( n1 > n2 ) ? n1 : n2;
535 
536 	if( ((float)((int)n)) != n ) {
537 		// round up
538 		n = ((float)((int)n)) + 1.0f;
539 	}
540 
541 	size = pow( 2.0f, n );
542 
543 	glGenTextures( 1, &texture );
544 	glBindTexture( GL_TEXTURE_2D, texture );
545 	updateFiltering( glFilter );
546 
547 	glTexImage2D(
548 		GL_TEXTURE_2D,
549 		0,
550 		GL_RGBA,
551 		(GLsizei)size,
552 		(GLsizei)size,
553 		0,
554 		GL_RGBA,
555 		GL_UNSIGNED_BYTE,
556 		NULL );
557 
558 	width = w;
559 	height = h;
560 
561 	//return ( glGetError() == GL_NO_ERROR) ? true : false;
562 	// Workaround: We usually get GL_INVALID_VALUE, but somehow it works nevertheless
563 	// In consequence, we must not treat it as an error or else the app behaves as if an error occured.
564 	// This in the end results in theApp->input not being created = no input when switching from D3D to OGL
565 	return true;
566 }
567 
568 //turn vsync on or off
setVSync(int interval)569 void OpenGLDisplay::setVSync( int interval )
570 {
571 	const char *extensions = (const char *)glGetString( GL_EXTENSIONS );
572 
573 	if( strstr( extensions, "WGL_EXT_swap_control" ) == 0 ) {
574 		winlog( "Error: WGL_EXT_swap_control extension not supported on your computer.\n" );
575 		return;
576 	} else {
577 		PFNWGLSWAPINTERVALFARPROC wglSwapIntervalEXT = NULL;
578 		wglSwapIntervalEXT = (PFNWGLSWAPINTERVALFARPROC)wglGetProcAddress( "wglSwapIntervalEXT" );
579 		if( wglSwapIntervalEXT ) {
580 			wglSwapIntervalEXT( interval );
581 		}
582 	}
583 }
584 
585 //change render size for fonts and filter data
changeRenderSize(int w,int h)586 bool OpenGLDisplay::changeRenderSize( int w, int h )
587 {
588 	if( (width != w) || (height != h) ) {
589 		if( texture != 0 ) {
590 			glDeleteTextures( 1, &texture );
591 			texture = 0;
592 		}
593 
594 		if( !initializeTexture( w, h ) ) {
595 			failed = true;
596 			return false;
597 		}
598 		if (filterData)
599 			free(filterData);
600 		filterData = (u8 *)malloc(4*w*h);
601 	}
602 
603 	return true;
604 }
605 
606 //calculate RECTs
calculateDestRect(int w,int h)607 void OpenGLDisplay::calculateDestRect( int w, int h )
608 {
609 	float scaleX = (float)w / (float)width;
610 	float scaleY = (float)h / (float)height;
611 	float min = (scaleX < scaleY) ? scaleX : scaleY;
612 	if( maxScale && (min > maxScale) ) {
613 		min = (float)maxScale;
614 	}
615 	destRect.left = 0;
616 	destRect.top = 0;
617 	destRect.right = (LONG)(width * min);
618 	destRect.bottom = (LONG)(height * min);
619 	if( destRect.right != w ) {
620 		LONG diff = (w - destRect.right) / 2;
621 		destRect.left += diff;
622 		destRect.right += diff;
623 	}
624 	if( destRect.bottom != h ) {
625 		LONG diff = (h - destRect.bottom) / 2;
626 		destRect.top += diff;
627 		destRect.bottom += diff;
628 	}
629 
630 }
631 
632 //config options
setOption(const char * option,int value)633 void OpenGLDisplay::setOption( const char *option, int value )
634 {
635 	if( !_tcscmp( option, _T("vsync") ) ) {
636 		setVSync( value );
637 	}
638 
639 	if( !_tcscmp( option, _T("glFilter") ) ) {
640 		updateFiltering( value );
641 	}
642 
643 	if( !_tcscmp( option, _T("maxScale") ) ) {
644 		initializeMatrices( theApp.dest.right-theApp.dest.left, theApp.dest.bottom-theApp.dest.top );
645 	}
646 
647 	if( !_tcscmp( option, _T("fullScreenStretch") ) ) {
648 		initializeMatrices( theApp.dest.right-theApp.dest.left, theApp.dest.bottom-theApp.dest.top );
649 	}
650 }
651 
652 //set fullscreen mode
selectFullScreenMode(VIDEO_MODE & mode)653 bool OpenGLDisplay::selectFullScreenMode( VIDEO_MODE &mode )
654 {
655 	FullscreenSettings dlg;
656 	dlg.setAPI( this->getType() );
657 	INT_PTR ret = dlg.DoModal();
658 	if( ret == IDOK ) {
659 		mode.adapter = dlg.m_device;
660 		switch( dlg.m_colorDepth )
661 		{
662 		case 30:
663 			// TODO: support
664 			return false;
665 			break;
666 		case 24:
667 			mode.bitDepth = 32;
668 			break;
669 		case 16:
670 		case 15:
671 			mode.bitDepth = 16;
672 			break;
673 		}
674 		mode.width = dlg.m_width;
675 		mode.height = dlg.m_height;
676 		mode.frequency = dlg.m_refreshRate;
677 		return true;
678 	} else {
679 		return false;
680 	}
681 }
682 
683 
newOpenGLDisplay()684 IDisplay *newOpenGLDisplay()
685 {
686 	return new OpenGLDisplay();
687 }
688 
689 #endif // #ifndef NO_OGL
690