~matobet/pyopengl/Python3

« back to all changes in this revision

Viewing changes to GLU/glunurbs.py.bak

  • 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
"""Implementation of GLU Nurbs structure and callback methods
 
2
 
 
3
Same basic pattern as seen with the gluTess* functions, just need to
 
4
add some bookkeeping to the structure class so that we can keep the
 
5
Python function references alive during the calling process.
 
6
"""
 
7
from OpenGL.raw import GLU as simple
 
8
from OpenGL import platform, converters, wrapper
 
9
from OpenGL.GLU import glustruct
 
10
from OpenGL.lazywrapper import lazy
 
11
from OpenGL import arrays, error
 
12
import ctypes
 
13
import weakref
 
14
from OpenGL.platform import PLATFORM
 
15
import OpenGL
 
16
 
 
17
__all__ = (
 
18
    'GLUnurbs',
 
19
    'gluNewNurbsRenderer',
 
20
    'gluNurbsCallback',
 
21
    'gluNurbsCallbackData',
 
22
    'gluNurbsCallbackDataEXT',
 
23
    'gluNurbsCurve',
 
24
    'gluNurbsSurface',
 
25
    'gluPwlCurve',
 
26
)
 
27
 
 
28
# /usr/include/GL/glu.h 242
 
29
class GLUnurbs(glustruct.GLUStruct, simple.GLUnurbs):
 
30
    """GLU Nurbs structure with oor and callback storage support
 
31
    
 
32
    IMPORTANT NOTE: the texture coordinate callback receives a raw ctypes 
 
33
    data-pointer, as without knowing what type of evaluation is being done 
 
34
    (1D or 2D) we cannot safely determine the size of the array to convert 
 
35
    it.  This is a limitation of the C implementation.  To convert to regular 
 
36
    data-pointer, just call yourNurb.ptrAsArray( ptr, size, arrays.GLfloatArray )
 
37
    with the size of data you expect.
 
38
    """
 
39
    FUNCTION_TYPE = PLATFORM.functionTypeFor(PLATFORM.GLU)
 
40
    CALLBACK_FUNCTION_REGISTRARS = {
 
41
        # mapping from "which" to a function that should take 3 parameters,
 
42
        # the nurb, the which and the function pointer...
 
43
    }
 
44
    CALLBACK_TYPES = {
 
45
        # mapping from "which" GLU enumeration to a ctypes function type
 
46
        simple.GLU_NURBS_BEGIN: FUNCTION_TYPE( 
 
47
            None, simple.GLenum 
 
48
        ),
 
49
        simple.GLU_NURBS_BEGIN_DATA: FUNCTION_TYPE( 
 
50
            None, simple.GLenum, ctypes.POINTER(simple.GLvoid) 
 
51
        ),
 
52
        simple.GLU_NURBS_VERTEX: FUNCTION_TYPE( 
 
53
            None, ctypes.POINTER(simple.GLfloat)
 
54
        ),
 
55
        simple.GLU_NURBS_VERTEX_DATA: FUNCTION_TYPE( 
 
56
            None, ctypes.POINTER(simple.GLfloat), ctypes.POINTER(simple.GLvoid) 
 
57
        ),
 
58
        simple.GLU_NURBS_NORMAL: FUNCTION_TYPE( 
 
59
            None, ctypes.POINTER(simple.GLfloat)
 
60
        ),
 
61
        simple.GLU_NURBS_NORMAL_DATA: FUNCTION_TYPE( 
 
62
            None, ctypes.POINTER(simple.GLfloat), ctypes.POINTER(simple.GLvoid) 
 
63
        ),
 
64
        simple.GLU_NURBS_COLOR: FUNCTION_TYPE( 
 
65
            None, ctypes.POINTER(simple.GLfloat)
 
66
        ),
 
67
        simple.GLU_NURBS_COLOR_DATA: FUNCTION_TYPE( 
 
68
            None, ctypes.POINTER(simple.GLfloat), ctypes.POINTER(simple.GLvoid) 
 
69
        ),
 
70
        simple.GLU_NURBS_TEXTURE_COORD: FUNCTION_TYPE( 
 
71
            None, ctypes.POINTER(simple.GLfloat)
 
72
        ),
 
73
        simple.GLU_NURBS_TEXTURE_COORD_DATA: FUNCTION_TYPE( 
 
74
            None, ctypes.POINTER(simple.GLfloat), ctypes.POINTER(simple.GLvoid) 
 
75
        ),
 
76
        simple.GLU_NURBS_END:FUNCTION_TYPE( 
 
77
            None
 
78
        ),
 
79
        simple.GLU_NURBS_END_DATA: FUNCTION_TYPE( 
 
80
            None, ctypes.POINTER(simple.GLvoid) 
 
81
        ),
 
82
        simple.GLU_NURBS_ERROR:FUNCTION_TYPE( 
 
83
            None, simple.GLenum, 
 
84
        ),
 
85
    }
 
