From d6f9dbc493df725d3d574403549de142c5e1222a Mon Sep 17 00:00:00 2001 From: Kenneth Russel Date: Mon, 24 Oct 2005 19:21:03 +0000 Subject: Merged JSR-231 branch on to the main JOGL trunk. The main trunk now contains the evolving JSR-231 Reference Implementation and the JSR-231 branch is permanently closed. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@401 232f8b59-042b-4e1e-8c03-345bb8c30851 --- src/net/java/games/jogl/GLJPanel.java | 730 ---------------------------------- 1 file changed, 730 deletions(-) delete mode 100644 src/net/java/games/jogl/GLJPanel.java (limited to 'src/net/java/games/jogl/GLJPanel.java') diff --git a/src/net/java/games/jogl/GLJPanel.java b/src/net/java/games/jogl/GLJPanel.java deleted file mode 100644 index e9b58bdae..000000000 --- a/src/net/java/games/jogl/GLJPanel.java +++ /dev/null @@ -1,730 +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 net.java.games.jogl; - -import java.awt.Component; -import java.awt.EventQueue; -import java.awt.Frame; -import java.awt.Graphics; -import java.awt.GraphicsConfiguration; -import java.awt.Rectangle; -import java.awt.image.BufferedImage; -import java.awt.image.DataBufferByte; -import java.awt.image.DataBufferInt; -import java.security.*; -import javax.swing.JComponent; -import javax.swing.JPanel; -import net.java.games.jogl.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. This component attempts to - use hardware-accelerated rendering via pbuffers and falls back on - to software rendering if problems occur. This class can not be - instantiated directly; use {@link GLDrawableFactory} to construct - them.

