Scirenderer: Fix memleak: textures were not correctly disposed
[scilab.git] / scilab / modules / scirenderer / src / org / scilab / forge / scirenderer / implementation / jogl / texture / JoGLTextureManager.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2009-2012 - DIGITEO - Pierre Lando
4  *
5  * This file must be used under the terms of the CeCILL.
6  * This source file is licensed as described in the file COPYING, which
7  * you should have received as part of this distribution.  The terms
8  * are also available at
9  * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
10  */
11
12 package org.scilab.forge.scirenderer.implementation.jogl.texture;
13
14 import com.jogamp.opengl.util.texture.TextureIO;
15 import com.jogamp.opengl.util.awt.TextureRenderer;
16 import com.jogamp.opengl.util.texture.TextureCoords;
17
18 import org.scilab.forge.scirenderer.DrawingTools;
19 import org.scilab.forge.scirenderer.SciRendererException;
20 import org.scilab.forge.scirenderer.buffers.ElementsBuffer;
21 import org.scilab.forge.scirenderer.implementation.jogl.JoGLCanvas;
22 import org.scilab.forge.scirenderer.implementation.jogl.JoGLDrawingTools;
23 import org.scilab.forge.scirenderer.texture.AbstractTexture;
24 import org.scilab.forge.scirenderer.texture.AnchorPosition;
25 import org.scilab.forge.scirenderer.texture.Texture;
26 import org.scilab.forge.scirenderer.texture.TextureManager;
27 import org.scilab.forge.scirenderer.texture.TextureDataProvider;
28 import org.scilab.forge.scirenderer.tranformations.Transformation;
29 import org.scilab.forge.scirenderer.tranformations.TransformationManager;
30 import org.scilab.forge.scirenderer.tranformations.Vector3d;
31
32 import javax.media.opengl.GLContext;
33
34 import javax.media.opengl.GL;
35 import javax.media.opengl.GL2;
36 import javax.media.opengl.GL2ES1;
37 import javax.media.opengl.GL2GL3;
38 import javax.media.opengl.GLProfile;
39 import java.awt.AlphaComposite;
40 import java.awt.Dimension;
41 import java.awt.Graphics2D;
42 import java.nio.ByteBuffer;
43 import java.nio.ByteOrder;
44 import java.nio.FloatBuffer;
45 import java.util.Collection;
46 import java.util.HashSet;
47 import java.util.Set;
48
49 /**
50  * @author Pierre Lando
51  */
52 public class JoGLTextureManager implements TextureManager {
53
54     private final Set<JoGLTexture> allTextures = new HashSet<JoGLTexture>();
55     JoGLCanvas canvas;
56
57     public JoGLTextureManager(JoGLCanvas canvas) {
58         this.canvas = canvas;
59     }
60
61     /**
62      * Texture binder.
63      * Bind the given texture to the given OpenGl context.
64      * @param drawingTools drawing tools.
65      * @param texture given texture.
66      * @throws org.scilab.forge.scirenderer.SciRendererException if the texture can't be bind.
67      */
68     public void bind(JoGLDrawingTools drawingTools, Texture texture) throws SciRendererException {
69         if ((texture instanceof JoGLTexture) && (allTextures.contains((JoGLTexture) texture))) {
70             ((JoGLTexture) texture).bind(drawingTools);
71         }
72     }
73
74     /**
75      * Draw the given texture.
76      * @param drawingTools used drawing tools.
77      * @param texture the texture too drawn.
78      * @throws org.scilab.forge.scirenderer.SciRendererException if the texture is invalid.
79      */
80     public void draw(JoGLDrawingTools drawingTools, Texture texture) throws SciRendererException {
81         if ((texture instanceof JoGLTexture) && (allTextures.contains((JoGLTexture) texture))) {
82             final JoGLTexture jt = (JoGLTexture) texture;
83             if (jt.preDraw(drawingTools)) {
84                 jt.draw(drawingTools);
85                 jt.postDraw(drawingTools);
86             }
87         }
88     }
89
90     public void draw(JoGLDrawingTools drawingTools, Texture texture, AnchorPosition anchor, ElementsBuffer positions, double rotationAngle) throws SciRendererException {
91         if ((texture instanceof JoGLTexture) && (allTextures.contains((JoGLTexture) texture))) {
92             if (positions != null) {
93                 FloatBuffer data = positions.getData();
94                 if (data != null) {
95                     data.rewind();
96                     float[] position = {0, 0, 0, 1};
97                     final JoGLTexture jt = (JoGLTexture) texture;
98                     if (jt.preDraw(drawingTools)) {
99                         while (data.remaining() >= 4) {
100                             data.get(position);
101                             jt.draw(drawingTools, anchor, new Vector3d(position), rotationAngle);
102                         }
103                         jt.postDraw(drawingTools);
104                     }
105                 }
106             }
107         }
108     }
109
110     public void draw(JoGLDrawingTools drawingTools, Texture texture, AnchorPosition anchor, Vector3d position, double rotationAngle) throws SciRendererException {
111         if ((texture instanceof JoGLTexture) && (allTextures.contains((JoGLTexture) texture))) {
112             final JoGLTexture jt = (JoGLTexture) texture;
113             jt.preDraw(drawingTools);
114             jt.draw(drawingTools, anchor, position, rotationAngle);
115             jt.postDraw(drawingTools);
116         }
117     }
118
119     /** Called when gl context is gone. */
120     public void glReload() {
121         for (JoGLTexture texture : allTextures) {
122             texture.glReload();
123         }
124     }
125
126     @Override
127     public Texture createTexture() {
128         JoGLTexture texture = new JoGLTexture();
129         allTextures.add(texture);
130         return texture;
131     }
132
133     @Override
134     public void dispose(Collection<Texture> textures) {
135         for (Texture texture : textures) {
136             dispose(texture);
137         }
138     }
139
140     @Override
141     public void dispose(Texture texture) {
142         if ((texture instanceof JoGLTexture) && (allTextures.contains((JoGLTexture) texture))) {
143             allTextures.remove((JoGLTexture) texture);
144             ((JoGLTexture) texture).dispose();
145         }
146     }
147
148     /**
149      * Inner class for {@link Texture} implementation.
150      */
151     public class JoGLTexture extends AbstractTexture implements Texture {
152         private com.jogamp.opengl.util.texture.Texture[] textures;
153         private JoGLTextureData[] textureData;
154         private int wCuts;
155         private int hCuts;
156         private double sfactor = 1;
157         private double tfactor = 1;
158         private ByteBuffer buffer;
159         private TextureDataProvider.ImageType previousType;
160         private JoGLDrawingTools drawingTools;
161
162         /**
163          * Default constructor.
164          */
165         public JoGLTexture() {
166         }
167
168         public final boolean isRowMajorOrder() {
169             return getDataProvider().isRowMajorOrder();
170         }
171
172         /**
173          * Bind the texture in the OpenGl context.
174          * @param drawingTools current drawing tools.
175          * @throws SciRendererException if the texture is invalid.
176          */
177         public synchronized void bind(JoGLDrawingTools drawingTools) throws SciRendererException {
178             if (this.drawingTools == null) {
179                 this.drawingTools = this.drawingTools;
180             }
181
182             GL2 gl = drawingTools.getGl().getGL2();
183             if (isValid()) {
184                 checkData(drawingTools);
185                 if (textures.length == 1) {
186                     gl.glEnable(GL2.GL_TEXTURE_2D);
187                     gl.glEnable(GL2.GL_BLEND);
188                     gl.glBlendFunc(GL2.GL_ONE, GL2.GL_ONE_MINUS_SRC_ALPHA);
189                     gl.glTexEnvi(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, GL2.GL_REPLACE);
190
191                     textures[0].setTexParameteri(gl, GL2.GL_TEXTURE_MAG_FILTER, getAsGLFilter(getMagnificationFilter(), false));
192                     textures[0].setTexParameteri(gl, GL2.GL_TEXTURE_MIN_FILTER, getAsGLFilter(getMinifyingFilter(), false));
193                     if (gl.isNPOTTextureAvailable()) {
194                         textures[0].setTexParameteri(gl, GL2.GL_TEXTURE_WRAP_S, getAsGLWrappingMode(getSWrappingMode()));
195                         textures[0].setTexParameteri(gl, GL2.GL_TEXTURE_WRAP_T, getAsGLWrappingMode(getTWrappingMode()));
196                     } else {
197                         textures[0].setTexParameteri(gl, GL2.GL_TEXTURE_WRAP_S, GL2.GL_CLAMP_TO_EDGE);
198                         textures[0].setTexParameteri(gl, GL2.GL_TEXTURE_WRAP_T, GL2.GL_CLAMP_TO_EDGE);
199                     }
200                     textures[0].bind(gl);
201
202                     /* sfactor and tfactor are useful to have the correct texture coordinates when the texture
203                        was transformed into a power-of-two texture */
204                     Dimension textureSize = getDataProvider().getTextureSize();
205                     sfactor = (double) textureSize.width / (double) textures[0].getWidth();
206                     tfactor = (double) textureSize.height / (double) textures[0].getHeight();
207                 } else {
208                     throw new SciRendererException("Texture is too large");
209                 }
210             } else {
211                 throw new SciRendererException("Texture have no data.");
212             }
213         }
214
215         /**
216          * Check if the texture data are up to date.
217          * @param drawingTools the drawing tools.
218          * @throws SciRendererException if the texture is too big.
219          */
220         private synchronized void checkData(JoGLDrawingTools drawingTools) throws SciRendererException {
221             if (isValid() && !upToDate) {
222                 GL2 gl = drawingTools.getGl().getGL2();
223
224                 Dimension textureSize = getDataProvider().getTextureSize();
225                 int maxSize = drawingTools.getGLCapacity().getMaximumTextureSize();
226                 wCuts = (int) Math.ceil(textureSize.getWidth() / maxSize);
227                 hCuts = (int) Math.ceil(textureSize.getHeight() / maxSize);
228                 ByteBuffer newBuffer = getDataProvider().getData();
229                 TextureDataProvider.ImageType newType = getDataProvider().getImageType();
230
231                 if (newBuffer != null && textureSize.width != 0 && textureSize.height != 0) {
232                     boolean hasChanged = false;
233                     if (newBuffer != buffer || newType != previousType) {
234                         releaseTextures(gl);
235                         if (newBuffer != null) {
236                             textures = new com.jogamp.opengl.util.texture.Texture[wCuts * hCuts];
237                             textureData = new JoGLTextureData[wCuts * hCuts];
238                         }
239                         buffer = newBuffer;
240                         previousType = newType;
241                         hasChanged = true;
242                     }
243
244                     if (newBuffer != null || buffer != null) {
245                         if (wCuts == 1 && hCuts == 1) {
246                             if (hasChanged) {
247                                 if (isRowMajorOrder()) {
248                                     textureData[0] = new JoGLTextureData(gl.getGLProfile(), newType, buffer, textureSize.width, textureSize.height);
249                                 } else {
250                                     textureData[0] = new JoGLTextureData(gl.getGLProfile(), newType, buffer, textureSize.height, textureSize.width);
251                                 }
252                                 try {
253                                     textures[0] = TextureIO.newTexture(textureData[0]);
254                                 } catch (Exception e) {
255                                     System.err.println(e);
256                                 }
257                             } else {
258                                 try {
259                                     textures[0].updateSubImage(gl, textureData[0], 0, 0, 0);
260                                 } catch (Exception e) {
261                                     System.err.println(e);
262                                 }
263                             }
264                         } else {
265                             int k = 0;
266                             for (int i = 0; i < wCuts; i++) {
267                                 for (int j = 0; j < hCuts; j++) {
268                                     if (hasChanged) {
269                                         final int x = i * maxSize;
270                                         final int y = j * maxSize;
271                                         final int width = getSubTextureSize((i == (wCuts - 1)), textureSize.width, maxSize);
272                                         final int height = getSubTextureSize((j == (hCuts - 1)), textureSize.height, maxSize);
273                                         if (isRowMajorOrder()) {
274                                             textureData[k] = new JoGLTextureData(gl.getGLProfile(), newType, buffer, width, height, x, y, textureSize.width, textureSize.height);
275                                         } else {
276                                             textureData[k] = new JoGLTextureData(gl.getGLProfile(), newType, buffer, height, width, y, x, textureSize.height, textureSize.width);
277                                         }
278                                         textures[k] = TextureIO.newTexture(textureData[k]);
279                                     } else {
280                                         textures[k].updateSubImage(gl, textureData[k], 0, 0, 0);
281                                     }
282                                     k++;
283                                 }
284                             }
285                         }
286                     }
287                 }
288                 if (textures != null) {
289                     upToDate = true;
290                 }
291             }
292         }
293
294         private void releaseTextures(GL2 gl) {
295             if (textures != null) {
296                 for (com.jogamp.opengl.util.texture.Texture texture : textures) {
297                     if (texture != null) {
298                         texture.destroy(gl);
299                     }
300                 }
301                 textures = null;
302             }
303
304             if (textureData != null) {
305                 for (JoGLTextureData td : textureData) {
306                     if (td != null) {
307                         td.destroy();
308                     }
309                 }
310                 textureData = null;
311             }
312         }
313
314         public void dispose() {
315             if (drawingTools != null) {
316                 releaseTextures(drawingTools.getGl().getGL2());
317             }
318         }
319
320         public boolean preDraw(JoGLDrawingTools drawingTools) throws SciRendererException {
321             checkData(drawingTools);
322
323             if (textures == null) {
324                 return false;
325             }
326
327             final GL2 gl = drawingTools.getGl().getGL2();
328
329             gl.glMatrixMode(GL2.GL_TEXTURE);
330             gl.glPushMatrix();
331             gl.glLoadIdentity();
332
333             gl.glMatrixMode(GL2.GL_PROJECTION);
334             gl.glPushMatrix();
335             gl.glLoadIdentity();
336
337             gl.glEnable(GL2.GL_TEXTURE_2D);
338             gl.glEnable(GL2.GL_BLEND);
339             gl.glBlendFunc(GL2.GL_ONE, GL2.GL_ONE_MINUS_SRC_ALPHA);
340
341             gl.glEnable(GL2.GL_ALPHA_TEST);
342             gl.glAlphaFunc(GL2.GL_GREATER, 0.0f);
343
344             gl.glPushAttrib(GL2.GL_ALL_ATTRIB_BITS);
345
346             gl.glTexEnvi(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, GL2.GL_REPLACE);
347
348             for (int k = 0; k < wCuts * hCuts; k++) {
349                 textures[k].enable(gl);
350                 textures[k].setTexParameteri(gl, GL2.GL_TEXTURE_MAG_FILTER, getAsGLFilter(getMagnificationFilter(), false));
351                 textures[k].setTexParameteri(gl, GL2.GL_TEXTURE_MIN_FILTER, getAsGLFilter(getMinifyingFilter(), false));
352                 if (gl.isNPOTTextureAvailable()) {
353                     textures[k].setTexParameteri(gl, GL2.GL_TEXTURE_WRAP_S, getAsGLWrappingMode(getSWrappingMode()));
354                     textures[k].setTexParameteri(gl, GL2.GL_TEXTURE_WRAP_T, getAsGLWrappingMode(getTWrappingMode()));
355                 } else {
356                     textures[k].setTexParameteri(gl, GL2.GL_TEXTURE_WRAP_S, GL2.GL_CLAMP_TO_EDGE);
357                     textures[k].setTexParameteri(gl, GL2.GL_TEXTURE_WRAP_T, GL2.GL_CLAMP_TO_EDGE);
358                 }
359             }
360
361             return true;
362         }
363
364         public void draw(JoGLDrawingTools drawingTools, AnchorPosition anchor, Vector3d position, double rotationAngle) throws SciRendererException {
365             TransformationManager transformationManager = drawingTools.getTransformationManager();
366             Transformation canvasProjection = transformationManager.getCanvasProjection();
367             boolean sceneCoordinate = drawingTools.getTransformationManager().isUsingSceneCoordinate();
368             Dimension dimension = drawingTools.getCanvas().getDimension();
369             Vector3d projected;
370             final GL2 gl = drawingTools.getGl().getGL2();
371
372             if (sceneCoordinate) {
373                 projected = canvasProjection.project(position);
374             } else {
375                 projected = position;
376             }
377
378             gl.glMatrixMode(GL2.GL_MODELVIEW);
379             gl.glPushMatrix();
380             gl.glLoadIdentity();
381             gl.glOrtho(0, dimension.width, 0,  dimension.height, 1, -1);
382
383             if (rotationAngle == 0) {
384                 gl.glTranslated(Math.round(projected.getX() + getAnchorDeltaX(anchor)), Math.round(projected.getY() + getAnchorDeltaY(anchor)), projected.getZ());
385             } else {
386                 gl.glTranslated(Math.round(projected.getX()), Math.round(projected.getY()), projected.getZ());
387                 gl.glRotated(rotationAngle, 0, 0, 1);
388                 gl.glTranslated(Math.round(getAnchorDeltaX(anchor)), Math.round(getAnchorDeltaY(anchor)), 0);
389             }
390
391             draw(drawingTools);
392
393             gl.glMatrixMode(GL2.GL_MODELVIEW);
394             gl.glPopMatrix();
395         }
396
397         public void postDraw(JoGLDrawingTools drawingTools) {
398             final GL2 gl = drawingTools.getGl().getGL2();
399
400             for (int k = 0; k < wCuts * hCuts; k++) {
401                 textures[k].disable(gl);
402             }
403
404             gl.glPopAttrib();
405             gl.glDisable(GL2.GL_ALPHA_TEST);
406             gl.glDisable(GL2.GL_TEXTURE_2D);
407             gl.glDisable(GL2.GL_BLEND);
408
409             gl.glMatrixMode(GL2.GL_PROJECTION);
410             gl.glPopMatrix();
411
412             gl.glMatrixMode(GL2.GL_TEXTURE);
413             gl.glPopMatrix();
414         }
415
416         /**
417          * Draw the texture in XY plane.
418          * @param drawingTools the drawing tools.
419          * @throws SciRendererException if the texture is invalid.
420          */
421         public void draw(JoGLDrawingTools drawingTools) throws SciRendererException {
422             final int maxSize = drawingTools.getGLCapacity().getMaximumTextureSize();
423             final Dimension textureSize = getDataProvider().getTextureSize();
424             final GL2 gl = drawingTools.getGl().getGL2();
425
426             if (textureSize != null && textures != null) {
427                 if (wCuts == 1 && hCuts == 1) {
428                     final TextureCoords coords;
429                     if (isRowMajorOrder()) {
430                         coords = textures[0].getSubImageTexCoords(0, 0, textureSize.width, textureSize.height);
431                     } else {
432                         coords = textures[0].getSubImageTexCoords(0, 0, textureSize.height, textureSize.width);
433                     }
434                     textures[0].bind(gl);
435
436                     gl.glBegin(GL2.GL_QUADS);
437                     gl.glTexCoord2f(coords.left(), coords.bottom());
438                     if (isRowMajorOrder()) {
439                         gl.glVertex2f(0, 0);
440                     } else {
441                         gl.glVertex2f(textureSize.width, textureSize.height);
442                     }
443                     gl.glTexCoord2f(coords.right(), coords.bottom());
444                     gl.glVertex2f(textureSize.width, 0);
445                     gl.glTexCoord2f(coords.right(), coords.top());
446                     if (isRowMajorOrder()) {
447                         gl.glVertex2f(textureSize.width, textureSize.height);
448                     } else {
449                         gl.glVertex2f(0, 0);
450                     }
451                     gl.glTexCoord2f(coords.left(), coords.top());
452                     gl.glVertex2f(0, textureSize.height);
453                     gl.glEnd();
454                 } else {
455                     int k = 0;
456                     for (int i = 0; i < wCuts; i++) {
457                         for (int j = 0; j < hCuts; j++) {
458                             final int x = i * maxSize;
459                             final int y = j * maxSize;
460                             final int width = getSubTextureSize((i == (wCuts - 1)), textureSize.width, maxSize);
461                             final int height = getSubTextureSize((j == (hCuts - 1)), textureSize.height, maxSize);
462
463                             // if the texture has been transformed in a power-of-two texture we need to have the correct coords.
464                             final TextureCoords coords;
465                             if (isRowMajorOrder()) {
466                                 coords = textures[k].getSubImageTexCoords(0, 0, width, height);
467                             } else {
468                                 coords = textures[k].getSubImageTexCoords(0, 0, height, width);
469                             }
470                             textures[k].bind(gl);
471
472                             gl.glBegin(GL2.GL_QUADS);
473                             gl.glTexCoord2f(coords.left(), coords.top());
474                             gl.glVertex2f(x, textureSize.height - y);
475                             gl.glTexCoord2f(coords.right(), coords.top());
476                             if (isRowMajorOrder()) {
477                                 gl.glVertex2f(x + width, textureSize.height - y);
478                             } else {
479                                 gl.glVertex2f(x, textureSize.height - y - height);
480                             }
481                             gl.glTexCoord2f(coords.right(), coords.bottom());
482                             gl.glVertex2f(x + width, textureSize.height - y - height);
483                             gl.glTexCoord2f(coords.left(), coords.bottom());
484                             if (isRowMajorOrder()) {
485                                 gl.glVertex2f(x, textureSize.height - y - height);
486                             } else {
487                                 gl.glVertex2f(x + width, textureSize.height - y);
488                             }
489                             gl.glEnd();
490
491                             k++;
492                         }
493                     }
494                 }
495             }
496         }
497
498         @Override
499         public double getSScaleFactor() {
500             return sfactor;
501         }
502
503         @Override
504         public double getTScaleFactor() {
505             return tfactor;
506         }
507
508         /**
509          * Compute the sub texture size.
510          * @param lastPart true if this is the last part.
511          * @param textureSize the global texture size.
512          * @param maxSize the maximum sub-texture size.
513          * @return the sub texture size.
514          */
515         private int getSubTextureSize(boolean lastPart, int textureSize, int maxSize) {
516             if (lastPart) {
517                 int lastSize = textureSize % maxSize;
518                 if (lastSize == 0) {
519                     return maxSize;
520                 } else {
521                     return lastSize;
522                 }
523             } else {
524                 return maxSize;
525             }
526         }
527
528         private int getAsGLWrappingMode(Texture.Wrap wrappingMode) {
529             switch (wrappingMode) {
530                 case CLAMP:
531                     return GL2.GL_CLAMP_TO_EDGE;
532                 case REPEAT:
533                     return GL2.GL_REPEAT;
534                 default:
535                     return GL2.GL_REPEAT;
536             }
537         }
538
539         private int getAsGLFilter(Texture.Filter filter, boolean mipmap) {
540             int returnedValue;
541             if (mipmap) {
542                 switch (filter) {
543                     case LINEAR:
544                         returnedValue = GL2.GL_LINEAR_MIPMAP_LINEAR;
545                         break;
546                     case NEAREST:
547                         returnedValue = GL2.GL_NEAREST_MIPMAP_NEAREST;
548                         break;
549                     default:
550                         returnedValue = GL2.GL_NEAREST;
551                         break;
552                 }
553             } else {
554                 switch (filter) {
555                     case LINEAR:
556                         returnedValue = GL2.GL_LINEAR;
557                         break;
558                     case NEAREST:
559                         returnedValue = GL2.GL_NEAREST;
560                         break;
561                     default:
562                         returnedValue = GL2.GL_NEAREST;
563                         break;
564                 }
565             }
566             return returnedValue;
567         }
568
569         /** Called when gl context is gone. */
570         public void glReload() {
571             buffer = null;
572             textures = null;
573             upToDate = false;
574         }
575
576         /**
577          * Return the deltaX to apply to the sprite in regards to the given anchor.
578          * @param anchor the given anchor.
579          * @return the deltaX to apply to the sprite in regards to the given anchor.
580          */
581         protected double getAnchorDeltaX(AnchorPosition anchor) {
582             int spriteWidth = getDataProvider().getTextureSize().width;
583             switch (anchor) {
584                 case LEFT:
585                 case LOWER_LEFT:
586                 case UPPER_LEFT:
587                     return 0;
588                 case UP:
589                 case CENTER:
590                 case DOWN:
591                     return -spriteWidth / 2f;
592                 case RIGHT:
593                 case LOWER_RIGHT:
594                 case UPPER_RIGHT:
595                     return -spriteWidth;
596                 default:
597                     return 0;
598             }
599         }
600
601         /**
602          * Return the deltaY to apply to the sprite in regards to the given anchor.
603          * @param anchor the given anchor.
604          * @return the deltaY to apply to the sprite in regards to the given anchor.
605          */
606         protected double getAnchorDeltaY(AnchorPosition anchor) {
607             int spriteHeight = getDataProvider().getTextureSize().height;
608             switch (anchor) {
609                 case UPPER_LEFT:
610                 case UP:
611                 case UPPER_RIGHT:
612                     return -spriteHeight;
613                 case LEFT:
614                 case CENTER:
615                 case RIGHT:
616                     return -spriteHeight / 2f;
617                 case LOWER_LEFT:
618                 case DOWN:
619                 case LOWER_RIGHT:
620                     return 0;
621                 default:
622                     return 0;
623             }
624         }
625     }
626
627     private static class JoGLTextureData extends com.jogamp.opengl.util.texture.TextureData {
628
629         private ByteBuffer data;
630         private int shift;
631
632         public JoGLTextureData(GLProfile glp, TextureDataProvider.ImageType type, ByteBuffer data, int width, int height, int x, int y, int totalWidth, int totalHeight) {
633             super(glp);
634             this.data = data;
635             this.mipmap = false;
636             this.width = width;
637             this.height = height;
638             this.mustFlipVertically = true;
639             this.shift = ((x == 0 && y == 0) || data.capacity() == 0) ? 0 : (data.capacity() / (totalWidth * totalHeight) * (x + y * totalWidth));
640             this.rowLength = totalWidth;
641
642             switch (type) {
643                 case RGB:
644                     this.internalFormat = GL2.GL_RGB;
645                     setPixelFormat(GL.GL_RGB);
646                     setPixelType(GL2.GL_UNSIGNED_BYTE);
647                     this.alignment = 1;
648                     break;
649                 case RGB_RGBA:
650                     this.internalFormat = GL2.GL_RGB;
651                     setPixelFormat(GL.GL_RGBA);
652                     setPixelType(GL2.GL_UNSIGNED_INT_8_8_8_8);
653                     this.alignment = 4;
654                     break;
655                 case BGR:
656                     this.internalFormat = GL2GL3.GL_RGB;
657                     setPixelFormat(GL2GL3.GL_BGR);
658                     setPixelType(GL.GL_UNSIGNED_BYTE);
659                     this.alignment = 1;
660                     break;
661                 case GRAY:
662                     this.internalFormat = GL.GL_LUMINANCE;
663                     setPixelFormat(GL.GL_LUMINANCE);
664                     setPixelType(GL.GL_UNSIGNED_BYTE);
665                     this.alignment = 1;
666                     break;
667                 case GRAY_16:
668                     this.internalFormat = GL2.GL_LUMINANCE16;
669                     setPixelFormat(GL2.GL_LUMINANCE);
670                     setPixelType(GL2.GL_UNSIGNED_SHORT);
671                     this.alignment = 2;
672                     break;
673                 case RGBA:
674                     this.internalFormat = GL2.GL_RGBA;
675                     setPixelFormat(GL2.GL_RGBA);
676                     setPixelType(GL2.GL_UNSIGNED_INT_8_8_8_8);
677                     this.alignment = 4;
678                     break;
679                 case RGBA_REV:
680                     this.internalFormat = GL2.GL_RGBA;
681                     setPixelFormat(GL2.GL_RGBA);
682                     setPixelType(GL2.GL_UNSIGNED_INT_8_8_8_8_REV);
683                     this.alignment = 4;
684                     break;
685                 case ABGR:
686                     this.internalFormat = GL2.GL_RGBA;
687                     setPixelFormat(GL2.GL_ABGR_EXT);
688                     setPixelType(GL.GL_UNSIGNED_BYTE);
689                     this.alignment = 1;
690                     break;
691                 case RGB_332:
692                     this.internalFormat = GL2.GL_R3_G3_B2;
693                     setPixelFormat(GL2.GL_RGB);
694                     setPixelType(GL2.GL_UNSIGNED_BYTE_3_3_2);
695                     this.alignment = 1;
696                     break;
697                 case RED:
698                     this.internalFormat = GL2.GL_RED;
699                     setPixelFormat(GL2.GL_RED);
700                     setPixelType(GL2.GL_UNSIGNED_BYTE);
701                     this.alignment = 1;
702                     break;
703                 case GREEN:
704                     this.internalFormat = GL2.GL_RGB8;
705                     setPixelFormat(GL2.GL_GREEN);
706                     setPixelType(GL2.GL_UNSIGNED_BYTE);
707                     this.alignment = 1;
708                     break;
709                 case BLUE:
710                     this.internalFormat = GL2.GL_RGB8;
711                     setPixelFormat(GL2.GL_BLUE);
712                     setPixelType(GL2.GL_UNSIGNED_BYTE);
713                     this.alignment = 1;
714                     break;
715                 case INTENSITY:
716                     this.internalFormat = GL2.GL_INTENSITY;
717                     setPixelFormat(GL2.GL_LUMINANCE);
718                     setPixelType(GL2.GL_UNSIGNED_BYTE);
719                     this.alignment = 1;
720                     break;
721                 case RGBA_4444:
722                     this.internalFormat = GL2.GL_RGBA4;
723                     setPixelFormat(GL2.GL_RGBA);
724                     setPixelType(GL2.GL_UNSIGNED_SHORT_4_4_4_4);
725                     this.alignment = 2;
726                     break;
727                 case RGBA_5551:
728                     this.internalFormat = GL2.GL_RGB5_A1;
729                     setPixelFormat(GL2.GL_RGBA);
730                     setPixelType(GL2.GL_UNSIGNED_SHORT_5_5_5_1);
731                     this.alignment = 2;
732                     break;
733                 case RGB_FLOAT:
734                     this.internalFormat = GL2ES1.GL_RGB16F;
735                     setPixelFormat(GL2.GL_RGB);
736                     setPixelType(GL2.GL_FLOAT);
737                     this.alignment = 4;
738                     break;
739                 case RGBA_FLOAT:
740                     this.internalFormat = GL2.GL_RGBA16F;
741                     setPixelFormat(GL2.GL_RGBA);
742                     setPixelType(GL2.GL_FLOAT);
743                     this.alignment = 4;
744                     break;
745                 case GRAY_FLOAT:
746                     this.internalFormat = GL2.GL_LUMINANCE16F;
747                     setPixelFormat(GL2.GL_LUMINANCE);
748                     setPixelType(GL2.GL_FLOAT);
749                     this.alignment = 4;
750                     break;
751                 case RED_16:
752                     this.internalFormat = GL2.GL_RGB16;
753                     setPixelFormat(GL2.GL_RED);
754                     setPixelType(GL2.GL_UNSIGNED_SHORT);
755                     this.alignment = 2;
756                     break;
757                 case GREEN_16:
758                     this.internalFormat = GL2.GL_RGB16;
759                     setPixelFormat(GL2.GL_GREEN);
760                     setPixelType(GL2.GL_UNSIGNED_SHORT);
761                     this.alignment = 2;
762                     break;
763                 case BLUE_16:
764                     this.internalFormat = GL2.GL_RGB16;
765                     setPixelFormat(GL2.GL_BLUE);
766                     setPixelType(GL2.GL_UNSIGNED_SHORT);
767                     this.alignment = 2;
768                     break;
769                 case RED_FLOAT:
770                     this.internalFormat = GL2ES1.GL_RGB16F;
771                     setPixelFormat(GL2.GL_RED);
772                     setPixelType(GL2.GL_FLOAT);
773                     this.alignment = 4;
774                     break;
775                 case GREEN_FLOAT:
776                     this.internalFormat = GL2ES1.GL_RGB16F;
777                     setPixelFormat(GL2.GL_GREEN);
778                     setPixelType(GL2.GL_FLOAT);
779                     this.alignment = 4;
780                     break;
781                 case BLUE_FLOAT:
782                     this.internalFormat = GL2ES1.GL_RGB16F;
783                     setPixelFormat(GL2.GL_BLUE);
784                     setPixelType(GL2.GL_FLOAT);
785                     this.alignment = 4;
786                     break;
787                 case RGBA_BYTE:
788                     this.internalFormat = GL2.GL_RGBA;
789                     setPixelFormat(GL2.GL_RGBA);
790                     setPixelType(GL2.GL_UNSIGNED_BYTE);
791                     this.alignment = 1;
792                     break;
793             }
794         }
795
796         public JoGLTextureData(GLProfile glp, TextureDataProvider.ImageType type, ByteBuffer data, int width, int height) {
797             this(glp, type, data, width, height, 0, 0, width, height);
798         }
799
800         public ByteBuffer getBuffer() {
801             if (shift == 0) {
802                 return data;
803             } else {
804                 data.position(shift);
805                 ByteBuffer b = data.slice();
806                 data.rewind();
807
808                 return b;
809             }
810         }
811
812         public void setData(ByteBuffer data) {
813             this.data = data;
814         }
815
816         public void destroy() {
817             super.destroy();
818             this.data = null;
819         }
820     }
821 }