86
    WRAPPER_METHODS = {
 
87
        simple.GLU_NURBS_BEGIN: None,
 
88
        simple.GLU_NURBS_BEGIN_DATA: '_justOOR',
 
89
        simple.GLU_NURBS_VERTEX: '_vec3',
 
90
        simple.GLU_NURBS_VERTEX_DATA: '_vec3',
 
91
        simple.GLU_NURBS_NORMAL: '_vec3',
 
92
        simple.GLU_NURBS_NORMAL_DATA: '_vec3',
 
93
        simple.GLU_NURBS_COLOR: '_vec4',
 
94
        simple.GLU_NURBS_COLOR_DATA: '_vec4',
 
95
        simple.GLU_NURBS_TEXTURE_COORD: '_tex',
 
96
        simple.GLU_NURBS_TEXTURE_COORD_DATA: '_tex',
 
97
        simple.GLU_NURBS_END: None,
 
98
        simple.GLU_NURBS_END_DATA: '_justOOR',
 
99
        simple.GLU_NURBS_ERROR: None,
 
100
    }
 
101
    def _justOOR( self, function ):
 
102
        """Just do OOR on the last argument..."""
 
103
        def getOOR( *args ):
 
104
            args = args[:-1] + (self.originalObject(args[-1]),)
 
105
            return function( *args )
 
106
        return getOOR
 
107
    def _vec3( self, function, size=3 ):
 
108
        """Convert first arg to size-element array, do OOR on arg2 if present"""
 
109
        def vec( *args ):
 
110
            vec = self.ptrAsArray(args[0],size,arrays.GLfloatArray)
 
111
            if len(args) > 1:
 
112
                oor = self.originalObject(args[1])
 
113
                return function( vec, oor )
 
114
            else:
 
115
                return function( vec )
 
116
        return vec
 
117
    def _vec4( self, function ):
 
118
        """Size-4 vector version..."""
 
119
        return self._vec3( function, 4 )
 
120
    def _tex( self, function ):
 
121
        """Texture coordinate callback 
 
122
        
 
123
        NOTE: there is no way for *us* to tell what size the array is, you will 
 
124
        get back a raw data-point, not an array, as you do for all other callback 
 
125
        types!!!
 
126
        """
 
127
        def oor( *args ):
 
128
            if len(args) > 1:
 
129
                oor = self.originalObject(args[1])
 
130
                return function( args[0], oor )
 
131
            else:
 
132
                return function( args[0] )
 
133
        return oor
 
134
 
 
135
# XXX yes, this is a side-effect...
 
136
simple.gluNewNurbsRenderer.restype = ctypes.POINTER( GLUnurbs )
 
137
 
 
138
def _callbackWithType( funcType ):
 
139
    """Get gluNurbsCallback function with set last arg-type"""
 
140
    result =  platform.copyBaseFunction(
 
141
        simple.gluNurbsCallback
 
142
    )
 
143
    result.argtypes = [ctypes.POINTER(GLUnurbs), simple.GLenum, funcType]
 
144
    assert result.argtypes[-1] == funcType
 
145
    return result
 
146
 
 
147
for (c,funcType) in GLUnurbs.CALLBACK_TYPES.items():
 
148
    cb = _callbackWithType( funcType )
 
149
    GLUnurbs.CALLBACK_FUNCTION_REGISTRARS[ c ] = cb
 
150
    assert funcType == GLUnurbs.CALLBACK_TYPES[c]
 
151
    assert cb.argtypes[-1] == funcType
 
152
del c,cb, funcType
 
153
 
 
154
def gluNurbsCallback( nurb, which, CallBackFunc ):
 
155
    """Dispatch to the nurb's addCallback operation"""
 
156
    return nurb.addCallback( which, CallBackFunc )
 
157
 
 
158
@lazy( simple.gluNewNurbsRenderer )
 
159
def gluNewNurbsRenderer( baseFunction ):
 
160
    """Return a new nurbs renderer for the system (dereferences pointer)"""
 
161
    newSet = baseFunction()
 
162
    new = newSet[0]
 
163
    #new.__class__ = GLUnurbs # yes, I know, ick
 
164
    return new
 
165
 
 
166
@lazy( simple.gluNurbsCallbackData )
 
167
def gluNurbsCallbackData( baseFunction, nurb, userData ):
 
168
    """Note the Python object for use as userData by the nurb"""
 
169
    return baseFunction( 
 
170
        nurb, nurb.noteObject( userData ) 
 
171
    )
 
172
 
 
173
MAX_ORDER = 8
 
174
def checkOrder( order,knotCount,name ):
 
175
    """Check that order is valid..."""
 
176
    if order < 1:
 
177
        raise error.GLUError( 
 
178
            """%s should be 1 or more, is %s"""%( name,order,) 
 
179
        )
 
180
    elif order > MAX_ORDER:
 
181
        raise error.GLUError( 
 
182
            """%s should be %s or less, is %s"""%( name, MAX_ORDER, order) 
 
183
        )
 
184
    elif knotCount < (2*order):
 
