MacGLide/MacGLide/Mac/SetupGL/Carbon_SetupGL.c

1186 lines
40 KiB
C
Executable File

/*
File: Carbon SetupGL.c
Contains: Functions to enable building and destorying a GL full screen or windowed context
Written by: Geoff Stahl (ggs)
Copyright: Copyright © 1999 Apple Computer, Inc., All Rights Reserved
Change History (most recent first):
<4> 8/23/01 ggs Fixed texture sharing and added number of bug fixes
<3> 4/20/01 ggs Added support for texture sharing by sharing all contexts by default
<2> 3/26/01 ggs Add DSp version check and other items for full screen on X
<1> 1/19/01 ggs Initial re-add
<7> 3/22/00 ggs remove extranious prototype
<6> 3/21/00 ggs Added windowed mode and clean up various implementation details
<5> 1/26/00 ggs Add fade code back in, ensure NULL pointer/context/drawable
checks are in, add Preflight
<4> 1/24/00 ggs Added glFinish to shutdown code
<3> 1/24/00 ggs update to latest, better rendrere info handling for 3dfx, better
checks on pause and resume, added frin devce numer and gdhandle
from point
<2.7> 11/28/99 ggs Split out DSp and error handling. Added texture memory
considerations, assume VRAM is required if other than zero
<2.6> 11/14/99 ggs Fix source server copy
<2.5> 11/13/99 ggs fixed default pixel depth (0) condition that was causing failures
<2.4> 11/13/99 ggs added custom fade code
<2.3> 11/13/99 ggs Reset for Quake 3 use
<2.2> 11/12/99 ggs re-add
<2.1> 11/12/99 ggs added support for frequency retrieval, fixed display number
output to be correct if display number input was -1
<2> 11/12/99 ggs 1.0 functionality
<1> 11/11/99 ggs Initial Add
Disclaimer: You may incorporate this sample code into your applications without
restriction, though the sample code has been provided "AS IS" and the
responsibility for its operation is 100% yours. However, what you are
not permitted to do is to redistribute the source as "DSC Sample Code"
after having made changes. If you're going to re-distribute the source,
we require that you make it clear in the source that the code was
descended from Apple Sample Code, but that you've made changes.
*/
// system includes ----------------------------------------------------------
#ifdef __APPLE_CC__
#include <Carbon/Carbon.h>
#else
#include <Gestalt.h>
#include <sound.h>
#endif
// project includes ---------------------------------------------------------
#include "Carbon_Error_Handler.h"
#include "Carbon_SetupDSp.h"
#include "Carbon_SetupGL.h"
// globals (internal/private) -----------------------------------------------
const RGBColor rgbBlack = { 0x0000, 0x0000, 0x0000 };
const short kWindowType = kWindowDocumentProc;
// prototypes (internal/private) --------------------------------------------
static Boolean CheckRenderer (GDHandle hGD, long *VRAM, long *textureRAM, GLint* , Boolean fAccelMust);
static Boolean CheckAllDeviceRenderers (long* pVRAM, long* pTextureRAM, GLint* pDepthSizeSupport, Boolean fAccelMust);
static Boolean CheckWindowExtents (GDHandle hGD, short width, short height);
static void DumpCurrent (AGLDrawable* paglDraw, AGLContext* paglContext, DSpContextReference* pdspContext, pstructGLInfo pcontextInfo);
static OSStatus BuildGLContext (AGLDrawable* paglDraw, AGLContext* paglContext, DSpContextReference* pdspContext, GDHandle hGD,
pstructGLInfo pcontextInfo, AGLContext aglShareContext);
static OSStatus BuildDrawable (AGLDrawable* paglDraw, GDHandle hGD, pstructGLInfo pcontextInfo);
static OSStatus BuildGLonDevice (AGLDrawable* paglDraw, AGLContext* paglContext, DSpContextReference* pdspContext,
GDHandle hGD, pstructGLInfo pcontextInfo, AGLContext aglShareContext);
static OSStatus BuildGLonWindow (WindowPtr pWindow, AGLContext* paglContext, pstructGLWindowInfo pcontextInfo, AGLContext aglShareContext);
// functions (internal/private) ---------------------------------------------
// CheckRenderer
// looks at renderer attributes it has at least the VRAM is accelerated
// Inputs: hGD: GDHandle to device to look at
// pVRAM: pointer to VRAM in bytes required; out is actual VRAM if a renderer was found, otherwise it is the input parameter
// pTextureRAM: pointer to texture RAM in bytes required; out is same (implementation assume VRAM returned by card is total so we add texture and VRAM)
// fAccelMust: do we check for acceleration
// Returns: true if renderer for the requested device complies, false otherwise
static Boolean CheckRenderer (GDHandle hGD, long* pVRAM, long* pTextureRAM, GLint* pDepthSizeSupport, Boolean fAccelMust)
{
AGLRendererInfo info, head_info;
GLint inum;
GLint dAccel = 0;
GLint dVRAM = 0, dMaxVRAM = 0;
Boolean canAccel = false, found = false;
head_info = aglQueryRendererInfo(&hGD, 1);
aglReportError ();
if(!head_info)
{
ReportError ("aglQueryRendererInfo error");
return false;
}
else
{
info = head_info;
inum = 0;
// see if we have an accelerated renderer, if so ignore non-accelerated ones
// this prevents returning info on software renderer when actually we'll get the hardware one
while (info)
{
aglDescribeRenderer(info, AGL_ACCELERATED, &dAccel);
aglReportError ();
if (dAccel)
canAccel = true;
info = aglNextRendererInfo(info);
aglReportError ();
inum++;
}
info = head_info;
inum = 0;
while (info)
{
aglDescribeRenderer (info, AGL_ACCELERATED, &dAccel);
aglReportError ();
// if we can accel then we will choose the accelerated renderer
// how about compliant renderers???
if ((canAccel && dAccel) || (!canAccel && (!fAccelMust || dAccel)))
{
aglDescribeRenderer (info, AGL_VIDEO_MEMORY, &dVRAM); // we assume that VRAM returned is total thus add texture and VRAM required
aglReportError ();
if (dVRAM >= (*pVRAM + *pTextureRAM))
{
if (dVRAM >= dMaxVRAM) // find card with max VRAM
{
aglDescribeRenderer (info, AGL_DEPTH_MODES, pDepthSizeSupport); // which depth buffer modes are supported
aglReportError ();
dMaxVRAM = dVRAM; // store max
found = true;
}
}
}
info = aglNextRendererInfo(info);
aglReportError ();
inum++;
}
}
aglDestroyRendererInfo(head_info);
if (found) // if we found a card that has enough VRAM and meets the accel criteria
{
*pVRAM = dMaxVRAM; // return VRAM
return true;
}
// VRAM will remain to same as it did when sent in
return false;
}
//-----------------------------------------------------------------------------------------------------------------------
// CheckAllDeviceRenderers
// looks at renderer attributes and each device must have at least one renderer that fits the profile
// Inputs: pVRAM: pointer to VRAM in bytes required; out is actual min VRAM of all renderers found, otherwise it is the input parameter
// pTextureRAM: pointer to texture RAM in bytes required; out is same (implementation assume VRAM returned by card is total so we add texture and VRAM)
// fAccelMust: do we check fro acceleration
// Returns: true if any renderer for on each device complies (not necessarily the same renderer), false otherwise
static Boolean CheckAllDeviceRenderers (long* pVRAM, long* pTextureRAM, GLint* pDepthSizeSupport, Boolean fAccelMust)
{
AGLRendererInfo info, head_info;
GLint inum;
GLint dAccel = 0;
GLint dVRAM = 0, dMaxVRAM = 0;
Boolean canAccel = false, found = false, goodCheck = true; // can the renderer accelerate, did we find a valid renderer for the device, are we still successfully on all the devices looked at
long MinVRAM = 0x8FFFFFFF; // max long
GDHandle hGD = GetDeviceList (); // get the first screen
while (hGD && goodCheck)
{
head_info = aglQueryRendererInfo(&hGD, 1);
aglReportError ();
if(!head_info)
{
ReportError ("aglQueryRendererInfo error");
return false;
}
else
{
info = head_info;
inum = 0;
// see if we have an accelerated renderer, if so ignore non-accelerated ones
// this prevents returning info on software renderer when actually we'll get the hardware one
while (info)
{
aglDescribeRenderer(info, AGL_ACCELERATED, &dAccel);
aglReportError ();
if (dAccel)
canAccel = true;
info = aglNextRendererInfo(info);
aglReportError ();
inum++;
}
info = head_info;
inum = 0;
while (info)
{
aglDescribeRenderer(info, AGL_ACCELERATED, &dAccel);
aglReportError ();
// if we can accel then we will choose the accelerated renderer
// how about compliant renderers???
if ((canAccel && dAccel) || (!canAccel && (!fAccelMust || dAccel)))
{
aglDescribeRenderer(info, AGL_VIDEO_MEMORY, &dVRAM); // we assume that VRAM returned is total thus add texture and VRAM required
aglReportError ();
if (dVRAM >= (*pVRAM + *pTextureRAM))
{
if (dVRAM >= dMaxVRAM) // find card with max VRAM
{
aglDescribeRenderer(info, AGL_DEPTH_MODES, pDepthSizeSupport); // which depth buffer modes are supported
aglReportError ();
dMaxVRAM = dVRAM; // store max
found = true;
}
}
}
info = aglNextRendererInfo(info);
aglReportError ();
inum++;
}
}
aglDestroyRendererInfo(head_info);
if (found) // if we found a card that has enough VRAM and meets the accel criteria
{
if (MinVRAM > dMaxVRAM)
MinVRAM = dMaxVRAM; // return VRAM
}
else
goodCheck = false; // one device failed thus entire requirement fails
hGD = GetNextDevice (hGD); // get next device
} // while
if (goodCheck) // we check all devices and each was good
{
*pVRAM = MinVRAM; // return VRAM
return true;
}
return false; //at least one device failed to have mins
}
//-----------------------------------------------------------------------------------------------------------------------
// CheckWindowExtents
// checks to see window fits on screen completely
// Inputs: hGD: GDHandle to device to look at
// width/height: requested width and height of window
// Returns: true if window and borders fit, false otherwise
static Boolean CheckWindowExtents (GDHandle hGD, short width, short height)
{
Rect strucRect, rectWin = {0, 0, 1, 1};
short deviceHeight = (short) ((**hGD).gdRect.bottom - (**hGD).gdRect.top - GetMBarHeight ());
short deviceWidth = (short) ((**hGD).gdRect.right - (**hGD).gdRect.left);
short windowWidthExtra, windowHeightExtra;
// build window (not visible)
WindowPtr pWindow = NewCWindow (NULL, &rectWin, "\p", true, kWindowType, (WindowPtr)-1, 0, 0);
#if !TARGET_API_MAC_CARBON
strucRect = (**(((WindowPeek)pWindow)->strucRgn)).rgnBBox;
#else
GetWindowBounds (pWindow, kWindowStructureRgn, &strucRect);
#endif
windowWidthExtra = (short) ((strucRect.right - strucRect.left) - 1);
windowHeightExtra = (short) ((strucRect.bottom - strucRect.top) - 1);
DisposeWindow (pWindow);
if ((width + windowWidthExtra <= deviceWidth) &&
(height + windowHeightExtra <= deviceHeight))
return true;
return false;
}
// --------------------------------------------------------------------------
// DumpCurrent
// Kills currently allocated context
// does not care about being pretty (assumes display is likely faded)
// Inputs: paglDraw, paglContext, pdspContext: things to be destroyed
void DumpCurrent (AGLDrawable* paglDraw, AGLContext* paglContext, DSpContextReference* pdspContext, pstructGLInfo pcontextInfo)
{
if (*pdspContext)
DSpReportError (DSpContext_CustomFadeGammaOut (NULL, NULL, fadeTicks));
if (*paglContext)
{
aglSetCurrentContext (NULL);
aglReportError ();
aglSetDrawable (*paglContext, NULL);
aglReportError ();
aglDestroyContext (*paglContext);
aglReportError ();
*paglContext = NULL;
}
if (pcontextInfo->fmt)
{
aglDestroyPixelFormat (pcontextInfo->fmt); // pixel format is no longer needed
aglReportError ();
}
pcontextInfo->fmt = 0;
if (*paglDraw && !(pcontextInfo->fFullscreen && CheckMacOSX ())) // do not destory a window on DSp if in Mac OS X
// since there is no window built in X
#if TARGET_API_MAC_CARBON
DisposeWindow (GetWindowFromPort (*paglDraw));
#else
DisposeWindow ((WindowPtr) *paglDraw);
#endif
*paglDraw = NULL;
DestroyDSpContext (pdspContext); // fades in, safe to call at all times
}
#pragma mark -
// --------------------------------------------------------------------------
// BuildGLContext
// Builds OpenGL context
// Inputs: hGD: GDHandle to device to look at
// pcontextInfo: request and requirements for cotext and drawable
// Outputs: paglContext as allocated
// pcontextInfo: allocated parameters
// if fail to allocate: paglContext will be NULL
// if error: will return error paglContext will be NULL
static OSStatus BuildGLContext (AGLDrawable* paglDraw, AGLContext* paglContext, DSpContextReference* pdspContext,
GDHandle hGD, pstructGLInfo pcontextInfo, AGLContext aglShareContext)
{
OSStatus err = noErr;
NumVersion versionDSp = GetDSpVersion ();
if ((Ptr) kUnresolvedCFragSymbolAddress == (Ptr) aglChoosePixelFormat) // check for existance of OpenGL
{
ReportError ("OpenGL not installed");
return noErr;
}
// DSp has problems on Mac OS X with DSp version less than 1.99 so use agl full screen
if ((pcontextInfo->fFullscreen) && (CheckMacOSX ()) && ((versionDSp.majorRev == 0x01) && (versionDSp.minorAndBugRev < 0x99))) // need to set pixel format for full screen
{
short i = 0;
while (pcontextInfo->aglAttributes[i++] != AGL_NONE) {}
i--; // point to AGL_NONE
pcontextInfo->aglAttributes [i++] = AGL_FULLSCREEN;
pcontextInfo->aglAttributes [i++] = AGL_PIXEL_SIZE;
pcontextInfo->aglAttributes [i++] = (SInt32) pcontextInfo->pixelDepth;
pcontextInfo->aglAttributes [i++] = AGL_NONE;
}
pcontextInfo->fmt = aglChoosePixelFormat (&hGD, 1, pcontextInfo->aglAttributes); // get an appropriate pixel format
aglReportError ();
if (NULL == pcontextInfo->fmt)
{
ReportError("Could not find valid pixel format");
return noErr;
}
// using a default method of sharing all the contexts enables texture sharing across these contexts by default
*paglContext = aglCreateContext (pcontextInfo->fmt, aglShareContext); // Create an AGL context
if (AGL_BAD_MATCH == aglGetError())
*paglContext = aglCreateContext (pcontextInfo->fmt, 0); // unable to sahre context, create without sharing
aglReportError ();
if (NULL == *paglContext)
{
ReportError ("Could not create context");
return paramErr;
}
if (aglShareContext == NULL)
aglShareContext = *paglContext;
// set our drawable
// DSp has problems on Mac OS X use DSp only when version is not less than 1.99
if ((pcontextInfo->fFullscreen) && (CheckMacOSX ()) && !((versionDSp.majorRev == 0x01) && (versionDSp.minorAndBugRev < 0x99))) // fullscreen X late DSp
{
// use DSp's front buffer on Mac OS X
*paglDraw = GetDSpDrawable (*pdspContext);
// 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
{
short deltaV, deltaH;
Rect portBounds;
#if TARGET_API_MAC_CARBON
PixMapHandle hPix = GetPortPixMap (*paglDraw);
Rect pixBounds = (**hPix).bounds;
GetPortBounds (*paglDraw, &portBounds);
#else
PixMapHandle hPix = (*paglDraw)->portPixMap;
Rect pixBounds = (**hPix).bounds;
portBounds = (*paglDraw)->portRect;
#endif
deltaV = (short) ((portBounds.bottom - portBounds.top) - (pixBounds.bottom - pixBounds.top) +
(portBounds.bottom - portBounds.top - pcontextInfo->height) / 2);
deltaH = (short) (-(portBounds.right - portBounds.left - pcontextInfo->width) / 2);
if (deltaV || deltaH)
{
GrafPtr pPortSave;
GetPort (&pPortSave);
SetPort ((GrafPtr)*paglDraw);
// set origin to account for CG offset and if requested drawable smaller than screen rez
SetOrigin (deltaH, deltaV);
SetPort (pPortSave);
}
}
if (!aglSetDrawable (*paglContext, *paglDraw)) // attach the CGrafPtr to the context
return aglReportError ();
}
// DSp has problems on Mac OS X with DSp version less than 1.99 so use agl full screen
else if ((pcontextInfo->fFullscreen) && (CheckMacOSX ()) && ((versionDSp.majorRev == 0x01) && (versionDSp.minorAndBugRev < 0x99))) // fulscreen X early DSp
{
// use aglFullScreen
short display = 0;
if (!aglSetFullScreen (*paglContext, pcontextInfo->width, pcontextInfo->height, 60, display)) // attach fulls screen device to the context
{
ReportError ("SetFullScreen failed");
aglReportError ();
return paramErr;
}
}
else // not Mac OS X fullscreen: this is for three cases 1) Mac OS 9 windowed 2) Mac OS X windowed 3) Mac OS 9 fullscreen (as you need to build a window on top of DSp for GL to work correctly
{
// build window as late as possible
err = BuildDrawable (paglDraw, hGD, pcontextInfo);
if (err != noErr)
{
ReportError ("Could not build drawable");
return err;
}
if (!aglSetDrawable (*paglContext, *paglDraw)) // attach the CGrafPtr to the context
return aglReportError ();
}
if(!aglSetCurrentContext (*paglContext)) // make the context the current context
return aglReportError ();
return err;
}
// --------------------------------------------------------------------------
// BuildDrawable
// Builds window to be used as drawable
// Inputs: hGD: GDHandle to device to look at
// pcontextInfo: request and requirements for cotext and drawable
// Outputs: paglDraw as allocated
// pcontextInfo: allocated parameters
// if fail to allocate: paglDraw will be NULL
// if error: will return error paglDraw will be NULL
static OSStatus BuildDrawable (AGLDrawable* paglDraw, GDHandle hGD, pstructGLInfo pcontextInfo)
{
Rect rectWin;
RGBColor rgbSave;
GrafPtr pGrafSave;
OSStatus err = noErr;
// center window in our context's gdevice
rectWin.top = (short) ((**hGD).gdRect.top + ((**hGD).gdRect.bottom - (**hGD).gdRect.top) / 2); // v center
rectWin.top -= pcontextInfo->height / 2;
rectWin.left = (short) ((**hGD).gdRect.left + ((**hGD).gdRect.right - (**hGD).gdRect.left) / 2); // h center
rectWin.left -= pcontextInfo->width / 2;
rectWin.right = (short) (rectWin.left + pcontextInfo->width);
rectWin.bottom = (short) (rectWin.top + pcontextInfo->height);
#if TARGET_API_MAC_CARBON
if (pcontextInfo->fFullscreen)
*paglDraw = GetWindowPort (NewCWindow (NULL, &rectWin, "\p", 0, plainDBox, (WindowPtr)-1, 0, 0));
else
*paglDraw = GetWindowPort (NewCWindow (NULL, &rectWin, "\p", 0, kWindowType, (WindowPtr)-1, 0, 0));
ShowWindow (GetWindowFromPort (*paglDraw));
#else
if (pcontextInfo->fFullscreen)
*paglDraw = (AGLDrawable) NewCWindow (NULL, &rectWin, "\p", 0, plainDBox, (WindowPtr)-1, 0, 0);
else
*paglDraw = (AGLDrawable) NewCWindow (NULL, &rectWin, "\p", 0, kWindowType, (WindowPtr)-1, 0, 0);
ShowWindow ((WindowPtr) *paglDraw);
#endif
GetPort (&pGrafSave);
SetPort ((GrafPtr)*paglDraw);
GetForeColor (&rgbSave);
RGBForeColor (&rgbBlack);
#if TARGET_API_MAC_CARBON
GetWindowBounds (GetWindowFromPort (*paglDraw), kWindowContentRgn, &rectWin);
#else
rectWin = ((GrafPtr) *paglDraw)->portRect;
#endif
PaintRect (&rectWin);
RGBForeColor (&rgbSave); // ensure color is reset for proper blitting
SetPort (pGrafSave);
return err;
}
// --------------------------------------------------------------------------
// BuildGLonDevice
// Takes device single device and tries to build on it
// Inputs: hGD: GDHandle to device to look at
// *pcontextInfo: request and requirements for cotext and drawable
// Outputs: *paglDraw, *paglContext and *pdspContext as allocated
// *pcontextInfo: allocated parameters
// if fail to allocate: paglDraw, paglContext and pdspContext will be NULL
// if error: will return error and paglDraw, paglContext and pdspContext will be NULL
// Note: *paglDraw and *pdspContext can be null is aglFullScreen is used
static OSStatus BuildGLonDevice (AGLDrawable* paglDraw, AGLContext* paglContext, DSpContextReference* pdspContext,
GDHandle hGD, pstructGLInfo pcontextInfo, AGLContext aglShareContext)
{
GLint depthSizeSupport;
OSStatus err = noErr;
Boolean fCheckRenderer = false;
NumVersion versionDSp = GetDSpVersion ();
if (pcontextInfo->fFullscreen)
{
// if we are in 16 or 32 bit mode already, we can check the renderer now (we will double check later)
if (16 <= (**(**hGD).gdPMap).pixelSize)
{
// check for VRAM and accelerated
if (!CheckRenderer (hGD, &(pcontextInfo->VRAM), &(pcontextInfo->textureRAM), &depthSizeSupport, pcontextInfo->fAcceleratedMust))
{
ReportError ("Renderer check failed");
return err;
}
else
fCheckRenderer = true;
}
// only for Mac OS 9 or less and greater than Mac OS X 10.0.2
// DSp has problems on Mac OS X with DSp version less than 1.99 (10.0.2 or less)
if ((!CheckMacOSX ()) || ((versionDSp.majorRev > 0x01) || ((versionDSp.majorRev == 0x01) && (versionDSp.minorAndBugRev >= 0x99)))) // DSp should be supported in version after 1.98
{
err = BuildDSpContext (pdspContext, hGD, depthSizeSupport, pcontextInfo);
// we are now faded
if ((err != noErr) || (*pdspContext == NULL))
{
if (err != noErr)
ReportErrorNum ("BuildDSpContext failed with error:", err);
else
ReportError ("Could not build DrawSprocket context");
if (*pdspContext)
DSpReportError (DSpContext_CustomFadeGammaIn (NULL, NULL, fadeTicks));
return err;
}
}
// else we are using aglFullScreen and no DSp work is required
}
else
{
if (pcontextInfo->pixelDepth == 0) // default
{
pcontextInfo->pixelDepth = (**(**hGD).gdPMap).pixelSize;
if (16 > pcontextInfo->pixelDepth)
pcontextInfo->pixelDepth = 16;
}
if (pcontextInfo->fDepthMust && (pcontextInfo->pixelDepth != (**(**hGD).gdPMap).pixelSize)) // device depth must match and does not
{
ReportError ("Pixel Depth does not match device in windowed mode.");
if (*pdspContext)
DSpReportError (DSpContext_CustomFadeGammaIn (NULL, NULL, fadeTicks));
return err;
}
// copy back the curretn depth
pcontextInfo->pixelDepth = (**(**hGD).gdPMap).pixelSize;
if (!CheckWindowExtents (hGD, pcontextInfo->width, pcontextInfo->height))
{
ReportError ("Window will not fit on device in windowed mode.");
if (*pdspContext)
DSpReportError (DSpContext_CustomFadeGammaIn (NULL, NULL, fadeTicks));
return err;
}
}
// if we have not already checked the renderer, check for VRAM and accelerated
if (!fCheckRenderer)
if (!CheckRenderer (hGD, &(pcontextInfo->VRAM), &(pcontextInfo->textureRAM), &depthSizeSupport, pcontextInfo->fAcceleratedMust))
{
ReportError ("Renderer check failed");
if (*pdspContext)
DSpReportError (DSpContext_CustomFadeGammaIn (NULL, NULL, fadeTicks));
return err;
}
// do agl
// need to send device #'s through this
err = BuildGLContext (paglDraw, paglContext, pdspContext, hGD, pcontextInfo, aglShareContext);
// DSp has problems on Mac OS X with DSp version less than 1.99
if ((!CheckMacOSX ()) || ((versionDSp.majorRev > 0x01) || ((versionDSp.majorRev == 0x01) && (versionDSp.minorAndBugRev >= 0x99))))// DSp should be supported in version after 1.98
{
if (*pdspContext)
DSpReportError (DSpContext_CustomFadeGammaIn (NULL, NULL, fadeTicks));
}
return err;
}
// --------------------------------------------------------------------------
// BuildGLonDrawable
// Takes a drawable and tries to build on it
// Inputs: aglDraw: a valid AGLDrawable
// *pcontextInfo: request and requirements for cotext and drawable
// Outputs: *paglContext as allocated
// *pcontextInfo: allocated parameters
// if fail to allocate: paglContext will be NULL
// if error: will return error and paglContext will be NULL
static OSStatus BuildGLonWindow (WindowPtr pWindow, AGLContext* paglContext, pstructGLWindowInfo pcontextInfo, AGLContext aglShareContext)
{
GDHandle hGD = NULL;
GrafPtr cgrafSave = NULL;
short numDevices;
GLint depthSizeSupport;
OSStatus err = noErr;
if (!pWindow || !pcontextInfo)
{
ReportError ("NULL parameter passed to BuildGLonDrawable.");
return paramErr;
}
GetPort (&cgrafSave);
SetPortWindowPort(pWindow);
// check renderere VRAM and acceleration
numDevices = FindGDHandleFromWindow (pWindow, &hGD);
if (!pcontextInfo->fDraggable) // if numDevices > 1 then we will only be using the software renderer otherwise check only window device
{
if ((numDevices > 1) || (numDevices == 0)) // this window spans mulitple devices thus will be software only
{
// software renderer
// infinite VRAM, infinite textureRAM, not accelerated
if (pcontextInfo->fAcceleratedMust)
{
ReportError ("Unable to accelerate window that spans multiple devices");
return err;
}
}
else // not draggable on single device
{
if (!CheckRenderer (hGD, &(pcontextInfo->VRAM), &(pcontextInfo->textureRAM), &depthSizeSupport, pcontextInfo->fAcceleratedMust))
{
ReportError ("Renderer check failed");
return err;
}
}
}
// else draggable so must check all for support (each device should have at least one renderer that meets the requirements)
else if (!CheckAllDeviceRenderers (&(pcontextInfo->VRAM), &(pcontextInfo->textureRAM), &depthSizeSupport, pcontextInfo->fAcceleratedMust))
{
ReportError ("Renderer check failed");
return err;
}
// do agl
if ((Ptr) kUnresolvedCFragSymbolAddress == (Ptr) aglChoosePixelFormat) // check for existance of OpenGL
{
ReportError ("OpenGL not installed");
return NULL;
}
// we successfully passed the renderer check
if ((!pcontextInfo->fDraggable && (numDevices == 1))) // not draggable on a single device
pcontextInfo->fmt = aglChoosePixelFormat (&hGD, 1, pcontextInfo->aglAttributes); // get an appropriate pixel format
else
pcontextInfo->fmt = aglChoosePixelFormat (NULL, 0, pcontextInfo->aglAttributes); // get an appropriate pixel format
aglReportError ();
if (NULL == pcontextInfo->fmt)
{
ReportError("Could not find valid pixel format");
return NULL;
}
*paglContext = aglCreateContext (pcontextInfo->fmt, aglShareContext); // Create an AGL context
if (AGL_BAD_MATCH == aglGetError())
*paglContext = aglCreateContext (pcontextInfo->fmt, 0); // unable to sahre context, create without sharing
aglReportError ();
if (NULL == *paglContext)
{
ReportError ("Could not create context");
return NULL;
}
if (!aglSetDrawable (*paglContext, GetWindowPort (pWindow))) // attach the CGrafPtr to the context
return aglReportError ();
if(!aglSetCurrentContext (*paglContext)) // make the context the current context
return aglReportError ();
SetPort (cgrafSave);
return err;
}
#pragma mark -
// functions (public) -------------------------------------------------------
// CheckMacOSX
// Runtime check to see if we are running on Mac OS X
// Inputs: None
// Returns: 0 if < Mac OS X or version number of Mac OS X (10.0 for GM)
UInt32 CheckMacOSX (void)
{
UInt32 response;
if ((Gestalt(gestaltSystemVersion, (SInt32 *) &response) == noErr) && (response >= 0x01000))
return response;
else
return 0;
}
// --------------------------------------------------------------------------
// PreflightGL
// Checks for presense of OpenGL and DSp (if required)
// Inputs: checkFullscreen: true if one wants to run fullscreen (which requires DrwSprocket currently)
// Ouputs: true if OpenGL is installed (and DrawSprocket if checkFullscreen is true
Boolean PreflightGL (Boolean checkFullscreen)
{
if ((Ptr) kUnresolvedCFragSymbolAddress == (Ptr) aglChoosePixelFormat) // check for existance of OpenGL
return false;
if (checkFullscreen && ((Ptr) kUnresolvedCFragSymbolAddress == (Ptr) DSpStartup)) // check for existance of DSp
return false;
return true;
}
// --------------------------------------------------------------------------
// BuildGL
// Takes device and geometry request and tries to build best context and drawable
// if device does not work will walk down devices looking for first one that satisfies requirments
// Inputs: *pnumDevice: 0 any device, # attempt that device first, then any device
// *pcontextInfo: request and requirements for cotext and drawable
// Outputs: *paglDraw, *paglContext and *pdspContext as allocated
// *pnumDevice to device number in list that was used
// *pcontextInfo: allocated parameters
// if fail to allocate: paglDraw, paglContext and pdspContext will be NULL
// if error: will return error and paglDraw, paglContext and pdspContext will be NULL
OSStatus BuildGL (AGLDrawable* paglDraw, AGLContext* paglContext, DSpContextReference* pdspContext,
short* pnumDevice, pstructGLInfo pcontextInfo, AGLContext aglShareContext)
{
OSStatus err = noErr;
GDHandle hGD = NULL;
structGLInfo contextInfoSave;
// clear
*paglDraw = NULL;
*paglContext = 0;
*pdspContext = 0;
contextInfoSave = *pcontextInfo; // save info to reset on failures
// if we are full screen and not on Mac OS X (which will use aglFullScreen)
if (pcontextInfo->fFullscreen)
{
NumVersion versionDSp = GetDSpVersion ();
// DSp has problems on Mac OS X with DSp version less than 1.99
if ((!CheckMacOSX ()) || ((versionDSp.majorRev > 0x01) || ((versionDSp.majorRev == 0x01) && (versionDSp.minorAndBugRev >= 0x99))))// DSp should be supported in version after 1.98
{
err = StartDSp ();
if (gDSpStarted)
gNeedFade = true;
else
return err;
}
}
//find main device
if (*pnumDevice == -1)
{
GDHandle hDevice; // check number of screens
hGD = GetMainDevice ();
if (NULL != hGD)
{
err = BuildGLonDevice (paglDraw, paglContext, pdspContext, hGD, pcontextInfo, aglShareContext);
// find device number
*pnumDevice = 0;
hDevice = DMGetFirstScreenDevice (true);
do
{
if (hDevice == hGD)
break;
hDevice = DMGetNextScreenDevice (hDevice, true);
(*pnumDevice)++;
}
while (hDevice);
if (!hDevice)
ReportError ("main device match not found");
}
else
ReportError ("Cannot get main device");
}
if ((err != noErr) || (*paglContext == 0))
{
err = noErr;
DumpCurrent (paglDraw, paglContext, pdspContext, pcontextInfo); // dump what ever partial solution we might have
*pcontextInfo = contextInfoSave; // restore info
//find target device and check this first is one exists
if (*pnumDevice)
{
short i;
hGD = DMGetFirstScreenDevice (true);
for (i = 0; i < *pnumDevice; i++)
{
GDHandle hGDNext = DMGetNextScreenDevice (hGD, true);
if (NULL == hGDNext) // ensure we did not run out of devices
break; // if no more devices drop out
else
hGD = hGDNext; // otherwise continue
}
*pnumDevice = i; // record device we actually got
err = BuildGLonDevice (paglDraw, paglContext, pdspContext, hGD, pcontextInfo, aglShareContext);
}
}
// while we have not allocated a context or there were errors
if ((err != noErr) || (*paglContext == 0))
{
err = noErr;
DumpCurrent (paglDraw, paglContext, pdspContext, pcontextInfo); // dump what ever partial solution we might have
*pcontextInfo = contextInfoSave; // restore info
// now look through the devices in order
hGD = DMGetFirstScreenDevice (true);
*pnumDevice = -1;
do
{
(*pnumDevice)++;
err = BuildGLonDevice (paglDraw, paglContext, pdspContext, hGD, pcontextInfo, aglShareContext);
if ((err != noErr) || (*paglDraw == NULL) || (*paglContext == 0)) // reset hGD only if we are not done
{
hGD = DMGetNextScreenDevice (hGD, true);
DumpCurrent (paglDraw, paglContext, pdspContext, pcontextInfo); // dump what ever partial solution we might have
*pcontextInfo = contextInfoSave; // restore info
}
}
while (((err != noErr) || (*paglContext == 0)) && hGD);
}
return err;
}
// --------------------------------------------------------------------------
// DestroyGL
// Destroys drawable and context
// Ouputs: *paglDraw, *paglContext and *pdspContext should be 0 on exit
OSStatus DestroyGL (AGLDrawable* paglDraw, AGLContext* paglContext, DSpContextReference* pdspContext, pstructGLInfo pcontextInfo)
{
if ((!paglContext) || (!*paglContext))
return paramErr; // not a valid context
glFinish ();
DumpCurrent (paglDraw, paglContext, pdspContext, pcontextInfo);
ShutdownDSp (); // safe to call anytime
return noErr;
}
//-----------------------------------------------------------------------------------------------------------------------
// BuildGLFromWindow
// Takes window in the form of an AGLDrawable and geometry request and tries to build best context
// Inputs: aglDraw: a valid AGLDrawable (i.e., a WindowPtr)
// *pcontextInfo: request and requirements for cotext and drawable
// Outputs: *paglContext as allocated
// *pcontextInfo: allocated parameters
// if fail to allocate: paglContext will be NULL
// if error: will return error and paglContext will be NULL
OSStatus BuildGLFromWindow (WindowPtr pWindow, AGLContext* paglContext, pstructGLWindowInfo pcontextInfo, AGLContext aglShareContext)
{
if (!pWindow)
return paramErr;
return BuildGLonWindow (pWindow, paglContext, pcontextInfo, aglShareContext);
}
// --------------------------------------------------------------------------
// DestroyGLFromWindow
// Destroys context that waas allocated with BuildGLFromWindow
// Ouputs: *paglContext should be NULL on exit
OSStatus DestroyGLFromWindow (AGLContext* paglContext, pstructGLWindowInfo pcontextInfo)
{
OSStatus err;
if ((!paglContext) || (!*paglContext))
return paramErr; // not a valid context
glFinish ();
aglSetCurrentContext (NULL);
err = aglReportError ();
aglSetDrawable (*paglContext, NULL);
err = aglReportError ();
aglDestroyContext (*paglContext);
err = aglReportError ();
*paglContext = NULL;
if (pcontextInfo->fmt)
{
aglDestroyPixelFormat (pcontextInfo->fmt); // pixel format is no longer valid
err = aglReportError ();
}
pcontextInfo->fmt = 0;
return err;
}
//-----------------------------------------------------------------------------------------------------------------------
// SuspendFullScreenGL
// Special suspend function to ensure the the GL window is hidden
// needs to be reviewed
OSStatus SuspendFullScreenGL (AGLDrawable aglDraw, AGLContext aglContext)
{
if (aglDraw && aglContext) // will only have a drawable
{
glFinish (); // must do this to ensure the queue is complete
aglSetCurrentContext (NULL);
#if TARGET_API_MAC_CARBON
HideWindow (GetWindowFromPort (aglDraw));
#else
HideWindow ((WindowPtr) aglDraw);
#endif
return aglReportError ();
}
return noErr;
}
//-----------------------------------------------------------------------------------------------------------------------
// ResumeFullScreenGL
// Needs a special resume function to ensure the the GL window is shown
// needs to be reviewed
OSStatus ResumeFullScreenGL (AGLDrawable aglDraw, AGLContext aglContext)
{
if (aglDraw && aglContext)
{
#if TARGET_API_MAC_CARBON
ShowWindow (GetWindowFromPort (aglDraw));
#else
ShowWindow ((WindowPtr) aglDraw);
#endif
aglSetCurrentContext (aglContext);
aglUpdateContext (aglContext);
return aglReportError ();
}
return paramErr;
}
//-----------------------------------------------------------------------------------------------------------------------
// PauseGL
// Pauses gl to allow toolbox drawing
OSStatus PauseGL (AGLContext aglContext)
{
if (aglContext)
{
glFinish (); // must do this to ensure the queue is complete
aglSetCurrentContext (NULL);
return aglReportError ();
}
return paramErr;
}
//-----------------------------------------------------------------------------------------------------------------------
// ResumeGL
// resumes gl to allow gl drawing
OSStatus ResumeGL (AGLContext aglContext)
{
if (aglContext)
{
aglSetCurrentContext (aglContext);
aglUpdateContext (aglContext);
return aglReportError ();
}
return paramErr;
}
// --------------------------------------------------------------------------
// FindGDHandleFromRect
// Inputs: a global Rect
// Outputs: the GDHandle that that Rect is mostly on
// returns the number of devices that the Rect touches
short FindGDHandleFromRect (Rect * pRect, GDHandle * phgdOnThisDevice)
{
Rect rectSect;
long greatestArea, sectArea;
short numDevices = 0;
GDHandle hgdNthDevice;
if (!phgdOnThisDevice)
return NULL;
*phgdOnThisDevice = NULL;
hgdNthDevice = GetDeviceList ();
greatestArea = 0;
// check window against all gdRects in gDevice list and remember
// which gdRect contains largest area of window}
while (hgdNthDevice)
{
if (TestDeviceAttribute (hgdNthDevice, screenDevice))
if (TestDeviceAttribute (hgdNthDevice, screenActive))
{
// The SectRect routine calculates the intersection
// of the window rectangle and this gDevice
// rectangle and returns TRUE if the rectangles intersect,
// FALSE if they don't.
SectRect (pRect, &(**hgdNthDevice).gdRect, &rectSect);
// determine which screen holds greatest window area
// first, calculate area of rectangle on current device
sectArea = (long) (rectSect.right - rectSect.left) * (rectSect.bottom - rectSect.top);
if (sectArea > 0)
numDevices++;
if (sectArea > greatestArea)
{
greatestArea = sectArea; // set greatest area so far
*phgdOnThisDevice = hgdNthDevice; // set zoom device
}
hgdNthDevice = GetNextDevice(hgdNthDevice);
}
}
return numDevices;
}
// --------------------------------------------------------------------------
// GetWindowDevice
// Inputs: a valid WindowPtr
// Outputs: the GDHandle that that window is mostly on
// returns the number of devices that the windows content touches
short FindGDHandleFromWindow (WindowPtr pWindow, GDHandle * phgdOnThisDevice)
{
GrafPtr pgpSave;
Rect rectWind, rectSect;
long greatestArea, sectArea;
short numDevices = 0;
GDHandle hgdNthDevice;
if (!pWindow || !phgdOnThisDevice)
return NULL;
*phgdOnThisDevice = NULL;
GetPort (&pgpSave);
SetPortWindowPort (pWindow);
#if TARGET_API_MAC_CARBON
GetWindowPortBounds (pWindow, &rectWind);
#else
rectWind = pWindow->portRect;
#endif // TARGET_API_MAC_CARBON
LocalToGlobal ((Point*)& rectWind.top); // convert to global coordinates
LocalToGlobal ((Point*)& rectWind.bottom);
hgdNthDevice = GetDeviceList ();
greatestArea = 0;
// check window against all gdRects in gDevice list and remember
// which gdRect contains largest area of window}
while (hgdNthDevice)
{
if (TestDeviceAttribute (hgdNthDevice, screenDevice))
if (TestDeviceAttribute (hgdNthDevice, screenActive))
{
// The SectRect routine calculates the intersection
// of the window rectangle and this gDevice
// rectangle and returns TRUE if the rectangles intersect,
// FALSE if they don't.
SectRect (&rectWind, &(**hgdNthDevice).gdRect, &rectSect);
// determine which screen holds greatest window area
// first, calculate area of rectangle on current device
sectArea = (long) (rectSect.right - rectSect.left) * (rectSect.bottom - rectSect.top);
if (sectArea > 0)
numDevices++;
if (sectArea > greatestArea)
{
greatestArea = sectArea; // set greatest area so far
*phgdOnThisDevice = hgdNthDevice; // set zoom device
}
hgdNthDevice = GetNextDevice(hgdNthDevice);
}
}
SetPort (pgpSave);
return numDevices;
}
//-----------------------------------------------------------------------------------------------------------------------
// FindDeviceNumFromRect
// returns the number of the device that the point is on (i.e., where it is in the search order)
// just a ultility to find the number of the device from a point
short FindDeviceNumFromRect (Rect * pRect)
{
short displayNum = 0;
GDHandle hgdNthDevice, hgdFoundDevice;
FindGDHandleFromRect (pRect, &hgdFoundDevice);
hgdNthDevice = DMGetFirstScreenDevice (true);
while (hgdNthDevice)
{
if (hgdFoundDevice == hgdNthDevice)
break;
hgdNthDevice = DMGetNextScreenDevice(hgdNthDevice, true);
displayNum++;
} // of WHILE
return displayNum;
}