diff options
Diffstat (limited to 'src/net/java/games/jogl/GLJPanel.java')
-rw-r--r-- | src/net/java/games/jogl/GLJPanel.java | 316 |
1 files changed, 316 insertions, 0 deletions
diff --git a/src/net/java/games/jogl/GLJPanel.java b/src/net/java/games/jogl/GLJPanel.java new file mode 100644 index 000000000..787a4a8cc --- /dev/null +++ b/src/net/java/games/jogl/GLJPanel.java @@ -0,0 +1,316 @@ +/* + * 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 + * MIDROSYSTEMS, 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.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 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. Currently implemented using + offscreen (i.e., non-hardware accelerated) rendering, so + performance will likely be poor. This class can not be + instantiated directly; use {@link GLDrawableFactory} to construct + them. */ + +public final class GLJPanel extends JPanel implements GLDrawable { + private GLCapabilities capabilities; + private GLCapabilitiesChooser chooser; + private GLDrawableHelper drawableHelper = new GLDrawableHelper(); + private GLContext context; + private BufferedImage offscreenImage; + private int awtFormat; + private int glFormat; + private int glType; + private int glComps; + private DataBufferByte dbByte; + private DataBufferInt dbInt; + private Object semaphore = new Object(); + private boolean repaintDone; + + // For saving/restoring of OpenGL state during ReadPixels + private int[] swapbytes = new int[1]; + private int[] lsbfirst = 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) { + super(); + this.capabilities = capabilities; + this.chooser = chooser; + } + + public void display() { + // Multithreaded redrawing of Swing components is not allowed + try { + synchronized(semaphore) { + repaintDone = false; + repaint(); + while (!repaintDone) { + semaphore.wait(); + } + } + } catch (InterruptedException e) { + } + } + + /** Overridden from JComponent; calls {@link #display}. Should not + be invoked by applications directly. */ + public void paintComponent(Graphics g) { + displayAction.setGraphics(g); + getContext().invokeGL(displayAction, false, initAction); + synchronized(semaphore) { + repaintDone = true; + semaphore.notifyAll(); + } + } + + /** 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); + // NOTE: we don't pay attention to the x and y provided since we + // are blitting into this component directly + final int fx = 0; + final int fy = 0; + final int fwidth = width; + final int fheight = height; + getContext().resizeOffscreenContext(width, height); + getContext().invokeGL(new Runnable() { + public void run() { + getGL().glViewport(fx, fy, fwidth, fheight); + drawableHelper.reshape(GLJPanel.this, fx, fy, fwidth, fheight); + if (offscreenImage != null && + (offscreenImage.getWidth() != getWidth() || + offscreenImage.getHeight() != getHeight())) { + offscreenImage.flush(); + offscreenImage = null; + } + } + }, true, initAction); + } + + public void addGLEventListener(GLEventListener listener) { + drawableHelper.addGLEventListener(listener); + } + + public void removeGLEventListener(GLEventListener listener) { + drawableHelper.removeGLEventListener(listener); + } + + public GL getGL() { + // must use getContext() because context is created lazily + return getContext().getGL(); + } + + public void setGL(GL gl) { + // must use getContext() because context is created lazily + getContext().setGL(gl); + } + + public GLU getGLU() { + // must use getContext() because context is created lazily + return getContext().getGLU(); + } + + public void setGLU(GLU glu) { + // must use getContext() because context is created lazily + getContext().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 getContext().getRenderingThread(); + } + + public void setNoAutoRedrawMode(boolean noAutoRedraws) { + } + + public boolean getNoAutoRedrawMode() { + return false; + } + + public boolean canCreateOffscreenDrawable() { + // For now let's say no; maybe we can reimplement this class in + // terms of pbuffers (though not all vendors support them, and + // they seem to require an onscreen context) + return false; + } + + public GLPbuffer createOffscreenDrawable(GLCapabilities capabilities, + int initialWidth, + int initialHeight) { + throw new GLException("Not supported"); + } + + //---------------------------------------------------------------------- + // Internals only below this point + // + + private GLContext getContext() { + if (context == null) { + context = GLContextFactory.getFactory().createGLContext(null, capabilities, chooser); + } + return context; + } + + class InitAction implements Runnable { + public void run() { + drawableHelper.init(GLJPanel.this); + } + } + private InitAction initAction = new InitAction(); + + class DisplayAction implements Runnable { + private Graphics g; + + public void setGraphics(Graphics g) { + this.g = g; + } + + public void run() { + drawableHelper.display(GLJPanel.this); + // Must now copy pixels from offscreen context into surface + if (offscreenImage == null) { + int awtFormat = getContext().getOffscreenContextBufferedImageType(); + offscreenImage = new BufferedImage(getWidth(), getHeight(), awtFormat); + switch (awtFormat) { + case BufferedImage.TYPE_3BYTE_BGR: + glFormat = GL.GL_BGR; + glType = GL.GL_UNSIGNED_BYTE; + glComps = 3; + dbByte = (DataBufferByte) offscreenImage.getRaster().getDataBuffer(); + break; + + case BufferedImage.TYPE_INT_RGB: + glFormat = GL.GL_BGRA; + glType = GL.GL_UNSIGNED_BYTE; + glComps = 4; + dbInt = (DataBufferInt) offscreenImage.getRaster().getDataBuffer(); + break; + + case BufferedImage.TYPE_INT_ARGB: + glFormat = GL.GL_BGRA; + glType = GL.GL_UNSIGNED_BYTE; + glComps = 4; + dbInt = (DataBufferInt) offscreenImage.getRaster().getDataBuffer(); + 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); + } + } + + GL gl = getGL(); + // Save current modes + gl.glGetIntegerv(GL.GL_PACK_SWAP_BYTES, swapbytes); + gl.glGetIntegerv(GL.GL_PACK_LSB_FIRST, lsbfirst); + 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); + + // Little endian machines (DEC Alpha, Intel X86, PPC (in LSB + // mode)... for example) could benefit from setting + // GL_PACK_LSB_FIRST to GL_TRUE instead of GL_FALSE, but this + // would require changing the generated bitmaps too. + gl.glPixelStorei(GL.GL_PACK_SWAP_BYTES, GL.GL_FALSE); + gl.glPixelStorei(GL.GL_PACK_LSB_FIRST, GL.GL_TRUE); + gl.glPixelStorei(GL.GL_PACK_ROW_LENGTH, getWidth()); + 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(context.getOffscreenContextReadBuffer()); + if (dbByte != null) { + gl.glReadPixels(0, 0, getWidth(), getHeight(), glFormat, glType, dbByte.getData()); + } else if (dbInt != null) { + gl.glReadPixels(0, 0, getWidth(), getHeight(), glFormat, glType, dbInt.getData()); + } + + // Restore saved modes. + gl.glPixelStorei(GL.GL_PACK_SWAP_BYTES, swapbytes[0]); + gl.glPixelStorei(GL.GL_PACK_LSB_FIRST, lsbfirst[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]); + + gl.glFlush(); + gl.glFinish(); + + if (context.offscreenImageNeedsVerticalFlip()) { + g.drawImage(offscreenImage, + 0, 0, getWidth(), getHeight(), + 0, getHeight(), getWidth(), 0, + GLJPanel.this); + } else { + g.drawImage(offscreenImage, 0, 0, getWidth(), getHeight(), GLJPanel.this); + } + } + } + private DisplayAction displayAction = new DisplayAction(); +} |