GLUtessellator example code

Started by nanoquack, July 30, 2013, 08:05:46

Previous topic - Next topic

nanoquack

Hi,

I'm trying to get the GLUtesselator to work. But as there is actually very litte example code or code that uses it at all (I googled, I swear ;-) ) and the documentation isn't very detailed, I've got a hard time getting it to work.

So my question is basically: Are there any examples out there?
On a very related topic: Are there any other straightforward possibilities to tesselate concave polygons in order to draw them with opengl? (specifically I would want to use a vertex array, an index buffer for drawing and glDrawElements for the actual drawing)

Thanks in advance,
Nano

quew8

I'm pretty sure you can't do that with GLU. Their tessellation stuff draws the complex polygon in immediate mode. I think the idea was you put the tessellation calls in a display list, then if you called the display list it would draw the polygon again without having to tessellate it again. So you can't (as far as I can see) use it with vbos.

As for 'straightforward possibilities to tesselate concave polygons,' I think that depends on how strong your maths is. Take a look at the "ear clipping" and "monotone polygons" methods here http://en.wikipedia.org/wiki/Polygon_triangulation Either one of these looks doable. Pick one and do some research on it.

Sorry I can't be more help

nanoquack

Thanks for your answer!

Hmm as far as I understand it, the tesselator doesn't draw anything at all. Maybe I'm off here but it seems to me that one provides callback methods (or as we're in the java world, a callback object) which get called when the tesselator runs. My idea was therefore to let the tesselator do its magic, collect the result through the callback methods (beginData, vertexData, endData) and store this into a vertex buffer for later rendering. Maybe I understood that wrong, but to me the idea seems to be that one can pretty much run any code in the callback, so why not "generate" tesselated polygons for later use?

As for ear clipping and monotone polygons: I would prefer not having to implement this on my own because I would like to focus on other aspects than the tesselation itself.

Fool Running

If you get the LWJGL source, there is a test in src/java/org/lwjgl/test/glu/tessellation/TessellationTest.java that should help you figure out how to use it. It does, indeed, use a callback function to draw, so you should be able to adapt it to getting the values into a VBO (see TessCallback.java in the same test folder).
Programmers will, one day, rule the world... and the world won't notice until its too late.Just testing the marquee option ;D

quew8

Having been proved wrong, I'm now working on a little example myself. Be with you momentarily.

quew8

Okay so here we go:

This is just a structure used to store the result.
class Primitive {
            public final int type;
            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 which extends GLUtessellatorImpl
class Tessellator extends GLUtessellatorImpl {
            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_VERTEX, callback);
            }
            
            private Primitive getLastPrimitive() {
                return primitives.get(primitives.size() - 1);
            }
        }


And a little proof of concept to tessellate a quad with a quad shaped hole in it.
Tessellator tess = new Tessellator();
        
        double[] verticesC1 = new double[]{
            0, 0, 0, //0
            100, 0, 0, //1
            100, 100, 0, //2
            0, 100, 0 //3
        };
        double[] verticesC2 = new double[]{
            25, 25, 0, //4
            75, 25, 0, //5
            75, 75, 0, //6
            25, 75, 0 //7
        };
        
        tess.gluBeginPolygon();
        
        tess.gluTessBeginContour();
        tess.gluTessVertex(verticesC1, 0, 0);
        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();
        
        for(int i = 0; i < tess.primitives.size(); i++) {
            System.out.println(tess.primitives.get(i).toString());
        }


This gives the output:
Quote
New Primitive GL_TRIANGLE_STRIP
Index: 0
Index: 4
Index: 3
Index: 7
Index: 2
Index: 6
Index: 1
Index: 5
Index: 4
New Primitive GL_TRIANGLES
Index: 4
Index: 0
Index: 1
Which is what we want. All that remains is to package these indices in an IBO. The one thing that could be troublesome I think is that the output can have different primitive types. I don't know about you but I like to use only one if I can, but probably converting between them isn't too hard.

Now a question, do you think that an explanation of how to use LWJGL GLUtessellatorImpl would be useful enough to enough people to warrant putting it on the wiki?

nanoquack

Wow, didn't expect a full example and certainly not that quick! Thumbs up to you guys!
That's exactly what I was hoping that it would work ;-) 

As for the question regarding the wiki: I think it would be a great idea to put this into the wiki as it might not be that uncommon to draw concave polygons.

Nano