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