1 package org.newdawn.slick.opengl;
2
3 import java.nio.ByteBuffer;
4 import java.nio.ByteOrder;
5 import java.nio.IntBuffer;
6
7 import org.lwjgl.BufferUtils;
8 import org.newdawn.slick.opengl.renderer.Renderer;
9 import org.newdawn.slick.opengl.renderer.SGL;
10 import org.newdawn.slick.util.Log;
11
12 import javax.annotation.Nonnull;
13 import javax.annotation.Nullable;
14
15 /**
16 * A texture to be bound within JOGL. This object is responsible for
17 * keeping track of a given OpenGL texture and for calculating the
18 * texturing mapping coordinates of the full image.
19 *
20 * Since textures need to be powers of 2 the actual texture may be
21 * considerably bigged that the source image and hence the texture
22 * mapping coordinates need to be adjusted to matchup drawing the
23 * sprite against the texture.
24 *
25 * @author Kevin Glass
26 * @author Brian Matzon
27 */
28 public class TextureImpl implements Texture {
29 /** The renderer to use for all GL operations */
30 private static final SGL GL = Renderer.get();
31
32 /** The last texture that was bound to */
33 @Nullable
34 private static Texture lastBind;
35
36 /**
37 * Retrieve the last texture bound through the texture interface
38 *
39 * @return The last texture bound
40 */
41 @Nullable
42 public static Texture getLastBind() {
43 return lastBind;
44 }
45
46 /** The GL target type */
47 private int target;
48 /** The GL texture ID */
49 private int textureID = 0;
50 /** The height of the image */
51 private int height;
52 /** The width of the image */
53 private int width;
54 /** The width of the texture */
55 private int texWidth;
56 /** The height of the texture */
57 private int texHeight;
58 /** The ratio of the width of the image to the texture */
59 private float widthRatio;
60 /** The ratio of the height of the image to the texture */
61 private float heightRatio;
62 /** The format of this image. */
63 private ImageData.Format format;
64 /** The reference this texture was loaded from */
65 private String ref;
66 /** The name the texture has in the cache */
67 private String cacheName;
68
69 /** Data used to reload this texture */
70 private ReloadData reloadData;
71
72 /**
73 * For subclasses to utilise
74 */
75 TextureImpl() {
76 }
77
78 /**
79 * Create a new texture
80 *
81 * @param ref The reference this texture was loaded from
82 * @param target The GL target
83 * @param textureID The GL texture ID
84 */
85 public TextureImpl(String ref, int target,int textureID) {
86 this.target = target;
87 this.ref = ref;
88 this.textureID = textureID;
89 lastBind = this;
90 }
91
92 /**
93 * Set the name this texture is stored against in the cache
94 *
95 * @param cacheName The name the texture is stored against in the cache
96 */
97 public void setCacheName(String cacheName) {
98 this.cacheName = cacheName;
99 }
100
101 /**
102 * @see org.newdawn.slick.opengl.Texture#hasAlpha()
103 */
104 public boolean hasAlpha() {
105 return format.hasAlpha();
106 }
107
108 /**
109 * @see org.newdawn.slick.opengl.Texture#getTextureRef()
110 */
111 public String getTextureRef() {
112 return ref;
113 }
114
115 /**
116 * Set the format of the image
117 *
118 * @param imageFormat the format of the image this texture displays
119 */
120 public void setImageFormat(final ImageData.Format imageFormat) {
121 format = imageFormat;
122 }
123
124 /**
125 * Clear the binding of the texture
126 */
127 public static void bindNone() {
128 lastBind = null;
129 GL.glDisable(SGL.GL_TEXTURE_2D);
130 }
131
132 /**
133 * Clear slick caching of the last bound texture so that an
134 * external texture binder can play with the context before returning
135 * control to slick.
136 */
137 public static void unbind() {
138 lastBind = null;
139 }
140
141 /**
142 * @see org.newdawn.slick.opengl.Texture#bind()
143 */
144 public void bind() {
145 if (lastBind != this) {
146 lastBind = this;
147 GL.glEnable(SGL.GL_TEXTURE_2D);
148 GL.glBindTexture(target, textureID);
149 }
150 }
151
152 /**
153 * Set the height of the image
154 *
155 * @param height The height of the image
156 */
157 public void setHeight(int height) {
158 this.height = height;
159 setHeight();
160 }
161
162 /**
163 * Set the width of the image
164 *
165 * @param width The width of the image
166 */
167 public void setWidth(int width) {
168 this.width = width;
169 setWidth();
170 }
171
172 public ImageData.Format getImageFormat() {
173 return format;
174 }
175
176 /**
177 * @see org.newdawn.slick.opengl.Texture#getImageHeight()
178 */
179 public int getImageHeight() {
180 return height;
181 }
182
183 /**
184 * @see org.newdawn.slick.opengl.Texture#getImageWidth()
185 */
186 public int getImageWidth() {
187 return width;
188 }
189
190 /**
191 * @see org.newdawn.slick.opengl.Texture#getHeight()
192 */
193 public float getHeight() {
194 return heightRatio;
195 }
196
197 /**
198 * @see org.newdawn.slick.opengl.Texture#getWidth()
199 */
200 public float getWidth() {
201 return widthRatio;
202 }
203
204 /**
205 * @see org.newdawn.slick.opengl.Texture#getTextureHeight()
206 */
207 public int getTextureHeight() {
208 return texHeight;
209 }
210
211 /**
212 * @see org.newdawn.slick.opengl.Texture#getTextureWidth()
213 */
214 public int getTextureWidth() {
215 return texWidth;
216 }
217
218 /**
219 * Set the height of this texture
220 *
221 * @param texHeight The height of the texture
222 */
223 public void setTextureHeight(int texHeight) {
224 this.texHeight = texHeight;
225 setHeight();
226 }
227
228 /**
229 * Set the width of this texture
230 *
231 * @param texWidth The width of the texture
232 */
233 public void setTextureWidth(int texWidth) {
234 this.texWidth = texWidth;
235 setWidth();
236 }
237
238 /**
239 * Set the height of the texture. This will update the
240 * ratio also.
241 */
242 private void setHeight() {
243 if (texHeight != 0) {
244 heightRatio = ((float) height)/texHeight;
245 }
246 }
247
248 /**
249 * Set the width of the texture. This will update the
250 * ratio also.
251 */
252 private void setWidth() {
253 if (texWidth != 0) {
254 widthRatio = ((float) width)/texWidth;
255 }
256 }
257
258 /**
259 * @see org.newdawn.slick.opengl.Texture#release()
260 */
261 public void release() {
262 if (textureID == 0)
263 return;
264 InternalTextureLoader.deleteTextureID(textureID);
265
266 if (lastBind == this) {
267 bindNone();
268 }
269
270 if (cacheName != null) {
271 InternalTextureLoader.get().clear(cacheName);
272 } else {
273 InternalTextureLoader.get().clear(ref);
274 }
275 textureID = 0;
276 }
277
278 /**
279 * @see org.newdawn.slick.opengl.Texture#getTextureID()
280 */
281 public int getTextureID() {
282 return textureID;
283 }
284
285 /**
286 * Set the OpenGL texture ID for this texture
287 *
288 * @param textureID The OpenGL texture ID
289 */
290 void setTextureID(int textureID) {
291 this.textureID = textureID;
292 }
293
294 /**
295 * Creates an integer buffer to hold specified ints
296 * - strictly a utility method
297 *
298 * @param size how many int to contain
299 * @return created IntBuffer
300 */
301 @Nonnull
302 protected IntBuffer createIntBuffer(int size) {
303 ByteBuffer temp = ByteBuffer.allocateDirect(4 * size);
304 temp.order(ByteOrder.nativeOrder());
305
306 return temp.asIntBuffer();
307 }
308
309 /**
310 * @see org.newdawn.slick.opengl.Texture#getTextureData()
311 */
312 public byte[] getTextureData() {
313 ByteBuffer buffer = BufferUtils.createByteBuffer(format.getColorComponents() * texWidth * texHeight);
314 bind();
315 GL.glGetTexImage(SGL.GL_TEXTURE_2D, 0, format.getOGLType(), SGL.GL_UNSIGNED_BYTE,
316 buffer);
317 byte[] data = new byte[buffer.limit()];
318 buffer.get(data);
319 buffer.clear();
320
321 return data;
322 }
323
324 /**
325 * @see org.newdawn.slick.opengl.Texture#setTextureFilter(int)
326 */
327 public void setTextureFilter(int textureFilter) {
328 bind();
329 GL.glTexParameteri(target, SGL.GL_TEXTURE_MIN_FILTER, textureFilter);
330 GL.glTexParameteri(target, SGL.GL_TEXTURE_MAG_FILTER, textureFilter);
331 }
332
333 /**
334 * Set the texture data that this texture can be reloaded from
335 *
336 * @param srcPixelFormat The pixel format
337 * @param componentCount The component count
338 * @param minFilter The OpenGL minification filter
339 * @param magFilter The OpenGL magnification filter
340 * @param textureBuffer The texture buffer containing the data for the texture
341 */
342 public void setTextureData(int srcPixelFormat, int componentCount,
343 int minFilter, int magFilter, ByteBuffer textureBuffer) {
344 reloadData = new ReloadData();
345 reloadData.srcPixelFormat = srcPixelFormat;
346 reloadData.componentCount = componentCount;
347 reloadData.minFilter = minFilter;
348 reloadData.magFilter = magFilter;
349 reloadData.textureBuffer = textureBuffer;
350 }
351
352 /**
353 * Reload this texture if it is holding texture data (release() should be called before this).
354 * This is generally done internally (i.e. for use with context switches in Android / OpenGL ES)
355 */
356 public void reload() {
357 if (reloadData != null) {
358 textureID = reloadData.reload();
359 }
360 }
361
362 /**
363 * Reload this texture from it's original source data
364 */
365 private class ReloadData {
366 /** The src pixel format */
367 private int srcPixelFormat;
368 /** The component count */
369 private int componentCount;
370 /** The OpenGL minification filter */
371 private int minFilter;
372 /** The OpenGL magnification filter */
373 private int magFilter;
374 /** The texture buffer of pixel data */
375 private ByteBuffer textureBuffer;
376
377 /**
378 * Reload this texture
379 *
380 * @return The new texture ID assigned to this texture
381 */
382 public int reload() {
383 Log.error("Reloading texture: "+ref);
384 return InternalTextureLoader.get().reload(TextureImpl.this, srcPixelFormat, componentCount, minFilter, magFilter, textureBuffer);
385 }
386 }
387 }