~matobet/pyopengl/Python3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
"""Numpy (new version) module implementation of the OpenGL-ctypes array interfaces

XXX Need to register handlers for all of the scalar types that numpy returns,
would like to have all return values be int/float if they are of  compatible
type as well.
"""
REGISTRY_NAME = 'numpy'
try:
    import numpy
except ImportError as err:
    raise ImportError( """No numpy module present: %s"""%(err))

import operator,logging
import OpenGL
import ctypes
c_void_p = ctypes.c_void_p
from OpenGL import constants, constant, error
from OpenGL.arrays import formathandler
log = logging.getLogger( 'OpenGL.arrays.numpymodule' )

from OpenGL import acceleratesupport
NumpyHandler = None
if acceleratesupport.ACCELERATE_AVAILABLE:
    try:
        from OpenGL_accelerate.numpy_formathandler import NumpyHandler
    except ImportError as err:
        log.warn(
            "Unable to load numpy_formathandler accelerator from OpenGL_accelerate"
        )
if NumpyHandler is None:
    # numpy's array interface has changed over time :(
    testArray = numpy.array( [1,2,3,4],'i' )
    # Numpy's "ctypes" interface actually creates a new ctypes object 
    # in python for every access of the .ctypes attribute... which can take 
    # ridiculously large periods when you multiply it by millions of iterations
    if hasattr(testArray,'__array_interface__'):
        def dataPointer( cls, instance ):
            """Convert given instance to a data-pointer value (integer)"""
            try:
                return int(instance.__array_interface__['data'][0])
            except AttributeError as err:
                instance = cls.asArray( instance )
                try:
                    return int(instance.__array_interface__['data'][0])
                except AttributeError as err:
                    return int(instance.__array_data__[0],0)
    else:
        def dataPointer( cls, instance ):
            """Convert given instance to a data-pointer value (integer)"""
            try:
                return int(instance.__array_data__[0],0)
            except AttributeError as err:
                instance = cls.asArray( instance )
                try:
                    return int(instance.__array_interface__['data'][0])
                except AttributeError as err:
                    return int(instance.__array_data__[0],0)
    del testArray
    dataPointer = classmethod( dataPointer )


    class NumpyHandler( formathandler.FormatHandler ):
        """Numpy-specific data-type handler for OpenGL
        
        Attributes:
        
            ERROR_ON_COPY -- if True, will raise errors 
                if we have to copy an array object in order to produce
                a contiguous array of the correct type.
        """
        HANDLED_TYPES = (numpy.ndarray,)# list, tuple )
        dataPointer = dataPointer
        isOutput = True
        ERROR_ON_COPY = OpenGL.ERROR_ON_COPY
        @classmethod
        def zeros( cls, dims, typeCode ):
            """Return Numpy array of zeros in given size"""
            return numpy.zeros( dims, GL_TYPE_TO_ARRAY_MAPPING[typeCode])
        @classmethod
        def arrayToGLType( cls, value ):
            """Given a value, guess OpenGL type of the corresponding pointer"""
            typeCode = value.dtype
            constant = ARRAY_TO_GL_TYPE_MAPPING.get( typeCode )
            if constant is None:
                raise TypeError(
                    """Don't know GL type for array of type %r, known types: %s\nvalue:%s"""%(
                        typeCode, list(ARRAY_TO_GL_TYPE_MAPPING.keys()), value,
                    )
                )
            return constant
        
        @classmethod
        def arraySize( cls, value, typeCode = None ):
            """Given a data-value, calculate dimensions for the array"""
            return value.size
        @classmethod
        def arrayByteCount( cls, value, typeCode = None ):
            """Given a data-value, calculate number of bytes required to represent"""
            try:
                return value.nbytes
            except AttributeError as err:
                if cls.ERROR_ON_COPY:
                    raise error.CopyError(
                        """Non-numpy array passed to numpy arrayByteCount: %s""",
                        type(value),
                    )
                value = cls.asArray( value, typeCode )
                return value.nbytes
        @classmethod
        def asArray( cls, value, typeCode=None ):
            """Convert given value to an array value of given typeCode"""
            if value is None:
                return value
            else:
                return cls.contiguous( value, typeCode )

        @classmethod
        def contiguous( cls, source, typeCode=None ):
            """Get contiguous array from source
            
            source -- numpy Python array (or compatible object)
                for use as the data source.  If this is not a contiguous
                array of the given typeCode, a copy will be made, 
                otherwise will just be returned unchanged.
            typeCode -- optional 1-character typeCode specifier for
                the numpy.array function.
                
            All gl*Pointer calls should use contiguous arrays, as non-
            contiguous arrays will be re-copied on every rendering pass.
            Although this doesn't raise an error, it does tend to slow
            down rendering.
            """
            typeCode = GL_TYPE_TO_ARRAY_MAPPING[ typeCode ]
            try:
                contiguous = source.flags.contiguous
            except AttributeError as err:
                if typeCode:
                    return numpy.ascontiguousarray( source, typeCode )
                else:
                    return numpy.ascontiguousarray( source )
            else:
                if contiguous and (typeCode is None or typeCode==source.dtype.char):
                    return source
                elif (contiguous and cls.ERROR_ON_COPY):
                    from OpenGL import error
                    raise error.CopyError(
                        """Array of type %r passed, required array of type %r""",
                        source.dtype.char, typeCode,
                    )
                else:
                    # We have to do astype to avoid errors about unsafe conversions
                    # XXX Confirm that this will *always* create a new contiguous array 
                    # XXX Guard against wacky conversion types like uint to float, where
                    # we really don't want to have the C-level conversion occur.
                    # XXX ascontiguousarray is apparently now available in numpy!
                    if cls.ERROR_ON_COPY:
                        from OpenGL import error
                        raise error.CopyError(
                            """Non-contiguous array passed""",
                            source,
                        )
                    if typeCode is None:
                        typeCode = source.dtype.char
                    return numpy.ascontiguousarray( source, typeCode )
        @classmethod
        def unitSize( cls, value, typeCode=None ):
            """Determine unit size of an array (if possible)"""
            return value.shape[-1]
        @classmethod
        def dimensions( cls, value, typeCode=None ):
            """Determine dimensions of the passed array value (if possible)"""
            return value.shape
        @classmethod
        def from_param( cls, instance, typeCode=None ):
            try:
                pointer = cls.dataPointer( instance )
            except TypeError as err:
                array = cls.asArray( instance, typeCode )
                pp = cls.dataPointer( array )
                pp._temporary_array_ = (array,)
                return pp
            else:
                if typeCode and instance.dtype != GL_TYPE_TO_ARRAY_MAPPING[ typeCode ]:
                    raise error.CopyError(
                        """Array of type %r passed, required array of type %r""",
                        instance.dtype.char, typeCode,
                    )					
                return c_void_p( pointer )

