How can I get the post-rendering data of a call of the method "gluCylinder"?

Hi!

I need to simulate the drawing of some cylinders (by using GLU to avoid reinventing existing methods) to get the computed vertices, to compute the corresponding texture coordinates and to write all these coordinates into a file. I think about the following solution but I want to be sure to be on the good way before implementing it:
FloatBuffer buffer=BufferUtil.newFloatBuffer(100000);
gl.glFeedbackBuffer(buffer.capacity,GL.GL_3D,buffer);
gl.glRenderMode(GL.GL_FEEDBACK);
GLUquadric q=glu.gluNewQuadric();
glu.gluCylinder(q, 10.0d, 10.0d, 50.0d, 10, 10);
glu.gluDeleteQuadric(q);
… computing the texture coordinates and write all into a file

Please can you tell me if you think it might work fine?

probably writing it yourself is a whole lot faster. both in CPU-time as in your own time.

The math shouldn’t be that difficult to understand, try googling it.

I already wrote some methods doing it. As this will be used in a program that prepares data, the performance is not a critical factor. I agree with you about the fact it might work slower but I disagree with you on the other point. Rewriting these methods by myself is not difficult but requires much time than using the GLU. In my code, I only need to set the proper perspective and to check some details, it seems to be the only things that are missing. I think I will look into the source code of the GLU in JOGL as it is written in Java ;D.

You can achieve this by providing your own implementation of the GL interface. I’ve done this myself by subclassing the TraceGL class and only overwriting the methods I’m interested in (much easier than to implement the huge GL interface) . I’ve attached my implementation which can “record” the vertex and normal coordinates, you can extend it to also deal with texture coordinates.

You can use the class as follows:


GLContext curContext = GLContext.getCurrent();
GL current=curContext.getGL();

GeometryGL geometryGL=new GeometryGL(current);
curContext.setGL(geometryGL);

// invoke the GLU calls to generate geometry
GLU glu=new GLU();

GLUquadric quadObj = glu.gluNewQuadric();
glu.gluQuadricDrawStyle(quadObj, GLU.GLU_FILL);
glu.gluQuadricNormals(quadObj, GLU.GLU_SMOOTH);
glu.gluPartialDisk(quadObj, 1.0, 1.2, 15, 1, 0, 360);
glu.gluDeleteQuadric(quadObj);

curContext.setGL(current);

// ->get the vertices and normals
// geometryGL.getVertices();
// geometryGL.getNormals();
// geometryGL.getVertexIndices();
// geometryGL.getNormalIndices();

Note: I couldn’t upload the file (“upload directory full”), that’s why I’m posting it here


public class GeometryGL extends TraceGL
{
    protected ArrayList<Vector3f> vertices;
    protected ArrayList<Vector3f> normals;
    protected IntList vertexIndices;
    // the current normal value.
    protected Vector3f normal;
    protected boolean lines;
    protected int mode=-1;
    // the index of the first vertex since the last "begin"
    protected int vFirstIndex;
    // the number of vertices after the last "begin"
    protected int vCount;

    public GeometryGL(GL downstreamGL)
    {
        // note: we set the stream to null so we know when a method is used which is not
        // overwritten yet; we will get a NullPointerException in this case
        super(downstreamGL, null);
        reset();
    }

    public void reset()
    {
        vertices=new ArrayList<Vector3f>();
        normals=new ArrayList<Vector3f>();

        vertexIndices=new IntList(10);
        //normalIndices=new IntList(10);
        normal=new Vector3f();

        lines=false;
    }

    public Vector3f[] getVertices()
    {
        return vertices.toArray(new Vector3f[vertices.size()]);
    }

    public Vector3f[] getNormals()
    {
        return normals.toArray(new Vector3f[normals.size()]);
    }

    public int[] getVertexIndices()
    {
        return vertexIndices.trim();
    }

    public int[] getNormalIndices()
    {
        return vertexIndices.trim(); // the lists are identical
    }

