Trouble with glDrawArrays and vertex arrays

Started by Fritzendugan, November 08, 2011, 02:37:21

Previous topic - Next topic

Fritzendugan

Ok, my end goal of what I'm currently trying to do is load in a mesh from file, storing the vertex data and texture coord data into arrays, and then render this mesh to the screen. After I create the arrays, I create buffers for those arrays, and then I'd like to render them using glDrawArrays().

I've tried a couple different ways of rendering besides glDrawArrays() just to make sure that the data is actually populated correctly, which it does (you can see these commented out in the code dump). I'm not doing anything silly like using GL_FLOAT for stride or anything like that, but for some reason the mesh just doesn't show up when I use glDrawArrays().

anyway, here's the code dump: http://www.pastie.org/2829501
(or if you prefer here:
// unrelated code not shown:
public class Shapes
{
    private final static float[] triVerts = new float[] {
        0.0f,  1.0f,  0.0f,
       -1.0f, -1.0f,  1.0f,
        1.0f, -1.0f,  1.0f,
        0.0f,  1.0f,  0.0f,
        1.0f, -1.0f,  1.0f,
        1.0f, -1.0f, -1.0f,
        0.0f,  1.0f,  0.0f,
        1.0f, -1.0f, -1.0f,
       -1.0f, -1.0f, -1.0f,
        0.0f,  1.0f,  0.0f,
       -1.0f, -1.0f, -1.0f,
       -1.0f, -1.0f,  1.0f
    };
    private final static float[] triTexCoord = new float[] {
        0f, 1f,
        1f, 1f,
        0f, 1f,
        0f, 0f,
        0f, 1f,
        1f, 1f,
        0f, 1f,
        0f, 0f,
        0f, 1f,
        1f, 1f,
        0f, 1f,
        0f, 0f
    };
    private final static FloatBuffer triVertBuffer = BufferUtil.toDirect(FloatBuffer.wrap(triVerts));
    private final static FloatBuffer triTexCoordBuffer = BufferUtil.toDirect(FloatBuffer.wrap(triTexCoord));
    
    public static void drawPyramidArrays(final float x, final float y, final float z)
    {
        glPushMatrix();
        
        glTranslatef(x,y,z);
        //* // this doesn't work
        glEnableClientState(GL_VERTEX_ARRAY);
        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
        
        glVertexPointer(3, 0, triVertBuffer);
        glTexCoordPointer(2, 0, triTexCoordBuffer);
        
        glDrawArrays(GL_TRIANGLES, 0, triVerts.length / 3);
        
        glDisableClientState(GL_VERTEX_ARRAY);
        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
        // */
        /* // this works
        glBegin(GL_TRIANGLES);
            for(int i = 0; i < triVerts.length / 3; i++)
            {
                glTexCoord2f(triTexCoord[i*2], triTexCoord[i*2+1]);
                glVertex3f(triVerts[i*3], triVerts[i*3+1], triVerts[i*3+2]);
            }
        glEnd();
        // */
        /* // this also works
        glBegin(GL_TRIANGLES);
        for(int i = 0; i < triVerts.length / 3; i++)
        {
            glTexCoord2f(triTexCoordBuffer.get(), triTexCoordBuffer.get());
            glVertex3f(triVertBuffer.get(), triVertBuffer.get(), triVertBuffer.get());
        }
        triTexCoordBuffer.flip();
        triVertBuffer.flip();
        glEnd();
        // */
        
        glPopMatrix();
    }
}

// and then in my rendering code I'm doing:
public void onRender()
    {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
        glLoadIdentity(); // Reset The View
        camera.use();
        
        glColor3f(1f,1f,1f);
        
        // TODO render meshes
        glEnable(GL_TEXTURE_2D);
        testpacker.bindTexture();
        
        this.test[0].render(-2f, 0f, 3f); // this renders fine using a method similar to the ones I've commented out in the Shapes code.
        
        glBegin(GL_QUADS);
            glTexCoord2f(this.tex_sdot.getLeft(),  this.tex_sdot.getTop());    glVertex3f(-1f, 0f, -1f);
            glTexCoord2f(this.tex_sdot.getRight(), this.tex_sdot.getTop());    glVertex3f(1f, 0f, -1f);
            glTexCoord2f(this.tex_sdot.getRight(), this.tex_sdot.getBottom()); glVertex3f(1f, 0f, 1f);
            glTexCoord2f(this.tex_sdot.getLeft(),  this.tex_sdot.getBottom()); glVertex3f(-1f, 0f, 1f);
        glEnd();
        Shapes.drawPyramidArrays(-1.5f, 0f, 1.6f); // nothing shows up
        TexturePacker.bindNoTextures();
        glDisable(GL_TEXTURE_2D);
        
        glScalef(100f, 10f, 100f);
        Shapes.drawCube(0f, 0.5f, 0f, 0f); // this shows up fine
    }


your help is greatly appreciated! :D

Mickelukas

Solved on JGO: http://www.java-gaming.org/topics/trouble-with-gldrawarrays-and-vertex-arrays/25033/view.html

Quote from: fritzendugan
figured it out, when I was creating the buffers I wasn't setting the byteorder.

relevant code for anyone stuck:
ByteBuffer secondbuf = ByteBuffer.allocateDirect(buf.capacity() * Float.SIZE);
secondbuf.order(ByteOrder.nativeOrder());
final FloatBuffer ret = secondbuf.asFloatBuffer();
ret.put(buf);
ret.flip();


abcdef

The byte order was not the issue, it was the line

ret.flip();


Once you populate a buffer its position is at the end of the buffer. To something that gets the buffer its empty as there are no elements left in the buffer to get data for.

By doing a rewind() or flip() on the array you are resetting the position to position 0 in the buffer. Flip does the additional thing of removing any marks from the buffer too, if you have a mark set in the middle of the buffer and you rewind, you rewind to that mark and not the beginning. But as you don't set any the effect is the same for using either. When you populate your buffers always do a rewind() or flip() at the end to reset everything ready for rendering.

Chuck

flip() also sets the limit of the buffer to the current position, which you do if you're at the end of your data but not the end of your buffer.  If you wrote to the middle of the buffer and don't want to truncate the contents at the current position, you always want to call rewind() instead.