Jump to content
  • Advertisement
Sign in to follow this  
Wyrframe

OpenGL Help with VBO usage

This topic is 2755 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Update: solved. See 1st reply, below.

I could really use some help debugging the use of a Vertex Buffer Object in LWJGL.

In this screenshot, you're looking at two viewports. On the left, I've drawn a grid, a 1x1 outline, and a textured quad, all using immediate mode. I'm trying to draw the same textured quad from a VBO, through the managing class SpritesBatchRenderer. At present, SpritesBatchRenderer just draws a transparent blue quad instead of a textured one, because I'm having no luck getting the same quad output.

[attachment=1613:bad-render.png]

There's a commented-out section in render(), which prints the occupied contents of the buffer, where I've confirmed that the vertex positions and texture coordinates are what they are supposed to be; a unit square. I've tried randomly positioning the center of that square in the [-3, 3] range, and get different scrambled quads; I'm guessing the floats are being interpreted oddly, or offset from where they're supposed to be, but I don't understand why or how.

Relevant source follows; SpritesBatchRenderer in full, and its only non-OpenGL external call, SpriteAsset.fillBuffer(). SpritesBatchRenderer.render() is near the bottom of its source block.

SpritesBatchRenderer.java
package assets;

import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.util.HashMap;

import lwjgl.Texture;

import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;

import assets.graphics.SpriteAsset;

public final class SpritesBatchRenderer
{
private static final int V_PER_SPRITE = 4;
private static final int ELEMENT_SIZE = 4;

private static final int SZ_TEX = 2; // U,V
private static final int SZ_VER = 3; // X,Y,Z
private static final int SZ_UNIT = SZ_TEX + SZ_VER;

private final Texture texture;

private HashMap<Long, Integer> idToIdx = new HashMap<Long, Integer> ();
private HashMap<Integer, Long> idxToId = new HashMap<Integer, Long> ();
private long nextID;

private FloatBuffer vertexBuffer;
private boolean bDirty;

private int capacity = 64;
private int size = 0;
private int vertexBO;

public SpritesBatchRenderer (Texture aTexture)
{
texture = aTexture;
vertexBO = GL15.glGenBuffers ();

resize (capacity);
}

public long addSprite (final float aX, final float aY, final float aScale, final boolean flipX,
final boolean flipY, SpriteAsset anAsset)
{
int theIndex = size++;
if( size == capacity )
resize ((int) (capacity * 1.5));

long theID = ++nextID;
idToIdx.put (theID, theIndex);
idxToId.put (theIndex, theID);

updateSprite (theID, aX, aY, aScale, flipX, flipY, anAsset);
return theID;
}

private void updateSprite (long theID, float aX, float aY, float aScale, boolean flipX,
boolean flipY, SpriteAsset anAsset)
{
int theIndex = idToIdx.get (theID);
bDirty = true;

anAsset.fillBuffer (vertexBuffer, aX, aY, aScale, flipX, flipY, theIndex * SZ_UNIT
* V_PER_SPRITE);
}

public void rmSprite (long aID)
{
size--;

// Fetch and remove the binding for the current item
int theIndex = idToIdx.get (aID);
idToIdx.remove (aID);

// If we removed an item from anywhere but the end of the list...
if( theIndex != size )
{
// Replace the removed item with the last item in the list.
for( int i = 0; i < V_PER_SPRITE * SZ_UNIT; ++i )
vertexBuffer.put (theIndex + i, vertexBuffer.get (size * i));

// Update the binding for the moved item
final long theMovedId = idxToId.get (size);
idToIdx.put (theMovedId, theIndex);
idxToId.put (theIndex, theMovedId);

bDirty = true;
}
}

private void resize (int aCap)
{
final FloatBuffer oldVB = vertexBuffer;

vertexBuffer = ByteBuffer.allocateDirect (aCap * V_PER_SPRITE * SZ_UNIT * ELEMENT_SIZE)
.asFloatBuffer ();

if( oldVB != null )
{
oldVB.position (0);
vertexBuffer.put (oldVB);
}

capacity = aCap;
bDirty = true;
}

public void render ()
{
if( bDirty )
{
// for( int i = 0; i < size * V_PER_SPRITE; ++i )
// {
// for( int j = 0; j < SZ_UNIT; ++j )
// {
// System.out.print (" ");
// System.out.print (vertexBuffer.get (i * SZ_UNIT + j));
// }
// System.out.println ();
// }

vertexBuffer.position (0);
GL15.glBindBuffer (GL15.GL_ARRAY_BUFFER, vertexBO);
GL15.glBufferData (GL15.GL_ARRAY_BUFFER, vertexBuffer, GL15.GL_DYNAMIC_DRAW);
bDirty = false;
}

GL11.glEnableClientState (GL11.GL_VERTEX_ARRAY);
GL11.glEnableClientState (GL11.GL_TEXTURE_COORD_ARRAY);

GL15.glBindBuffer (GL15.GL_ARRAY_BUFFER, vertexBO);
GL11.glVertexPointer (SZ_VER, GL11.GL_FLOAT, SZ_UNIT * ELEMENT_SIZE, 0);
GL11.glTexCoordPointer (SZ_TEX, GL11.GL_FLOAT, SZ_UNIT * ELEMENT_SIZE, SZ_VER * ELEMENT_SIZE);

// TODO For testing purposes; change to 1,1,1,1 and bind() later
GL11.glColor4f (0, 1, 1, 0.4f);
// texture.bind ();
GL11.glDrawArrays (GL11.GL_TRIANGLES, 0, size * V_PER_SPRITE);
// texture.unbind ();

GL15.glBindBuffer (GL15.GL_ARRAY_BUFFER, 0);
GL11.glDisableClientState (GL11.GL_VERTEX_ARRAY);
GL11.glDisableClientState (GL11.GL_TEXTURE_COORD_ARRAY);
}

protected void finalize () throws Throwable
{
dispose ();
}

public void dispose ()
{
if( vertexBO != 0 ) {
GL15.glDeleteBuffers (vertexBO);
vertexBO = 0;
}
}
}