    /**
     * Returns true in case there is at least one line geometry.
     */
    public boolean isLines()
    {
        return lines;
    }

    public void glBegin(int arg0)
    {
        // see http://wiki.delphigl.com/index.php/GlBegin for a good description of modes
        mode=arg0;

        vFirstIndex=vertices.size();
        vCount=0;
        switch(mode)
        {
            case GL.GL_POINTS:
                throw new IllegalArgumentException("GL_POINTS not supported");
            case GL.GL_LINES: // fall through
            case GL.GL_LINE_STRIP: // fall through
            case GL.GL_LINE_LOOP: 
                lines=true;
                break;
            case GL.GL_TRIANGLES:
                break;
            case GL.GL_TRIANGLE_STRIP:
                break;
            case GL.GL_TRIANGLE_FAN:
                break;
            case GL.GL_QUADS:
                break;
            case GL.GL_QUAD_STRIP:
                break;
            case GL.GL_POLYGON:
                throw new IllegalArgumentException("GL_POLYGON not supported");
            default: throw new IllegalArgumentException("mode not supported");
        }
    }

    public void glEnd()
    {
        if(mode==GL.GL_LINE_LOOP)
        {
            // close last line
            if(vCount>1)
            {
                vertexIndices.add(vertices.size()-1);
                vertexIndices.add(vFirstIndex);
            }
        }
        mode=-1;
    }
 
    public void glVertex3d(double arg0, double arg1, double arg2)
    {
        glVertex3f((float)arg0, (float)arg1, (float)arg2);
    }

    public void glVertex3dv(double[] arg0, int arg1)
    {
        glVertex3f((float)arg0[arg1], (float)arg0[arg1+1], (float)arg0[arg1+2]);
    }

    public void glVertex3fv(float[] arg0, int arg1)
    {
        glVertex3f(arg0[arg1], arg0[arg1+1], arg0[arg1+2]);
    }

    public void glVertex3f(float arg0, float arg1, float arg2)
    {
        vertices.add(new Vector3f(arg0, arg1, arg2));
        vCount++;

        // apply the normal value as well
        normals.add((Vector3f)normal.clone());

        switch(mode)
        {
            case GL.GL_POINTS:
                break;
            case GL.GL_LINES:
                vertexIndices.add(vertices.size()-1); // only one vertex added
                break;
            case GL.GL_LINE_STRIP: // fall through
            case GL.GL_LINE_LOOP:
                if(vCount>1)
                {
                    vertexIndices.add(vertices.size()-2);
                    vertexIndices.add(vertices.size()-1);
                }
                break;
            case GL.GL_TRIANGLES:
                vertexIndices.add(vertices.size()-1); // only one vertex added
                break;
            case GL.GL_TRIANGLE_STRIP:
                if(vCount>2)
                {
                    if(vCount%2==0) // even
                    {
                        // one triangle (three vertices) added
                        vertexIndices.add(vertices.size()-3);
                        vertexIndices.add(vertices.size()-2);
                    }
                    else // odd
                    {
                        // one triangle (three vertices) added
                        vertexIndices.add(vertices.size()-2);
                        vertexIndices.add(vertices.size()-3);
                    }
                    vertexIndices.add(vertices.size()-1);
                }
                break;
            case GL.GL_TRIANGLE_FAN:
                if(vCount>2)
                {
                    // one triangle (three vertices) added
                    vertexIndices.add(vFirstIndex);
                    vertexIndices.add(vertices.size()-2);
                    vertexIndices.add(vertices.size()-1);
                }
                break;
            case GL.GL_QUADS:
                if(vCount%4==0) // do it every 4
                {
                    // two triangles (4 vertices) added
                    vertexIndices.add(vertices.size()-4);
                    vertexIndices.add(vertices.size()-3);
                    vertexIndices.add(vertices.size()-1);
                    
                    vertexIndices.add(vertices.size()-1);
                    vertexIndices.add(vertices.size()-3);
                    vertexIndices.add(vertices.size()-2);
                }
                break;
            case GL.GL_QUAD_STRIP:
                if(vCount>2 && vCount%2==0) // do it after the first two vertices and then every two
                {
                    // two triangles (4 vertices) added
                    vertexIndices.add(vertices.size()-3);
                    vertexIndices.add(vertices.size()-4);
                    vertexIndices.add(vertices.size()-2);
                    
                    vertexIndices.add(vertices.size()-3);
                    vertexIndices.add(vertices.size()-2);
                    vertexIndices.add(vertices.size()-1);
                }
                break;
            case GL.GL_POLYGON:
                break;
        }
    }