185
        raise error.GLUError( 
 
186
            """Knotcount must be at least 2x %s is %s should be at least %s"""%( name, knotCount, 2*order) 
 
187
        )
 
188
def checkKnots( knots, name ):
 
189
    """Check that knots are in ascending order"""
 
190
    if len(knots):
 
191
        knot = knots[0]
 
192
        for next in knots[1:]:
 
193
            if next < knot:
 
194
                raise error.GLUError(
 
195
                    """%s has decreasing knot %s after %s"""%( name, next, knot )
 
196
                )
 
197
 
 
198
@lazy( simple.gluNurbsCallbackDataEXT )
 
199
def gluNurbsCallbackDataEXT( baseFunction,nurb, userData ):
 
200
    """Note the Python object for use as userData by the nurb"""
 
201
    return baseFunction( 
 
202
        nurb, nurb.noteObject( userData ) 
 
203
    )
 
204
 
 
205
@lazy( simple.gluNurbsCurve )
 
206
def gluNurbsCurve( baseFunction, nurb, knots, control, type ):
 
207
    """Pythonic version of gluNurbsCurve
 
208
    
 
209
    Calculates knotCount, stride, and order automatically
 
210
    """
 
211
    knots = arrays.GLfloatArray.asArray( knots )
 
212
    knotCount = arrays.GLfloatArray.arraySize( knots )
 
213
    control = arrays.GLfloatArray.asArray( control )
 
214
    try:
 
215
        length,step = arrays.GLfloatArray.dimensions( control )
 
216
    except ValueError, err:
 
217
        raise error.GLUError( """Need a 2-dimensional control array""" )
 
218
    order = knotCount - length
 
219
    if OpenGL.ERROR_CHECKING:
 
220
        checkOrder( order, knotCount, 'order of NURBS curve')
 
221
        checkKnots( knots, 'knots of NURBS curve')
 
222
    return baseFunction(
 
223
        nurb, knotCount, knots, step, control, order, type,
 
224
    )
 
225
 
 
226
@lazy( simple.gluNurbsSurface )
 
227
def gluNurbsSurface( baseFunction, nurb, sKnots, tKnots, control, type ):
 
228
    """Pythonic version of gluNurbsSurface
 
229
    
 
230
    Calculates knotCount, stride, and order automatically
 
231
    """
 
232
    sKnots = arrays.GLfloatArray.asArray( sKnots )
 
233
    sKnotCount = arrays.GLfloatArray.arraySize( sKnots )
 
234
    tKnots = arrays.GLfloatArray.asArray( tKnots )
 
235
    tKnotCount = arrays.GLfloatArray.arraySize( tKnots )
 
236
    control = arrays.GLfloatArray.asArray( control )
 
237
 
 
238
    try:
 
239
        length,width,step = arrays.GLfloatArray.dimensions( control )
 
240
    except ValueError, err:
 
241
        raise error.GLUError( """Need a 3-dimensional control array""" )
 
242
    sOrder = sKnotCount - length 
 
243
    tOrder = tKnotCount - width 
 
244
    sStride = width*step
 
245
    tStride = step
 
246
    if OpenGL.ERROR_CHECKING:
 
247
        checkOrder( sOrder, sKnotCount, 'sOrder of NURBS surface')
 
248
        checkOrder( tOrder, tKnotCount, 'tOrder of NURBS surface')
 
249
        checkKnots( sKnots, 'sKnots of NURBS surface')
 
250
        checkKnots( tKnots, 'tKnots of NURBS surface')
 
251
    if not (sKnotCount-sOrder)*(tKnotCount-tOrder) == length*width:
 
252
        raise error.GLUError(
 
253
            """Invalid NURB structure""",
 
254
            nurb, sKnotCount, sKnots, tKnotCount, tKnots,
 
255
            sStride, tStride, control,
 
256
            sOrder,tOrder,
 
257
            type
 
258
        )
 
259
 
 
260
    result = baseFunction(
 
261
        nurb, sKnotCount, sKnots, tKnotCount, tKnots,
 
262
        sStride, tStride, control,
 
263
        sOrder,tOrder,
 
264
        type
 
265
    )
 
266
    return result
 
267
 
 
268
@lazy( simple.gluPwlCurve )
 
269
def gluPwlCurve( baseFunction, nurb, data, type ):
 
270
    """gluPwlCurve -- piece-wise linear curve within GLU context
 
271
    
 
272
    data -- the data-array 
 
273
    type -- determines number of elements/data-point
 
274
    """
 
275
    data = arrays.GLfloatArray.asArray( data )
 
276
    if type == simple.GLU_MAP1_TRIM_2:
 
277
        divisor = 2
 
278
    elif type == simple.GLU_MAP_TRIM_3:
 
279
        divisor = 3
 
280
    else:
 
281
        raise ValueError( """Unrecognised type constant: %s"""%(type))
 
282
    size = arrays.GLfloatArray.arraySize( data )
 
283
    size = int(size//divisor)
 
284
    return baseFunction( nurb, size, data, divisor, type )