|
"""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 = { |
|
|
|
_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) |
|
|
|
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) |
|
|
|
|
|
|
|
@_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', |
|
) |
|
|