home *** CD-ROM | disk | FTP | other *** search
- """GLUT functions requiring special handling to provide Pythonic wrappers
-
- Note:
- GLUT callbacks are controlled by a flag in the platform module. The
- GLUT_GUARD_CALLBACKS flag controls whether to wrap passed functions
- with error-checking and context-validity checking code so that the
- callbacks will only trigger if there is a valid context. This is done
- so that systems such as Win32 will not continue running GLUT callbacks
- after the system has exited.
-
- Note:
- This is not a problem with FreeGLUT on Linux, so Linux does not
- add the extra overhead of the wrapper function.
- Note:
- This hack does *not* prevent hanging if there is no GLUT callback
- being triggered. I.e. if you create a GLUT program that doesn't
- explicitly call exit and doesn't call display or the like in a timer
- then your app will hang on exit on Win32.
-
- XXX the platform-specific stuff should be getting done in the
- platform module *not* in the module here!
- """
- from OpenGL.platform import GLUT, CurrentContextIsValid, GLUT_GUARD_CALLBACKS
- from OpenGL import contextdata, error, platform, logs
- from OpenGL.raw import GLUT as simple
- import ctypes, os, sys, traceback
- PLATFORM = platform.PLATFORM
- FUNCTION_TYPE = simple.CALLBACK_FUNCTION_TYPE
-
- log = logs.getLog( 'OpenGL.GLUT.special' )
-
- if os.name == "nt":
- log.info( """Using NT-specific GLUT calls with exit callbacks""" )
- __glutInitWithExit = platform.createBaseFunction(
- '__glutInitWithExit', dll=platform.GLUT, resultType=None,
- argTypes=[ctypes.POINTER(ctypes.c_int),ctypes.POINTER(ctypes.c_char_p),ctypes.c_void_p],
- doc='glutInit( POINTER(c_int)(pargc), POINTER(STRING)(argv) ) -> None',
- argNames=('pargc', 'argv'),
- )
- __glutCreateWindowWithExit = platform.createBaseFunction(
- '__glutCreateWindowWithExit', dll=platform.GLUT, resultType=ctypes.c_int,
- argTypes=[ctypes.c_char_p, ctypes.c_void_p],
- doc='glutCreateWindow( STRING(title) ) -> c_int',
- argNames=('title',),
- )
- __glutCreateMenuWithExit = platform.createBaseFunction(
- '__glutCreateMenuWithExit', dll=platform.GLUT, resultType=ctypes.c_int,
- argTypes=[FUNCTION_TYPE(None, ctypes.c_int), ctypes.c_void_p],
- doc='glutCreateMenu( FUNCTION_TYPE(None, c_int)(callback) ) -> c_int',
- argNames=('callback',),
- )
- import sys
- _exitfunc = FUNCTION_TYPE( None, ctypes.c_int )(sys.exit)
-
- def _base_glutInit(pargc, argv):
- """Overrides base glut init with exit-function-aware version"""
- return __glutInitWithExit(pargc, argv, _exitfunc)
- def glutCreateWindow(title):
- """Create window with given title
-
- This is the Win32-specific version that handles
- registration of an exit-function handler
- """
- return __glutCreateWindowWithExit(title, _exitfunc)
- def glutCreateMenu(callback):
- """Create menu with given callback
-
- This is the Win32-specific version that handles
- registration of an exit-function callback.
- """
- return __glutCreateMenuWithExit(callback, _exitfunc)
- else:
- _base_glutInit = getattr(GLUT, 'glutInit', None)
- ##_base_glutDisplayFunc = GLUT.glutDisplayFunc
- ##_base_glutIdleFunc = GLUT.glutIdleFunc
- ##_base_glutEntryFunc = GLUT.glutEntryFunc
- ##_base_glutReshapeFunc = GLUT.glutReshapeFunc
- _base_glutDestroyWindow = getattr(GLUT, 'glutDestroyWindow', None)
-
- class GLUTCallback( object ):
- """Class implementing GLUT Callback registration functions"""
- def __init__( self, typeName, parameterTypes, parameterNames ):
- """Initialise the glut callback instance"""
- self.typeName = typeName
- def describe( typ, name ):
- return '(int) %s'%(name)
- self.__doc__ = """Specify handler for GLUT %r events
- def handler( %s ):
- return None"""%( typeName, ", ".join([
- describe( typ,name )
- for (typ,name) in zip( parameterTypes, parameterNames )
- ]))
- try:
- self.wrappedOperation = getattr( GLUT, 'glut%sFunc'%(typeName) )
- except AttributeError, err:
- def failFunction( *args, **named ):
- from OpenGL import error
- raise error.NullFunctionError(
- """Undefined GLUT callback function %s, check for bool(%s) before calling"""%(
- typeName, 'glut%sFunc'%(typeName),
- )
- )
- self.wrappedOperation = failFunction
- self.callbackType = FUNCTION_TYPE( None, *parameterTypes )
- self.CONTEXT_DATA_KEY = 'glut%sFunc'%(typeName, )
- def __call__( self, function, *args ):
- if GLUT_GUARD_CALLBACKS and callable( function ):
- def safeCall( *args, **named ):
- """Safe calling of GUI callbacks, exits on failures"""
- try:
- if not CurrentContextIsValid():
- raise RuntimeError( """No valid context!""" )
- return function( *args, **named )
- except Exception, err:
- traceback.print_exc()
- sys.stderr.write( """GLUT %s callback %s with %s,%s failed: returning None %s\n"""%(
- self.typeName, function, args, named, err,
- ))
- os._exit(1)
- #return None
- finalFunction = safeCall
- else:
- finalFunction = function
- if callable( finalFunction ):
- cCallback = self.callbackType( finalFunction )
- else:
- cCallback = function
- # keep the function alive as long as the cCallback is...
- #cCallback.function = function
- contextdata.setValue( self.CONTEXT_DATA_KEY, cCallback )
- self.wrappedOperation( cCallback, *args )
- return cCallback
- class GLUTTimerCallback( GLUTCallback ):
- """GLUT timer callbacks (completely nonstandard wrt other GLUT callbacks)"""
- def __call__( self, milliseconds, function, value ):
- cCallback = self.callbackType( function )
- # timers should de-register as soon as they are called...
- # Note: there's no good key to use! we want to allow for
- # multiple instances of the same function with the same value
- # which means we have nothing that can store it properly...
- callbacks = contextdata.getValue( self.CONTEXT_DATA_KEY )
- if callbacks is None:
- callbacks = []
- contextdata.setValue( self.CONTEXT_DATA_KEY, callbacks )
- def deregister( value ):
- try:
- function( value )
- finally:
- for item in callbacks:
- if item.function is deregister:
- callbacks.remove( item )
- item.function = None
- break
- if not callbacks:
- contextdata.delValue( self.CONTEXT_DATA_KEY )
- cCallback = self.callbackType( deregister )
- cCallback.function = deregister
- callbacks.append( cCallback )
- self.wrappedOperation( milliseconds, cCallback, value )
- return cCallback
-
- class GLUTMenuCallback( object ):
- """Place to collect the GLUT Menu manipulation special code"""
- callbackType = FUNCTION_TYPE( ctypes.c_int, ctypes.c_int )
- def glutCreateMenu( cls, func ):
- """Create a new (current) menu, return small integer identifier
-
- func( int ) -- Function taking a single integer reflecting
- the user's choice, the value passed to glutAddMenuEntry
-
- return menuID (small integer)
- """
- cCallback = cls.callbackType( func )
- menu = simple.glutCreateMenu( cCallback )
- contextdata.setValue( ('menucallback',menu), (cCallback,func) )
- return menu
- glutCreateMenu.argNames = [ 'func' ]
- glutCreateMenu = classmethod( glutCreateMenu )
- def glutDestroyMenu( cls, menu ):
- """Destroy (cleanup) the given menu
-
- Deregister's the interal pointer to the menu callback
-
- returns None
- """
- result = simple.glutDestroyMenu( menu )
- contextdata.delValue( ('menucallback',menu) )
- return result
- glutDestroyMenu.argNames = [ 'menu' ]
- glutDestroyMenu = classmethod( glutDestroyMenu )
-
- glutCreateMenu = GLUTMenuCallback.glutCreateMenu
- #glutCreateMenu.wrappedOperation = simple.glutCreateMenu
- glutDestroyMenu = GLUTMenuCallback.glutDestroyMenu
- #glutDestroyMenu.wrappedOperation = simple.glutDestroyMenu
-
- glutButtonBoxFunc = GLUTCallback(
- 'ButtonBox', (ctypes.c_int,ctypes.c_int), ('button','state'),
- )
- glutDialsFunc = GLUTCallback(
- 'Dials', (ctypes.c_int,ctypes.c_int), ('dial','value'),
- )
- glutDisplayFunc = GLUTCallback(
- 'Display', (), (),
- )
- glutEntryFunc = GLUTCallback(
- 'Entry', (ctypes.c_int,), ('state',),
- )
- glutIdleFunc = GLUTCallback(
- 'Idle', (), (),
- )
- glutJoystickFunc = GLUTCallback(
- 'Joystick', (ctypes.c_uint,ctypes.c_int,ctypes.c_int,ctypes.c_int), ('buttonMask','x','y','z'),
- )
- glutKeyboardFunc = GLUTCallback(
- 'Keyboard', (ctypes.c_char,ctypes.c_int,ctypes.c_int), ('key','x','y'),
- )
- glutKeyboardUpFunc = GLUTCallback(
- 'KeyboardUp', (ctypes.c_char,ctypes.c_int,ctypes.c_int), ('key','x','y'),
- )
- glutMenuStatusFunc = GLUTCallback(
- 'MenuStatus', (ctypes.c_int,ctypes.c_int,ctypes.c_int), ('status','x','y'),
- )
- glutMenuStateFunc = GLUTCallback(
- 'MenuState', (ctypes.c_int,), ('status',),
- )
- glutMotionFunc = GLUTCallback(
- 'Motion', (ctypes.c_int,ctypes.c_int), ('x','y'),
- )
- glutMouseFunc = GLUTCallback(
- 'Mouse', (ctypes.c_int,ctypes.c_int,ctypes.c_int,ctypes.c_int), ('button','state','x','y'),
- )
- glutOverlayDisplayFunc = GLUTCallback(
- 'OverlayDisplay', (), (),
- )
- glutPassiveMotionFunc = GLUTCallback(
- 'PassiveMotion', (ctypes.c_int,ctypes.c_int), ('x','y'),
- )
- glutReshapeFunc = GLUTCallback(
- 'Reshape', (ctypes.c_int,ctypes.c_int), ('width','height'),
- )
- glutSpaceballButtonFunc = GLUTCallback(
- 'SpaceballButton', (ctypes.c_int,ctypes.c_int), ('button','state'),
- )
- glutSpaceballMotionFunc = GLUTCallback(
- 'SpaceballMotion', (ctypes.c_int,ctypes.c_int,ctypes.c_int), ('x','y','z'),
- )
- glutSpaceballRotateFunc = GLUTCallback(
- 'SpaceballRotate', (ctypes.c_int,ctypes.c_int,ctypes.c_int), ('x','y','z'),
- )
- glutSpecialFunc = GLUTCallback(
- 'Special', (ctypes.c_int,ctypes.c_int,ctypes.c_int), ('key','x','y'),
- )
- glutSpecialUpFunc = GLUTCallback(
- 'SpecialUp', (ctypes.c_int,ctypes.c_int,ctypes.c_int), ('key','x','y'),
- )
- glutTabletButtonFunc = GLUTCallback(
- 'TabletButton', (ctypes.c_int,ctypes.c_int,ctypes.c_int,ctypes.c_int), ('button','state','x','y',),
- )
- glutTabletButtonFunc = GLUTCallback(
- 'TabletButton', (ctypes.c_int,ctypes.c_int,ctypes.c_int,ctypes.c_int), ('button','state','x','y',),
- )
- glutTabletMotionFunc = GLUTCallback(
- 'TabletMotion', (ctypes.c_int,ctypes.c_int), ('x','y',),
- )
- glutVisibilityFunc = GLUTCallback(
- 'Visibility', (ctypes.c_int,), ('state',),
- )
- glutWindowStatusFunc = GLUTCallback(
- 'WindowStatus', (ctypes.c_int,), ('state',),
- )
-
- # glutTimerFunc is unlike any other GLUT callback-registration...
- glutTimerFunc = GLUTTimerCallback(
- 'Timer', (ctypes.c_int,), ('value',),
- )
-
- INITIALIZED = False
- def glutInit( *args ):
- """Initialise the GLUT library"""
- global INITIALIZED
- if INITIALIZED:
- return args
- INITIALIZED = True
- if args:
- arg,args = args[0],args[1:]
- count = None
- if isinstance(arg, (int,long)):
- # raw API style, (count, values)
- count = arg
- if count != len(args):
- raise ValueError( """Specified count of %s does not match length (%s) of argument list %s"""%(
- count, len(args), args,
- ))
- elif isinstance( arg, (str,unicode)):
- # passing in a sequence of strings as individual arguments
- args = (arg,)+args
- count = len(args)
- else:
- args = arg
- count = len(args)
- else:
- count=0
- args = []
- args = [str(x) for x in args]
- if not count:
- count, args = 1, ['foo']
- holder = (ctypes.c_char_p * len(args))()
- for i,arg in enumerate(args):
- holder[i] = arg
- count = ctypes.c_int( count )
- import os
- currentDirectory = os.getcwd()
- try:
- # XXX need to check for error condition here...
- _base_glutInit( ctypes.byref(count), holder )
- finally:
- os.chdir( currentDirectory )
- return [
- str(holder[i]) for i in range( count.value )
- ]
- glutInit.wrappedOperation = simple.glutInit
-
- def glutDestroyWindow( window ):
- """Want to destroy the window, we need to do some cleanup..."""
- context = 0
- try:
- GLUT.glutSetWindow(window)
- context = contextdata.getContext()
- result = contextdata.cleanupContext( context )
- log.info( """Cleaning up context data for window %s: %s""", window, result )
- except Exception, err:
- log.error( """Error attempting to clean up context data for GLUT window %s: %s""", window, result )
- return _base_glutDestroyWindow( window )
- glutDestroyWindow.wrappedOperation = simple.glutDestroyWindow
-
-