~matobet/pyopengl/Python3

« back to all changes in this revision

Viewing changes to arrays/numpymodule.py

  • Committer: matobet at gmail
  • Date: 2010-06-26 14:11:04 UTC
  • Revision ID: matobet@gmail.com-20100626141104-k011ofmltgiiu60g
Initial

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
"""Numpy (new version) module implementation of the OpenGL-ctypes array interfaces
 
2
 
 
3
XXX Need to register handlers for all of the scalar types that numpy returns,
 
4
would like to have all return values be int/float if they are of  compatible
 
5
type as well.
 
6
"""
 
7
REGISTRY_NAME = 'numpy'
 
8
try:
 
9
    import numpy
 
10
except ImportError as err:
 
11
    raise ImportError( """No numpy module present: %s"""%(err))
 
12
 
 
13
import operator,logging
 
14
import OpenGL
 
15
import ctypes
 
16
c_void_p = ctypes.c_void_p
 
17
from OpenGL import constants, constant, error
 
18
from OpenGL.arrays import formathandler
 
19
log = logging.getLogger( 'OpenGL.arrays.numpymodule' )
 
20
 
 
21
from OpenGL import acceleratesupport
 
22
NumpyHandler = None
 
23
if acceleratesupport.ACCELERATE_AVAILABLE:
 
24
    try:
 
25
        from OpenGL_accelerate.numpy_formathandler import NumpyHandler
 
26
    except ImportError as err:
 
27
        log.warn(
 
28
            "Unable to load numpy_formathandler accelerator from OpenGL_accelerate"
 
29
        )
 
30
if NumpyHandler is None:
 
31
    # numpy's array interface has changed over time :(
 
32
    testArray = numpy.array( [1,2,3,4],'i' )
 
33
    # Numpy's "ctypes" interface actually creates a new ctypes object 
 
34
    # in python for every access of the .ctypes attribute... which can take 
 
35
    # ridiculously large periods when you multiply it by millions of iterations
 
36
    if hasattr(testArray,'__array_interface__'):
 
37
        def dataPointer( cls, instance ):
 
38
            """Convert given instance to a data-pointer value (integer)"""
 
39
            try:
 
40
                return int(instance.__array_interface__['data'][0])
 
41
            except AttributeError as err:
 
42
                instance = cls.asArray( instance )
 
43
                try:
 
44
                    return int(instance.__array_interface__['data'][0])
 
45
                except AttributeError as err:
 
46
                    return int(instance.__array_data__[0],0)
 
47
    else:
 
48
        def dataPointer( cls, instance ):
 
49
            """Convert given instance to a data-pointer value (integer)"""
 
50
            try:
 
51
                return int(instance.__array_data__[0],0)
 
52
            except AttributeError as err:
 
53
                instance = cls.asArray( instance )
 
54
                try:
 
55
                    return int(instance.__array_interface__['data'][0])
 
56
                except AttributeError as err:
 
57
                    return int(instance.__array_data__[0],0)
 
58
    del testArray
 
59
    dataPointer = classmethod( dataPointer )
 
60
 
 
61
 
 
62
    class NumpyHandler( formathandler.FormatHandler ):
 
63
        """Numpy-specific data-type handler for OpenGL
 
64
        
 
65
        Attributes:
 
66
        
 
67
            ERROR_ON_COPY -- if True, will raise errors 
 
68
                if we have to copy an array object in order to produce
 
69
                a contiguous array of the correct type.
 
70
        """
 
71
        HANDLED_TYPES = (numpy.ndarray,)# list, tuple )
 
72
        dataPointer = dataPointer
 
73
        isOutput = True
 
74
        ERROR_ON_COPY = OpenGL.ERROR_ON_COPY
 
75
        @classmethod
 
76
        def zeros( cls, dims, typeCode ):
 
77
            """Return Numpy array of zeros in given size"""
 
78
            return numpy.zeros( dims, GL_TYPE_TO_ARRAY_MAPPING[typeCode])
 
79
        @classmethod
 
80
        def arrayToGLType( cls, value ):
 
81
            """Given a value, guess OpenGL type of the corresponding pointer"""
 
82
            typeCode = value.dtype
 
83
            constant = ARRAY_TO_GL_TYPE_MAPPING.get( typeCode )
 
84
            if constant is None:
 
85
                raise TypeError(
 
86
                    """Don't know GL type for array of type %r, known types: %s\nvalue:%s"""%(
 
87
                        typeCode, list(ARRAY_TO_GL_TYPE_MAPPING.keys()), value,
 
88
                    )
 
89
                )
 
90
            return constant
 
91
        
 
92
        @classmethod
 
93
        def arraySize( cls, value, typeCode = None ):
 
94
            """Given a data-value, calculate dimensions for the array"""
 
95
            return value.size
 
96
        @classmethod
 
97
        def arrayByteCount( cls, value, typeCode = None ):
 
98
            """Given a data-value, calculate number of bytes required to represent"""
 
99
            try:
 
100
                return value.nbytes
 
101
            except AttributeError as err:
 
102
                if cls.ERROR_ON_COPY:
 
103
                    raise error.CopyError(
 
104
                        """Non-numpy array passed to numpy arrayByteCount: %s""",
 
105
                        type(value),
 
106
                    )
 
107
                value = cls.asArray( value, typeCode )
 
108
                return value.nbytes
 
109
        @classmethod
 
110
        def asArray( cls, value, typeCode=None ):
 
111
            """Convert given value to an array value of given typeCode"""
 
112
            if value is None:
 
113
                return value
 