SpriteAsset.fillBuffer()

public void fillBuffer (FloatBuffer aBuffer, float aX, float aY, float aScale, boolean flipX, boolean flipY, int idx)
{
final float uea = flipX ? ub : ua;
final float ueb = flipX ? ua : ub;
final float vea = flipY ? vb : va;
final float veb = flipY ? va : vb;

aScale *= 0.5;

aBuffer.put(idx++, (float) (aX - aScale));
aBuffer.put(idx++, (float) (aY - aScale));
aBuffer.put(idx++, 0);
aBuffer.put(idx++, uea);
aBuffer.put(idx++, vea);

aBuffer.put(idx++, (float) (aX + aScale));
aBuffer.put(idx++, (float) (aY - aScale));
aBuffer.put(idx++, 0);
aBuffer.put(idx++, ueb);
aBuffer.put(idx++, vea);

aBuffer.put(idx++, (float) (aX + aScale));
aBuffer.put(idx++, (float) (aY + aScale));
aBuffer.put(idx++, 0);
aBuffer.put(idx++, ueb);
aBuffer.put(idx++, veb);

aBuffer.put(idx++, (float) (aX - aScale));
aBuffer.put(idx++, (float) (aY + aScale));
aBuffer.put(idx++, 0);
aBuffer.put(idx++, uea);
aBuffer.put(idx++, veb);
}

Share this post


Link to post
Share on other sites
Advertisement
Wierdly enough, it was nothing expected. Apparently ByteBuffer.allocateDirect() gives you a buffer in network-endian setup by default; I discovered on the LWJGL forums that I had to either use org.lwjgl.BufferUtils.createFloatBuffer() or call FloatBuffer.order(ByteOrder.nativeOrder()) on my buffer before passing it to OpenGL.

So... an endianness issue of all things. That was dash strange, but at least it's working now.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!