* May have to wait for the bufferLock to open.
*/
public void setupBuffers(int numbRegionsWide, int bufferMaxCapacity)
{
bufferLock.lock();
previousRegionWidth = numbRegionsWide;
previousBufferSize = bufferMaxCapacity;
buildableBuffers = new BufferBuilder[numbRegionsWide][numbRegionsWide];
buildableVbos = new VertexBuffer[numbRegionsWide][numbRegionsWide];
drawableVbos = new VertexBuffer[numbRegionsWide][numbRegionsWide];
for (int x = 0; x < numbRegionsWide; x++)
{
for (int z = 0; z < numbRegionsWide; z++)
{
buildableBuffers[x][z] = new BufferBuilder(bufferMaxCapacity);
buildableVbos[x][z] = new VertexBuffer(LodRenderer.LOD_VERTEX_FORMAT);
drawableVbos[x][z] = new VertexBuffer(LodRenderer.LOD_VERTEX_FORMAT);
}
}
bufferLock.unlock();
}
/**
* sets the buffers and Vbos to null, forcing them to be recreated.
*
* May have to wait for the bufferLock to open. */ public void destroyBuffers() { bufferLock.lock(); buildableBuffers = null; buildableVbos = null; drawableVbos = null; bufferLock.unlock(); } /** * Calls begin on each of the buildable BufferBuilders. */ private void startBuffers(boolean fullRegen, LodDimension lodDim) { for (int x = 0; x < buildableBuffers.length; x++) { for (int z = 0; z < buildableBuffers.length; z++) { if (fullRegen || lodDim.regen[x][z]) { buildableBuffers[x][z].begin(GL11.GL_QUADS, LodRenderer.LOD_VERTEX_FORMAT); } } } } /** * Calls end on each of the buildable BufferBuilders. */ private void closeBuffers(boolean fullRegen, LodDimension lodDim) { for (int x = 0; x < buildableBuffers.length; x++) for (int z = 0; z < buildableBuffers.length; z++) if (buildableBuffers[x][z] != null && buildableBuffers[x][z].building() && (fullRegen || lodDim.regen[x][z])) buildableBuffers[x][z].end(); } /** * Upload all buildableBuffers to the GPU. */ private void uploadBuffers(boolean fullRegen, LodDimension lodDim) { GlProxy glProxy = GlProxy.getInstance(); // make sure we are uploading to a different OpenGL context, // to prevent interference (IE stuttering) with the Minecraft context. glProxy.setGlContext(GlProxyContext.LOD_BUILDER); // only print console debugging for vboUpload once per upload cycle boolean bufferMapFail = false; for (int x = 0; x < buildableVbos.length; x++) { for (int z = 0; z < buildableVbos.length; z++) { if (fullRegen || lodDim.regen[x][z]) { ByteBuffer builderBuffer = buildableBuffers[x][z].popNextBuffer().getSecond(); bufferMapFail = vboUpload(buildableVbos[x][z], builderBuffer, bufferMapFail); lodDim.regen[x][z] = false; } } } // make sure all the buffers have been uploaded. // this probably is necessary, but it makes me feel good :) GL11.glFlush(); glProxy.setGlContext(GlProxyContext.NONE); } /** * Uploads the uploadBuffer into the VBO in GPU memory. */ private boolean vboUpload(VertexBuffer vbo, ByteBuffer uploadBuffer, boolean bufferMapFail) { // this shouldn't happen, but just to be safe if (vbo.id != -1) { vbo.vertexCount = uploadBuffer.remaining() / vbo.format.getVertexSize(); GL15C.glBindBuffer(GL15.GL_ARRAY_BUFFER, vbo.id); // make sure enough space is allocated to fit the builderBuffer GL15C.glBufferData(GL15.GL_ARRAY_BUFFER, uploadBuffer.capacity(), GL15C.GL_DYNAMIC_DRAW); // try to get a pointer to the VBO's byteBuffer in GPU memory ByteBuffer vboBuffer = GL15C.glMapBuffer(GL15.GL_ARRAY_BUFFER, GL15.GL_WRITE_ONLY); // upload the builderBuffer to the GPU if (vboBuffer != null) { // This is the best way to upload lots of data, since writes directly to GPU // memory, and doesn't pause OpenGL. vboBuffer.put(uploadBuffer); } else { // Sometimes the vboBuffer is null (I think it may be due to buffer sizes // changing or a setup process that didn't complete), so in that case // we have to use this method which is slower and pauses OpenGL, // but always succeeds. GL15C.glBufferData(GL15.GL_ARRAY_BUFFER, uploadBuffer, GL15C.GL_DYNAMIC_DRAW); // only print to console once per upload cycle if (!bufferMapFail) ClientProxy.LOGGER.debug("LOD buffer upload: glMapBuffer failed, used slower glBufferData."); bufferMapFail = true; } GL15C.glUnmapBuffer(GL15.GL_ARRAY_BUFFER); GL15C.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0); } // just used to improve debug printing return bufferMapFail; } /** * Get the newly created VBOs */ public VertexBuffersAndOffset getVertexBuffers() { // don't wait for the lock to open // since this is called on the main render thread if (bufferLock.tryLock()) { VertexBuffer[][] tmpVbo = drawableVbos; drawableVbos = buildableVbos; buildableVbos = tmpVbo; drawableCenterChunkPos = buildableCenterChunkPos; // the vbos have been swapped switchVbos = false; bufferLock.unlock(); } return new VertexBuffersAndOffset(drawableVbos, drawableCenterChunkPos); } /** * A simple container to pass multiple objects back in the getVertexBuffers method. */ public class VertexBuffersAndOffset { public VertexBuffer[][] vbos; public ChunkPos drawableCenterChunkPos; public VertexBuffersAndOffset(VertexBuffer[][] newVbos, ChunkPos newDrawableCenterChunkPos) { vbos = newVbos; drawableCenterChunkPos = newDrawableCenterChunkPos; } } /** * If this is true the buildable near and far * buffers have been generated and are ready to be * sent to the LodRenderer. */ public boolean newBuffersAvaliable() { return switchVbos; } }