mirror of https://github.com/BOINC/boinc.git
1380 lines
50 KiB
C
Executable File
1380 lines
50 KiB
C
Executable File
// The contents of this file are subject to the Mozilla Public License
|
|
// Version 1.0 (the "License"); you may not use this file except in
|
|
// compliance with the License. You may obtain a copy of the License at
|
|
// http://www.mozilla.org/MPL/
|
|
//
|
|
// Software distributed under the License is distributed on an "AS IS"
|
|
// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
|
// License for the specific language governing rights and limitations
|
|
// under the License.
|
|
//
|
|
// The Original Code is the Berkeley Open Infrastructure for Network Computing.
|
|
//
|
|
// The Initial Developer of the Original Code is the SETI@home project.
|
|
// Portions created by the SETI@home project are Copyright (C) 2002
|
|
// University of California at Berkeley. All Rights Reserved.
|
|
//
|
|
// Contributor(s):
|
|
//
|
|
|
|
|
|
/*
|
|
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.
|
|
|
|
Adapted to BOINC by Eric Heien
|
|
*/
|
|
|
|
// system includes ----------------------------------------------------------
|
|
|
|
#ifdef __APPLE_CC__
|
|
#include <Carbon/Carbon.h>
|
|
#include <AGL/agl.h>
|
|
#else
|
|
#include <Gestalt.h>
|
|
#include <sound.h>
|
|
#include <MacTypes.h>
|
|
#include <DriverServices.h>
|
|
#include <Timer.h>
|
|
#include <Math64.h>
|
|
#include <agl.h>
|
|
#include <gl.h>
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
|
|
// project includes ---------------------------------------------------------
|
|
|
|
#include "mac_carbon_dsp.h"
|
|
#include "mac_carbon_gl.h"
|
|
|
|
extern WindowRef appGLWindow;
|
|
|
|
// 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);
|
|
|
|
|
|
extern void drawGL(WindowPtr pWindow);
|
|
|
|
|
|
// 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);
|
|
|
|
GetWindowBounds (pWindow, kWindowStructureRgn, &strucRect);
|
|
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
|
|
DisposeWindow (GetWindowFromPort (*paglDraw));
|
|
*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;
|
|
PixMapHandle hPix = GetPortPixMap (*paglDraw);
|
|
Rect pixBounds = (**hPix).bounds;
|
|
GetPortBounds (*paglDraw, &portBounds);
|
|
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 (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));
|
|
GetPort (&pGrafSave);
|
|
SetPort ((GrafPtr)*paglDraw);
|
|
GetForeColor (&rgbSave);
|
|
RGBForeColor (&rgbBlack);
|
|
GetWindowBounds (GetWindowFromPort (*paglDraw), kWindowContentRgn, &rectWin);
|
|
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 renderer 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);
|
|
HideWindow (GetWindowFromPort (aglDraw));
|
|
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)
|
|
{
|
|
ShowWindow (GetWindowFromPort (aglDraw));
|
|
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);
|
|
|
|
GetWindowPortBounds (pWindow, &rectWind);
|
|
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;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------------------------------------
|
|
|
|
// Draw frame rate in current color at current raster positon with provided font display list
|
|
// This version handles multiple windows, thus the calling code must track the values of frames and time from call to call
|
|
// The application needs to maintain a cstring (32 characters should be fine), frame counter and time for each window,
|
|
// but this routine will take care of all updates.
|
|
|
|
void MultiWinDrawFrameRate (GLuint fontList, char * cString, long * frames, AbsoluteTime * time)
|
|
{
|
|
AbsoluteTime currTime = UpTime ();
|
|
float deltaTime = (float) AbsoluteDeltaToDuration (currTime, *time);
|
|
if (0 > deltaTime) // if negative microseconds
|
|
deltaTime /= -1000000.0;
|
|
else // else milliseconds
|
|
deltaTime /= 1000.0;
|
|
|
|
(*frames)++;
|
|
|
|
if (0.5 <= deltaTime) // has update interval passed
|
|
{
|
|
sprintf (cString, "FPS: %0.1f", (float) *frames / deltaTime);
|
|
*time = currTime; // reset for next time interval
|
|
*frames = 0;
|
|
}
|
|
|
|
DrawCStringGL (cString, fontList);
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
//-----------------------------------------------------------------------------------------------------------------------
|
|
|
|
void DrawCStringGL (char * cstrOut, GLuint fontList)
|
|
{
|
|
GLint i = 0;
|
|
while (cstrOut [i])
|
|
glCallList (fontList + cstrOut[i++]);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------------------------------------
|
|
|
|
GLuint BuildFontGL (AGLContext ctx, GLint fontID, Style face, GLint size)
|
|
{
|
|
GLuint listBase = glGenLists (256);
|
|
if (aglUseFont (ctx, fontID , face, size, 0, 256, (long) listBase))
|
|
{
|
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
|
return listBase;
|
|
}
|
|
else
|
|
{
|
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
|
glDeleteLists (listBase, 256);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------------------------------------
|
|
|
|
void DeleteFontGL (GLuint fontList)
|
|
{
|
|
if (fontList)
|
|
glDeleteLists (fontList, 256);
|
|
}
|
|
|
|
#pragma mark -
|
|
// --------------------------------------------------------------------------
|
|
|
|
// central error reporting
|
|
|
|
void ReportErrorNum (char * strError, long numError)
|
|
{
|
|
fprintf (stderr, "%s %ld (0x%lx)\n", strError, numError, numError);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
void ReportError (char * strError)
|
|
{
|
|
fprintf (stderr, "%s\n", strError);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------------------------------------
|
|
|
|
OSStatus DSpReportError (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
|
|
|
|
OSStatus aglReportError (void)
|
|
{
|
|
GLenum err = aglGetError();
|
|
if (AGL_NO_ERROR != err)
|
|
ReportError ((char *)aglErrorString(err));
|
|
// ensure we are returning an OSStatus noErr if no error condition
|
|
if (err == AGL_NO_ERROR)
|
|
return noErr;
|
|
else
|
|
return (OSStatus) err;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------------------------------------
|
|
|
|
// if error dump gl errors to debugger string, return error
|
|
|
|
OSStatus glReportError (void)
|
|
{
|
|
GLenum err = glGetError();
|
|
switch (err)
|
|
{
|
|
case GL_NO_ERROR:
|
|
break;
|
|
case GL_INVALID_ENUM:
|
|
ReportError ("GL Error: Invalid enumeration");
|
|
break;
|
|
case GL_INVALID_VALUE:
|
|
ReportError ("GL Error: Invalid value");
|
|
break;
|
|
case GL_INVALID_OPERATION:
|
|
ReportError ("GL Error: Invalid operation");
|
|
break;
|
|
case GL_STACK_OVERFLOW:
|
|
ReportError ("GL Error: Stack overflow");
|
|
break;
|
|
case GL_STACK_UNDERFLOW:
|
|
ReportError ("GL Error: Stack underflow");
|
|
break;
|
|
case GL_OUT_OF_MEMORY:
|
|
ReportError ("GL Error: Out of memory");
|
|
break;
|
|
}
|
|
// ensure we are returning an OSStatus noErr if no error condition
|
|
if (err == GL_NO_ERROR)
|
|
return noErr;
|
|
else
|
|
return (OSStatus) err;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
void DoUpdate (AGLContext aglContext)
|
|
{
|
|
if (aglContext)
|
|
{
|
|
aglSetCurrentContext (aglContext);
|
|
aglUpdateContext (aglContext);
|
|
|
|
drawGL (appGLWindow);
|
|
|
|
aglSwapBuffers(aglContext); // send swap command
|
|
}
|
|
}
|
|
|