"""Wrapper/Implementation of the GLU tessellator objects for PyOpenGL""" from OpenGL.raw import GLU as _simple from OpenGL.raw.GL.VERSION import GL_1_1 from OpenGL.platform import createBaseFunction from OpenGL.GLU import glustruct from OpenGL import arrays, wrapper from OpenGL.platform import PLATFORM GLU = PLATFORM.GLU from OpenGL.lazywrapper import lazy as _lazy import ctypes class GLUtesselator(glustruct.GLUStruct, _simple.GLUtesselator): """Implementation class for GLUTessellator structures in OpenGL-ctypes""" FUNCTION_TYPE = PLATFORM.functionTypeFor(PLATFORM.GLU) CALLBACK_TYPES = { # mapping from "which" GLU enumeration to a ctypes function type _simple.GLU_TESS_BEGIN: FUNCTION_TYPE(None, _simple.GLenum), _simple.GLU_TESS_BEGIN_DATA: FUNCTION_TYPE( None, _simple.GLenum, ctypes.c_void_p ), _simple.GLU_TESS_EDGE_FLAG: FUNCTION_TYPE(None, _simple.GLboolean), _simple.GLU_TESS_EDGE_FLAG_DATA: FUNCTION_TYPE( None, _simple.GLboolean, ctypes.c_void_p ), _simple.GLU_TESS_VERTEX: FUNCTION_TYPE(None, ctypes.c_void_p), _simple.GLU_TESS_VERTEX_DATA: FUNCTION_TYPE( None, ctypes.c_void_p, ctypes.c_void_p ), _simple.GLU_TESS_END: FUNCTION_TYPE(None), _simple.GLU_TESS_END_DATA: FUNCTION_TYPE(None, ctypes.c_void_p), _simple.GLU_TESS_COMBINE: FUNCTION_TYPE( None, ctypes.POINTER(_simple.GLdouble), ctypes.POINTER(ctypes.c_void_p), ctypes.POINTER(_simple.GLfloat), ctypes.POINTER(ctypes.c_void_p), ), _simple.GLU_TESS_COMBINE_DATA: FUNCTION_TYPE( None, ctypes.POINTER(_simple.GLdouble), ctypes.POINTER(ctypes.c_void_p), ctypes.POINTER(_simple.GLfloat), ctypes.POINTER(ctypes.c_void_p), ctypes.c_void_p, ), _simple.GLU_TESS_ERROR: FUNCTION_TYPE(None, _simple.GLenum), _simple.GLU_TESS_ERROR_DATA: FUNCTION_TYPE( None, _simple.GLenum, ctypes.c_void_p ), _simple.GLU_ERROR: FUNCTION_TYPE(None, _simple.GLenum), } WRAPPER_METHODS = { _simple.GLU_TESS_BEGIN_DATA: 'dataWrapper', _simple.GLU_TESS_EDGE_FLAG_DATA: 'dataWrapper', _simple.GLU_TESS_VERTEX: 'vertexWrapper', _simple.GLU_TESS_VERTEX_DATA: 'vertexWrapper', _simple.GLU_TESS_END_DATA: 'dataWrapper', _simple.GLU_TESS_COMBINE: 'combineWrapper', _simple.GLU_TESS_COMBINE_DATA: 'combineWrapper', _simple.GLU_TESS_ERROR_DATA: 'dataWrapper', } def gluTessVertex(self, location, data=None): """Add a vertex to this tessellator, storing data for later lookup""" vertexCache = getattr(self, 'vertexCache', None) if vertexCache is None: self.vertexCache = [] vertexCache = self.vertexCache location = arrays.GLdoubleArray.asArray(location, GL_1_1.GL_DOUBLE) if arrays.GLdoubleArray.arraySize(location) != 3: raise ValueError( """Require 3 doubles for array location, got: %s""" % (location,) ) oorValue = self.noteObject(data) vp = ctypes.c_void_p(oorValue) self.vertexCache.append(location) return gluTessVertexBase(self, location, vp) def gluTessBeginPolygon(self, data): """Note the object pointer to return it as a Python object""" return _simple.gluTessBeginPolygon(self, ctypes.c_void_p(self.noteObject(data))) def combineWrapper(self, function): """Wrap a Python function with ctypes-compatible wrapper for combine callback For a Python combine callback, the signature looks like this: def combine( GLdouble coords[3], void *vertex_data[4], GLfloat weight[4] ): return data While the C signature looks like this: void combine( GLdouble coords[3], void *vertex_data[4], GLfloat weight[4], void **outData ) """ if (function is not None) and (not hasattr(function, '__call__')): raise TypeError("""Require a callable callback, got: %s""" % (function,)) def wrap(coords, vertex_data, weight, outData, *args): """The run-time wrapper around the function""" coords = self.ptrAsArray(coords, 3, arrays.GLdoubleArray) weight = self.ptrAsArray(weight, 4, arrays.GLfloatArray) # find the original python objects for vertex data vertex_data = [self.originalObject(vertex_data[i]) for i in range(4)] args = tuple([self.originalObject(x) for x in args]) try: result = function(coords, vertex_data, weight, *args) except Exception as err: raise err.__class__( """Failure during combine callback %r with args( %s,%s,%s,*%s):\n%s""" % ( function, coords, vertex_data, weight, args, str(err), ) ) outP = ctypes.c_void_p(self.noteObject(result)) if outData: outData[0] = outP else: raise RuntimeError("Null outData passed to callback") return None return wrap def dataWrapper(self, function): """Wrap a function which only has the one data-pointer as last arg""" if (function is not None) and (not hasattr(function, '__call__')): raise TypeError("""Require a callable callback, got: %s""" % (function,)) def wrap(*args): """Just return the original object for polygon_data""" args = args[:-1] + (self.originalObject(args[-1]),) try: return function(*args) except Exception as err: err.args += (function, args) raise return wrap def dataWrapper2(self, function): """Wrap a function which has two data-pointers as last args""" if (function is not None) and (not hasattr(function, '__call__')): raise TypeError("""Require a callable callback, got: %s""" % (function,)) def wrap(*args): """Just return the original object for polygon_data""" args = args[:-2] + ( self.originalObject(args[-2]), self.originalObject(args[-1]), ) try: return function(*args) except Exception as err: err.args += (function, args) raise return wrap def vertexWrapper(self, function): """Converts a vertex-pointer into an OOR vertex for processing""" if (function is not None) and (not hasattr(function, '__call__')): raise TypeError("""Require a callable callback, got: %s""" % (function,)) def wrap(vertex, data=None): """Just return the original object for polygon_data""" vertex = self.originalObject(vertex) try: if data is not None: data = self.originalObject(data) return function(vertex, data) else: return function(vertex) except Exception as err: err.args += (function, (vertex, data)) raise return wrap c = funcType = None GLUtesselator.CALLBACK_FUNCTION_REGISTRARS = dict( [ ( c, createBaseFunction( 'gluTessCallback', dll=GLU, resultType=None, argTypes=[ctypes.POINTER(GLUtesselator), _simple.GLenum, funcType], doc='gluTessCallback( POINTER(GLUtesselator)(tess), GLenum(which), _GLUfuncptr(CallBackFunc) ) -> None', argNames=('tess', 'which', 'CallBackFunc'), ), ) for (c, funcType) in GLUtesselator.CALLBACK_TYPES.items() ] ) try: del c, funcType except NameError as err: pass def gluTessCallback(tess, which, function): """Set a given gluTessellator callback for the given tessellator""" return tess.addCallback(which, function) def gluTessBeginPolygon(tess, data): """Start definition of polygon in the tessellator""" return tess.gluTessBeginPolygon(data) def gluTessVertex(tess, location, data=None): """Add a vertex to the tessellator's current polygon""" return tess.gluTessVertex(location, data) # /usr/include/GL/glu.h 293 @_lazy( createBaseFunction( 'gluNewTess', dll=GLU, resultType=ctypes.POINTER(GLUtesselator), doc='gluNewTess( ) -> POINTER(GLUtesselator)', ) ) def gluNewTess(baseFunction): """Get a new tessellator object (just unpacks the pointer for you)""" return baseFunction()[0] @_lazy(_simple.gluGetTessProperty) def gluGetTessProperty(baseFunction, tess, which, data=None): """Retrieve single double for a tessellator property""" if data is None: data = _simple.GLdouble(0.0) baseFunction(tess, which, data) return data.value else: return baseFunction(tess, which, data) gluTessVertexBase = wrapper.wrapper(_simple.gluTessVertex).setInputArraySize( 'location', 3, ) __all__ = ( 'gluNewTess', 'gluGetTessProperty', 'gluTessBeginPolygon', 'gluTessCallback', 'gluTessVertex', )