Home | History | Annotate | Download | only in glutils
      1 /*******************************************************************************
      2  * Copyright 2011 See AUTHORS file.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *   http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  ******************************************************************************/
     16 
     17 package com.badlogic.gdx.graphics.glutils;
     18 
     19 import java.nio.ByteBuffer;
     20 import java.nio.ShortBuffer;
     21 
     22 import com.badlogic.gdx.Gdx;
     23 import com.badlogic.gdx.graphics.GL20;
     24 import com.badlogic.gdx.utils.BufferUtils;
     25 import com.badlogic.gdx.utils.GdxRuntimeException;
     26 
     27 /** <p>
     28  * In IndexBufferObject wraps OpenGL's index buffer functionality to be used in conjunction with VBOs. This class can be
     29  * seamlessly used with OpenGL ES 1.x and 2.0.
     30  * </p>
     31  *
     32  * <p>
     33  * Uses indirect Buffers on Android 1.5/1.6 to fix GC invocation due to leaking PlatformAddress instances.
     34  * </p>
     35  *
     36  * <p>
     37  * You can also use this to store indices for vertex arrays. Do not call {@link #bind()} or {@link #unbind()} in this case but
     38  * rather use {@link #getBuffer()} to use the buffer directly with glDrawElements. You must also create the IndexBufferObject with
     39  * the second constructor and specify isDirect as true as glDrawElements in conjunction with vertex arrays needs direct buffers.
     40  * </p>
     41  *
     42  * <p>
     43  * VertexBufferObjects must be disposed via the {@link #dispose()} method when no longer needed
     44  * </p>
     45  *
     46  * @author mzechner */
     47 public class IndexBufferObjectSubData implements IndexData {
     48 	final ShortBuffer buffer;
     49 	final ByteBuffer byteBuffer;
     50 	int bufferHandle;
     51 	final boolean isDirect;
     52 	boolean isDirty = true;
     53 	boolean isBound = false;
     54 	final int usage;
     55 
     56 	/** Creates a new IndexBufferObject.
     57 	 *
     58 	 * @param isStatic whether the index buffer is static
     59 	 * @param maxIndices the maximum number of indices this buffer can hold */
     60 	public IndexBufferObjectSubData (boolean isStatic, int maxIndices) {
     61 		byteBuffer = BufferUtils.newByteBuffer(maxIndices * 2);
     62 		isDirect = true;
     63 
     64 		usage = isStatic ? GL20.GL_STATIC_DRAW : GL20.GL_DYNAMIC_DRAW;
     65 		buffer = byteBuffer.asShortBuffer();
     66 		buffer.flip();
     67 		byteBuffer.flip();
     68 		bufferHandle = createBufferObject();
     69 	}
     70 
     71 	/** Creates a new IndexBufferObject to be used with vertex arrays.
     72 	 *
     73 	 * @param maxIndices the maximum number of indices this buffer can hold */
     74 	public IndexBufferObjectSubData (int maxIndices) {
     75 		byteBuffer = BufferUtils.newByteBuffer(maxIndices * 2);
     76 		this.isDirect = true;
     77 
     78 		usage = GL20.GL_STATIC_DRAW;
     79 		buffer = byteBuffer.asShortBuffer();
     80 		buffer.flip();
     81 		byteBuffer.flip();
     82 		bufferHandle = createBufferObject();
     83 	}
     84 
     85 	private int createBufferObject () {
     86 		int result = Gdx.gl20.glGenBuffer();
     87 		Gdx.gl20.glBindBuffer(GL20.GL_ELEMENT_ARRAY_BUFFER, result);
     88 		Gdx.gl20.glBufferData(GL20.GL_ELEMENT_ARRAY_BUFFER, byteBuffer.capacity(), null, usage);
     89 		Gdx.gl20.glBindBuffer(GL20.GL_ELEMENT_ARRAY_BUFFER, 0);
     90 		return result;
     91 	}
     92 
     93 	/** @return the number of indices currently stored in this buffer */
     94 	public int getNumIndices () {
     95 		return buffer.limit();
     96 	}
     97 
     98 	/** @return the maximum number of indices this IndexBufferObject can store. */
     99 	public int getNumMaxIndices () {
    100 		return buffer.capacity();
    101 	}
    102 
    103 	/** <p>
    104 	 * Sets the indices of this IndexBufferObject, discarding the old indices. The count must equal the number of indices to be
    105 	 * copied to this IndexBufferObject.
    106 	 * </p>
    107 	 *
    108 	 * <p>
    109 	 * This can be called in between calls to {@link #bind()} and {@link #unbind()}. The index data will be updated instantly.
    110 	 * </p>
    111 	 *
    112 	 * @param indices the vertex data
    113 	 * @param offset the offset to start copying the data from
    114 	 * @param count the number of floats to copy */
    115 	public void setIndices (short[] indices, int offset, int count) {
    116 		isDirty = true;
    117 		buffer.clear();
    118 		buffer.put(indices, offset, count);
    119 		buffer.flip();
    120 		byteBuffer.position(0);
    121 		byteBuffer.limit(count << 1);
    122 
    123 		if (isBound) {
    124 			Gdx.gl20.glBufferSubData(GL20.GL_ELEMENT_ARRAY_BUFFER, 0, byteBuffer.limit(), byteBuffer);
    125 			isDirty = false;
    126 		}
    127 	}
    128 
    129 	public void setIndices (ShortBuffer indices) {
    130 		int pos = indices.position();
    131 		isDirty = true;
    132 		buffer.clear();
    133 		buffer.put(indices);
    134 		buffer.flip();
    135 		indices.position(pos);
    136 		byteBuffer.position(0);
    137 		byteBuffer.limit(buffer.limit() << 1);
    138 
    139 		if (isBound) {
    140 			Gdx.gl20.glBufferSubData(GL20.GL_ELEMENT_ARRAY_BUFFER, 0, byteBuffer.limit(), byteBuffer);
    141 			isDirty = false;
    142 		}
    143 	}
    144 
    145 	@Override
    146 	public void updateIndices (int targetOffset, short[] indices, int offset, int count) {
    147 		isDirty = true;
    148 		final int pos = byteBuffer.position();
    149 		byteBuffer.position(targetOffset * 2);
    150 		BufferUtils.copy(indices, offset, byteBuffer, count);
    151 		byteBuffer.position(pos);
    152 		buffer.position(0);
    153 
    154 		if (isBound) {
    155 			Gdx.gl20.glBufferSubData(GL20.GL_ELEMENT_ARRAY_BUFFER, 0, byteBuffer.limit(), byteBuffer);
    156 			isDirty = false;
    157 		}
    158 	}
    159 
    160 
    161 	/** <p>
    162 	 * Returns the underlying ShortBuffer. If you modify the buffer contents they wil be uploaded on the call to {@link #bind()}.
    163 	 * If you need immediate uploading use {@link #setIndices(short[], int, int)}.
    164 	 * </p>
    165 	 *
    166 	 * @return the underlying short buffer. */
    167 	public ShortBuffer getBuffer () {
    168 		isDirty = true;
    169 		return buffer;
    170 	}
    171 
    172 	/** Binds this IndexBufferObject for rendering with glDrawElements. */
    173 	public void bind () {
    174 		if (bufferHandle == 0) throw new GdxRuntimeException("buuh");
    175 
    176 		Gdx.gl20.glBindBuffer(GL20.GL_ELEMENT_ARRAY_BUFFER, bufferHandle);
    177 		if (isDirty) {
    178 			byteBuffer.limit(buffer.limit() * 2);
    179 			Gdx.gl20.glBufferSubData(GL20.GL_ELEMENT_ARRAY_BUFFER, 0, byteBuffer.limit(), byteBuffer);
    180 			isDirty = false;
    181 		}
    182 		isBound = true;
    183 	}
    184 
    185 	/** Unbinds this IndexBufferObject. */
    186 	public void unbind () {
    187 		Gdx.gl20.glBindBuffer(GL20.GL_ELEMENT_ARRAY_BUFFER, 0);
    188 		isBound = false;
    189 	}
    190 
    191 	/** Invalidates the IndexBufferObject so a new OpenGL buffer handle is created. Use this in case of a context loss. */
    192 	public void invalidate () {
    193 		bufferHandle = createBufferObject();
    194 		isDirty = true;
    195 	}
    196 
    197 	/** Disposes this IndexBufferObject and all its associated OpenGL resources. */
    198 	public void dispose () {
    199 		GL20 gl = Gdx.gl20;
    200 		gl.glBindBuffer(GL20.GL_ELEMENT_ARRAY_BUFFER, 0);
    201 		gl.glDeleteBuffer(bufferHandle);
    202 		bufferHandle = 0;
    203 	}
    204 }
    205