    public void glNormal3d(double arg0, double arg1, double arg2)
    {
        glNormal3f((float)arg0, (float)arg1, (float)arg2);
    }
 
    public void glNormal3dv(double[] arg0, int arg1)
    {
        glNormal3f((float)arg0[arg1], (float)arg0[arg1+1], (float)arg0[arg1+2]);
    }

    public void glNormal3fv(float[] arg0, int arg1)
    {
        glNormal3f(arg0[arg1], arg0[arg1+1], arg0[arg1+2]);
    }

    public void glNormal3f(float arg0, float arg1, float arg2)
    {
        // the normal value will be applied once a new vertex is created
        normal.set(arg0, arg1, arg2);
    }

    static class IntList
    {
        int ints[] ;
        int count ;

        IntList(int initialSize)
        {
            ints = new int[initialSize] ;
            count = 0 ;
        }

        IntList(int ints[])
        {
            this.ints = ints ;
            this.count = ints.length ;
        }

        void add(int i)
        {
            if (count == ints.length)
            {
                int newints[] = new int[2*count] ;
                System.arraycopy(ints, 0, newints, 0, count) ;
                ints = newints ;
            }
            ints[count++] = i ;
        }

        /**
         * Trim the backing array to the current count and return the
         * resulting backing array.
         */
        int[] trim()
        {
            if (count != ints.length)
            {
                int newints[] = new int[count] ;
                System.arraycopy(ints, 0, newints, 0, count) ;
                ints = newints ;
            }
            return ints;
        }

        /**
         * Fill the list with consecutive integers starting from 0.
         */
        void fillAscending()
        {
            for (int i = 0 ; i < ints.length ; i++)
                ints[i] = i ;

            count = ints.length ;
        }
    }
}

Ye gods! A page worth of code just to avoid writing code to generate a cylinder? That’s just silly - generating a cylinder is going to be about 20 lines max. ::slight_smile:

The cylinder is of course just an example. This is a utility class for getting the geometry of any object drawn via GLUT or other classes without copying huge amount of code.

The aim is not to avoid writing it, it is to compute the coordinates without drawing them, to put them into a VBO. I agree with you about the number of lines, that’s why I tried a simple version using GLU and the feedback mode. The source code of drawCylinder in GLUquadricImpl is 130 lines long and uses the immediate mode… it is known to be very very slow. I’ve used this code to compute the coordinates and it seems to be working. I will compare with the approach suggested by andreasf that I thank for his interesting source code.

Can you tell me what is Vertex3f please? Your approach is more simple than mine, it doesn’t require to rewrite all. That is why I will follow your excellent advice. Thank you very very much for your help.

Vector3f is one of our internal classes, however you can easily replace it with the standard javax.vecmath.Vector3f class from the Java3D package. In case you don’t want to depend on Java3D, you can also use this tiny class

public class Vector3f
{
public float x;
public float y;
public float z;

public Tuple3f(float x, float y, float z)
{
  this.x = x;
  this.y = y;
  this.z = z;
}

public void set(float x, float y, float z)
{
  this.x = x;
  this.y = y;
  this.z = z;
}

public Object clone()
{
try {
return super.clone();
}
catch (CloneNotSupportedException e)
{
throw new RuntimeException(e);
}
}
}