114
            else:
 
115
                return cls.contiguous( value, typeCode )
 
116
 
 
117
        @classmethod
 
118
        def contiguous( cls, source, typeCode=None ):
 
119
            """Get contiguous array from source
 
120
            
 
121
            source -- numpy Python array (or compatible object)
 
122
                for use as the data source.  If this is not a contiguous
 
123
                array of the given typeCode, a copy will be made, 
 
124
                otherwise will just be returned unchanged.
 
125
            typeCode -- optional 1-character typeCode specifier for
 
126
                the numpy.array function.
 
127
                
 
128
            All gl*Pointer calls should use contiguous arrays, as non-
 
129
            contiguous arrays will be re-copied on every rendering pass.
 
130
            Although this doesn't raise an error, it does tend to slow
 
131
            down rendering.
 
132
            """
 
133
            typeCode = GL_TYPE_TO_ARRAY_MAPPING[ typeCode ]
 
134
            try:
 
135
                contiguous = source.flags.contiguous
 
136
            except AttributeError as err:
 
137
                if typeCode:
 
138
                    return numpy.ascontiguousarray( source, typeCode )
 
139
                else:
 
140
                    return numpy.ascontiguousarray( source )
 
141
            else:
 
142
                if contiguous and (typeCode is None or typeCode==source.dtype.char):
 
143
                    return source
 
144
                elif (contiguous and cls.ERROR_ON_COPY):
 
145
                    from OpenGL import error
 
146
                    raise error.CopyError(
 
147
                        """Array of type %r passed, required array of type %r""",
 
148
                        source.dtype.char, typeCode,
 
149
                    )
 
150
                else:
 
151
                    # We have to do astype to avoid errors about unsafe conversions
 
152
                    # XXX Confirm that this will *always* create a new contiguous array 
 
153
                    # XXX Guard against wacky conversion types like uint to float, where
 
154
                    # we really don't want to have the C-level conversion occur.
 
155
                    # XXX ascontiguousarray is apparently now available in numpy!
 
156
                    if cls.ERROR_ON_COPY:
 
157
                        from OpenGL import error
 
158
                        raise error.CopyError(
 
159
                            """Non-contiguous array passed""",
 
160
                            source,
 
161
                        )
 
162
                    if typeCode is None:
 
163
                        typeCode = source.dtype.char
 
164
                    return numpy.ascontiguousarray( source, typeCode )
 
165
        @classmethod
 
166
        def unitSize( cls, value, typeCode=None ):
 
167
            """Determine unit size of an array (if possible)"""
 
168
            return value.shape[-1]
 
169
        @classmethod
 
170
        def dimensions( cls, value, typeCode=None ):
 
171
            """Determine dimensions of the passed array value (if possible)"""
 
172
            return value.shape
 
173
        @classmethod
 
174
        def from_param( cls, instance, typeCode=None ):
 
175
            try:
 
176
                pointer = cls.dataPointer( instance )
 
177
            except TypeError as err:
 
178
                array = cls.asArray( instance, typeCode )
 
179
                pp = cls.dataPointer( array )
 
180
                pp._temporary_array_ = (array,)
 
181
                return pp
 
182
            else:
 
183
                if typeCode and instance.dtype != GL_TYPE_TO_ARRAY_MAPPING[ typeCode ]:
 
184
                    raise error.CopyError(
 
185
                        """Array of type %r passed, required array of type %r""",
 
186
                        instance.dtype.char, typeCode,
 
187
                    )                                   
 
188
                return c_void_p( pointer )
 
189
 
 
190
try:
 
191
    numpy.array( [1], 's' )
 
192
    SHORT_TYPE = 's'
 
193
except TypeError as err:
 
194
    SHORT_TYPE = 'h'
 
195
    USHORT_TYPE = 'H'
 
196
 
 
197
def lookupDtype( char ):
 
198
    return numpy.zeros( (1,), dtype=char ).dtype
 
199
 
 
200
ARRAY_TO_GL_TYPE_MAPPING = {
 
201
    lookupDtype('d'): constants.GL_DOUBLE,
 
202
    lookupDtype('f'): constants.GL_FLOAT,
 
203
    lookupDtype('i'): constants.GL_INT,
 
204
    lookupDtype(SHORT_TYPE): constants.GL_SHORT,
 
205
    lookupDtype(USHORT_TYPE): constants.GL_UNSIGNED_SHORT,
 
206
    lookupDtype('B'): constants.GL_UNSIGNED_BYTE,
 
207
    lookupDtype('c'): constants.GL_UNSIGNED_BYTE,
 
208
    lookupDtype('b'): constants.GL_BYTE,
 
209
    lookupDtype('I'): constants.GL_UNSIGNED_INT,
 
210
    None: None,
 
211
}
 
212
GL_TYPE_TO_ARRAY_MAPPING = {
 
213
    constants.GL_DOUBLE: lookupDtype('d'),
 
214
    constants.GL_FLOAT:lookupDtype('f'),
 
215
    constants.GL_INT: lookupDtype('i'),
 
216
    constants.GL_BYTE: lookupDtype('b'),
 
217
    constants.GL_SHORT: lookupDtype(SHORT_TYPE),
 
218
    constants.GL_UNSIGNED_INT: lookupDtype('I'),
 
219
    constants.GL_UNSIGNED_BYTE: lookupDtype('B'),
 
220
    constants.GL_UNSIGNED_SHORT: lookupDtype(USHORT_TYPE),
 
221
    None: None,
 
222
}
 
 
b'\\ No newline at end of file'