// 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): // #include "graphics_api.h" #include "mac_app_opengl.h" #include "mac_carbon_gl.h" #ifdef __APPLE_CC__ #include #include #else #include #include #include #include #include #include #include #include #include #include #include #include #endif #include #include #include // project includes --------------------------------------------------------- #include "mac_main.h" void drawGL(WindowPtr pWindow); static void DisposeGLWindow (WindowPtr pWindow); // Dispose a single window and it's GL context // statics/globals (internal only) ------------------------------------------ static const EventTypeSpec appEventList[] = { {kEventClassCommand, kEventCommandProcess}, {kEventClassMouse, kEventMouseDown}, {kEventClassMouse, kEventMouseUp}, {kEventClassMouse, kEventMouseMoved}, {kEventClassMouse, kEventMouseDragged}, {kEventClassMouse, kEventMouseWheelMoved} }; WindowRef appGLWindow; EventLoopTimerRef boincTimer; EventLoopTimerUPP boincTimerUPP; EventHandlerUPP appCommandProcessor; WindowPtr boincAboutWindow; AGLContext boincAGLContext; GLuint monacoFontList; char boincStrContext [256]; structGLWindowInfo glInfo; long gFrameWindow=0; float gRotation=0; AbsoluteTime gTimeWindow; bool user_requested_exit = false; // -------------------------------------------------------------------------- int InitGLWindow(int xsize, int ysize, int depth) { OSStatus err; Rect winRect; TimerUPP boincYieldUPP; EventLoopTimerRef boincYieldTimer; short i,fNum; long response; MenuHandle menu; InitCursor(); // add quit if not under Mac OS X err = Gestalt (gestaltMenuMgrAttr, &response); if ((err == noErr) && !(response & gestaltMenuMgrAquaLayoutMask)) { menu = NewMenu (128, "\pFile"); // new menu InsertMenu (menu, 0); // add menu to end AppendMenu (menu, "\pQuit/Q"); // add quit } SetRect( &winRect, 100, 100, 100+xsize, 100+ysize ); err = CreateNewWindow ( kDocumentWindowClass, kWindowStandardDocumentAttributes, &winRect, &appGLWindow ); if (err != noErr) return -1; // Application-level event handler installer appCommandProcessor = NewEventHandlerUPP(MainAppEventHandler); err = InstallApplicationEventHandler(appCommandProcessor, GetEventTypeCount(appEventList), appEventList, 0, NULL); // Install application graphics timer boincTimerUPP = NewEventLoopTimerUPP(GraphicsLoopProcessor); err = InstallEventLoopTimer(GetMainEventLoop(), 0, kEventDurationMillisecond*10, // Every 1/60th of a second boincTimerUPP, NULL, &boincTimer); // Install preemption boincYieldUPP = NewEventLoopTimerUPP(YieldProcessor); err = InstallEventLoopTimer(GetMainEventLoop(), 0, kEventDurationMillisecond*10, // Every 10 ms boincYieldUPP, NULL, &boincYieldTimer); // TODO: add an event handler for the window ChangeWindowAttributes( appGLWindow, kWindowStandardHandlerAttribute, 0 ); SetWTitle (appGLWindow, "\pWindow"); ShowWindow(appGLWindow); SetPortWindowPort (appGLWindow); glInfo.fAcceleratedMust = false; // must renderer be accelerated? glInfo.VRAM = 0 * 1048576; // minimum VRAM (if not zero this is always a required minimum) glInfo.textureRAM = 0 * 1048576; // minimum texture RAM (if not zero this is always a required minimum) if (!CheckMacOSX ()) // this is false on Mac OS 9 since Mac OS 9 does not support dragging conttexts with shared txtures between to different vendor's renderers. glInfo.fDraggable = false; // should a pixel format that supports all monitors be chosen? else glInfo.fDraggable = true; // should a pixel format that supports all monitors be chosen? glInfo.fmt = 0; // output pixel format i = 0; glInfo.aglAttributes [i++] = AGL_RGBA; glInfo.aglAttributes [i++] = AGL_DOUBLEBUFFER; glInfo.aglAttributes [i++] = AGL_ACCELERATED; glInfo.aglAttributes [i++] = AGL_NO_RECOVERY; glInfo.aglAttributes [i++] = AGL_DEPTH_SIZE; glInfo.aglAttributes [i++] = 16; glInfo.aglAttributes [i++] = AGL_NONE; BuildGLFromWindow (appGLWindow, &boincAGLContext, &glInfo, NULL ); if (!boincAGLContext) { DestroyGLFromWindow (&boincAGLContext, &glInfo); sprintf (boincStrContext, "No context"); } else { Rect rectPort; GetWindowPortBounds (appGLWindow, &rectPort); aglSetCurrentContext (boincAGLContext); aglReportError (); aglUpdateContext (boincAGLContext); aglReportError (); // Set Texture mapping parameters glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR); glClearColor(0.15f, 0.15f, 0.15f, 1.0f); // Clear color buffer to dark grey glClear (GL_COLOR_BUFFER_BIT); glReportError (); aglSwapBuffers (boincAGLContext); aglReportError (); aglDisable (boincAGLContext, AGL_BUFFER_RECT); aglReportError (); glViewport (0, 0, rectPort.right - rectPort.left, rectPort.bottom - rectPort.top); glReportError (); sprintf (boincStrContext, "%d x %d", rectPort.right - rectPort.left, rectPort.bottom - rectPort.top); GetFNum("\pMonaco", &fNum); // build font monacoFontList = BuildFontGL (boincAGLContext, fNum, normal, 9); aglUpdateContext (boincAGLContext); aglReportError (); } return 0; } ////////////////////////////////////////////////////////////////////////////////// // GraphicsLoopProcessor // ////////////////////////////////////////////////////////////////////////////////// pascal void GraphicsLoopProcessor(EventLoopTimerRef inTimer, void* timeData) { DoUpdate (boincAGLContext); } ////////////////////////////////////////////////////////////////////////////////// // YieldProcessor // ////////////////////////////////////////////////////////////////////////////////// pascal void YieldProcessor(EventLoopTimerRef inTimer, void* timeData) { YieldToAnyThread(); } /* if ((pWindowInfo) && (boincAGLContext)) { GetWindowPortBounds (whichWindow, &rectTemp); aglSetCurrentContext (boincAGLContext); // ensure the context we are working with is current aglUpdateContext (boincAGLContext); glViewport (0, 0, rectTemp.right - rectTemp.left, rectTemp.bottom - rectTemp.top); sprintf (pWindowInfo->strContext, "%d x %d", rectTemp.right - rectTemp.left, rectTemp.bottom - rectTemp.top); } */ ////////////////////////////////////////////////////////////////////////////////// // MainAppEventHandler // ////////////////////////////////////////////////////////////////////////////////// pascal OSStatus MainAppEventHandler(EventHandlerCallRef appHandler, EventRef theEvent, void* appData) { #pragma unused (appHandler, appData) HICommand aCommand; OSStatus result; Point mDelta; switch(GetEventClass(theEvent)) { case kEventClassMouse: // 'mous' GetEventParameter(theEvent, // the event itself kEventParamMouseDelta, // symbolic parameter name typeQDPoint, // expected type NULL, // actual type (NULL is valid) sizeof(mDelta), // buffer size NULL, // actual buffer size (Can be NULL) &mDelta); // variable to hold data switch(GetEventKind(theEvent)) { case kEventMouseDown: break; case kEventMouseUp: break; case kEventMouseMoved: break; case kEventMouseDragged: break; case kEventMouseWheelMoved: break; default: result = eventNotHandledErr; break; } break; case kEventClassCommand: result = GetEventParameter(theEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &aCommand); switch (aCommand.commandID) { case kHICommandQuit: QuitApplicationEventLoop(); result = noErr; break; case kHICommandOK: // 'ok ' case kHICommandCancel: // 'not!' case kHICommandUndo: // 'undo' case kHICommandRedo: // 'redo' case kHICommandCut: // 'cut ' case kHICommandCopy: // 'copy' case kHICommandPaste: // 'past' case kHICommandClear: // 'clea' case kHICommandSelectAll: // 'sall' case kHICommandHide: // 'hide' case kHICommandZoomWindow: // 'zoom' case kHICommandMinimizeWindow: // 'mini' case kHICommandArrangeInFront: // 'frnt' break; case kHICommandAbout: // 'abou' // Open About window //CreateAboutWindow(); result = noErr; break; default: result = eventNotHandledErr; break; } break; default: result = eventNotHandledErr; break; } return result; } // -------------------------------------------------------------------------- pascal void mac_graphics_event_loop ( GRAPHICS_INFO *gi ) { InitGLWindow(gi->xsize, gi->ysize, 16); RunApplicationEventLoop(); } // -------------------------------------------------------------------------- void mac_cleanup (void) { // TODO: Dispose all the timers here RemoveEventLoopTimer(boincTimer); DisposeEventLoopTimerUPP(boincTimerUPP); DisposeEventHandlerUPP(appCommandProcessor); //DisposeGLWindow (appGLWindow); } // -------------------------------------------------------------------------- static void DisposeGLWindow (WindowPtr pWindow) // Dispose a single window and it's GL context { if (pWindow) { DeleteFontGL (monacoFontList); // must clean up failure to do so will result in an Unmapped Memory Exception DestroyGLFromWindow (&boincAGLContext, &glInfo); DisposeWindow (pWindow); } } #pragma mark - //----------------------------------------------------------------------------------------------------------------------- // OpenGL Drawing void drawGL(WindowPtr pWindow) { static int first = 1; static char myStr[256]; if( first ) { gFrameWindow = 0; gTimeWindow.hi = 0; gTimeWindow.lo = 0; gRotation = 0.0; first = 0; } float f = 0.0; glClearColor(0.25f, 0.25f, 0.25f, 1.0f); // Clear color buffer to dark grey glClear(GL_COLOR_BUFFER_BIT); gRotation += 0.5; f = gRotation; glMatrixMode (GL_MODELVIEW); glLoadIdentity (); glRotated (f, 0.0, 0.0, 1.0); glEnable (GL_TEXTURE_2D); glBegin(GL_QUADS); // Draw textured polygon glColor3d(1.0, 0.0, 0.0); glVertex3d(0.7, 0.7, 0.0); glColor3d(0.0, 1.0, 0.0); glVertex3d(-0.7, 0.7, 0.0); glColor3d(0.0, 0.0, 1.0); glVertex3d(-0.7, -0.7, 0.0); glColor3d(0.7, 0.7, 0.7); glVertex3d(0.7, -0.7, 0.0); glEnd(); glDisable (GL_TEXTURE_2D); // draw info Rect rectPort; GLint matrixMode; GetWindowPortBounds (pWindow, &rectPort); glGetIntegerv (GL_MATRIX_MODE, &matrixMode); glMatrixMode (GL_PROJECTION); glPushMatrix(); glLoadIdentity (); glMatrixMode (GL_MODELVIEW); glPushMatrix(); glLoadIdentity (); glScalef (2.0 / (rectPort.right - rectPort.left), -2.0 / (rectPort.bottom - rectPort.top), 1.0); glTranslatef (-(rectPort.right - rectPort.left) / 2.0, -(rectPort.bottom - rectPort.top) / 2.0, 0.0); glColor3f (1.0, 1.0, 1.0); glRasterPos3d (10, 12, 0); MultiWinDrawFrameRate (monacoFontList, myStr, &gFrameWindow, &gTimeWindow); glRasterPos3d (10, 24, 0); DrawCStringGL (boincStrContext, monacoFontList); glRasterPos3d (10, (rectPort.bottom - rectPort.top) - 15, 0); DrawCStringGL ((char*) glGetString (GL_VENDOR), monacoFontList); glRasterPos3d (10, (rectPort.bottom - rectPort.top) - 3, 0); DrawCStringGL ((char*) glGetString (GL_RENDERER), monacoFontList); glPopMatrix(); // GL_MODELVIEW glMatrixMode (GL_PROJECTION); glPopMatrix(); glMatrixMode (matrixMode); }