Viewing file: lists.py (6.93 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
"""Lists/tuples as data-format for storage
Note: This implementation is *far* less efficient than using Numpy to support lists/tuples, as the code here is all available in C-level code there. This implementation is required to allow for usage without numpy installed. """ REGISTRY_NAME = 'ctypesarrays' import ctypes, _ctypes
from OpenGL import constants, constant, error, ERROR_ON_COPY from OpenGL.arrays import formathandler HANDLED_TYPES = (list,tuple) import operator
def err_on_copy( func ): """Decorator which raises informative error if we try to copy while ERROR_ON_COPY""" if not ERROR_ON_COPY: return func else: def raiseErrorOnCopy( self, value, *args, **named ): raise error.CopyError( """%s passed, cannot copy with ERROR_ON_COPY set, please use an array type which has native data-pointer support (e.g. numpy or ctypes arrays)"""%( value.__class__.__name__, ) ) raiseErrorOnCopy.__name__ = func.__name__ return raiseErrorOnCopy
class ListHandler( formathandler.FormatHandler ): """Storage of array data in Python lists/arrays
This mechanism, unlike multi-dimensional arrays, is not necessarily uniform in type or dimension, so we have to do a lot of extra checks to make sure that we get a correctly-structured array. That, as well as the need to copy the arrays in Python code, makes this a far less efficient implementation than the numpy implementation, which does all the same things, but does them all in C code.
Note: as an *output* format, this format handler produces ctypes arrays, not Python lists, this is done for convenience in coding the implementation, mostly. """ @err_on_copy def from_param( self, instance, typeCode=None ): try: return ctypes.byref( instance ) except TypeError, err: array = self.asArray( instance, typeCode ) pp = ctypes.c_void_p( ctypes.addressof( array ) ) pp._temporary_array_ = (array,) return pp dataPointer = staticmethod( ctypes.addressof ) HANDLED_TYPES = HANDLED_TYPES isOutput = True @err_on_copy def voidDataPointer( cls, value ): """Given value in a known data-pointer type, return void_p for pointer""" return ctypes.byref( value ) def zeros( self, dims, typeCode ): """Return array of zeros in given size""" type = GL_TYPE_TO_ARRAY_MAPPING[ typeCode ] for dim in dims: type *= dim return type() # should expicitly set to 0s def dimsOf( cls, x ): """Calculate total dimension-set of the elements in x This is *extremely* messy, as it has to track nested arrays where the arrays could be different sizes on all sorts of levels... """ try: dimensions = [ len(x) ] except (TypeError,AttributeError,ValueError), err: return [] else: childDimension = None for child in x: newDimension = cls.dimsOf( child ) if childDimension is not None: if newDimension != childDimension: raise ValueError( """Non-uniform array encountered: %s versus %s"""%( newDimension, childDimension, ), x ) dimsOf = classmethod( dimsOf )
def arrayToGLType( self, value ): """Given a value, guess OpenGL type of the corresponding pointer"""
result = ARRAY_TO_GL_TYPE_MAPPING.get( value._type_ ) if result is not None: return result raise TypeError( """Don't know GL type for array of type %r, known types: %s\nvalue:%s"""%( value._type_, ARRAY_TO_GL_TYPE_MAPPING.keys(), value, ) ) def arraySize( self, value, typeCode = None ): """Given a data-value, calculate dimensions for the array""" dims = 1 for base in self.types( value ): length = getattr( base, '_length_', None) if length is not None: dims *= length return dims def types( self, value ): """Produce iterable producing all composite types""" dimObject = value while dimObject is not None: yield dimObject dimObject = getattr( dimObject, '_type_', None ) if isinstance( dimObject, (str,unicode)): dimObject = None def dims( self, value ): """Produce iterable of all dimensions""" for base in self.types( value ): length = getattr( base, '_length_', None) if length is not None: yield length @err_on_copy def asArray( self, value, typeCode=None ): """Convert given value to a ctypes array value of given typeCode This does a *lot* of work just to get the data into the correct format. It's not going to be anywhere near as fast as a numpy or similar approach! """ if typeCode is None: raise NotImplementedError( """Haven't implemented type-inference for lists yet""" ) arrayType = GL_TYPE_TO_ARRAY_MAPPING[ typeCode ] if isinstance( value, (list,tuple)): subItems = [ self.asArray( item, typeCode ) for item in value ] if subItems: for dim in self.dimensions( subItems[0] )[::-1]: arrayType *= dim arrayType *= len( subItems ) result = arrayType() result[:] = subItems return result else: return arrayType( value ) @err_on_copy def unitSize( self, value, typeCode=None ): """Determine unit size of an array (if possible)""" return tuple(self.dims(value))[-1] @err_on_copy def dimensions( self, value, typeCode=None ): """Determine dimensions of the passed array value (if possible)""" return tuple( self.dims(value) )
ARRAY_TO_GL_TYPE_MAPPING = { constants.GLdouble: constants.GL_DOUBLE, constants.GLfloat: constants.GL_FLOAT, constants.GLint: constants.GL_INT, constants.GLuint: constants.GL_UNSIGNED_INT, constants.GLshort: constants.GL_SHORT, constants.GLushort: constants.GL_UNSIGNED_SHORT, constants.GLchar: constants.GL_CHAR, constants.GLbyte: constants.GL_BYTE, constants.GLubyte: constants.GL_UNSIGNED_BYTE, } GL_TYPE_TO_ARRAY_MAPPING = { constants.GL_DOUBLE: constants.GLdouble, constants.GL_FLOAT: constants.GLfloat, constants.GL_INT: constants.GLint, constants.GL_UNSIGNED_INT: constants.GLuint, constants.GL_SHORT: constants.GLshort, constants.GL_UNSIGNED_SHORT: constants.GLushort, constants.GL_CHAR: constants.GLchar, constants.GL_BYTE: constants.GLbyte, constants.GL_UNSIGNED_BYTE: constants.GLubyte, }
|