try:
    numpy.array( [1], 's' )
    SHORT_TYPE = 's'
except TypeError as err:
    SHORT_TYPE = 'h'
    USHORT_TYPE = 'H'

def lookupDtype( char ):
    return numpy.zeros( (1,), dtype=char ).dtype

ARRAY_TO_GL_TYPE_MAPPING = {
    lookupDtype('d'): constants.GL_DOUBLE,
    lookupDtype('f'): constants.GL_FLOAT,
    lookupDtype('i'): constants.GL_INT,
    lookupDtype(SHORT_TYPE): constants.GL_SHORT,
    lookupDtype(USHORT_TYPE): constants.GL_UNSIGNED_SHORT,
    lookupDtype('B'): constants.GL_UNSIGNED_BYTE,
    lookupDtype('c'): constants.GL_UNSIGNED_BYTE,
    lookupDtype('b'): constants.GL_BYTE,
    lookupDtype('I'): constants.GL_UNSIGNED_INT,
    None: None,
}
GL_TYPE_TO_ARRAY_MAPPING = {
    constants.GL_DOUBLE: lookupDtype('d'),
    constants.GL_FLOAT:lookupDtype('f'),
    constants.GL_INT: lookupDtype('i'),
    constants.GL_BYTE: lookupDtype('b'),
    constants.GL_SHORT: lookupDtype(SHORT_TYPE),
    constants.GL_UNSIGNED_INT: lookupDtype('I'),
    constants.GL_UNSIGNED_BYTE: lookupDtype('B'),
    constants.GL_UNSIGNED_SHORT: lookupDtype(USHORT_TYPE),
    None: None,
}