// 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 #else #include #include #include #include #include #include #include #endif #include // 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; }