2002-10-14 20:42:01 +00:00
// 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 "mac_app_opengl.h"
# include "mac_carbon_gl.h"
# ifdef __APPLE_CC__
# include <OpenGL/gl.h>
# else
# include <gl.h>
# include <Devices.h>
# include <Dialogs.h>
# include <DriverServices.h>
# include <Events.h>
# include <Gestalt.h>
# include <LowMem.h>
# include <PictUtils.h>
# include <TextEdit.h>
# include <ToolUtils.h>
# include <QDOffscreen.h>
# include <Windows.h>
# endif
# include <stdio.h>
# include <string.h>
// project includes ---------------------------------------------------------
2002-10-30 04:30:28 +00:00
# include "graphics_api.h"
2002-10-14 20:42:01 +00:00
// 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 ;
2002-10-31 00:13:50 +00:00
GLuint main_font ;
2002-10-14 20:42:01 +00:00
structGLWindowInfo glInfo ;
bool user_requested_exit = false ;
2003-02-14 18:47:26 +00:00
extern bool using_opengl ;
2002-10-14 20:42:01 +00:00
// --------------------------------------------------------------------------
2003-02-19 18:26:11 +00:00
int InitGLWindow ( int xsize , int ysize , int depth , double refresh_period ) {
2002-10-14 20:42:01 +00:00
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 preemption
boincYieldUPP = NewEventLoopTimerUPP ( YieldProcessor ) ;
err = InstallEventLoopTimer ( GetMainEventLoop ( ) , 0 ,
kEventDurationMillisecond * 10 , // Every 10 ms
boincYieldUPP , NULL , & boincYieldTimer ) ;
2002-10-29 18:51:45 +00:00
// Install graphics
boincYieldUPP = NewEventLoopTimerUPP ( GraphicsLoopProcessor ) ;
err = InstallEventLoopTimer ( GetMainEventLoop ( ) , 0 ,
2003-02-19 18:26:11 +00:00
kEventDurationMillisecond * refresh_period * 1000 ,
2002-10-29 18:51:45 +00:00
boincYieldUPP , NULL , & boincYieldTimer ) ;
2002-10-14 20:42:01 +00:00
// 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 ) ;
2003-02-19 18:26:11 +00:00
if ( ! boincAGLContext ) {
2002-10-14 20:42:01 +00:00
DestroyGLFromWindow ( & boincAGLContext , & glInfo ) ;
2003-02-19 18:26:11 +00:00
} else {
2002-10-14 20:42:01 +00:00
Rect rectPort ;
GetWindowPortBounds ( appGLWindow , & rectPort ) ;
aglSetCurrentContext ( boincAGLContext ) ;
aglReportError ( ) ;
aglUpdateContext ( boincAGLContext ) ;
aglReportError ( ) ;
2003-02-14 18:47:26 +00:00
aglDisable ( boincAGLContext , AGL_BUFFER_RECT ) ;
aglReportError ( ) ;
ReSizeGLScene ( rectPort . right - rectPort . left , rectPort . bottom - rectPort . top ) ;
glReportError ( ) ;
InitGL ( ) ;
2002-10-14 20:42:01 +00:00
glClear ( GL_COLOR_BUFFER_BIT ) ;
glReportError ( ) ;
aglSwapBuffers ( boincAGLContext ) ;
aglReportError ( ) ;
2002-10-31 00:13:50 +00:00
GetFNum ( " \ pTimes New Roman " , & fNum ) ; // build font
main_font = BuildFontGL ( boincAGLContext , fNum , normal , 9 ) ;
2002-10-14 20:42:01 +00:00
aglUpdateContext ( boincAGLContext ) ;
aglReportError ( ) ;
2003-02-14 18:47:26 +00:00
using_opengl = true ;
2002-10-14 20:42:01 +00:00
}
return 0 ;
}
//////////////////////////////////////////////////////////////////////////////////
// GraphicsLoopProcessor //
//////////////////////////////////////////////////////////////////////////////////
pascal void GraphicsLoopProcessor ( EventLoopTimerRef inTimer , void * timeData ) {
DoUpdate ( boincAGLContext ) ;
}
//////////////////////////////////////////////////////////////////////////////////
// YieldProcessor //
//////////////////////////////////////////////////////////////////////////////////
pascal void YieldProcessor ( EventLoopTimerRef inTimer , void * timeData ) {
YieldToAnyThread ( ) ;
}
//////////////////////////////////////////////////////////////////////////////////
// MainAppEventHandler //
//////////////////////////////////////////////////////////////////////////////////
pascal OSStatus MainAppEventHandler ( EventHandlerCallRef appHandler , EventRef theEvent , void * appData )
{
# pragma unused (appHandler, appData)
HICommand aCommand ;
OSStatus result ;
Point mDelta ;
2002-10-30 04:30:28 +00:00
Rect rectPort ;
2002-10-14 20:42:01 +00:00
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 :
case kEventMouseUp :
case kEventMouseMoved :
case kEventMouseDragged :
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 ;
2002-10-30 04:30:28 +00:00
case kHICommandMaximizeWindow : // 'mini'
case kHICommandZoomWindow : // 'zoom'
GetWindowPortBounds ( appGLWindow , & rectPort ) ;
2003-02-14 18:47:26 +00:00
ReSizeGLScene ( rectPort . right - rectPort . left , rectPort . bottom - rectPort . top ) ;
2002-10-30 04:30:28 +00:00
glReportError ( ) ;
break ;
2002-10-14 20:42:01 +00:00
case kHICommandHide : // 'hide'
case kHICommandMinimizeWindow : // 'mini'
case kHICommandArrangeInFront : // 'frnt'
break ;
default :
result = eventNotHandledErr ;
break ;
}
break ;
default :
result = eventNotHandledErr ;
break ;
}
return result ;
}
// --------------------------------------------------------------------------
2002-10-31 00:13:50 +00:00
pascal void * mac_graphics_event_loop ( void * data ) {
2003-02-19 18:26:11 +00:00
GRAPHICS_INFO * gi = data ;
2002-10-30 04:30:28 +00:00
2003-02-19 18:26:11 +00:00
InitGLWindow ( gi - > xsize , gi - > ysize , 16 , gi - > refresh_period ) ;
2002-10-14 20:42:01 +00:00
RunApplicationEventLoop ( ) ;
2002-10-31 00:13:50 +00:00
return NULL ;
2002-10-14 20:42:01 +00:00
}
// --------------------------------------------------------------------------
2003-02-19 18:26:11 +00:00
void mac_cleanup ( void ) {
2002-10-14 20:42:01 +00:00
// TODO: Dispose all the timers here
RemoveEventLoopTimer ( boincTimer ) ;
DisposeEventLoopTimerUPP ( boincTimerUPP ) ;
DisposeEventHandlerUPP ( appCommandProcessor ) ;
2002-10-29 18:51:45 +00:00
DisposeGLWindow ( appGLWindow ) ;
2002-10-14 20:42:01 +00:00
}
// --------------------------------------------------------------------------
2003-02-19 18:26:11 +00:00
void DisposeGLWindow ( WindowPtr pWindow ) { // Dispose a single window and it's GL context
if ( pWindow ) {
2002-10-31 00:13:50 +00:00
DeleteFontGL ( main_font ) ;
2002-10-14 20:42:01 +00:00
// must clean up failure to do so will result in an Unmapped Memory Exception
DestroyGLFromWindow ( & boincAGLContext , & glInfo ) ;
DisposeWindow ( pWindow ) ;
}
}