OSDN Git Service

Merge branch 'origin/master'
[mikumikustudio/libgdx-mikumikustudio.git] / gdx / src / com / badlogic / gdx / graphics / g3d / utils / DefaultTextureBinder.java
1 package com.badlogic.gdx.graphics.g3d.utils;
2
3 import java.nio.IntBuffer;
4
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;
11
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. 
14  * @author xoppa */
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 TextureDescriptor[] 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;
34         
35         private int reuseCount = 0; // TODO remove debug code
36         private int bindCount = 0; // TODO remove debug code
37         
38         /** Uses all available texture units and reuse weight of 3 */
39         public DefaultTextureBinder(final int method) {
40                 this(method, 0);
41         }
42         
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);
46         }
47         
48         /** Uses reuse weight of 10 */
49         public DefaultTextureBinder(final int method, final int offset, final int count) {
50                 this(method, offset, count, 10);
51         }
52         
53         public DefaultTextureBinder(final int method, final int offset, int count, final int reuseWeight) {
54                 final int max = Math.min(getMaxTextureUnits(), MAX_GLES_UNITS);
55                 if (count < 0)
56                         count = max - offset;
57                 if (offset < 0 || count < 0 || (offset + count) > max || reuseWeight < 1)
58                         throw new GdxRuntimeException("Illegal arguments");
59                 this.method = method;
60                 this.offset = offset;
61                 this.count = count;
62                 this.textures = new TextureDescriptor[count];
63                 for (int i = 0; i < count; i++)
64                         this.textures[i] = new TextureDescriptor();
65                 this.reuseWeight = reuseWeight;
66                 this.weights = (method == WEIGHTED) ? new int[count] : null;
67         }
68
69         private static int getMaxTextureUnits () {
70                 IntBuffer buffer = BufferUtils.newIntBuffer(16);
71                 if (Gdx.graphics.isGL20Available())
72                         Gdx.gl.glGetIntegerv(GL20.GL_MAX_TEXTURE_IMAGE_UNITS, buffer);
73                 else
74                         Gdx.gl.glGetIntegerv(GL10.GL_MAX_TEXTURE_UNITS, buffer);
75                 return buffer.get(0);
76         }
77
78         @Override
79         public void begin () {
80                 for(int i = 0; i < count; i++) {
81                         textures[i].reset();
82                         if(weights != null) weights[i] = 0;
83                 }
84         }
85
86         @Override
87         public void end () {
88                 for(int i = 0; i < count; i++) {
89                         if (textures[i].texture != null) {
90                                 Gdx.gl.glActiveTexture(GL20.GL_TEXTURE0 + offset + i);
91                                 Gdx.gl.glBindTexture(GL20.GL_TEXTURE_2D, 0);
92                                 textures[i].texture = null;
93                         }
94                 }
95                 Gdx.gl.glActiveTexture(GL20.GL_TEXTURE0);
96         }
97         
98         /** Binds the texture if needed and sets it active, returns the unit */
99         @Override
100         public final int bind(final TextureDescriptor textureDesc) {
101                 return bindTexture(textureDesc, false);
102         }
103
104         private final int bindTexture(final TextureDescriptor textureDesc, final boolean rebind) {
105                 int idx, result;
106                 reused = false;
107                 
108                 switch (method) {
109                 case ROUNDROBIN: result = offset + (idx = bindTextureRoundRobin(textureDesc.texture)); break;
110                 case WEIGHTED: result = offset + (idx = bindTextureWeighted(textureDesc.texture)); break;
111                 default: return -1; 
112                 }
113                 
114                 if (reused) {
115                         reuseCount++;
116                         if (rebind)
117                                 textureDesc.texture.bind(result);
118                         else
119                                 Gdx.gl.glActiveTexture(GL10.GL_TEXTURE0 + result);
120                 } else
121                         bindCount++;
122                 if (textureDesc.minFilter != GL10.GL_INVALID_VALUE && textureDesc.minFilter != textures[idx].minFilter)
123                         Gdx.gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, textures[idx].minFilter = textureDesc.minFilter);
124                 if (textureDesc.magFilter != GL10.GL_INVALID_VALUE && textureDesc.magFilter != textures[idx].magFilter)
125                         Gdx.gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, textures[idx].magFilter = textureDesc.magFilter);
126                 if (textureDesc.uWrap != GL10.GL_INVALID_VALUE && textureDesc.uWrap != textures[idx].uWrap)
127                         Gdx.gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, textures[idx].uWrap = textureDesc.uWrap);
128                 if (textureDesc.vWrap != GL10.GL_INVALID_VALUE && textureDesc.vWrap != textures[idx].vWrap)
129                         Gdx.gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, textures[idx].vWrap = textureDesc.vWrap);
130                 return result;
131         }
132
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 == texture) {
138                                 reused = true;
139                                 return idx;
140                         }
141                 }
142                 currentTexture = (currentTexture + 1) % count;
143                 textures[currentTexture].texture = texture;
144                 texture.bind(offset + currentTexture);
145                 return currentTexture;
146         }
147         
148         private final int bindTextureWeighted(final Texture texture) {
149                 int result = -1;
150                 int weight = weights[0];
151                 int windex = 0;
152                 for (int i = 0; i < count; i++) {
153                         if (textures[i].texture == texture) {
154                                 result = i;
155                                 weights[i]+=reuseWeight;
156                         } else if (weights[i] < 0 || --weights[i] < weight) {
157                                 weight = weights[i];
158                                 windex = i;
159                         }
160                 }
161                 if (result < 0) {
162                         textures[windex].texture = texture;
163                         weights[windex] = 100;
164                         texture.bind(offset + (result = windex));
165                 } else 
166                         reused = true;
167                 return result;
168         }
169         
170         @Override
171         public final int getBindCount() { return bindCount; }
172         
173         @Override
174         public final int getReuseCount() { return reuseCount; }
175         
176         @Override
177         public final void resetCounts() { bindCount = reuseCount = 0; }
178 }