1"""Helper functions for wrapping array-using operations 2 3These are functions intended to be used in wrapping 4GL functions that deal with OpenGL array data-types. 5""" 6import OpenGL 7import ctypes 8from OpenGL import _configflags 9from OpenGL import contextdata, error, converters 10from OpenGL.arrays import arraydatatype 11from OpenGL._bytes import bytes,unicode 12import logging 13_log = logging.getLogger( 'OpenGL.arrays.arrayhelpers' ) 14from OpenGL import acceleratesupport 15AsArrayTypedSizeChecked = None 16if acceleratesupport.ACCELERATE_AVAILABLE: 17 try: 18 from OpenGL_accelerate.arraydatatype import AsArrayTypedSizeChecked 19 from OpenGL_accelerate.wrapper import returnPyArgumentIndex 20 from OpenGL_accelerate.arraydatatype import ( 21 AsArrayOfType,AsArrayTyped,AsArrayTypedSize 22 ) 23 except ImportError as err: 24 _log.warn( 25 "Unable to load arrayhelpers accelerator from OpenGL_accelerate" 26 ) 27if AsArrayTypedSizeChecked is None: 28 def returnPointer( result,baseOperation,pyArgs,cArgs, ): 29 """Return the converted object as result of function 30 31 Note: this is a hack that always returns pyArgs[0]! 32 """ 33 return pyArgs[0] 34 class AsArrayOfType( converters.PyConverter ): 35 """Given arrayName and typeName coerce arrayName to array of type typeName 36 37 TODO: It should be possible to drop this if ERROR_ON_COPY, 38 as array inputs always have to be the final objects in that 39 case. 40 """ 41 argNames = ( 'arrayName','typeName' ) 42 indexLookups = ( 43 ('arrayIndex', 'arrayName','pyArgIndex'), 44 ('typeIndex', 'typeName','pyArgIndex'), 45 ) 46 def __init__( self, arrayName='pointer', typeName='type' ): 47 self.arrayName = arrayName 48 self.typeName = typeName 49 def __call__( self, arg, wrappedOperation, args): 50 """Get the arg as an array of the appropriate type""" 51 type = args[ self.typeIndex ] 52 arrayType = arraydatatype.GL_CONSTANT_TO_ARRAY_TYPE[ type ] 53 return arrayType.asArray( arg ) 54 class AsArrayTyped( converters.PyConverter ): 55 """Given arrayName and arrayType, convert arrayName to array of type 56 57 TODO: It should be possible to drop this if ERROR_ON_COPY, 58 as array inputs always have to be the final objects in that 59 case. 60 """ 61 argNames = ( 'arrayName','arrayType' ) 62 indexLookups = ( 63 ('arrayIndex', 'arrayName','pyArgIndex'), 64 ) 65 def __init__( self, arrayName='pointer', arrayType=None ): 66 self.arrayName = arrayName 67 self.arrayType = arrayType 68 def __call__( self, arg, wrappedOperation, args): 69 """Get the arg as an array of the appropriate type""" 70 return self.arrayType.asArray( arg ) 71 class AsArrayTypedSize( converters.CConverter ): 72 """Given arrayName and arrayType, determine size of arrayName 73 """ 74 argNames = ( 'arrayName','arrayType' ) 75 indexLookups = ( 76 ('arrayIndex', 'arrayName','pyArgIndex'), 77 ) 78 def __init__( self, arrayName='pointer', arrayType=None ): 79 self.arrayName = arrayName 80 self.arrayType = arrayType 81 def __call__( self, pyArgs, index, wrappedOperation ): 82 """Get the arg as an array of the appropriate type""" 83 return self.arrayType.arraySize( pyArgs[self.arrayIndex ] ) 84else: 85 returnPointer = returnPyArgumentIndex( 0 ) 86 87if not _configflags.ERROR_ON_COPY: 88 def asArrayType( typ, size=None ): 89 """Create PyConverter to get first argument as array of type""" 90 return converters.CallFuncPyConverter( typ.asArray ) 91else: 92 def asArrayType( typ, size=None ): 93 """No converter required""" 94 return None 95 96if not _configflags.ARRAY_SIZE_CHECKING: 97 asArrayTypeSize = asArrayType 98else: 99 if AsArrayTypedSizeChecked: 100 asArrayTypeSize = AsArrayTypedSizeChecked 101 else: 102 def asArrayTypeSize( typ, size ): 103 """Create PyConverter function to get array as type and check size 104 105 Produces a raw function, not a PyConverter instance 106 """ 107 asArray = typ.asArray 108 dataType = typ.typeConstant 109 arraySize = typ.arraySize 110 expectedBytes = ctypes.sizeof( typ.baseType ) * size 111 def asArraySize( incoming, function, args ): 112 handler = typ.getHandler( incoming ) 113 result = handler.asArray( incoming, dataType ) 114 # check that the number of bytes expected is present... 115 byteSize = handler.arrayByteCount( result ) 116 if byteSize != expectedBytes: 117 raise ValueError( 118 """Expected %r byte array, got %r byte array"""%( 119 expectedBytes, 120 byteSize, 121 ), 122 incoming, 123 ) 124 return result 125 return asArraySize 126 127 128if not _configflags.ERROR_ON_COPY: 129 def asVoidArray( ): 130 """Create PyConverter returning incoming as an array of any type""" 131 from OpenGL.arrays import ArrayDatatype 132 return converters.CallFuncPyConverter( ArrayDatatype.asArray ) 133else: 134 def asVoidArray( ): 135 """If there's no copying allowed, we can use default passing""" 136 return None 137 138class storePointerType( object ): 139 """Store named pointer value in context indexed by constant 140 141 pointerName -- named pointer argument 142 constant -- constant used to index in the context storage 143 144 Note: OpenGL.STORE_POINTERS can be set with ERROR_ON_COPY 145 to ignore this storage operation. 146 147 Stores the pyArgs (i.e. result of pyConverters) for the named 148 pointer argument... 149 """ 150 def __init__( self, pointerName, constant ): 151 self.pointerName = pointerName 152 self.constant = constant 153 def finalise( self, wrapper ): 154 self.pointerIndex = wrapper.pyArgIndex( self.pointerName ) 155 def __call__( self, result, baseOperation, pyArgs, cArgs ): 156 contextdata.setValue( self.constant, pyArgs[self.pointerIndex] ) 157 158 159def setInputArraySizeType( baseOperation, size, type, argName=0 ): 160 """Decorate function with vector-handling code for a single argument 161 162 if OpenGL.ERROR_ON_COPY is False, then we return the 163 named argument, converting to the passed array type, 164 optionally checking that the array matches size. 165 166 if OpenGL.ERROR_ON_COPY is True, then we will dramatically 167 simplify this function, only wrapping if size is True, i.e. 168 only wrapping if we intend to do a size check on the array. 169 """ 170 from OpenGL import wrapper 171 return wrapper.wrapper( baseOperation ).setInputArraySize( argName, size ) 172 173def arraySizeOfFirstType( typ, default ): 174 unitSize = typ.unitSize 175 def arraySizeOfFirst( pyArgs, index, baseOperation ): 176 """Return the array size of the first argument""" 177 array = pyArgs[0] 178 if array is None: 179 return default 180 else: 181 return unitSize( array ) 182 return arraySizeOfFirst 183