home *** CD-ROM | disk | FTP | other *** search
/ Hackers Magazine 57 / CdHackersMagazineNr57.iso / Software / Multimedia / k3d-setup-0.7.11.0.exe / lib / site-packages / OpenGL / GLUT / special.py < prev   
Encoding:
Python Source  |  2008-12-07  |  11.5 KB  |  337 lines

  1. """GLUT functions requiring special handling to provide Pythonic wrappers
  2.  
  3. Note:
  4.     GLUT callbacks are controlled by a flag in the platform module.  The
  5.     GLUT_GUARD_CALLBACKS flag controls whether to wrap passed functions
  6.     with error-checking and context-validity checking code so that the
  7.     callbacks will only trigger if there is a valid context.  This is done
  8.     so that systems such as Win32 will not continue running GLUT callbacks
  9.     after the system has exited.
  10.  
  11.     Note:
  12.         This is not a problem with FreeGLUT on Linux, so Linux does not
  13.         add the extra overhead of the wrapper function.
  14.     Note:
  15.         This hack does *not* prevent hanging if there is no GLUT callback
  16.         being triggered.  I.e. if you create a GLUT program that doesn't
  17.         explicitly call exit and doesn't call display or the like in a timer
  18.         then your app will hang on exit on Win32.
  19.  
  20. XXX the platform-specific stuff should be getting done in the 
  21. platform module *not* in the module here!
  22. """
  23. from OpenGL.platform import GLUT, CurrentContextIsValid, GLUT_GUARD_CALLBACKS
  24. from OpenGL import contextdata, error, platform, logs
  25. from OpenGL.raw import GLUT as simple
  26. import ctypes, os, sys, traceback
  27. PLATFORM = platform.PLATFORM
  28. FUNCTION_TYPE = simple.CALLBACK_FUNCTION_TYPE
  29.  
  30. log = logs.getLog( 'OpenGL.GLUT.special' )
  31.  
  32. if os.name == "nt":
  33.     log.info( """Using NT-specific GLUT calls with exit callbacks""" )
  34.     __glutInitWithExit = platform.createBaseFunction(
  35.         '__glutInitWithExit', dll=platform.GLUT, resultType=None,
  36.         argTypes=[ctypes.POINTER(ctypes.c_int),ctypes.POINTER(ctypes.c_char_p),ctypes.c_void_p],
  37.         doc='glutInit( POINTER(c_int)(pargc), POINTER(STRING)(argv) ) -> None',
  38.         argNames=('pargc', 'argv'),
  39.     )
  40.     __glutCreateWindowWithExit = platform.createBaseFunction(
  41.         '__glutCreateWindowWithExit', dll=platform.GLUT, resultType=ctypes.c_int,
  42.         argTypes=[ctypes.c_char_p, ctypes.c_void_p],
  43.         doc='glutCreateWindow( STRING(title) ) -> c_int',
  44.         argNames=('title',),
  45.     )
  46.     __glutCreateMenuWithExit = platform.createBaseFunction( 
  47.         '__glutCreateMenuWithExit', dll=platform.GLUT, resultType=ctypes.c_int, 
  48.         argTypes=[FUNCTION_TYPE(None, ctypes.c_int), ctypes.c_void_p],
  49.         doc='glutCreateMenu( FUNCTION_TYPE(None, c_int)(callback) ) -> c_int', 
  50.         argNames=('callback',),
  51.     )
  52.     import sys
  53.     _exitfunc = FUNCTION_TYPE( None, ctypes.c_int )(sys.exit)
  54.     
  55.     def _base_glutInit(pargc, argv):
  56.         """Overrides base glut init with exit-function-aware version"""
  57.         return __glutInitWithExit(pargc, argv, _exitfunc)
  58.     def glutCreateWindow(title):
  59.         """Create window with given title
  60.         
  61.         This is the Win32-specific version that handles
  62.         registration of an exit-function handler 
  63.         """
  64.         return __glutCreateWindowWithExit(title, _exitfunc)
  65.     def glutCreateMenu(callback):
  66.         """Create menu with given callback 
  67.         
  68.         This is the Win32-specific version that handles 
  69.         registration of an exit-function callback.
  70.         """
  71.         return __glutCreateMenuWithExit(callback, _exitfunc)
  72. else:
  73.     _base_glutInit = getattr(GLUT, 'glutInit', None)
  74. ##_base_glutDisplayFunc = GLUT.glutDisplayFunc
  75. ##_base_glutIdleFunc = GLUT.glutIdleFunc
  76. ##_base_glutEntryFunc = GLUT.glutEntryFunc
  77. ##_base_glutReshapeFunc = GLUT.glutReshapeFunc
  78. _base_glutDestroyWindow = getattr(GLUT, 'glutDestroyWindow', None)
  79.  
  80. class GLUTCallback( object ):
  81.     """Class implementing GLUT Callback registration functions"""
  82.     def __init__( self, typeName, parameterTypes, parameterNames ):
  83.         """Initialise the glut callback instance"""
  84.         self.typeName = typeName
  85.         def describe( typ, name ):
  86.             return '(int) %s'%(name)
  87.         self.__doc__ = """Specify handler for GLUT %r events
  88.     def handler( %s ):
  89.         return None"""%( typeName, ", ".join([
  90.             describe( typ,name )
  91.             for (typ,name) in zip( parameterTypes, parameterNames )
  92.         ]))
  93.         try:
  94.             self.wrappedOperation = getattr( GLUT, 'glut%sFunc'%(typeName) )
  95.         except AttributeError, err:
  96.             def failFunction( *args, **named ):
  97.                 from OpenGL import error
  98.                 raise error.NullFunctionError(
  99.                     """Undefined GLUT callback function %s, check for bool(%s) before calling"""%(
  100.                         typeName, 'glut%sFunc'%(typeName),
  101.                     )
  102.                 )
  103.             self.wrappedOperation = failFunction
  104.         self.callbackType = FUNCTION_TYPE( None, *parameterTypes )
  105.         self.CONTEXT_DATA_KEY = 'glut%sFunc'%(typeName, )
  106.     def __call__( self, function, *args ):
  107.         if GLUT_GUARD_CALLBACKS and callable( function ):
  108.             def safeCall( *args, **named ):
  109.                 """Safe calling of GUI callbacks, exits on failures"""
  110.                 try:
  111.                     if not CurrentContextIsValid():
  112.                         raise RuntimeError( """No valid context!""" )
  113.                     return function( *args, **named )
  114.                 except Exception, err:
  115.                     traceback.print_exc()
  116.                     sys.stderr.write( """GLUT %s callback %s with %s,%s failed: returning None %s\n"""%(
  117.                         self.typeName, function, args, named, err, 
  118.                     ))
  119.                     os._exit(1)
  120.                     #return None
  121.             finalFunction = safeCall
  122.         else:
  123.             finalFunction = function
  124.         if callable( finalFunction ):
  125.             cCallback = self.callbackType( finalFunction )
  126.         else:
  127.             cCallback = function
  128.         # keep the function alive as long as the cCallback is...
  129.         #cCallback.function = function
  130.         contextdata.setValue( self.CONTEXT_DATA_KEY, cCallback )
  131.         self.wrappedOperation( cCallback, *args )
  132.         return cCallback
  133. class GLUTTimerCallback( GLUTCallback ):
  134.     """GLUT timer callbacks (completely nonstandard wrt other GLUT callbacks)"""
  135.     def __call__( self, milliseconds, function, value ):
  136.         cCallback = self.callbackType( function )
  137.         # timers should de-register as soon as they are called...
  138.         # Note: there's no good key to use! we want to allow for
  139.         # multiple instances of the same function with the same value 
  140.         # which means we have nothing that can store it properly...
  141.         callbacks = contextdata.getValue( self.CONTEXT_DATA_KEY )
  142.         if callbacks is None:
  143.             callbacks = []
  144.             contextdata.setValue( self.CONTEXT_DATA_KEY, callbacks )
  145.         def deregister( value ):
  146.             try:
  147.                 function( value )
  148.             finally:
  149.                 for item in callbacks:
  150.                     if item.function is deregister:
  151.                         callbacks.remove( item )
  152.                         item.function = None
  153.                         break
  154.                 if not callbacks:
  155.                     contextdata.delValue( self.CONTEXT_DATA_KEY )
  156.         cCallback = self.callbackType( deregister )
  157.         cCallback.function = deregister
  158.         callbacks.append( cCallback )
  159.         self.wrappedOperation( milliseconds, cCallback, value )
  160.         return cCallback
  161.  
  162. class GLUTMenuCallback( object ):
  163.     """Place to collect the GLUT Menu manipulation special code"""
  164.     callbackType = FUNCTION_TYPE( ctypes.c_int, ctypes.c_int )
  165.     def glutCreateMenu( cls, func ):
  166.         """Create a new (current) menu, return small integer identifier
  167.         
  168.         func( int ) -- Function taking a single integer reflecting
  169.             the user's choice, the value passed to glutAddMenuEntry
  170.         
  171.         return menuID (small integer)
  172.         """
  173.         cCallback = cls.callbackType( func )
  174.         menu = simple.glutCreateMenu( cCallback )
  175.         contextdata.setValue( ('menucallback',menu), (cCallback,func) )
  176.         return menu
  177.     glutCreateMenu.argNames = [ 'func' ]
  178.     glutCreateMenu = classmethod( glutCreateMenu )
  179.     def glutDestroyMenu( cls, menu ):
  180.         """Destroy (cleanup) the given menu
  181.         
  182.         Deregister's the interal pointer to the menu callback 
  183.         
  184.         returns None
  185.         """
  186.         result = simple.glutDestroyMenu( menu )
  187.         contextdata.delValue( ('menucallback',menu) )
  188.         return result
  189.     glutDestroyMenu.argNames = [ 'menu' ]
  190.     glutDestroyMenu = classmethod( glutDestroyMenu )
  191.  
  192. glutCreateMenu = GLUTMenuCallback.glutCreateMenu
  193. #glutCreateMenu.wrappedOperation = simple.glutCreateMenu
  194. glutDestroyMenu = GLUTMenuCallback.glutDestroyMenu
  195. #glutDestroyMenu.wrappedOperation = simple.glutDestroyMenu
  196.  
  197. glutButtonBoxFunc = GLUTCallback(
  198.     'ButtonBox', (ctypes.c_int,ctypes.c_int), ('button','state'),
  199. )
  200. glutDialsFunc = GLUTCallback(
  201.     'Dials', (ctypes.c_int,ctypes.c_int), ('dial','value'),
  202. )
  203. glutDisplayFunc = GLUTCallback(
  204.     'Display', (), (),
  205. )
  206. glutEntryFunc = GLUTCallback(
  207.     'Entry', (ctypes.c_int,), ('state',),
  208. )
  209. glutIdleFunc = GLUTCallback(
  210.     'Idle', (), (),
  211. )
  212. glutJoystickFunc = GLUTCallback(
  213.     'Joystick', (ctypes.c_uint,ctypes.c_int,ctypes.c_int,ctypes.c_int), ('buttonMask','x','y','z'),
  214. )
  215. glutKeyboardFunc = GLUTCallback(
  216.     'Keyboard', (ctypes.c_char,ctypes.c_int,ctypes.c_int), ('key','x','y'),
  217. )
  218. glutKeyboardUpFunc = GLUTCallback(
  219.     'KeyboardUp', (ctypes.c_char,ctypes.c_int,ctypes.c_int), ('key','x','y'),
  220. )
  221. glutMenuStatusFunc = GLUTCallback(
  222.     'MenuStatus', (ctypes.c_int,ctypes.c_int,ctypes.c_int), ('status','x','y'),
  223. )
  224. glutMenuStateFunc = GLUTCallback(
  225.     'MenuState', (ctypes.c_int,), ('status',),
  226. )
  227. glutMotionFunc = GLUTCallback(
  228.     'Motion', (ctypes.c_int,ctypes.c_int), ('x','y'),
  229. )
  230. glutMouseFunc = GLUTCallback(
  231.     'Mouse', (ctypes.c_int,ctypes.c_int,ctypes.c_int,ctypes.c_int), ('button','state','x','y'),
  232. )
  233. glutOverlayDisplayFunc = GLUTCallback(
  234.     'OverlayDisplay', (), (),
  235. )
  236. glutPassiveMotionFunc = GLUTCallback(
  237.     'PassiveMotion', (ctypes.c_int,ctypes.c_int), ('x','y'),
  238. )
  239. glutReshapeFunc = GLUTCallback(
  240.     'Reshape', (ctypes.c_int,ctypes.c_int), ('width','height'),
  241. )
  242. glutSpaceballButtonFunc = GLUTCallback(
  243.     'SpaceballButton', (ctypes.c_int,ctypes.c_int), ('button','state'),
  244. )
  245. glutSpaceballMotionFunc = GLUTCallback(
  246.     'SpaceballMotion', (ctypes.c_int,ctypes.c_int,ctypes.c_int), ('x','y','z'),
  247. )
  248. glutSpaceballRotateFunc = GLUTCallback(
  249.     'SpaceballRotate', (ctypes.c_int,ctypes.c_int,ctypes.c_int), ('x','y','z'),
  250. )
  251. glutSpecialFunc = GLUTCallback(
  252.     'Special', (ctypes.c_int,ctypes.c_int,ctypes.c_int), ('key','x','y'),
  253. )
  254. glutSpecialUpFunc = GLUTCallback(
  255.     'SpecialUp', (ctypes.c_int,ctypes.c_int,ctypes.c_int), ('key','x','y'),
  256. )
  257. glutTabletButtonFunc = GLUTCallback(
  258.     'TabletButton', (ctypes.c_int,ctypes.c_int,ctypes.c_int,ctypes.c_int), ('button','state','x','y',),
  259. )
  260. glutTabletButtonFunc = GLUTCallback(
  261.     'TabletButton', (ctypes.c_int,ctypes.c_int,ctypes.c_int,ctypes.c_int), ('button','state','x','y',),
  262. )
  263. glutTabletMotionFunc = GLUTCallback(
  264.     'TabletMotion', (ctypes.c_int,ctypes.c_int), ('x','y',),
  265. )
  266. glutVisibilityFunc = GLUTCallback(
  267.     'Visibility', (ctypes.c_int,), ('state',),
  268. )
  269. glutWindowStatusFunc = GLUTCallback(
  270.     'WindowStatus', (ctypes.c_int,), ('state',),
  271. )
  272.  
  273. # glutTimerFunc is unlike any other GLUT callback-registration...
  274. glutTimerFunc = GLUTTimerCallback(
  275.     'Timer', (ctypes.c_int,), ('value',),
  276. )
  277.  
  278. INITIALIZED = False
  279. def glutInit( *args ):
  280.     """Initialise the GLUT library"""
  281.     global INITIALIZED
  282.     if INITIALIZED:
  283.         return args
  284.     INITIALIZED = True
  285.     if args:
  286.         arg,args = args[0],args[1:]
  287.         count = None
  288.         if isinstance(arg, (int,long)):
  289.             # raw API style, (count, values)
  290.             count = arg
  291.             if count != len(args):
  292.                 raise ValueError( """Specified count of %s does not match length (%s) of argument list %s"""%(
  293.                     count, len(args), args,
  294.                 ))
  295.         elif isinstance( arg, (str,unicode)):
  296.             # passing in a sequence of strings as individual arguments
  297.             args = (arg,)+args 
  298.             count = len(args)
  299.         else:
  300.             args = arg 
  301.             count = len(args)
  302.     else:
  303.         count=0
  304.         args = []
  305.     args = [str(x) for x in args]
  306.     if not count:
  307.         count, args = 1, ['foo']
  308.     holder = (ctypes.c_char_p * len(args))()
  309.     for i,arg in enumerate(args):
  310.         holder[i] = arg
  311.     count = ctypes.c_int( count )
  312.     import os 
  313.     currentDirectory = os.getcwd()
  314.     try:
  315.         # XXX need to check for error condition here...
  316.         _base_glutInit( ctypes.byref(count), holder )
  317.     finally:
  318.         os.chdir( currentDirectory )
  319.     return [
  320.         str(holder[i]) for i in range( count.value )
  321.     ]
  322. glutInit.wrappedOperation = simple.glutInit
  323.  
  324. def glutDestroyWindow( window ):
  325.     """Want to destroy the window, we need to do some cleanup..."""
  326.     context = 0
  327.     try:
  328.         GLUT.glutSetWindow(window)
  329.         context = contextdata.getContext()
  330.         result = contextdata.cleanupContext( context )
  331.         log.info( """Cleaning up context data for window %s: %s""", window, result )
  332.     except Exception, err:
  333.         log.error( """Error attempting to clean up context data for GLUT window %s: %s""", window, result )
  334.     return _base_glutDestroyWindow( window )
  335. glutDestroyWindow.wrappedOperation = simple.glutDestroyWindow
  336.  
  337.