Registering Callbacks and Basic Callback Handling

Major Callbacks to Register

All callbacks are registered with the following common method:

void gluTessCallback(GLUtesselator* tObj, GLenum callbackType, void (*cbFcn)());
"callbackType"expected "cbFcn" prototype
GLU_TESS_BEGINvoid beginCB(GLenum mode);
GLU_TESS_VERTEXvoid vertexCB(void* pvas);
GLU_TESS_ENDvoid endCB();
GLU_TESS_ERRORvoid errorCB(GLenum errorCode);

As indicated in the table, most of the tessellation callbacks take one or more parameters; hence you will need to type-cast actual parameters. Assuming you have executed:

GLUtesselator* tObj = gluNewTess();

and assuming you have created the following typedef:

typedef GLvoid (*parameterlessCallbackType)();

do as indicated in the following table:

Given function prototypeRegister your callback handler as
void tessBeginCB(GLenum mode); gluTessCallback(tObj,GLU_TESS_BEGIN, reinterpret_cast<parameterlessCallbackType>(tessBeginCB));
void tessVertexCB(void* pva); gluTessCallback(tObj,GLU_TESS_VERTEX, reinterpret_cast<parameterlessCallbackType>(tessVertexCB));
void tessEndCB(); gluTessCallback(tObj,GLU_TESS_END, tessEndCB); // No need for type-cast
void tessErrorCB(GLenum e); gluTessCallback(tObj,GLU_TESS_ERROR, reinterpret_cast<parameterlessCallbackType>(tessErrorCB));

If you want your callbacks to be methods of a class, they must be class (not instance) methods; i.e., they must be declared as "static" in the class definition. Hence:

Given class method declarationsRegister your callback handler as
class SceneElement
{
    …
    static void tessBeginCB(GLenum mode);
    static void tessVertexCB(void* pva);
    static void tessEndCB();
    static void tessErrorCB(GLenum e);
    …
};
gluTessCallback(tObj,GLU_TESS_BEGIN, reinterpret_cast<parameterlessCallbackType>(SceneElement::tessBeginCB));
gluTessCallback(tObj,GLU_TESS_VERTEX, reinterpret_cast<parameterlessCallbackType>(SceneElement::tessVertexCB));
gluTessCallback(tObj,GLU_TESS_END, SceneElement::tessEndCB); // No need for type-cast
gluTessCallback(tObj,GLU_TESS_ERROR, reinterpret_cast<parameterlessCallbackType>(SceneElement::tessErrorCB));

Expectations of the Registered Callback Functions

(Some of this material may make more sense after studying Step 3 of Part 1.)

When you call gluTessEndPolygon, the algorithm to do the tessellation starts, and it will begin calling your callbacks in sequences like:

yourTessBeginCB, yourTessVertexCB, …, yourTessVertexCB, yourTessEndCB

You will need to create two buffers: (i) a coordinate buffer to hold vertex coordinates as they are delivered to your vertex callback, and (ii) a buffer to hold the glDrawArrays data you will be recording as the callbacks are made.

The basic idea is the following:

When control returns to your code from the gluEndPolygon call, you need to copy the coordinate buffer data to the GPU in the usual way (i.e., using glGenBuffers-glBindBuffer-glBufferData along with the usual glVertexAttribPointer and glEnableVertexAttribArray calls). The "glDrawArrays buffer" you created will just remain a CPU-side data structure as one of your ModelView subclass instance variables and will be used as described in Part 2. It should look something like:

GL_TRIANGLE_STRIP020
GL_TRIANGLE_STRIP2013
GL_TRIANGLES333

Because we never make mistakes, there will be no need to worry about the GLU_TESS_ERROR callback.

Yeah, right.

Your error callback will be invoked if the algorithm detects a problem of some sort. The GLenum passed to it is an error code. There is a utility function for obtaining a string representation for any such error code. You can implement your error callback something like:

void tessErrorCB(GLenum e)
{
    std::cerr << static_cast<const unsigned char*>(gluErrorString(e)) << std::endl;

    // On the most recent Mac OS release, "gluErrorString" seems to have disappeared. If you get compilation errors
    // related to this funtion, you will need to do instead:
    // std::cerr << static_cast<int>(e) << std::endl;
}

Note

In your GLU_TESS_VERTEX callback, you will need to cast the void* formal parameter that comes in:

void tessVertexCB(void* pvaAsVoid)
{
    double* xyz = reinterpret_cast<double*> (pvaAsVoid);
    …
}