JOGL v2.6.0-rc-20250712
JOGL, High-Performance Graphics Binding for Java™ (public API).
Texture.java
Go to the documentation of this file.
1/**
2 * Copyright (c) 2010-2023 JogAmp Community. All rights reserved.
3 * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * - Redistribution of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * - Redistribution in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * Neither the name of Sun Microsystems, Inc. or the names of
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * This software is provided "AS IS," without a warranty of any kind. ALL
21 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
22 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
23 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
24 * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
25 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
26 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
27 * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
28 * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
29 * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
30 * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
31 * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
32 *
33 * You acknowledge that this software is not designed or intended for use
34 * in the design, construction, operation or maintenance of any nuclear
35 * facility.
36 */
37
38package com.jogamp.opengl.util.texture;
39
40import java.nio.Buffer;
41import java.nio.ByteBuffer;
42import java.nio.FloatBuffer;
43import java.nio.IntBuffer;
44
45import com.jogamp.common.util.Bitfield;
46import com.jogamp.nativewindow.NativeWindowFactory;
47import com.jogamp.opengl.GL;
48import com.jogamp.opengl.GL2;
49import com.jogamp.opengl.GL2ES1;
50import com.jogamp.opengl.GL2ES2;
51import com.jogamp.opengl.GLES2;
52import com.jogamp.opengl.GLException;
53import com.jogamp.opengl.GLExtensions;
54import com.jogamp.opengl.glu.GLU;
55import com.jogamp.opengl.util.texture.spi.DDSImage;
56
57import jogamp.opengl.Debug;
58
59/**
60 * Represents an OpenGL texture object. Contains convenience routines
61 * for enabling/disabling OpenGL texture state, binding this texture,
62 * and computing texture coordinates for both the entire image as well
63 * as a sub-image.
64 *
65 * <a name="textureCallOrder"><h5>Order of Texture Commands</h5></a>
66 * <p>
67 * Due to many confusions w/ texture usage, following list described the order
68 * and semantics of texture unit selection, binding and enabling.
69 * <ul>
70 * <li><i>Optional:</i> Set active textureUnit via <code>gl.glActiveTexture(GL.GL_TEXTURE0 + textureUnit)</code>, <code>0</code> is default.</li>
71 * <li>Bind <code>textureId</code> -> active <code>textureUnit</code>'s <code>textureTarget</code> via <code>gl.glBindTexture(textureTarget, textureId)</code></li>
72 * <li><i>Compatible Context Only:</i> Enable active <code>textureUnit</code>'s <code>textureTarget</code> via <code>glEnable(textureTarget)</code>.
73 * <li><i>Optional:</i> Fiddle with the texture parameters and/or environment settings.</li>
74 * <li>GLSL: Use <code>textureUnit</code> in your shader program, enable shader program.</li>
75 * <li>Issue draw commands</li>
76 * </ul>
77 * </p>
78 *
79 * <p><a name="nonpow2"><b>Non-power-of-two restrictions</b></a>
80 * <br> When creating an OpenGL texture object, the Texture class will
81 * attempt to use <i>non-power-of-two textures</i> (NPOT) if available, see {@link GL#isNPOTTextureAvailable()}.
82 * Further more,
83 * <a href="http://www.opengl.org/registry/specs/ARB/texture_rectangle.txt">GL_ARB_texture_rectangle</a>
84 * (RECT) will be attempted on OSX w/ ATI drivers.
85 * If NPOT is not available or RECT not chosen, the Texture class will simply upload a non-pow2-sized
86 * image into a standard pow2-sized texture (without any special
87 * scaling).
88 * Since the choice of extension (or whether one is used at
89 * all) depends on the user's machine configuration, developers are
90 * recommended to use {@link #getImageTexCoords} and {@link
91 * #getSubImageTexCoords}, as those methods will calculate the
92 * appropriate texture coordinates for the situation.
93 *
94 * <p>One caveat in this approach is that certain texture wrap modes
95 * (e.g. <code>GL_REPEAT</code>) are not legal when the GL_ARB_texture_rectangle
96 * extension is in use. Another issue to be aware of is that in the
97 * default pow2 scenario, if the original image does not have pow2
98 * dimensions, then wrapping may not work as one might expect since
99 * the image does not extend to the edges of the pow2 texture. If
100 * texture wrapping is important, it is recommended to use only
101 * pow2-sized images with the Texture class.
102 *
103 * <p><a name="perftips"><b>Performance Tips</b></a>
104 * <br> For best performance, try to avoid calling {@link #enable} /
105 * {@link #bind} / {@link #disable} any more than necessary. For
106 * example, applications using many Texture objects in the same scene
107 * may want to reduce the number of calls to both {@link #enable} and
108 * {@link #disable}. To do this it is necessary to call {@link
109 * #getTarget} to make sure the OpenGL texture target is the same for
110 * all of the Texture objects in use; non-power-of-two textures using
111 * the GL_ARB_texture_rectangle extension use a different target than
112 * power-of-two textures using the GL_TEXTURE_2D target. Note that
113 * when switching between textures it is necessary to call {@link
114 * #bind}, but when drawing many triangles all using the same texture,
115 * for best performance only one call to {@link #bind} should be made.
116 * User may also utilize multiple texture units,
117 * see <a href="#textureCallOrder"> order of texture commands above</a>.
118 *
119 * <p><a name="premult"><b>Alpha premultiplication and blending</b></a>
120 * <p>
121 * <i>Disclaimer: Consider performing alpha premultiplication in shader code, if really desired! Otherwise use RGBA.</i><br/>
122 * </p>
123 * <p>
124 * The Texture class does not convert RGBA image data into
125 * premultiplied data when storing it into an OpenGL texture.
126 * </p>
127 * <p>
128 * The mathematically correct way to perform blending in OpenGL
129 * with the SrcOver "source over destination" mode, or any other
130 * Porter-Duff rule, is to use <i>premultiplied color components</i>,
131 * which means the R/G/ B color components must have been multiplied by
132 * the alpha value. If using <i>premultiplied color components</i>
133 * it is important to use the correct blending function; for
134 * example, the SrcOver rule is expressed as:
135<pre>
136 gl.glBlendFunc(GL.GL_ONE, GL.GL_ONE_MINUS_SRC_ALPHA);
137</pre>
138 * Also, when using a texture function like <code>GL_MODULATE</code> where
139 * the current color plays a role, it is important to remember to make
140 * sure that the color is specified in a premultiplied form, for
141 * example:
142<pre>
143 float a = ...;
144 float r = r * a;
145 float g = g * a;
146 float b = b * a;
147 gl.glColor4f(r, g, b, a);
148</pre>
149 *
150 * For reference, here is a list of the Porter-Duff compositing rules
151 * and the associated OpenGL blend functions (source and destination
152 * factors) to use in the face of premultiplied alpha:
153 *
154<CENTER>
155<TABLE WIDTH="75%">
156<TR> <TD> Rule <TD> Source <TD> Dest
157<TR> <TD> Clear <TD> GL_ZERO <TD> GL_ZERO
158<TR> <TD> Src <TD> GL_ONE <TD> GL_ZERO
159<TR> <TD> SrcOver <TD> GL_ONE <TD> GL_ONE_MINUS_SRC_ALPHA
160<TR> <TD> DstOver <TD> GL_ONE_MINUS_DST_ALPHA <TD> GL_ONE
161<TR> <TD> SrcIn <TD> GL_DST_ALPHA <TD> GL_ZERO
162<TR> <TD> DstIn <TD> GL_ZERO <TD> GL_SRC_ALPHA
163<TR> <TD> SrcOut <TD> GL_ONE_MINUS_DST_ALPHA <TD> GL_ZERO
164<TR> <TD> DstOut <TD> GL_ZERO <TD> GL_ONE_MINUS_SRC_ALPHA
165<TR> <TD> Dst <TD> GL_ZERO <TD> GL_ONE
166<TR> <TD> SrcAtop <TD> GL_DST_ALPHA <TD> GL_ONE_MINUS_SRC_ALPHA
167<TR> <TD> DstAtop <TD> GL_ONE_MINUS_DST_ALPHA <TD> GL_SRC_ALPHA
168<TR> <TD> AlphaXor <TD> GL_ONE_MINUS_DST_ALPHA <TD> GL_ONE_MINUS_SRC_ALPHA
169</TABLE>
170</CENTER>
171 * @author Chris Campbell, Kenneth Russell, et.al.
172 */
173public class Texture {
174 /** The GL target type for this texture. */
175 private int target;
176 /** The image GL target type for this texture, or its sub-components if cubemap. */
177 private int imageTarget;
178 /** The GL texture ID. */
179 private int texID;
180 /** Owning texture texID */
181 private final boolean ownsTextureID;
182 /** The width of the texture. */
183 private int texWidth;
184 /** The height of the texture. */
185 private int texHeight;
186 /** The width of the image. */
187 private int imgWidth;
188 /** The height of the image. */
189 private int imgHeight;
190 /** The original aspect ratio of the image, before any rescaling
191 that might have occurred due to using the GLU mipmap routines. */
192 private float aspectRatio;
193 /** Indicates whether the TextureData requires a vertical flip of
194 the texture coords. */
195 private boolean mustFlipVertically;
196 /** Indicates whether we're using automatic mipmap generation
197 support (GL_GENERATE_MIPMAP). */
198 private boolean usingAutoMipmapGeneration;
199
200 /** The texture coordinates corresponding to the entire image. */
201 private TextureCoords coords;
202
203 @Override
204 public String toString() {
205 final String targetS = target == imageTarget ? Integer.toHexString(target) : Integer.toHexString(target) + " - image "+Integer.toHexString(imageTarget);
206 return "Texture[target "+targetS+", name "+texID+", "+
207 imgWidth+"/"+texWidth+" x "+imgHeight+"/"+texHeight+", y-flip "+mustFlipVertically+
208 ", "+estimatedMemorySize+" bytes]";
209 }
210
211 /** An estimate of the amount of texture memory this texture consumes. */
212 private int estimatedMemorySize;
213
214 private static final boolean DEBUG = Debug.debug("Texture");
215 private static final boolean VERBOSE = Debug.verbose();
216
217 // For testing alternate code paths on more capable hardware
218 private static final boolean disableNPOT = Debug.isPropertyDefined("jogl.texture.nonpot", true);
219 private static final boolean disableTexRect = Debug.isPropertyDefined("jogl.texture.notexrect", true);
220
221 public Texture(final GL gl, final TextureData data) throws GLException {
222 this.texID = 0;
223 this.ownsTextureID = true;
224 this.target = 0;
225 this.imageTarget = 0;
226 updateImage(gl, data);
227 }
228
229 /**
230 * Constructor for use when creating e.g. cube maps, where there is
231 * no initial texture data
232 * @param target the OpenGL texture target, eg GL.GL_TEXTURE_2D,
233 * GL2.GL_TEXTURE_RECTANGLE
234 */
235 public Texture(final int target) {
236 this.texID = 0;
237 this.ownsTextureID = true;
238 this.target = target;
239 this.imageTarget = target;
240 }
241
242 /**
243 * Constructor to wrap an OpenGL texture ID from an external library and allows
244 * some of the base methods from the Texture class, such as
245 * binding and querying of texture coordinates, to be used with
246 * it. Attempts to update such textures' contents will yield
247 * undefined results.
248 *
249 * @param textureID the valid OpenGL texture object to wrap
250 * @param ownsTextureID pass {@code true} if this {@link Texture} instance takes ownership of {@code textureID} texture
251 * and {@link GL#glDeleteTextures(int, int[], int) deletes the texture} at {@link #destroy(GL)}.
252 * Otherwise, if {@code false}, {@code textureID} texture will not be {@link GL#glDeleteTextures(int, int[], int) deleted} at {@link #destroy(GL)}.
253 * @param target the OpenGL texture target, eg GL.GL_TEXTURE_2D,
254 * GL2.GL_TEXTURE_RECTANGLE
255 * @param texWidth the width of the texture in pixels
256 * @param texHeight the height of the texture in pixels
257 * @param imgWidth the width of the image within the texture in
258 * pixels (if the content is a sub-rectangle in the upper
259 * left corner); otherwise, pass in texWidth
260 * @param imgHeight the height of the image within the texture in
261 * pixels (if the content is a sub-rectangle in the upper
262 * left corner); otherwise, pass in texHeight
263 * @param mustFlipVertically indicates whether the texture
264 * coordinates must be flipped vertically
265 * in order to properly display the
266 * texture
267 */
268 public Texture(final int textureID, final boolean ownsTextureID,
269 final int target,
270 final int texWidth, final int texHeight,
271 final int imgWidth, final int imgHeight,
272 final boolean mustFlipVertically) {
273 this.texID = textureID;
274 this.ownsTextureID = ownsTextureID;
275 this.target = target;
276 this.imageTarget = target;
277 this.mustFlipVertically = mustFlipVertically;
278 this.texWidth = texWidth;
279 this.texHeight = texHeight;
280 this.aspectRatio = (float) imgWidth / (float) imgHeight;
281 this.imgWidth = imgWidth;
282 this.imgHeight = imgHeight;
283 this.updateTexCoords();
284 if ( 0 == texID ) {
285 throw new GLException("External texture ID invalid: texID "+textureID);
286 }
287 }
288 /**
289 * Pending setup or update of texture and image dimensions
290 * @param texWidth the width of the texture in pixels
291 * @param texHeight the height of the texture in pixels
292 * @param imgWidth the width of the image within the texture in
293 * pixels (if the content is a sub-rectangle in the upper
294 * left corner); otherwise, pass in texWidth
295 * @param imgHeight the height of the image within the texture in
296 * pixels (if the content is a sub-rectangle in the upper
297 * left corner); otherwise, pass in texHeight
298 */
299 public void set(final int texWidth, final int texHeight,
300 final int imgWidth, final int imgHeight) {
301 this.texWidth = texWidth;
302 this.texHeight = texHeight;
303 this.aspectRatio = (float) imgWidth / (float) imgHeight;
304 this.imgWidth = imgWidth;
305 this.imgHeight = imgHeight;
306 this.updateTexCoords();
307 }
308
309 /**
310 * Enables this texture's target (e.g., GL_TEXTURE_2D) in the
311 * given GL context's state. This method is a shorthand equivalent
312 * of the following OpenGL code:
313 * <pre>
314 * gl.glEnable(texture.getTarget());
315 * </pre>
316 * <p>
317 * Call is ignored if the {@link GL} object's context
318 * is using a core profile, see {@link GL#isGLcore()},
319 * or if {@link #getTarget()} is {@link GLES2#GL_TEXTURE_EXTERNAL_OES}.
320 * </p>
321 * <p>
322 * See the <a href="#perftips">performance tips</a> above for hints
323 * on how to maximize performance when using many Texture objects.
324 * </p>
325 * @param gl the current GL object
326 *
327 * @throws GLException if no OpenGL context was current or if any
328 * OpenGL-related errors occurred
329 */
330 public void enable(final GL gl) throws GLException {
331 if( !gl.isGLcore() && GLES2.GL_TEXTURE_EXTERNAL_OES != target) {
332 gl.glEnable(target);
333 }
334 }
335
336 /**
337 * Disables this texture's target (e.g., GL_TEXTURE_2D) in the
338 * given GL state. This method is a shorthand equivalent
339 * of the following OpenGL code:
340 * <pre>
341 * gl.glDisable(texture.getTarget());
342 * </pre>
343 * <p>
344 * Call is ignored if the {@link GL} object's context
345 * is using a core profile, see {@link GL#isGLcore()},
346 * or if {@link #getTarget()} is {@link GLES2#GL_TEXTURE_EXTERNAL_OES}.
347 * </p>
348 * <p>
349 * See the <a href="#perftips">performance tips</a> above for hints
350 * on how to maximize performance when using many Texture objects.
351 * </p>
352 * @param gl the current GL object
353 *
354 * @throws GLException if no OpenGL context was current or if any
355 * OpenGL-related errors occurred
356 */
357 public void disable(final GL gl) throws GLException {
358 if( !gl.isGLcore() && GLES2.GL_TEXTURE_EXTERNAL_OES != target ) {
359 gl.glDisable(target);
360 }
361 }
362
363 /**
364 * Binds this texture to the given GL context. This method is a
365 * shorthand equivalent of the following OpenGL code:
366 <pre>
367 gl.glBindTexture(texture.getTarget(), texture.getTextureObject());
368 </pre>
369 *
370 * See the <a href="#perftips">performance tips</a> above for hints
371 * on how to maximize performance when using many Texture objects.
372 *
373 * @param gl the current GL context
374 * @throws GLException if no OpenGL context was current or if any
375 * OpenGL-related errors occurred
376 */
377 public void bind(final GL gl) throws GLException {
378 validateTexID(gl, true);
379 gl.glBindTexture(target, texID);
380 }
381
382 /**
383 * Destroys and {@code null}s the {@link #getTextureObject() underlying native texture} used by this {@link Texture} instance
384 * if {@link #ownsTexture() owned}, otherwise just {@code null}s the {@link #getTextureObject() underlying native texture}.
385 *
386 * @throws GLException if any OpenGL-related errors occurred
387 */
388 public void destroy(final GL gl) throws GLException {
389 if( 0 != texID && ownsTextureID ) {
390 gl.glDeleteTextures(1, new int[] {texID}, 0);
391 }
392 texID = 0;
393 }
394
395 /**
396 * Returns the OpenGL "target" of this texture.
397 * @see com.jogamp.opengl.GL#GL_TEXTURE_2D
398 * @see com.jogamp.opengl.GL2#GL_TEXTURE_RECTANGLE_ARB
399 */
400 public int getTarget() {
401 return target;
402 }
403
404 /**
405 * Returns the image OpenGL "target" of this texture, or its sub-components if cubemap.
406 * @see com.jogamp.opengl.GL#GL_TEXTURE_2D
407 * @see com.jogamp.opengl.GL2#GL_TEXTURE_RECTANGLE_ARB
408 */
409 public int getImageTarget() {
410 return imageTarget;
411 }
412
413 /**
414 * Returns the width of the allocated OpenGL texture in pixels.
415 * Note that the texture width will be greater than or equal to the
416 * width of the image contained within.
417 *
418 * @return the width of the texture
419 */
420 public int getWidth() {
421 return texWidth;
422 }
423
424 /**
425 * Returns the height of the allocated OpenGL texture in pixels.
426 * Note that the texture height will be greater than or equal to the
427 * height of the image contained within.
428 *
429 * @return the height of the texture
430 */
431 public int getHeight() {
432 return texHeight;
433 }
434
435 /**
436 * Returns the width of the image contained within this texture.
437 * Note that for non-power-of-two textures in particular this may
438 * not be equal to the result of {@link #getWidth}. It is
439 * recommended that applications call {@link #getImageTexCoords} and
440 * {@link #getSubImageTexCoords} rather than using this API
441 * directly.
442 *
443 * @return the width of the image
444 */
445 public int getImageWidth() {
446 return imgWidth;
447 }
448
449 /**
450 * Returns the height of the image contained within this texture.
451 * Note that for non-power-of-two textures in particular this may
452 * not be equal to the result of {@link #getHeight}. It is
453 * recommended that applications call {@link #getImageTexCoords} and
454 * {@link #getSubImageTexCoords} rather than using this API
455 * directly.
456 *
457 * @return the height of the image
458 */
459 public int getImageHeight() {
460 return imgHeight;
461 }
462
463 /**
464 * Returns the original aspect ratio of the image, defined as (image
465 * width) / (image height), before any scaling that might have
466 * occurred as a result of using the GLU mipmap routines.
467 */
468 public float getAspectRatio() {
469 return aspectRatio;
470 }
471
472 /**
473 * Returns the set of texture coordinates corresponding to the
474 * entire image. If the TextureData indicated that the texture
475 * coordinates must be flipped vertically, the returned
476 * TextureCoords will take that into account.
477 *
478 * @return the texture coordinates corresponding to the entire image
479 */
481 return coords;
482 }
483
484 /**
485 * Returns the set of texture coordinates corresponding to the
486 * specified sub-image. The (x1, y1) and (x2, y2) points are
487 * specified in terms of pixels starting from the lower-left of the
488 * image. (x1, y1) should specify the lower-left corner of the
489 * sub-image and (x2, y2) the upper-right corner of the sub-image.
490 * If the TextureData indicated that the texture coordinates must be
491 * flipped vertically, the returned TextureCoords will take that
492 * into account; this should not be handled by the end user in the
493 * specification of the y1 and y2 coordinates.
494 *
495 * @return the texture coordinates corresponding to the specified sub-image
496 */
497 public TextureCoords getSubImageTexCoords(final int x1, final int y1, final int x2, final int y2) {
498 if (GL2.GL_TEXTURE_RECTANGLE_ARB == imageTarget) {
499 if (mustFlipVertically) {
500 return new TextureCoords(x1, texHeight - y1, x2, texHeight - y2);
501 } else {
502 return new TextureCoords(x1, y1, x2, y2);
503 }
504 } else {
505 final float tx1 = (float)x1 / (float)texWidth;
506 final float ty1 = (float)y1 / (float)texHeight;
507 final float tx2 = (float)x2 / (float)texWidth;
508 final float ty2 = (float)y2 / (float)texHeight;
509 if (mustFlipVertically) {
510 final float yMax = (float) imgHeight / (float) texHeight;
511 return new TextureCoords(tx1, yMax - ty1, tx2, yMax - ty2);
512 } else {
513 return new TextureCoords(tx1, ty1, tx2, ty2);
514 }
515 }
516 }
517
518 /**
519 * Updates the entire content area incl. {@link TextureCoords}
520 * of this texture using the data in the given image.
521 *
522 * @throws GLException if any OpenGL-related errors occurred
523 */
524 public void updateImage(final GL gl, final TextureData data) throws GLException {
525 updateImage(gl, data, 0);
526 }
527
528 /**
529 * Indicates whether this texture's texture coordinates must be
530 * flipped vertically in order to properly display the texture. This
531 * is handled automatically by {@link #getImageTexCoords
532 * getImageTexCoords} and {@link #getSubImageTexCoords
533 * getSubImageTexCoords}, but applications may generate or otherwise
534 * produce texture coordinates which must be corrected.
535 */
536 public boolean getMustFlipVertically() {
537 return mustFlipVertically;
538 }
539
540 /**
541 * Change whether the TextureData requires a vertical flip of
542 * the texture coords.
543 * <p>
544 * No-op if no change, otherwise generates new {@link TextureCoords}.
545 * </p>
546 */
547 public void setMustFlipVertically(final boolean v) {
548 if( v != mustFlipVertically ) {
549 mustFlipVertically = v;
550 updateTexCoords();
551 }
552 }
553
554 /**
555 * Updates the content area incl. {@link TextureCoords} of the specified target of this texture
556 * using the data in the given image. In general this is intended
557 * for construction of cube maps.
558 *
559 * @throws GLException if any OpenGL-related errors occurred
560 */
561 public void updateImage(final GL gl, final TextureData data, final int targetOverride) throws GLException {
562 validateTexID(gl, true);
563
564 imgWidth = data.getWidth();
565 imgHeight = data.getHeight();
566 aspectRatio = (float) imgWidth / (float) imgHeight;
567 mustFlipVertically = data.getMustFlipVertically();
568
569 int texTarget = 0;
570 int texParamTarget = this.target;
571
572 // See whether we have automatic mipmap generation support
573 boolean haveAutoMipmapGeneration =
574 (gl.isExtensionAvailable(GLExtensions.VERSION_1_4) ||
575 gl.isExtensionAvailable(GLExtensions.SGIS_generate_mipmap));
576
577 // Indicate to the TextureData what functionality is available
578 data.setHaveEXTABGR(gl.isExtensionAvailable(GLExtensions.EXT_abgr));
579 data.setHaveGL12(gl.isExtensionAvailable(GLExtensions.VERSION_1_2));
580
581 // Indicates whether both width and height are power of two
582 final boolean isPOT = Bitfield.Util.isPowerOf2(imgWidth) && Bitfield.Util.isPowerOf2(imgHeight);
583
584 // Note that automatic mipmap generation doesn't work for
585 // GL_ARB_texture_rectangle
586 if (!isPOT && !haveNPOT(gl)) {
587 haveAutoMipmapGeneration = false;
588 }
589
590 boolean expandingCompressedTexture = false;
591 boolean done = false;
592 if (data.getMipmap() && !haveAutoMipmapGeneration) {
593 // GLU always scales the texture's dimensions to be powers of
594 // two. It also doesn't really matter exactly what the texture
595 // width and height are because the texture coords are always
596 // between 0.0 and 1.0.
597 imgWidth = Bitfield.Util.roundToPowerOf2(imgWidth);
598 imgHeight = Bitfield.Util.roundToPowerOf2(imgHeight);
599 texWidth = imgWidth;
600 texHeight = imgHeight;
601 texTarget = GL.GL_TEXTURE_2D;
602 done = true;
603 }
604
605 if (!done && preferTexRect(gl) && !isPOT &&
606 haveTexRect(gl) && !data.isDataCompressed() && !gl.isGL3() && !gl.isGLES()) {
607 // GL_ARB_texture_rectangle does not work for compressed textures
608 if (DEBUG) {
609 System.err.println("Using GL_ARB_texture_rectangle preferentially on this hardware");
610 }
611
612 texWidth = imgWidth;
613 texHeight = imgHeight;
614 texTarget = GL2.GL_TEXTURE_RECTANGLE_ARB;
615 done = true;
616 }
617
618 if (!done && (isPOT || haveNPOT(gl))) {
619 if (DEBUG) {
620 if (isPOT) {
621 System.err.println("Power-of-two texture");
622 } else {
623 System.err.println("Using GL_ARB_texture_non_power_of_two");
624 }
625 }
626
627 texWidth = imgWidth;
628 texHeight = imgHeight;
629 texTarget = GL.GL_TEXTURE_2D;
630 done = true;
631 }
632
633 if (!done && haveTexRect(gl) && !data.isDataCompressed() && !gl.isGL3() && !gl.isGLES()) {
634 // GL_ARB_texture_rectangle does not work for compressed textures
635 if (DEBUG) {
636 System.err.println("Using GL_ARB_texture_rectangle");
637 }
638
639 texWidth = imgWidth;
640 texHeight = imgHeight;
641 texTarget = GL2.GL_TEXTURE_RECTANGLE_ARB;
642 done = true;
643 }
644
645 if (!done) {
646 // If we receive non-power-of-two compressed texture data and
647 // don't have true hardware support for compressed textures, we
648 // can fake this support by producing an empty "compressed"
649 // texture image, using glCompressedTexImage2D with that to
650 // allocate the texture, and glCompressedTexSubImage2D with the
651 // incoming data.
652 if (data.isDataCompressed()) {
653 if (data.getMipmapData() != null) {
654
655 // We don't currently support expanding of compressed,
656 // mipmapped non-power-of-two textures to the nearest power
657 // of two; the obvious port of the non-mipmapped code didn't
658 // work
659 throw new GLException("Mipmapped non-power-of-two compressed textures only supported on OpenGL 2.0 hardware (GL_ARB_texture_non_power_of_two)");
660 }
661
662 expandingCompressedTexture = true;
663 }
664
665 if (DEBUG) {
666 System.err.println("Expanding texture to power-of-two dimensions");
667 }
668
669 if (data.getBorder() != 0) {
670 throw new RuntimeException("Scaling up a non-power-of-two texture which has a border won't work");
671 }
672 texWidth = Bitfield.Util.roundToPowerOf2(imgWidth);
673 texHeight = Bitfield.Util.roundToPowerOf2(imgHeight);
674 texTarget = GL.GL_TEXTURE_2D;
675 }
676 texParamTarget = texTarget;
677 imageTarget = texTarget;
678 updateTexCoords();
679
680 if (targetOverride != 0) {
681 // Allow user to override auto detection and skip bind step (for
682 // cubemap construction)
683 if (this.target == 0) {
684 throw new GLException("Override of target failed; no target specified yet");
685 }
686 texTarget = targetOverride;
687 texParamTarget = this.target;
688 gl.glBindTexture(texParamTarget, texID);
689 } else {
690 gl.glBindTexture(texTarget, texID);
691 }
692
693 if (data.getMipmap() && !haveAutoMipmapGeneration) {
694 final int[] align = new int[1];
695 gl.glGetIntegerv(GL.GL_UNPACK_ALIGNMENT, align, 0); // save alignment
696 gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, data.getAlignment());
697
698 if (data.isDataCompressed()) {
699 throw new GLException("May not request mipmap generation for compressed textures");
700 }
701
702 try {
703 // FIXME: may need check for GLUnsupportedException
704 final GLU glu = GLU.createGLU(gl);
705 glu.gluBuild2DMipmaps(texTarget, data.getInternalFormat(),
706 data.getWidth(), data.getHeight(),
707 data.getPixelFormat(), data.getPixelType(), data.getBuffer());
708 } finally {
709 gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, align[0]); // restore alignment
710 }
711 } else {
712 checkCompressedTextureExtensions(gl, data);
713 final Buffer[] mipmapData = data.getMipmapData();
714 if (mipmapData != null) {
715 int width = texWidth;
716 int height = texHeight;
717 for (int i = 0; i < mipmapData.length; i++) {
718 if (data.isDataCompressed()) {
719 // Need to use glCompressedTexImage2D directly to allocate and fill this image
720 // Avoid spurious memory allocation when possible
721 gl.glCompressedTexImage2D(texTarget, i, data.getInternalFormat(),
722 width, height, data.getBorder(),
723 mipmapData[i].remaining(), mipmapData[i]);
724 } else {
725 // Allocate texture image at this level
726 gl.glTexImage2D(texTarget, i, data.getInternalFormat(),
727 width, height, data.getBorder(),
728 data.getPixelFormat(), data.getPixelType(), null);
729 updateSubImageImpl(gl, data, texTarget, i, 0, 0, 0, 0, data.getWidth(), data.getHeight());
730 }
731
732 width = Math.max(width / 2, 1);
733 height = Math.max(height / 2, 1);
734 }
735 } else {
736 if (data.isDataCompressed()) {
737 if (!expandingCompressedTexture) {
738 // Need to use glCompressedTexImage2D directly to allocate and fill this image
739 // Avoid spurious memory allocation when possible
740 gl.glCompressedTexImage2D(texTarget, 0, data.getInternalFormat(),
741 texWidth, texHeight, data.getBorder(),
742 data.getBuffer().capacity(), data.getBuffer());
743 } else {
744 final ByteBuffer buf = DDSImage.allocateBlankBuffer(texWidth,
745 texHeight,
746 data.getInternalFormat());
747 gl.glCompressedTexImage2D(texTarget, 0, data.getInternalFormat(),
748 texWidth, texHeight, data.getBorder(),
749 buf.capacity(), buf);
750 updateSubImageImpl(gl, data, texTarget, 0, 0, 0, 0, 0, data.getWidth(), data.getHeight());
751 }
752 } else {
753 if (data.getMipmap() && haveAutoMipmapGeneration && gl.isGL2ES1()) {
754 // For now, only use hardware mipmapping for uncompressed 2D
755 // textures where the user hasn't explicitly specified
756 // mipmap data; don't know about interactions between
757 // GL_GENERATE_MIPMAP and glCompressedTexImage2D
758 gl.glTexParameteri(texParamTarget, GL2ES1.GL_GENERATE_MIPMAP, GL.GL_TRUE);
759 usingAutoMipmapGeneration = true;
760 }
761
762 gl.glTexImage2D(texTarget, 0, data.getInternalFormat(),
763 texWidth, texHeight, data.getBorder(),
764 data.getPixelFormat(), data.getPixelType(), null);
765 updateSubImageImpl(gl, data, texTarget, 0, 0, 0, 0, 0, data.getWidth(), data.getHeight());
766 }
767 }
768 }
769
770 final int minFilter = (data.getMipmap() ? GL.GL_LINEAR_MIPMAP_LINEAR : GL.GL_LINEAR);
771 final int magFilter = GL.GL_LINEAR;
772 final int wrapMode = (gl.isExtensionAvailable(GLExtensions.VERSION_1_2) || !gl.isGL2()) ? GL.GL_CLAMP_TO_EDGE : GL2.GL_CLAMP;
773
774 // REMIND: figure out what to do for GL_TEXTURE_RECTANGLE_ARB
775 if (texTarget != GL2.GL_TEXTURE_RECTANGLE_ARB) {
776 gl.glTexParameteri(texParamTarget, GL.GL_TEXTURE_MIN_FILTER, minFilter);
777 gl.glTexParameteri(texParamTarget, GL.GL_TEXTURE_MAG_FILTER, magFilter);
778 gl.glTexParameteri(texParamTarget, GL.GL_TEXTURE_WRAP_S, wrapMode);
779 gl.glTexParameteri(texParamTarget, GL.GL_TEXTURE_WRAP_T, wrapMode);
780 if (this.target == GL.GL_TEXTURE_CUBE_MAP) {
781 gl.glTexParameteri(texParamTarget, GL2ES2.GL_TEXTURE_WRAP_R, wrapMode);
782 }
783 }
784
785 // Don't overwrite target if we're loading e.g. faces of a cube
786 // map
787 if ((this.target == 0) ||
788 (this.target == GL.GL_TEXTURE_2D) ||
789 (this.target == GL2.GL_TEXTURE_RECTANGLE_ARB)) {
790 this.target = texTarget;
791 }
792
793 // This estimate will be wrong for cube maps
794 estimatedMemorySize = data.getEstimatedMemorySize();
795 }
796
797 /**
798 * Updates a subregion of the content area of this texture using the
799 * given data. If automatic mipmap generation is in use (see {@link
800 * #isUsingAutoMipmapGeneration isUsingAutoMipmapGeneration}),
801 * updates to the base (level 0) mipmap will cause the lower-level
802 * mipmaps to be regenerated, and updates to other mipmap levels
803 * will be ignored. Otherwise, if automatic mipmap generation is not
804 * in use, only updates the specified mipmap level and does not
805 * re-generate mipmaps if they were originally produced or loaded.
806 *
807 * @param data the image data to be uploaded to this texture
808 * @param mipmapLevel the mipmap level of the texture to set. If
809 * this is non-zero and the TextureData contains mipmap data, the
810 * appropriate mipmap level will be selected.
811 * @param x the x offset (in pixels) relative to the lower-left corner
812 * of this texture
813 * @param y the y offset (in pixels) relative to the lower-left corner
814 * of this texture
815 *
816 * @throws GLException if any OpenGL-related errors occurred
817 */
818 public void updateSubImage(final GL gl, final TextureData data, final int mipmapLevel, final int x, final int y) throws GLException {
819 if (usingAutoMipmapGeneration && mipmapLevel != 0) {
820 // When we're using mipmap generation via GL_GENERATE_MIPMAP, we
821 // don't need to update other mipmap levels
822 return;
823 }
824 bind(gl);
825 updateSubImageImpl(gl, data, target, mipmapLevel, x, y, 0, 0, data.getWidth(), data.getHeight());
826 }
827
828 /**
829 * Updates a subregion of the content area of this texture using the
830 * specified sub-region of the given data. If automatic mipmap
831 * generation is in use (see {@link #isUsingAutoMipmapGeneration
832 * isUsingAutoMipmapGeneration}), updates to the base (level 0)
833 * mipmap will cause the lower-level mipmaps to be regenerated, and
834 * updates to other mipmap levels will be ignored. Otherwise, if
835 * automatic mipmap generation is not in use, only updates the
836 * specified mipmap level and does not re-generate mipmaps if they
837 * were originally produced or loaded. This method is only supported
838 * for uncompressed TextureData sources.
839 *
840 * @param data the image data to be uploaded to this texture
841 * @param mipmapLevel the mipmap level of the texture to set. If
842 * this is non-zero and the TextureData contains mipmap data, the
843 * appropriate mipmap level will be selected.
844 * @param dstx the x offset (in pixels) relative to the lower-left corner
845 * of this texture where the update will be applied
846 * @param dsty the y offset (in pixels) relative to the lower-left corner
847 * of this texture where the update will be applied
848 * @param srcx the x offset (in pixels) relative to the lower-left corner
849 * of the supplied TextureData from which to fetch the update rectangle
850 * @param srcy the y offset (in pixels) relative to the lower-left corner
851 * of the supplied TextureData from which to fetch the update rectangle
852 * @param width the width (in pixels) of the rectangle to be updated
853 * @param height the height (in pixels) of the rectangle to be updated
854 *
855 * @throws GLException if no OpenGL context was current or if any
856 * OpenGL-related errors occurred
857 */
858 public void updateSubImage(final GL gl, final TextureData data, final int mipmapLevel,
859 final int dstx, final int dsty,
860 final int srcx, final int srcy,
861 final int width, final int height) throws GLException {
862 if (data.isDataCompressed()) {
863 throw new GLException("updateSubImage specifying a sub-rectangle is not supported for compressed TextureData");
864 }
865 if (usingAutoMipmapGeneration && mipmapLevel != 0) {
866 // When we're using mipmap generation via GL_GENERATE_MIPMAP, we
867 // don't need to update other mipmap levels
868 return;
869 }
870 bind(gl);
871 updateSubImageImpl(gl, data, target, mipmapLevel, dstx, dsty, srcx, srcy, width, height);
872 }
873
874 /**
875 * Sets the OpenGL floating-point texture parameter for the
876 * texture's target. This gives control over parameters such as
877 * GL_TEXTURE_MAX_ANISOTROPY_EXT. Causes this texture to be bound to
878 * the current texture state.
879 *
880 * @throws GLException if no OpenGL context was current or if any
881 * OpenGL-related errors occurred
882 */
883 public void setTexParameterf(final GL gl, final int parameterName,
884 final float value) {
885 bind(gl);
886 gl.glTexParameterf(target, parameterName, value);
887 }
888
889 /**
890 * Sets the OpenGL multi-floating-point texture parameter for the
891 * texture's target. Causes this texture to be bound to the current
892 * texture state.
893 *
894 * @throws GLException if any OpenGL-related errors occurred
895 */
896 public void setTexParameterfv(final GL gl, final int parameterName,
897 final FloatBuffer params) {
898 bind(gl);
899 gl.glTexParameterfv(target, parameterName, params);
900 }
901
902 /**
903 * Sets the OpenGL multi-floating-point texture parameter for the
904 * texture's target. Causes this texture to be bound to the current
905 * texture state.
906 *
907 * @throws GLException if any OpenGL-related errors occurred
908 */
909 public void setTexParameterfv(final GL gl, final int parameterName,
910 final float[] params, final int params_offset) {
911 bind(gl);
912 gl.glTexParameterfv(target, parameterName, params, params_offset);
913 }
914
915 /**
916 * Sets the OpenGL integer texture parameter for the texture's
917 * target. This gives control over parameters such as
918 * GL_TEXTURE_WRAP_S and GL_TEXTURE_WRAP_T, which by default are set
919 * to GL_CLAMP_TO_EDGE if OpenGL 1.2 is supported on the current
920 * platform and GL_CLAMP if not. Causes this texture to be bound to
921 * the current texture state.
922 *
923 * @throws GLException if any OpenGL-related errors occurred
924 */
925 public void setTexParameteri(final GL gl, final int parameterName,
926 final int value) {
927 bind(gl);
928 gl.glTexParameteri(target, parameterName, value);
929 }
930
931 /**
932 * Sets the OpenGL multi-integer texture parameter for the texture's
933 * target. Causes this texture to be bound to the current texture
934 * state.
935 *
936 * @throws GLException if any OpenGL-related errors occurred
937 */
938 public void setTexParameteriv(final GL gl, final int parameterName,
939 final IntBuffer params) {
940 bind(gl);
941 gl.glTexParameteriv(target, parameterName, params);
942 }
943
944 /**
945 * Sets the OpenGL multi-integer texture parameter for the texture's
946 * target. Causes this texture to be bound to the current texture
947 * state.
948 *
949 * @throws GLException if any OpenGL-related errors occurred
950 */
951 public void setTexParameteriv(final GL gl, final int parameterName,
952 final int[] params, final int params_offset) {
953 bind(gl);
954 gl.glTexParameteriv(target, parameterName, params, params_offset);
955 }
956
957 /**
958 * Returns the underlying OpenGL texture object for this texture
959 * and generates it if not done yet.
960 * <p>
961 * Most applications will not need to access this, since it is
962 * handled automatically by the bind(GL) and destroy(GL) APIs.
963 * </p>
964 * @param gl required to be valid and current in case the texture object has not been generated yet,
965 * otherwise it may be <code>null</code>.
966 * @see #getTextureObject()
967 */
968 public int getTextureObject(final GL gl) {
969 validateTexID(gl, false);
970 return texID;
971 }
972
973 /**
974 * Returns the underlying OpenGL texture object for this texture,
975 * maybe <code>0</code> if not yet generated.
976 * <p>
977 * Most applications will not need to access this, since it is
978 * handled automatically by the bind(GL) and destroy(GL) APIs.
979 * </p>
980 * @see #getTextureObject(GL)
981 */
982 public int getTextureObject() { return texID; }
983
984 /** Returns whether {@link #getTextureObject()} is owned by this {@link Texture} instance. */
985 public final boolean ownsTexture() { return ownsTextureID; }
986
987 /** Returns an estimate of the amount of texture memory in bytes
988 this Texture consumes. It should only be treated as an estimate;
989 most applications should not need to query this but instead let
990 the OpenGL implementation page textures in and out as
991 necessary. */
993 return estimatedMemorySize;
994 }
995
996 /** Indicates whether this Texture is using automatic mipmap
997 generation (via the OpenGL texture parameter
998 GL_GENERATE_MIPMAP). This will automatically be used when
999 mipmapping is requested via the TextureData and either OpenGL
1000 1.4 or the GL_SGIS_generate_mipmap extension is available. If
1001 so, updates to the base image (mipmap level 0) will
1002 automatically propagate down to the lower mipmap levels. Manual
1003 updates of the mipmap data at these lower levels will be
1004 ignored. */
1006 return usingAutoMipmapGeneration;
1007 }
1008
1009 //----------------------------------------------------------------------
1010 // Internals only below this point
1011 //
1012
1013 private void updateTexCoords() {
1014 if ( GL2.GL_TEXTURE_RECTANGLE_ARB == imageTarget ) {
1015 if (mustFlipVertically) {
1016 coords = new TextureCoords(0, imgHeight, imgWidth, 0);
1017 } else {
1018 coords = new TextureCoords(0, 0, imgWidth, imgHeight);
1019 }
1020 } else {
1021 if (mustFlipVertically) {
1022 coords = new TextureCoords(0, // l
1023 (float) imgHeight / (float) texHeight, // b
1024 (float) imgWidth / (float) texWidth, // r
1025 0 // t
1026 );
1027 } else {
1028 coords = new TextureCoords(0, // l
1029 0, // b
1030 (float) imgWidth / (float) texWidth, // r
1031 (float) imgHeight / (float) texHeight // t
1032 );
1033 }
1034 }
1035 }
1036
1037 private void updateSubImageImpl(final GL gl, final TextureData data, final int newTarget, final int mipmapLevel,
1038 int dstx, int dsty,
1039 int srcx, int srcy, int width, int height) throws GLException {
1040 data.setHaveEXTABGR(gl.isExtensionAvailable(GLExtensions.EXT_abgr));
1041 data.setHaveGL12(gl.isExtensionAvailable(GLExtensions.VERSION_1_2));
1042
1043 Buffer buffer = data.getBuffer();
1044 if (buffer == null && data.getMipmapData() == null) {
1045 // Assume user just wanted to get the Texture object allocated
1046 return;
1047 }
1048
1049 int rowlen = data.getRowLength();
1050 int dataWidth = data.getWidth();
1051 int dataHeight = data.getHeight();
1052 if (data.getMipmapData() != null) {
1053 // Compute the width, height and row length at the specified mipmap level
1054 // Note we do not support specification of the row length for
1055 // mipmapped textures at this point
1056 for (int i = 0; i < mipmapLevel; i++) {
1057 width = Math.max(width / 2, 1);
1058 height = Math.max(height / 2, 1);
1059
1060 dataWidth = Math.max(dataWidth / 2, 1);
1061 dataHeight = Math.max(dataHeight / 2, 1);
1062 }
1063 rowlen = 0;
1064 buffer = data.getMipmapData()[mipmapLevel];
1065 }
1066
1067 // Clip incoming rectangles to what is available both on this
1068 // texture and in the incoming TextureData
1069 if (srcx < 0) {
1070 width += srcx;
1071 srcx = 0;
1072 }
1073 if (srcy < 0) {
1074 height += srcy;
1075 srcy = 0;
1076 }
1077 // NOTE: not sure whether the following two are the correct thing to do
1078 if (dstx < 0) {
1079 width += dstx;
1080 dstx = 0;
1081 }
1082 if (dsty < 0) {
1083 height += dsty;
1084 dsty = 0;
1085 }
1086
1087 if (srcx + width > dataWidth) {
1088 width = dataWidth - srcx;
1089 }
1090 if (srcy + height > dataHeight) {
1091 height = dataHeight - srcy;
1092 }
1093 if (dstx + width > texWidth) {
1094 width = texWidth - dstx;
1095 }
1096 if (dsty + height > texHeight) {
1097 height = texHeight - dsty;
1098 }
1099
1100 checkCompressedTextureExtensions(gl, data);
1101
1102 if (data.isDataCompressed()) {
1103 gl.glCompressedTexSubImage2D(newTarget, mipmapLevel,
1104 dstx, dsty, width, height,
1105 data.getInternalFormat(),
1106 buffer.remaining(), buffer);
1107 } else {
1108 final int[] align = { 0 };
1109 final int[] rowLength = { 0 };
1110 final int[] skipRows = { 0 };
1111 final int[] skipPixels = { 0 };
1112 gl.glGetIntegerv(GL.GL_UNPACK_ALIGNMENT, align, 0); // save alignment
1113 if(gl.isGL2GL3()) {
1114 gl.glGetIntegerv(GL2ES2.GL_UNPACK_ROW_LENGTH, rowLength, 0); // save row length
1115 gl.glGetIntegerv(GL2ES2.GL_UNPACK_SKIP_ROWS, skipRows, 0); // save skipped rows
1116 gl.glGetIntegerv(GL2ES2.GL_UNPACK_SKIP_PIXELS, skipPixels, 0); // save skipped pixels
1117 }
1118 gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, data.getAlignment());
1119 if (DEBUG && VERBOSE) {
1120 System.out.println("Row length = " + rowlen);
1121 System.out.println("skip pixels = " + srcx);
1122 System.out.println("skip rows = " + srcy);
1123 System.out.println("dstx = " + dstx);
1124 System.out.println("dsty = " + dsty);
1125 System.out.println("width = " + width);
1126 System.out.println("height = " + height);
1127 }
1128 if(gl.isGL2GL3()) {
1129 gl.glPixelStorei(GL2ES2.GL_UNPACK_ROW_LENGTH, rowlen);
1130 gl.glPixelStorei(GL2ES2.GL_UNPACK_SKIP_ROWS, srcy);
1131 gl.glPixelStorei(GL2ES2.GL_UNPACK_SKIP_PIXELS, srcx);
1132 } else {
1133 if ( rowlen!=0 && rowlen!=width &&
1134 srcy!=0 && srcx!=0 ) {
1135 throw new GLException("rowlen and/or x/y offset only available for GL2");
1136 }
1137 }
1138
1139 gl.glTexSubImage2D(newTarget, mipmapLevel,
1140 dstx, dsty, width, height,
1141 data.getPixelFormat(), data.getPixelType(),
1142 buffer);
1143 gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, align[0]); // restore alignment
1144 if(gl.isGL2GL3()) {
1145 gl.glPixelStorei(GL2ES2.GL_UNPACK_ROW_LENGTH, rowLength[0]); // restore row length
1146 gl.glPixelStorei(GL2ES2.GL_UNPACK_SKIP_ROWS, skipRows[0]); // restore skipped rows
1147 gl.glPixelStorei(GL2ES2.GL_UNPACK_SKIP_PIXELS, skipPixels[0]); // restore skipped pixels
1148 }
1149 }
1150 }
1151
1152 private void checkCompressedTextureExtensions(final GL gl, final TextureData data) {
1153 if (data.isDataCompressed()) {
1154 switch (data.getInternalFormat()) {
1155 case GL.GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1156 case GL.GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
1157 case GL.GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
1158 case GL.GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
1159 if (!gl.isExtensionAvailable(GLExtensions.EXT_texture_compression_s3tc) &&
1160 !gl.isExtensionAvailable(GLExtensions.NV_texture_compression_vtc)) {
1161 throw new GLException("DXTn compressed textures not supported by this graphics card");
1162 }
1163 break;
1164 default:
1165 // FI1027GXME: should test availability of more texture
1166 // compression extensions here
1167 break;
1168 }
1169 }
1170 }
1171
1172 private boolean validateTexID(final GL gl, final boolean throwException) {
1173 if( 0 == texID ) {
1174 if( null != gl && ownsTextureID ) {
1175 final int[] tmp = new int[1];
1176 gl.glGenTextures(1, tmp, 0);
1177 texID = tmp[0];
1178 if ( 0 == texID && throwException ) {
1179 throw new GLException("Create texture ID invalid: texID "+texID+", glerr 0x"+Integer.toHexString(gl.glGetError()));
1180 }
1181 } else if ( throwException ) {
1182 if( !ownsTextureID ) {
1183 throw new GLException("Invalid external texture ID");
1184 } else {
1185 throw new GLException("No GL context given, can't create texture ID");
1186 }
1187 }
1188 }
1189 return 0 != texID;
1190 }
1191
1192 // Helper routines for disabling certain codepaths
1193 private static boolean haveNPOT(final GL gl) {
1194 return !disableNPOT && gl.isNPOTTextureAvailable();
1195 }
1196
1197 private static boolean haveTexRect(final GL gl) {
1198 return (!disableTexRect &&
1199 TextureIO.isTexRectEnabled() &&
1200 gl.isExtensionAvailable(GLExtensions.ARB_texture_rectangle));
1201 }
1202
1203 private static boolean preferTexRect(final GL gl) {
1204 // Prefer GL_ARB_texture_rectangle on ATI hardware on Mac OS X
1205 // due to software fallbacks
1206
1207 if (NativeWindowFactory.TYPE_MACOSX == NativeWindowFactory.getNativeWindowType(false)) {
1208 final String vendor = gl.glGetString(GL.GL_VENDOR);
1209 if (vendor != null && vendor.startsWith("ATI")) {
1210 return true;
1211 }
1212 }
1213
1214 return false;
1215 }
1216}
A generic exception for OpenGL errors used throughout the binding as a substitute for RuntimeExceptio...
Class holding OpenGL extension strings, commonly used by JOGL's implementation.
static final String VERSION_1_4
static final String SGIS_generate_mipmap
static final String VERSION_1_2
static final String EXT_abgr
Provides access to the OpenGL Utility Library (GLU).
Definition: GLU.java:43
int gluBuild2DMipmaps(int target, int internalFormat, int width, int height, int format, int type, java.nio.Buffer data)
Optional, throws GLException if not available in profile.
Definition: GLU.java:1525
static final GLU createGLU()
Instantiates a GLU implementation object in respect to the given GL profile of this thread current GL...
Definition: GLU.java:147
Specifies texture coordinates for a rectangular area of a texture.
Represents the data for an OpenGL texture.
Represents an OpenGL texture object.
Definition: Texture.java:173
int getImageHeight()
Returns the height of the image contained within this texture.
Definition: Texture.java:459
TextureCoords getImageTexCoords()
Returns the set of texture coordinates corresponding to the entire image.
Definition: Texture.java:480
void setTexParameteri(final GL gl, final int parameterName, final int value)
Sets the OpenGL integer texture parameter for the texture's target.
Definition: Texture.java:925
void setTexParameteriv(final GL gl, final int parameterName, final IntBuffer params)
Sets the OpenGL multi-integer texture parameter for the texture's target.
Definition: Texture.java:938
void setTexParameterfv(final GL gl, final int parameterName, final FloatBuffer params)
Sets the OpenGL multi-floating-point texture parameter for the texture's target.
Definition: Texture.java:896
Texture(final GL gl, final TextureData data)
Definition: Texture.java:221
void bind(final GL gl)
Binds this texture to the given GL context.
Definition: Texture.java:377
int getHeight()
Returns the height of the allocated OpenGL texture in pixels.
Definition: Texture.java:431
int getTarget()
Returns the OpenGL "target" of this texture.
Definition: Texture.java:400
final boolean ownsTexture()
Returns whether getTextureObject() is owned by this Texture instance.
Definition: Texture.java:985
void setTexParameterf(final GL gl, final int parameterName, final float value)
Sets the OpenGL floating-point texture parameter for the texture's target.
Definition: Texture.java:883
boolean getMustFlipVertically()
Indicates whether this texture's texture coordinates must be flipped vertically in order to properly ...
Definition: Texture.java:536
void disable(final GL gl)
Disables this texture's target (e.g., GL_TEXTURE_2D) in the given GL state.
Definition: Texture.java:357
void updateImage(final GL gl, final TextureData data)
Updates the entire content area incl.
Definition: Texture.java:524
int getTextureObject()
Returns the underlying OpenGL texture object for this texture, maybe 0 if not yet generated.
Definition: Texture.java:982
void updateSubImage(final GL gl, final TextureData data, final int mipmapLevel, final int dstx, final int dsty, final int srcx, final int srcy, final int width, final int height)
Updates a subregion of the content area of this texture using the specified sub-region of the given d...
Definition: Texture.java:858
float getAspectRatio()
Returns the original aspect ratio of the image, defined as (image width) / (image height),...
Definition: Texture.java:468
void updateImage(final GL gl, final TextureData data, final int targetOverride)
Updates the content area incl.
Definition: Texture.java:561
int getWidth()
Returns the width of the allocated OpenGL texture in pixels.
Definition: Texture.java:420
void setMustFlipVertically(final boolean v)
Change whether the TextureData requires a vertical flip of the texture coords.
Definition: Texture.java:547
int getImageTarget()
Returns the image OpenGL "target" of this texture, or its sub-components if cubemap.
Definition: Texture.java:409
void setTexParameterfv(final GL gl, final int parameterName, final float[] params, final int params_offset)
Sets the OpenGL multi-floating-point texture parameter for the texture's target.
Definition: Texture.java:909
int getEstimatedMemorySize()
Returns an estimate of the amount of texture memory in bytes this Texture consumes.
Definition: Texture.java:992
void setTexParameteriv(final GL gl, final int parameterName, final int[] params, final int params_offset)
Sets the OpenGL multi-integer texture parameter for the texture's target.
Definition: Texture.java:951
int getTextureObject(final GL gl)
Returns the underlying OpenGL texture object for this texture and generates it if not done yet.
Definition: Texture.java:968
void enable(final GL gl)
Enables this texture's target (e.g., GL_TEXTURE_2D) in the given GL context's state.
Definition: Texture.java:330
int getImageWidth()
Returns the width of the image contained within this texture.
Definition: Texture.java:445
TextureCoords getSubImageTexCoords(final int x1, final int y1, final int x2, final int y2)
Returns the set of texture coordinates corresponding to the specified sub-image.
Definition: Texture.java:497
Texture(final int textureID, final boolean ownsTextureID, final int target, final int texWidth, final int texHeight, final int imgWidth, final int imgHeight, final boolean mustFlipVertically)
Constructor to wrap an OpenGL texture ID from an external library and allows some of the base methods...
Definition: Texture.java:268
boolean isUsingAutoMipmapGeneration()
Indicates whether this Texture is using automatic mipmap generation (via the OpenGL texture parameter...
Definition: Texture.java:1005
Texture(final int target)
Constructor for use when creating e.g.
Definition: Texture.java:235
void destroy(final GL gl)
Destroys and nulls the underlying native texture used by this Texture instance if owned,...
Definition: Texture.java:388
void updateSubImage(final GL gl, final TextureData data, final int mipmapLevel, final int x, final int y)
Updates a subregion of the content area of this texture using the given data.
Definition: Texture.java:818
A reader and writer for DirectDraw Surface (.dds) files, which are used to describe textures.
Definition: DDSImage.java:63
static ByteBuffer allocateBlankBuffer(final int width, final int height, final int openGLInternalFormat)
Allocates a temporary, empty ByteBuffer suitable for use in a call to glCompressedTexImage2D.
Definition: DDSImage.java:464
static final int GL_GENERATE_MIPMAP
GL_VERSION_1_4, GL_VERSION_ES_1_0, GL_SGIS_generate_mipmap Alias for: GL_GENERATE_MIPMAP_SGIS Define...
Definition: GL2ES1.java:274
static final int GL_TEXTURE_WRAP_R
GL_ES_VERSION_3_0, GL_VERSION_1_2, GL_EXT_texture3D, GL_OES_texture_3D Alias for: GL_TEXTURE_WRAP_R_E...
Definition: GL2ES2.java:480
static final int GL_TEXTURE_RECTANGLE_ARB
GL_ARB_texture_rectangle Define "GL_TEXTURE_RECTANGLE_ARB" with expression '0x84F5',...
Definition: GL2.java:934
static final int GL_CLAMP
GL_VERSION_1_0 Define "GL_CLAMP" with expression '0x2900', CType: int
Definition: GL2.java:2004
static final int GL_TEXTURE_EXTERNAL_OES
GL_OES_EGL_image_external Define "GL_TEXTURE_EXTERNAL_OES" with expression '0x8D65',...
Definition: GLES2.java:57
static final int GL_TEXTURE_MAG_FILTER
GL_ES_VERSION_2_0, GL_VERSION_1_1, GL_VERSION_1_0, GL_VERSION_ES_1_0 Define "GL_TEXTURE_MAG_FILTER" w...
Definition: GL.java:197
static final int GL_UNPACK_ALIGNMENT
GL_ES_VERSION_2_0, GL_VERSION_1_1, GL_VERSION_1_0, GL_VERSION_ES_1_0 Define "GL_UNPACK_ALIGNMENT" wit...
Definition: GL.java:746
static final int GL_TEXTURE_2D
GL_ES_VERSION_2_0, GL_VERSION_1_1, GL_VERSION_1_0, GL_VERSION_ES_1_0 Define "GL_TEXTURE_2D" with expr...
Definition: GL.java:491
static final int GL_TEXTURE_WRAP_S
GL_ES_VERSION_2_0, GL_VERSION_1_1, GL_VERSION_1_0, GL_VERSION_ES_1_0 Define "GL_TEXTURE_WRAP_S" with ...
Definition: GL.java:485
static final int GL_LINEAR
GL_ES_VERSION_2_0, GL_VERSION_1_1, GL_VERSION_1_0, GL_VERSION_ES_1_0 Define "GL_LINEAR" with expressi...
Definition: GL.java:323
void glTexParameteriv(int target, int pname, IntBuffer params)
Entry point to C language function: void {@native glTexParameteriv}(GLenum target,...
static final int GL_TEXTURE_MIN_FILTER
GL_ES_VERSION_2_0, GL_VERSION_1_1, GL_VERSION_1_0, GL_VERSION_ES_1_0 Define "GL_TEXTURE_MIN_FILTER" w...
Definition: GL.java:372
void glTexParameterfv(int target, int pname, FloatBuffer params)
Entry point to C language function: void {@native glTexParameterfv}(GLenum target,...
static final int GL_TEXTURE_WRAP_T
GL_ES_VERSION_2_0, GL_VERSION_1_1, GL_VERSION_1_0, GL_VERSION_ES_1_0 Define "GL_TEXTURE_WRAP_T" with ...
Definition: GL.java:489
void glTexParameteri(int target, int pname, int param)
Entry point to C language function: void {@native glTexParameteri}(GLenum target,...
static final int GL_TRUE
GL_ES_VERSION_2_0, GL_VERSION_1_1, GL_VERSION_1_0, GL_VERSION_ES_1_0 Define "GL_TRUE" with expression...
Definition: GL.java:308
void glTexParameterf(int target, int pname, float param)
Entry point to C language function: void {@native glTexParameterf}(GLenum target,...
static final int GL_CLAMP_TO_EDGE
GL_ES_VERSION_2_0, GL_VERSION_1_2, GL_VERSION_ES_1_0, GL_SGIS_texture_edge_clamp Alias for: GL_CLAMP_...
Definition: GL.java:775
static final int GL_TEXTURE_CUBE_MAP
GL_ES_VERSION_2_0, GL_VERSION_1_3, GL_OES_texture_cube_map, GL_ARB_texture_cube_map,...
Definition: GL.java:207