/*******************************************************************************
* Copyright 2012 Geoscience Australia
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package au.gov.ga.earthsci.worldwind.common.layers.curtain;
import gov.nasa.worldwind.cache.GpuResourceCache;
import gov.nasa.worldwind.geom.Vec4;
import gov.nasa.worldwind.render.DrawContext;
import gov.nasa.worldwind.render.Renderable;
import gov.nasa.worldwind.util.OGLStackHandler;
import java.nio.FloatBuffer;
import javax.media.opengl.GL2;
/**
* A {@link Renderable} piece of geometry that draws a segment (or section) of a
* curtain/path for the {@link TiledCurtainLayer}.
*
* @author Michael de Hoog (michael.dehoog@ga.gov.au)
*/
public class SegmentGeometry implements Renderable
{
private final int vertexCount;
private final FloatBuffer vertices;
private final FloatBuffer texCoords;
private Vec4 referenceCenter;
private long time;
protected Object vboCacheKey = new Object();
public SegmentGeometry(DrawContext dc, FloatBuffer vertices, FloatBuffer texCoords, Vec4 referenceCenter)
{
this.vertexCount = vertices.limit() / 3;
this.vertices = vertices;
this.texCoords = texCoords;
this.referenceCenter = referenceCenter;
time = System.currentTimeMillis();
if (dc.getGLRuntimeCapabilities().isUseVertexBufferObject())
{
fillVerticesVBO(dc);
}
}
@Override
public void render(DrawContext dc)
{
render(dc, 1);
}
public void render(DrawContext dc, int numTextureUnits)
{
dc.getView().pushReferenceCenter(dc, referenceCenter);
GL2 gl = dc.getGL().getGL2();
OGLStackHandler ogsh = new OGLStackHandler();
try
{
ogsh.pushClientAttrib(gl, GL2.GL_CLIENT_VERTEX_ARRAY_BIT);
gl.glEnableClientState(GL2.GL_VERTEX_ARRAY);
if (dc.getGLRuntimeCapabilities().isUseVertexBufferObject())
{
//Use VBOs
int[] vboIds = (int[]) dc.getGpuResourceCache().get(this.vboCacheKey);
if (vboIds == null)
{
vboIds = fillVerticesVBO(dc);
}
gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, vboIds[0]);
gl.glVertexPointer(3, GL2.GL_FLOAT, 0, 0);
for (int i = 0; i < numTextureUnits; i++)
{
gl.glClientActiveTexture(GL2.GL_TEXTURE0 + i);
gl.glEnableClientState(GL2.GL_TEXTURE_COORD_ARRAY);
gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, vboIds[1]);
gl.glTexCoordPointer(2, GL2.GL_FLOAT, 0, 0);
}
gl.glDrawArrays(GL2.GL_TRIANGLE_STRIP, 0, vertexCount);
}
else
{
//Use Vertex Arrays
gl.glVertexPointer(3, GL2.GL_FLOAT, 0, vertices.rewind());
for (int i = 0; i < numTextureUnits; i++)
{
gl.glClientActiveTexture(GL2.GL_TEXTURE0 + i);
gl.glEnableClientState(GL2.GL_TEXTURE_COORD_ARRAY);
gl.glTexCoordPointer(2, GL2.GL_FLOAT, 0, texCoords.rewind());
}
gl.glDrawArrays(GL2.GL_TRIANGLE_STRIP, 0, vertexCount);
}
}
finally
{
ogsh.pop(gl);
}
dc.getView().popReferenceCenter(dc);
}
public Vec4 getReferenceCenter()
{
return referenceCenter;
}
public FloatBuffer getVertices()
{
return vertices;
}
public FloatBuffer getTexCoords()
{
return texCoords;
}
public long getTime()
{
return time;
}
public long getSizeInBytes()
{
return 5 * vertexCount * Float.SIZE / 8;
}
protected void update(DrawContext dc, Vec4 referenceCenter)
{
this.time = System.currentTimeMillis();
this.referenceCenter = referenceCenter;
if (dc.getGLRuntimeCapabilities().isUseVertexBufferObject())
{
this.fillVerticesVBO(dc);
}
}
protected int[] fillVerticesVBO(DrawContext dc)
{
GL2 gl = dc.getGL().getGL2();
int[] vboIds = (int[]) dc.getGpuResourceCache().get(this.vboCacheKey);
if (vboIds == null)
{
vboIds = new int[2];
gl.glGenBuffers(vboIds.length, vboIds, 0);
int size = (vertices.limit() + texCoords.limit()) * 4;
dc.getGpuResourceCache().put(this.vboCacheKey, vboIds, GpuResourceCache.VBO_BUFFERS, size);
}
try
{
gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, vboIds[0]);
gl.glBufferData(GL2.GL_ARRAY_BUFFER, vertices.limit() * 4, vertices.rewind(), GL2.GL_STATIC_DRAW);
gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, vboIds[1]);
gl.glBufferData(GL2.GL_ARRAY_BUFFER, texCoords.limit() * 4, texCoords.rewind(), GL2.GL_STATIC_DRAW);
}
finally
{
gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, 0);
}
return vboIds;
}
}