mirror of https://github.com/BOINC/boinc.git
541 lines
17 KiB
C++
Executable File
541 lines
17 KiB
C++
Executable File
// The contents of this file are subject to the BOINC 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://boinc.berkeley.edu/license_1.0.txt
|
|
//
|
|
// 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
|
|
|
|
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 <AGL/agl.h>
|
|
#else
|
|
#include <Gestalt.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_gl.h"
|
|
#include "graphics_api.h"
|
|
#include "mac_app_opengl.h"
|
|
#include "util.h"
|
|
|
|
extern WindowRef appGLWindow;
|
|
|
|
// --------------------------------------------------------------------------
|
|
// BuildGLonWindow
|
|
// Takes a window 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
|
|
|
|
OSStatus BuildGLonWindow (WindowPtr pWindow, AGLContext* paglContext, pstructGLWindowInfo pcontextInfo)
|
|
{
|
|
GDHandle hGD = NULL;
|
|
GrafPtr cgrafSave = NULL;
|
|
short numDevices;
|
|
OSStatus err = noErr;
|
|
|
|
GetPort (&cgrafSave);
|
|
SetPortWindowPort(pWindow);
|
|
|
|
// check renderer VRAM and acceleration
|
|
numDevices = FindGDHandleFromWindow (pWindow, &hGD);
|
|
|
|
// do agl
|
|
if ((Ptr) kUnresolvedCFragSymbolAddress == (Ptr) aglChoosePixelFormat) { // check for existance of OpenGL
|
|
ReportError ("OpenGL not installed");
|
|
return NULL;
|
|
}
|
|
// we successfully passed the renderer check
|
|
|
|
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, NULL); // Create an AGL context
|
|
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) -------------------------------------------------------
|
|
// 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;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// 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;
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
//-----------------------------------------------------------------------------------------------------------------------
|
|
|
|
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)
|
|
{
|
|
Rect portRect;
|
|
int width, height;
|
|
|
|
if (aglContext)
|
|
{
|
|
aglSetCurrentContext (aglContext);
|
|
aglUpdateContext (aglContext);
|
|
|
|
GetWindowBounds( appGLWindow, kWindowContentRgn, &portRect );
|
|
width = portRect.right - portRect.left;
|
|
height = portRect.bottom - portRect.top;
|
|
ReSizeGLScene(width,height);
|
|
app_render(width, height, time(0)); // Here's Where We Do All The Drawing
|
|
|
|
aglSwapBuffers(aglContext); // send swap command
|
|
}
|
|
}
|
|
|
|
/*
|
|
Contains: Functions to enable building and destroying a DSp fullscreen context
|
|
|
|
*/
|
|
|
|
// globals (internal/private) -----------------------------------------------
|
|
|
|
Boolean gDSpStarted = false; // will never be true unless DSp is installed and start succeeds
|
|
|
|
// functions (public) -------------------------------------------------------
|
|
// StartDSp
|
|
// handles starting up DrawSprocket
|
|
|
|
OSStatus StartDSp (void)
|
|
{
|
|
OSStatus err = noErr;
|
|
if (!gDSpStarted) {
|
|
// check for DSp
|
|
if ((Ptr) kUnresolvedCFragSymbolAddress == (Ptr) DSpStartup) {
|
|
ReportError ("DSp not installed");
|
|
return kDSpNotInitializedErr;
|
|
} else {
|
|
err = DSpReportError (DSpStartup()); // start DSp
|
|
if (noErr != err)
|
|
return err;
|
|
else
|
|
gDSpStarted = true;
|
|
}
|
|
}
|
|
return err;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// ShutdownDSpContext
|
|
// shuts down DrawSprocket
|
|
|
|
void ShutdownDSp (void)
|
|
{
|
|
if (gDSpStarted) {
|
|
DSpShutdown ();
|
|
gDSpStarted = false;
|
|
}
|
|
}
|
|
|
|
#pragma mark -
|
|
// --------------------------------------------------------------------------
|
|
// GetDSpDrawable
|
|
// Just returns the front buffer
|
|
// Inputs: *pdspContext
|
|
// pcontextInfo: request and requirements for cotext and drawable
|
|
// Outputs: returns CGrafPtr thaat is front buffer of context
|
|
// if error: will return NULL
|
|
|
|
CGrafPtr GetDSpDrawable (DSpContextReference dspContext)
|
|
{
|
|
CGrafPtr pCGraf = NULL;
|
|
if (noErr == DSpReportError (DSpContext_GetFrontBuffer (dspContext, &pCGraf)))
|
|
return pCGraf;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------------------------------------
|
|
|
|
// Deactivates and dumps context
|
|
|
|
void DestroyDSpContext (DSpContextReference* pdspContext)
|
|
{
|
|
if (gDSpStarted) {
|
|
if (*pdspContext) {
|
|
DSpReportError (DSpContext_SetState(*pdspContext, kDSpContextState_Inactive));
|
|
DSpReportError (DSpContext_CustomFadeGammaIn (NULL, fadeTicks));
|
|
DSpReportError (DSpContext_Release (*pdspContext));
|
|
*pdspContext = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
#pragma mark -
|
|
//-----------------------------------------------------------------------------------------------------------------------
|
|
|
|
OSStatus DSpContext_CustomFadeGammaIn (DSpContextReference inContext, long fadeTicks)
|
|
{
|
|
OSStatus err = noErr;
|
|
RGBColor inZeroIntensityColor;
|
|
UInt32 currTick;
|
|
UInt16 step = (UInt16) (800 / fadeTicks);
|
|
long x, percent = 0;
|
|
|
|
if (gDSpStarted)
|
|
{
|
|
if (fadeTicks == 0)
|
|
fadeTicks = 1;
|
|
inZeroIntensityColor.red = 0x0000;
|
|
inZeroIntensityColor.green = 0x0000;
|
|
inZeroIntensityColor.blue = 0x0000;
|
|
currTick = TickCount ();
|
|
for (x = 1; x <= fadeTicks; x++)
|
|
{
|
|
percent = step * x / 8;
|
|
err = DSpContext_FadeGamma(inContext, percent, &inZeroIntensityColor);
|
|
if (err != noErr) break;
|
|
while (currTick >= TickCount ()) {}
|
|
currTick = TickCount ();
|
|
}
|
|
if (err == noErr)
|
|
err = DSpContext_FadeGamma(inContext, 100, &inZeroIntensityColor);
|
|
}
|
|
return err;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------------------------------------
|
|
|
|
OSStatus DSpContext_CustomFadeGammaOut (DSpContextReference inContext, long fadeTicks )
|
|
{
|
|
OSStatus err = noErr;
|
|
RGBColor inZeroIntensityColor;
|
|
UInt32 currTick;
|
|
UInt16 step = (UInt16) (800 / fadeTicks);
|
|
long x, percent = 0;
|
|
|
|
if (gDSpStarted)
|
|
{
|
|
if (fadeTicks == 0)
|
|
fadeTicks = 1; // ensure we do not have zero fade time
|
|
inZeroIntensityColor.red = 0x0000;
|
|
inZeroIntensityColor.green = 0x0000;
|
|
inZeroIntensityColor.blue = 0x0000;
|
|
currTick = TickCount ();
|
|
for (x = fadeTicks - 1; x >= 0; x--)
|
|
{
|
|
percent = step * x / 8;
|
|
err = DSpContext_FadeGamma(inContext, percent, &inZeroIntensityColor);
|
|
if (err != noErr) break;
|
|
while (currTick >= TickCount ()) {}
|
|
currTick = TickCount ();
|
|
}
|
|
}
|
|
return err;
|
|
}
|