- - 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. -*/ - -public final class GLJPanel extends JPanel implements GLDrawable { - protected static final boolean DEBUG = Debug.debug("GLJPanel"); - - private GLDrawableHelper drawableHelper = new GLDrawableHelper(); - private volatile boolean isInitialized; - - // Data used for either pbuffers or pixmap-based offscreen surfaces - private GLCapabilities offscreenCaps; - private GLCapabilitiesChooser chooser; - private GLDrawable 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 byte[] readBackBytes; - private int[] 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; - - // Implementation using pbuffers - private static boolean hardwareAccelerationDisabled = - Debug.isPropertyDefined("jogl.gljpanel.nohw"); - private boolean pbufferInitializationCompleted; - private GLPbuffer pbuffer; - private int pbufferWidth = 256; - private int pbufferHeight = 256; - private GLCanvas heavyweight; - private Frame toplevel; - - // Implementation using software rendering - private GLContext offscreenContext; - - // 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]; - - GLJPanel(GLCapabilities capabilities, GLCapabilitiesChooser chooser, GLDrawable shareWith) { - super(); - - // Works around problems on many vendors' cards; we don't need a - // back buffer for the offscreen surface anyway - offscreenCaps = (GLCapabilities) capabilities.clone(); - offscreenCaps.setDoubleBuffered(false); - this.chooser = chooser; - this.shareWith = shareWith; - } - - public void display() { - if (!isInitialized) { - return; - } - - 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); - } - } - } - - /** Overridden from JComponent; calls {@link - GLEventListener#display}. Should not be invoked by applications - directly. */ - public void paintComponent(Graphics g) { - if (!isInitialized) { - return; - } - - updater.setGraphics(g); - if (!hardwareAccelerationDisabled) { - if (!pbufferInitializationCompleted) { - try { - heavyweight.display(); - pbuffer.display(); - } catch (GLException e) { - if (DEBUG) { - e.printStackTrace(); - } - // We consider any exception thrown during updating of the - // heavyweight or pbuffer during the initialization phases - // to be an indication that there was a problem - // instantiating the pbuffer, regardless of whether the - // exception originated in the user's GLEventListener. In - // these cases we immediately back off and use software - // rendering. - disableHardwareRendering(); - } - } else { - pbuffer.display(); - } - } else { - offscreenContext.invokeGL(displayAction, false, initAction); - } - } - - public void addNotify() { - super.addNotify(); - initialize(); - if (DEBUG) { - System.err.println("GLJPanel.addNotify()"); - } - } - - /** Overridden from JPanel; used to indicate that it's no longer - safe to have an OpenGL context for the component. */ - public void removeNotify() { - if (DEBUG) { - System.err.println("GLJPanel.removeNotify()"); - } - if (!hardwareAccelerationDisabled) { - if (pbuffer != null) { - pbuffer.destroy(); - } - if (toplevel != null) { - toplevel.dispose(); - } - pbuffer = null; - heavyweight = null; - toplevel = null; - } else { - offscreenContext.destroy(); - } - isInitialized = false; - super.removeNotify(); - } - - /** Overridden from Canvas; causes {@link GLDrawableHelper#reshape} - to be called on all registered {@link GLEventListener}s. Called - automatically by the AWT; should not be invoked by applications - directly. */ - public void reshape(int x, int y, int width, int height) { - super.reshape(x, y, width, height); - - if (!isInitialized) { - return; - } - - // Move all reshape requests onto AWT EventQueue thread - final int fx = x; - final int fy = y; - final int fwidth = width; - final int fheight = height; - - Runnable r = new Runnable() { - public void run() { - GLContext context = null; - readBackWidthInPixels = 0; - readBackHeightInPixels = 0; - - if (!hardwareAccelerationDisabled) { - // Use factor larger than 2 during shrinks for some hysteresis - float shrinkFactor = 2.5f; - if ((fwidth > pbufferWidth ) || (fheight > pbufferHeight) || - (fwidth < (pbufferWidth / shrinkFactor)) || (fheight < (pbufferWidth / shrinkFactor))) { - if (DEBUG) { - System.err.println("Resizing pbuffer from (" + pbufferWidth + ", " + pbufferHeight + ") " + - " to fit (" + fwidth + ", " + fheight + ")"); - } - // Must destroy and recreate pbuffer to fit - if (pbuffer != null) { - pbuffer.destroy(); - } - if (toplevel != null) { - toplevel.dispose(); - } - pbuffer = null; - isInitialized = false; - pbufferWidth = getNextPowerOf2(fwidth); - pbufferHeight = getNextPowerOf2(fheight); - if (DEBUG) { - System.err.println("New pbuffer size is (" + pbufferWidth + ", " + pbufferHeight + ")"); - } - initialize(); - } - GLPbufferImpl pbufferImpl = (GLPbufferImpl) pbuffer; - context = pbufferImpl.getContext(); - // 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... - readBackWidthInPixels = pbufferWidth; - readBackHeightInPixels = fheight; - } else { - offscreenContext.resizeOffscreenContext(fwidth, fheight); - context = offscreenContext; - readBackWidthInPixels = fwidth; - readBackHeightInPixels = fheight; - } - - if (offscreenImage != null) { - offscreenImage.flush(); - offscreenImage = null; - } - - panelWidth = fwidth; - panelHeight = fheight; - - context.invokeGL(new Runnable() { - public void run() { - getGL().glViewport(0, 0, panelWidth, panelHeight); - drawableHelper.reshape(GLJPanel.this, 0, 0, panelWidth, panelHeight); - } - }, true, initAction); - } - }; - if (EventQueue.isDispatchThread()) { - r.run(); - } else { - // Avoid blocking EventQueue thread due to possible deadlocks - // during component creation - EventQueue.invokeLater(r); - } - } - - 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 GL getGL() { - if (!hardwareAccelerationDisabled) { - if (pbuffer == null) { - return null; - } - return pbuffer.getGL(); - } else { - if (offscreenContext == null) { - return null; - } - return offscreenContext.getGL(); - } - } - - public void setGL(GL gl) { - if (!hardwareAccelerationDisabled) { - if (pbuffer != null) { - pbuffer.setGL(gl); - } - } else { - if (offscreenContext != null) { - offscreenContext.setGL(gl); - } - } - } - - public GLU getGLU() { - if (!hardwareAccelerationDisabled) { - return pbuffer.getGLU(); - } else { - return offscreenContext.getGLU(); - } - } - - public void setGLU(GLU glu) { - if (!hardwareAccelerationDisabled) { - pbuffer.setGLU(glu); - } else { - offscreenContext.setGLU(glu); - } - } - - public void setRenderingThread(Thread currentThreadOrNull) throws GLException { - // Not supported for GLJPanel because all repaint requests must be - // handled by the AWT thread - } - - public Thread getRenderingThread() { - return null; - } - - public void setNoAutoRedrawMode(boolean noAutoRedraws) { - } - - public boolean getNoAutoRedrawMode() { - return false; - } - - public void setAutoSwapBufferMode(boolean onOrOff) { - if (!hardwareAccelerationDisabled) { - pbuffer.setAutoSwapBufferMode(onOrOff); - } else { - offscreenContext.setAutoSwapBufferMode(onOrOff); - } - } - - public boolean getAutoSwapBufferMode() { - if (!hardwareAccelerationDisabled) { - return pbuffer.getAutoSwapBufferMode(); - } else { - return offscreenContext.getAutoSwapBufferMode(); - } - } - - public void swapBuffers() { - if (!hardwareAccelerationDisabled) { - pbuffer.swapBuffers(); - } else { - offscreenContext.invokeGL(swapBuffersAction, false, initAction); - } - } - - public boolean canCreateOffscreenDrawable() { - // For now let's say no, although we could using the heavyweight - // if hardware acceleration is still enabled - return false; - } - - public GLPbuffer createOffscreenDrawable(GLCapabilities capabilities, - int initialWidth, - int initialHeight) { - throw new GLException("Not supported"); - } - - GLContext getContext() { - if (!hardwareAccelerationDisabled) { - return ((GLPbufferImpl) pbuffer).getContext(); - } else { - return offscreenContext; - } - } - - //---------------------------------------------------------------------- - // Internals only below this point - // - - private void disableHardwareRendering() { - if (Debug.verbose()) { - System.err.println("GLJPanel: Falling back on software rendering due to pbuffer problems"); - } - hardwareAccelerationDisabled = true; - pbufferInitializationCompleted = false; - EventQueue.invokeLater(new Runnable() { - public void run() { - toplevel.setVisible(false); - // Should dispose of this -- not sure about stability on - // various cards -- should test (FIXME) - // toplevel.dispose(); - } - }); - initialize(); - } - - private void initialize() { - // Initialize either the hardware-accelerated rendering path or - // the lightweight rendering path - if (!hardwareAccelerationDisabled) { - boolean firstTime = false; - if (heavyweight == null) { - // Make the heavyweight share with the "shareWith" parameter. - // The pbuffer shares textures and display lists with the - // heavyweight, so by transitivity the pbuffer will share with - // it as well. - heavyweight = GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities(), shareWith); - firstTime = true; - } - if (heavyweight.canCreateOffscreenDrawable()) { - if (firstTime) { - toplevel = new Frame(); - toplevel.setUndecorated(true); - } - pbuffer = heavyweight.createOffscreenDrawable(offscreenCaps, pbufferWidth, pbufferHeight); - updater = new Updater(); - pbuffer.addGLEventListener(updater); - pbufferInitializationCompleted = false; - if (firstTime) { - toplevel.add(heavyweight); - toplevel.setSize(1, 1); - } - EventQueue.invokeLater(new Runnable() { - public void run() { - try { - toplevel.setVisible(true); - } catch (GLException e) { - if (DEBUG) { - e.printStackTrace(); - } - disableHardwareRendering(); - } - } - }); - isInitialized = true; - return; - } else { - // If the heavyweight reports that it can't create an - // offscreen drawable (pbuffer), don't try again the next - // time, and fall through to the software rendering path - hardwareAccelerationDisabled = true; - } - } - - // Create an offscreen context instead - offscreenContext = GLContextFactory.getFactory().createGLContext(null, offscreenCaps, chooser, - GLContextHelper.getContext(shareWith)); - offscreenContext.resizeOffscreenContext(panelWidth, panelHeight); - updater = new Updater(); - if (panelWidth > 0 && panelHeight > 0) { - offscreenContext.invokeGL(new Runnable() { - public void run() { - getGL().glViewport(0, 0, panelWidth, panelHeight); - drawableHelper.reshape(GLJPanel.this, 0, 0, panelWidth, panelHeight); - } - }, true, initAction); - } - - isInitialized = true; - } - - class Updater implements GLEventListener { - private Graphics g; - - public void setGraphics(Graphics g) { - this.g = g; - } - - public void init(GLDrawable drawable) { - if (!hardwareAccelerationDisabled) { - if (DEBUG) { - System.err.println("GLJPanel$Updater.init(): pbufferInitializationCompleted = true"); - } - pbufferInitializationCompleted = true; - EventQueue.invokeLater(new Runnable() { - public void run() { - // Race conditions might dispose of this before now - if (toplevel != null) { - toplevel.setVisible(false); - } - } - }); - } - drawableHelper.init(GLJPanel.this); - } - - public void display(GLDrawable drawable) { - drawableHelper.display(GLJPanel.this); - - // 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 = new byte[readBackWidthInPixels * readBackHeightInPixels * 3]; - break; - - case BufferedImage.TYPE_INT_RGB: - case BufferedImage.TYPE_INT_ARGB: - glFormat = GL.GL_BGRA; - glType = (hardwareAccelerationDisabled - ? offscreenContext.getOffscreenContextPixelDataType() - : hwGLFormat); - readBackInts = new int[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); - gl.glGetIntegerv(GL.GL_PACK_ROW_LENGTH, rowlength); - gl.glGetIntegerv(GL.GL_PACK_SKIP_ROWS, skiprows); - gl.glGetIntegerv(GL.GL_PACK_SKIP_PIXELS, skippixels); - gl.glGetIntegerv(GL.GL_PACK_ALIGNMENT, alignment); - - 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; - dest = ((DataBufferByte) offscreenImage.getRaster().getDataBuffer()).getData(); - srcIncr = readBackWidthInPixels * 3; - destIncr = offscreenImage.getWidth() * 3; - } else { - src = readBackInts; - 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); - } - } - - // Draw resulting image in one shot - g.drawImage(offscreenImage, 0, 0, offscreenImage.getWidth(), offscreenImage.getHeight(), GLJPanel.this); - } - } - } - - public void reshape(GLDrawable drawable, int x, int y, int width, int height) { - // This is handled above and dispatched directly to the appropriate context - } - - public void displayChanged(GLDrawable 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() { - offscreenContext.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<