summaryrefslogtreecommitdiffstats
path: root/src/demos/xtrans/XTDesktopManager.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/demos/xtrans/XTDesktopManager.java')
-rwxr-xr-xsrc/demos/xtrans/XTDesktopManager.java166
1 files changed, 166 insertions, 0 deletions
diff --git a/src/demos/xtrans/XTDesktopManager.java b/src/demos/xtrans/XTDesktopManager.java
new file mode 100755
index 0000000..4b911ee
--- /dev/null
+++ b/src/demos/xtrans/XTDesktopManager.java
@@ -0,0 +1,166 @@
+package demos.xtrans;
+
+import java.awt.*;
+import java.awt.geom.*;
+import java.awt.image.*;
+import java.beans.*;
+import java.nio.*;
+import java.util.*;
+import javax.swing.*;
+import javax.media.opengl.*;
+import javax.media.opengl.glu.*;
+import com.sun.opengl.impl.*;
+
+import com.sun.opengl.impl.windows.*;
+
+/** A desktop manager implementation supporting accelerated
+ transitions of the components on the desktop via OpenGL. This
+ class does not need to be instantiated by end users; it is
+ installed automatically when an XTDesktopPane is constructed. */
+public class XTDesktopManager extends OffscreenDesktopManager {
+ private GLContext j2dContext;
+ private Object j2dContextSurfaceIdentifier;
+ private int oglTextureId;
+ private int prevBackBufferWidth;
+ private int prevBackBufferHeight;
+
+ private int textureTarget = GL.GL_TEXTURE_2D;
+
+ /** Returns the OpenGL texture object ID associated with the
+ off-screen back buffer for all of the components on the
+ desktop. */
+ public int getOpenGLTextureObject() {
+ return oglTextureId;
+ }
+
+ /** Returns a rectangle specifying the OpenGL texture coordinates of
+ the passed component in the texture object. The x and y
+ coordinates of the returned rectangle specify the lower left
+ corner of the component's image. */
+ public Rectangle2D getOpenGLTextureCoords(Component c) {
+ Rectangle rect = getBoundsOnBackBuffer(c);
+ if (rect == null) {
+ throw new RuntimeException("Unknown component " + c);
+ }
+ double offscreenWidth = getOffscreenBackBufferWidth();
+ double offscreenHeight = getOffscreenBackBufferHeight();
+ return new Rectangle2D.Double(rect.x / offscreenWidth,
+ (offscreenHeight - rect.y - rect.height) / offscreenHeight,
+ rect.width / offscreenWidth,
+ rect.height / offscreenHeight);
+ }
+
+ /** Updates the off-screen buffer of this desktop manager and makes
+ the rendering results available to OpenGL in the form of a
+ texture object. */
+ public void updateOffscreenBuffer(OffscreenDesktopPane parent) {
+ boolean needsCopy = needsCopyBack();
+ boolean hadPrevBackBuffer = false;
+ super.updateOffscreenBuffer(parent);
+ Image img = getOffscreenBackBuffer();
+ final boolean mustResizeOGLTexture = ((oglTextureId == 0) ||
+ (img == null) ||
+ (prevBackBufferWidth != img.getWidth(null)) ||
+ (prevBackBufferHeight != img.getHeight(null)));
+ if (needsCopy) {
+ final Graphics g = getOffscreenGraphics();
+ // Capture off-screen buffer contents into OpenGL texture
+ Java2D.invokeWithOGLContextCurrent(g, new Runnable() {
+ public void run() {
+ // Get valid Java2D context
+ if (j2dContext == null ||
+ j2dContextSurfaceIdentifier != Java2D.getOGLSurfaceIdentifier(g)) {
+ j2dContext = GLDrawableFactory.getFactory().createExternalGLContext();
+ j2dContext.setGL(new DebugGL(j2dContext.getGL()));
+ j2dContextSurfaceIdentifier = Java2D.getOGLSurfaceIdentifier(g);
+ }
+
+ j2dContext.makeCurrent(); // No-op
+ try {
+ GL gl = j2dContext.getGL();
+
+ if (oglTextureId == 0) {
+ // Set up and initialize texture
+ int[] tmp = new int[1];
+
+ gl.glGenTextures(1, tmp, 0);
+ oglTextureId = tmp[0];
+ if (oglTextureId == 0) {
+ throw new RuntimeException("Error generating OpenGL back buffer texture");
+ }
+ assert mustResizeOGLTexture : "Must know we need to resize";
+ }
+
+ gl.glBindTexture(textureTarget, oglTextureId);
+
+ int offscreenWidth = getOffscreenBackBufferWidth();
+ int offscreenHeight = getOffscreenBackBufferHeight();
+
+ if (mustResizeOGLTexture) {
+ prevBackBufferWidth = offscreenWidth;
+ prevBackBufferHeight = offscreenHeight;
+
+ gl.glTexImage2D(textureTarget,
+ 0,
+ GL.GL_RGBA8,
+ offscreenWidth,
+ offscreenHeight,
+ 0,
+ GL.GL_RGBA,
+ GL.GL_UNSIGNED_BYTE,
+ null);
+ }
+
+ // Copy texture from offscreen buffer
+ // NOTE: assumes read buffer is set up
+ // FIXME: could be more efficient by copying only bounding rectangle
+
+ gl.glPixelStorei(GL.GL_UNPACK_SWAP_BYTES, GL.GL_FALSE);
+ gl.glPixelStorei(GL.GL_PACK_SWAP_BYTES, GL.GL_FALSE);
+ gl.glPixelStorei(GL.GL_UNPACK_LSB_FIRST, GL.GL_FALSE);
+ gl.glPixelStorei(GL.GL_PACK_LSB_FIRST, GL.GL_FALSE);
+ gl.glPixelStorei(GL.GL_UNPACK_ROW_LENGTH, 0);
+ gl.glPixelStorei(GL.GL_PACK_ROW_LENGTH, 0);
+ gl.glPixelStorei(GL.GL_UNPACK_SKIP_ROWS, 0);
+ gl.glPixelStorei(GL.GL_PACK_SKIP_ROWS, 0);
+ gl.glPixelStorei(GL.GL_UNPACK_SKIP_PIXELS, 0);
+ gl.glPixelStorei(GL.GL_PACK_SKIP_PIXELS, 0);
+ gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1);
+ gl.glPixelStorei(GL.GL_PACK_ALIGNMENT, 1);
+ gl.glPixelTransferf(GL.GL_RED_SCALE, 1);
+ gl.glPixelTransferf(GL.GL_GREEN_SCALE, 1);
+ gl.glPixelTransferf(GL.GL_BLUE_SCALE, 1);
+ gl.glPixelTransferf(GL.GL_ALPHA_SCALE, 1);
+ gl.glPixelTransferf(GL.GL_RED_BIAS, 0);
+ gl.glPixelTransferf(GL.GL_GREEN_BIAS, 0);
+ gl.glPixelTransferf(GL.GL_BLUE_BIAS, 0);
+ gl.glPixelTransferf(GL.GL_ALPHA_BIAS, 0);
+
+ // long start = System.currentTimeMillis();
+ gl.glCopyTexSubImage2D(textureTarget,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ offscreenWidth,
+ offscreenHeight);
+ // long end = System.currentTimeMillis();
+ // System.err.println("glCopyTexSubImage2D " + offscreenWidth + "x" + offscreenHeight + " took " + (end - start) + " ms");
+
+ } finally {
+ j2dContext.release();
+ }
+ }
+ });
+ }
+ }
+
+ // Ideally we would force a repaint only of the 2D bounds of the 3D
+ // component projected onto the desktop. However for expedience
+ // we'll currently just repaint the entire desktop to get correct
+ // results.
+ protected void repaintPortionOfDesktop(JDesktopPane desktop, Component comp) {
+ desktop.repaint();
+ }
+}