Ok… here is the code. This is Java using JOGL. The VertexBufferTerrain class is responsible for specifying the vertices to OpenGL. The Data class specified to the constructor maps a z-height to an x,y coordinate and the ColorMap class determines the color for a particular z-height.
What are degenerates? I was thinking that I need to terminate the end of one strip somehow. Is that what a degenerate is for? That wasn’t necessary using glBegin, glEnd, and glVertex. I tried splitting the triangle strips into different VBOs, but that didn’t seem to work.
Thanks…
import java.awt.Color;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import net.java.games.jogl.GL;
final class VertexBufferTerrain
implements Terrain
{
// CONSTRUCTORS
//
public VertexBufferTerrain( final Data imageData, final ColorMap colors )
{
this.vertexBufferID = new int[1];
this.colorBufferID = new int[1];
this.numVertices = 2*(imageData.getHeight()-1)*imageData.getWidth();
this.vertexBuffer = FloatBuffer.allocate( numVertices*3 );
this.colorBuffer = ByteBuffer.allocate( numVertices*3 );
this.zScale = -20f;
populateBuffers( imageData, colors );
}
private void populateBuffers( final Data data, final ColorMap colors )
{
int width = data.getWidth();
int height = data.getHeight();
// these offsets are used to center the surface at the origin...
float xOffset = -width/2f;
float yOffset = -height/2f;
// the resulting x and y coordinates after the offsets are applied..
float xCoord;
float yCoord;
// reuse these...
float dataValue;
Color color;
for( int y=1; y<height; y++ )
{
int topYIndex = height-1-y;
int botYIndex = height-y;
for( int x=0; x<width; x++ )
{
xCoord = (x+xOffset);
yCoord = (y+yOffset);
vertexBuffer.put( xCoord );
vertexBuffer.put( yCoord );
dataValue = data.getValue( x, topYIndex );
vertexBuffer.put( dataValue*zScale );
color = colors.getColor( dataValue );
colorBuffer.put( (byte)color.getRed() );
colorBuffer.put( (byte)color.getGreen() );
colorBuffer.put( (byte)color.getBlue() );
yCoord = (y-1+yOffset);
vertexBuffer.put( xCoord );
vertexBuffer.put( yCoord );
dataValue = data.getValue( x, botYIndex );
vertexBuffer.put( dataValue*zScale );
color = colors.getColor( dataValue );
colorBuffer.put( (byte)color.getRed() );
colorBuffer.put( (byte)color.getGreen() );
colorBuffer.put( (byte)color.getBlue() );
}
}
}
// METHODS
//
private void initialize( final GL gl )
{
// it would be nice to do this in the ctor, but we don't have a handle
// to gl until the first time drawTerrain is invoked. Perhaps just
// move this into the interface...
if( vertexBuffer != null )
{
// generate and bind the buffer
//
// 1) get the buffer ID
gl.glGenBuffers( 1, vertexBufferID );
// 2) bind the buffer (e.g. make it the active buffer).
gl.glBindBuffer( GL.GL_ARRAY_BUFFER, vertexBufferID[0] );
// load the data into the buffer...
gl.glBufferData(
GL.GL_ARRAY_BUFFER,
vertexBuffer.capacity()*4,
vertexBuffer.array(),
GL.GL_STATIC_DRAW );
// we don't need the geometry anymore... it's on the graphics card
vertexBuffer.clear();
vertexBuffer = null;
}
if( colorBuffer != null )
{
// generate and bind the buffer
//
// 1) get the buffer ID
gl.glGenBuffers( 1, colorBufferID );
// 2) bind the buffer (e.g. make it the active buffer).
gl.glBindBuffer( GL.GL_ARRAY_BUFFER, colorBufferID[0] );
// load the data into the buffer...
gl.glBufferData(
GL.GL_ARRAY_BUFFER,
colorBuffer.capacity(),
colorBuffer.array(),
GL.GL_STATIC_DRAW );
// we don't need the geometry anymore... it's on the graphics card
colorBuffer.clear();
colorBuffer = null;
}
}
public void shutdown( final GL gl )
{
gl.glDeleteBuffers( GL.GL_ARRAY_BUFFER, vertexBufferID );
gl.glDeleteBuffers( GL.GL_ARRAY_BUFFER, colorBufferID );
}
public void drawTerrain( final GL gl )
{
initialize( gl );
gl.glBindBuffer( GL.GL_ARRAY_BUFFER, vertexBufferID[0] );
gl.glVertexPointer(
3, // num floats in a vertex (x,y,z)
GL.GL_FLOAT, // the data type
0, // the stride between verteces in the array
null // this would be the vertex array, if using those...
);
gl.glBindBuffer( GL.GL_ARRAY_BUFFER, colorBufferID[0] );
gl.glColorPointer(
3, // num color components
GL.GL_UNSIGNED_BYTE, // data type
0, // the stride
null // this would be the color array, if not using VBOs
);
// now, do the drawing...
gl.glDrawArrays( GL.GL_TRIANGLE_STRIP, 0, numVertices );
}
// ATTRIBUTES
//
// RxTBD: we probably only need one array for the buffer IDs.
private final int[] vertexBufferID;
private final int[] colorBufferID;
private FloatBuffer vertexBuffer;
private ByteBuffer colorBuffer;
private final int numVertices;
private float zScale;
// STATICS
//
}