diff src/win32/OpenGL.cpp @ 1:f9f4f1b99eed

importing src directory
author Robert McIntyre <rlm@mit.edu>
date Sat, 03 Mar 2012 10:31:27 -0600
parents
children
line wrap: on
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/win32/OpenGL.cpp	Sat Mar 03 10:31:27 2012 -0600
     1.3 @@ -0,0 +1,544 @@
     1.4 +#include "stdafx.h"
     1.5 +#include <gl/GL.h>
     1.6 +
     1.7 +#include "resource.h"
     1.8 +#include "MainWnd.h"
     1.9 +#include "Reg.h"
    1.10 +#include "VBA.h"
    1.11 +
    1.12 +#include "../gba/GBAGlobals.h"
    1.13 +#include "../gb/gbGlobals.h"
    1.14 +#include "../common/Text.h"
    1.15 +#include "../version.h"
    1.16 +
    1.17 +#ifdef MMX
    1.18 +extern "C" bool cpu_mmx;
    1.19 +
    1.20 +extern bool detectMMX();
    1.21 +#endif
    1.22 +
    1.23 +extern int systemSpeed;
    1.24 +extern int Init_2xSaI(u32);
    1.25 +extern void winlog(const char *, ...);
    1.26 +
    1.27 +class OpenGLDisplay : public IDisplay
    1.28 +{
    1.29 +private:
    1.30 +	HDC    hDC;
    1.31 +	HGLRC  hglrc;
    1.32 +	GLuint texture;
    1.33 +	int    width;
    1.34 +	int    height;
    1.35 +	float  size;
    1.36 +	u8 *   filterData;
    1.37 +	bool   failed;
    1.38 +
    1.39 +	bool initializeTexture(int w, int h);
    1.40 +	void updateFiltering(int);
    1.41 +public:
    1.42 +	OpenGLDisplay();
    1.43 +	virtual ~OpenGLDisplay();
    1.44 +
    1.45 +	virtual bool initialize();
    1.46 +	virtual void cleanup();
    1.47 +	virtual void render();
    1.48 +	virtual void checkFullScreen();
    1.49 +	virtual void renderMenu();
    1.50 +	virtual void clear();
    1.51 +	virtual bool changeRenderSize(int w, int h);
    1.52 +	virtual void resize(int w, int h);
    1.53 +	virtual DISPLAY_TYPE getType() { return OPENGL; };
    1.54 +	virtual void setOption(const char *, int);
    1.55 +	virtual int selectFullScreenMode(GUID * *);
    1.56 +};
    1.57 +
    1.58 +OpenGLDisplay::OpenGLDisplay()
    1.59 +{
    1.60 +	hDC        = NULL;
    1.61 +	hglrc      = NULL;
    1.62 +	texture    = 0;
    1.63 +	width      = 0;
    1.64 +	height     = 0;
    1.65 +	size       = 0.0f;
    1.66 +	filterData = (u8 *)malloc(4*16*256*256); // sufficient for 4x filters @ 32bit color depth
    1.67 +	failed     = false;
    1.68 +}
    1.69 +
    1.70 +OpenGLDisplay::~OpenGLDisplay()
    1.71 +{
    1.72 +	cleanup();
    1.73 +}
    1.74 +
    1.75 +void OpenGLDisplay::cleanup()
    1.76 +{
    1.77 +	if (texture != 0)
    1.78 +	{
    1.79 +		glDeleteTextures(1, &texture);
    1.80 +		texture = 0;
    1.81 +	}
    1.82 +	if (hglrc != NULL)
    1.83 +	{
    1.84 +		wglDeleteContext(hglrc);
    1.85 +		wglMakeCurrent(NULL, NULL);
    1.86 +		hglrc = NULL;
    1.87 +	}
    1.88 +	if (hDC != NULL)
    1.89 +	{
    1.90 +		ReleaseDC(*theApp.m_pMainWnd, hDC);
    1.91 +		hDC = NULL;
    1.92 +	}
    1.93 +	if (filterData)
    1.94 +	{
    1.95 +		free(filterData);
    1.96 +		filterData = NULL;
    1.97 +	}
    1.98 +	width  = 0;
    1.99 +	height = 0;
   1.100 +	size   = 0.0f;
   1.101 +}
   1.102 +
   1.103 +bool OpenGLDisplay::initialize()
   1.104 +{
   1.105 +	CWnd *pWnd = theApp.m_pMainWnd;
   1.106 +
   1.107 +	theApp.mode320Available = false;
   1.108 +	theApp.mode640Available = false;
   1.109 +	theApp.mode800Available = false;
   1.110 +
   1.111 +	CDC *dc  = pWnd->GetDC();
   1.112 +	HDC  hDC = dc->GetSafeHdc();
   1.113 +
   1.114 +	PIXELFORMATDESCRIPTOR pfd = {
   1.115 +		sizeof(PIXELFORMATDESCRIPTOR), //  size of this pfd
   1.116 +		1, // version number
   1.117 +		PFD_DRAW_TO_WINDOW | // support window
   1.118 +		PFD_SUPPORT_OPENGL | // support OpenGL
   1.119 +		PFD_DOUBLEBUFFER, // double buffered
   1.120 +		PFD_TYPE_RGBA, // RGBA type
   1.121 +		16, // 16-bit color depth
   1.122 +		0, 0, 0, 0, 0, 0,  // color bits ignored
   1.123 +		0, // no alpha buffer
   1.124 +		0, // shift bit ignored
   1.125 +		0, // no accumulation buffer
   1.126 +		0, 0, 0, 0, // accum bits ignored
   1.127 +		32, // 32-bit z-buffer
   1.128 +		0, // no stencil buffer
   1.129 +		0, // no auxiliary buffer
   1.130 +		PFD_MAIN_PLANE, // main layer
   1.131 +		0, // reserved
   1.132 +		0, 0, 0            // layer masks ignored
   1.133 +	};
   1.134 +	int iPixelFormat;
   1.135 +
   1.136 +	if (!(iPixelFormat = ChoosePixelFormat(hDC, &pfd)))
   1.137 +	{
   1.138 +		winlog("Failed ChoosePixelFormat\n");
   1.139 +		return false;
   1.140 +	}
   1.141 +
   1.142 +	// obtain detailed information about
   1.143 +	// the device context's first pixel format
   1.144 +	if (!(DescribePixelFormat(hDC, iPixelFormat,
   1.145 +	                          sizeof(PIXELFORMATDESCRIPTOR), &pfd)))
   1.146 +	{
   1.147 +		winlog("Failed DescribePixelFormat\n");
   1.148 +		return false;
   1.149 +	}
   1.150 +
   1.151 +	if (!SetPixelFormat(hDC, iPixelFormat, &pfd))
   1.152 +	{
   1.153 +		winlog("Failed SetPixelFormat\n");
   1.154 +		return false;
   1.155 +	}
   1.156 +
   1.157 +	if (!(hglrc = wglCreateContext(hDC)))
   1.158 +	{
   1.159 +		winlog("Failed wglCreateContext\n");
   1.160 +		return false;
   1.161 +	}
   1.162 +
   1.163 +	if (!wglMakeCurrent(hDC, hglrc))
   1.164 +	{
   1.165 +		winlog("Failed wglMakeCurrent\n");
   1.166 +		return false;
   1.167 +	}
   1.168 +	pWnd->ReleaseDC(dc);
   1.169 +
   1.170 +	// setup 2D gl environment
   1.171 +	glPushAttrib(GL_ENABLE_BIT);
   1.172 +	glDisable(GL_DEPTH_TEST);
   1.173 +	glDisable(GL_CULL_FACE);
   1.174 +	glEnable(GL_TEXTURE_2D);
   1.175 +
   1.176 +	glViewport(0, 0, theApp.surfaceSizeX, theApp.surfaceSizeY);
   1.177 +
   1.178 +	glMatrixMode(GL_PROJECTION);
   1.179 +	glLoadIdentity();
   1.180 +
   1.181 +	glOrtho(0.0, (GLdouble)(theApp.surfaceSizeX), (GLdouble)(theApp.surfaceSizeY),
   1.182 +	        0.0, 0.0, 1.0);
   1.183 +	glMatrixMode(GL_MODELVIEW);
   1.184 +	glLoadIdentity();
   1.185 +
   1.186 +	systemRedShift      = 3;
   1.187 +	systemGreenShift    = 11;
   1.188 +	systemBlueShift     = 19;
   1.189 +	systemColorDepth    = 32;
   1.190 +	theApp.fsColorDepth = 32;
   1.191 +
   1.192 +	Init_2xSaI(32);
   1.193 +#ifdef MMX
   1.194 +	if (!theApp.disableMMX)
   1.195 +		cpu_mmx = theApp.detectMMX();
   1.196 +	else
   1.197 +		cpu_mmx = 0;
   1.198 +#endif
   1.199 +
   1.200 +	if (theApp.ddrawDebug)
   1.201 +	{
   1.202 +		winlog("R shift: %d\n", systemRedShift);
   1.203 +		winlog("G shift: %d\n", systemGreenShift);
   1.204 +		winlog("B shift: %d\n", systemBlueShift);
   1.205 +	}
   1.206 +
   1.207 +	switch (systemColorDepth)
   1.208 +	{
   1.209 +	case 16:
   1.210 +	{
   1.211 +		for (int i = 0; i < 0x10000; i++)
   1.212 +		{
   1.213 +			systemColorMap16[i] = ((i & 0x1f) << systemRedShift) |
   1.214 +			                      (((i & 0x3e0) >> 5) << systemGreenShift) |
   1.215 +			                      (((i & 0x7c00) >> 10) << systemBlueShift);
   1.216 +		}
   1.217 +		break;
   1.218 +	}
   1.219 +	case 24:
   1.220 +	case 32:
   1.221 +	{
   1.222 +		for (int i = 0; i < 0x10000; i++)
   1.223 +		{
   1.224 +			systemColorMap32[i] = ((i & 0x1f) << systemRedShift) |
   1.225 +			                      (((i & 0x3e0) >> 5) << systemGreenShift) |
   1.226 +			                      (((i & 0x7c00) >> 10) << systemBlueShift);
   1.227 +		}
   1.228 +		break;
   1.229 +	}
   1.230 +	}
   1.231 +	theApp.updateFilter();
   1.232 +	theApp.updateIFB();
   1.233 +
   1.234 +	if (failed)
   1.235 +		return false;
   1.236 +
   1.237 +	pWnd->DragAcceptFiles(TRUE);
   1.238 +
   1.239 +	return TRUE;
   1.240 +}
   1.241 +
   1.242 +void OpenGLDisplay::clear()
   1.243 +{}
   1.244 +
   1.245 +void OpenGLDisplay::renderMenu()
   1.246 +{
   1.247 +	checkFullScreen();
   1.248 +	if (theApp.m_pMainWnd)
   1.249 +		theApp.m_pMainWnd->DrawMenuBar();
   1.250 +}
   1.251 +
   1.252 +void OpenGLDisplay::checkFullScreen()
   1.253 +{
   1.254 +	//  if(tripleBuffering)
   1.255 +	//    pOpenGL->FlipToGDISurface();
   1.256 +}
   1.257 +
   1.258 +void OpenGLDisplay::render()
   1.259 +{
   1.260 +	void (*filterFunction)(u8 *, u32, u8 *, u8 *, u32, int, int) = theApp.filterFunction;
   1.261 +	int  filterWidth = theApp.filterWidth, filterHeight = theApp.filterHeight;
   1.262 +/*
   1.263 +    if(textMethod == 1)
   1.264 +    {
   1.265 +        int copyX = 240, copyY = 160;
   1.266 +        if(systemCartridgeType == 1)
   1.267 +            if(gbBorderOn) copyX = 256, copyY = 224;
   1.268 +            else           copyX = 160, copyY = 144;
   1.269 +
   1.270 +        extern void Simple1x(u8*,u32,u8*,u8*,u32,int,int);
   1.271 +        filterFunction = Simple1x;
   1.272 +        filterWidth = copyX;
   1.273 +        filterHeight = copyY;
   1.274 +    }
   1.275 + */
   1.276 +	int pitch = filterWidth * 4 + 4;
   1.277 +	u8 *data  = pix + (theApp.sizeX+1)*4;
   1.278 +
   1.279 +	int filterPitch = theApp.rect.right*4;
   1.280 +
   1.281 +/*
   1.282 +	// HACK: see below
   1.283 +	if (textMethod == 1 && !filterFunction)
   1.284 +	{
   1.285 +		textMethod = 0; // must not be after systemMessage!
   1.286 +		systemMessage(
   1.287 +		    0,
   1.288 +		    "The \"On Game\" text display mode does not work with this combination of renderers and filters.\nThe display mode is automatically being changed to \"In Game\" instead,\nbut this may cause message text to go into AVI recordings and screenshots.\nThis can be reconfigured by choosing \"Options->Video->Text Display Options...\"");
   1.289 +	}
   1.290 +*/
   1.291 +
   1.292 +	if (filterFunction)
   1.293 +	{
   1.294 +		data = filterData;
   1.295 +		filterFunction(pix + pitch,
   1.296 +		               pitch,
   1.297 +		               (u8 *)theApp.delta,
   1.298 +		               (u8 *)filterData,
   1.299 +		               filterPitch,
   1.300 +		               filterWidth,
   1.301 +		               filterHeight);
   1.302 +	}
   1.303 +
   1.304 +	if (theApp.showSpeed && theApp.videoOption > VIDEO_4X)
   1.305 +	{
   1.306 +		char buffer[30];
   1.307 +		if (theApp.showSpeed == 1)
   1.308 +			sprintf(buffer, "%3d%%", systemSpeed);
   1.309 +		else
   1.310 +			sprintf(buffer, "%3d%%(%d, %d fps)", systemSpeed,
   1.311 +			        systemFrameSkip,
   1.312 +			        theApp.showRenderedFrames);
   1.313 +
   1.314 +		if (filterFunction)
   1.315 +		{
   1.316 +			if (theApp.showSpeedTransparent)
   1.317 +				drawTextTransp((u8 *)filterData,
   1.318 +				               filterPitch,
   1.319 +				               theApp.rect.left+10,
   1.320 +				               theApp.rect.bottom-10,
   1.321 +				               buffer);
   1.322 +			else
   1.323 +				drawText((u8 *)filterData,
   1.324 +				         filterPitch,
   1.325 +			             theApp.rect.left+10,
   1.326 +			             theApp.rect.bottom-10,
   1.327 +				         buffer);
   1.328 +		}
   1.329 +		else
   1.330 +		{
   1.331 +			if (theApp.showSpeedTransparent)
   1.332 +				drawTextTransp((u8 *)pix,
   1.333 +				               pitch,
   1.334 +				               theApp.rect.left+10,
   1.335 +				               theApp.rect.bottom-10,
   1.336 +				               buffer);
   1.337 +			else
   1.338 +				drawText((u8 *)pix,
   1.339 +				         pitch,
   1.340 +			             theApp.rect.left+10,
   1.341 +			             theApp.rect.bottom-10,
   1.342 +				         buffer);
   1.343 +		}
   1.344 +	}
   1.345 +
   1.346 +	if (textMethod == 1 && filterFunction)
   1.347 +	{
   1.348 +		DrawTextMessages((u8 *)filterData, filterPitch, theApp.rect.left, theApp.rect.bottom);
   1.349 +	}
   1.350 +
   1.351 +	// Texturemap complete texture to surface so we have free scaling
   1.352 +	// and antialiasing
   1.353 +	if (filterFunction)
   1.354 +	{
   1.355 +		glPixelStorei(GL_UNPACK_ROW_LENGTH, theApp.rect.right);
   1.356 +	}
   1.357 +	else
   1.358 +	{
   1.359 +		glPixelStorei(GL_UNPACK_ROW_LENGTH, theApp.sizeX+1);
   1.360 +	}
   1.361 +
   1.362 +	glTexSubImage2D(GL_TEXTURE_2D, 0,
   1.363 +					0, 0, theApp.rect.right, theApp.rect.bottom,
   1.364 +	                GL_RGBA, GL_UNSIGNED_BYTE, data);
   1.365 +
   1.366 +	if (theApp.glType == 0)
   1.367 +	{
   1.368 +		glBegin(GL_TRIANGLE_STRIP);
   1.369 +		glTexCoord2f(0.0, 0.0); glVertex3i(0, 0, 0);
   1.370 +		glTexCoord2f(theApp.rect.right/size, 0.0); glVertex3i(theApp.surfaceSizeX, 0, 0);
   1.371 +		glTexCoord2f(0.0, theApp.rect.bottom/size); glVertex3i(0, theApp.surfaceSizeY, 0);
   1.372 +		glTexCoord2f(theApp.rect.right/size, theApp.rect.bottom/size); glVertex3i(theApp.surfaceSizeX, theApp.surfaceSizeY, 0);
   1.373 +		glEnd();
   1.374 +	}
   1.375 +	else
   1.376 +	{
   1.377 +		glBegin(GL_QUADS);
   1.378 +		glTexCoord2f(0.0, 0.0); glVertex3i(0, 0, 0);
   1.379 +		glTexCoord2f(theApp.rect.right/size, 0.0); glVertex3i(theApp.surfaceSizeX, 0, 0);
   1.380 +		glTexCoord2f(theApp.rect.right/size, theApp.rect.bottom/size); glVertex3i(theApp.surfaceSizeX, theApp.surfaceSizeY, 0);
   1.381 +		glTexCoord2f(0.0, theApp.rect.bottom/size); glVertex3i(0, theApp.surfaceSizeY, 0);
   1.382 +		glEnd();
   1.383 +	}
   1.384 +
   1.385 +	CDC *dc = theApp.m_pMainWnd->GetDC();
   1.386 +
   1.387 +	if (textMethod == 2 || (textMethod == 1 && !filterFunction)) // HACK: so that textMethod isn't changed
   1.388 +	{
   1.389 +		for (int slot = 0; slot < SCREEN_MESSAGE_SLOTS; slot++)
   1.390 +		{
   1.391 +			if (theApp.screenMessage[slot])
   1.392 +			{
   1.393 +				if ((theApp.screenMessageDuration[slot] < 0 || 
   1.394 +					(int)(GetTickCount() - theApp.screenMessageTime[slot]) < theApp.screenMessageDuration[slot]) &&
   1.395 +				    (!theApp.disableStatusMessage || slot == 1 || slot == 2))
   1.396 +				{
   1.397 +					dc->SetBkMode(TRANSPARENT);
   1.398 +
   1.399 +					if (outlinedText)
   1.400 +					{
   1.401 +						dc->SetTextColor(textColor != 7 ? RGB(0, 0, 0) : RGB(255, 255, 255));
   1.402 +						// draw black outline
   1.403 +						const static int xd [8] = {-1, 0, 1, 1, 1, 0, -1, -1};
   1.404 +						const static int yd [8] = {-1, -1, -1, 0, 1, 1, 1, 0};
   1.405 +						for (int i = 0; i < 8; i++)
   1.406 +						{
   1.407 +							dc->TextOut(10+xd[i], theApp.surfaceSizeY - 20*(slot+1)+yd[i], theApp.screenMessageBuffer[slot]);
   1.408 +						}
   1.409 +					}
   1.410 +
   1.411 +					COLORREF color;
   1.412 +					switch (textColor)
   1.413 +					{
   1.414 +					case 0:
   1.415 +						color = RGB(255, 255, 255); break;
   1.416 +					case 1:
   1.417 +						color = RGB(255, 0, 0); break;
   1.418 +					case 2:
   1.419 +						color = RGB(255, 255, 0); break;
   1.420 +					case 3:
   1.421 +						color = RGB(0, 255, 0); break;
   1.422 +					case 4:
   1.423 +						color = RGB(0, 255, 255); break;
   1.424 +					case 5:
   1.425 +						color = RGB(0, 0, 255); break;
   1.426 +					case 6:
   1.427 +						color = RGB(255, 0, 255); break;
   1.428 +					case 7:
   1.429 +						color = RGB(0, 0, 0); break;
   1.430 +					}
   1.431 +					dc->SetTextColor(color);
   1.432 +
   1.433 +					// draw center text
   1.434 +					dc->TextOut(10, theApp.surfaceSizeY - 20*(slot+1), theApp.screenMessageBuffer[slot]);
   1.435 +				}
   1.436 +				else
   1.437 +				{
   1.438 +					theApp.screenMessage[slot] = false;
   1.439 +				}
   1.440 +			}
   1.441 +		}
   1.442 +	}
   1.443 +
   1.444 +	SwapBuffers(dc->GetSafeHdc());
   1.445 +
   1.446 +	theApp.m_pMainWnd->ReleaseDC(dc);
   1.447 +}
   1.448 +
   1.449 +void OpenGLDisplay::resize(int w, int h)
   1.450 +{
   1.451 +	glViewport(0, 0, w, h);
   1.452 +	glMatrixMode(GL_PROJECTION);
   1.453 +	glLoadIdentity();
   1.454 +
   1.455 +	glOrtho(0.0, (GLdouble)(w), (GLdouble)(h), 0.0, 0.0, 1.0);
   1.456 +	glMatrixMode(GL_MODELVIEW);
   1.457 +	glLoadIdentity();
   1.458 +}
   1.459 +
   1.460 +void OpenGLDisplay::updateFiltering(int value)
   1.461 +{
   1.462 +	switch (value)
   1.463 +	{
   1.464 +	case 0:
   1.465 +		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
   1.466 +		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
   1.467 +		break;
   1.468 +	case 1:
   1.469 +		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   1.470 +		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   1.471 +		break;
   1.472 +	}
   1.473 +}
   1.474 +
   1.475 +bool OpenGLDisplay::initializeTexture(int w, int h)
   1.476 +{
   1.477 +	int mySize = 256;
   1.478 +	size = 256.0f;
   1.479 +	if (w > 511 || h > 511)
   1.480 +	{
   1.481 +		size   = 1024.0f;
   1.482 +		mySize = 1024;
   1.483 +	}
   1.484 +	else if (w > 255 || h > 255)
   1.485 +	{
   1.486 +		size   = 512.0f;
   1.487 +		mySize = 512;
   1.488 +	}
   1.489 +	glGenTextures(1, &texture);
   1.490 +	glBindTexture(GL_TEXTURE_2D, texture);
   1.491 +
   1.492 +	int filter = regQueryDwordValue("glFilter", 0);
   1.493 +	if (filter < 0 || filter > 1)
   1.494 +		filter = 0;
   1.495 +	updateFiltering(filter);
   1.496 +
   1.497 +	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, mySize, mySize, 0, GL_RGBA,
   1.498 +	             GL_UNSIGNED_BYTE, NULL);
   1.499 +	width  = w;
   1.500 +	height = h;
   1.501 +
   1.502 +	return true;
   1.503 +}
   1.504 +
   1.505 +bool OpenGLDisplay::changeRenderSize(int w, int h)
   1.506 +{
   1.507 +	if (width != w || height != h)
   1.508 +	{
   1.509 +		if (texture != 0)
   1.510 +		{
   1.511 +			glDeleteTextures(1, &texture);
   1.512 +			texture = 0;
   1.513 +		}
   1.514 +		if (!initializeTexture(w, h))
   1.515 +		{
   1.516 +			failed = true;
   1.517 +			return false;
   1.518 +		}
   1.519 +	}
   1.520 +	return true;
   1.521 +}
   1.522 +
   1.523 +void OpenGLDisplay::setOption(const char *option, int value)
   1.524 +{
   1.525 +	if (!strcmp(option, "glFilter"))
   1.526 +		updateFiltering(value);
   1.527 +}
   1.528 +
   1.529 +int OpenGLDisplay::selectFullScreenMode(GUID * *)
   1.530 +{
   1.531 +	HWND wnd = GetDesktopWindow();
   1.532 +	RECT r;
   1.533 +	GetWindowRect(wnd, &r);
   1.534 +	int w  = (r.right - r.left) & 4095;
   1.535 +	int h  = (r.bottom - r.top) & 4095;
   1.536 +	HDC dc = GetDC(wnd);
   1.537 +	int c  = GetDeviceCaps(dc, BITSPIXEL);
   1.538 +	ReleaseDC(wnd, dc);
   1.539 +
   1.540 +	return (c << 24) | (w << 12) | h;
   1.541 +}
   1.542 +
   1.543 +IDisplay *newOpenGLDisplay()
   1.544 +{
   1.545 +	return new OpenGLDisplay();
   1.546 +}
   1.547 +