1944 lines
66 KiB
C++
Executable File
1944 lines
66 KiB
C++
Executable File
//-----------------------------------------------------------------------------
|
|
// Torque Game Engine
|
|
// Copyright (C) GarageGames.com, Inc.
|
|
//
|
|
// Portions taken from OpenGL Full Screen.c sample from Apple Computer, Inc.
|
|
// (that's where many of the lead helper functions originated from, but code
|
|
// has been significantly changed & revised.)
|
|
//-----------------------------------------------------------------------------
|
|
#define NO_REDEFINE_GL_FUNCS
|
|
#include "platform/types.h"
|
|
#if defined(TORQUE_OS_MAC_OSX)
|
|
// AAAAAAAAARGGGH.
|
|
// OSX Frameworks version of AGL.h includes CoreServices, which hits the
|
|
// OpenTransport-has-a-new-but-platform.h-#defs-new-to-something-nonstandard
|
|
// issue, so we need to pre-include OT here...
|
|
#include <OpenTransport.h>
|
|
#endif
|
|
|
|
#include "platformMacCarb/platformMacCarb.h"
|
|
#include "platformMacCarb/platformGL.h"
|
|
#include "platformMacCarb/maccarbOGLVideo.h"
|
|
#include "console/console.h"
|
|
#include "math/mPoint.h"
|
|
#include "platform/event.h"
|
|
#include "platform/gameInterface.h"
|
|
#include "console/consoleInternal.h"
|
|
#include "console/ast.h"
|
|
#include "core/fileStream.h"
|
|
|
|
// !!!!!!!TBD
|
|
// Note: Card Profiling code isn't doing anything.
|
|
// Note: Screen-res list building is hardcoded, and should tap DSp.
|
|
// Note: Gamma support.
|
|
|
|
#define USE_AGL_FULLSCREEN 1
|
|
|
|
// whether to enable DSpSetDebugMode
|
|
#define DSP_DEBUG_MODE (defined(TORQUE_DEBUG))
|
|
// whether to only capture single monitor under gl fullscreen
|
|
#define ALLOW_SINGLEMON_CAPTURE (defined(TORQUE_DEBUG))
|
|
|
|
// flip this if we want smooth gamma-fades when switching screenres or in/out of DSp.
|
|
// generally, it's less nice but easier to find probs if we just leave it off, even for release.
|
|
#define FADE_ON_SWITCH 0
|
|
|
|
#define CALL_IN_SPOCKETS_BUT_NOT_IN_CARBON 1
|
|
#include <DrawSprocket/DrawSprocket.h>
|
|
#include <AGL/AGL.h>
|
|
|
|
AGLContext agl_ctx;
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
// prototypes and globals -- !!!!!!TBD - globals should mostly go away, into platState.
|
|
//-----------------------------------------------------------------------------------------
|
|
|
|
void ReportError (char * strError);
|
|
OSStatus DSpDebugStr (OSStatus error);
|
|
GLenum aglDebugStr (void);
|
|
|
|
CGrafPtr SetupDSp (GDHandle *phGD, int width, int height, int bpp);
|
|
void ShutdownDSp (CGrafPtr pDSpPort);
|
|
|
|
AGLContext SetupAGL (AGLPixelFormat *inFmt, GDHandle hGD, AGLDrawable win, int bpp);
|
|
AGLContext SetupAGLFullScreen (AGLPixelFormat *inFmt, GDHandle hGD, int width, int height, int bpp);
|
|
|
|
const RGBColor rgbBlack = { 0x0000, 0x0000, 0x0000 };
|
|
|
|
// extern accessible global!
|
|
bool gDSpActive = false;
|
|
|
|
NumVersion gVersionDSp;
|
|
DSpContextAttributes gContextAttributes;
|
|
DSpContextReference gContext = 0;
|
|
int gCurrentFrequency = 0;
|
|
|
|
AGLDrawable gpDSpPort = NULL; // will be NULL for full screen under X
|
|
Rect gRectPort = {0, 0, 0, 0};
|
|
bool gDSpOwnsPort = false;
|
|
#define MAX_DEVICES 8 // Geez, this SHOULD be safe!
|
|
GDHandle gDeviceList[MAX_DEVICES];
|
|
int gNumDevices = 0;
|
|
DSpContextReference gBlockedContext[MAX_DEVICES];
|
|
int gNumBlockedContexts = 0;
|
|
|
|
#if defined(TORQUE_DEBUG)
|
|
bool gOutlineEnabled = false;
|
|
|
|
void (* glDrawElementsProcPtr) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) = glDrawElements;
|
|
void (* glDrawArraysProcPtr) (GLenum mode, GLint first, GLsizei count) = glDrawArrays;
|
|
void (* glNormDrawElements) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) = glDrawElements;
|
|
void (* glNormDrawArrays) (GLenum mode, GLint first, GLsizei count) = glDrawArrays;
|
|
#endif
|
|
|
|
// locals.
|
|
static AGLDrawable drawable;
|
|
static AGLPixelFormat mainfmt;
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
// display errors -- for the moment, dumps to the console. !!!!TBD
|
|
//-----------------------------------------------------------------------------------------
|
|
void ReportError (char * strError)
|
|
{
|
|
// !!!!!TBD - for now, dump all errors to console.
|
|
Con::errorf(strError);
|
|
// used to do a debug str. or should do an alert/assert.
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
// translate DSp codes to strings.
|
|
//-----------------------------------------------------------------------------------------
|
|
OSStatus DSpDebugStr (OSStatus error)
|
|
{
|
|
switch (error)
|
|
{
|
|
case noErr:
|
|
break;
|
|
case kDSpNotInitializedErr:
|
|
ReportError ("DSp Error: Not initialized");
|
|
break;
|
|
case kDSpSystemSWTooOldErr:
|
|
ReportError ("DSp Error: system Software too old");
|
|
break;
|
|
case kDSpInvalidContextErr:
|
|
ReportError ("DSp Error: Invalid context");
|
|
break;
|
|
case kDSpInvalidAttributesErr:
|
|
ReportError ("DSp Error: Invalid attributes");
|
|
break;
|
|
case kDSpContextAlreadyReservedErr:
|
|
ReportError ("DSp Error: Context already reserved");
|
|
break;
|
|
case kDSpContextNotReservedErr:
|
|
ReportError ("DSp Error: Context not reserved");
|
|
break;
|
|
case kDSpContextNotFoundErr:
|
|
ReportError ("DSp Error: Context not found");
|
|
break;
|
|
case kDSpFrameRateNotReadyErr:
|
|
ReportError ("DSp Error: Frame rate not ready");
|
|
break;
|
|
case kDSpConfirmSwitchWarning:
|
|
// ReportError ("DSp Warning: Must confirm switch"); // removed since it is just a warning, add back for debugging
|
|
return 0; // don't want to fail on this warning
|
|
break;
|
|
case kDSpInternalErr:
|
|
ReportError ("DSp Error: Internal error");
|
|
break;
|
|
case kDSpStereoContextErr:
|
|
ReportError ("DSp Error: Stereo context");
|
|
break;
|
|
}
|
|
return error;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
// if error dump agl errors to debugger string, return error
|
|
//-----------------------------------------------------------------------------------------
|
|
GLenum aglDebugStr (void)
|
|
{
|
|
GLenum err = aglGetError();
|
|
if (AGL_NO_ERROR != err)
|
|
ReportError ((char *)aglErrorString(err));
|
|
return err;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
// if error dump agl errors to debugger string, return error
|
|
//-----------------------------------------------------------------------------------------
|
|
GLenum glDebugStr (void)
|
|
{
|
|
GLenum err = glGetError();
|
|
if (GL_NO_ERROR != err)
|
|
ReportError ((char *)gluErrorString(err));
|
|
return err;
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
// release any blocks held
|
|
//-----------------------------------------------------------------------------------------
|
|
void UnblockDSpContexts(void)
|
|
{
|
|
int i;
|
|
if (gNumBlockedContexts) // shouldn't happen, but...
|
|
{
|
|
for (i=0; i<gNumBlockedContexts; i++)
|
|
DSpContext_Release(gBlockedContext[i]);
|
|
gNumBlockedContexts = 0;
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
// setup blocks on contexts on non-selected display device
|
|
//-----------------------------------------------------------------------------------------
|
|
DisplayIDType BlockDSpContexts(GDHandle hDevice)
|
|
{
|
|
int i;
|
|
DisplayIDType mainDid = 0;
|
|
|
|
if (hDevice)
|
|
{
|
|
OSErr err = noErr;
|
|
DisplayIDType did;
|
|
DSpContextAttributes attrib;
|
|
DSpContextReference dsp;
|
|
for (i=0; i<gNumDevices; i++)
|
|
{
|
|
err = DMGetDisplayIDByGDevice(gDeviceList[i], &did, false);
|
|
if(err) continue;
|
|
if (gDeviceList[i]==hDevice) // skip our preferred device, but cache its did
|
|
{
|
|
mainDid = did;
|
|
continue;
|
|
}
|
|
if (platState.osX==false) // since we don't reserve on OSX.
|
|
{
|
|
err = DSpGetFirstContext(did, &dsp);
|
|
if (err) continue;
|
|
err = DSpContext_GetAttributes(dsp, &attrib);
|
|
if (err) continue;
|
|
err = DSpContext_Reserve(dsp, &attrib);
|
|
if (err) continue;
|
|
// store the blocked-out context for cleanup later.
|
|
gBlockedContext[gNumBlockedContexts] = dsp;
|
|
gNumBlockedContexts++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return(mainDid);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
// Does the basic setup and initialization of DSp, returns false if any error state.
|
|
//-----------------------------------------------------------------------------------------
|
|
bool InitDSp(void)
|
|
{
|
|
// check for DSp
|
|
if ((Ptr) kUnresolvedCFragSymbolAddress == (Ptr) DSpStartup)
|
|
{
|
|
ReportError ("DSp not installed");
|
|
return(false);
|
|
}
|
|
|
|
if (noErr != DSpDebugStr (DSpStartup()))
|
|
return false;
|
|
|
|
if ((Ptr) kUnresolvedCFragSymbolAddress == (Ptr) DSpGetVersion)
|
|
{
|
|
ReportError ("DSp error when checking installed version number");
|
|
return(false);
|
|
}
|
|
else
|
|
gVersionDSp = DSpGetVersion ();
|
|
|
|
if ((gVersionDSp.majorRev == 0x01) && (gVersionDSp.minorAndBugRev < 0x99))
|
|
{
|
|
// this version of DrawSprocket is not completely functional on Mac OS X
|
|
if (platState.osX)
|
|
{
|
|
ReportError ("DSp not properly functional -- upgrade to release build of OSX");
|
|
return(false);
|
|
}
|
|
}
|
|
|
|
// !!!!tbd assuming no error.
|
|
DSpSetBlankingColor(&rgbBlack);
|
|
|
|
#if DSP_DEBUG_MODE
|
|
// !!!!tbd assuming no error.
|
|
DSpSetDebugMode(TRUE);
|
|
#endif
|
|
|
|
// !!!!tbd assuming no error.
|
|
UnblockDSpContexts();
|
|
|
|
return(true);
|
|
}
|
|
|
|
#if !defined(TORQUE_DEBUG)
|
|
//-----------------------------------------------------------------------------------------
|
|
// Creates a dummy AGL context, so that naughty objects that call OpenGL before the window
|
|
// exists will not crash the game.
|
|
// If for some reason we fail to get a default contet, assert -- something's very wrong.
|
|
//-----------------------------------------------------------------------------------------
|
|
void InitDummyAgl(void)
|
|
{
|
|
short i = 0;
|
|
GLint attrib[64];
|
|
AGLPixelFormat fmt;
|
|
AGLContext ctx;
|
|
|
|
// clear the existing pixel format.
|
|
if (mainfmt != NULL)
|
|
aglDestroyPixelFormat(mainfmt);
|
|
mainfmt = NULL;
|
|
|
|
// clear the existing agl context
|
|
if(platState.ctx != NULL)
|
|
aglDestroyContext((AGLContext)platState.ctx);
|
|
platState.ctx = NULL;
|
|
agl_ctx = NULL;
|
|
|
|
// set up an attribute array for the pixel format.
|
|
attrib [i++] = AGL_RGBA; // red green blue and alpha
|
|
attrib [i++] = AGL_DOUBLEBUFFER; // double buffered
|
|
attrib [i++] = AGL_ACCELERATED; // hardware accelerated format
|
|
attrib [i++] = AGL_NO_RECOVERY; // don't fall back to a software renderer if out of video card resources
|
|
attrib [i++] = AGL_DEPTH_SIZE; // depth buffer
|
|
attrib [i++] = 16; // size for depth buffer - either 16 or 32.
|
|
// BUG: bit depth is ignored for color buffer. fix and test.
|
|
// attrib [i++] = AGL_PIXEL_SIZE;
|
|
// attrib [i++] = bpp;
|
|
attrib [i++] = AGL_NONE; // terminate the list.
|
|
|
|
// choose a pixel format that works for any current display device, and matches
|
|
// the attributes above as closely as possible.
|
|
fmt = aglChoosePixelFormat(NULL, 0, attrib);
|
|
aglDebugStr ();
|
|
AssertFatal(fmt, "Could not find a valid default pixel format");
|
|
|
|
// create an agl context. NULL = don't share resouces with any other context.
|
|
ctx = aglCreateContext (fmt, NULL);
|
|
aglDebugStr ();
|
|
AssertFatal(ctx, "Could not create a default agl context");
|
|
|
|
// make gl calls go to our dummy context
|
|
if (!aglSetCurrentContext (ctx))
|
|
{
|
|
aglDebugStr ();
|
|
AssertFatal(false,"Could not set a default agl context as the current context.");
|
|
}
|
|
|
|
agl_ctx = ctx; // maintain up aglMacro.h context
|
|
mainfmt = fmt;
|
|
|
|
}
|
|
#endif
|
|
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
// Runs through and builds a list of supported modes.
|
|
//-----------------------------------------------------------------------------------------
|
|
bool OpenGLDevice::enumDisplayModes (GDHandle hDevice)
|
|
{
|
|
DSpContextAttributes attr;
|
|
DSpContextReference ctxt;
|
|
OSStatus err;
|
|
int i;
|
|
|
|
if (!InitDSp()) return(false);
|
|
|
|
// first, lock out other display devices if we have a preferred device..
|
|
DisplayIDType mainDid = BlockDSpContexts(hDevice);
|
|
|
|
if (noErr == (err = DSpDebugStr (DSpGetFirstContext(mainDid, &ctxt)) ))
|
|
while (ctxt)
|
|
{
|
|
// extract the attributes of this context, and if we don't have a matching
|
|
// set on our list already, add it to our list.
|
|
if (noErr != (err = DSpDebugStr (DSpContext_GetAttributes(ctxt, &attr)) )) // see what we actually found
|
|
{
|
|
ReportError ("DSpContext_GetAttributes() had an error.");
|
|
break;
|
|
}
|
|
|
|
if (attr.displayWidth >= 640 && attr.displayHeight >= 480
|
|
&& (attr.displayBestDepth == 16 || attr.displayBestDepth == 32) )
|
|
{
|
|
// Only add this resolution if it is not already in the list:
|
|
bool alreadyInList = false;
|
|
for (i=0; i<mResolutionList.size(); i++)
|
|
{
|
|
if (attr.displayWidth == mResolutionList[i].w
|
|
&& attr.displayHeight == mResolutionList[i].h
|
|
&& attr.displayBestDepth == mResolutionList[i].bpp )
|
|
{
|
|
alreadyInList = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!alreadyInList)
|
|
{
|
|
Resolution newRes( attr.displayWidth, attr.displayHeight, attr.displayBestDepth );
|
|
mResolutionList.push_back( newRes );
|
|
}
|
|
}
|
|
|
|
// go on to next context
|
|
if (noErr != (err = DSpGetNextContext(ctxt, &ctxt) )) // don't do the DSpDebugStr here!
|
|
{
|
|
if (err == kDSpContextNotFoundErr) // that's okay
|
|
err = noErr;
|
|
else
|
|
{
|
|
DSpDebugStr (err);
|
|
ReportError ("DSpGetNextContext() had an error.");
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// clear the blocked contexts now that we're done
|
|
UnblockDSpContexts();
|
|
|
|
if (noErr != err)
|
|
return(false);
|
|
|
|
return(true);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
// Set up DSp screens, handles multi-monitor correctly
|
|
// side effect: sets both gpDSpWindow and gpPort
|
|
//-----------------------------------------------------------------------------------------
|
|
CGrafPtr SetupDSp (GDHandle *phGD, int width, int height, int bpp)
|
|
{
|
|
GDHandle hDevice = NULL;
|
|
DSpContextAttributes foundAttributes;
|
|
DisplayIDType displayID;
|
|
CGrafPtr pPort;
|
|
int i;
|
|
|
|
if (*phGD)
|
|
hDevice = *phGD; // save it to look for.
|
|
gDSpOwnsPort = false;
|
|
gDSpActive = false;
|
|
|
|
if (!InitDSp()) return(NULL);
|
|
|
|
AssertFatal( bpp!=0, "SetupDSp\nBPP passed in was ZERO!" );
|
|
|
|
// first, lock out other display devices if we have a preferred device..
|
|
DisplayIDType mainDid = BlockDSpContexts(hDevice);
|
|
|
|
// Note: DSp < 1.7.3 REQUIRES the back buffer attributes even if only one buffer is required
|
|
dMemset(&gContextAttributes, 0, sizeof (DSpContextAttributes));
|
|
gContextAttributes.displayWidth = width;
|
|
gContextAttributes.displayHeight = height;
|
|
gContextAttributes.colorNeeds = kDSpColorNeeds_Require;
|
|
gContextAttributes.displayBestDepth = bpp;
|
|
gContextAttributes.backBufferBestDepth = bpp;
|
|
gContextAttributes.displayDepthMask = kDSpDepthMask_All;
|
|
gContextAttributes.backBufferDepthMask = kDSpDepthMask_All;
|
|
gContextAttributes.pageCount = 1; // only the front buffer is needed
|
|
gContextAttributes.frequency = 0; //try letting DSp pick.
|
|
|
|
if (platState.osX && hDevice)
|
|
{ // use a different function.
|
|
if (noErr != DSpDebugStr (DSpFindBestContextOnDisplayID(&gContextAttributes, &gContext, mainDid)))
|
|
{ // then try 60hz frequency.
|
|
gContextAttributes.frequency = 60<<16;
|
|
if (noErr != DSpDebugStr (DSpFindBestContextOnDisplayID(&gContextAttributes, &gContext, mainDid)))
|
|
{
|
|
ReportError ("DSpFindBestContextOnDisplayID() had an error.");
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
if (noErr != DSpDebugStr (DSpFindBestContext(&gContextAttributes, &gContext)))
|
|
{ // then try 60hz frequency.
|
|
gContextAttributes.frequency = 60<<16;
|
|
if (noErr != DSpDebugStr (DSpFindBestContext(&gContextAttributes, &gContext)))
|
|
{
|
|
ReportError ("DSpFindBestContext() had an error.");
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
if (noErr != DSpDebugStr (DSpContext_GetAttributes (gContext, &foundAttributes))) // see what we actually found
|
|
{
|
|
ReportError ("DSpContext_GetAttributes() had an error.");
|
|
return NULL;
|
|
}
|
|
|
|
// clear the blocked contexts now that we're done locating ours.
|
|
UnblockDSpContexts();
|
|
|
|
// reset width and height to full screen and handle our own centering
|
|
// HWA will not correctly center less than full screen size contexts
|
|
gContextAttributes.displayWidth = foundAttributes.displayWidth;
|
|
gContextAttributes.displayHeight = foundAttributes.displayHeight;
|
|
gContextAttributes.pageCount = 1; // only the front buffer is needed
|
|
gContextAttributes.contextOptions = 0 | kDSpContextOption_DontSyncVBL; // no page flipping and no VBL sync needed
|
|
|
|
if (noErr != DSpDebugStr (DSpContext_GetDisplayID(gContext, &displayID))) // get our device for future use
|
|
{
|
|
ReportError ("DSpContext_GetDisplayID() had an error.");
|
|
return NULL;
|
|
}
|
|
|
|
if (noErr != DMGetGDeviceByDisplayID (displayID, phGD, false)) // get GDHandle for ID'd device
|
|
{
|
|
ReportError ("DMGetGDeviceByDisplayID() had an error.");
|
|
return NULL;
|
|
}
|
|
|
|
if (noErr != DSpDebugStr (DSpContext_Reserve ( gContext, &gContextAttributes))) // reserve our context
|
|
{
|
|
ReportError ("DSpContext_Reserve() had an error.");
|
|
return NULL;
|
|
}
|
|
|
|
gCurrentFrequency = foundAttributes.frequency>>16;
|
|
#if FADE_ON_SWITCH
|
|
DSpDebugStr (DSpContext_FadeGammaOut (NULL, NULL)); // fade display, remove for debug
|
|
#endif
|
|
if (noErr != DSpDebugStr (DSpContext_SetState (gContext, kDSpContextState_Active))) // activate our context
|
|
{
|
|
ReportError ("DSpContext_SetState() had an error.");
|
|
return NULL;
|
|
}
|
|
|
|
if (platState.osX && !((gVersionDSp.majorRev > 0x01) || ((gVersionDSp.majorRev == 0x01) && (gVersionDSp.minorAndBugRev >= 0x99))))// DSp should be supported in version after 1.98
|
|
{
|
|
ReportError ("Mac OS X with DSp < 1.99 does not support DrawSprocket for OpenGL full screen");
|
|
return NULL;
|
|
}
|
|
else if (platState.osX) // DSp should be supported in versions 1.99 and later
|
|
{
|
|
#if originally
|
|
/*
|
|
// use DSp's front buffer on Mac OS X
|
|
if (noErr != DSpDebugStr (DSpContext_GetFrontBuffer (gContext, &pPort)))
|
|
{
|
|
ReportError ("DSpContext_GetFrontBuffer() had an error.");
|
|
return NULL;
|
|
}
|
|
// make sure to flag this!
|
|
gDSpOwnsPort = true;
|
|
// there is a problem in Mac OS X GM CoreGraphics that may not size the port pixmap correctly
|
|
// this will check the vertical sizes and offset if required to fix the problem
|
|
// this will not center ports that are smaller then a particular resolution
|
|
{
|
|
long deltaV, deltaH;
|
|
Rect portBounds;
|
|
PixMapHandle hPix = GetPortPixMap (pPort);
|
|
Rect pixBounds = (**hPix).bounds;
|
|
GetPortBounds (pPort, &portBounds);
|
|
deltaV = (portBounds.bottom - portBounds.top) - (pixBounds.bottom - pixBounds.top) +
|
|
(portBounds.bottom - portBounds.top - height) / 2;
|
|
deltaH = -(portBounds.right - portBounds.left - width) / 2;
|
|
if (deltaV || deltaH)
|
|
{
|
|
GrafPtr pPortSave;
|
|
GetPort (&pPortSave);
|
|
SetPort ((GrafPtr)pPort);
|
|
// set origin to account for CG offset and if requested drawable smaller than screen rez
|
|
SetOrigin (deltaH, deltaV);
|
|
SetPort (pPortSave);
|
|
}
|
|
}
|
|
platState.appWindow = GetWindowFromPort(pPort);
|
|
#if FADE_ON_SWITCH
|
|
DSpDebugStr (DSpContext_FadeGammaIn (NULL, NULL));
|
|
#endif
|
|
return pPort;
|
|
*/
|
|
#endif
|
|
}
|
|
|
|
Con::printf( "Creating new Fullscreen window..." );
|
|
WindowPtr pWindow = CreateOpenGLWindow(*phGD, width, height, true);
|
|
if (pWindow == NULL)
|
|
return(NULL); // !!!!TBD err msg.
|
|
platState.appWindow = pWindow;
|
|
pPort = GetWindowPort(pWindow);
|
|
|
|
#if FADE_ON_SWITCH
|
|
DSpDebugStr (DSpContext_FadeGammaIn (NULL, NULL));
|
|
#endif
|
|
|
|
gDSpActive = true;
|
|
|
|
return pPort;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
// clean up DSp
|
|
//-----------------------------------------------------------------------------------------
|
|
void ShutdownDSp (CGrafPtr pDSpPort)
|
|
{
|
|
#if FADE_ON_SWITCH
|
|
DSpContext_FadeGammaOut(NULL, NULL);
|
|
#endif
|
|
if ((NULL != pDSpPort))
|
|
{
|
|
// retreive the actual window in question...
|
|
WindowPtr w = GetWindowFromPort(pDSpPort);
|
|
if (w == platState.appWindow) // then clear our storage variable.
|
|
platState.appWindow = NULL;
|
|
if (!gDSpOwnsPort) // then we created the window, so we have to dispose of it.
|
|
{
|
|
if (platState.osX)
|
|
ReleaseWindow(w);
|
|
else
|
|
DisposeWindow(w);
|
|
}
|
|
}
|
|
|
|
DSpContext_SetState(gContext, kDSpContextState_Inactive);
|
|
#if FADE_ON_SWITCH
|
|
DSpContext_FadeGammaIn(NULL, NULL);
|
|
#endif
|
|
|
|
// ShowCursor(); // !!!!!!TBD - what the heck is this doing here??? this could screw up mouse/cursor management!!!
|
|
|
|
DSpContext_Release(gContext);
|
|
|
|
if (gNumBlockedContexts) // shouldn't happen, but...
|
|
{
|
|
for (int i=0; i<gNumBlockedContexts; i++)
|
|
DSpContext_Release(gBlockedContext[i]);
|
|
gNumBlockedContexts = 0;
|
|
}
|
|
|
|
DSpShutdown();
|
|
|
|
gContext = NULL;
|
|
gpDSpPort = NULL;
|
|
gDSpOwnsPort = false;
|
|
gDSpActive = false;
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
// OpenGL Setup, for any case where we already have a drawable (whether windowed or DSp-screen)
|
|
//-----------------------------------------------------------------------------------------
|
|
AGLContext SetupAGL (AGLPixelFormat *inFmt, GDHandle hGD, AGLDrawable drawable, int bpp)
|
|
{
|
|
// software renderer = AGL_RENDERER_ID + AGL_RENDERER_GENERIC_ID + AGL_ALL_RENDERERS
|
|
// any renderer = AGL_ALL_RENDERERS instead of AGL_ACCELERATED
|
|
// OpenGL compliant ATI renderer = AGL_RENDERER_ID + AGL_RENDERER_ATI_ID + AGL_ACCELERATED
|
|
|
|
short i = 0;
|
|
GLint attrib[64];
|
|
AGLPixelFormat fmt;
|
|
AGLContext ctx;
|
|
|
|
if (*inFmt!=NULL)
|
|
aglDestroyPixelFormat(*inFmt); // prev pixel format is no longer needed
|
|
*inFmt = NULL;
|
|
|
|
attrib [i++] = AGL_RGBA; // red green blue and alpha
|
|
attrib [i++] = AGL_DOUBLEBUFFER; // double buffered
|
|
attrib [i++] = AGL_ACCELERATED; // HWA pixel format only
|
|
attrib [i++] = AGL_NO_RECOVERY; // HWA pixel format only
|
|
attrib [i++] = AGL_DEPTH_SIZE; // MUST request a depth buffer.
|
|
attrib [i++] = bpp>16?32:16; // !!!!!!!TBD this should be from a pref variable.
|
|
// !!!!!TBD -- do we need to have a pixelsize in here?
|
|
// attrib [i++] = AGL_PIXEL_SIZE;
|
|
// attrib [i++] = bpp;
|
|
|
|
// attrib [i++] = AGL_ALL_RENDERERS; // choose even non-compliant renderers
|
|
// attrib [i++] = AGL_RENDERER_ID; // choose only renderer type specified in next parameter
|
|
// attrib [i++] = AGL_RENDERER_ATI_ID; // ATI renderer
|
|
// attrib [i++] = AGL_RENDERER_GENERIC_ID; // generic renderer
|
|
|
|
// terminate the list.
|
|
attrib [i++] = AGL_NONE;
|
|
|
|
if (hGD && gNumDevices>1)
|
|
fmt = aglChoosePixelFormat (&hGD, 1, attrib); // get an appropriate pixel format
|
|
else
|
|
fmt = aglChoosePixelFormat(NULL, 0, attrib); // get an appropriate pixel format
|
|
aglDebugStr ();
|
|
if (NULL == fmt)
|
|
{
|
|
ReportError("Could not find valid pixel format");
|
|
return NULL;
|
|
}
|
|
|
|
ctx = aglCreateContext (fmt, NULL); // Create an AGL context
|
|
aglDebugStr ();
|
|
if (NULL == ctx)
|
|
{
|
|
ReportError ("Could not create context");
|
|
return NULL;
|
|
}
|
|
|
|
if (!aglSetDrawable (ctx, drawable)) // attach the window to the context
|
|
{
|
|
ReportError ("SetDrawable failed");
|
|
aglDebugStr ();
|
|
return NULL;
|
|
}
|
|
|
|
|
|
if (!aglSetCurrentContext (ctx)) // make the context the current context
|
|
{
|
|
aglDebugStr ();
|
|
aglSetDrawable (ctx, NULL);
|
|
return NULL;
|
|
}
|
|
#if !defined(TORQUE_DEBUG)
|
|
agl_ctx = ctx; // maintain up aglMacro.h context
|
|
#endif
|
|
*inFmt = fmt;
|
|
return ctx;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------------------
|
|
// OpenGL Setup
|
|
AGLContext SetupAGLFullScreen (AGLPixelFormat *inFmt, GDHandle hGD, int width, int height, int bpp)
|
|
{
|
|
GLint attrib[64];
|
|
AGLPixelFormat fmt;
|
|
AGLContext ctx;
|
|
|
|
if (*inFmt!=NULL)
|
|
aglDestroyPixelFormat(*inFmt); // prev pixel format is no longer needed
|
|
*inFmt = NULL;
|
|
|
|
// different possible pixel format choices for different renderers
|
|
// basics requirements are RGBA and double buffer
|
|
// OpenGL will select acclerated context if available
|
|
|
|
short i = 0;
|
|
attrib [i++] = AGL_RGBA; // red green blue and alpha
|
|
attrib [i++] = AGL_DOUBLEBUFFER; // double buffered
|
|
attrib [i++] = AGL_ACCELERATED; // HWA pixel format only
|
|
attrib [i++] = AGL_NO_RECOVERY; // HWA pixel format only
|
|
attrib [i++] = AGL_DEPTH_SIZE;
|
|
attrib [i++] = bpp>16?32:16;
|
|
|
|
attrib [i++] = AGL_FULLSCREEN;
|
|
attrib [i++] = AGL_PIXEL_SIZE;
|
|
attrib [i++] = bpp;
|
|
|
|
// attrib [i++] = AGL_ALL_RENDERERS; // choose even non-compliant renderers
|
|
// attrib [i++] = AGL_RENDERER_ID; // choose only renderer type specified in next parameter
|
|
// attrib [i++] = AGL_RENDERER_ATI_ID; // ATI renderer
|
|
// attrib [i++] = AGL_RENDERER_GENERIC_ID; // generic renderer
|
|
|
|
attrib [i++] = AGL_NONE;
|
|
|
|
if (hGD && gNumDevices>1)
|
|
fmt = aglChoosePixelFormat (&hGD, 1, attrib); // get an appropriate pixel format
|
|
else
|
|
fmt = aglChoosePixelFormat(NULL, 0, attrib); // get an appropriate pixel format
|
|
if (NULL == fmt)
|
|
{
|
|
ReportError("Could not find valid pixel format");
|
|
aglDebugStr ();
|
|
return NULL;
|
|
}
|
|
|
|
ctx = aglCreateContext (fmt, NULL); // Create an AGL context
|
|
if (NULL == ctx)
|
|
{
|
|
ReportError ("Could not create context");
|
|
aglDebugStr ();
|
|
return NULL;
|
|
}
|
|
|
|
#ifdef ALLOW_SINGLEMON_CAPTURE
|
|
#ifndef AGL_FS_CAPTURE_SINGLE
|
|
#define AGL_FS_CAPTURE_SINGLE 255 /* enable the capture of only a single display for aglFullscreen */
|
|
#endif
|
|
aglEnable(ctx, AGL_FS_CAPTURE_SINGLE);
|
|
#endif
|
|
|
|
static int hzrate = 0; //gCurrentFrequency; // should be a fairly safe rate on most displays. we could use DSp to get rates, or DM maybe.
|
|
|
|
if (!aglSetFullScreen (ctx, width, height, hzrate, 0)) // attach fulls screen device to the context
|
|
{
|
|
ReportError ("SetFullScreen(0Hz) failed");
|
|
aglDebugStr ();
|
|
|
|
hzrate = 60; // safe mode.
|
|
gCurrentFrequency = 60; // so we know what we set...
|
|
if (!aglSetFullScreen (ctx, width, height, hzrate, 0)) // attach fulls screen device to the context
|
|
{
|
|
ReportError ("SetFullScreen(60Hz) failed");
|
|
aglDebugStr ();
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
if (!aglSetCurrentContext (ctx)) // make the context the current context
|
|
{
|
|
ReportError ("SetCurrentContext failed");
|
|
aglDebugStr ();
|
|
aglSetDrawable (ctx, NULL); // turn off full screen
|
|
return NULL;
|
|
}
|
|
#if !defined(TORQUE_DEBUG)
|
|
agl_ctx = ctx; // maintain up aglMacro.h context
|
|
#endif
|
|
|
|
// aglDestroyPixelFormat(fmt); // pixel format is no longer needed
|
|
*inFmt = fmt;
|
|
|
|
return ctx;
|
|
}
|
|
|
|
|
|
#pragma mark -
|
|
|
|
//===============================================================================
|
|
|
|
Boolean sCanDoFullscreen = TRUE;
|
|
|
|
struct CardProfile
|
|
{
|
|
const char *vendor; // manufacturer
|
|
const char *renderer; // driver name
|
|
|
|
bool safeMode; // destroy rendering context for resolution change
|
|
bool lockArray; // allow compiled vertex arrays
|
|
bool subImage; // allow glTexSubImage*
|
|
bool fogTexture; // require bound texture for combine extension
|
|
bool noEnvColor; // no texture environment color
|
|
bool clipHigh; // clip high resolutions
|
|
bool deleteContext; // delete rendering context
|
|
bool texCompress; // allow texture compression
|
|
bool interiorLock; // lock arrays for Interior render
|
|
bool skipFirstFog; // skip first two-pass fogging (dumb 3Dfx hack)
|
|
bool only16; // inhibit 32-bit resolutions
|
|
bool noArraysAlpha; // don't use glDrawArrays with a GL_ALPHA texture
|
|
|
|
const char *proFile; // explicit profile of graphic settings
|
|
};
|
|
|
|
struct OSCardProfile
|
|
{
|
|
const char *vendor; // manufacturer
|
|
const char *renderer; // driver name
|
|
};
|
|
|
|
static Vector<CardProfile> sCardProfiles(__FILE__, __LINE__);
|
|
static Vector<OSCardProfile> sOSCardProfiles(__FILE__, __LINE__);
|
|
|
|
struct ProcessorProfile
|
|
{
|
|
U16 clock; // clock range max
|
|
U16 adjust; // CPU adjust
|
|
};
|
|
|
|
static U8 sNumProcessors = 4;
|
|
static ProcessorProfile sProcessorProfiles[] =
|
|
{
|
|
{ 400, 0 },
|
|
{ 600, 5 },
|
|
{ 800, 10 },
|
|
{ 1000, 15 },
|
|
};
|
|
|
|
struct SettingProfile
|
|
{
|
|
U16 performance; // metric range max
|
|
const char *settings; // default file
|
|
};
|
|
|
|
static U8 sNumSettings = 3;
|
|
static SettingProfile sSettingProfiles[] =
|
|
{
|
|
{ 33, "LowProfile.cs" },
|
|
{ 66, "MediumProfile.cs" },
|
|
{ 100, "HighProfile.cs" },
|
|
};
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
ConsoleFunction( addCardProfile, void, 16, 16, "(string vendor, string renderer, "
|
|
" bool safeMode, bool lockArray, bool subImage, "
|
|
" bool fogTexture, bool noEnvColor, bool clipHigh, "
|
|
" bool deleteContext, bool texCompress, bool interiorLock, "
|
|
" bool skipFirstFog, bool only16, bool noArraysAlpha, "
|
|
" string proFile)")
|
|
{
|
|
CardProfile profile;
|
|
|
|
profile.vendor = dStrdup(argv[1]);
|
|
profile.renderer = dStrdup(argv[2]);
|
|
|
|
profile.safeMode = dAtob(argv[3]);
|
|
profile.lockArray = dAtob(argv[4]);
|
|
profile.subImage = dAtob(argv[5]);
|
|
profile.fogTexture = dAtob(argv[6]);
|
|
profile.noEnvColor = dAtob(argv[7]);
|
|
profile.clipHigh = dAtob(argv[8]);
|
|
profile.deleteContext = dAtob(argv[9]);
|
|
profile.texCompress = dAtob(argv[10]);
|
|
profile.interiorLock = dAtob(argv[11]);
|
|
profile.skipFirstFog = dAtob(argv[12]);
|
|
profile.only16 = dAtob(argv[13]);
|
|
profile.noArraysAlpha = dAtob(argv[14]);
|
|
|
|
if (dStrcmp(argv[15],""))
|
|
profile.proFile = dStrdup(argv[15]);
|
|
else
|
|
profile.proFile = NULL;
|
|
|
|
sCardProfiles.push_back(profile);
|
|
}
|
|
|
|
ConsoleFunction( addOSCardPRofile, void, 6, 6, "(string vendor, string renderer, "
|
|
" bool allowOpenGL, bool allowD3D, "
|
|
" bool preferOpenGL) Mac builds ignore the last three flags.")
|
|
{
|
|
OSCardProfile profile;
|
|
|
|
profile.vendor = dStrdup(argv[1]);
|
|
profile.renderer = dStrdup(argv[2]);
|
|
|
|
/*
|
|
profile.allowOpenGL = dAtob(argv[3]);
|
|
profile.allowD3D = dAtob(argv[4]);
|
|
profile.preferOpenGL = dAtob(argv[5]);
|
|
*/
|
|
|
|
sOSCardProfiles.push_back(profile);
|
|
}
|
|
|
|
static void clearCardProfiles()
|
|
{
|
|
while (sCardProfiles.size())
|
|
{
|
|
dFree((char *) sCardProfiles.last().vendor);
|
|
dFree((char *) sCardProfiles.last().renderer);
|
|
|
|
dFree((char *) sCardProfiles.last().proFile);
|
|
|
|
sCardProfiles.decrement();
|
|
}
|
|
}
|
|
|
|
static void clearOSCardProfiles()
|
|
{
|
|
while (sOSCardProfiles.size())
|
|
{
|
|
dFree((char *) sOSCardProfiles.last().vendor);
|
|
dFree((char *) sOSCardProfiles.last().renderer);
|
|
|
|
sOSCardProfiles.decrement();
|
|
}
|
|
}
|
|
|
|
static void execScript(const char *scriptFile)
|
|
{
|
|
// execute the script
|
|
FileStream str;
|
|
|
|
if (!str.open(scriptFile, FileStream::Read))
|
|
return;
|
|
|
|
U32 size = str.getStreamSize();
|
|
char *script = new char[size + 1];
|
|
|
|
str.read(size, script);
|
|
str.close();
|
|
|
|
script[size] = 0;
|
|
Con::executef(2, "eval", script);
|
|
delete[] script;
|
|
}
|
|
|
|
static void profileSystem(const char *vendor, const char *renderer)
|
|
{
|
|
//Con::executef(2, "exec", "scripts/CardProfiles.cs");
|
|
execScript("CardProfiles.cs");
|
|
|
|
const char *os = NULL;
|
|
char osProfiles[64];
|
|
|
|
#pragma message("todo: implement full profile checking")
|
|
os = "MACCARB";
|
|
|
|
if ( os != NULL )
|
|
{
|
|
dSprintf(osProfiles,64,"%s%sCardProfiles.cs","PPC",os);
|
|
//Con::executef(2, "exec", osProfiles);
|
|
execScript(osProfiles);
|
|
}
|
|
|
|
const char *proFile = NULL;
|
|
U32 i;
|
|
|
|
for (i = 0; i < sCardProfiles.size(); ++i)
|
|
if (dStrstr(vendor, sCardProfiles[i].vendor) &&
|
|
(!dStrcmp(sCardProfiles[i].renderer, "*") ||
|
|
dStrstr(renderer, sCardProfiles[i].renderer)))
|
|
{
|
|
Con::setBoolVariable("$pref::Video::safeModeOn", sCardProfiles[i].safeMode);
|
|
Con::setBoolVariable("$pref::OpenGL::disableEXTCompiledVertexArray", !sCardProfiles[i].lockArray);
|
|
Con::setBoolVariable("$pref::OpenGL::disableSubImage", !sCardProfiles[i].subImage);
|
|
Con::setBoolVariable("$pref::TS::fogTexture", sCardProfiles[i].fogTexture);
|
|
Con::setBoolVariable("$pref::OpenGL::noEnvColor", sCardProfiles[i].noEnvColor);
|
|
Con::setBoolVariable("$pref::Video::clipHigh", sCardProfiles[i].clipHigh);
|
|
if (!sCardProfiles[i].deleteContext)
|
|
{
|
|
Con::setBoolVariable("$pref::Video::deleteContext", false);
|
|
/*
|
|
// HACK: The Voodoo3/5 on W2K crash when deleting a rendering context
|
|
// So we're not deleting it.
|
|
// Oh, and the Voodoo3 returns a Banshee renderer string under W2K
|
|
dMemset( &OSVersionInfo, 0, sizeof( OSVERSIONINFO ) );
|
|
OSVersionInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
|
|
if ( GetVersionEx( &OSVersionInfo ) &&
|
|
OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT &&
|
|
OSVersionInfo.dwMajorVersion == 5)
|
|
Con::setBoolVariable("$pref::Video::deleteContext", false);
|
|
else
|
|
Con::setBoolVariable("$pref::Video::deleteContext", true);
|
|
*/
|
|
}
|
|
else
|
|
Con::setBoolVariable("$pref::Video::deleteContext", true);
|
|
Con::setBoolVariable("$pref::OpenGL::disableARBTextureCompression", !sCardProfiles[i].texCompress);
|
|
Con::setBoolVariable("$pref::Interior::lockArrays", sCardProfiles[i].interiorLock);
|
|
Con::setBoolVariable("$pref::TS::skipFirstFog", sCardProfiles[i].skipFirstFog);
|
|
Con::setBoolVariable("$pref::Video::only16", sCardProfiles[i].only16);
|
|
Con::setBoolVariable("$pref::OpenGL::noDrawArraysAlpha", sCardProfiles[i].noArraysAlpha);
|
|
|
|
proFile = sCardProfiles[i].proFile;
|
|
|
|
break;
|
|
}
|
|
|
|
// defaults
|
|
U16 glProfile;
|
|
|
|
if (!proFile)
|
|
{
|
|
// no driver GL profile -- make one via weighting GL extensions
|
|
glProfile = 25;
|
|
|
|
glProfile += gGLState.suppARBMultitexture * 25;
|
|
glProfile += gGLState.suppLockedArrays * 15;
|
|
glProfile += gGLState.suppVertexArrayRange * 10;
|
|
glProfile += gGLState.suppTextureEnvCombine * 5;
|
|
glProfile += gGLState.suppPackedPixels * 5;
|
|
glProfile += gGLState.suppTextureCompression * 5;
|
|
glProfile += gGLState.suppS3TC * 5;
|
|
glProfile += gGLState.suppFXT1 * 5;
|
|
|
|
Con::setBoolVariable("$pref::Video::safeModeOn", true);
|
|
Con::setBoolVariable("$pref::OpenGL::disableEXTCompiledVertexArray", false);
|
|
Con::setBoolVariable("$pref::OpenGL::disableSubImage", false);
|
|
Con::setBoolVariable("$pref::TS::fogTexture", false);
|
|
Con::setBoolVariable("$pref::OpenGL::noEnvColor", false);
|
|
Con::setBoolVariable("$pref::Video::clipHigh", false);
|
|
Con::setBoolVariable("$pref::Video::deleteContext", true);
|
|
Con::setBoolVariable("$pref::OpenGL::disableARBTextureCompression", false);
|
|
Con::setBoolVariable("$pref::Interior::lockArrays", true);
|
|
Con::setBoolVariable("$pref::TS::skipFirstFog", false);
|
|
Con::setBoolVariable("$pref::Video::only16", false);
|
|
Con::setBoolVariable("$pref::OpenGL::noDrawArraysAlpha", false);
|
|
}
|
|
|
|
Con::setVariable("$pref::Video::profiledVendor", vendor);
|
|
Con::setVariable("$pref::Video::profiledRenderer", renderer);
|
|
|
|
if (!Con::getBoolVariable("$DisableSystemProfiling") &&
|
|
( dStrcmp(vendor, Con::getVariable("$pref::Video::defaultsVendor")) ||
|
|
dStrcmp(renderer, Con::getVariable("$pref::Video::defaultsRenderer")) ))
|
|
{
|
|
if (proFile)
|
|
{
|
|
char settings[64];
|
|
|
|
dSprintf(settings,64,"%s.cs",proFile);
|
|
//Con::executef(2, "exec", settings);
|
|
execScript(settings);
|
|
}
|
|
else
|
|
{
|
|
U16 adjust;
|
|
|
|
// match clock with profile
|
|
for (i = 0; i < sNumProcessors; ++i)
|
|
{
|
|
adjust = sProcessorProfiles[i].adjust;
|
|
|
|
if (Platform::SystemInfo.processor.mhz < sProcessorProfiles[i].clock) break;
|
|
}
|
|
|
|
const char *settings;
|
|
|
|
// match performance metric with profile
|
|
for (i = 0; i < sNumSettings; ++i)
|
|
{
|
|
settings = sSettingProfiles[i].settings;
|
|
|
|
if (glProfile+adjust <= sSettingProfiles[i].performance) break;
|
|
}
|
|
|
|
//Con::executef(2, "exec", settings);
|
|
execScript(settings);
|
|
}
|
|
|
|
bool match = false;
|
|
|
|
for (i = 0; i < sOSCardProfiles.size(); ++i)
|
|
if (dStrstr(vendor, sOSCardProfiles[i].vendor) &&
|
|
(!dStrcmp(sOSCardProfiles[i].renderer, "*") ||
|
|
dStrstr(renderer, sOSCardProfiles[i].renderer)))
|
|
{
|
|
|
|
// Con::setBoolVariable("$pref::Video::allowOpenGL", sOSCardProfiles[i].allowOpenGL);
|
|
// Con::setBoolVariable("$pref::Video::allowD3D", sOSCardProfiles[i].allowD3D);
|
|
// Con::setBoolVariable("$pref::Video::preferOpenGL", sOSCardProfiles[i].preferOpenGL);
|
|
|
|
match = true;
|
|
|
|
break;
|
|
}
|
|
|
|
if (!match)
|
|
{
|
|
Con::setBoolVariable("$pref::Video::allowOpenGL", true);
|
|
// Con::setBoolVariable("$pref::Video::allowD3D", true);
|
|
Con::setBoolVariable("$pref::Video::preferOpenGL", true);
|
|
}
|
|
|
|
Con::setVariable("$pref::Video::defaultsVendor", vendor);
|
|
Con::setVariable("$pref::Video::defaultsRenderer", renderer);
|
|
}
|
|
|
|
// write out prefs
|
|
gEvalState.globalVars.exportVariables("$pref::*", "prefs/ClientPrefs.cs", false);
|
|
|
|
clearCardProfiles();
|
|
clearOSCardProfiles();
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
//------------------------------------------------------------------------------
|
|
OpenGLDevice::OpenGLDevice()
|
|
{
|
|
initDevice();
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
void OpenGLDevice::initDevice()
|
|
{
|
|
// Set the device name:
|
|
mDeviceName = "OpenGL";
|
|
|
|
// Never unload a code module
|
|
aglConfigure(AGL_RETAIN_RENDERERS, GL_TRUE);
|
|
|
|
#if defined(TORQUE_OS_MAC_OSX) && defined(AGL_TARGET_OS_MAC_OSX)
|
|
{// carbon porting guide says we MUST do this in mach-o Carbon code...
|
|
aglConfigure(AGL_TARGET_OS_MAC_OSX, GL_TRUE);
|
|
}
|
|
#endif
|
|
|
|
// Set some initial conditions:
|
|
mResolutionList.clear();
|
|
// sCanDoFullscreen = FALSE;
|
|
|
|
bool gotEm = enumDisplayModes(platState.hDisplay);
|
|
if (!gotEm)
|
|
{
|
|
mResolutionList.clear();
|
|
// fill it with some standard sizes for a machine, just to have something.
|
|
Point sizes[4] = {{640,480},{800,600},{1024,768},{1280,1024}};
|
|
for(int i=0; i<4; i++)
|
|
{
|
|
Resolution newRes16( sizes[i].h, sizes[i].v, 16 );
|
|
Resolution newRes32( sizes[i].h, sizes[i].v, 32 );
|
|
mResolutionList.push_back( newRes16 );
|
|
mResolutionList.push_back( newRes32 );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
bool OpenGLDevice::activate( U32 width, U32 height, U32 bpp, bool fullScreen )
|
|
{
|
|
Con::printf( "Activating the OpenGL display device..." );
|
|
|
|
bool needResurrect = false;
|
|
|
|
#pragma message("todo: need to error check on return from agl funcs.")
|
|
|
|
// If the rendering context exists, delete it:
|
|
/*
|
|
if (platState.ctx)
|
|
{
|
|
Con::printf( "Killing the texture manager..." );
|
|
Game->textureKill();
|
|
needResurrect = true;
|
|
|
|
Con::printf( "Making the rendering context not current..." );
|
|
aglSetCurrentContext(NULL);
|
|
aglSetDrawable(platState.ctx, NULL);
|
|
|
|
Con::printf( "Deleting the rendering context..." );
|
|
aglDestroyContext(platState.ctx);
|
|
platState.ctx = NULL;
|
|
}
|
|
*/
|
|
static bool onceAlready = false;
|
|
bool profiled = false;
|
|
|
|
// Set the resolution:
|
|
if ( !setScreenMode( width, height, bpp, ( fullScreen || mFullScreenOnly ), true, false ) )
|
|
return false;
|
|
|
|
// Get original gamma ramp
|
|
// mRestoreGamma = GetDeviceGammaRamp(platState.appDC, mOriginalRamp);
|
|
|
|
// Output some driver info to the console:
|
|
const char* vendorString = (const char*) glGetString( GL_VENDOR );
|
|
const char* rendererString = (const char*) glGetString( GL_RENDERER );
|
|
const char* versionString = (const char*) glGetString( GL_VERSION );
|
|
Con::printf( "OpenGL driver information:" );
|
|
if ( vendorString )
|
|
Con::printf( " Vendor: %s", vendorString );
|
|
if ( rendererString )
|
|
Con::printf( " Renderer: %s", rendererString );
|
|
if ( versionString )
|
|
Con::printf( " Version: %s", versionString );
|
|
|
|
if ( needResurrect )
|
|
{
|
|
// Reload the textures:
|
|
Con::printf( "Resurrecting the texture manager..." );
|
|
Game->textureResurrect();
|
|
}
|
|
|
|
//Now that we have video setup, and window established, we do any initialization/checking
|
|
// of OpenGL interfaces necessary to setup the rendering system.
|
|
GL_EXT_Init();
|
|
|
|
Con::setVariable( "$pref::Video::displayDevice", mDeviceName );
|
|
|
|
/* !!!!!!TBD LATER!!!!!!!!
|
|
// only do this for the first session
|
|
if (!profiled &&
|
|
!Con::getBoolVariable("$DisableSystemProfiling") &&
|
|
( dStrcmp(vendorString, Con::getVariable("$pref::Video::profiledVendor")) ||
|
|
dStrcmp(rendererString, Con::getVariable("$pref::Video::profiledRenderer")) ))
|
|
{
|
|
profileSystem(vendorString, rendererString);
|
|
profiled = true;
|
|
}
|
|
|
|
if (profiled)
|
|
{
|
|
U32 width, height, bpp;
|
|
|
|
if (Con::getBoolVariable("$pref::Video::clipHigh", false))
|
|
for (S32 i = mResolutionList.size()-1; i >= 0; --i)
|
|
if (mResolutionList[i].w > 1152 || mResolutionList[i].h > 864)
|
|
mResolutionList.erase(i);
|
|
|
|
if (Con::getBoolVariable("$pref::Video::only16", false))
|
|
for (S32 i = mResolutionList.size()-1; i >= 0; --i)
|
|
if (mResolutionList[i].bpp == 32)
|
|
mResolutionList.erase(i);
|
|
|
|
dSscanf(Con::getVariable("$pref::Video::resolution"), "%d %d %d", &width, &height, &bpp);
|
|
setScreenMode(width, height, bpp,
|
|
Con::getBoolVariable("$pref::Video::fullScreen", true), false, false);
|
|
}
|
|
*/
|
|
|
|
// Do this here because we now know about the extensions:
|
|
// if ( gGLState.suppSwapInterval )
|
|
setVerticalSync( !Con::getBoolVariable( "$pref::Video::disableVerticalSync" ) );
|
|
Con::setBoolVariable("$pref::OpenGL::allowTexGen", true);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// returns TRUE if textures need resurrecting in future...
|
|
//------------------------------------------------------------------------------
|
|
bool OpenGLDevice::GLCleanupHelper()
|
|
{
|
|
bool needResurrect = false;
|
|
|
|
Con::printf( "Cleaning up the display device..." );
|
|
|
|
// !!!!!TBD
|
|
// NOTE THAT A LARGE CHUNK OF THIS CODE IS SHARED WITH shutdown(), AND THUS SHOULD BE >REALLY< SHARED CODE.
|
|
// Delete the rendering context:
|
|
if (platState.ctx)
|
|
{
|
|
if (!Video::smNeedResurrect) // as that flag means we already ditched textures...
|
|
{
|
|
Con::printf( "Killing the texture manager..." );
|
|
Game->textureKill();
|
|
needResurrect = true;
|
|
}
|
|
|
|
Con::printf( "Making sure the rendering context is not current..." );
|
|
aglSetCurrentContext(NULL);
|
|
#if !defined(TORQUE_DEBUG)
|
|
agl_ctx = NULL; // maintain up aglMacro.h context
|
|
#endif
|
|
|
|
aglSetDrawable((AGLContext)platState.ctx, NULL);
|
|
if (0) // !!!!TBD error check
|
|
{
|
|
AssertFatal( false, "OpenGLDevice::setScreenMode\naglSetDrawable( ctx, NULL ) failed!" );
|
|
return false;
|
|
}
|
|
|
|
Con::printf( "Deleting the rendering context..." );
|
|
// !!!! TBD WHY IS THIS CHECK HERE??? IS IT VALID ON MAC?? WHY NOT IN ACTIVATE???
|
|
// if ( Con::getBoolVariable("$pref::Video::deleteContext",true) )
|
|
aglDestroyContext((AGLContext)platState.ctx);
|
|
if (0) // !!!!TBD error check
|
|
{
|
|
AssertFatal( false, "OpenGLDevice::setScreenMode\naglDestroyContext failed!" );
|
|
return false;
|
|
}
|
|
|
|
// make sure it is null...
|
|
platState.ctx = NULL;
|
|
}
|
|
|
|
// !!!!!TBD HANDLE GAMMA
|
|
// if (mRestoreGamma)
|
|
// SetDeviceGammaRamp(platState.appDC, mOriginalRamp);
|
|
|
|
if (gpDSpPort) // == smIsFullScreen...
|
|
{
|
|
Con::printf("Shutting down DrawSprocket and restoring Desktop (%dx%dx%d)...", platState.desktopWidth, platState.desktopHeight, platState.desktopBitsPixel );
|
|
ShutdownDSp(gpDSpPort);
|
|
}
|
|
|
|
// on the mac, if the window is still around for any reason, dispose of it now.
|
|
// DestroyGL or ShutdownDSp will have nuked it already if they created it...
|
|
if ( platState.appWindow )
|
|
{
|
|
Con::printf( "Destroying the window..." );
|
|
if (platState.osX)
|
|
ReleaseWindow(platState.appWindow);
|
|
else
|
|
DisposeWindow(platState.appWindow);
|
|
platState.appWindow = NULL;
|
|
}
|
|
|
|
// clear some Res state, so we don't think we're set up already.
|
|
smCurrentRes.w = 0;
|
|
smCurrentRes.h = 0;
|
|
|
|
return(needResurrect);
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
void OpenGLDevice::shutdown()
|
|
{
|
|
OSStatus err = noErr;
|
|
|
|
Con::printf( "Shutting down the OpenGL display device..." );
|
|
|
|
// call our new universal helper function...
|
|
GLCleanupHelper();
|
|
|
|
// should be safe to always call.
|
|
ShowMenuBar();
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// This is the real workhorse function of the DisplayDevice...
|
|
//
|
|
static bool wasWindowed = true;
|
|
bool OpenGLDevice::setScreenMode( U32 width, U32 height, U32 bpp, bool fullScreen, bool forceIt, bool repaint )
|
|
{
|
|
// SANITY CHECK, AS THE FRICKING SCRIPTS PASS IN BAD VALUES. LIKE ZERO.
|
|
if (!bpp)
|
|
bpp = platState.desktopBitsPixel;
|
|
|
|
WindowPtr curtain = NULL;
|
|
char errorMessage[256];
|
|
bool newFullScreen = fullScreen;
|
|
bool safeModeOn = Con::getBoolVariable( "$pref::Video::safeModeOn" );
|
|
bool needResurrect = false;
|
|
Resolution newRes( width, height, bpp );
|
|
Resolution oldRes = smCurrentRes;
|
|
OSStatus err;
|
|
|
|
// !!!!!TBD
|
|
// if no values changing, return immediately.
|
|
// this is sort-of an optimization, but also useful to prevent thrashing (which the
|
|
// current graphic startup would do otherwise...)
|
|
if (smCurrentRes.w == width && smCurrentRes.h == height && smCurrentRes.bpp == bpp && smIsFullScreen == newFullScreen)
|
|
return(true);
|
|
|
|
if ( !newFullScreen && mFullScreenOnly )
|
|
{
|
|
Con::warnf( ConsoleLogEntry::General, "OpenGLDevice::setScreenMode - device or desktop color depth does not allow windowed mode!" );
|
|
newFullScreen = true;
|
|
}
|
|
|
|
|
|
|
|
#pragma message("todo: how to handle picking available resolutions?")
|
|
|
|
// !!!!!!!TBD NOT SURE THAT WOULD DO THE RIGHT THING FOR MAC IN ALL CASES!
|
|
// THEREFORE, ALWAYS GO DO SHUTDOWN CODE!!!
|
|
needResurrect = GLCleanupHelper();
|
|
|
|
// MAC DOESN'T NEED A CURTAIN -- prefers to use gamma fade out/in...
|
|
// curtain = CreateCurtain( newRes.w, newRes.h );
|
|
|
|
Con::printf( ">> Attempting to change display settings to %s %dx%dx%d...", newFullScreen?"fullscreen":"windowed", newRes.w, newRes.h, newRes.bpp );
|
|
|
|
if ( newFullScreen )
|
|
smIsFullScreen = true;
|
|
else if ( smIsFullScreen )
|
|
smIsFullScreen = false;
|
|
// WRITE TO PREFS
|
|
Con::setBoolVariable( "$pref::Video::fullScreen", smIsFullScreen );
|
|
|
|
// set our preferred device
|
|
// default is the main device (which should be the one at [0,0]).
|
|
GDHandle currDev = GetMainDevice();
|
|
int devicenum = Con::getIntVariable("$pref::Video::monitorNum", 0);
|
|
if (devicenum)
|
|
{ // then find the right device.
|
|
if (devicenum>gNumDevices || devicenum<1)
|
|
{
|
|
// well, then give them default device
|
|
devicenum = 0;
|
|
Con::setIntVariable("$pref::Video::monitorNum", devicenum);
|
|
}
|
|
else
|
|
currDev = gDeviceList[devicenum-1];
|
|
}
|
|
platState.hDisplay = currDev;
|
|
|
|
// in case we fail, put back values for the moment, as we munged them in Cleanup.
|
|
smCurrentRes = oldRes;
|
|
bool aglReady = false;
|
|
if (newFullScreen)
|
|
{
|
|
#if USE_AGL_FULLSCREEN
|
|
if (platState.osX) // under osx we can try SetaglFullScreen
|
|
{
|
|
short display = devicenum; // !!!! IS THIS CORRECT? !!!!TBD -- need to define a GDHandle to display # mapping
|
|
if (platState.ctx = SetupAGLFullScreen (&mainfmt, platState.hDisplay, newRes.w, newRes.h, newRes.bpp)) // Setup the OpenGL context
|
|
{
|
|
aglReady = true;
|
|
SetRect (&gRectPort, 0, 0, newRes.w, newRes.h); // l, t, r, b
|
|
Con::printf("Successfully set up AGLFullscreen support [%d x %d x %d : %dHz]", newRes.w, newRes.h, newRes.bpp, gCurrentFrequency);
|
|
}
|
|
else
|
|
{
|
|
Con::printf("Failed to set up AGLFullscreen support.");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (!aglReady) // not ready yet. try normal SetupAGL.
|
|
{
|
|
gpDSpPort = SetupDSp (&(platState.hDisplay), newRes.w, newRes.h, newRes.bpp); // Setup DSp for OpenGL
|
|
if (gpDSpPort==NULL) // oops
|
|
{
|
|
Con::warnf("Failed to establish DrawSprocket monitor control.");
|
|
return(false);
|
|
}
|
|
|
|
if (platState.ctx = SetupAGL(&mainfmt, platState.hDisplay, gpDSpPort, newRes.bpp)) // Setup the OpenGL context
|
|
{
|
|
GetPortBounds (gpDSpPort, &gRectPort);
|
|
if (platState.hDisplay)
|
|
Con::printf("Successfully set up AGL support with DSp Fullscreen [%d x %d x %d : %dHz]", gRectPort.right - gRectPort.left, gRectPort.bottom - gRectPort.top, (**(**platState.hDisplay).gdPMap).pixelSize, gCurrentFrequency);
|
|
else
|
|
Con::printf("Successfully set up GL support [%d x %d]", gRectPort.right - gRectPort.left, gRectPort.bottom - gRectPort.top);
|
|
}
|
|
else
|
|
{
|
|
Con::printf("Failed to set up AGL context support.");
|
|
return(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
//if we haven't yet created/assigned a plat window, need to do so now.
|
|
if (!platState.appWindow )
|
|
{
|
|
platState.appWindow = CreateOpenGLWindow( platState.hDisplay, newRes.w, newRes.h, false );
|
|
if ( !platState.appWindow )
|
|
{
|
|
AssertFatal( false, "OpenGLDevice::setScreenMode - Failed to create a new window!" );
|
|
return false;
|
|
}
|
|
else
|
|
Con::printf( "Created new %swindow for GL [%d x %d].", newFullScreen ? "Fullscreen " : "", newRes.w, newRes.h );
|
|
}
|
|
|
|
if (!newFullScreen)
|
|
{
|
|
CGrafPtr port = GetWindowPort(platState.appWindow);
|
|
AGLDrawable drawto = port; // just to be clear.
|
|
GetPortBounds (port, &gRectPort);
|
|
if (NULL == (platState.ctx = SetupAGL(&mainfmt, platState.hDisplay, drawto, newRes.bpp))) // Setup the OpenGL context
|
|
{
|
|
Con::warnf("Failed to set up AGL windowed support.");
|
|
return false;
|
|
}
|
|
Con::printf("Successfully set up AGL windowed support [%d x %d]", gRectPort.right - gRectPort.left, gRectPort.bottom - gRectPort.top);
|
|
}
|
|
|
|
//PRINT BACK THE FORMAT WE GOT!!!! !!!!TBD
|
|
//qwglDescribePixelFormat( platState.appDC, chosenFormat, sizeof( pfd ), &pfd );
|
|
//Con::printf( "Pixel format set:" );
|
|
//Con::printf( " %d color bits, %d depth bits, %d stencil bits", platState.fmt.cColorBits, pfd.cDepthBits, pfd.cStencilBits );
|
|
|
|
// validate that this function is available in CFM on OSX...
|
|
if ((Ptr) kUnresolvedCFragSymbolAddress != (Ptr) glPixelStorei)
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
|
|
|
if ( needResurrect )
|
|
{
|
|
// Reload the textures:
|
|
Con::printf( "Resurrecting the texture manager..." );
|
|
Game->textureResurrect();
|
|
}
|
|
|
|
// if ( gGLState.suppSwapInterval ) // mac always supports this, basically.
|
|
setVerticalSync( !Con::getBoolVariable( "$pref::Video::disableVerticalSync" ) );
|
|
|
|
smCurrentRes = newRes;
|
|
// !!!TBD
|
|
// this is kinda redundant in the mac schema...
|
|
Platform::setWindowSize( newRes.w, newRes.h );
|
|
|
|
// WRITE TO PREFS
|
|
char tempBuf[15];
|
|
if (smIsFullScreen)
|
|
{
|
|
dSprintf( tempBuf, sizeof( tempBuf ), "%d %d %d", smCurrentRes.w, smCurrentRes.h, smCurrentRes.bpp );
|
|
Con::setVariable( "$pref::Video::resolution", tempBuf );
|
|
if (wasWindowed)
|
|
HideMenuBar();
|
|
wasWindowed = false;
|
|
}
|
|
else // windowed
|
|
{
|
|
dSprintf( tempBuf, sizeof( tempBuf ), "%d %d", smCurrentRes.w, smCurrentRes.h );
|
|
Con::setVariable( "$pref::Video::windowedRes", tempBuf );
|
|
wasWindowed = true;
|
|
ShowMenuBar(); // should be safe to always call...
|
|
}
|
|
|
|
// if ( curtain )
|
|
// DisposeWindow( curtain );
|
|
|
|
if ( repaint )
|
|
Con::evaluate( "resetCanvas();" );
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
void OpenGLDevice::swapBuffers()
|
|
{
|
|
// TBD!!!!! should this be setting to platState.ctx
|
|
// in future, support multiple contexts?
|
|
#if later //!!!
|
|
//dhc - also adding in a sanity check here.
|
|
AssertISV((AGLContext)platState.ctx, "OpenGLDevice::swapBuffers -- No GL context in place!");
|
|
#endif
|
|
if (platState.ctx)
|
|
aglSwapBuffers(aglGetCurrentContext());
|
|
#if defined(TORQUE_DEBUG)
|
|
if(gOutlineEnabled)
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
#endif
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
const char* OpenGLDevice::getDriverInfo()
|
|
{
|
|
// Output some driver info to the console:
|
|
const char* vendorString = (const char*) glGetString( GL_VENDOR );
|
|
const char* rendererString = (const char*) glGetString( GL_RENDERER );
|
|
const char* versionString = (const char*) glGetString( GL_VERSION );
|
|
const char* extensionsString = (const char*) glGetString( GL_EXTENSIONS );
|
|
|
|
U32 bufferLen = ( vendorString ? dStrlen( vendorString ) : 0 )
|
|
+ ( rendererString ? dStrlen( rendererString ) : 0 )
|
|
+ ( versionString ? dStrlen( versionString ) : 0 )
|
|
+ ( extensionsString ? dStrlen( extensionsString ) : 0 )
|
|
+ 4;
|
|
|
|
char* returnString = Con::getReturnBuffer( bufferLen );
|
|
dSprintf( returnString, bufferLen, "%s\t%s\t%s\t%s",
|
|
( vendorString ? vendorString : "" ),
|
|
( rendererString ? rendererString : "" ),
|
|
( versionString ? versionString : "" ),
|
|
( extensionsString ? extensionsString : "" ) );
|
|
|
|
return( returnString );
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
bool OpenGLDevice::getGammaCorrection(F32 &g)
|
|
{
|
|
U16 ramp[256*3];
|
|
|
|
#pragma message("todo: gamma")
|
|
/*
|
|
if (!GetDeviceGammaRamp(platState.appDC, ramp))
|
|
return false;
|
|
*/
|
|
|
|
F32 csum = 0.0;
|
|
U32 ccount = 0;
|
|
|
|
for (U16 i = 0; i < 256; ++i)
|
|
{
|
|
if (i != 0 && ramp[i] != 0 && ramp[i] != 65535)
|
|
{
|
|
F64 b = (F64) i/256.0;
|
|
F64 a = (F64) ramp[i]/65535.0;
|
|
F32 c = (F32) (mLog(a)/mLog(b));
|
|
|
|
csum += c;
|
|
++ccount;
|
|
}
|
|
}
|
|
g = csum/ccount;
|
|
|
|
return true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
bool OpenGLDevice::setGammaCorrection(F32 g)
|
|
{
|
|
U16 ramp[256*3];
|
|
|
|
for (U16 i = 0; i < 256; ++i)
|
|
ramp[i] = mPow((F32) i/256.0f, g) * 65535.0f;
|
|
dMemcpy(&ramp[256],ramp,256*sizeof(U16));
|
|
dMemcpy(&ramp[512],ramp,256*sizeof(U16));
|
|
|
|
bool t = false;
|
|
#pragma message("todo: gamma")
|
|
// t = SetDeviceGammaRamp(platState.appDC, ramp);
|
|
return t;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
bool OpenGLDevice::setVerticalSync( bool on )
|
|
{
|
|
// HACK
|
|
on = false; // !!!!!TBD for some reason, the disable pref is set to one, the value is grabbed and flipped
|
|
// and it STILL comes through as non-zero!!!
|
|
|
|
// Apple has an internal vsync flag:
|
|
if (platState.ctx)
|
|
{
|
|
GLint val = on ? 1 : 0;
|
|
return(GL_FALSE != aglSetInteger((AGLContext)platState.ctx, AGL_SWAP_INTERVAL, &val));
|
|
}
|
|
return(false);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
DisplayDevice* OpenGLDevice::create()
|
|
{
|
|
bool result = true;
|
|
bool fullScreenOnly = false;
|
|
|
|
// validate OpenGL existance/linkage here for now.
|
|
if ((Ptr) kUnresolvedCFragSymbolAddress == (Ptr) glBegin
|
|
|| (Ptr) kUnresolvedCFragSymbolAddress == (Ptr) aglChoosePixelFormat)
|
|
{
|
|
ReportError ("OpenGL not installed");
|
|
return NULL;
|
|
}
|
|
|
|
if (!InitDSp())
|
|
return(NULL);
|
|
|
|
#if !defined(TORQUE_DEBUG)
|
|
// set up a dummy default agl context
|
|
// this will be replaced later with the window's context, but
|
|
// since we use aglMacro.h in release builds, we need agl_ctx to be valid at any time.
|
|
InitDummyAgl();
|
|
#endif
|
|
|
|
|
|
// go find all the screen devices, in device order.
|
|
GDHandle hDevice;
|
|
gNumDevices = 0;
|
|
// always at least one screen device...
|
|
hDevice = DMGetFirstScreenDevice (true); // check number of screens
|
|
gDeviceList[gNumDevices++] = hDevice;
|
|
while(hDevice = DMGetNextScreenDevice (hDevice, true))
|
|
gDeviceList[gNumDevices++] = hDevice;
|
|
|
|
// set our preferred device
|
|
// default is the main device (which should be the one at [0,0]).
|
|
GDHandle currDev = GetMainDevice();
|
|
int devicenum = Con::getIntVariable("$pref::Video::monitorNum", 0);
|
|
if (devicenum)
|
|
{ // then find the right device.
|
|
if (devicenum>gNumDevices || devicenum<1)
|
|
{
|
|
// well, then give them default device
|
|
devicenum = 0;
|
|
Con::setIntVariable("$pref::Video::monitorNum", devicenum);
|
|
}
|
|
else
|
|
currDev = gDeviceList[devicenum-1];
|
|
}
|
|
platState.hDisplay = currDev;
|
|
|
|
#pragma message("todo: ::create() full gl acceleration/availability test")
|
|
|
|
if ( result )
|
|
{
|
|
OpenGLDevice* newOGLDevice = new OpenGLDevice();
|
|
if ( newOGLDevice )
|
|
{
|
|
newOGLDevice->mFullScreenOnly = fullScreenOnly;
|
|
return (DisplayDevice*) newOGLDevice;
|
|
}
|
|
else
|
|
return NULL;
|
|
}
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
#if defined(TORQUE_DEBUG)
|
|
static U32 getIndex(GLenum type, const void *indices, U32 i)
|
|
{
|
|
if(type == GL_UNSIGNED_BYTE)
|
|
return ((U8 *) indices)[i];
|
|
else if(type == GL_UNSIGNED_SHORT)
|
|
return ((U16 *) indices)[i];
|
|
else
|
|
return ((U32 *) indices)[i];
|
|
}
|
|
|
|
void glOutlineDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)
|
|
{
|
|
if(mode == GL_POLYGON)
|
|
mode = GL_LINE_LOOP;
|
|
|
|
if(mode == GL_POINTS || mode == GL_LINE_STRIP || mode == GL_LINE_LOOP || mode == GL_LINES)
|
|
glDrawElements( mode, count, type, indices );
|
|
else
|
|
{
|
|
glBegin(GL_LINES);
|
|
if(mode == GL_TRIANGLE_STRIP)
|
|
{
|
|
U32 i;
|
|
for(i = 0; i < count - 1; i++)
|
|
{
|
|
glArrayElement(getIndex(type, indices, i));
|
|
glArrayElement(getIndex(type, indices, i + 1));
|
|
if(i + 2 != count)
|
|
{
|
|
glArrayElement(getIndex(type, indices, i));
|
|
glArrayElement(getIndex(type, indices, i + 2));
|
|
}
|
|
}
|
|
}
|
|
else if(mode == GL_TRIANGLE_FAN)
|
|
{
|
|
for(U32 i = 1; i < count; i ++)
|
|
{
|
|
glArrayElement(getIndex(type, indices, 0));
|
|
glArrayElement(getIndex(type, indices, i));
|
|
if(i != count - 1)
|
|
{
|
|
glArrayElement(getIndex(type, indices, i));
|
|
glArrayElement(getIndex(type, indices, i + 1));
|
|
}
|
|
}
|
|
}
|
|
else if(mode == GL_TRIANGLES)
|
|
{
|
|
for(U32 i = 3; i <= count; i += 3)
|
|
{
|
|
glArrayElement(getIndex(type, indices, i - 3));
|
|
glArrayElement(getIndex(type, indices, i - 2));
|
|
glArrayElement(getIndex(type, indices, i - 2));
|
|
glArrayElement(getIndex(type, indices, i - 1));
|
|
glArrayElement(getIndex(type, indices, i - 3));
|
|
glArrayElement(getIndex(type, indices, i - 1));
|
|
}
|
|
}
|
|
else if(mode == GL_QUADS)
|
|
{
|
|
for(U32 i = 4; i <= count; i += 4)
|
|
{
|
|
glArrayElement(getIndex(type, indices, i - 4));
|
|
glArrayElement(getIndex(type, indices, i - 3));
|
|
glArrayElement(getIndex(type, indices, i - 3));
|
|
glArrayElement(getIndex(type, indices, i - 2));
|
|
glArrayElement(getIndex(type, indices, i - 2));
|
|
glArrayElement(getIndex(type, indices, i - 1));
|
|
glArrayElement(getIndex(type, indices, i - 4));
|
|
glArrayElement(getIndex(type, indices, i - 1));
|
|
}
|
|
}
|
|
else if(mode == GL_QUAD_STRIP)
|
|
{
|
|
if(count < 4)
|
|
return;
|
|
glArrayElement(getIndex(type, indices, 0));
|
|
glArrayElement(getIndex(type, indices, 1));
|
|
for(U32 i = 4; i <= count; i += 2)
|
|
{
|
|
glArrayElement(getIndex(type, indices, i - 4));
|
|
glArrayElement(getIndex(type, indices, i - 2));
|
|
|
|
glArrayElement(getIndex(type, indices, i - 3));
|
|
glArrayElement(getIndex(type, indices, i - 1));
|
|
|
|
glArrayElement(getIndex(type, indices, i - 2));
|
|
glArrayElement(getIndex(type, indices, i - 1));
|
|
}
|
|
}
|
|
glEnd();
|
|
}
|
|
}
|
|
|
|
void glOutlineDrawArrays(GLenum mode, GLint first, GLsizei count)
|
|
{
|
|
if(mode == GL_POLYGON)
|
|
mode = GL_LINE_LOOP;
|
|
|
|
if(mode == GL_POINTS || mode == GL_LINE_STRIP || mode == GL_LINE_LOOP || mode == GL_LINES)
|
|
glDrawArrays( mode, first, count );
|
|
else
|
|
{
|
|
glBegin(GL_LINES);
|
|
if(mode == GL_TRIANGLE_STRIP)
|
|
{
|
|
U32 i;
|
|
for(i = 0; i < count - 1; i++)
|
|
{
|
|
glArrayElement(first + i);
|
|
glArrayElement(first + i + 1);
|
|
if(i + 2 != count)
|
|
{
|
|
glArrayElement(first + i);
|
|
glArrayElement(first + i + 2);
|
|
}
|
|
}
|
|
}
|
|
else if(mode == GL_TRIANGLE_FAN)
|
|
{
|
|
for(U32 i = 1; i < count; i ++)
|
|
{
|
|
glArrayElement(first);
|
|
glArrayElement(first + i);
|
|
if(i != count - 1)
|
|
{
|
|
glArrayElement(first + i);
|
|
glArrayElement(first + i + 1);
|
|
}
|
|
}
|
|
}
|
|
else if(mode == GL_TRIANGLES)
|
|
{
|
|
for(U32 i = 3; i <= count; i += 3)
|
|
{
|
|
glArrayElement(first + i - 3);
|
|
glArrayElement(first + i - 2);
|
|
glArrayElement(first + i - 2);
|
|
glArrayElement(first + i - 1);
|
|
glArrayElement(first + i - 3);
|
|
glArrayElement(first + i - 1);
|
|
}
|
|
}
|
|
else if(mode == GL_QUADS)
|
|
{
|
|
for(U32 i = 4; i <= count; i += 4)
|
|
{
|
|
glArrayElement(first + i - 4);
|
|
glArrayElement(first + i - 3);
|
|
glArrayElement(first + i - 3);
|
|
glArrayElement(first + i - 2);
|
|
glArrayElement(first + i - 2);
|
|
glArrayElement(first + i - 1);
|
|
glArrayElement(first + i - 4);
|
|
glArrayElement(first + i - 1);
|
|
}
|
|
}
|
|
else if(mode == GL_QUAD_STRIP)
|
|
{
|
|
if(count < 4)
|
|
return;
|
|
glArrayElement(first + 0);
|
|
glArrayElement(first + 1);
|
|
for(U32 i = 4; i <= count; i += 2)
|
|
{
|
|
glArrayElement(first + i - 4);
|
|
glArrayElement(first + i - 2);
|
|
|
|
glArrayElement(first + i - 3);
|
|
glArrayElement(first + i - 1);
|
|
|
|
glArrayElement(first + i - 2);
|
|
glArrayElement(first + i - 1);
|
|
}
|
|
}
|
|
glEnd();
|
|
}
|
|
}
|
|
|
|
|
|
ConsoleFunction(GLEnableOutline,void,2,2,"GLEnableOutline( true | false ) - sets whether to render wireframe")
|
|
{
|
|
gOutlineEnabled = dAtob(argv[1]);
|
|
if(gOutlineEnabled)
|
|
{
|
|
glDrawElementsProcPtr = glOutlineDrawElements;
|
|
glDrawArraysProcPtr = glOutlineDrawArrays;
|
|
Con::printf("swapped to outline mode funcs");
|
|
} else {
|
|
glDrawElementsProcPtr = glDrawElements;
|
|
glDrawArraysProcPtr = glDrawArrays;
|
|
Con::printf("swapped to normal funcs");
|
|
}
|
|
}
|
|
#endif
|