Using GLU Tesselator

From LWJGL
Jump to: navigation, search

The primitive structure class.

/**
 * A class to store a single OpenGL primitive (ie a triangle, triangle_loop etc.) returned 
 * from the tesselator.
 *
 * @author Quew8
 */
class Primitive {
    /**
     * The OpenGL constant defining the type of this primitive 
     * 
     */
    public final int type;

    /**
     * A list of the indices of the vertices required to draw this primitive.
     * 
     */
    public final ArrayList<Integer> vertices = new ArrayList<>();

    public Primitive(int type) {
        this.type = type;
    }

    private String getTypeString() {
        switch(type) {
        case GL11.GL_TRIANGLES: return "GL_TRIANGLES";
        case GL11.GL_TRIANGLE_STRIP: return "GL_TRIANGLE_STRIP";
        case GL11.GL_TRIANGLE_FAN: return "GL_TRIANGLE_FAN";
        default: return Integer.toString(type);
        }
    }

    @Override
    public String toString() {
        String s = "New Primitive " + getTypeString();
        for(int i = 0; i < vertices.size(); i++) {
            s += "\nIndex: " + vertices.get(i);
        }
        return s;
    }
}

The Tessellator class.

/**
 * A class to interface with the GLU tessellator.
 * Constructs a series of primitives to draw the complex shape. You describe to it. 
 *
 * A single instance of this class can be reused as many times as desired.
 *
 * @author Quew8
 */
class Tessellator extends GLUtessellatorImpl {
    /**
     * A list of the primitives
     */
    public ArrayList<Primitive> primitives = new ArrayList<Primitive>();

    public Tessellator() {
        GLUtessellatorCallbackAdapter callback = new GLUtessellatorCallbackAdapter() {
            @Override
            public void begin(int type) {
                Tessellator.this.primitives.add(new Primitive(type));
            }

            @Override
            public void vertex(Object vertexData) {
                Integer coords = (Integer) vertexData;
                Tessellator.this.getLastPrimitive().vertices.add(coords);
            }

            @Override
            public void error(int errnum) {
                throw new RuntimeException("GLU Error " + GLU.gluErrorString(errnum));
            }

        };
        this.gluTessCallback(GLU.GLU_TESS_BEGIN, callback);
        this.gluTessCallback(GLU.GLU_TESS_VERTEX, callback);
        this.gluTessCallback(GLU.GLU_TESS_ERROR, callback);
    }

    @Override
    public void gluBeginPolygon() {
        super.gluBeginPolygon();
        primitives.clear();
    }

    private Primitive getLastPrimitive() {
        return primitives.get(primitives.size() - 1);
    }
}

An example of usage - tessellates a quad with a square whole in the middle.

Tessellator tess = new Tessellator();

double[] verticesC1 = new double[]{ //Vertices of outer quad.
    0, 0, 0,
    100, 0, 0,
    100, 100, 0,
    0, 100, 0
};
double[] verticesC2 = new double[]{ //Vertices of inner quad
    25, 25, 0,
    75, 25, 0,
    75, 75, 0,
    25, 75, 0
};

tess.gluBeginPolygon();

tess.gluTessBeginContour();
tess.gluTessVertex(verticesC1, 0, 0); //Arguments are: vertex coords array, offset into array of vertex, data (in this case vertex 
                                      //index). For those wishing to impl their own version, data is the vertexData parameter 
                                      //passed back in the callback method.
tess.gluTessVertex(verticesC1, 3, 1);
tess.gluTessVertex(verticesC1, 6, 2);
tess.gluTessVertex(verticesC1, 9, 3);
tess.gluTessEndContour();

tess.gluTessBeginContour();
tess.gluTessVertex(verticesC2, 0, 4);
tess.gluTessVertex(verticesC2, 3, 5);
tess.gluTessVertex(verticesC2, 6, 6);
tess.gluTessVertex(verticesC2, 9, 7);
tess.gluTessEndContour();

tess.gluEndPolygon();
tess.gluDeleteTess(); //This tessellator could just as easily be reused.

//Prints out the result of the tessellation.
for(int i = 0; i < tess.primitives.size(); i++) {
    System.out.println(tess.primitives.get(i).toString());
}
//To draw the shape it is now a simple matter to put the vertex data you passed in initially into a VBO, and the indices returned
//into an IBO (Index VBO). You have the types of the primitives and the number of indices for each one. Drawing the result should
//be a walk in the park, as long as you have read the appropriate tutorials here or elsewhere.