1 package com.badlogic.gdx.graphics.g3d.utils;
3 import java.nio.IntBuffer;
5 import com.badlogic.gdx.Gdx;
6 import com.badlogic.gdx.graphics.GL10;
7 import com.badlogic.gdx.graphics.GL20;
8 import com.badlogic.gdx.graphics.Texture;
9 import com.badlogic.gdx.utils.BufferUtils;
10 import com.badlogic.gdx.utils.GdxRuntimeException;
12 /** Class that you assign a range of texture units and binds textures for you within that range.
13 * It does some basic usage tracking to avoid unnessecary bind calls.
15 public final class DefaultTextureBinder implements TextureBinder {
16 public final static int ROUNDROBIN = 0;
17 public final static int WEIGHTED = 1;
18 /** GLES only supports up to 32 textures */
19 public final static int MAX_GLES_UNITS = 32;
20 /** The index of the first exclusive texture unit */
21 private final int offset;
22 /** The amount of exclusive textures that may be used */
23 private final int count;
24 /** The weight added to a texture when its reused */
25 private final int reuseWeight;
26 /** The textures currently exclusive bound */
27 private final Texture[] textures;
28 /** The weight (reuseWeight * reused - discarded) of the textures */
29 private final int[] weights;
30 /** The method of binding to use */
31 private final int method;
32 /** Flag to indicate the current texture is reused */
33 private boolean reused;
35 private int reuseCount = 0; // TODO remove debug code
36 private int bindCount = 0; // TODO remove debug code
38 /** Uses all available texture units and reuse weight of 3 */
39 public DefaultTextureBinder(final int method) {
43 /** Uses all remaining texture units and reuse weight of 3 */
44 public DefaultTextureBinder(final int method, final int offset) {
45 this(method, offset, -1);
48 /** Uses reuse weight of 10 */
49 public DefaultTextureBinder(final int method, final int offset, final int count) {
50 this(method, offset, count, 10);
53 public DefaultTextureBinder(final int method, final int offset, int count, final int reuseWeight) {
54 final int max = Math.min(getMaxTextureUnits(), MAX_GLES_UNITS);
57 if (offset < 0 || count < 0 || (offset + count) > max || reuseWeight < 1)
58 throw new GdxRuntimeException("Illegal arguments");
62 this.textures = new Texture[count];
63 this.reuseWeight = reuseWeight;
64 this.weights = (method == WEIGHTED) ? new int[count] : null;
67 private static int getMaxTextureUnits () {
68 IntBuffer buffer = BufferUtils.newIntBuffer(16);
69 if (Gdx.graphics.isGL20Available())
70 Gdx.gl.glGetIntegerv(GL20.GL_MAX_TEXTURE_IMAGE_UNITS, buffer);
72 Gdx.gl.glGetIntegerv(GL10.GL_MAX_TEXTURE_UNITS, buffer);
77 public void begin () {
78 for(int i = 0; i < count; i++) {
80 if(weights != null) weights[i] = 0;
86 /* No need to unbind and textures are set to null in begin()
87 for(int i = 0; i < count; i++) {
88 if (textures[i] != null) {
89 Gdx.gl.glActiveTexture(GL20.GL_TEXTURE0 + offset + i);
90 Gdx.gl.glBindTexture(GL20.GL_TEXTURE_2D, 0);
94 Gdx.gl.glActiveTexture(GL20.GL_TEXTURE0);
98 public final int bind(final TextureDescriptor textureDesc) {
99 return bindTexture(textureDesc, false);
102 private final TextureDescriptor tempDesc = new TextureDescriptor();
104 public final int bind(final Texture texture) {
105 tempDesc.set(texture, null, null, null, null);
106 return bindTexture(tempDesc, false);
109 private final int bindTexture(final TextureDescriptor textureDesc, final boolean rebind) {
110 final int idx, result;
111 final Texture texture = textureDesc.texture;
115 case ROUNDROBIN: result = offset + (idx = bindTextureRoundRobin(texture)); break;
116 case WEIGHTED: result = offset + (idx = bindTextureWeighted(texture)); break;
123 texture.bind(result);
125 Gdx.gl.glActiveTexture(GL10.GL_TEXTURE0 + result);
128 texture.unsafeSetWrap(textureDesc.uWrap, textureDesc.vWrap);
129 texture.unsafeSetFilter(textureDesc.minFilter, textureDesc.magFilter);
133 private int currentTexture = 0;
134 private final int bindTextureRoundRobin(final Texture texture) {
135 for (int i = 0; i < count; i++) {
136 final int idx = (currentTexture + i) % count;
137 if (textures[idx] == texture) {
142 currentTexture = (currentTexture + 1) % count;
143 textures[currentTexture] = texture;
144 texture.bind(offset + currentTexture);
145 return currentTexture;
148 private final int bindTextureWeighted(final Texture texture) {
150 int weight = weights[0];
152 for (int i = 0; i < count; i++) {
153 if (textures[i] == texture) {
155 weights[i]+=reuseWeight;
156 } else if (weights[i] < 0 || --weights[i] < weight) {
162 textures[windex] = texture;
163 weights[windex] = 100;
164 texture.bind(offset + (result = windex));
171 public final int getBindCount() { return bindCount; }
174 public final int getReuseCount() { return reuseCount; }
177 public final void resetCounts() { bindCount = reuseCount = 0; }