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