1"""Exceptional cases that need some extra wrapping"""
2from OpenGL import arrays
3from OpenGL.arrays.arraydatatype import GLfloatArray
4from OpenGL.lazywrapper import lazy as _lazy
5from OpenGL.GL.VERSION import GL_1_1 as full
6from OpenGL.raw.GL import _errors
7from OpenGL._bytes import bytes
8from OpenGL import _configflags
9from OpenGL._null import NULL as _NULL
10import ctypes
11
12__all__ = [
13    'glBegin',
14    'glCallLists',
15    'glColor',
16    'glDeleteTextures',
17    'glEnd',
18    'glMap1d',
19    'glMap1f',
20    'glMap2d',
21    'glMap2f',
22    'glMaterial',
23    'glRasterPos',
24    'glTexParameter',
25    'glVertex',
26    'glAreTexturesResident',
27]
28
29glRasterPosDispatch = {
30    2: full.glRasterPos2d,
31    3: full.glRasterPos3d,
32    4: full.glRasterPos4d,
33}
34
35if _configflags.ERROR_CHECKING:
36    @_lazy( full.glBegin )
37    def glBegin( baseFunction, mode ):
38        """Begin GL geometry-definition mode, disable automatic error checking"""
39        _errors._error_checker.onBegin( )
40        return baseFunction( mode )
41    @_lazy( full.glEnd )
42    def glEnd( baseFunction ):
43        """Finish GL geometry-definition mode, re-enable automatic error checking"""
44        _errors._error_checker.onEnd( )
45        return baseFunction( )
46else:
47    glBegin = full.glBegin
48    glEnd = full.glEnd
49
50@_lazy( full.glDeleteTextures )
51def glDeleteTextures( baseFunction, size, array=_NULL ):
52    """Delete specified set of textures
53
54    If array is *not* passed then `size` must be a `GLuintArray`
55    compatible object which can be sized using `arraySize`, the
56    result of which will be used as size.
57    """
58    if array is _NULL:
59        ptr = arrays.GLuintArray.asArray( size )
60        size = arrays.GLuintArray.arraySize( ptr )
61    else:
62        ptr = array
63    return baseFunction( size, ptr )
64
65
66def glMap2( baseFunction, arrayType ):
67    def glMap2( target, u1, u2, v1, v2, points):
68        """glMap2(target, u1, u2, v1, v2, points[][][]) -> None
69
70        This is a completely non-standard signature which doesn't allow for most
71        of the funky uses with strides and the like, but it has been like this for
72        a very long time...
73        """
74        ptr = arrayType.asArray( points )
75        uorder,vorder,vstride = arrayType.dimensions( ptr )
76        ustride = vstride*vorder
77        return baseFunction(
78            target,
79            u1, u2,
80            ustride, uorder,
81            v1, v2,
82            vstride, vorder,
83            ptr
84        )
85    glMap2.__name__ = baseFunction.__name__
86    glMap2.baseFunction = baseFunction
87    return glMap2
88glMap2d = glMap2( full.glMap2d, arrays.GLdoubleArray )
89glMap2f = glMap2( full.glMap2f, arrays.GLfloatArray )
90try:
91    del glMap2
92except NameError as err:
93    pass
94
95def glMap1( baseFunction, arrayType ):
96    def glMap1(target,u1,u2,points):
97        """glMap1(target, u1, u2, points[][][]) -> None
98
99        This is a completely non-standard signature which doesn't allow for most
100        of the funky uses with strides and the like, but it has been like this for
101        a very long time...
102        """
103        ptr = arrayType.asArray( points )
104        dims = arrayType.dimensions( ptr )
105        uorder = dims[0]
106        ustride = dims[1]
107        return baseFunction( target, u1,u2,ustride,uorder, ptr )
108    glMap1.__name__ == baseFunction.__name__
109    glMap1.baseFunction = baseFunction
110    return glMap1
111glMap1d = glMap1( full.glMap1d, arrays.GLdoubleArray )
112glMap1f = glMap1( full.glMap1f, arrays.GLfloatArray )
113try:
114    del glMap1
115except NameError as err:
116    pass
117
118def glRasterPos( *args ):
119    """Choose glRasterPosX based on number of args"""
120    if len(args) == 1:
121        # v form...
122        args = args[0]
123    function = glRasterPosDispatch[ len(args) ]
124    return function( *args )
125
126glVertexDispatch = {
127    2: full.glVertex2d,
128    3: full.glVertex3d,
129    4: full.glVertex4d,
130}
131def glVertex( *args ):
132    """Choose glVertexX based on number of args"""
133    if len(args) == 1:
134        # v form...
135        args = args[0]
136    return glVertexDispatch[ len(args) ]( *args )
137
138@_lazy( full.glCallLists )
139def glCallLists( baseFunction, lists, *args ):
140    """glCallLists( bytes( lists ) or lists[] ) -> None
141
142    Restricted version of glCallLists, takes a string or a GLuint compatible
143    array data-type and passes into the base function.
144    """
145    if not len(args):
146        if isinstance( lists, bytes ):
147            return baseFunction(
148                len(lists),
149                full.GL_UNSIGNED_BYTE,
150                ctypes.c_void_p(arrays.GLubyteArray.dataPointer( lists )),
151            )
152        ptr = arrays.GLuintArray.asArray( lists )
153        size = arrays.GLuintArray.arraySize( ptr )
154        return baseFunction(
155            size,
156            full.GL_UNSIGNED_INT,
157            ctypes.c_void_p( arrays.GLuintArray.dataPointer(ptr))
158        )
159    return baseFunction( lists, *args )
160
161def glTexParameter( target, pname, parameter ):
162    """Set a texture parameter, choose underlying call based on pname and parameter"""
163    if isinstance( parameter, float ):
164        return full.glTexParameterf( target, pname, parameter )
165    elif isinstance( parameter, int ):
166        return full.glTexParameteri( target, pname, parameter )
167    else:
168        value = GLfloatArray.asArray( parameter, full.GL_FLOAT )
169        return full.glTexParameterfv( target, pname, value )
170
171def glMaterial( faces, constant, *args ):
172    """glMaterial -- convenience function to dispatch on argument type
173
174    If passed a single argument in args, calls:
175        glMaterialfv( faces, constant, args[0] )
176    else calls:
177        glMaterialf( faces, constant, *args )
178    """
179    if len(args) == 1:
180        arg = GLfloatArray.asArray( args[0] )
181        if arg is None:
182            raise ValueError( """Null value in glMaterial: %s"""%(args,) )
183        return full.glMaterialfv( faces, constant, arg )
184    else:
185        return full.glMaterialf( faces, constant, *args )
186
187glColorDispatch = {
188    3: full.glColor3fv,
189    4: full.glColor4fv,
190}
191
192def glColor( *args ):
193    """glColor*f* -- convenience function to dispatch on argument type
194
195    dispatches to glColor3f, glColor2f, glColor4f, glColor3f, glColor2f, glColor4f
196    depending on the arguments passed...
197    """
198    arglen = len(args)
199    if arglen == 1:
200        arg = arrays.GLfloatArray.asArray( args[0] )
201        function = glColorDispatch[arrays.GLfloatArray.arraySize( arg )]
202        return function( arg )
203    elif arglen == 2:
204        return full.glColor2d( *args )
205    elif arglen == 3:
206        return full.glColor3d( *args )
207    elif arglen == 4:
208        return full.glColor4d( *args )
209    else:
210        raise ValueError( """Don't know how to handle arguments: %s"""%(args,))
211
212
213# Rectagle coordinates,
214@_lazy( full.glAreTexturesResident )
215def glAreTexturesResident( baseFunction, *args ):
216    """Allow both Pythonic and C-style calls to glAreTexturesResident
217
218        glAreTexturesResident( arrays.GLuintArray( textures) )
219
220    or
221
222        glAreTexturesResident( int(n), arrays.GLuintArray( textures), arrays.GLuboolean( output) )
223
224    or
225
226        glAreTexturesResident( int(n), arrays.GLuintArray( textures) )
227
228    returns the output arrays.GLubooleanArray
229    """
230    if len(args) == 1:
231        # Pythonic form...
232        textures = args[0]
233        textures = arrays.GLuintArray.asArray( textures )
234        n = arrays.GLuintArray.arraySize(textures)
235        output = arrays.GLbooleanArray.zeros( (n,))
236    elif len(args) == 2:
237        try:
238            n = int( args[0] )
239        except TypeError:
240            textures = args[0]
241            textures = arrays.GLuintArray.asArray( textures )
242
243            n = arrays.GLuintArray.arraySize(textures)
244            output = args[1]
245            output = arrays.GLbooleanArray.asArray( output )
246        else:
247            textures = args[1]
248            textures = arrays.GLuintArray.asArray( textures )
249
250            output = arrays.GLbooleanArray.zeros( (n,))
251    elif len(args) == 3:
252        n,textures,output = args
253        textures = arrays.GLuintArray.asArray( textures )
254        output = arrays.GLbooleanArray.asArray( output )
255    else:
256        raise TypeError( """Expected 1 to 3 arguments to glAreTexturesResident""" )
257    texturePtr = arrays.GLuintArray.typedPointer( textures )
258    outputPtr = arrays.GLbooleanArray.typedPointer( output )
259    result = baseFunction( n, texturePtr, outputPtr )
260    if result:
261        # weirdness of the C api, doesn't produce values if all are true
262        for i in range(len(output)):
263            output[i] = 1
264    return output
265