| | """Implementations for common converter types""" |
| | import ctypes,logging |
| | from OpenGL._bytes import bytes, unicode, as_8_bit |
| | from OpenGL._null import NULL |
| | _log = logging.getLogger( 'OpenGL.converters' ) |
| |
|
| | class Converter( object ): |
| | """Base class for Converter types |
| | |
| | Converter objects are callable objects used with the |
| | OpenGL.wrapper.Wrapper class to simplify the wrapping |
| | of functions by collecting commonly used functionality |
| | into a reusable function. |
| | |
| | Each Converter has two (class) attributes: |
| | |
| | argNames -- list of argument names for initialisation |
| | indexLookups -- set of (indexname, argName,methodName) values |
| | to lookup on wrapper. These allow us to use argument-name |
| | references to refer to which arguments to use when |
| | processing (prevents the need to revise pointers when |
| | we change the API for a function). |
| | |
| | Converters can be any of the Wrapper API helper functions, |
| | so the callable interface can vary among Converter classes. |
| | """ |
| | argNames = ( ) |
| | indexLookups = ( ) |
| | def __init__( self, *args, **named ): |
| | """Store arguments in attributes |
| | |
| | *args -- mapped to self.argNames in order to set attributes |
| | **named -- mapped to self.argNames by name to set attributes |
| | """ |
| | argNames = list(self.argNames) |
| | for a in self.argNames: |
| | if a in named: |
| | setattr( self, a, named[a] ) |
| | argNames.remove( a ) |
| | for a,value in zip( argNames, args ): |
| | setattr( self, a, value ) |
| | def finalise( self, wrapper ): |
| | """Look up our indices (where appropriate)""" |
| | for indexname,argName,methodName in self.indexLookups: |
| | setattr( |
| | self, indexname, |
| | getattr(wrapper,methodName)(getattr( self, argName )) |
| | ) |
| |
|
| | |
| | class PyConverter( Converter ): |
| | """Converter sub-class for use in Wrapper.pyConverters |
| | |
| | This class just defines the interface for a pyConverter-style |
| | Converter object |
| | """ |
| | def __call__( self, incoming, function, arguments ): |
| | """Convert incoming argument into compatable data-types |
| | |
| | incoming -- the Python argument for this parameter |
| | function -- the wrapper.Wrapper class we are supporting |
| | arguments -- the complete set of arguments passed to the |
| | function |
| | |
| | |
| | """ |
| | raise NotImplemented( """%s class doesn't implement __call__"""%( |
| | self.__class__.__name__, |
| | )) |
| |
|
| | class CConverter( Converter ): |
| | """Converter sub-class for use in Wrapper.cConverters |
| | |
| | This class just defines the interface for a cConverter-style |
| | Converter object |
| | """ |
| | def __call__( self, pyArgs, index, baseOperation ): |
| | """Calculate C-compatible Python object from Python arguments |
| | |
| | pyArgs -- set of Python argument objects converted by |
| | pyConverters from the incoming arguments |
| | index -- our index in baseOperation.cConverters |
| | baseOperation -- the Wrapper object which we are supporting |
| | """ |
| | raise NotImplemented( """%s class doesn't implement __call__"""%( |
| | self.__class__.__name__, |
| | )) |
| | class ReturnValues( Converter ): |
| | """Converter sub-class for use as Wrapper.returnValues |
| | |
| | This class just defines the interface for a returnValues-style |
| | Converter object |
| | """ |
| | def __call__( self, result, baseOperation, pyArgs, cArgs ): |
| | """Return a final value to the caller |
| | |
| | result -- the raw ctypes result value |
| | baseOperation -- the Wrapper object which we are supporting |
| | pyArgs -- the set of Python arguments produced by pyConverters |
| | cArgs -- the set of C-compatible arguments produced by CConverter |
| | |
| | return the Python object for the final result |
| | """ |
| | raise NotImplemented( """%s class doesn't implement __call__"""%( |
| | self.__class__.__name__, |
| | )) |
| |
|
| | |
| | from OpenGL import acceleratesupport |
| | CallFuncPyConverter = None |
| | if acceleratesupport.ACCELERATE_AVAILABLE: |
| | try: |
| | from OpenGL_accelerate.wrapper import ( |
| | CallFuncPyConverter, DefaultCConverter, getPyArgsName, |
| | ) |
| | from OpenGL_accelerate.arraydatatype import ( |
| | Output,SizedOutput,OutputOrInput,SizedOutputOrInput |
| | ) |
| | from OpenGL_accelerate.wrapper import ( |
| | returnCArgument, returnPyArgument, |
| | ) |
| | except ImportError as err: |
| | _log.warn( |
| | "Unable to load converters accelerators (wrapper, arraydatatype) from OpenGL_accelerate" |
| | ) |
| | CallFuncPyConverter = None |
| | if CallFuncPyConverter is None: |
| | class CallFuncPyConverter( PyConverter ): |
| | """PyConverter that takes a callable and calls it on incoming""" |
| | def __init__( self, function ): |
| | """Store the function""" |
| | self.function = function |
| | def __call__( self, incoming, function, argument ): |
| | """Call our function on incoming""" |
| | return self.function( incoming ) |
| | class DefaultCConverter( CConverter ): |
| | """NULL or Default CConverter, returns same-named Python argument |
| | |
| | Used primarily to allow for specifying a converter that explicitly |
| | says "use the default behaviour". This is *not* a finalise-ing |
| | converter, it is passed in the index explicitly and just retrieves |
| | that index from pyArgs when called. |
| | |
| | Raises informative errors if the index cannot be resolved in pyArgs |
| | """ |
| | def __init__( self, index ): |
| | """Just store index for future access""" |
| | self.index = index |
| | def __call__( self, pyArgs, index, wrapper ): |
| | """Return pyArgs[self.index] or raise a ValueError""" |
| | try: |
| | return pyArgs[ self.index ] |
| | except IndexError as err: |
| | raise ValueError( |
| | """Expected parameter index %r, but pyArgs only length %s"""%( |
| | self.index, |
| | len(pyArgs ) |
| | )) |
| | class getPyArgsName( CConverter ): |
| | """CConverter returning named Python argument |
| | |
| | Intended for use in cConverters, the function returned |
| | retrieves the named pyArg and returns it when called. |
| | """ |
| | argNames = ('name',) |
| | indexLookups = [ ('index','name', 'pyArgIndex' ), ] |
| | __slots__ = ( 'index', 'name') |
| | def __call__( self, pyArgs, index, baseOperation ): |
| | """Return pyArgs[ self.index ]""" |
| | try: |
| | return pyArgs[ self.index ] |
| | except AttributeError as err: |
| | raise RuntimeError( """"Did not resolve parameter index for %r"""%(self.name)) |
| |
|
| | class Output( CConverter ): |
| | """CConverter generating static-size typed output arrays |
| | |
| | Produces an output array of given type (arrayType) and |
| | size using self.lookup() to determine the size of the |
| | array to be produced, where the lookup function is passed |
| | as an initialisation argument. |
| | |
| | Provides also: |
| | |
| | oldStyleReturn( ... ) for use in the default case of |
| | PyOpenGL compatability mode, where result arrays of |
| | size (1,) are returned as scalar values. |
| | """ |
| | argNames = ('name','size','arrayType' ) |
| | indexLookups = [ |
| | ('outIndex','name', 'cArgIndex' ), |
| | ] |
| | __slots__ = ('index','size','arrayType','outIndex','inIndex') |
| | def __call__( self, pyArgs, index, baseOperation ): |
| | """Return pyArgs[ self.index ]""" |
| | return self.arrayType.zeros( self.getSize(pyArgs) ) |
| | def getSize( self, pyArgs ): |
| | """Retrieve the array size for this argument""" |
| | return self.size |
| | def oldStyleReturn( self, result, baseOperation, pyArgs, cArgs ): |
| | """Retrieve cArgs[ self.index ]""" |
| | result = cArgs[ self.outIndex ] |
| | try: |
| | thisSize = self.getSize(pyArgs) |
| | except KeyError as err: |
| | return result |
| | if thisSize == (1,): |
| | try: |
| | return result[0] |
| | except TypeError as err: |
| | return result |
| | else: |
| | return result |
| | class OutputOrInput( Output ): |
| | DO_OUTPUT = (None,NULL) |
| | def __call__( self, pyArgs, index, baseOperation ): |
| | for do_output in self.DO_OUTPUT: |
| | if pyArgs[index] is do_output: |
| | return super( OutputOrInput,self ).__call__( pyArgs, index, baseOperation ) |
| | return self.arrayType.asArray( pyArgs[index] ) |
| |
|
| | class SizedOutput( Output ): |
| | """Output generating dynamically-sized typed output arrays |
| | |
| | Takes an extra parameter "specifier", which is the name of |
| | a Python argument to be passed to the lookup function in order |
| | to determine the appropriate size for the output array. |
| | """ |
| | argNames = ('name','specifier','lookup','arrayType' ) |
| | indexLookups = [ |
| | ('outIndex','name', 'cArgIndex' ), |
| | ('index','specifier', 'pyArgIndex' ), |
| | ] |
| | __slots__ = ('index','specifier','lookup','arrayType') |
| | def getSize( self, pyArgs ): |
| | """Retrieve the array size for this argument""" |
| | try: |
| | specifier = pyArgs[ self.index ] |
| | except AttributeError as err: |
| | raise RuntimeError( """"Did not resolve parameter index for %r"""%(self.name)) |
| | else: |
| | try: |
| | return self.lookup( specifier ) |
| | except KeyError as err: |
| | raise KeyError( """Unknown specifier %s"""%( specifier )) |
| | class SizedOutputOrInput( SizedOutput ): |
| | DO_OUTPUT = (None,NULL) |
| | def __call__( self, pyArgs, index, baseOperation ): |
| | for do_output in self.DO_OUTPUT: |
| | if pyArgs[index] is do_output: |
| | return super( SizedOutputOrInput,self ).__call__( pyArgs, index, baseOperation ) |
| | return self.arrayType.asArray( pyArgs[index] ) |
| | class returnCArgument( ReturnValues ): |
| | """ReturnValues returning the named cArgs value""" |
| | argNames = ('name',) |
| | indexLookups = [ ('index','name', 'cArgIndex' ), ] |
| | __slots__ = ( 'index', 'name' ) |
| | def __call__( self, result, baseOperation, pyArgs, cArgs ): |
| | """Retrieve cArgs[ self.index ]""" |
| | return cArgs[self.index] |
| |
|
| | class returnPyArgument( ReturnValues ): |
| | """ReturnValues returning the named pyArgs value""" |
| | argNames = ('name',) |
| | indexLookups = [ ('index','name', 'pyArgIndex' ), ] |
| | __slots__ = ( 'index', 'name' ) |
| | def __call__( self, result, baseOperation, pyArgs, cArgs ): |
| | """Retrieve pyArgs[ self.index ]""" |
| | return pyArgs[self.index] |
| |
|
| | class StringLengths( CConverter ): |
| | """CConverter for processing array-of-pointers-to-strings data-type |
| | |
| | Converter is a CConverter for the array-of-lengths for a |
| | array-of-pointers-to-strings data-type used to pass a set |
| | of code fragments to the GLSL compiler. |
| | |
| | Provides also: |
| | |
| | stringArray -- PyConverter callable ensuring list-of-strings |
| | format for the python argument |
| | |
| | stringArrayForC -- CResolver converting the array to |
| | POINTER(c_char_p) format for passing to C |
| | |
| | totalCount -- CConverter callable giving count of string |
| | pointers (that is, length of the pointer array) |
| | """ |
| | argNames = ('name',) |
| | indexLookups = [ ('index','name', 'pyArgIndex' ), ] |
| | __slots__ = () |
| | def __call__( self, pyArgs, index, baseOperation ): |
| | """Get array of length integers for string contents""" |
| | from OpenGL.raw.GL import _types |
| | tmp = [len(x) for x in pyArgs[self.index]] |
| | a_type = _types.GLint * len(tmp) |
| | return a_type( *tmp ) |
| | def totalCount( self, pyArgs, index, baseOperation ): |
| | """Get array of length integers for string contents""" |
| | return len(pyArgs[self.index]) |
| | def stringArray( self, arg, baseOperation, args ): |
| | """Create basic array-of-strings object from pyArg""" |
| | if isinstance( arg, (bytes,unicode) ): |
| | arg = [arg] |
| | value = [as_8_bit(x) for x in arg] |
| | return value |
| | def stringArrayForC( self, strings ): |
| | """Create a ctypes pointer to char-pointer set""" |
| | from OpenGL import arrays |
| | result = (ctypes.c_char_p * len(strings))() |
| | for i,s in enumerate(strings): |
| | result[i] = ctypes.cast( |
| | arrays.GLcharARBArray.dataPointer(s), |
| | ctypes.c_char_p, |
| | ) |
| | return result |
| |
|