aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2008-06-21 03:04:14 +0000
committerSven Gothel <[email protected]>2008-06-21 03:04:14 +0000
commit26b7878c3b47f76e55195a8682fd7dce04d83ea8 (patch)
tree9db98703be0d205320f18e357f8ad1c814dccaf2 /src
parent32f216838432d0a67ce78061aa8a09261e3c3716 (diff)
2nd big refactoring.
Goals are orthogonal components for: - OS Windowing system - NEWT, X11, Windows, MacOsX - GL Windowing GLUE - EGL, GLX, WGL, CGL - GL profiles - core and util packages - generate all Java components from any platform All above goals are achieved. TODO: - Native compilation fix and test - Check/Fix Win32, MacOSX and the mobile devices - .. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/branches/JOGL_2_SANDBOX@1670 232f8b59-042b-4e1e-8c03-345bb8c30851
Diffstat (limited to 'src')
-rw-r--r--src/classes/com/sun/opengl/impl/glue/Glue.java114
-rwxr-xr-xsrc/classes/com/sun/opengl/impl/nurbs/CurveEvaluator.java86
-rwxr-xr-xsrc/classes/com/sun/opengl/impl/nurbs/SurfaceEvaluator.java111
-rwxr-xr-xsrc/classes/com/sun/opengl/util/texture/awt/AWTTextureData.java764
-rwxr-xr-xsrc/classes/com/sun/opengl/util/texture/awt/AWTTextureReader.java968
-rwxr-xr-xsrc/classes/com/sun/opengl/util/texture/awt/AWTTextureWriter.java500
-rw-r--r--src/classes/javax/media/opengl/GLContext.java6
-rw-r--r--src/classes/javax/media/opengl/GLDrawable.java15
-rw-r--r--src/classes/javax/media/opengl/GLDrawableFactory.java126
-rw-r--r--src/classes/javax/media/opengl/NativeWindow.java27
-rw-r--r--src/classes/javax/media/opengl/NativeWindowFactory.java9
-rwxr-xr-xsrc/classes/javax/media/opengl/Threading.java2
-rw-r--r--src/classes/javax/media/opengl/awt/GLCanvas.java36
-rw-r--r--src/classes/javax/media/opengl/awt/GLJPanel.java1270
-rwxr-xr-xsrc/classes/javax/media/opengl/glu/GLUquadric.java26
-rwxr-xr-xsrc/native/jogl/WindowsWindow.c58
-rwxr-xr-xsrc/native/jogl/X11Window.c163
17 files changed, 2788 insertions, 1493 deletions
diff --git a/src/classes/com/sun/opengl/impl/glue/Glue.java b/src/classes/com/sun/opengl/impl/glue/Glue.java
deleted file mode 100644
index 863c9417c..000000000
--- a/src/classes/com/sun/opengl/impl/glue/Glue.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * License Applicability. Except to the extent portions of this file are
- * made subject to an alternative license as permitted in the SGI Free
- * Software License B, Version 1.1 (the "License"), the contents of this
- * file are subject only to the provisions of the License. You may not use
- * this file except in compliance with the License. You may obtain a copy
- * of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
- * Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
- *
- * http://oss.sgi.com/projects/FreeB
- *
- * Note that, as provided in the License, the Software is distributed on an
- * "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
- * DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
- * CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
- * PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
- *
- * NOTE: The Original Code (as defined below) has been licensed to Sun
- * Microsystems, Inc. ("Sun") under the SGI Free Software License B
- * (Version 1.1), shown above ("SGI License"). Pursuant to Section
- * 3.2(3) of the SGI License, Sun is distributing the Covered Code to
- * you under an alternative license ("Alternative License"). This
- * Alternative License includes all of the provisions of the SGI License
- * except that Section 2.2 and 11 are omitted. Any differences between
- * the Alternative License and the SGI License are offered solely by Sun
- * and not by SGI.
- *
- * Original Code. The Original Code is: OpenGL Sample Implementation,
- * Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
- * Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
- * Copyright in any portions created by third parties is as indicated
- * elsewhere herein. All Rights Reserved.
- *
- * Additional Notice Provisions: The application programming interfaces
- * established by SGI in conjunction with the Original Code are The
- * OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
- * April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
- * 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
- * Window System(R) (Version 1.3), released October 19, 1998. This software
- * was created using the OpenGL(R) version 1.2.1 Sample Implementation
- * published by SGI, but has not been independently verified as being
- * compliant with the OpenGL(R) version 1.2.1 Specification.
- */
-
-package com.sun.opengl.impl.glue;
-
-/**
- *
- * @author Administrator
- */
-public class Glue {
- private static String[] __gluNurbsErrors = {
- " ",
- "spline order un-supported",
- "too few knots",
- "valid knot range is empty",
- "decreasing knot sequence knot",
- "knot multiplicity greater than order of spline",
- "gluEndCurve() must follow gluBeginCurve()",
- "gluBeginCurve() must precede gluEndCurve()",
- "missing or extra geometric data",
- "can't draw piecewise linear trimming curves",
- "missing or extra domain data",
- "missing or extra domain data",
- "gluEndTrim() must precede gluEndSurface()",
- "gluBeginSurface() must precede gluEndSurface()",
- "curve of improper type passed as trim curve",
- "gluBeginSurface() must precede gluBeginTrim()",
- "gluEndTrim() must follow gluBeginTrim()",
- "gluBeginTrim() must follow gluEndTrim()",
- "invalid or missing trim curve",
- "gluBeginTrim() must precede gluPwlCurve()",
- "piecewise linear trimming curve referenced twice",
- "piecewise linear trimming curve and nurbs curve mixed",
- "improper usage of trim data type",
- "nurbs curve referenced twice",
- "nurbs curve and piecewise linear trimming curve mixed",
- "nurbs surface referenced twice",
- "invalid property",
- "gluEndSurface() must follow gluBeginSurface()",
- "intersecting or misoriented trim curve",
- "intersecting trim curves",
- "UNUSED",
- "inconnected trim curves",
- "unknown knot error",
- "negative vertex count encountered",
- "negative byte-stride encountered",
- "unknown type descriptor",
- "null control point reference",
- "duplicate point on piecewise linear trimming curve"
- } ;
-
- /** Creates a new instance of Glue */
- public Glue() {
- }
-
- public static String __gluNURBSErrorString( int errno ) {
- return( __gluNurbsErrors[ errno ] );
- }
-
- private static String[] __gluTessErrors = {
- " ",
- "gluTessBeginPolygon() must precede a gluTessEndPolygon",
- "gluTessBeginContour() must precede a gluTessEndContour()",
- "gluTessEndPolygon() must follow a gluTessBeginPolygon()",
- "gluTessEndContour() must follow a gluTessBeginContour()",
- "a coordinate is too large",
- "need combine callback"
- };
-
- public static String __gluTessErrorString( int errno ) {
- return( __gluTessErrors[ errno ] );
- }
-}
diff --git a/src/classes/com/sun/opengl/impl/nurbs/CurveEvaluator.java b/src/classes/com/sun/opengl/impl/nurbs/CurveEvaluator.java
new file mode 100755
index 000000000..a6393ddf4
--- /dev/null
+++ b/src/classes/com/sun/opengl/impl/nurbs/CurveEvaluator.java
@@ -0,0 +1,86 @@
+package com.sun.opengl.impl.glu.nurbs;
+
+/*
+ ** License Applicability. Except to the extent portions of this file are
+ ** made subject to an alternative license as permitted in the SGI Free
+ ** Software License B, Version 1.1 (the "License"), the contents of this
+ ** file are subject only to the provisions of the License. You may not use
+ ** this file except in compliance with the License. You may obtain a copy
+ ** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+ ** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+ **
+ ** http://oss.sgi.com/projects/FreeB
+ **
+ ** Note that, as provided in the License, the Software is distributed on an
+ ** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+ ** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+ ** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+ ** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+ **
+ ** Original Code. The Original Code is: OpenGL Sample Implementation,
+ ** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+ ** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+ ** Copyright in any portions created by third parties is as indicated
+ ** elsewhere herein. All Rights Reserved.
+ **
+ ** Additional Notice Provisions: The application programming interfaces
+ ** established by SGI in conjunction with the Original Code are The
+ ** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+ ** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+ ** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+ ** Window System(R) (Version 1.3), released October 19, 1998. This software
+ ** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+ ** published by SGI, but has not been independently verified as being
+ ** compliant with the OpenGL(R) version 1.2.1 Specification.
+ */
+
+/**
+ * Class rendering curves with OpenGL
+ * @author Tomáš Hráský
+ *
+ */
+public interface CurveEvaluator {
+ /**
+ * Pushes eval bit
+ */
+ public void bgnmap1f();
+
+ /**
+ * Pops all OpenGL attributes
+ */
+ public void endmap1f() ;
+
+ /**
+ * Initializes opengl evaluator
+ * @param type curve type
+ * @param ulo lowest u
+ * @param uhi highest u
+ * @param stride control point coords
+ * @param order curve order
+ * @param ps control points
+ */
+ public void map1f(int type, float ulo, float uhi, int stride, int order,
+ CArrayOfFloats ps) ;
+
+ /**
+ * Calls opengl enable
+ * @param type what to enable
+ */
+ public void enable(int type) ;
+
+ /**
+ * Calls glMapGrid1f
+ * @param nu steps
+ * @param u1 low u
+ * @param u2 high u
+ */
+ public void mapgrid1f(int nu, float u1, float u2) ;
+
+ /**
+ * Evaluates a curve using glEvalMesh1f
+ * @param style Backend.N_MESHFILL/N_MESHLINE/N_MESHPOINT
+ * @param from lowest param
+ * @param to highest param
+ */
+ public void mapmesh1f(int style, int from, int to) ;
+}
diff --git a/src/classes/com/sun/opengl/impl/nurbs/SurfaceEvaluator.java b/src/classes/com/sun/opengl/impl/nurbs/SurfaceEvaluator.java
new file mode 100755
index 000000000..feb3bc9a7
--- /dev/null
+++ b/src/classes/com/sun/opengl/impl/nurbs/SurfaceEvaluator.java
@@ -0,0 +1,111 @@
+package com.sun.opengl.impl.glu.nurbs;
+
+/*
+ ** License Applicability. Except to the extent portions of this file are
+ ** made subject to an alternative license as permitted in the SGI Free
+ ** Software License B, Version 1.1 (the "License"), the contents of this
+ ** file are subject only to the provisions of the License. You may not use
+ ** this file except in compliance with the License. You may obtain a copy
+ ** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+ ** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+ **
+ ** http://oss.sgi.com/projects/FreeB
+ **
+ ** Note that, as provided in the License, the Software is distributed on an
+ ** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+ ** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+ ** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+ ** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+ **
+ ** Original Code. The Original Code is: OpenGL Sample Implementation,
+ ** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+ ** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+ ** Copyright in any portions created by third parties is as indicated
+ ** elsewhere herein. All Rights Reserved.
+ **
+ ** Additional Notice Provisions: The application programming interfaces
+ ** established by SGI in conjunction with the Original Code are The
+ ** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+ ** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+ ** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+ ** Window System(R) (Version 1.3), released October 19, 1998. This software
+ ** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+ ** published by SGI, but has not been independently verified as being
+ ** compliant with the OpenGL(R) version 1.2.1 Specification.
+ */
+
+/**
+ * Class rendering surfaces with OpenGL
+ * @author Tomas Hrasky
+ *
+ */
+public interface SurfaceEvaluator {
+
+ /**
+ * Pushes eval bit
+ */
+ public void bgnmap2f() ;
+
+ /**
+ * Sets glPolygonMode
+ * @param style polygon mode (N_MESHFILL/N_MESHLINE/N_MESHPOINT)
+ */
+ public void polymode(int style) ;
+
+ /**
+ * Pops all attributes
+ */
+ public void endmap2f() ;
+
+ /**
+ * Empty method
+ * @param ulo
+ * @param uhi
+ * @param vlo
+ * @param vhi
+ */
+ public void domain2f(float ulo, float uhi, float vlo, float vhi) ;
+
+ /**
+ * Defines 2D mesh
+ * @param nu number of steps in u direction
+ * @param u0 lowest u
+ * @param u1 highest u
+ * @param nv number of steps in v direction
+ * @param v0 lowest v
+ * @param v1 highest v
+ */
+ public void mapgrid2f(int nu, float u0, float u1, int nv, float v0, float v1) ;
+
+ /**
+ * Evaluates surface
+ * @param style surface style
+ * @param umin minimum U
+ * @param umax maximum U
+ * @param vmin minimum V
+ * @param vmax maximum V
+ */
+ public void mapmesh2f(int style, int umin, int umax, int vmin, int vmax) ;
+
+ /**
+ * Initializes evaluator
+ * @param type surface type
+ * @param ulo lowest u
+ * @param uhi highest u
+ * @param ustride number of objects between control points in u direction
+ * @param uorder surface order in u direction
+ * @param vlo lowest v
+ * @param vhi highest v
+ * @param vstride number of control points' coords
+ * @param vorder surface order in v direction
+ * @param pts control points
+ */
+ public void map2f(int type, float ulo, float uhi, int ustride, int uorder,
+ float vlo, float vhi, int vstride, int vorder, CArrayOfFloats pts) ;
+
+ /**
+ * Calls opengl enable
+ * @param type what to enable
+ */
+ public void enable(int type) ;
+}
diff --git a/src/classes/com/sun/opengl/util/texture/awt/AWTTextureData.java b/src/classes/com/sun/opengl/util/texture/awt/AWTTextureData.java
new file mode 100755
index 000000000..41895cf1a
--- /dev/null
+++ b/src/classes/com/sun/opengl/util/texture/awt/AWTTextureData.java
@@ -0,0 +1,764 @@
+/*
+ * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ */
+
+package com.sun.opengl.util.texture.awt;
+
+import java.awt.AlphaComposite;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.Transparency;
+import java.awt.color.*;
+import java.awt.image.*;
+import java.nio.*;
+
+import javax.media.opengl.*;
+import javax.media.opengl.util.*;
+import com.sun.opengl.util.texture.*;
+import com.sun.opengl.util.texture.spi.*;
+
+/**
+ * Represents the data for an OpenGL texture. This is separated from
+ * the notion of a Texture to support things like streaming in of
+ * textures in a background thread without requiring an OpenGL context
+ * to be current on that thread.
+ *
+ * @author Chris Campbell
+ * @author Kenneth Russell
+ */
+
+public class AWTTextureData implements TextureData {
+ private int width;
+ private int height;
+ private int border;
+ private int pixelFormat;
+ private int pixelType;
+ private int internalFormat; // perhaps inferred from pixelFormat?
+ private boolean mipmap; // indicates whether mipmaps should be generated
+ // (ignored if mipmaps are supplied from the file)
+ private boolean dataIsCompressed;
+ private boolean mustFlipVertically; // Must flip texture coordinates
+ // vertically to get OpenGL output
+ // to look correct
+ private Buffer buffer; // the actual data...
+ private Buffer[] mipmapData; // ...or a series of mipmaps
+ private Flusher flusher;
+ private int rowLength;
+ private int alignment; // 1, 2, or 4 bytes
+ private int estimatedMemorySize;
+
+ // Mechanism for lazily converting input BufferedImages with custom
+ // ColorModels to standard ones for uploading to OpenGL, as well as
+ // backing off from the optimizations of hoping that either
+ // GL_EXT_abgr or OpenGL 1.2 are present
+ private BufferedImage imageForLazyCustomConversion;
+ private boolean expectingEXTABGR;
+ private boolean haveEXTABGR;
+ private boolean expectingGL12;
+ private boolean haveGL12;
+
+ private static final ColorModel rgbaColorModel =
+ new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
+ new int[] {8, 8, 8, 8}, true, true,
+ Transparency.TRANSLUCENT,
+ DataBuffer.TYPE_BYTE);
+ private static final ColorModel rgbColorModel =
+ new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
+ new int[] {8, 8, 8, 0}, false, false,
+ Transparency.OPAQUE,
+ DataBuffer.TYPE_BYTE);
+
+ /**
+ * Constructs a new AWTTextureData object with the specified parameters
+ * and data contained in the given Buffer. The optional Flusher can
+ * be used to clean up native resources associated with this
+ * AWTTextureData when processing is complete; for example, closing of
+ * memory-mapped files that might otherwise require a garbage
+ * collection to reclaim and close.
+ *
+ * @param internalFormat the OpenGL internal format for the
+ * resulting texture; must be specified, may
+ * not be 0
+ * @param width the width in pixels of the texture
+ * @param height the height in pixels of the texture
+ * @param border the number of pixels of border this texture
+ * data has (0 or 1)
+ * @param pixelFormat the OpenGL pixel format for the
+ * resulting texture; must be specified, may
+ * not be 0
+ * @param pixelType the OpenGL type of the pixels of the texture
+ * @param mipmap indicates whether mipmaps should be
+ * autogenerated (using GLU) for the resulting
+ * texture. Currently if mipmap is true then
+ * dataIsCompressed may not be true.
+ * @param dataIsCompressed indicates whether the texture data is in
+ * compressed form
+ * (e.g. GL_COMPRESSED_RGB_S3TC_DXT1_EXT)
+ * @param mustFlipVertically indicates whether the texture
+ * coordinates must be flipped vertically
+ * in order to properly display the
+ * texture
+ * @param buffer the buffer containing the texture data
+ * @param flusher optional flusher to perform cleanup tasks
+ * upon call to flush()
+ *
+ * @throws IllegalArgumentException if any parameters of the texture
+ * data were invalid, such as requesting mipmap generation for a
+ * compressed texture
+ */
+ public AWTTextureData(int internalFormat,
+ int width,
+ int height,
+ int border,
+ int pixelFormat,
+ int pixelType,
+ boolean mipmap,
+ boolean dataIsCompressed,
+ boolean mustFlipVertically,
+ Buffer buffer,
+ Flusher flusher) throws IllegalArgumentException {
+ if (mipmap && dataIsCompressed) {
+ throw new IllegalArgumentException("Can not generate mipmaps for compressed textures");
+ }
+
+ this.width = width;
+ this.height = height;
+ this.border = border;
+ this.pixelFormat = pixelFormat;
+ this.pixelType = pixelType;
+ this.internalFormat = internalFormat;
+ this.mipmap = mipmap;
+ this.dataIsCompressed = dataIsCompressed;
+ this.mustFlipVertically = mustFlipVertically;
+ this.buffer = buffer;
+ this.flusher = flusher;
+ alignment = 1; // FIXME: is this correct enough in all situations?
+ estimatedMemorySize = estimatedMemorySize(buffer);
+ }
+
+ /**
+ * Constructs a new AWTTextureData object with the specified parameters
+ * and data for multiple mipmap levels contained in the given array
+ * of Buffers. The optional Flusher can be used to clean up native
+ * resources associated with this AWTTextureData when processing is
+ * complete; for example, closing of memory-mapped files that might
+ * otherwise require a garbage collection to reclaim and close.
+ *
+ * @param internalFormat the OpenGL internal format for the
+ * resulting texture; must be specified, may
+ * not be 0
+ * @param width the width in pixels of the topmost mipmap
+ * level of the texture
+ * @param height the height in pixels of the topmost mipmap
+ * level of the texture
+ * @param border the number of pixels of border this texture
+ * data has (0 or 1)
+ * @param pixelFormat the OpenGL pixel format for the
+ * resulting texture; must be specified, may
+ * not be 0
+ * @param pixelType the OpenGL type of the pixels of the texture
+ * @param dataIsCompressed indicates whether the texture data is in
+ * compressed form
+ * (e.g. GL_COMPRESSED_RGB_S3TC_DXT1_EXT)
+ * @param mustFlipVertically indicates whether the texture
+ * coordinates must be flipped vertically
+ * in order to properly display the
+ * texture
+ * @param mipmapData the buffers containing all mipmap levels
+ * of the texture's data
+ * @param flusher optional flusher to perform cleanup tasks
+ * upon call to flush()
+ *
+ * @throws IllegalArgumentException if any parameters of the texture
+ * data were invalid, such as requesting mipmap generation for a
+ * compressed texture
+ */
+ public AWTTextureData(int internalFormat,
+ int width,
+ int height,
+ int border,
+ int pixelFormat,
+ int pixelType,
+ boolean dataIsCompressed,
+ boolean mustFlipVertically,
+ Buffer[] mipmapData,
+ Flusher flusher) throws IllegalArgumentException {
+ this.width = width;
+ this.height = height;
+ this.border = border;
+ this.pixelFormat = pixelFormat;
+ this.pixelType = pixelType;
+ this.internalFormat = internalFormat;
+ this.dataIsCompressed = dataIsCompressed;
+ this.mustFlipVertically = mustFlipVertically;
+ this.mipmapData = (Buffer[]) mipmapData.clone();
+ this.flusher = flusher;
+ alignment = 1; // FIXME: is this correct enough in all situations?
+ for (int i = 0; i < mipmapData.length; i++) {
+ estimatedMemorySize += estimatedMemorySize(mipmapData[i]);
+ }
+ }
+
+ /**
+ * Constructs a new AWTTextureData object with the specified parameters
+ * and data contained in the given BufferedImage. The resulting
+ * AWTTextureData "wraps" the contents of the BufferedImage, so if a
+ * modification is made to the BufferedImage between the time the
+ * AWTTextureData is constructed and when a Texture is made from the
+ * AWTTextureData, that modification will be visible in the resulting
+ * Texture.
+ *
+ * @param internalFormat the OpenGL internal format for the
+ * resulting texture; may be 0, in which case
+ * it is inferred from the image's type
+ * @param pixelFormat the OpenGL internal format for the
+ * resulting texture; may be 0, in which case
+ * it is inferred from the image's type (note:
+ * this argument is currently always ignored)
+ * @param mipmap indicates whether mipmaps should be
+ * autogenerated (using GLU) for the resulting
+ * texture
+ * @param image the image containing the texture data
+ */
+ public AWTTextureData(int internalFormat,
+ int pixelFormat,
+ boolean mipmap,
+ BufferedImage image) {
+ if (internalFormat == 0) {
+ this.internalFormat = image.getColorModel().hasAlpha() ? GL.GL_RGBA : GL.GL_RGB;
+ } else {
+ this.internalFormat = internalFormat;
+ }
+ createFromImage(image);
+ this.mipmap = mipmap;
+ if (buffer != null) {
+ estimatedMemorySize = estimatedMemorySize(buffer);
+ } else {
+ // In the lazy custom conversion case we don't yet have a buffer
+ if (imageForLazyCustomConversion != null) {
+ estimatedMemorySize = estimatedMemorySize(wrapImageDataBuffer(imageForLazyCustomConversion));
+ }
+ }
+ }
+
+ /** Returns the width in pixels of the texture data. */
+ public int getWidth() { return width; }
+ /** Returns the height in pixels of the texture data. */
+ public int getHeight() { return height; }
+ /** Returns the border in pixels of the texture data. */
+ public int getBorder() { return border; }
+ /** Returns the intended OpenGL pixel format of the texture data. */
+ public int getPixelFormat() {
+ if (imageForLazyCustomConversion != null) {
+ if (!((expectingEXTABGR && haveEXTABGR) ||
+ (expectingGL12 && haveGL12))) {
+ revertPixelFormatAndType();
+ }
+ }
+ return pixelFormat;
+ }
+ /** Returns the intended OpenGL pixel type of the texture data. */
+ public int getPixelType() {
+ if (imageForLazyCustomConversion != null) {
+ if (!((expectingEXTABGR && haveEXTABGR) ||
+ (expectingGL12 && haveGL12))) {
+ revertPixelFormatAndType();
+ }
+ }
+ return pixelType;
+ }
+ /** Returns the intended OpenGL internal format of the texture data. */
+ public int getInternalFormat() { return internalFormat; }
+ /** Returns whether mipmaps should be generated for the texture data. */
+ public boolean getMipmap() { return mipmap; }
+ /** Indicates whether the texture data is in compressed form. */
+ public boolean isDataCompressed() { return dataIsCompressed; }
+ /** Indicates whether the texture coordinates must be flipped
+ vertically for proper display. */
+ public boolean getMustFlipVertically() { return mustFlipVertically; }
+ /** Returns the texture data, or null if it is specified as a set of mipmaps. */
+ public Buffer getBuffer() {
+ if (imageForLazyCustomConversion != null) {
+ if (!((expectingEXTABGR && haveEXTABGR) ||
+ (expectingGL12 && haveGL12))) {
+ revertPixelFormatAndType();
+ // Must present the illusion to the end user that we are simply
+ // wrapping the input BufferedImage
+ createFromCustom(imageForLazyCustomConversion);
+ }
+ }
+ return buffer;
+ }
+ /** Returns all mipmap levels for the texture data, or null if it is
+ specified as a single image. */
+ public Buffer[] getMipmapData() { return mipmapData; }
+ /** Returns the required byte alignment for the texture data. */
+ public int getAlignment() { return alignment; }
+ /** Returns the row length needed for correct GL_UNPACK_ROW_LENGTH
+ specification. This is currently only supported for
+ non-mipmapped, non-compressed textures. */
+ public int getRowLength() { return rowLength; }
+
+ /** Sets the width in pixels of the texture data. */
+ public void setWidth(int width) { this.width = width; }
+ /** Sets the height in pixels of the texture data. */
+ public void setHeight(int height) { this.height = height; }
+ /** Sets the border in pixels of the texture data. */
+ public void setBorder(int border) { this.border = border; }
+ /** Sets the intended OpenGL pixel format of the texture data. */
+ public void setPixelFormat(int pixelFormat) { this.pixelFormat = pixelFormat; }
+ /** Sets the intended OpenGL pixel type of the texture data. */
+ public void setPixelType(int pixelType) { this.pixelType = pixelType; }
+ /** Sets the intended OpenGL internal format of the texture data. */
+ public void setInternalFormat(int internalFormat) { this.internalFormat = internalFormat; }
+ /** Sets whether mipmaps should be generated for the texture data. */
+ public void setMipmap(boolean mipmap) { this.mipmap = mipmap; }
+ /** Sets whether the texture data is in compressed form. */
+ public void setIsDataCompressed(boolean compressed) { this.dataIsCompressed = compressed; }
+ /** Sets whether the texture coordinates must be flipped vertically
+ for proper display. */
+ public void setMustFlipVertically(boolean mustFlipVertically) { this.mustFlipVertically = mustFlipVertically; }
+ /** Sets the texture data. */
+ public void setBuffer(Buffer buffer) {
+ this.buffer = buffer;
+ estimatedMemorySize = estimatedMemorySize(buffer);
+ }
+ /** Sets the required byte alignment for the texture data. */
+ public void setAlignment(int alignment) { this.alignment = alignment; }
+ /** Sets the row length needed for correct GL_UNPACK_ROW_LENGTH
+ specification. This is currently only supported for
+ non-mipmapped, non-compressed textures. */
+ public void setRowLength(int rowLength) { this.rowLength = rowLength; }
+ /** Indicates to this TextureData whether the GL_EXT_abgr extension
+ is available. Used for optimization along some code paths to
+ avoid data copies. */
+ public void setHaveEXTABGR(boolean haveEXTABGR) {
+ this.haveEXTABGR = haveEXTABGR;
+ }
+ /** Indicates to this TextureData whether OpenGL version 1.2 is
+ available. If not, falls back to relatively inefficient code
+ paths for several input data types (several kinds of packed
+ pixel formats, in particular). */
+ public void setHaveGL12(boolean haveGL12) {
+ this.haveGL12 = haveGL12;
+ }
+
+ /** Returns an estimate of the amount of memory in bytes this
+ TextureData will consume once uploaded to the graphics card. It
+ should only be treated as an estimate; most applications should
+ not need to query this but instead let the OpenGL implementation
+ page textures in and out as necessary. */
+ public int getEstimatedMemorySize() {
+ return estimatedMemorySize;
+ }
+
+ /** Flushes resources associated with this TextureData by calling
+ Flusher.flush(). */
+ public void flush() {
+ if (flusher != null) {
+ flusher.flush();
+ flusher = null;
+ }
+ }
+
+ //----------------------------------------------------------------------
+ // Internals only below this point
+ //
+
+ private void createNIOBufferFromImage(BufferedImage image) {
+ buffer = wrapImageDataBuffer(image);
+ }
+
+ private Buffer wrapImageDataBuffer(BufferedImage image) {
+ //
+ // Note: Grabbing the DataBuffer will defeat Java2D's image
+ // management mechanism (as of JDK 5/6, at least). This shouldn't
+ // be a problem for most JOGL apps, but those that try to upload
+ // the image into an OpenGL texture and then use the same image in
+ // Java2D rendering might find the 2D rendering is not as fast as
+ // it could be.
+ //
+
+ DataBuffer data = image.getRaster().getDataBuffer();
+ if (data instanceof DataBufferByte) {
+ return ByteBuffer.wrap(((DataBufferByte) data).getData());
+ } else if (data instanceof DataBufferDouble) {
+ throw new RuntimeException("DataBufferDouble rasters not supported by OpenGL");
+ } else if (data instanceof DataBufferFloat) {
+ return FloatBuffer.wrap(((DataBufferFloat) data).getData());
+ } else if (data instanceof DataBufferInt) {
+ return IntBuffer.wrap(((DataBufferInt) data).getData());
+ } else if (data instanceof DataBufferShort) {
+ return ShortBuffer.wrap(((DataBufferShort) data).getData());
+ } else if (data instanceof DataBufferUShort) {
+ return ShortBuffer.wrap(((DataBufferUShort) data).getData());
+ } else {
+ throw new RuntimeException("Unexpected DataBuffer type?");
+ }
+ }
+
+ private void createFromImage(BufferedImage image) {
+ pixelType = 0; // Determine from image
+ mustFlipVertically = true;
+
+ width = image.getWidth();
+ height = image.getHeight();
+
+ int scanlineStride;
+ SampleModel sm = image.getRaster().getSampleModel();
+ if (sm instanceof SinglePixelPackedSampleModel) {
+ scanlineStride =
+ ((SinglePixelPackedSampleModel)sm).getScanlineStride();
+ } else if (sm instanceof MultiPixelPackedSampleModel) {
+ scanlineStride =
+ ((MultiPixelPackedSampleModel)sm).getScanlineStride();
+ } else if (sm instanceof ComponentSampleModel) {
+ scanlineStride =
+ ((ComponentSampleModel)sm).getScanlineStride();
+ } else {
+ // This will only happen for TYPE_CUSTOM anyway
+ setupLazyCustomConversion(image);
+ return;
+ }
+
+ if(GLProfile.isGL2()) {
+ switch (image.getType()) {
+ case BufferedImage.TYPE_INT_RGB:
+ pixelFormat = GL2.GL_BGRA;
+ pixelType = GL2.GL_UNSIGNED_INT_8_8_8_8_REV;
+ rowLength = scanlineStride;
+ alignment = 4;
+ expectingGL12 = true;
+ setupLazyCustomConversion(image);
+ break;
+ case BufferedImage.TYPE_INT_ARGB_PRE:
+ pixelFormat = GL2.GL_BGRA;
+ pixelType = GL2.GL_UNSIGNED_INT_8_8_8_8_REV;
+ rowLength = scanlineStride;
+ alignment = 4;
+ expectingGL12 = true;
+ setupLazyCustomConversion(image);
+ break;
+ case BufferedImage.TYPE_INT_BGR:
+ pixelFormat = GL.GL_RGBA;
+ pixelType = GL2.GL_UNSIGNED_INT_8_8_8_8_REV;
+ rowLength = scanlineStride;
+ alignment = 4;
+ expectingGL12 = true;
+ setupLazyCustomConversion(image);
+ break;
+ case BufferedImage.TYPE_3BYTE_BGR:
+ {
+ // we can pass the image data directly to OpenGL only if
+ // we have an integral number of pixels in each scanline
+ if ((scanlineStride % 3) == 0) {
+ pixelFormat = GL2.GL_BGR;
+ pixelType = GL.GL_UNSIGNED_BYTE;
+ rowLength = scanlineStride / 3;
+ alignment = 1;
+ } else {
+ setupLazyCustomConversion(image);
+ return;
+ }
+ }
+ break;
+ case BufferedImage.TYPE_4BYTE_ABGR_PRE:
+ {
+ // we can pass the image data directly to OpenGL only if
+ // we have an integral number of pixels in each scanline
+ // and only if the GL_EXT_abgr extension is present
+
+ // NOTE: disabling this code path for now as it appears it's
+ // buggy at least on some NVidia drivers and doesn't perform
+ // the necessary byte swapping (FIXME: needs more
+ // investigation)
+ if ((scanlineStride % 4) == 0 && false) {
+ pixelFormat = GL2.GL_ABGR_EXT;
+ pixelType = GL.GL_UNSIGNED_BYTE;
+ rowLength = scanlineStride / 4;
+ alignment = 4;
+
+ // Store a reference to the original image for later in
+ // case it turns out that we don't have GL_EXT_abgr at the
+ // time we're going to do the texture upload to OpenGL
+ setupLazyCustomConversion(image);
+ expectingEXTABGR = true;
+ break;
+ } else {
+ setupLazyCustomConversion(image);
+ return;
+ }
+ }
+ case BufferedImage.TYPE_USHORT_565_RGB:
+ pixelFormat = GL.GL_RGB;
+ pixelType = GL.GL_UNSIGNED_SHORT_5_6_5;
+ rowLength = scanlineStride;
+ alignment = 2;
+ expectingGL12 = true;
+ setupLazyCustomConversion(image);
+ break;
+ case BufferedImage.TYPE_USHORT_555_RGB:
+ pixelFormat = GL2.GL_BGRA;
+ pixelType = GL2.GL_UNSIGNED_SHORT_1_5_5_5_REV;
+ rowLength = scanlineStride;
+ alignment = 2;
+ expectingGL12 = true;
+ setupLazyCustomConversion(image);
+ break;
+ case BufferedImage.TYPE_BYTE_GRAY:
+ pixelFormat = GL.GL_LUMINANCE;
+ pixelType = GL.GL_UNSIGNED_BYTE;
+ rowLength = scanlineStride;
+ alignment = 1;
+ break;
+ case BufferedImage.TYPE_USHORT_GRAY:
+ pixelFormat = GL.GL_LUMINANCE;
+ pixelType = GL.GL_UNSIGNED_SHORT;
+ rowLength = scanlineStride;
+ alignment = 2;
+ break;
+ // Note: TYPE_INT_ARGB and TYPE_4BYTE_ABGR images go down the
+ // custom code path to satisfy the invariant that images with an
+ // alpha channel always go down with premultiplied alpha.
+ case BufferedImage.TYPE_INT_ARGB:
+ case BufferedImage.TYPE_4BYTE_ABGR:
+ case BufferedImage.TYPE_BYTE_BINARY:
+ case BufferedImage.TYPE_BYTE_INDEXED:
+ case BufferedImage.TYPE_CUSTOM:
+ default:
+ ColorModel cm = image.getColorModel();
+ if (cm.equals(rgbColorModel)) {
+ pixelFormat = GL.GL_RGB;
+ pixelType = GL.GL_UNSIGNED_BYTE;
+ rowLength = scanlineStride / 3;
+ alignment = 1;
+ } else if (cm.equals(rgbaColorModel)) {
+ pixelFormat = GL.GL_RGBA;
+ pixelType = GL.GL_UNSIGNED_BYTE;
+ rowLength = scanlineStride / 4; // FIXME: correct?
+ alignment = 4;
+ } else {
+ setupLazyCustomConversion(image);
+ return;
+ }
+ break;
+ }
+ } else {
+ switch (image.getType()) {
+ case BufferedImage.TYPE_INT_RGB:
+ pixelFormat = GL.GL_RGB;
+ pixelType = GL.GL_UNSIGNED_BYTE;
+ rowLength = scanlineStride;
+ alignment = 3;
+ expectingGL12 = true;
+ setupLazyCustomConversion(image);
+ break;
+ case BufferedImage.TYPE_INT_ARGB_PRE:
+ throw new GLException("INT_ARGB_PRE n.a.");
+ case BufferedImage.TYPE_INT_BGR:
+ throw new GLException("INT_BGR n.a.");
+ case BufferedImage.TYPE_3BYTE_BGR:
+ throw new GLException("INT_BGR n.a.");
+ case BufferedImage.TYPE_4BYTE_ABGR_PRE:
+ throw new GLException("INT_BGR n.a.");
+ case BufferedImage.TYPE_USHORT_565_RGB:
+ pixelFormat = GL.GL_RGB;
+ pixelType = GL.GL_UNSIGNED_SHORT_5_6_5;
+ rowLength = scanlineStride;
+ alignment = 2;
+ expectingGL12 = true;
+ setupLazyCustomConversion(image);
+ break;
+ case BufferedImage.TYPE_USHORT_555_RGB:
+ pixelFormat = GL.GL_RGBA;
+ pixelType = GL.GL_UNSIGNED_SHORT_5_5_5_1;
+ rowLength = scanlineStride;
+ alignment = 2;
+ expectingGL12 = true;
+ setupLazyCustomConversion(image);
+ break;
+ case BufferedImage.TYPE_BYTE_GRAY:
+ pixelFormat = GL.GL_LUMINANCE;
+ pixelType = GL.GL_UNSIGNED_BYTE;
+ rowLength = scanlineStride;
+ alignment = 1;
+ break;
+ case BufferedImage.TYPE_USHORT_GRAY:
+ throw new GLException("USHORT_GRAY n.a.");
+ // Note: TYPE_INT_ARGB and TYPE_4BYTE_ABGR images go down the
+ // custom code path to satisfy the invariant that images with an
+ // alpha channel always go down with premultiplied alpha.
+ case BufferedImage.TYPE_INT_ARGB:
+ case BufferedImage.TYPE_4BYTE_ABGR:
+ case BufferedImage.TYPE_BYTE_BINARY:
+ case BufferedImage.TYPE_BYTE_INDEXED:
+ case BufferedImage.TYPE_CUSTOM:
+ default:
+ ColorModel cm = image.getColorModel();
+ if (cm.equals(rgbColorModel)) {
+ pixelFormat = GL.GL_RGB;
+ pixelType = GL.GL_UNSIGNED_BYTE;
+ rowLength = scanlineStride / 3;
+ alignment = 1;
+ } else if (cm.equals(rgbaColorModel)) {
+ pixelFormat = GL.GL_RGBA;
+ pixelType = GL.GL_UNSIGNED_BYTE;
+ rowLength = scanlineStride / 4; // FIXME: correct?
+ alignment = 4;
+ } else {
+ setupLazyCustomConversion(image);
+ return;
+ }
+ break;
+ }
+ }
+
+ createNIOBufferFromImage(image);
+ }
+
+ private void setupLazyCustomConversion(BufferedImage image) {
+ imageForLazyCustomConversion = image;
+ boolean hasAlpha = image.getColorModel().hasAlpha();
+ if (pixelFormat == 0) {
+ pixelFormat = hasAlpha ? GL.GL_RGBA : GL.GL_RGB;
+ }
+ alignment = 1; // FIXME: do we need better?
+ rowLength = width; // FIXME: correct in all cases?
+
+ // Allow previously-selected pixelType (if any) to override that
+ // we can infer from the DataBuffer
+ DataBuffer data = image.getRaster().getDataBuffer();
+ if (data instanceof DataBufferByte || isPackedInt(image)) {
+ // Don't use GL_UNSIGNED_INT for BufferedImage packed int images
+ if (pixelType == 0) pixelType = GL.GL_UNSIGNED_BYTE;
+ } else if (data instanceof DataBufferDouble) {
+ throw new RuntimeException("DataBufferDouble rasters not supported by OpenGL");
+ } else if (data instanceof DataBufferFloat) {
+ if (pixelType == 0) pixelType = GL.GL_FLOAT;
+ } else if ((data instanceof DataBufferInt) && GLProfile.isGL2ES2()) {
+ // FIXME: should we support signed ints?
+ if (pixelType == 0) pixelType = GL2.GL_UNSIGNED_INT;
+ } else if (data instanceof DataBufferShort) {
+ if (pixelType == 0) pixelType = GL.GL_SHORT;
+ } else if (data instanceof DataBufferUShort) {
+ if (pixelType == 0) pixelType = GL.GL_UNSIGNED_SHORT;
+ } else {
+ throw new RuntimeException("Unexpected DataBuffer type?");
+ }
+ }
+
+ private void createFromCustom(BufferedImage image) {
+ int width = image.getWidth();
+ int height = image.getHeight();
+
+ // create a temporary image that is compatible with OpenGL
+ boolean hasAlpha = image.getColorModel().hasAlpha();
+ ColorModel cm = null;
+ int dataBufferType = image.getRaster().getDataBuffer().getDataType();
+ // Don't use integer components for packed int images
+ if (isPackedInt(image)) {
+ dataBufferType = DataBuffer.TYPE_BYTE;
+ }
+ if (dataBufferType == DataBuffer.TYPE_BYTE) {
+ cm = hasAlpha ? rgbaColorModel : rgbColorModel;
+ } else {
+ if (hasAlpha) {
+ cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
+ null, true, true,
+ Transparency.TRANSLUCENT,
+ dataBufferType);
+ } else {
+ cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
+ null, false, false,
+ Transparency.OPAQUE,
+ dataBufferType);
+ }
+ }
+
+ boolean premult = cm.isAlphaPremultiplied();
+ WritableRaster raster =
+ cm.createCompatibleWritableRaster(width, height);
+ BufferedImage texImage = new BufferedImage(cm, raster, premult, null);
+
+ // copy the source image into the temporary image
+ Graphics2D g = texImage.createGraphics();
+ g.setComposite(AlphaComposite.Src);
+ g.drawImage(image, 0, 0, null);
+ g.dispose();
+
+ // Wrap the buffer from the temporary image
+ createNIOBufferFromImage(texImage);
+ }
+
+ private boolean isPackedInt(BufferedImage image) {
+ int imgType = image.getType();
+ return (imgType == BufferedImage.TYPE_INT_RGB ||
+ imgType == BufferedImage.TYPE_INT_BGR ||
+ imgType == BufferedImage.TYPE_INT_ARGB ||
+ imgType == BufferedImage.TYPE_INT_ARGB_PRE);
+ }
+
+ private void revertPixelFormatAndType() {
+ // Knowing we don't have e.g. OpenGL 1.2 functionality available,
+ // and knowing we're in the process of doing the fallback code
+ // path, re-infer a vanilla pixel format and type compatible with
+ // OpenGL 1.1
+ pixelFormat = 0;
+ pixelType = 0;
+ setupLazyCustomConversion(imageForLazyCustomConversion);
+ }
+
+ private int estimatedMemorySize(Buffer buffer) {
+ if (buffer == null) {
+ return 0;
+ }
+ int capacity = buffer.capacity();
+ if (buffer instanceof ByteBuffer) {
+ return capacity;
+ } else if (buffer instanceof IntBuffer) {
+ return capacity * BufferUtil.SIZEOF_INT;
+ } else if (buffer instanceof FloatBuffer) {
+ return capacity * BufferUtil.SIZEOF_FLOAT;
+ } else if (buffer instanceof ShortBuffer) {
+ return capacity * BufferUtil.SIZEOF_SHORT;
+ } else if (buffer instanceof LongBuffer) {
+ return capacity * BufferUtil.SIZEOF_LONG;
+ } else if (buffer instanceof DoubleBuffer) {
+ return capacity * BufferUtil.SIZEOF_DOUBLE;
+ }
+ throw new RuntimeException("Unexpected buffer type " +
+ buffer.getClass().getName());
+ }
+}
diff --git a/src/classes/com/sun/opengl/util/texture/awt/AWTTextureReader.java b/src/classes/com/sun/opengl/util/texture/awt/AWTTextureReader.java
new file mode 100755
index 000000000..13d8dac0e
--- /dev/null
+++ b/src/classes/com/sun/opengl/util/texture/awt/AWTTextureReader.java
@@ -0,0 +1,968 @@
+/*
+ * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.opengl.util.texture.awt;
+
+import java.awt.image.BufferedImage;
+
+import java.io.*;
+import java.net.*;
+import java.nio.*;
+import java.util.*;
+import javax.imageio.*;
+
+import javax.media.opengl.*;
+import javax.media.opengl.glu.*;
+import com.sun.opengl.impl.Debug;
+import com.sun.opengl.util.io.*;
+import com.sun.opengl.util.texture.*;
+import com.sun.opengl.util.texture.spi.*;
+
+/** <P> Provides input and output facilities for both loading OpenGL
+ textures from disk and streams as well as writing textures already
+ in memory back to disk. </P>
+
+ <P> The TextureIO class supports an arbitrary number of plug-in
+ readers and writers via TextureProviders and TextureWriters.
+ TextureProviders know how to produce TextureData objects from
+ files, InputStreams and URLs. TextureWriters know how to write
+ TextureData objects to disk in various file formats. The
+ TextureData class represents the raw data of the texture before it
+ has been converted to an OpenGL texture object. The Texture class
+ represents the OpenGL texture object and provides easy facilities
+ for using the texture. </P>
+
+ <P> There are several built-in TextureProviders and TextureWriters
+ supplied with the TextureIO implementation. The most basic
+ provider uses the platform's Image I/O facilities to read in a
+ BufferedImage and convert it to a texture. This is the baseline
+ provider and is registered so that it is the last one consulted.
+ All others are asked first to open a given file. </P>
+
+ <P> There are three other providers registered by default as of
+ the time of this writing. One handles SGI RGB (".sgi", ".rgb")
+ images from both files and streams. One handles DirectDraw Surface
+ (".dds") images read from files, though can not read these images
+ from streams. One handles Targa (".tga") images read from both
+ files and streams. These providers are executed in an arbitrary
+ order. Some of these providers require the file's suffix to either
+ be specified via the newTextureData methods or for the file to be
+ named with the appropriate suffix. In general a file suffix should
+ be provided to the newTexture and newTextureData methods if at all
+ possible. </P>
+
+ <P> Note that additional TextureProviders, if reading images from
+ InputStreams, must use the mark()/reset() methods on InputStream
+ when probing for e.g. magic numbers at the head of the file to
+ make sure not to disturb the state of the InputStream for
+ downstream TextureProviders. </P>
+
+ <P> There are analogous TextureWriters provided for writing
+ textures back to disk if desired. As of this writing, there are
+ four TextureWriters registered by default: one for Targa files,
+ one for SGI RGB files, one for DirectDraw surface (.dds) files,
+ and one for ImageIO-supplied formats such as .jpg and .png. Some
+ of these writers have certain limitations such as only being able
+ to write out textures stored in GL_RGB or GL_RGBA format. The DDS
+ writer supports fetching and writing to disk of texture data in
+ DXTn compressed format. Whether this will occur is dependent on
+ whether the texture's internal format is one of the DXTn
+ compressed formats and whether the target file is .dds format.
+*/
+
+public class AWTTextureReader {
+ private static final boolean DEBUG = Debug.debug("TextureReader");
+
+ // For manually disabling the use of the texture rectangle
+ // extensions so you know the texture target is GL_TEXTURE_2D; this
+ // is useful for shader writers (thanks to Chris Campbell for this
+ // observation)
+ private static boolean texRectEnabled = true;
+
+ //----------------------------------------------------------------------
+ // methods that *do not* require a current context
+ // These methods assume RGB or RGBA textures.
+ // Some texture providers may not recognize the file format unless
+ // the fileSuffix is specified, so it is strongly recommended to
+ // specify it wherever it is known.
+ // Some texture providers may also only support one kind of input,
+ // i.e., reading from a file as opposed to a stream.
+
+ /**
+ * Creates a TextureData from the given file. Does no OpenGL work.
+ *
+ * @param file the file from which to read the texture data
+ * @param mipmap whether mipmaps should be produced for this
+ * texture either by autogenerating them or
+ * reading them from the file. Some file formats
+ * support multiple mipmaps in a single file in
+ * which case those mipmaps will be used rather
+ * than generating them.
+ * @param fileSuffix the suffix of the file name to be used as a
+ * hint of the file format to the underlying
+ * texture provider, or null if none and should be
+ * auto-detected (some texture providers do not
+ * support this)
+ * @return the texture data from the file, or null if none of the
+ * registered texture providers could read the file
+ * @throws IOException if an error occurred while reading the file
+ */
+ public static TextureData newTextureData(File file,
+ boolean mipmap,
+ String fileSuffix) throws IOException {
+ if (fileSuffix == null) {
+ fileSuffix = FileUtil.getFileSuffix(file);
+ }
+ return newTextureDataImpl(file, 0, 0, mipmap, fileSuffix);
+ }
+
+ /**
+ * Creates a TextureData from the given stream. Does no OpenGL work.
+ *
+ * @param stream the stream from which to read the texture data
+ * @param mipmap whether mipmaps should be produced for this
+ * texture either by autogenerating them or
+ * reading them from the file. Some file formats
+ * support multiple mipmaps in a single file in
+ * which case those mipmaps will be used rather
+ * than generating them.
+ * @param fileSuffix the suffix of the file name to be used as a
+ * hint of the file format to the underlying
+ * texture provider, or null if none and should be
+ * auto-detected (some texture providers do not
+ * support this)
+ * @return the texture data from the stream, or null if none of the
+ * registered texture providers could read the stream
+ * @throws IOException if an error occurred while reading the stream
+ */
+ public static TextureData newTextureData(InputStream stream,
+ boolean mipmap,
+ String fileSuffix) throws IOException {
+ return newTextureDataImpl(stream, 0, 0, mipmap, fileSuffix);
+ }
+
+ /**
+ * Creates a TextureData from the given URL. Does no OpenGL work.
+ *
+ * @param url the URL from which to read the texture data
+ * @param mipmap whether mipmaps should be produced for this
+ * texture either by autogenerating them or
+ * reading them from the file. Some file formats
+ * support multiple mipmaps in a single file in
+ * which case those mipmaps will be used rather
+ * than generating them.
+ * @param fileSuffix the suffix of the file name to be used as a
+ * hint of the file format to the underlying
+ * texture provider, or null if none and should be
+ * auto-detected (some texture providers do not
+ * support this)
+ * @return the texture data from the URL, or null if none of the
+ * registered texture providers could read the URL
+ * @throws IOException if an error occurred while reading the URL
+ */
+ public static TextureData newTextureData(URL url,
+ boolean mipmap,
+ String fileSuffix) throws IOException {
+ if (fileSuffix == null) {
+ fileSuffix = FileUtil.getFileSuffix(url.getPath());
+ }
+ return newTextureDataImpl(url, 0, 0, mipmap, fileSuffix);
+ }
+
+ /**
+ * Creates a TextureData from the given BufferedImage. Does no
+ * OpenGL work.
+ *
+ * @param image the BufferedImage containing the texture data
+ * @param mipmap whether mipmaps should be produced for this
+ * texture by autogenerating them
+ * @return the texture data from the image
+ */
+ public static TextureData newTextureData(BufferedImage image,
+ boolean mipmap) {
+ return newTextureDataImpl(image, 0, 0, mipmap);
+ }
+
+ //----------------------------------------------------------------------
+ // These methods make no assumption about the OpenGL internal format
+ // or pixel format of the texture; they must be specified by the
+ // user. It is not allowed to supply 0 (indicating no preference)
+ // for either the internalFormat or the pixelFormat;
+ // IllegalArgumentException will be thrown in this case.
+
+ /**
+ * Creates a TextureData from the given file, using the specified
+ * OpenGL internal format and pixel format for the texture which
+ * will eventually result. The internalFormat and pixelFormat must
+ * be specified and may not be zero; to use default values, use the
+ * variant of this method which does not take these arguments. Does
+ * no OpenGL work.
+ *
+ * @param file the file from which to read the texture data
+ * @param internalFormat the OpenGL internal format of the texture
+ * which will eventually result from the TextureData
+ * @param pixelFormat the OpenGL pixel format of the texture
+ * which will eventually result from the TextureData
+ * @param mipmap whether mipmaps should be produced for this
+ * texture either by autogenerating them or
+ * reading them from the file. Some file formats
+ * support multiple mipmaps in a single file in
+ * which case those mipmaps will be used rather
+ * than generating them.
+ * @param fileSuffix the suffix of the file name to be used as a
+ * hint of the file format to the underlying
+ * texture provider, or null if none and should be
+ * auto-detected (some texture providers do not
+ * support this)
+ * @return the texture data from the file, or null if none of the
+ * registered texture providers could read the file
+ * @throws IllegalArgumentException if either internalFormat or
+ * pixelFormat was 0
+ * @throws IOException if an error occurred while reading the file
+ */
+ public static TextureData newTextureData(File file,
+ int internalFormat,
+ int pixelFormat,
+ boolean mipmap,
+ String fileSuffix) throws IOException, IllegalArgumentException {
+ if ((internalFormat == 0) || (pixelFormat == 0)) {
+ throw new IllegalArgumentException("internalFormat and pixelFormat must be non-zero");
+ }
+
+ if (fileSuffix == null) {
+ fileSuffix = FileUtil.getFileSuffix(file);
+ }
+
+ return newTextureDataImpl(file, internalFormat, pixelFormat, mipmap, fileSuffix);
+ }
+
+ /**
+ * Creates a TextureData from the given stream, using the specified
+ * OpenGL internal format and pixel format for the texture which
+ * will eventually result. The internalFormat and pixelFormat must
+ * be specified and may not be zero; to use default values, use the
+ * variant of this method which does not take these arguments. Does
+ * no OpenGL work.
+ *
+ * @param stream the stream from which to read the texture data
+ * @param internalFormat the OpenGL internal format of the texture
+ * which will eventually result from the TextureData
+ * @param pixelFormat the OpenGL pixel format of the texture
+ * which will eventually result from the TextureData
+ * @param mipmap whether mipmaps should be produced for this
+ * texture either by autogenerating them or
+ * reading them from the file. Some file formats
+ * support multiple mipmaps in a single file in
+ * which case those mipmaps will be used rather
+ * than generating them.
+ * @param fileSuffix the suffix of the file name to be used as a
+ * hint of the file format to the underlying
+ * texture provider, or null if none and should be
+ * auto-detected (some texture providers do not
+ * support this)
+ * @return the texture data from the stream, or null if none of the
+ * registered texture providers could read the stream
+ * @throws IllegalArgumentException if either internalFormat or
+ * pixelFormat was 0
+ * @throws IOException if an error occurred while reading the stream
+ */
+ public static TextureData newTextureData(InputStream stream,
+ int internalFormat,
+ int pixelFormat,
+ boolean mipmap,
+ String fileSuffix) throws IOException, IllegalArgumentException {
+ if ((internalFormat == 0) || (pixelFormat == 0)) {
+ throw new IllegalArgumentException("internalFormat and pixelFormat must be non-zero");
+ }
+
+ return newTextureDataImpl(stream, internalFormat, pixelFormat, mipmap, fileSuffix);
+ }
+
+ /**
+ * Creates a TextureData from the given URL, using the specified
+ * OpenGL internal format and pixel format for the texture which
+ * will eventually result. The internalFormat and pixelFormat must
+ * be specified and may not be zero; to use default values, use the
+ * variant of this method which does not take these arguments. Does
+ * no OpenGL work.
+ *
+ * @param url the URL from which to read the texture data
+ * @param internalFormat the OpenGL internal format of the texture
+ * which will eventually result from the TextureData
+ * @param pixelFormat the OpenGL pixel format of the texture
+ * which will eventually result from the TextureData
+ * @param mipmap whether mipmaps should be produced for this
+ * texture either by autogenerating them or
+ * reading them from the file. Some file formats
+ * support multiple mipmaps in a single file in
+ * which case those mipmaps will be used rather
+ * than generating them.
+ * @param fileSuffix the suffix of the file name to be used as a
+ * hint of the file format to the underlying
+ * texture provider, or null if none and should be
+ * auto-detected (some texture providers do not
+ * support this)
+ * @return the texture data from the URL, or null if none of the
+ * registered texture providers could read the URL
+ * @throws IllegalArgumentException if either internalFormat or
+ * pixelFormat was 0
+ * @throws IOException if an error occurred while reading the URL
+ */
+ public static TextureData newTextureData(URL url,
+ int internalFormat,
+ int pixelFormat,
+ boolean mipmap,
+ String fileSuffix) throws IOException, IllegalArgumentException {
+ if ((internalFormat == 0) || (pixelFormat == 0)) {
+ throw new IllegalArgumentException("internalFormat and pixelFormat must be non-zero");
+ }
+
+ if (fileSuffix == null) {
+ fileSuffix = FileUtil.getFileSuffix(url.getPath());
+ }
+
+ return newTextureDataImpl(url, internalFormat, pixelFormat, mipmap, fileSuffix);
+ }
+
+ /**
+ * Creates a TextureData from the given BufferedImage, using the
+ * specified OpenGL internal format and pixel format for the texture
+ * which will eventually result. The internalFormat and pixelFormat
+ * must be specified and may not be zero; to use default values, use
+ * the variant of this method which does not take these
+ * arguments. Does no OpenGL work.
+ *
+ * @param image the BufferedImage containing the texture data
+ * @param internalFormat the OpenGL internal format of the texture
+ * which will eventually result from the TextureData
+ * @param pixelFormat the OpenGL pixel format of the texture
+ * which will eventually result from the TextureData
+ * @param mipmap whether mipmaps should be produced for this
+ * texture either by autogenerating them or
+ * reading them from the file. Some file formats
+ * support multiple mipmaps in a single file in
+ * which case those mipmaps will be used rather
+ * than generating them.
+ * @return the texture data from the image
+ * @throws IllegalArgumentException if either internalFormat or
+ * pixelFormat was 0
+ */
+ public static TextureData newTextureData(BufferedImage image,
+ int internalFormat,
+ int pixelFormat,
+ boolean mipmap) throws IllegalArgumentException {
+ if ((internalFormat == 0) || (pixelFormat == 0)) {
+ throw new IllegalArgumentException("internalFormat and pixelFormat must be non-zero");
+ }
+
+ return newTextureDataImpl(image, internalFormat, pixelFormat, mipmap);
+ }
+
+ //----------------------------------------------------------------------
+ // methods that *do* require a current context
+ //
+
+ /**
+ * Creates an OpenGL texture object from the specified TextureData
+ * using the current OpenGL context.
+ *
+ * @param data the texture data to turn into an OpenGL texture
+ * @throws GLException if no OpenGL context is current or if an
+ * OpenGL error occurred
+ * @throws IllegalArgumentException if the passed TextureData was null
+ */
+ public static Texture newTexture(TextureData data) throws GLException, IllegalArgumentException {
+ if (data == null) {
+ throw new IllegalArgumentException("Null TextureData");
+ }
+ return new Texture(data);
+ }
+
+ /**
+ * Creates an OpenGL texture object from the specified file using
+ * the current OpenGL context.
+ *
+ * @param file the file from which to read the texture data
+ * @param mipmap whether mipmaps should be produced for this
+ * texture either by autogenerating them or
+ * reading them from the file. Some file formats
+ * support multiple mipmaps in a single file in
+ * which case those mipmaps will be used rather
+ * than generating them.
+ * @throws IOException if an error occurred while reading the file
+ * @throws GLException if no OpenGL context is current or if an
+ * OpenGL error occurred
+ */
+ public static Texture newTexture(File file, boolean mipmap) throws IOException, GLException {
+ TextureData data = newTextureData(file, mipmap, FileUtil.getFileSuffix(file));
+ Texture texture = newTexture(data);
+ data.flush();
+ return texture;
+ }
+
+ /**
+ * Creates an OpenGL texture object from the specified stream using
+ * the current OpenGL context.
+ *
+ * @param stream the stream from which to read the texture data
+ * @param mipmap whether mipmaps should be produced for this
+ * texture either by autogenerating them or
+ * reading them from the file. Some file formats
+ * support multiple mipmaps in a single file in
+ * which case those mipmaps will be used rather
+ * than generating them.
+ * @param fileSuffix the suffix of the file name to be used as a
+ * hint of the file format to the underlying
+ * texture provider, or null if none and should be
+ * auto-detected (some texture providers do not
+ * support this)
+ * @throws IOException if an error occurred while reading the stream
+ * @throws GLException if no OpenGL context is current or if an
+ * OpenGL error occurred
+ */
+ public static Texture newTexture(InputStream stream, boolean mipmap, String fileSuffix) throws IOException, GLException {
+ TextureData data = newTextureData(stream, mipmap, fileSuffix);
+ Texture texture = newTexture(data);
+ data.flush();
+ return texture;
+ }
+
+ /**
+ * Creates an OpenGL texture object from the specified URL using the
+ * current OpenGL context.
+ *
+ * @param url the URL from which to read the texture data
+ * @param mipmap whether mipmaps should be produced for this
+ * texture either by autogenerating them or
+ * reading them from the file. Some file formats
+ * support multiple mipmaps in a single file in
+ * which case those mipmaps will be used rather
+ * than generating them.
+ * @param fileSuffix the suffix of the file name to be used as a
+ * hint of the file format to the underlying
+ * texture provider, or null if none and should be
+ * auto-detected (some texture providers do not
+ * support this)
+ * @throws IOException if an error occurred while reading the URL
+ * @throws GLException if no OpenGL context is current or if an
+ * OpenGL error occurred
+ */
+ public static Texture newTexture(URL url, boolean mipmap, String fileSuffix) throws IOException, GLException {
+ if (fileSuffix == null) {
+ fileSuffix = FileUtil.getFileSuffix(url.getPath());
+ }
+ TextureData data = newTextureData(url, mipmap, fileSuffix);
+ Texture texture = newTexture(data);
+ data.flush();
+ return texture;
+ }
+
+ /**
+ * Creates an OpenGL texture object from the specified BufferedImage
+ * using the current OpenGL context.
+ *
+ * @param image the BufferedImage from which to read the texture data
+ * @param mipmap whether mipmaps should be produced for this
+ * texture by autogenerating them
+ * @throws GLException if no OpenGL context is current or if an
+ * OpenGL error occurred
+ */
+ public static Texture newTexture(BufferedImage image, boolean mipmap) throws GLException {
+ TextureData data = newTextureData(image, mipmap);
+ Texture texture = newTexture(data);
+ data.flush();
+ return texture;
+ }
+
+ /**
+ * Creates an OpenGL texture object associated with the given OpenGL
+ * texture target using the current OpenGL context. The texture has
+ * no initial data. This is used, for example, to construct cube
+ * maps out of multiple TextureData objects.
+ *
+ * @throws GLException if no OpenGL context is current or if an
+ * OpenGL error occurred
+ */
+ public static Texture newTexture(int target) throws GLException {
+ return new Texture(target);
+ }
+
+ //----------------------------------------------------------------------
+ // SPI support
+ //
+
+ /** Adds a TextureProvider to support reading of a new file
+ format. */
+ public static void addTextureProvider(TextureProvider provider) {
+ // Must always add at the front so the ImageIO provider is last,
+ // so we don't accidentally use it instead of a user's possibly
+ // more optimal provider
+ textureProviders.add(0, provider);
+ }
+
+ //---------------------------------------------------------------------------
+ // Global disabling of texture rectangle extension
+ //
+
+ /** Toggles the use of the GL_ARB_texture_rectangle extension by the
+ TextureIO classes. By default, on hardware supporting this
+ extension, the TextureIO classes may use the
+ GL_ARB_texture_rectangle extension for non-power-of-two
+ textures. (If the hardware supports the
+ GL_ARB_texture_non_power_of_two extension, that one is
+ preferred.) In some situations, for example when writing
+ shaders, it is advantageous to force the texture target to
+ always be GL_TEXTURE_2D in order to have one version of the
+ shader, even at the expense of texture memory in the case where
+ NPOT textures are not supported. This method allows the use of
+ the GL_ARB_texture_rectangle extension to be turned off globally
+ for this purpose. The default is that the use of the extension
+ is enabled. */
+ public static void setTexRectEnabled(boolean enabled) {
+ texRectEnabled = enabled;
+ }
+
+ /** Indicates whether the GL_ARB_texture_rectangle extension is
+ allowed to be used for non-power-of-two textures; see {@link
+ #setTexRectEnabled setTexRectEnabled}. */
+ public static boolean isTexRectEnabled() {
+ return texRectEnabled;
+ }
+
+ //----------------------------------------------------------------------
+ // Internals only below this point
+ //
+
+ private static List/*<TextureProvider>*/ textureProviders = new ArrayList/*<TextureProvider>*/();
+ private static List/*<TextureWriter>*/ textureWriters = new ArrayList/*<TextureWriter>*/();
+
+ static {
+ // ImageIO provider, the fall-back, must be the first one added
+ addTextureProvider(new IIOTextureProvider());
+
+ // Other special-case providers
+ addTextureProvider(new DDSTextureProvider());
+ addTextureProvider(new SGITextureProvider());
+ addTextureProvider(new TGATextureProvider());
+ }
+
+ // Implementation methods
+ private static TextureData newTextureDataImpl(File file,
+ int internalFormat,
+ int pixelFormat,
+ boolean mipmap,
+ String fileSuffix) throws IOException {
+ if (file == null) {
+ throw new IOException("File was null");
+ }
+
+ fileSuffix = toLowerCase(fileSuffix);
+
+ for (Iterator iter = textureProviders.iterator(); iter.hasNext(); ) {
+ TextureProvider provider = (TextureProvider) iter.next();
+ TextureData data = provider.newTextureData(file,
+ internalFormat,
+ pixelFormat,
+ mipmap,
+ fileSuffix);
+ if (data != null) {
+ return data;
+ }
+ }
+
+ throw new IOException("No suitable reader for given file");
+ }
+
+ private static TextureData newTextureDataImpl(InputStream stream,
+ int internalFormat,
+ int pixelFormat,
+ boolean mipmap,
+ String fileSuffix) throws IOException {
+ if (stream == null) {
+ throw new IOException("Stream was null");
+ }
+
+ fileSuffix = toLowerCase(fileSuffix);
+
+ // Note: use of BufferedInputStream works around 4764639/4892246
+ if (!(stream instanceof BufferedInputStream)) {
+ stream = new BufferedInputStream(stream);
+ }
+
+ for (Iterator iter = textureProviders.iterator(); iter.hasNext(); ) {
+ TextureProvider provider = (TextureProvider) iter.next();
+ TextureData data = provider.newTextureData(stream,
+ internalFormat,
+ pixelFormat,
+ mipmap,
+ fileSuffix);
+ if (data != null) {
+ return data;
+ }
+ }
+
+ throw new IOException("No suitable reader for given stream");
+ }
+
+ private static TextureData newTextureDataImpl(URL url,
+ int internalFormat,
+ int pixelFormat,
+ boolean mipmap,
+ String fileSuffix) throws IOException {
+ if (url == null) {
+ throw new IOException("URL was null");
+ }
+
+ fileSuffix = toLowerCase(fileSuffix);
+
+ for (Iterator iter = textureProviders.iterator(); iter.hasNext(); ) {
+ TextureProvider provider = (TextureProvider) iter.next();
+ TextureData data = provider.newTextureData(url,
+ internalFormat,
+ pixelFormat,
+ mipmap,
+ fileSuffix);
+ if (data != null) {
+ return data;
+ }
+ }
+
+ throw new IOException("No suitable reader for given URL");
+ }
+
+ private static TextureData newTextureDataImpl(BufferedImage image,
+ int internalFormat,
+ int pixelFormat,
+ boolean mipmap) {
+ return new AWTTextureData(internalFormat, pixelFormat, mipmap, image);
+ }
+
+ //----------------------------------------------------------------------
+ // Base provider - used last
+ static class IIOTextureProvider implements TextureProvider {
+ public TextureData newTextureData(File file,
+ int internalFormat,
+ int pixelFormat,
+ boolean mipmap,
+ String fileSuffix) throws IOException {
+ BufferedImage img = ImageIO.read(file);
+ if (img == null) {
+ return null;
+ }
+ if (DEBUG) {
+ System.out.println("TextureIO.newTextureData(): BufferedImage type for " + file + " = " +
+ img.getType());
+ }
+ return new AWTTextureData(internalFormat, pixelFormat, mipmap, img);
+ }
+
+ public TextureData newTextureData(InputStream stream,
+ int internalFormat,
+ int pixelFormat,
+ boolean mipmap,
+ String fileSuffix) throws IOException {
+ BufferedImage img = ImageIO.read(stream);
+ if (img == null) {
+ return null;
+ }
+ if (DEBUG) {
+ System.out.println("TextureIO.newTextureData(): BufferedImage type for stream = " +
+ img.getType());
+ }
+ return new AWTTextureData(internalFormat, pixelFormat, mipmap, img);
+ }
+
+ public TextureData newTextureData(URL url,
+ int internalFormat,
+ int pixelFormat,
+ boolean mipmap,
+ String fileSuffix) throws IOException {
+ InputStream stream = url.openStream();
+ try {
+ return newTextureData(stream, internalFormat, pixelFormat, mipmap, fileSuffix);
+ } finally {
+ stream.close();
+ }
+ }
+ }
+
+ //----------------------------------------------------------------------
+ // DDS provider -- supports files only for now
+ static class DDSTextureProvider implements TextureProvider {
+ public TextureData newTextureData(File file,
+ int internalFormat,
+ int pixelFormat,
+ boolean mipmap,
+ String fileSuffix) throws IOException {
+ if (TextureUtil.DDS.equals(fileSuffix) ||
+ TextureUtil.DDS.equals(FileUtil.getFileSuffix(file))) {
+ DDSImage image = DDSImage.read(file);
+ return newTextureData(image, internalFormat, pixelFormat, mipmap);
+ }
+
+ return null;
+ }
+
+ public TextureData newTextureData(InputStream stream,
+ int internalFormat,
+ int pixelFormat,
+ boolean mipmap,
+ String fileSuffix) throws IOException {
+ if (TextureUtil.DDS.equals(fileSuffix) ||
+ DDSImage.isDDSImage(stream)) {
+ byte[] data = StreamUtil.readAll(stream);
+ ByteBuffer buf = ByteBuffer.wrap(data);
+ DDSImage image = DDSImage.read(buf);
+ return newTextureData(image, internalFormat, pixelFormat, mipmap);
+ }
+
+ return null;
+ }
+
+ public TextureData newTextureData(URL url,
+ int internalFormat,
+ int pixelFormat,
+ boolean mipmap,
+ String fileSuffix) throws IOException {
+ InputStream stream = new BufferedInputStream(url.openStream());
+ try {
+ return newTextureData(stream, internalFormat, pixelFormat, mipmap, fileSuffix);
+ } finally {
+ stream.close();
+ }
+ }
+
+ private TextureData newTextureData(final DDSImage image,
+ int internalFormat,
+ int pixelFormat,
+ boolean mipmap) {
+ DDSImage.ImageInfo info = image.getMipMap(0);
+ if (pixelFormat == 0) {
+ switch (image.getPixelFormat()) {
+ case DDSImage.D3DFMT_R8G8B8:
+ pixelFormat = GL.GL_RGB;
+ break;
+ default:
+ pixelFormat = GL.GL_RGBA;
+ break;
+ }
+ }
+ if (info.isCompressed()) {
+ switch (info.getCompressionFormat()) {
+ case DDSImage.D3DFMT_DXT1:
+ internalFormat = GL.GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
+ break;
+ case DDSImage.D3DFMT_DXT3:
+ internalFormat = GL.GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
+ break;
+ case DDSImage.D3DFMT_DXT5:
+ internalFormat = GL.GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
+ break;
+ default:
+ throw new RuntimeException("Unsupported DDS compression format \"" +
+ DDSImage.getCompressionFormatName(info.getCompressionFormat()) + "\"");
+ }
+ }
+ if (internalFormat == 0) {
+ switch (image.getPixelFormat()) {
+ case DDSImage.D3DFMT_R8G8B8:
+ pixelFormat = GL.GL_RGB;
+ break;
+ default:
+ pixelFormat = GL.GL_RGBA;
+ break;
+ }
+ }
+ TextureData.Flusher flusher = new TextureData.Flusher() {
+ public void flush() {
+ image.close();
+ }
+ };
+ TextureData data;
+ if (mipmap && image.getNumMipMaps() > 0) {
+ Buffer[] mipmapData = new Buffer[image.getNumMipMaps()];
+ for (int i = 0; i < image.getNumMipMaps(); i++) {
+ mipmapData[i] = image.getMipMap(i).getData();
+ }
+ data = new AWTTextureData(internalFormat,
+ info.getWidth(),
+ info.getHeight(),
+ 0,
+ pixelFormat,
+ GL.GL_UNSIGNED_BYTE,
+ info.isCompressed(),
+ true,
+ mipmapData,
+ flusher);
+ } else {
+ // Fix this up for the end user because we can't generate
+ // mipmaps for compressed textures
+ mipmap = false;
+ data = new AWTTextureData(internalFormat,
+ info.getWidth(),
+ info.getHeight(),
+ 0,
+ pixelFormat,
+ GL.GL_UNSIGNED_BYTE,
+ mipmap,
+ info.isCompressed(),
+ true,
+ info.getData(),
+ flusher);
+ }
+ return data;
+ }
+ }
+
+ //----------------------------------------------------------------------
+ // Base class for SGI RGB and TGA image providers
+ static abstract class StreamBasedTextureProvider implements TextureProvider {
+ public TextureData newTextureData(File file,
+ int internalFormat,
+ int pixelFormat,
+ boolean mipmap,
+ String fileSuffix) throws IOException {
+ InputStream inStream = new BufferedInputStream(new FileInputStream(file));
+ try {
+ // The SGIImage and TGAImage implementations use InputStreams
+ // anyway so there isn't much point in having a separate code
+ // path for files
+ return newTextureData(inStream,
+ internalFormat,
+ pixelFormat,
+ mipmap,
+ ((fileSuffix != null) ? fileSuffix : FileUtil.getFileSuffix(file)));
+ } finally {
+ inStream.close();
+ }
+ }
+
+ public TextureData newTextureData(URL url,
+ int internalFormat,
+ int pixelFormat,
+ boolean mipmap,
+ String fileSuffix) throws IOException {
+ InputStream stream = new BufferedInputStream(url.openStream());
+ try {
+ return newTextureData(stream, internalFormat, pixelFormat, mipmap, fileSuffix);
+ } finally {
+ stream.close();
+ }
+ }
+ }
+
+ //----------------------------------------------------------------------
+ // SGI RGB image provider
+ static class SGITextureProvider extends StreamBasedTextureProvider {
+ public TextureData newTextureData(InputStream stream,
+ int internalFormat,
+ int pixelFormat,
+ boolean mipmap,
+ String fileSuffix) throws IOException {
+ if (TextureUtil.SGI.equals(fileSuffix) ||
+ TextureUtil.SGI_RGB.equals(fileSuffix) ||
+ SGIImage.isSGIImage(stream)) {
+ SGIImage image = SGIImage.read(stream);
+ if (pixelFormat == 0) {
+ pixelFormat = image.getFormat();
+ }
+ if (internalFormat == 0) {
+ internalFormat = image.getFormat();
+ }
+ return new AWTTextureData(internalFormat,
+ image.getWidth(),
+ image.getHeight(),
+ 0,
+ pixelFormat,
+ GL.GL_UNSIGNED_BYTE,
+ mipmap,
+ false,
+ false,
+ ByteBuffer.wrap(image.getData()),
+ null);
+ }
+
+ return null;
+ }
+ }
+
+ //----------------------------------------------------------------------
+ // TGA (Targa) image provider
+ static class TGATextureProvider extends StreamBasedTextureProvider {
+ public TextureData newTextureData(InputStream stream,
+ int internalFormat,
+ int pixelFormat,
+ boolean mipmap,
+ String fileSuffix) throws IOException {
+ if (TextureUtil.TGA.equals(fileSuffix)) {
+ TGAImage image = TGAImage.read(stream);
+ if (pixelFormat == 0) {
+ pixelFormat = image.getGLFormat();
+ }
+ if (internalFormat == 0) {
+ internalFormat = GL.GL_RGBA8;
+ }
+ return new AWTTextureData(internalFormat,
+ image.getWidth(),
+ image.getHeight(),
+ 0,
+ pixelFormat,
+ GL.GL_UNSIGNED_BYTE,
+ mipmap,
+ false,
+ false,
+ image.getData(),
+ null);
+ }
+
+ return null;
+ }
+ }
+ //----------------------------------------------------------------------
+ // Helper routines
+ //
+
+ private static String toLowerCase(String arg) {
+ if (arg == null) {
+ return null;
+ }
+
+ return arg.toLowerCase();
+ }
+}
diff --git a/src/classes/com/sun/opengl/util/texture/awt/AWTTextureWriter.java b/src/classes/com/sun/opengl/util/texture/awt/AWTTextureWriter.java
new file mode 100755
index 000000000..29082c27c
--- /dev/null
+++ b/src/classes/com/sun/opengl/util/texture/awt/AWTTextureWriter.java
@@ -0,0 +1,500 @@
+/*
+ * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.sun.opengl.util.texture.awt;
+
+import java.awt.Graphics;
+import java.awt.image.*;
+import java.io.*;
+import java.net.*;
+import java.nio.*;
+import java.util.*;
+import javax.imageio.*;
+
+import javax.media.opengl.*;
+import javax.media.opengl.glu.*;
+import com.sun.opengl.impl.Debug;
+import com.sun.opengl.util.awt.*;
+import com.sun.opengl.util.io.*;
+import com.sun.opengl.util.texture.*;
+import com.sun.opengl.util.texture.spi.*;
+
+/** <P> Provides input and output facilities for both loading OpenGL
+ textures from disk and streams as well as writing textures already
+ in memory back to disk. </P>
+
+ <P> The TextureIO class supports an arbitrary number of plug-in
+ readers and writers via TextureProviders and TextureWriters.
+ TextureProviders know how to produce TextureData objects from
+ files, InputStreams and URLs. TextureWriters know how to write
+ TextureData objects to disk in various file formats. The
+ TextureData class represents the raw data of the texture before it
+ has been converted to an OpenGL texture object. The Texture class
+ represents the OpenGL texture object and provides easy facilities
+ for using the texture. </P>
+
+ <P> There are several built-in TextureProviders and TextureWriters
+ supplied with the TextureIO implementation. The most basic
+ provider uses the platform's Image I/O facilities to read in a
+ BufferedImage and convert it to a texture. This is the baseline
+ provider and is registered so that it is the last one consulted.
+ All others are asked first to open a given file. </P>
+
+ <P> There are three other providers registered by default as of
+ the time of this writing. One handles SGI RGB (".sgi", ".rgb")
+ images from both files and streams. One handles DirectDraw Surface
+ (".dds") images read from files, though can not read these images
+ from streams. One handles Targa (".tga") images read from both
+ files and streams. These providers are executed in an arbitrary
+ order. Some of these providers require the file's suffix to either
+ be specified via the newTextureData methods or for the file to be
+ named with the appropriate suffix. In general a file suffix should
+ be provided to the newTexture and newTextureData methods if at all
+ possible. </P>
+
+ <P> Note that additional TextureProviders, if reading images from
+ InputStreams, must use the mark()/reset() methods on InputStream
+ when probing for e.g. magic numbers at the head of the file to
+ make sure not to disturb the state of the InputStream for
+ downstream TextureProviders. </P>
+
+ <P> There are analogous TextureWriters provided for writing
+ textures back to disk if desired. As of this writing, there are
+ four TextureWriters registered by default: one for Targa files,
+ one for SGI RGB files, one for DirectDraw surface (.dds) files,
+ and one for ImageIO-supplied formats such as .jpg and .png. Some
+ of these writers have certain limitations such as only being able
+ to write out textures stored in GL_RGB or GL_RGBA format. The DDS
+ writer supports fetching and writing to disk of texture data in
+ DXTn compressed format. Whether this will occur is dependent on
+ whether the texture's internal format is one of the DXTn
+ compressed formats and whether the target file is .dds format.
+*/
+
+public class AWTTextureWriter {
+ private static final boolean DEBUG = Debug.debug("TextureReader");
+
+ //----------------------------------------------------------------------
+ // methods that *do not* require a current context
+ // These methods assume RGB or RGBA textures.
+ // Some texture providers may not recognize the file format unless
+ // the fileSuffix is specified, so it is strongly recommended to
+ // specify it wherever it is known.
+ // Some texture providers may also only support one kind of input,
+ // i.e., reading from a file as opposed to a stream.
+
+ /**
+ * Writes the given texture to a file. The type of the file is
+ * inferred from its suffix. An OpenGL context must be current in
+ * order to fetch the texture data back from the OpenGL pipeline.
+ * This method causes the specified Texture to be bound to the
+ * GL_TEXTURE_2D state. If no suitable writer for the requested file
+ * format was found, throws an IOException. <P>
+ *
+ * Reasonable attempts are made to produce good results in the
+ * resulting images. The Targa, SGI and ImageIO writers produce
+ * results in the correct vertical orientation for those file
+ * formats. The DDS writer performs no vertical flip of the data,
+ * even in uncompressed mode. (It is impossible to perform such a
+ * vertical flip with compressed data.) Applications should keep
+ * this in mind when using this routine to save textures to disk for
+ * later re-loading. <P>
+ *
+ * Any mipmaps for the specified texture are currently discarded
+ * when it is written to disk, regardless of whether the underlying
+ * file format supports multiple mipmaps in a given file.
+ *
+ * @throws IOException if an error occurred during writing or no
+ * suitable writer was found
+ * @throws GLException if no OpenGL context was current or an
+ * OpenGL-related error occurred
+ */
+ public static void write(Texture texture, File file) throws IOException, GLException {
+ if (texture.getTarget() != GL.GL_TEXTURE_2D) {
+ throw new GLException("Only GL_TEXTURE_2D textures are supported");
+ }
+
+ // First fetch the texture data
+ GL _gl = GLU.getCurrentGL();
+ if(!_gl.isGL2()) {
+ throw new GLException("Only GL2 supports fetching compressed images, GL: "+_gl);
+ }
+ GL2 gl = _gl.getGL2();
+
+ texture.bind();
+ int internalFormat = glGetTexLevelParameteri(gl, GL.GL_TEXTURE_2D, 0, GL2.GL_TEXTURE_INTERNAL_FORMAT);
+ int width = glGetTexLevelParameteri(gl, GL.GL_TEXTURE_2D, 0, GL2.GL_TEXTURE_WIDTH);
+ int height = glGetTexLevelParameteri(gl, GL.GL_TEXTURE_2D, 0, GL2.GL_TEXTURE_HEIGHT);
+ int border = glGetTexLevelParameteri(gl, GL.GL_TEXTURE_2D, 0, GL2.GL_TEXTURE_BORDER);
+ TextureData data = null;
+ if (internalFormat == GL.GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
+ internalFormat == GL.GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ||
+ internalFormat == GL.GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ||
+ internalFormat == GL.GL_COMPRESSED_RGBA_S3TC_DXT5_EXT) {
+ // Fetch using glGetCompressedTexImage
+ int size = glGetTexLevelParameteri(gl, GL.GL_TEXTURE_2D, 0, GL2.GL_TEXTURE_COMPRESSED_IMAGE_SIZE);
+ ByteBuffer res = ByteBuffer.allocate(size);
+ gl.glGetCompressedTexImage(GL.GL_TEXTURE_2D, 0, res);
+ data = new AWTTextureData(internalFormat, width, height, border, internalFormat, GL.GL_UNSIGNED_BYTE,
+ false, true, true, res, null);
+ } else {
+ int bytesPerPixel = 0;
+ int fetchedFormat = 0;
+ switch (internalFormat) {
+ case GL.GL_RGB:
+ case GL2.GL_BGR:
+ case GL.GL_RGB8:
+ bytesPerPixel = 3;
+ fetchedFormat = GL.GL_RGB;
+ break;
+ case GL.GL_RGBA:
+ case GL2.GL_BGRA:
+ case GL2.GL_ABGR_EXT:
+ case GL.GL_RGBA8:
+ bytesPerPixel = 4;
+ fetchedFormat = GL.GL_RGBA;
+ break;
+ default:
+ throw new IOException("Unsupported texture internal format 0x" + Integer.toHexString(internalFormat));
+ }
+
+ // Fetch using glGetTexImage
+ int packAlignment = glGetInteger(GL.GL_PACK_ALIGNMENT);
+ int packRowLength = glGetInteger(GL2.GL_PACK_ROW_LENGTH);
+ int packSkipRows = glGetInteger(GL2.GL_PACK_SKIP_ROWS);
+ int packSkipPixels = glGetInteger(GL2.GL_PACK_SKIP_PIXELS);
+ int packSwapBytes = glGetInteger(GL2.GL_PACK_SWAP_BYTES);
+
+ gl.glPixelStorei(GL.GL_PACK_ALIGNMENT, 1);
+ gl.glPixelStorei(GL2.GL_PACK_ROW_LENGTH, 0);
+ gl.glPixelStorei(GL2.GL_PACK_SKIP_ROWS, 0);
+ gl.glPixelStorei(GL2.GL_PACK_SKIP_PIXELS, 0);
+ gl.glPixelStorei(GL2.GL_PACK_SWAP_BYTES, 0);
+
+ ByteBuffer res = ByteBuffer.allocate((width + (2 * border)) *
+ (height + (2 * border)) *
+ bytesPerPixel);
+ if (DEBUG) {
+ System.out.println("Allocated buffer of size " + res.remaining() + " for fetched image (" +
+ ((fetchedFormat == GL.GL_RGB) ? "GL_RGB" : "GL_RGBA") + ")");
+ }
+ gl.glGetTexImage(GL.GL_TEXTURE_2D, 0, fetchedFormat, GL.GL_UNSIGNED_BYTE, res);
+
+ gl.glPixelStorei(GL.GL_PACK_ALIGNMENT, packAlignment);
+ gl.glPixelStorei(GL2.GL_PACK_ROW_LENGTH, packRowLength);
+ gl.glPixelStorei(GL2.GL_PACK_SKIP_ROWS, packSkipRows);
+ gl.glPixelStorei(GL2.GL_PACK_SKIP_PIXELS, packSkipPixels);
+ gl.glPixelStorei(GL2.GL_PACK_SWAP_BYTES, packSwapBytes);
+
+ data = new AWTTextureData(internalFormat, width, height, border, fetchedFormat, GL.GL_UNSIGNED_BYTE,
+ false, false, false, res, null);
+
+ if (DEBUG) {
+ System.out.println("data.getPixelFormat() = " +
+ ((data.getPixelFormat() == GL.GL_RGB) ? "GL_RGB" : "GL_RGBA"));
+ }
+ }
+
+ for (Iterator iter = textureWriters.iterator(); iter.hasNext(); ) {
+ TextureWriter writer = (TextureWriter) iter.next();
+ if (writer.write(file, data)) {
+ return;
+ }
+ }
+
+ throw new IOException("No suitable texture writer found");
+ }
+
+ //----------------------------------------------------------------------
+ // SPI support
+ //
+
+ /** Adds a TextureWriter to support writing of a new file
+ format. */
+ public static void addTextureWriter(TextureWriter writer) {
+ // Must always add at the front so the ImageIO writer is last,
+ // so we don't accidentally use it instead of a user's possibly
+ // more optimal writer
+ textureWriters.add(0, writer);
+ }
+
+ //---------------------------------------------------------------------------
+ // Global disabling of texture rectangle extension
+ //
+
+ //----------------------------------------------------------------------
+ // Internals only below this point
+ //
+
+ private static List/*<TextureWriter>*/ textureWriters = new ArrayList/*<TextureWriter>*/();
+
+ static {
+ // ImageIO writer, the fall-back, must be the first one added
+ textureWriters.add(new IIOTextureWriter());
+
+ // Other special-case writers
+ addTextureWriter(new DDSTextureWriter());
+ addTextureWriter(new SGITextureWriter());
+ addTextureWriter(new TGATextureWriter());
+ }
+
+ //----------------------------------------------------------------------
+ // ImageIO texture writer
+ //
+ static class IIOTextureWriter implements TextureWriter {
+ public boolean write(File file,
+ TextureData data) throws IOException {
+ int pixelFormat = data.getPixelFormat();
+ int pixelType = data.getPixelType();
+ if ((pixelFormat == GL.GL_RGB ||
+ pixelFormat == GL.GL_RGBA) &&
+ (pixelType == GL.GL_BYTE ||
+ pixelType == GL.GL_UNSIGNED_BYTE)) {
+ // Convert TextureData to appropriate BufferedImage
+ // FIXME: almost certainly not obeying correct pixel order
+ BufferedImage image = new BufferedImage(data.getWidth(), data.getHeight(),
+ (pixelFormat == GL.GL_RGB) ?
+ BufferedImage.TYPE_3BYTE_BGR :
+ BufferedImage.TYPE_4BYTE_ABGR);
+ byte[] imageData = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
+ ByteBuffer buf = (ByteBuffer) data.getBuffer();
+ if (buf == null) {
+ buf = (ByteBuffer) data.getMipmapData()[0];
+ }
+ buf.rewind();
+ buf.get(imageData);
+ buf.rewind();
+
+ // Swizzle image components to be correct
+ if (pixelFormat == GL.GL_RGB) {
+ for (int i = 0; i < imageData.length; i += 3) {
+ byte red = imageData[i + 0];
+ byte blue = imageData[i + 2];
+ imageData[i + 0] = blue;
+ imageData[i + 2] = red;
+ }
+ } else {
+ for (int i = 0; i < imageData.length; i += 4) {
+ byte red = imageData[i + 0];
+ byte green = imageData[i + 1];
+ byte blue = imageData[i + 2];
+ byte alpha = imageData[i + 3];
+ imageData[i + 0] = alpha;
+ imageData[i + 1] = blue;
+ imageData[i + 2] = green;
+ imageData[i + 3] = red;
+ }
+ }
+
+ // Flip image vertically for the user's convenience
+ ImageUtil.flipImageVertically(image);
+
+ // Happened to notice that writing RGBA images to JPEGS is broken
+ if (TextureUtil.JPG.equals(FileUtil.getFileSuffix(file)) &&
+ image.getType() == BufferedImage.TYPE_4BYTE_ABGR) {
+ BufferedImage tmpImage = new BufferedImage(image.getWidth(), image.getHeight(),
+ BufferedImage.TYPE_3BYTE_BGR);
+ Graphics g = tmpImage.getGraphics();
+ g.drawImage(image, 0, 0, null);
+ g.dispose();
+ image = tmpImage;
+ }
+
+ return ImageIO.write(image, FileUtil.getFileSuffix(file), file);
+ }
+
+ throw new IOException("ImageIO writer doesn't support this pixel format / type (only GL_RGB/A + bytes)");
+ }
+ }
+
+ //----------------------------------------------------------------------
+ // DDS texture writer
+ //
+ static class DDSTextureWriter implements TextureWriter {
+ public boolean write(File file,
+ TextureData data) throws IOException {
+ if (TextureUtil.DDS.equals(FileUtil.getFileSuffix(file))) {
+ // See whether the DDS writer can handle this TextureData
+ int pixelFormat = data.getPixelFormat();
+ int pixelType = data.getPixelType();
+ if (pixelType != GL.GL_BYTE &&
+ pixelType != GL.GL_UNSIGNED_BYTE) {
+ throw new IOException("DDS writer only supports byte / unsigned byte textures");
+ }
+
+ int d3dFormat = 0;
+ // FIXME: some of these are probably not completely correct and would require swizzling
+ switch (pixelFormat) {
+ case GL.GL_RGB: d3dFormat = DDSImage.D3DFMT_R8G8B8; break;
+ case GL.GL_RGBA: d3dFormat = DDSImage.D3DFMT_A8R8G8B8; break;
+ case GL.GL_COMPRESSED_RGB_S3TC_DXT1_EXT: d3dFormat = DDSImage.D3DFMT_DXT1; break;
+ case GL.GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: throw new IOException("RGBA DXT1 not yet supported");
+ case GL.GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: d3dFormat = DDSImage.D3DFMT_DXT3; break;
+ case GL.GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: d3dFormat = DDSImage.D3DFMT_DXT5; break;
+ default: throw new IOException("Unsupported pixel format 0x" + Integer.toHexString(pixelFormat) + " by DDS writer");
+ }
+
+ ByteBuffer[] mipmaps = null;
+ if (data.getMipmapData() != null) {
+ mipmaps = new ByteBuffer[data.getMipmapData().length];
+ for (int i = 0; i < mipmaps.length; i++) {
+ mipmaps[i] = (ByteBuffer) data.getMipmapData()[i];
+ }
+ } else {
+ mipmaps = new ByteBuffer[] { (ByteBuffer) data.getBuffer() };
+ }
+
+ DDSImage image = DDSImage.createFromData(d3dFormat,
+ data.getWidth(),
+ data.getHeight(),
+ mipmaps);
+ image.write(file);
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ //----------------------------------------------------------------------
+ // SGI (rgb) texture writer
+ //
+ static class SGITextureWriter implements TextureWriter {
+ public boolean write(File file,
+ TextureData data) throws IOException {
+ String fileSuffix = FileUtil.getFileSuffix(file);
+ if (TextureUtil.SGI.equals(fileSuffix) ||
+ TextureUtil.SGI_RGB.equals(fileSuffix)) {
+ // See whether the SGI writer can handle this TextureData
+ int pixelFormat = data.getPixelFormat();
+ int pixelType = data.getPixelType();
+ if ((pixelFormat == GL.GL_RGB ||
+ pixelFormat == GL.GL_RGBA) &&
+ (pixelType == GL.GL_BYTE ||
+ pixelType == GL.GL_UNSIGNED_BYTE)) {
+ ByteBuffer buf = ((data.getBuffer() != null) ?
+ (ByteBuffer) data.getBuffer() :
+ (ByteBuffer) data.getMipmapData()[0]);
+ byte[] bytes;
+ if (buf.hasArray()) {
+ bytes = buf.array();
+ } else {
+ buf.rewind();
+ bytes = new byte[buf.remaining()];
+ buf.get(bytes);
+ buf.rewind();
+ }
+
+ SGIImage image = SGIImage.createFromData(data.getWidth(),
+ data.getHeight(),
+ (pixelFormat == GL.GL_RGBA),
+ bytes);
+ image.write(file, false);
+ return true;
+ }
+
+ throw new IOException("SGI writer doesn't support this pixel format / type (only GL_RGB/A + bytes)");
+ }
+
+ return false;
+ }
+ }
+
+ //----------------------------------------------------------------------
+ // TGA (Targa) texture writer
+
+ static class TGATextureWriter implements TextureWriter {
+ public boolean write(File file,
+ TextureData data) throws IOException {
+ if (TextureUtil.TGA.equals(FileUtil.getFileSuffix(file))) {
+ // See whether the TGA writer can handle this TextureData
+ int pixelFormat = data.getPixelFormat();
+ int pixelType = data.getPixelType();
+ if ((pixelFormat == GL.GL_RGB ||
+ pixelFormat == GL.GL_RGBA) &&
+ (pixelType == GL.GL_BYTE ||
+ pixelType == GL.GL_UNSIGNED_BYTE)) {
+ ByteBuffer buf = ((data.getBuffer() != null) ?
+ (ByteBuffer) data.getBuffer() :
+ (ByteBuffer) data.getMipmapData()[0]);
+ // Must reverse order of red and blue channels to get correct results
+ int skip = ((pixelFormat == GL.GL_RGB) ? 3 : 4);
+ for (int i = 0; i < buf.remaining(); i += skip) {
+ byte red = buf.get(i + 0);
+ byte blue = buf.get(i + 2);
+ buf.put(i + 0, blue);
+ buf.put(i + 2, red);
+ }
+
+ TGAImage image = TGAImage.createFromData(data.getWidth(),
+ data.getHeight(),
+ (pixelFormat == GL.GL_RGBA),
+ false,
+ ((data.getBuffer() != null) ?
+ (ByteBuffer) data.getBuffer() :
+ (ByteBuffer) data.getMipmapData()[0]));
+ image.write(file);
+ return true;
+ }
+
+ throw new IOException("TGA writer doesn't support this pixel format / type (only GL_RGB/A + bytes)");
+ }
+
+ return false;
+ }
+ }
+
+ //----------------------------------------------------------------------
+ // Helper routines
+ //
+
+ private static int glGetInteger(int pname) {
+ int[] tmp = new int[1];
+ GL gl = GLU.getCurrentGL();
+ gl.glGetIntegerv(pname, tmp, 0);
+ return tmp[0];
+ }
+
+ private static int glGetTexLevelParameteri(GL2 gl, int target, int level, int pname) {
+ int[] tmp = new int[1];
+ gl.glGetTexLevelParameteriv(target, 0, pname, tmp, 0);
+ return tmp[0];
+ }
+
+}
diff --git a/src/classes/javax/media/opengl/GLContext.java b/src/classes/javax/media/opengl/GLContext.java
index a70e131c8..02345ef04 100644
--- a/src/classes/javax/media/opengl/GLContext.java
+++ b/src/classes/javax/media/opengl/GLContext.java
@@ -187,4 +187,10 @@ public abstract class GLContext {
* Sets the GL pipeline object for this GLContext.
*/
public abstract void setGL(GL gl);
+
+ public final String toString() {
+ return "GLContext: "+getClass().getName()+
+ "(GL: "+getGL().getClass().getName()+","+
+ " Factory: "+ getGLDrawable().getFactory().getClass().getName()+")";
+ }
}
diff --git a/src/classes/javax/media/opengl/GLDrawable.java b/src/classes/javax/media/opengl/GLDrawable.java
index c7f0ef803..e99764af7 100644
--- a/src/classes/javax/media/opengl/GLDrawable.java
+++ b/src/classes/javax/media/opengl/GLDrawable.java
@@ -134,12 +134,21 @@ public interface GLDrawable {
currently created or if its pixel format has not been set yet.
On some platforms, the pixel format is not directly associated
with the drawable; a best attempt is made to return a reasonable
- value in this case. */
+ value in this case.
+ Returns a copy of the passed object.
+ */
public GLCapabilities getChosenGLCapabilities();
- public NativeWindow getNativeWindow();
+ /**
+ * stores a copy of the passed object
+ */
+ public void setChosenGLCapabilities(GLCapabilities caps);
- public String getProfile();
+ public NativeWindow getNativeWindow();
public GLDrawableFactory getFactory();
+
+ public int lockSurface() throws GLException;
+ public void unlockSurface();
+ public boolean isSurfaceLocked();
}
diff --git a/src/classes/javax/media/opengl/GLDrawableFactory.java b/src/classes/javax/media/opengl/GLDrawableFactory.java
index 2c48e3ceb..8177f2924 100644
--- a/src/classes/javax/media/opengl/GLDrawableFactory.java
+++ b/src/classes/javax/media/opengl/GLDrawableFactory.java
@@ -80,38 +80,30 @@ public abstract class GLDrawableFactory {
private static GLDrawableFactory awtFactory;
private static GLDrawableFactory nwFactory;
- /** The desktop (OpenGL 2.0) profile */
- public static final String PROFILE_GL_20 = "GL20";
-
- /** The OpenGL ES 1 (really, 1.1) profile */
- public static final String PROFILE_GLES1 = "GLES1";
-
- /** The OpenGL ES 2 (really, 2.0) profile */
- public static final String PROFILE_GLES2 = "GLES2";
-
- private String profile;
-
/** Initializes the sole GLDrawableFactory instance for the given profile. */
- public static void initializeAWTFactory(String profile) throws GLException {
+ private static void initializeAWTFactory() throws GLException {
if (awtFactory != null) {
return;
}
// See if the user is requesting one of the embedded profiles,
// and if so, try to instantiate the EGLDrawableFactory
- if (PROFILE_GLES1.equals(profile) ||
- PROFILE_GLES2.equals(profile)) {
+ if (GLProfile.isGLES()) {
try {
Class clazz = Class.forName("com.sun.opengl.impl.egl.awt.EGLDrawableFactory");
+ /**
Constructor c = clazz.getDeclaredConstructor(new Class[] { String.class });
- awtFactory = (GLDrawableFactory) c.newInstance(new Object[] { profile });
+ awtFactory = (GLDrawableFactory) c.newInstance(new Object[] { GLProfile.getProfile() });
+ */
+ Constructor c = clazz.getDeclaredConstructor(new Class[0]);
+ awtFactory = (GLDrawableFactory) c.newInstance(null);
return;
} catch (Exception e) {
e.printStackTrace();
}
- } else if (!PROFILE_GL_20.equals(profile)) {
+ } else if (!GLProfile.isGL2()) {
// We require that the user passes in one of the known profiles
- throw new GLException("Unknown or unsupported profile \"" + profile + "\"");
+ throw new GLException("Unknown or unsupported profile \"" + GLProfile.getProfile() + "\"");
}
// Use the desktop OpenGL as the fallback always
@@ -135,46 +127,53 @@ public abstract class GLDrawableFactory {
if (factoryClassName != null) {
factoryClass = Class.forName(factoryClassName);
} else if (osNameLowerCase.startsWith("wind")) {
- factoryClass = Class.forName("com.sun.opengl.impl.windows.awt.WindowsAWTGLDrawableFactory");
+ factoryClass = Class.forName("com.sun.opengl.impl.windows.wgl.WindowsWGLDrawableFactory");
} else if (osNameLowerCase.startsWith("mac os x")) {
- factoryClass = Class.forName("com.sun.opengl.impl.macosx.awt.MacOSXAWTGLDrawableFactory");
+ factoryClass = Class.forName("com.sun.opengl.impl.macosx.cgl.awt.MacOSXAWTCGLDrawableFactory");
} else {
// Assume Linux, Solaris, etc. Should probably test for these explicitly.
- factoryClass = Class.forName("com.sun.opengl.impl.x11.awt.X11AWTGLDrawableFactory");
+ factoryClass = Class.forName("com.sun.opengl.impl.x11.glx.awt.X11AWTGLXDrawableFactory");
}
if (factoryClass == null) {
throw new GLException("OS " + osName + " not yet supported");
}
+ /**
Constructor c = factoryClass.getDeclaredConstructor(new Class[] { String.class });
- awtFactory = (GLDrawableFactory) c.newInstance(new Object[] { profile });
+ awtFactory = (GLDrawableFactory) c.newInstance(new Object[] { GLProfile.getProfile() });
+ */
+ Constructor c = factoryClass.getDeclaredConstructor(new Class[0]);
+ awtFactory = (GLDrawableFactory) c.newInstance(null);
} catch (Exception e) {
throw new GLException(e);
}
}
/** Initializes the sole GLDrawableFactory instance for the given profile. */
- public static void initializeNWFactory(String profile) throws GLException {
+ private static void initializeNWFactory() throws GLException {
if (nwFactory != null) {
return;
}
// See if the user is requesting one of the embedded profiles,
// and if so, try to instantiate the EGLDrawableFactory
- if (PROFILE_GLES1.equals(profile) ||
- PROFILE_GLES2.equals(profile)) {
+ if (GLProfile.isGLES()) {
try {
Class clazz = Class.forName("com.sun.opengl.impl.egl.EGLDrawableFactory");
+ /**
Constructor c = clazz.getDeclaredConstructor(new Class[] { String.class });
- nwFactory = (GLDrawableFactory) c.newInstance(new Object[] { profile });
+ nwFactory = (GLDrawableFactory) c.newInstance(new Object[] { GLProfile.getProfile() });
+ */
+ Constructor c = clazz.getDeclaredConstructor(new Class[0]);
+ nwFactory = (GLDrawableFactory) c.newInstance(null);
return;
} catch (Exception e) {
e.printStackTrace();
}
- } else if (!PROFILE_GL_20.equals(profile)) {
+ } else if (!GLProfile.isGL2()) {
// We require that the user passes in one of the known profiles
- throw new GLException("Unknown or unsupported profile \"" + profile + "\"");
+ throw new GLException("Unknown or unsupported profile \"" + GLProfile.getProfile() + "\"");
}
// Use the desktop OpenGL as the fallback always
@@ -192,20 +191,24 @@ public abstract class GLDrawableFactory {
if (factoryClassName != null) {
factoryClass = Class.forName(factoryClassName);
} else if (osNameLowerCase.startsWith("wind")) {
- factoryClass = Class.forName("com.sun.opengl.impl.windows.WindowsGLDrawableFactory");
+ factoryClass = Class.forName("com.sun.opengl.impl.windows.wgl.WindowsWGLDrawableFactory");
} else if (osNameLowerCase.startsWith("mac os x")) {
- factoryClass = Class.forName("com.sun.opengl.impl.macosx.MacOSXGLDrawableFactory");
+ factoryClass = Class.forName("com.sun.opengl.impl.macosx.cgl.MacOSXCGLDrawableFactory");
} else {
// Assume Linux, Solaris, etc. Should probably test for these explicitly.
- factoryClass = Class.forName("com.sun.opengl.impl.x11.X11GLDrawableFactory");
+ factoryClass = Class.forName("com.sun.opengl.impl.x11.glx.X11GLXDrawableFactory");
}
if (factoryClass == null) {
throw new GLException("OS " + osName + " not yet supported");
}
+ /**
Constructor c = factoryClass.getDeclaredConstructor(new Class[] { String.class });
- nwFactory = (GLDrawableFactory) c.newInstance(new Object[] { profile });
+ nwFactory = (GLDrawableFactory) c.newInstance(new Object[] { GLProfile.getProfile() });
+ */
+ Constructor c = factoryClass.getDeclaredConstructor(new Class[0]);
+ nwFactory = (GLDrawableFactory) c.newInstance(null);
return;
} catch (Exception e) {
throw new GLException(e);
@@ -214,34 +217,54 @@ public abstract class GLDrawableFactory {
/** Creates a new GLDrawableFactory instance. End users do not need
to call this method. */
- protected GLDrawableFactory(String profile) {
- this.profile = profile;
+ protected GLDrawableFactory() {
}
/** Returns the sole GLDrawableFactory instance for the specified profile. */
- public static GLDrawableFactory getFactory(String profile, Object target) {
+ public static GLDrawableFactory getFactory(String profile, Object target)
+ throws GLException
+ {
+ GLProfile.setProfile(profile);
+ return getFactory(target);
+ }
+
+ public static GLDrawableFactory getFactory(Object target)
+ throws GLException
+ {
if(null==target) {
throw new IllegalArgumentException("target is null");
}
if(target instanceof NativeWindow) {
- return getFactory(profile, false);
+ return getFactory(false);
} else if (NativeWindowFactory.isAWTComponent(target)) {
- return getFactory(profile, true);
+ return getFactory(true);
}
throw new IllegalArgumentException("Target type is unsupported. Currently supported: \n"+
"\tjavax.media.opengl.NativeWindow\n"+
"\tjava.awt.Component\n");
}
- public static GLDrawableFactory getFactory(String profile, boolean awt) {
+ public static GLDrawableFactory getFactory(String profile, boolean awt)
+ throws GLException
+ {
+ GLProfile.setProfile(profile);
+ return getFactory(awt);
+ }
+
+ public static GLDrawableFactory getFactory(boolean awt)
+ throws GLException
+ {
+ if(null==GLProfile.getProfile()) {
+ throw new GLException("No choosen/preset profile");
+ }
if(awt) {
- initializeAWTFactory(profile);
+ initializeAWTFactory();
if(awtFactory == null) {
throw new GLException("Could not determine the AWT-GLDrawableFactory");
}
return awtFactory;
} else {
- initializeNWFactory(profile);
+ initializeNWFactory();
if(nwFactory == null) {
throw new GLException("Could not determine the NativeWindow-GLDrawableFactory");
}
@@ -249,11 +272,6 @@ public abstract class GLDrawableFactory {
}
}
- /** Indicates which profile this GLDrawableFactory was created for. */
- public String getProfile() {
- return profile;
- }
-
/** Shuts down this GLDrawableFactory, releasing resources
associated with it. Before calling this method you should first
destroy any GLContexts and GLDrawables that have been created
@@ -262,6 +280,25 @@ public abstract class GLDrawableFactory {
public void shutdown() {
}
+ public void lockToolkit() throws GLException {
+ if(lockedToolkit) {
+ throw new GLException("Toolkit already locked");
+ }
+ lockedToolkit=true;
+ }
+
+ public void unlockToolkit() {
+ if(lockedToolkit) {
+ lockedToolkit=false;
+ }
+ }
+
+ public boolean isToolkitLocked() {
+ return lockedToolkit;
+ }
+
+ protected static boolean lockedToolkit = false;
+
/**
* <P> Selects a graphics configuration on the specified graphics
* device compatible with the supplied GLCapabilities. This method
@@ -411,4 +448,5 @@ public abstract class GLDrawableFactory {
*/
public abstract GLDrawable createExternalGLDrawable()
throws GLException;
+
}
diff --git a/src/classes/javax/media/opengl/NativeWindow.java b/src/classes/javax/media/opengl/NativeWindow.java
index a93037bee..688c4c374 100644
--- a/src/classes/javax/media/opengl/NativeWindow.java
+++ b/src/classes/javax/media/opengl/NativeWindow.java
@@ -40,19 +40,40 @@
package javax.media.opengl;
public interface NativeWindow {
+ public static final int LOCK_NOT_SUPPORTED = 0;
public static final int LOCK_SURFACE_NOT_READY = 1;
public static final int LOCK_SURFACE_CHANGED = 2;
public static final int LOCK_SUCCESS = 3;
- public boolean lockSurface() throws NativeWindowException ;
+ /**
+ * Lock this surface
+ */
+ public int lockSurface() throws NativeWindowException ;
+
+ /**
+ * Unlock this surface
+ */
public void unlockSurface();
public boolean isSurfaceLocked();
+ /**
+ * render all native window information invalid,
+ * as if the native window was destroyed
+ */
+ public void invalidate();
+
+ /**
+ * Lifetime: locked state
+ */
public long getDisplayHandle();
public long getScreenHandle();
- public int getScreenIndex();
public long getWindowHandle();
- public int getVisualID();
+
+ /**
+ * Lifetime: after 1st lock, until invalidation
+ */
+ public long getVisualID();
+ public int getScreenIndex();
public void setSize(int width, int height);
public void setPosition(int x, int y);
diff --git a/src/classes/javax/media/opengl/NativeWindowFactory.java b/src/classes/javax/media/opengl/NativeWindowFactory.java
index c206adb78..cdd850322 100644
--- a/src/classes/javax/media/opengl/NativeWindowFactory.java
+++ b/src/classes/javax/media/opengl/NativeWindowFactory.java
@@ -95,14 +95,7 @@ public class NativeWindowFactory {
* hence the independency to the java.awt.* package.
*/
public static boolean isAWTComponent(Object target) {
- Class clazz = target.getClass();
- do {
- if(clazz.getName().equals("java.awt.Component")) {
- return true;
- }
- clazz = clazz.getSuperclass();
- } while (clazz!=null);
- return false;
+ return GLProfile.instanceOf(target, "java.awt.Component");
}
/**
diff --git a/src/classes/javax/media/opengl/Threading.java b/src/classes/javax/media/opengl/Threading.java
index f14912a3c..763389aca 100755
--- a/src/classes/javax/media/opengl/Threading.java
+++ b/src/classes/javax/media/opengl/Threading.java
@@ -313,7 +313,7 @@ public class Threading {
/** This is a workaround for AWT-related deadlocks which only seem
to show up in the context of applets */
- static boolean isAWTMode() {
+ public static boolean isAWTMode() {
return (mode == AWT);
}
diff --git a/src/classes/javax/media/opengl/awt/GLCanvas.java b/src/classes/javax/media/opengl/awt/GLCanvas.java
index 8b52c6da4..d002b58de 100644
--- a/src/classes/javax/media/opengl/awt/GLCanvas.java
+++ b/src/classes/javax/media/opengl/awt/GLCanvas.java
@@ -107,8 +107,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable {
which to create the GLCanvas; the GLDrawableFactory uses the
default screen device of the local GraphicsEnvironment if null
is passed for this argument. */
- public GLCanvas(String profile,
- GLCapabilities capabilities,
+ public GLCanvas(GLCapabilities capabilities,
GLCapabilitiesChooser chooser,
GLContext shareWith,
GraphicsDevice device) {
@@ -142,8 +141,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable {
this.glCaps = capabilities;
}
if (!Beans.isDesignTime()) {
- drawable = GLDrawableFactory.getFactory(profile, true).createGLDrawable(profile,
- NativeWindowFactory.getNativeWindow(this),
+ drawable = GLDrawableFactory.getFactory(true).createGLDrawable(NativeWindowFactory.getNativeWindow(this),
capabilities, chooser);
context = (GLContextImpl) drawable.createContext(shareWith);
context.setSynchronized(true);
@@ -404,6 +402,34 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable {
return drawable.getChosenGLCapabilities();
}
+ public void setChosenGLCapabilities(GLCapabilities caps) {
+ drawable.setChosenGLCapabilities(caps);
+ }
+
+ public NativeWindow getNativeWindow() {
+ return drawable.getNativeWindow();
+ }
+
+ public GLDrawableFactory getFactory() {
+ return drawable.getFactory();
+ }
+
+ public int lockSurface() throws GLException {
+ return drawable.lockSurface();
+ }
+
+ public void unlockSurface() {
+ drawable.unlockSurface();
+ }
+
+ public boolean isSurfaceLocked() {
+ return drawable.isSurfaceLocked();
+ }
+
+ public void destroy() {
+ drawable.destroy();
+ }
+
//----------------------------------------------------------------------
// Internals only below this point
//
@@ -523,7 +549,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable {
}
AWTGraphicsConfiguration config = (AWTGraphicsConfiguration)
- GLDrawableFactory.getFactory().chooseGraphicsConfiguration(capabilities,
+ GLDrawableFactory.getFactory(true).chooseGraphicsConfiguration(capabilities,
chooser,
new AWTGraphicsDevice(device));
if (config == null) {
diff --git a/src/classes/javax/media/opengl/awt/GLJPanel.java b/src/classes/javax/media/opengl/awt/GLJPanel.java
deleted file mode 100644
index 4c1df74da..000000000
--- a/src/classes/javax/media/opengl/awt/GLJPanel.java
+++ /dev/null
@@ -1,1270 +0,0 @@
-/*
- * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * - Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any kind. ALL
- * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
- * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
- * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
- * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
- * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
- * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
- * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
- * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
- * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
- * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
- * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
- * You acknowledge that this software is not designed or intended for use
- * in the design, construction, operation or maintenance of any nuclear
- * facility.
- *
- * Sun gratefully acknowledges that this software was originally authored
- * and developed by Kenneth Bradley Russell and Christopher John Kline.
- */
-
-package javax.media.opengl.awt;
-
-import javax.media.opengl.*;
-
-import java.awt.*;
-import java.awt.geom.*;
-import java.awt.image.*;
-import java.beans.*;
-import javax.swing.*;
-import java.nio.*;
-import java.security.*;
-import javax.swing.JComponent;
-import javax.swing.JPanel;
-import com.sun.opengl.impl.*;
-
-// FIXME: Subclasses need to call resetGLFunctionAvailability() on their
-// context whenever the displayChanged() function is called on their
-// GLEventListeners
-
-/** A lightweight Swing component which provides OpenGL rendering
- support. Provided for compatibility with Swing user interfaces
- when adding a heavyweight doesn't work either because of
- Z-ordering or LayoutManager problems. <P>
-
- The GLJPanel can be made transparent by creating it with a
- GLCapabilities object with alpha bits specified and calling {@link
- #setOpaque}(false). Pixels with resulting OpenGL alpha values less
- than 1.0 will be overlaid on any underlying Swing rendering. <P>
-
- Notes specific to the Reference Implementation: This component
- attempts to use hardware-accelerated rendering via pbuffers and
- falls back on to software rendering if problems occur.
- Note that because this component attempts to use pbuffers for
- rendering, and because pbuffers can not be resized, somewhat
- surprising behavior may occur during resize operations; the {@link
- GLEventListener#init} method may be called multiple times as the
- pbuffer is resized to be able to cover the size of the GLJPanel.
- This behavior is correct, as the textures and display lists for
- the GLJPanel will have been lost during the resize operation. The
- application should attempt to make its GLEventListener.init()
- methods as side-effect-free as possible. <P>
-
-*/
-
-public class GLJPanel extends JPanel implements AWTGLAutoDrawable {
- private static final boolean DEBUG = Debug.debug("GLJPanel");
- private static final boolean VERBOSE = Debug.verbose();
-
- private GLDrawableHelper drawableHelper = new GLDrawableHelper();
- private volatile boolean isInitialized;
- private volatile boolean shouldInitialize = false;
-
- // Data used for either pbuffers or pixmap-based offscreen surfaces
- private GLCapabilities offscreenCaps;
- private GLCapabilitiesChooser chooser;
- private GLContext shareWith;
- // This image is exactly the correct size to render into the panel
- private BufferedImage offscreenImage;
- // One of these is used to store the read back pixels before storing
- // in the BufferedImage
- private ByteBuffer readBackBytes;
- private IntBuffer readBackInts;
- private int readBackWidthInPixels;
- private int readBackHeightInPixels;
- // Width of the actual GLJPanel
- private int panelWidth = 0;
- private int panelHeight = 0;
- private Updater updater;
- private int awtFormat;
- private int glFormat;
- private int glType;
- // Lazy reshape notification
- private boolean handleReshape = false;
- private boolean sendReshape = true;
-
- // Implementation using pbuffers
- private static boolean hardwareAccelerationDisabled =
- Debug.isPropertyDefined("jogl.gljpanel.nohw");
- private static boolean softwareRenderingDisabled =
- Debug.isPropertyDefined("jogl.gljpanel.nosw");
- private GLPbuffer pbuffer;
- private int pbufferWidth = 256;
- private int pbufferHeight = 256;
-
- // Implementation using software rendering
- private GLDrawableImpl offscreenDrawable;
- private GLContextImpl offscreenContext;
-
- // For handling reshape events lazily
- private int reshapeX;
- private int reshapeY;
- private int reshapeWidth;
- private int reshapeHeight;
-
- // For saving/restoring of OpenGL state during ReadPixels
- private int[] swapbytes = new int[1];
- private int[] rowlength = new int[1];
- private int[] skiprows = new int[1];
- private int[] skippixels = new int[1];
- private int[] alignment = new int[1];
-
- // Implementation using Java2D OpenGL pipeline's back buffer
- private boolean oglPipelineEnabled =
- Java2D.isOGLPipelineActive() &&
- !Debug.isPropertyDefined("jogl.gljpanel.noogl");
- // Opaque Object identifier representing the Java2D surface we are
- // drawing to; used to determine when to destroy and recreate JOGL
- // context
- private Object j2dSurface;
- // Graphics object being used during Java2D update action
- // (absolutely essential to cache this)
- private Graphics cached2DGraphics;
- // No-op context representing the Java2D OpenGL context
- private GLContext j2dContext;
- // Context associated with no-op drawable representing the JOGL
- // OpenGL context
- private GLDrawable joglDrawable;
- // The real OpenGL context JOGL uses to render
- private GLContext joglContext;
- // State captured from Java2D OpenGL context necessary in order to
- // properly render into Java2D back buffer
- private int[] drawBuffer = new int[1];
- private int[] readBuffer = new int[1];
- // This is required when the FBO option of the Java2D / OpenGL
- // pipeline is active
- private int[] frameBuffer = new int[1];
- // Current (as of this writing) NVidia drivers have a couple of bugs
- // relating to the sharing of framebuffer and renderbuffer objects
- // between contexts. It appears we have to (a) reattach the color
- // attachment and (b) actually create new depth buffer storage and
- // attach it in order for the FBO to behave properly in our context.
- private boolean checkedForFBObjectWorkarounds;
- private boolean fbObjectWorkarounds;
- private int[] frameBufferDepthBuffer;
- private int[] frameBufferTexture;
- private boolean createNewDepthBuffer;
- // Current (as of this writing) ATI drivers have problems when the
- // same FBO is bound in two different contexts. Here we check for
- // this case and explicitly release the FBO from Java2D's context
- // before switching to ours. Java2D will re-bind the FBO when it
- // makes its context current the next time. Interestingly, if we run
- // this code path on NVidia hardware, it breaks the rendering
- // results -- no output is generated. This doesn't appear to be an
- // interaction with the abovementioned NVidia-specific workarounds,
- // as even if we disable that code the FBO is still reported as
- // incomplete in our context.
- private boolean checkedGLVendor;
- private boolean vendorIsATI;
-
- // Holding on to this GraphicsConfiguration is a workaround for a
- // problem in the Java 2D / JOGL bridge when FBOs are enabled; see
- // comment related to Issue 274 below
- private GraphicsConfiguration workaroundConfig;
-
- // These are always set to (0, 0) except when the Java2D / OpenGL
- // pipeline is active
- private int viewportX;
- private int viewportY;
-
- static {
- // Force eager initialization of part of the Java2D class since
- // otherwise it's likely it will try to be initialized while on
- // the Queue Flusher Thread, which is not allowed
- if (Java2D.isOGLPipelineActive() && Java2D.isFBOEnabled()) {
- Java2D.getShareContext(GraphicsEnvironment.
- getLocalGraphicsEnvironment().
- getDefaultScreenDevice().
- getDefaultConfiguration());
- }
- }
-
- /** Creates a new GLJPanel component with a default set of OpenGL
- capabilities and using the default OpenGL capabilities selection
- mechanism. */
- public GLJPanel() {
- this(null);
- }
-
- /** Creates a new GLJPanel component with the requested set of
- OpenGL capabilities, using the default OpenGL capabilities
- selection mechanism. */
- public GLJPanel(GLCapabilities capabilities) {
- this(capabilities, null, null);
- }
-
- /** Creates a new GLJPanel component. The passed GLCapabilities
- specifies the OpenGL capabilities for the component; if null, a
- default set of capabilities is used. The GLCapabilitiesChooser
- specifies the algorithm for selecting one of the available
- GLCapabilities for the component; a DefaultGLCapabilitesChooser
- is used if null is passed for this argument. The passed
- GLContext specifies an OpenGL context with which to share
- textures, display lists and other OpenGL state, and may be null
- if sharing is not desired. See the note in the overview documentation on
- <a href="../../../overview-summary.html#SHARING">context sharing</a>.
- */
- public GLJPanel(GLCapabilities capabilities, GLCapabilitiesChooser chooser, GLContext shareWith) {
- super();
-
- // Works around problems on many vendors' cards; we don't need a
- // back buffer for the offscreen surface anyway
- if (capabilities != null) {
- offscreenCaps = (GLCapabilities) capabilities.clone();
- } else {
- offscreenCaps = new GLCapabilities();
- }
- offscreenCaps.setDoubleBuffered(false);
- this.chooser = ((chooser != null) ? chooser : new DefaultGLCapabilitiesChooser());
- this.shareWith = shareWith;
- }
-
- public void display() {
- if (EventQueue.isDispatchThread()) {
- // Want display() to be synchronous, so call paintImmediately()
- paintImmediately(0, 0, getWidth(), getHeight());
- } else {
- // Multithreaded redrawing of Swing components is not allowed,
- // so do everything on the event dispatch thread
- try {
- EventQueue.invokeAndWait(paintImmediatelyAction);
- } catch (Exception e) {
- throw new GLException(e);
- }
- }
- }
-
- private void captureJ2DState(GL gl, Graphics g) {
- gl.glGetIntegerv(GL.GL_DRAW_BUFFER, drawBuffer, 0);
- gl.glGetIntegerv(GL.GL_READ_BUFFER, readBuffer, 0);
- if (Java2D.isFBOEnabled() &&
- Java2D.getOGLSurfaceType(g) == Java2D.FBOBJECT) {
- if (DEBUG && VERBOSE) {
- System.err.println("GLJPanel: Fetching GL_FRAMEBUFFER_BINDING_EXT");
- }
- gl.glGetIntegerv(GL.GL_FRAMEBUFFER_BINDING_EXT, frameBuffer, 0);
-
- if (fbObjectWorkarounds ||
- !checkedForFBObjectWorkarounds) {
- // See above for description of what we are doing here
- if (frameBufferTexture == null)
- frameBufferTexture = new int[1];
-
- // Query the framebuffer for its color buffer so we can hook
- // it back up in our context (should not be necessary)
- gl.glGetFramebufferAttachmentParameterivEXT(GL.GL_FRAMEBUFFER_EXT,
- GL.GL_COLOR_ATTACHMENT0_EXT,
- GL.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT,
- frameBufferTexture, 0);
- if (DEBUG && VERBOSE) {
- System.err.println("GLJPanel: FBO COLOR_ATTACHMENT0: " + frameBufferTexture[0]);
- }
- }
-
- if (!checkedGLVendor) {
- checkedGLVendor = true;
- String vendor = gl.glGetString(GL.GL_VENDOR);
-
- if ((vendor != null) &&
- vendor.startsWith("ATI")) {
- vendorIsATI = true;
- }
- }
-
- if (vendorIsATI) {
- // Unbind the FBO from Java2D's context as it appears that
- // driver bugs on ATI's side are causing problems if the FBO is
- // simultaneously bound to more than one context. Java2D will
- // re-bind the FBO during the next validation of its context.
- // Note: this breaks rendering at least on NVidia hardware
- gl.glBindFramebufferEXT(GL.GL_FRAMEBUFFER_EXT, 0);
- }
- }
- }
-
- private boolean preGL(Graphics g) {
- GL gl = joglContext.getGL();
- // Set up needed state in JOGL context from Java2D context
- gl.glEnable(GL.GL_SCISSOR_TEST);
- Rectangle r = Java2D.getOGLScissorBox(g);
-
- if (r == null) {
- if (DEBUG && VERBOSE) {
- System.err.println("Java2D.getOGLScissorBox() returned null");
- }
- return false;
- }
- if (DEBUG && VERBOSE) {
- System.err.println("GLJPanel: gl.glScissor(" + r.x + ", " + r.y + ", " + r.width + ", " + r.height + ")");
- }
-
- gl.glScissor(r.x, r.y, r.width, r.height);
- Rectangle oglViewport = Java2D.getOGLViewport(g, panelWidth, panelHeight);
- // If the viewport X or Y changes, in addition to the panel's
- // width or height, we need to send a reshape operation to the
- // client
- if ((viewportX != oglViewport.x) ||
- (viewportY != oglViewport.y)) {
- sendReshape = true;
- if (DEBUG) {
- System.err.println("Sending reshape because viewport changed");
- System.err.println(" viewportX (" + viewportX + ") ?= oglViewport.x (" + oglViewport.x + ")");
- System.err.println(" viewportY (" + viewportY + ") ?= oglViewport.y (" + oglViewport.y + ")");
- }
- }
- viewportX = oglViewport.x;
- viewportY = oglViewport.y;
-
- // If the FBO option is active, bind to the FBO from the Java2D
- // context.
- // Note that all of the plumbing in the context sharing stuff will
- // allow us to bind to this object since it's in our namespace.
- if (Java2D.isFBOEnabled() &&
- Java2D.getOGLSurfaceType(g) == Java2D.FBOBJECT) {
- if (DEBUG && VERBOSE) {
- System.err.println("GLJPanel: Binding to framebuffer object " + frameBuffer[0]);
- }
-
- // The texture target for Java2D's OpenGL pipeline when using FBOs
- // -- either GL_TEXTURE_2D or GL_TEXTURE_RECTANGLE_ARB
- int fboTextureTarget = Java2D.getOGLTextureType(g);
-
- if (!checkedForFBObjectWorkarounds) {
- checkedForFBObjectWorkarounds = true;
- gl.glBindTexture(fboTextureTarget, 0);
- gl.glBindFramebufferEXT(GL.GL_FRAMEBUFFER_EXT, frameBuffer[0]);
- if (gl.glCheckFramebufferStatusEXT(GL.GL_FRAMEBUFFER_EXT) !=
- GL.GL_FRAMEBUFFER_COMPLETE_EXT) {
- // Need to do workarounds
- fbObjectWorkarounds = true;
- createNewDepthBuffer = true;
- if (DEBUG) {
- System.err.println("-- GLJPanel: discovered frame_buffer_object workarounds to be necessary");
- }
- } else {
- // Don't need the frameBufferTexture temporary any more
- frameBufferTexture = null;
- }
- }
-
- if (fbObjectWorkarounds && createNewDepthBuffer) {
- if (frameBufferDepthBuffer == null)
- frameBufferDepthBuffer = new int[1];
-
- // Create our own depth renderbuffer and associated storage
- // If we have an old one, delete it
- if (frameBufferDepthBuffer[0] != 0) {
- gl.glDeleteRenderbuffersEXT(1, frameBufferDepthBuffer, 0);
- frameBufferDepthBuffer[0] = 0;
- }
-
- gl.glBindTexture(fboTextureTarget, frameBufferTexture[0]);
- int[] width = new int[1];
- int[] height = new int[1];
- gl.glGetTexLevelParameteriv(fboTextureTarget, 0, GL.GL_TEXTURE_WIDTH, width, 0);
- gl.glGetTexLevelParameteriv(fboTextureTarget, 0, GL.GL_TEXTURE_HEIGHT, height, 0);
-
- gl.glGenRenderbuffersEXT(1, frameBufferDepthBuffer, 0);
- if (DEBUG) {
- System.err.println("GLJPanel: Generated frameBufferDepthBuffer " + frameBufferDepthBuffer[0] +
- " with width " + width[0] + ", height " + height[0]);
- }
-
- gl.glBindRenderbufferEXT(GL.GL_RENDERBUFFER_EXT, frameBufferDepthBuffer[0]);
- // FIXME: may need a loop here like in Java2D
- gl.glRenderbufferStorageEXT(GL.GL_RENDERBUFFER_EXT, GL.GL_DEPTH_COMPONENT24, width[0], height[0]);
-
- gl.glBindRenderbufferEXT(GL.GL_RENDERBUFFER_EXT, 0);
- createNewDepthBuffer = false;
- }
-
- gl.glBindTexture(fboTextureTarget, 0);
- gl.glBindFramebufferEXT(GL.GL_FRAMEBUFFER_EXT, frameBuffer[0]);
-
- if (fbObjectWorkarounds) {
- // Hook up the color and depth buffer attachment points for this framebuffer
- gl.glFramebufferTexture2DEXT(GL.GL_FRAMEBUFFER_EXT,
- GL.GL_COLOR_ATTACHMENT0_EXT,
- fboTextureTarget,
- frameBufferTexture[0],
- 0);
- if (DEBUG && VERBOSE) {
- System.err.println("GLJPanel: frameBufferDepthBuffer: " + frameBufferDepthBuffer[0]);
- }
- gl.glFramebufferRenderbufferEXT(GL.GL_FRAMEBUFFER_EXT,
- GL.GL_DEPTH_ATTACHMENT_EXT,
- GL.GL_RENDERBUFFER_EXT,
- frameBufferDepthBuffer[0]);
- }
-
- if (DEBUG) {
- int status = gl.glCheckFramebufferStatusEXT(GL.GL_FRAMEBUFFER_EXT);
- if (status != GL.GL_FRAMEBUFFER_COMPLETE_EXT) {
- throw new GLException("Error: framebuffer was incomplete: status = 0x" +
- Integer.toHexString(status));
- }
- }
- } else {
- if (DEBUG && VERBOSE) {
- System.err.println("GLJPanel: Setting up drawBuffer " + drawBuffer[0] +
- " and readBuffer " + readBuffer[0]);
- }
-
- gl.glDrawBuffer(drawBuffer[0]);
- gl.glReadBuffer(readBuffer[0]);
- }
-
- return true;
- }
-
- private void postGL(Graphics g) {
- if (Java2D.isFBOEnabled() &&
- Java2D.getOGLSurfaceType(g) == Java2D.FBOBJECT) {
- // Unbind the framebuffer from our context to work around
- // apparent driver bugs or at least unspecified behavior causing
- // OpenGL to run out of memory with certain cards and drivers
- GL gl = joglContext.getGL();
- gl.glBindFramebufferEXT(GL.GL_FRAMEBUFFER_EXT, 0);
- }
- }
-
- /** Overridden to cause OpenGL rendering to be performed during
- repaint cycles. Subclasses which override this method must call
- super.paintComponent() in their paintComponent() method in order
- to function properly. <P>
-
- <B>Overrides:</B>
- <DL><DD><CODE>paintComponent</CODE> in class <CODE>javax.swing.JComponent</CODE></DD></DL> */
- protected void paintComponent(final Graphics g) {
- if (Beans.isDesignTime()) {
- // Make GLJPanel behave better in NetBeans GUI builder
- g.setColor(Color.BLACK);
- g.fillRect(0, 0, getWidth(), getHeight());
- FontMetrics fm = g.getFontMetrics();
- String name = getName();
- if (name == null) {
- name = getClass().getName();
- int idx = name.lastIndexOf('.');
- if (idx >= 0) {
- name = name.substring(idx + 1);
- }
- }
- Rectangle2D bounds = fm.getStringBounds(name, g);
- g.setColor(Color.WHITE);
- g.drawString(name,
- (int) ((getWidth() - bounds.getWidth()) / 2),
- (int) ((getHeight() + bounds.getHeight()) / 2));
- return;
- }
-
- if (shouldInitialize) {
- initialize();
- }
-
- if (!isInitialized) {
- return;
- }
-
- // NOTE: must do this when the context is not current as it may
- // involve destroying the pbuffer (current context) and
- // re-creating it -- tricky to do properly while the context is
- // current
- if (handleReshape) {
- handleReshape();
- }
-
- updater.setGraphics(g);
-
- if (oglPipelineEnabled) {
-
- // This is a workaround for an issue in the Java 2D / JOGL
- // bridge (reported by an end user as JOGL Issue 274) where Java
- // 2D can occasionally leave its internal OpenGL context current
- // to the on-screen window rather than its internal "scratch"
- // pbuffer surface to which the FBO is attached. JOGL expects to
- // find a stable OpenGL drawable (on Windows, an HDC) upon which
- // it can create another OpenGL context. It turns out that, on
- // Windows, when Java 2D makes its internal OpenGL context
- // current against the window in order to put pixels on the
- // screen, it gets the device context for the window, makes its
- // context current, and releases the device context. This means
- // that when JOGL's Runnable gets to run below, the HDC is
- // already invalid. The workaround for this is to force Java 2D
- // to make its context current to the scratch surface, which we
- // can do by executing an empty Runnable with the "shared"
- // context current. This will be fixed in a Java SE 6 update
- // release, hopefully 6u2.
- if (Java2D.isFBOEnabled()) {
- if (workaroundConfig == null) {
- workaroundConfig = GraphicsEnvironment.
- getLocalGraphicsEnvironment().
- getDefaultScreenDevice().
- getDefaultConfiguration();
- }
- Java2D.invokeWithOGLSharedContextCurrent(workaroundConfig, new Runnable() { public void run() {}});
- }
-
- Java2D.invokeWithOGLContextCurrent(g, new Runnable() {
- public void run() {
- if (DEBUG && VERBOSE) {
- System.err.println("-- In invokeWithOGLContextCurrent");
- }
-
- // Create no-op context representing Java2D context
- if (j2dContext == null) {
- j2dContext = GLDrawableFactory.getFactory().createExternalGLContext();
- if (DEBUG) {
- j2dContext.setGL(new DebugGL(j2dContext.getGL()));
- }
-
- // Check to see whether we can support the requested
- // capabilities or need to fall back to a pbuffer
- // FIXME: add more checks?
-
- j2dContext.makeCurrent();
- GL gl = j2dContext.getGL();
- if ((getGLInteger(gl, GL.GL_RED_BITS) < offscreenCaps.getRedBits()) ||
- (getGLInteger(gl, GL.GL_GREEN_BITS) < offscreenCaps.getGreenBits()) ||
- (getGLInteger(gl, GL.GL_BLUE_BITS) < offscreenCaps.getBlueBits()) ||
- // (getGLInteger(gl, GL.GL_ALPHA_BITS) < offscreenCaps.getAlphaBits()) ||
- (getGLInteger(gl, GL.GL_ACCUM_RED_BITS) < offscreenCaps.getAccumRedBits()) ||
- (getGLInteger(gl, GL.GL_ACCUM_GREEN_BITS) < offscreenCaps.getAccumGreenBits()) ||
- (getGLInteger(gl, GL.GL_ACCUM_BLUE_BITS) < offscreenCaps.getAccumBlueBits()) ||
- (getGLInteger(gl, GL.GL_ACCUM_ALPHA_BITS) < offscreenCaps.getAccumAlphaBits()) ||
- // (getGLInteger(gl, GL.GL_DEPTH_BITS) < offscreenCaps.getDepthBits()) ||
- (getGLInteger(gl, GL.GL_STENCIL_BITS) < offscreenCaps.getStencilBits())) {
- if (DEBUG) {
- System.err.println("GLJPanel: Falling back to pbuffer-based support because Java2D context insufficient");
- System.err.println(" Available Required");
- System.err.println("GL_RED_BITS " + getGLInteger(gl, GL.GL_RED_BITS) + " " + offscreenCaps.getRedBits());
- System.err.println("GL_GREEN_BITS " + getGLInteger(gl, GL.GL_GREEN_BITS) + " " + offscreenCaps.getGreenBits());
- System.err.println("GL_BLUE_BITS " + getGLInteger(gl, GL.GL_BLUE_BITS) + " " + offscreenCaps.getBlueBits());
- System.err.println("GL_ALPHA_BITS " + getGLInteger(gl, GL.GL_ALPHA_BITS) + " " + offscreenCaps.getAlphaBits());
- System.err.println("GL_ACCUM_RED_BITS " + getGLInteger(gl, GL.GL_ACCUM_RED_BITS) + " " + offscreenCaps.getAccumRedBits());
- System.err.println("GL_ACCUM_GREEN_BITS " + getGLInteger(gl, GL.GL_ACCUM_GREEN_BITS) + " " + offscreenCaps.getAccumGreenBits());
- System.err.println("GL_ACCUM_BLUE_BITS " + getGLInteger(gl, GL.GL_ACCUM_BLUE_BITS) + " " + offscreenCaps.getAccumBlueBits());
- System.err.println("GL_ACCUM_ALPHA_BITS " + getGLInteger(gl, GL.GL_ACCUM_ALPHA_BITS) + " " + offscreenCaps.getAccumAlphaBits());
- System.err.println("GL_DEPTH_BITS " + getGLInteger(gl, GL.GL_DEPTH_BITS) + " " + offscreenCaps.getDepthBits());
- System.err.println("GL_STENCIL_BITS " + getGLInteger(gl, GL.GL_STENCIL_BITS) + " " + offscreenCaps.getStencilBits());
- }
- isInitialized = false;
- shouldInitialize = true;
- oglPipelineEnabled = false;
- handleReshape = true;
- j2dContext.release();
- j2dContext.destroy();
- j2dContext = null;
- return;
- }
- j2dContext.release();
- }
-
- j2dContext.makeCurrent();
- try {
- captureJ2DState(j2dContext.getGL(), g);
- Object curSurface = Java2D.getOGLSurfaceIdentifier(g);
- if (curSurface != null) {
- if (j2dSurface != curSurface) {
- if (joglContext != null) {
- joglContext.destroy();
- joglContext = null;
- joglDrawable = null;
- sendReshape = true;
- if (DEBUG) {
- System.err.println("Sending reshape because surface changed");
- System.err.println("New surface = " + curSurface);
- }
- }
- j2dSurface = curSurface;
- }
- if (joglContext == null) {
- if (GLDrawableFactory.getFactory().canCreateExternalGLDrawable()) {
- joglDrawable = GLDrawableFactory.getFactory().createExternalGLDrawable();
- joglContext = joglDrawable.createContext(shareWith);
- } else if (GLDrawableFactoryImpl.getFactoryImpl().canCreateContextOnJava2DSurface()) {
- // Mac OS X code path
- joglContext = GLDrawableFactoryImpl.getFactoryImpl().createContextOnJava2DSurface(g, shareWith);
- }
- if (DEBUG) {
- joglContext.setGL(new DebugGL(joglContext.getGL()));
- }
-
- if (Java2D.isFBOEnabled() &&
- Java2D.getOGLSurfaceType(g) == Java2D.FBOBJECT &&
- fbObjectWorkarounds) {
- createNewDepthBuffer = true;
- }
- }
- if (joglContext instanceof Java2DGLContext) {
- // Mac OS X code path
- ((Java2DGLContext) joglContext).setGraphics(g);
- }
-
- if (DEBUG && VERBOSE && Java2D.isFBOEnabled()) {
- System.err.print("-- Surface type: ");
- int surfaceType = Java2D.getOGLSurfaceType(g);
- if (surfaceType == Java2D.UNDEFINED) {
- System.err.println("UNDEFINED");
- } else if (surfaceType == Java2D.WINDOW) {
- System.err.println("WINDOW");
- } else if (surfaceType == Java2D.PBUFFER) {
- System.err.println("PBUFFER");
- } else if (surfaceType == Java2D.TEXTURE) {
- System.err.println("TEXTURE");
- } else if (surfaceType == Java2D.FLIP_BACKBUFFER) {
- System.err.println("FLIP_BACKBUFFER");
- } else if (surfaceType == Java2D.FBOBJECT) {
- System.err.println("FBOBJECT");
- } else {
- System.err.println("(Unknown surface type " + surfaceType + ")");
- }
- }
-
- drawableHelper.invokeGL(joglDrawable, joglContext, displayAction, initAction);
- }
- } finally {
- j2dContext.release();
- }
- }
- });
- } else {
- if (!hardwareAccelerationDisabled) {
- pbuffer.display();
- } else {
- drawableHelper.invokeGL(offscreenDrawable, offscreenContext, displayAction, initAction);
- }
-
- if (offscreenImage != null) {
- // Draw resulting image in one shot
- g.drawImage(offscreenImage, 0, 0, offscreenImage.getWidth(), offscreenImage.getHeight(), this);
- }
- }
- }
-
- /** Overridden to track when this component is added to a container.
- Subclasses which override this method must call
- super.addNotify() in their addNotify() method in order to
- function properly. <P>
-
- <B>Overrides:</B>
- <DL><DD><CODE>addNotify</CODE> in class <CODE>java.awt.Component</CODE></DD></DL> */
- public void addNotify() {
- super.addNotify();
- shouldInitialize = true;
- if (DEBUG) {
- System.err.println("GLJPanel.addNotify()");
- }
- }
-
- /** Overridden to track when this component is removed from a
- container. Subclasses which override this method must call
- super.removeNotify() in their removeNotify() method in order to
- function properly. <P>
-
- <B>Overrides:</B>
- <DL><DD><CODE>removeNotify</CODE> in class <CODE>java.awt.Component</CODE></DD></DL> */
- public void removeNotify() {
- if (DEBUG) {
- System.err.println("GLJPanel.removeNotify()");
- }
- if (oglPipelineEnabled) {
- Java2D.invokeWithOGLContextCurrent(null, new Runnable() {
- public void run() {
- if (joglContext != null) {
- joglContext.destroy();
- joglContext = null;
- }
- joglDrawable = null;
- if (j2dContext != null) {
- j2dContext.destroy();
- j2dContext = null;
- }
- }
- });
- } else {
- if (!hardwareAccelerationDisabled) {
- if (pbuffer != null) {
- pbuffer.destroy();
- pbuffer = null;
- }
- } else {
- if (offscreenContext != null) {
- offscreenContext.destroy();
- offscreenContext = null;
- }
- if (offscreenDrawable != null) {
- offscreenDrawable.destroy();
- offscreenDrawable = null;
- }
- }
- }
- isInitialized = false;
- super.removeNotify();
- }
-
- /** Overridden to cause {@link GLDrawableHelper#reshape} to be
- called on all registered {@link GLEventListener}s. Subclasses
- which override this method must call super.reshape() in
- their reshape() method in order to function properly. <P>
-
- <B>Overrides:</B>
- <DL><DD><CODE>reshape</CODE> in class <CODE>java.awt.Component</CODE></DD></DL> */
- public void reshape(int x, int y, int width, int height) {
- super.reshape(x, y, width, height);
-
- reshapeX = x;
- reshapeY = y;
- reshapeWidth = width;
- reshapeHeight = height;
- handleReshape = true;
- }
-
- public void setOpaque(boolean opaque) {
- if (opaque != isOpaque()) {
- if (offscreenImage != null) {
- offscreenImage.flush();
- offscreenImage = null;
- }
- }
- super.setOpaque(opaque);
- }
-
- public void addGLEventListener(GLEventListener listener) {
- drawableHelper.addGLEventListener(listener);
- }
-
- public void removeGLEventListener(GLEventListener listener) {
- drawableHelper.removeGLEventListener(listener);
- }
-
- public GLContext createContext(GLContext shareWith) {
- if (!hardwareAccelerationDisabled) {
- return pbuffer.createContext(shareWith);
- } else {
- return offscreenDrawable.createContext(shareWith);
- }
- }
-
- public void setRealized(boolean realized) {
- }
-
- public GLContext getContext() {
- if (oglPipelineEnabled) {
- return joglContext;
- } else {
- if (!hardwareAccelerationDisabled) {
- // Workaround for crashes in NetBeans GUI builder
- if (pbuffer == null && Beans.isDesignTime()) {
- return null;
- }
- return pbuffer.getContext();
- } else {
- return offscreenContext;
- }
- }
- }
-
- public GL getGL() {
- GLContext context = getContext();
- return (context == null) ? null : context.getGL();
- }
-
- public void setGL(GL gl) {
- GLContext context = getContext();
- if (context != null) {
- context.setGL(gl);
- }
- }
-
- public void setAutoSwapBufferMode(boolean onOrOff) {
- if (!hardwareAccelerationDisabled) {
- // Workaround for crashes in NetBeans GUI builder
- if (pbuffer == null && Beans.isDesignTime()) {
- return;
- }
- pbuffer.setAutoSwapBufferMode(onOrOff);
- } else {
- drawableHelper.setAutoSwapBufferMode(onOrOff);
- }
- }
-
- public boolean getAutoSwapBufferMode() {
- if (!hardwareAccelerationDisabled && !oglPipelineEnabled) {
- return pbuffer.getAutoSwapBufferMode();
- } else {
- return drawableHelper.getAutoSwapBufferMode();
- }
- }
-
- public void swapBuffers() {
- // In the current implementation this is basically a no-op. Both
- // the pbuffer and pixmap based rendering paths use a single-
- // buffered surface so swapping the buffers doesn't do anything.
- // We also don't currently have the provision to skip copying the
- // data to the Swing portion of the GLJPanel in any of the
- // rendering paths.
- if (oglPipelineEnabled) {
- // Do nothing
- } else if (!hardwareAccelerationDisabled) {
- pbuffer.swapBuffers();
- } else {
- drawableHelper.invokeGL(offscreenDrawable, offscreenContext, swapBuffersAction, initAction);
- }
- }
-
- /** For a translucent GLJPanel (one for which {@link #setOpaque
- setOpaque}(false) has been called), indicates whether the
- application should preserve the OpenGL color buffer
- (GL_COLOR_BUFFER_BIT) for correct rendering of the GLJPanel and
- underlying widgets which may show through portions of the
- GLJPanel with alpha values less than 1. Most Swing
- implementations currently expect the GLJPanel to be completely
- cleared (e.g., by <code>glClear(GL_COLOR_BUFFER_BIT |
- GL_DEPTH_BUFFER_BIT)</code>), but for certain optimized Swing
- implementations which use OpenGL internally, it may be possible
- to perform OpenGL rendering using the GLJPanel into the same
- OpenGL drawable as the Swing implementation uses. */
- public boolean shouldPreserveColorBufferIfTranslucent() {
- return oglPipelineEnabled;
- }
-
- public GLCapabilities getChosenGLCapabilities() {
- if (oglPipelineEnabled) {
- // FIXME: should do better than this; is it possible to using only platform-independent code?
- return new GLCapabilities();
- }
-
- if (hardwareAccelerationDisabled) {
- if (offscreenDrawable != null)
- return offscreenDrawable.getChosenGLCapabilities();
- } else {
- if (pbuffer != null)
- return pbuffer.getChosenGLCapabilities();
- }
-
- return null;
- }
-
- //----------------------------------------------------------------------
- // Internals only below this point
- //
-
- private void initialize() {
- if (panelWidth == 0 ||
- panelHeight == 0) {
- // See whether we have a non-zero size yet and can go ahead with
- // initialization
- if (reshapeWidth == 0 ||
- reshapeHeight == 0) {
- return;
- }
-
- // Pull down reshapeWidth and reshapeHeight into panelWidth and
- // panelHeight eagerly in order to complete initialization, and
- // force a reshape later
- panelWidth = reshapeWidth;
- panelHeight = reshapeHeight;
- }
-
- if (!oglPipelineEnabled) {
- // Initialize either the hardware-accelerated rendering path or
- // the lightweight rendering path
- if (!hardwareAccelerationDisabled) {
- if (GLDrawableFactory.getFactory().canCreateGLPbuffer()) {
- if (pbuffer != null) {
- throw new InternalError("Creating pbuffer twice without destroying it (memory leak / correctness bug)");
- }
- try {
- pbuffer = GLDrawableFactory.getFactory().createGLPbuffer(offscreenCaps,
- null,
- pbufferWidth,
- pbufferHeight,
- shareWith);
- updater = new Updater();
- pbuffer.addGLEventListener(updater);
- shouldInitialize = false;
- isInitialized = true;
- return;
- } catch (GLException e) {
- if (DEBUG) {
- e.printStackTrace();
- System.err.println("GLJPanel: Falling back on software rendering because of problems creating pbuffer");
- }
- hardwareAccelerationDisabled = true;
- }
- } else {
- if (DEBUG) {
- System.err.println("GLJPanel: Falling back on software rendering because no pbuffer support");
- }
-
- // If the factory reports that it can't create a pbuffer,
- // don't try again the next time, and fall through to the
- // software rendering path
- hardwareAccelerationDisabled = true;
- }
- }
-
- if (softwareRenderingDisabled) {
- throw new GLException("Fallback to software rendering disabled by user");
- }
-
- // Fall-through path: create an offscreen context instead
- offscreenDrawable = GLDrawableFactoryImpl.getFactoryImpl().createOffscreenDrawable(offscreenCaps, chooser);
- offscreenDrawable.setSize(Math.max(1, panelWidth), Math.max(1, panelHeight));
- offscreenContext = (GLContextImpl) offscreenDrawable.createContext(shareWith);
- offscreenContext.setSynchronized(true);
- }
- updater = new Updater();
- shouldInitialize = false;
- isInitialized = true;
- }
-
- private void handleReshape() {
- readBackWidthInPixels = 0;
- readBackHeightInPixels = 0;
-
- panelWidth = reshapeWidth;
- panelHeight = reshapeHeight;
-
- if (DEBUG) {
- System.err.println("GLJPanel.handleReshape: (w,h) = (" +
- panelWidth + "," + panelHeight + ")");
- }
-
- sendReshape = true;
-
- if (!oglPipelineEnabled) {
- if (!hardwareAccelerationDisabled) {
- // Use factor larger than 2 during shrinks for some hysteresis
- float shrinkFactor = 2.5f;
- if ((panelWidth > pbufferWidth ) || (panelHeight > pbufferHeight) ||
- (panelWidth < (pbufferWidth / shrinkFactor)) || (panelHeight < (pbufferHeight / shrinkFactor))) {
- if (DEBUG) {
- System.err.println("Resizing pbuffer from (" + pbufferWidth + ", " + pbufferHeight + ") " +
- " to fit (" + panelWidth + ", " + panelHeight + ")");
- }
- // Must destroy and recreate pbuffer to fit
- if (pbuffer != null) {
- // Watch for errors during pbuffer destruction (due to
- // buggy / bad OpenGL drivers, in particular SiS) and fall
- // back to software rendering
- try {
- pbuffer.destroy();
- } catch (GLException e) {
- hardwareAccelerationDisabled = true;
- if (DEBUG) {
- System.err.println("WARNING: falling back to software rendering due to bugs in OpenGL drivers");
- e.printStackTrace();
- }
- }
- }
- pbuffer = null;
- isInitialized = false;
- pbufferWidth = getNextPowerOf2(panelWidth);
- pbufferHeight = getNextPowerOf2(panelHeight);
- if (DEBUG && !hardwareAccelerationDisabled) {
- System.err.println("New pbuffer size is (" + pbufferWidth + ", " + pbufferHeight + ")");
- }
- initialize();
- }
-
- // It looks like NVidia's drivers (at least the ones on my
- // notebook) are buggy and don't allow a rectangle of less than
- // the pbuffer's width to be read...this doesn't really matter
- // because it's the Graphics.drawImage() calls that are the
- // bottleneck. Should probably make the size of the offscreen
- // image be the exact size of the pbuffer to save some work on
- // resize operations...
- if (!hardwareAccelerationDisabled) {
- readBackWidthInPixels = pbufferWidth;
- readBackHeightInPixels = panelHeight;
- } else {
- // Just disabled hardware acceleration during this resize operation; do a fixup
- readBackWidthInPixels = Math.max(1, panelWidth);
- readBackHeightInPixels = Math.max(1, panelHeight);
- }
- } else {
- offscreenContext.destroy();
- offscreenDrawable.setSize(Math.max(1, panelWidth), Math.max(1, panelHeight));
- readBackWidthInPixels = Math.max(1, panelWidth);
- readBackHeightInPixels = Math.max(1, panelHeight);
- }
-
- if (offscreenImage != null) {
- offscreenImage.flush();
- offscreenImage = null;
- }
- }
-
- handleReshape = false;
- }
-
- // FIXME: it isn't clear whether this works any more given that
- // we're accessing the GLDrawable inside of the GLPbuffer directly
- // up in reshape() -- need to rethink and clean this up
- class Updater implements GLEventListener {
- private Graphics g;
-
- public void setGraphics(Graphics g) {
- this.g = g;
- }
-
- public void init(GLAutoDrawable drawable) {
- if (oglPipelineEnabled) {
- if (!preGL(g)) {
- return;
- }
- }
- drawableHelper.init(GLJPanel.this);
- if (oglPipelineEnabled) {
- postGL(g);
- }
- }
-
- public void display(GLAutoDrawable drawable) {
- if (oglPipelineEnabled) {
- if (!preGL(g)) {
- return;
- }
- }
-
- if (sendReshape) {
- if (DEBUG) {
- System.err.println("glViewport(" + viewportX + ", " + viewportY + ", " + panelWidth + ", " + panelHeight + ")");
- }
- getGL().glViewport(viewportX, viewportY, panelWidth, panelHeight);
- drawableHelper.reshape(GLJPanel.this, viewportX, viewportY, panelWidth, panelHeight);
- sendReshape = false;
- }
-
- drawableHelper.display(GLJPanel.this);
-
- if (!oglPipelineEnabled) {
- // Must now copy pixels from offscreen context into surface
- if (offscreenImage == null) {
- if (panelWidth > 0 && panelHeight > 0) {
- // It looks like NVidia's drivers (at least the ones on my
- // notebook) are buggy and don't allow a sub-rectangle to be
- // read from a pbuffer...this doesn't really matter because
- // it's the Graphics.drawImage() calls that are the
- // bottleneck
-
- int awtFormat = 0;
- int hwGLFormat = 0;
- if (!hardwareAccelerationDisabled) {
- // This seems to be a good choice on all platforms
- hwGLFormat = GL.GL_UNSIGNED_INT_8_8_8_8_REV;
- }
-
- // Should be more flexible in these BufferedImage formats;
- // perhaps see what the preferred image types are on the
- // given platform
- if (isOpaque()) {
- awtFormat = BufferedImage.TYPE_INT_RGB;
- } else {
- awtFormat = BufferedImage.TYPE_INT_ARGB;
- }
-
- offscreenImage = new BufferedImage(panelWidth,
- panelHeight,
- awtFormat);
- switch (awtFormat) {
- case BufferedImage.TYPE_3BYTE_BGR:
- glFormat = GL.GL_BGR;
- glType = GL.GL_UNSIGNED_BYTE;
- readBackBytes = ByteBuffer.allocate(readBackWidthInPixels * readBackHeightInPixels * 3);
- break;
-
- case BufferedImage.TYPE_INT_RGB:
- case BufferedImage.TYPE_INT_ARGB:
- glFormat = GL.GL_BGRA;
- glType = (hardwareAccelerationDisabled
- ? offscreenContext.getOffscreenContextPixelDataType()
- : hwGLFormat);
- readBackInts = IntBuffer.allocate(readBackWidthInPixels * readBackHeightInPixels);
- break;
-
- default:
- // FIXME: Support more off-screen image types (current
- // offscreen context implementations don't use others, and
- // some of the OpenGL formats aren't supported in the 1.1
- // headers, which we're currently using)
- throw new GLException("Unsupported offscreen image type " + awtFormat);
- }
- }
- }
-
- if (offscreenImage != null) {
- GL gl = getGL();
- // Save current modes
- gl.glGetIntegerv(GL.GL_PACK_SWAP_BYTES, swapbytes, 0);
- gl.glGetIntegerv(GL.GL_PACK_ROW_LENGTH, rowlength, 0);
- gl.glGetIntegerv(GL.GL_PACK_SKIP_ROWS, skiprows, 0);
- gl.glGetIntegerv(GL.GL_PACK_SKIP_PIXELS, skippixels, 0);
- gl.glGetIntegerv(GL.GL_PACK_ALIGNMENT, alignment, 0);
-
- gl.glPixelStorei(GL.GL_PACK_SWAP_BYTES, GL.GL_FALSE);
- gl.glPixelStorei(GL.GL_PACK_ROW_LENGTH, readBackWidthInPixels);
- gl.glPixelStorei(GL.GL_PACK_SKIP_ROWS, 0);
- gl.glPixelStorei(GL.GL_PACK_SKIP_PIXELS, 0);
- gl.glPixelStorei(GL.GL_PACK_ALIGNMENT, 1);
-
- // Actually read the pixels.
- gl.glReadBuffer(GL.GL_FRONT);
- if (readBackBytes != null) {
- gl.glReadPixels(0, 0, readBackWidthInPixels, readBackHeightInPixels, glFormat, glType, readBackBytes);
- } else if (readBackInts != null) {
- gl.glReadPixels(0, 0, readBackWidthInPixels, readBackHeightInPixels, glFormat, glType, readBackInts);
- }
-
- // Restore saved modes.
- gl.glPixelStorei(GL.GL_PACK_SWAP_BYTES, swapbytes[0]);
- gl.glPixelStorei(GL.GL_PACK_ROW_LENGTH, rowlength[0]);
- gl.glPixelStorei(GL.GL_PACK_SKIP_ROWS, skiprows[0]);
- gl.glPixelStorei(GL.GL_PACK_SKIP_PIXELS, skippixels[0]);
- gl.glPixelStorei(GL.GL_PACK_ALIGNMENT, alignment[0]);
-
- if (readBackBytes != null || readBackInts != null) {
- // Copy temporary data into raster of BufferedImage for faster
- // blitting Note that we could avoid this copy in the cases
- // where !offscreenContext.offscreenImageNeedsVerticalFlip(),
- // but that's the software rendering path which is very slow
- // anyway
- Object src = null;
- Object dest = null;
- int srcIncr = 0;
- int destIncr = 0;
-
- if (readBackBytes != null) {
- src = readBackBytes.array();
- dest = ((DataBufferByte) offscreenImage.getRaster().getDataBuffer()).getData();
- srcIncr = readBackWidthInPixels * 3;
- destIncr = offscreenImage.getWidth() * 3;
- } else {
- src = readBackInts.array();
- dest = ((DataBufferInt) offscreenImage.getRaster().getDataBuffer()).getData();
- srcIncr = readBackWidthInPixels;
- destIncr = offscreenImage.getWidth();
- }
-
- if (!hardwareAccelerationDisabled ||
- offscreenContext.offscreenImageNeedsVerticalFlip()) {
- int srcPos = 0;
- int destPos = (offscreenImage.getHeight() - 1) * destIncr;
- for (; destPos >= 0; srcPos += srcIncr, destPos -= destIncr) {
- System.arraycopy(src, srcPos, dest, destPos, destIncr);
- }
- } else {
- int srcPos = 0;
- int destEnd = destIncr * offscreenImage.getHeight();
- for (int destPos = 0; destPos < destEnd; srcPos += srcIncr, destPos += destIncr) {
- System.arraycopy(src, srcPos, dest, destPos, destIncr);
- }
- }
-
- // Note: image will be drawn back in paintComponent() for
- // correctness on all platforms
- }
- }
- } else {
- // Cause OpenGL pipeline to flush its results because
- // otherwise it's possible we will buffer up multiple frames'
- // rendering results, resulting in apparent mouse lag
- GL gl = getGL();
- gl.glFinish();
-
- postGL(g);
- }
- }
-
- public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
- // This is handled above and dispatched directly to the appropriate context
- }
-
- public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) {
- }
- }
-
- class InitAction implements Runnable {
- public void run() {
- updater.init(GLJPanel.this);
- }
- }
- private InitAction initAction = new InitAction();
-
- class DisplayAction implements Runnable {
- public void run() {
- updater.display(GLJPanel.this);
- }
- }
- private DisplayAction displayAction = new DisplayAction();
-
- // This one is used exclusively in the non-hardware-accelerated case
- class SwapBuffersAction implements Runnable {
- public void run() {
- offscreenDrawable.swapBuffers();
- }
- }
- private SwapBuffersAction swapBuffersAction = new SwapBuffersAction();
-
- class PaintImmediatelyAction implements Runnable {
- public void run() {
- paintImmediately(0, 0, getWidth(), getHeight());
- }
- }
- private PaintImmediatelyAction paintImmediatelyAction = new PaintImmediatelyAction();
-
- private int getNextPowerOf2(int number) {
- // Workaround for problems where 0 width or height are transiently
- // seen during layout
- if (number == 0) {
- return 2;
- }
-
- if (((number-1) & number) == 0) {
- //ex: 8 -> 0b1000; 8-1=7 -> 0b0111; 0b1000&0b0111 == 0
- return number;
- }
- int power = 0;
- while (number > 0) {
- number = number>>1;
- power++;
- }
- return (1<<power);
- }
-
- private int getGLInteger(GL gl, int which) {
- int[] tmp = new int[1];
- gl.glGetIntegerv(which, tmp, 0);
- return tmp[0];
- }
-}
diff --git a/src/classes/javax/media/opengl/glu/GLUquadric.java b/src/classes/javax/media/opengl/glu/GLUquadric.java
index 882df6cb6..937d77f8b 100755
--- a/src/classes/javax/media/opengl/glu/GLUquadric.java
+++ b/src/classes/javax/media/opengl/glu/GLUquadric.java
@@ -1,19 +1,33 @@
package javax.media.opengl.glu;
-import javax.media.opengl.GL;
-import com.sun.opengl.util.ImmModeSink;
+import javax.media.opengl.GL2ES1;
+import javax.media.opengl.util.ImmModeSink;
/**
* Wrapper for a GLU quadric object.
*/
public interface GLUquadric {
+ // enable/disables the Immediate Mode Sink module.
+ // This defaults to false for GLUgl2,
+ // and is always true for GLUes1.
+ public void enableImmModeSink(boolean val);
+
+ public boolean isImmModeSinkEnabled();
+
+ // set Immediate Mode usage.
+ // This defaults to false at GLU creation time.
+ // If enabled rendering will happen immediately,
+ // otherwise rendering will be hold in the ImmModeSink
+ // object, to be rendered deferred.
+ public void setImmMode(boolean val);
+
+ public boolean getImmMode();
+
// creates a new ImmModeSink (VBO Buffers) and
// returns the old vbo buffer with it's rendering result
- public ImmModeSink replaceVBOBuffer();
-
- public void setVBOImmediateMode(boolean val);
+ public ImmModeSink replaceImmModeSink();
// gl may be null, then the GL client states are not disabled
- public void resetVBOBuffer(GL gl);
+ public void resetImmModeSink(GL2ES1 gl);
}
diff --git a/src/native/jogl/WindowsWindow.c b/src/native/jogl/WindowsWindow.c
index bf4dcb819..cd6844cd2 100755
--- a/src/native/jogl/WindowsWindow.c
+++ b/src/native/jogl/WindowsWindow.c
@@ -50,6 +50,7 @@ typedef int intptr_t;
#include "com_sun_javafx_newt_windows_WindowsWindow.h"
+#include "EventListener.h"
#include "MouseEvent.h"
#include "KeyEvent.h"
@@ -273,10 +274,10 @@ JNIEXPORT jlong JNICALL Java_com_sun_javafx_newt_windows_WindowsWindow_RegisterW
/*
* Class: com_sun_javafx_newt_windows_WindowsWindow
* Method: CreateWindow
- * Signature: (Ljava/lang/String;JIIIII)J
+ * Signature: (Ljava/lang/String;JJIIII)J
*/
JNIEXPORT jlong JNICALL Java_com_sun_javafx_newt_windows_WindowsWindow_CreateWindow
- (JNIEnv *env, jobject obj, jstring windowClassName, jlong hInstance, jint visualID,
+ (JNIEnv *env, jobject obj, jstring windowClassName, jlong hInstance, jlong visualID,
jint jx, jint jy, jint defaultWidth, jint defaultHeight)
{
const TCHAR* wndClassName = NULL;
@@ -347,10 +348,10 @@ JNIEXPORT void JNICALL Java_com_sun_javafx_newt_windows_WindowsWindow_setVisible
/*
* Class: com_sun_javafx_newt_windows_WindowsWindow
* Method: DispatchMessages
- * Signature: (J)V
+ * Signature: (JI)V
*/
JNIEXPORT void JNICALL Java_com_sun_javafx_newt_windows_WindowsWindow_DispatchMessages
- (JNIEnv *_env, jclass clazz, jlong window)
+ (JNIEnv *_env, jclass clazz, jlong window, jint eventMask)
{
int i = 0;
MSG msg;
@@ -358,11 +359,60 @@ JNIEXPORT void JNICALL Java_com_sun_javafx_newt_windows_WindowsWindow_DispatchMe
env = _env;
+ if(eventMask<0) {
+ eventMask *= -1;
+ /* FIXME: re-select input mask
+ long xevent_mask_key = 0;
+ long xevent_mask_ptr = 0;
+ long xevent_mask_win = 0;
+ if( 0 != ( eventMask & EVENT_MOUSE ) ) {
+ xevent_mask_ptr |= ButtonPressMask|ButtonReleaseMask|PointerMotionMask;
+ }
+ if( 0 != ( eventMask & EVENT_KEY ) ) {
+ xevent_mask_key |= KeyPressMask|KeyReleaseMask;
+ }
+ if( 0 != ( eventMask & EVENT_WINDOW ) ) {
+ xevent_mask_win |= ExposureMask;
+ }
+
+ XSelectInput(dpy, w, xevent_mask_win|xevent_mask_key|xevent_mask_ptr);
+ */
+ }
+
// Periodically take a break
do {
gotOne = PeekMessage(&msg, (HWND) window, 0, 0, PM_REMOVE);
if (gotOne) {
++i;
+ switch (msg.message) {
+ case WM_CLOSE:
+ case WM_DESTROY:
+ case WM_SIZE:
+ if( ! ( eventMask & EVENT_WINDOW ) ) {
+ continue;
+ }
+ break;
+
+ case WM_CHAR:
+ case WM_KEYDOWN:
+ case WM_KEYUP:
+ if( ! ( eventMask & EVENT_KEY ) ) {
+ continue;
+ }
+ break;
+
+ case WM_LBUTTONDOWN:
+ case WM_LBUTTONUP:
+ case WM_MBUTTONDOWN:
+ case WM_MBUTTONUP:
+ case WM_RBUTTONDOWN:
+ case WM_RBUTTONUP:
+ case WM_MOUSEMOVE:
+ if( ! ( eventMask & EVENT_MOUSE ) ) {
+ continue;
+ }
+ break;
+ }
TranslateMessage(&msg);
DispatchMessage(&msg);
}
diff --git a/src/native/jogl/X11Window.c b/src/native/jogl/X11Window.c
index d4c764a6a..3f08b5d49 100755
--- a/src/native/jogl/X11Window.c
+++ b/src/native/jogl/X11Window.c
@@ -41,6 +41,7 @@
#include "com_sun_javafx_newt_x11_X11Window.h"
+#include "EventListener.h"
#include "MouseEvent.h"
#include "KeyEvent.h"
@@ -170,11 +171,11 @@ JNIEXPORT jboolean JNICALL Java_com_sun_javafx_newt_x11_X11Window_initIDs
/*
* Class: com_sun_javafx_newt_x11_X11Window
* Method: CreateWindow
- * Signature: (JJIIIIII)J
+ * Signature: (JJIJIIII)J
*/
JNIEXPORT jlong JNICALL Java_com_sun_javafx_newt_x11_X11Window_CreateWindow
(JNIEnv *env, jobject obj, jlong display, jlong screen, jint screen_index,
- jint visualID,
+ jlong visualID,
jint x, jint y, jint width, jint height)
{
Display * dpy = NULL;
@@ -220,7 +221,7 @@ JNIEXPORT jlong JNICALL Java_com_sun_javafx_newt_x11_X11Window_CreateWindow
pVisualQuery=NULL;
}
#ifdef VERBOSE_ON
- fprintf(stderr, "trying given (screen %d, visualID: %d) found: %p\n", scrn_idx, visualID, visual);
+ fprintf(stderr, "trying given (screen %d, visualID: %d) found: %p\n", scrn_idx, (int)visualID, visual);
#endif
}
if (visual==NULL)
@@ -246,7 +247,7 @@ JNIEXPORT jlong JNICALL Java_com_sun_javafx_newt_x11_X11Window_CreateWindow
visualID = 0;
}
#ifdef VERBOSE_ON
- fprintf(stderr, "default visual (screen %d, visualID: %d) found: %p\n", scrn_idx, visualID, visual);
+ fprintf(stderr, "default visual (screen %d, visualID: %d) found: %p\n", scrn_idx, (int)visualID, visual);
#endif
}
}
@@ -296,6 +297,24 @@ JNIEXPORT jlong JNICALL Java_com_sun_javafx_newt_x11_X11Window_CreateWindow
* Method: setVisible0
* Signature: (JJZ)V
*/
+JNIEXPORT void JNICALL Java_com_sun_javafx_newt_x11_X11Window_CloseWindow
+ (JNIEnv *env, jobject obj, jlong display, jlong window)
+{
+ Display * dpy = (Display *) (intptr_t) display;
+ Window w = (Window)window;
+
+ XUngrabPointer(dpy, CurrentTime);
+ XUngrabKeyboard(dpy, CurrentTime);
+ XSelectInput(dpy, w, 0);
+ XUnmapWindow(dpy, w);
+ XDestroyWindow(dpy, w);
+}
+
+/*
+ * Class: com_sun_javafx_newt_x11_X11Window
+ * Method: setVisible0
+ * Signature: (JJZ)V
+ */
JNIEXPORT void JNICALL Java_com_sun_javafx_newt_x11_X11Window_setVisible0
(JNIEnv *env, jobject obj, jlong display, jlong window, jboolean visible)
{
@@ -304,12 +323,12 @@ JNIEXPORT void JNICALL Java_com_sun_javafx_newt_x11_X11Window_setVisible0
if(visible==JNI_TRUE) {
XMapRaised(dpy, w);
- XSelectInput(dpy, w, ExposureMask|ButtonPressMask|ButtonReleaseMask|PointerMotionMask|
- KeyPressMask|KeyReleaseMask);
XSetInputFocus(dpy, w, RevertToNone, CurrentTime);
XSync(dpy, False);
} else {
+ XUngrabPointer(dpy, CurrentTime);
+ XUngrabKeyboard(dpy, CurrentTime);
XSelectInput(dpy, w, 0);
XUnmapWindow(dpy, w);
}
@@ -318,14 +337,40 @@ JNIEXPORT void JNICALL Java_com_sun_javafx_newt_x11_X11Window_setVisible0
/*
* Class: com_sun_javafx_newt_x11_X11Window
* Method: DispatchMessages
- * Signature: (JJ)V
+ * Signature: (JJI)V
*/
JNIEXPORT void JNICALL Java_com_sun_javafx_newt_x11_X11Window_DispatchMessages
- (JNIEnv *env, jobject obj, jlong display, jlong window)
+ (JNIEnv *env, jobject obj, jlong display, jlong window, jint eventMask)
{
Display * dpy = (Display *) (intptr_t) display;
Window w = (Window)window;
- (void) w; // unused for now, might be necessary to verify the event source
+
+ if(eventMask<0) {
+ long xevent_mask_key = 0;
+ long xevent_mask_ptr = 0;
+ long xevent_mask_win = 0;
+ eventMask *= -1;
+ if( 0 != ( eventMask & EVENT_MOUSE ) ) {
+ xevent_mask_ptr |= ButtonPressMask|ButtonReleaseMask|PointerMotionMask;
+ }
+ if( 0 != ( eventMask & EVENT_KEY ) ) {
+ xevent_mask_key |= KeyPressMask|KeyReleaseMask;
+ }
+ if( 0 != ( eventMask & EVENT_WINDOW ) ) {
+ xevent_mask_win |= ExposureMask;
+ }
+
+ XSelectInput(dpy, w, xevent_mask_win|xevent_mask_key|xevent_mask_ptr);
+
+ if(0!=xevent_mask_ptr) {
+ XGrabPointer(dpy, w, True, xevent_mask_ptr,
+ GrabModeAsync, GrabModeAsync, w, None, CurrentTime);
+ }
+ if(0!=xevent_mask_key) {
+ XGrabKeyboard(dpy, w, True, GrabModeAsync, GrabModeAsync, CurrentTime);
+ }
+
+ }
// Periodically take a break
while( XPending(dpy)>0 ) {
@@ -338,45 +383,93 @@ JNIEXPORT void JNICALL Java_com_sun_javafx_newt_x11_X11Window_DispatchMessages
switch(evt.type) {
case ButtonPress:
- (*env)->CallVoidMethod(env, obj, sendMouseEventID, (jint) EVENT_MOUSE_PRESSED,
- (jint) evt.xbutton.state,
- (jint) evt.xbutton.x, (jint) evt.xbutton.y, (jint) evt.xbutton.button);
+ case ButtonRelease:
+ case MotionNotify:
+ if( ! ( eventMask & EVENT_MOUSE ) ) {
+ continue;
+ }
+ break;
+ case KeyPress:
+ case KeyRelease:
+ if( ! ( eventMask & EVENT_KEY ) ) {
+ continue;
+ }
+ break;
+ case FocusIn:
+ case FocusOut:
+ case DestroyNotify:
+ case CreateNotify:
+ case VisibilityNotify:
+ if( ! ( eventMask & EVENT_WINDOW ) ) {
+ continue;
+ }
+ break;
+ }
+
+ switch(evt.type) {
+ case ButtonPress:
+ if(evt.xbutton.window==w) {
+ (*env)->CallVoidMethod(env, obj, sendMouseEventID, (jint) EVENT_MOUSE_PRESSED,
+ (jint) evt.xbutton.state,
+ (jint) evt.xbutton.x, (jint) evt.xbutton.y, (jint) evt.xbutton.button);
+ }
break;
case ButtonRelease:
- (*env)->CallVoidMethod(env, obj, sendMouseEventID, (jint) EVENT_MOUSE_RELEASED,
- (jint) evt.xbutton.state,
- (jint) evt.xbutton.x, (jint) evt.xbutton.y, (jint) evt.xbutton.button);
+ if(evt.xbutton.window==w) {
+ (*env)->CallVoidMethod(env, obj, sendMouseEventID, (jint) EVENT_MOUSE_RELEASED,
+ (jint) evt.xbutton.state,
+ (jint) evt.xbutton.x, (jint) evt.xbutton.y, (jint) evt.xbutton.button);
+ }
break;
case MotionNotify:
- (*env)->CallVoidMethod(env, obj, sendMouseEventID, (jint) EVENT_MOUSE_MOVED,
- (jint) evt.xmotion.state,
- (jint) evt.xmotion.x, (jint) evt.xmotion.y, (jint) 0);
+ if(evt.xmotion.window==w) {
+ (*env)->CallVoidMethod(env, obj, sendMouseEventID, (jint) EVENT_MOUSE_MOVED,
+ (jint) evt.xmotion.state,
+ (jint) evt.xmotion.x, (jint) evt.xmotion.y, (jint) 0);
+ }
break;
case KeyPress:
- if(XLookupString(&evt.xkey,text,255,&keySym,0)==1) {
- keyChar=text[0];
- } else {
- keyChar=0;
+ if(evt.xkey.window==w) {
+ if(XLookupString(&evt.xkey,text,255,&keySym,0)==1) {
+ keyChar=text[0];
+ } else {
+ keyChar=0;
+ }
+ (*env)->CallVoidMethod(env, obj, sendKeyEventID, (jint) EVENT_KEY_PRESSED,
+ (jint) evt.xkey.state,
+ (jint) keySym, (jchar) keyChar);
}
- (*env)->CallVoidMethod(env, obj, sendKeyEventID, (jint) EVENT_KEY_PRESSED,
- (jint) evt.xkey.state,
- (jint) keySym, (jchar) keyChar);
break;
case KeyRelease:
- if(XLookupString(&evt.xkey,text,255,&keySym,0)==1) {
- keyChar=text[0];
- } else {
- keyChar=0;
+ if(evt.xkey.window==w) {
+ if(XLookupString(&evt.xkey,text,255,&keySym,0)==1) {
+ keyChar=text[0];
+ } else {
+ keyChar=0;
+ }
+ (*env)->CallVoidMethod(env, obj, sendKeyEventID, (jint) EVENT_KEY_RELEASED,
+ (jint) evt.xkey.state,
+ (jint) keySym, (jchar) keyChar);
}
- (*env)->CallVoidMethod(env, obj, sendKeyEventID, (jint) EVENT_KEY_RELEASED,
- (jint) evt.xkey.state,
- (jint) keySym, (jchar) keyChar);
break;
case FocusIn:
- // evt.xfocus
- break;
case FocusOut:
- // evt.xfocus
+ if(evt.xfocus.window==w) {
+ }
+ break;
+ case DestroyNotify:
+ if(evt.xdestroywindow.window==w) {
+ (*env)->CallVoidMethod(env, obj, windowDestroyedID);
+ }
+ break;
+ case CreateNotify:
+ if(evt.xcreatewindow.window==w) {
+ (*env)->CallVoidMethod(env, obj, windowCreatedID);
+ }
+ break;
+ case VisibilityNotify:
+ if(evt.xvisibility.window==w) {
+ }
break;
}
}