/*******************************************************************************
* 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.render.fastshape;
import java.nio.Buffer;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import javax.media.opengl.GL2;
/**
* Abstract class representing an OpenGL VBO (Vertex Buffer Object). Contains
* methods for binding the buffer and updating the buffer data.
*
* @author Michael de Hoog (michael.dehoog@ga.gov.au)
*/
public abstract class AbstractVBO<ARRAY>
{
private ARRAY buffer = null;
private int vboId = -1;
private boolean dirty = false;
private Lock lock = new ReentrantLock();
private boolean uploadRequired = true;
/**
* @return This VBO's data array
*/
public ARRAY getBuffer()
{
return buffer;
}
/**
* Set this VBO's data array. The array will be passed to the video card
* upon the next call to {@link #bind(GL)}.
*
* @param buffer
*/
public void setBuffer(ARRAY buffer)
{
if (!uploadRequired)
{
uploadRequired = this.buffer != buffer;
}
this.buffer = buffer;
markDirty();
}
/**
* Mark this VBO's data array as dirty. The array will be passed to the
* video card upon the next call to {@link #bind(GL)}. Also called
* internally by {@link #setBuffer(ARRAY)}.
*/
public void markDirty()
{
dirty = true;
}
/**
* Mark this VBO as locked for writing. While this is locked, the
* {@link #bind(GL)} method will not upload the buffer to the video card.
*/
public void lock()
{
lock.lock();
}
/**
* Mark this VBO as unlocked. The {@link #bind(GL)} method will now be able
* to upload the buffer if it's dirty.
*/
public void unlock()
{
lock.unlock();
}
/**
* Bind this VBO's buffer. Also uploads the buffer to the video card if it
* is dirty.
*
* @param gl
* OpenGL context
*/
public void bind(GL2 gl)
{
if (vboId < 0)
{
int[] vboIds = new int[1];
gl.glGenBuffers(vboIds.length, vboIds, 0);
vboId = vboIds[0];
}
gl.glBindBuffer(getTarget(), vboId);
if (dirty)
{
boolean locked = false;
if (uploadRequired)
{
lock.lock();
uploadRequired = false;
locked = true;
}
else
{
locked = lock.tryLock();
}
if (locked)
{
try
{
Buffer b = wrapBuffer(buffer);
gl.glBufferData(getTarget(), b.limit() * getDataSize(), b.rewind(), GL2.GL_STATIC_DRAW);
dirty = false;
}
finally
{
lock.unlock();
}
}
}
}
/**
* Unbind this VBO.
*
* @param gl
* OpenGL context
*/
public void unbind(GL2 gl)
{
gl.glBindBuffer(getTarget(), 0);
}
/**
* @return OpenGL target to which to bind/unbind this VBO. Either
* {@link GL#GL_ARRAY_BUFFER} or {@link GL#GL_ELEMENT_ARRAY_BUFFER}.
*/
protected abstract int getTarget();
/**
* Wrap this VBO's array in a java.nio {@link Buffer} class. Used when
* uploading the array to the video card.
*
* @param buffer
* Array to wrap
* @return Wrapped buffer
*/
protected abstract Buffer wrapBuffer(ARRAY buffer);
/**
* @return Data size of each buffer element, in bytes.
*/
protected abstract int getDataSize();
}