View Javadoc
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 }