1
"""Implementation of GLU Nurbs structure and callback methods
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.
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
14
from OpenGL.platform import PLATFORM
19
'gluNewNurbsRenderer',
21
'gluNurbsCallbackData',
22
'gluNurbsCallbackDataEXT',
28
# /usr/include/GL/glu.h 242
29
class GLUnurbs(glustruct.GLUStruct, simple.GLUnurbs):
30
"""GLU Nurbs structure with oor and callback storage support
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.
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...
45
# mapping from "which" GLU enumeration to a ctypes function type
46
simple.GLU_NURBS_BEGIN: FUNCTION_TYPE(
49
simple.GLU_NURBS_BEGIN_DATA: FUNCTION_TYPE(
50
None, simple.GLenum, ctypes.POINTER(simple.GLvoid)
52
simple.GLU_NURBS_VERTEX: FUNCTION_TYPE(
53
None, ctypes.POINTER(simple.GLfloat)
55
simple.GLU_NURBS_VERTEX_DATA: FUNCTION_TYPE(
56
None, ctypes.POINTER(simple.GLfloat), ctypes.POINTER(simple.GLvoid)
58
simple.GLU_NURBS_NORMAL: FUNCTION_TYPE(
59
None, ctypes.POINTER(simple.GLfloat)
61
simple.GLU_NURBS_NORMAL_DATA: FUNCTION_TYPE(
62
None, ctypes.POINTER(simple.GLfloat), ctypes.POINTER(simple.GLvoid)
64
simple.GLU_NURBS_COLOR: FUNCTION_TYPE(
65
None, ctypes.POINTER(simple.GLfloat)
67
simple.GLU_NURBS_COLOR_DATA: FUNCTION_TYPE(
68
None, ctypes.POINTER(simple.GLfloat), ctypes.POINTER(simple.GLvoid)
70
simple.GLU_NURBS_TEXTURE_COORD: FUNCTION_TYPE(
71
None, ctypes.POINTER(simple.GLfloat)
73
simple.GLU_NURBS_TEXTURE_COORD_DATA: FUNCTION_TYPE(
74
None, ctypes.POINTER(simple.GLfloat), ctypes.POINTER(simple.GLvoid)
76
simple.GLU_NURBS_END:FUNCTION_TYPE(
79
simple.GLU_NURBS_END_DATA: FUNCTION_TYPE(
80
None, ctypes.POINTER(simple.GLvoid)
82
simple.GLU_NURBS_ERROR:FUNCTION_TYPE(
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,
101
def _justOOR( self, function ):
102
"""Just do OOR on the last argument..."""
104
args = args[:-1] + (self.originalObject(args[-1]),)
105
return function( *args )
107
def _vec3( self, function, size=3 ):
108
"""Convert first arg to size-element array, do OOR on arg2 if present"""
110
vec = self.ptrAsArray(args[0],size,arrays.GLfloatArray)
112
oor = self.originalObject(args[1])
113
return function( vec, oor )
115
return function( 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
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
129
oor = self.originalObject(args[1])
130
return function( args[0], oor )
132
return function( args[0] )
135
# XXX yes, this is a side-effect...
136
simple.gluNewNurbsRenderer.restype = ctypes.POINTER( GLUnurbs )
138
def _callbackWithType( funcType ):
139
"""Get gluNurbsCallback function with set last arg-type"""
140
result = platform.copyBaseFunction(
141
simple.gluNurbsCallback
143
result.argtypes = [ctypes.POINTER(GLUnurbs), simple.GLenum, funcType]
144
assert result.argtypes[-1] == funcType
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
154
def gluNurbsCallback( nurb, which, CallBackFunc ):
155
"""Dispatch to the nurb's addCallback operation"""
156
return nurb.addCallback( which, CallBackFunc )
158
@lazy( simple.gluNewNurbsRenderer )
159
def gluNewNurbsRenderer( baseFunction ):
160
"""Return a new nurbs renderer for the system (dereferences pointer)"""
161
newSet = baseFunction()
163
#new.__class__ = GLUnurbs # yes, I know, ick
166
@lazy( simple.gluNurbsCallbackData )
167
def gluNurbsCallbackData( baseFunction, nurb, userData ):
168
"""Note the Python object for use as userData by the nurb"""
170
nurb, nurb.noteObject( userData )
174
def checkOrder( order,knotCount,name ):
175
"""Check that order is valid..."""
177
raise error.GLUError(
178
"""%s should be 1 or more, is %s"""%( name,order,)
180
elif order > MAX_ORDER:
181
raise error.GLUError(
182
"""%s should be %s or less, is %s"""%( name, MAX_ORDER, order)
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)
188
def checkKnots( knots, name ):
189
"""Check that knots are in ascending order"""
192
for next in knots[1:]:
194
raise error.GLUError(
195
"""%s has decreasing knot %s after %s"""%( name, next, knot )
198
@lazy( simple.gluNurbsCallbackDataEXT )
199
def gluNurbsCallbackDataEXT( baseFunction,nurb, userData ):
200
"""Note the Python object for use as userData by the nurb"""
202
nurb, nurb.noteObject( userData )
205
@lazy( simple.gluNurbsCurve )
206
def gluNurbsCurve( baseFunction, nurb, knots, control, type ):
207
"""Pythonic version of gluNurbsCurve
209
Calculates knotCount, stride, and order automatically
211
knots = arrays.GLfloatArray.asArray( knots )
212
knotCount = arrays.GLfloatArray.arraySize( knots )
213
control = arrays.GLfloatArray.asArray( control )
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')
223
nurb, knotCount, knots, step, control, order, type,
226
@lazy( simple.gluNurbsSurface )
227
def gluNurbsSurface( baseFunction, nurb, sKnots, tKnots, control, type ):
228
"""Pythonic version of gluNurbsSurface
230
Calculates knotCount, stride, and order automatically
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 )
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
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,
260
result = baseFunction(
261
nurb, sKnotCount, sKnots, tKnotCount, tKnots,
262
sStride, tStride, control,
268
@lazy( simple.gluPwlCurve )
269
def gluPwlCurve( baseFunction, nurb, data, type ):
270
"""gluPwlCurve -- piece-wise linear curve within GLU context
272
data -- the data-array
273
type -- determines number of elements/data-point
275
data = arrays.GLfloatArray.asArray( data )
276
if type == simple.GLU_MAP1_TRIM_2:
278
elif type == simple.GLU_MAP_TRIM_3:
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 )