aboutsummaryrefslogtreecommitdiffstats
path: root/src/classes
diff options
context:
space:
mode:
authorAugust Lammersdorf <[email protected]>2013-01-26 09:00:23 -0800
committerHarvey Harrison <[email protected]>2013-02-18 22:24:39 -0800
commit167369e0df9044a86bf749425feedaa8a2f565b3 (patch)
treedfde5abfaaa4c12838672d9dafc1e30a0ef16baa /src/classes
parent3923249983f210fc562d8e51b1e6595537a641cf (diff)
j3dcore: changes from August Lammersdorf
Quoting August: 1. Mac OS X 10.7+ / Oracle JRE 7+ - new Pipeline method 'resizeOffscreenLayerSurface' - Renderer detects Canvas3D's size changes and performs offscreen layer resizing - Still required : fix of Mac/Oracle JRE/JOGL's x/y-positioning and z-ordering issues (see post above) - classes: Canvas3D, JoglPipeline, NoopPipeline, Pipeline, Renderer 2. Offscreen rendering - deprecated pbuffer replaced with framebuffer object - based on JOGL's FBO implementation GLFBODrawable and FBObject - pbuffer is still available if FBO isn't supported or not desired - double buffering and scene antialiasing support if requested and available - currently fixed number of samples: 4 - classes: Canvas3D, JoglPipeline, Renderer 3. Best configuration - Java 3D compliant GLCapabilitiesChooser introduced : J3DCapsChooser - Workaround if capability chooser isn't called (Mac/JRE 7) - class: JoglPipeline Signed-off-by: August Lammersdorf <[email protected]> Signed-off-by: Harvey Harrison <[email protected]>
Diffstat (limited to 'src/classes')
-rw-r--r--src/classes/share/javax/media/j3d/JoglPipeline.java1040
-rw-r--r--src/classes/share/javax/media/j3d/Renderer.java10
2 files changed, 782 insertions, 268 deletions
diff --git a/src/classes/share/javax/media/j3d/JoglPipeline.java b/src/classes/share/javax/media/j3d/JoglPipeline.java
index 075f33f..64956d9 100644
--- a/src/classes/share/javax/media/j3d/JoglPipeline.java
+++ b/src/classes/share/javax/media/j3d/JoglPipeline.java
@@ -26,6 +26,18 @@
package javax.media.j3d;
+import static javax.media.opengl.GL.GL_BACK;
+import static javax.media.opengl.GL.GL_FRONT;
+import static javax.media.opengl.GL.GL_FRONT_AND_BACK;
+import static javax.media.opengl.GL.GL_LEQUAL;
+import static javax.media.opengl.GL.GL_UNPACK_ALIGNMENT;
+import static javax.media.opengl.GL2.GL_LIGHT_MODEL_COLOR_CONTROL;
+import static javax.media.opengl.GL2.GL_SEPARATE_SPECULAR_COLOR;
+import static javax.media.opengl.GL2ES1.GL_RESCALE_NORMAL;
+import static javax.media.opengl.GL2GL3.GL_READ_BUFFER;
+import static javax.media.opengl.fixedfunc.GLLightingFunc.GL_COLOR_MATERIAL;
+import static javax.media.opengl.fixedfunc.GLLightingFunc.GL_DIFFUSE;
+
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.DisplayMode;
@@ -39,13 +51,13 @@ import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.nio.Buffer;
import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
import java.nio.DoubleBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
@@ -57,27 +69,28 @@ import com.jogamp.nativewindow.awt.AWTGraphicsScreen;
import com.jogamp.nativewindow.awt.JAWTWindow;
import com.jogamp.opengl.FBObject;
-import javax.media.nativewindow.AbstractGraphicsConfiguration;
+import javax.media.nativewindow.AbstractGraphicsDevice;
+import javax.media.nativewindow.AbstractGraphicsScreen;
import javax.media.nativewindow.CapabilitiesChooser;
import javax.media.nativewindow.CapabilitiesImmutable;
import javax.media.nativewindow.GraphicsConfigurationFactory;
-import javax.media.nativewindow.NativeWindow;
+import javax.media.nativewindow.NativeSurface;
import javax.media.nativewindow.NativeWindowFactory;
+import javax.media.nativewindow.ProxySurface;
+import javax.media.nativewindow.UpstreamSurfaceHook;
import javax.media.nativewindow.VisualIDHolder;
import javax.media.opengl.DefaultGLCapabilitiesChooser;
import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLCapabilitiesChooser;
+import javax.media.opengl.GLCapabilitiesImmutable;
import javax.media.opengl.GLContext;
import javax.media.opengl.GLDrawable;
import javax.media.opengl.GLDrawableFactory;
-import javax.media.opengl.GLException;
import javax.media.opengl.GLFBODrawable;
-import javax.media.opengl.GLPbuffer;
import javax.media.opengl.GLProfile;
import javax.media.opengl.Threading;
-import javax.media.opengl.glu.GLU;
import com.jogamp.common.nio.Buffers;
@@ -6163,64 +6176,173 @@ class JoglPipeline extends Pipeline {
// Canvas3D methods - native wrappers
//
+ // Mac/JRE 7; called from Renderer when resizing is dedected
+ // Implementation follows the approach in jogamp.opengl.GLDrawableHelper.resizeOffscreenDrawable(..)
+ void resizeOffscreenLayer(Canvas3D cv, int cvWidth, int cvHeight) {
+ if (!isOffscreenLayerSurfaceEnabled(cv))
+ return;
+
+ JoglDrawable joglDrawable = (JoglDrawable)cv.drawable;
+ if (!hasFBObjectSizeChanged(joglDrawable, cvWidth, cvHeight))
+ return;
+
+ int newWidth = Math.max(1, cvWidth);
+ int newHeight = Math.max(1, cvHeight);
+
+ GLDrawable glDrawble = joglDrawable.getGLDrawable();
+ GLContext glContext = ((JoglContext)cv.ctx).getGLContext();
+
+ // Assuming glContext != null
+
+ final NativeSurface surface = glDrawble.getNativeSurface();
+ final ProxySurface proxySurface = (surface instanceof ProxySurface) ? (ProxySurface)surface : null;
+
+ final int lockRes = surface.lockSurface();
+
+ try {
+ // propagate new size - seems not relevant here
+ if (proxySurface != null) {
+ final UpstreamSurfaceHook ush = proxySurface.getUpstreamSurfaceHook();
+ if (ush instanceof UpstreamSurfaceHook.MutableSize) {
+ ((UpstreamSurfaceHook.MutableSize)ush).setSize(newWidth, newHeight);
+ }
+ }
+ /*else if(DEBUG) { // we have to assume surface contains the new size already, hence size check @ bottom
+ System.err.println("GLDrawableHelper.resizeOffscreenDrawable: Drawable's offscreen surface n.a. ProxySurface, but "+ns.getClass().getName()+": "+ns);
+ }*/
+
+ GL2 gl = glContext.getGL().getGL2();
+
+ // FBO : should be the default case on Mac OS X
+ if (glDrawble instanceof GLFBODrawable) {
+
+ // Resize GLFBODrawable
+ // TODO msaa gets lost
+// ((GLFBODrawable)glDrawble).resetSize(gl);
+
+ // Alternative: resize GL_BACK FBObject directly,
+ // if multisampled the FBO sink (GL_FRONT) will be resized before the swap is executed
+ int numSamples = ((GLFBODrawable)glDrawble).getChosenGLCapabilities().getNumSamples();
+ FBObject fboObjectBack = ((GLFBODrawable)glDrawble).getFBObject( GL_BACK );
+ fboObjectBack.reset(gl, newWidth, newHeight, numSamples, false); // false = don't reset SamplingSinkFBO immediately
+ fboObjectBack.bind(gl);
+
+ // If double buffered without antialiasing the GL_FRONT FBObject
+ // will be resized by glDrawble after the next swap-call
+ }
+ // pbuffer - not tested because Mac OS X 10.7+ supports FBO
+ else {
+ // Create new GLDrawable (pbuffer) and update the coresponding GLContext
+
+ final GLContext currentContext = GLContext.getCurrent();
+ final GLDrawableFactory factory = glDrawble.getFactory();
+
+ // Ensure to sync GL command stream
+ if (currentContext != glContext) {
+ glContext.makeCurrent();
+ }
+ gl.glFinish();
+ glContext.release();
+
+ if (proxySurface != null) {
+ proxySurface.enableUpstreamSurfaceHookLifecycle(false);
+ }
+
+ try {
+ glDrawble.setRealized(false);
+ // New GLDrawable
+ glDrawble = (GLDrawable)factory.createGLDrawable(surface);
+ glDrawble.setRealized(true);
+
+ joglDrawable.setGLDrawable(glDrawble);
+ }
+ finally {
+ if (proxySurface != null) {
+ proxySurface.enableUpstreamSurfaceHookLifecycle(true);
+ }
+ }
+
+ glContext.setGLDrawable(glDrawble, true); // re-association
+
+ // make current last current context
+ if (currentContext != null) {
+ currentContext.makeCurrent();
+ }
+ }
+ }
+ finally {
+ surface.unlockSurface();
+ }
+ }
+
// This is the native method for creating the underlying graphics context.
Context createNewContext(Canvas3D cv, Drawable drawable,
Context shareCtx, boolean isSharedCtx,
boolean offScreen) {
if (VERBOSE) System.err.println("JoglPipeline.createNewContext()");
- GLDrawable draw = null;
- GLCapabilitiesChooser indexChooser = null;
- JoglGraphicsConfiguration config = (JoglGraphicsConfiguration) cv.graphicsConfiguration;
- if (config.getChosenIndex() >= 0) {
- indexChooser = new IndexCapabilitiesChooser(config.getChosenIndex());
- }
- if (cv.drawable == null) {
- AWTGraphicsScreen awtGraphicsScreen = new AWTGraphicsScreen(config.getAwtGraphicsDevice());
- GraphicsConfigurationFactory factory = GraphicsConfigurationFactory.getFactory(config.getAwtGraphicsDevice().getClass(), GLCapabilities.class);
- AWTGraphicsConfiguration awtGraphicsConfiguration = (AWTGraphicsConfiguration)factory.chooseGraphicsConfiguration(config.getGLCapabilities(),
- config.getGLCapabilities(),
- indexChooser, awtGraphicsScreen, VisualIDHolder.VID_UNDEFINED);
- NativeWindow nativeWindow = NativeWindowFactory.getNativeWindow(cv, awtGraphicsConfiguration);
- draw = GLDrawableFactory.getFactory(profile).createGLDrawable(nativeWindow);
- cv.drawable = new JoglDrawable(draw, null);
- } else {
- draw = drawable(cv.drawable);
+
+ GLDrawable glDrawable = null;
+ GLContext glContext = null;
+
+ if (offScreen) {
+ glDrawable = drawable(cv.drawable); // cv.drawable != null, set in 'createOffScreenBuffer'
+ glContext = glDrawable.createContext(context(shareCtx));
+ }
+ else {
+ // determined in 'getBestConfiguration'
+ GraphicsConfigInfo gcInf0 = Canvas3D.graphicsConfigTable.get(cv.graphicsConfiguration);
+ AWTGraphicsConfiguration awtConfig = (AWTGraphicsConfiguration)gcInf0.getPrivateData();
+
+ // JAWTWindow
+ JAWTWindow nativeWindow = (JAWTWindow)NativeWindowFactory.getNativeWindow(cv, awtConfig);
+ nativeWindow.lockSurface();
+ try {
+ glDrawable = GLDrawableFactory.getFactory(profile).createGLDrawable(nativeWindow);
+ glContext = glDrawable.createContext(context(shareCtx));
+ }
+ finally {
+ nativeWindow.unlockSurface();
+ }
+
+ cv.drawable = new JoglDrawable(glDrawable, nativeWindow);
}
- // FIXME: assuming that this only gets called after addNotify has been called
- draw.setRealized(true);
- GLContext context = draw.createContext(context(shareCtx));
+ // assuming that this only gets called after addNotify has been called
+ glDrawable.setRealized(true);
- // Apparently we are supposed to make the context current at
- // this point and set up a bunch of properties
+ // Apparently we are supposed to make the context current at this point
+ // and set up a bunch of properties
// Work around for some low end graphics driver bug, such as Intel Chipset.
- // Issue 324 : Lockup Java3D program and throw exception using JOGL renderer
+ // Issue 324 : Lockup J3D program and throw exception using JOGL renderer
boolean failed = false;
int failCount = 0;
int MAX_FAIL_COUNT = 5;
do {
failed = false;
- int res = context.makeCurrent();
+ int res = glContext.makeCurrent();
if (res == GLContext.CONTEXT_NOT_CURRENT) {
// System.err.println("makeCurrent fail : " + failCount);
failed = true;
++failCount;
try {
Thread.sleep(100);
- } catch (InterruptedException e) {
+ }
+ catch (InterruptedException e) {
}
}
} while (failed && (failCount < MAX_FAIL_COUNT));
+
if (failCount == MAX_FAIL_COUNT) {
throw new IllegalRenderingStateException("Unable to make new context current after " + failCount + "tries");
}
- GL2 gl = context.getGL().getGL2();
- JoglContext ctx = new JoglContext(context);
+ GL2 gl = glContext.getGL().getGL2();
+
+ JoglContext ctx = new JoglContext(glContext);
try {
- if (!getPropertiesFromCurrentContext(ctx)) {
+ if (!getPropertiesFromCurrentContext(ctx, gl)) {
throw new IllegalRenderingStateException("Unable to fetch properties from current OpenGL context");
}
@@ -6230,21 +6352,67 @@ class JoglPipeline extends Pipeline {
}
// Enable rescale normal
- gl.glEnable(GL2.GL_RESCALE_NORMAL);
+ gl.glEnable(GL_RESCALE_NORMAL);
- gl.glColorMaterial(GL.GL_FRONT_AND_BACK, GL2.GL_DIFFUSE);
- gl.glDepthFunc(GL.GL_LEQUAL);
- gl.glEnable(GL2.GL_COLOR_MATERIAL);
- gl.glReadBuffer(GL.GL_FRONT);
+ gl.glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
+ gl.glDepthFunc(GL_LEQUAL);
+ gl.glEnable(GL_COLOR_MATERIAL);
+
+ /*
+ OpenGL specs:
+ glReadBuffer specifies a color buffer as the source for subsequent glReadPixels.
+ This source mode is initially GL_FRONT in single-buffered and GL_BACK in double-buffered configurations.
+
+ We leave this mode unchanged in on-screen rendering and adjust it in off-screen rendering. See below.
+ */
+// gl.glReadBuffer(GL_FRONT); // off window, default for single-buffered non-stereo window
// Issue 417: JOGL: Mip-mapped NPOT textures rendered incorrectly
- // Java 3D images are aligned to 1 byte
- gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1);
+ // J3D images are aligned to 1 byte
+ gl.glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// Workaround for issue 400: Enable separate specular by default
- gl.glLightModeli(GL2.GL_LIGHT_MODEL_COLOR_CONTROL, GL2.GL_SEPARATE_SPECULAR_COLOR);
- } finally {
- context.release();
+ gl.glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
+
+
+ // Mac OS X / JRE 7 : onscreen rendering = offscreen rendering
+ // bind FBO
+ if (!offScreen && glDrawable instanceof GLFBODrawable) {
+ GLFBODrawable fboDrawable = (GLFBODrawable)glDrawable;
+ // bind GLFBODrawable's drawing FBObject
+ // GL_BACK returns the correct FBOObject for single/double buffering, incl. multisampling
+ fboDrawable.getFBObject( GL_BACK ).bind(gl);
+ }
+
+
+ // FBO or pbuffer
+ if (offScreen) {
+
+ // Final caps
+ GLCapabilitiesImmutable chosenCaps = glDrawable.getChosenGLCapabilities();
+
+ // FBO
+ if (glDrawable instanceof GLFBODrawable) {
+ GLFBODrawable fboDrawable = (GLFBODrawable)glDrawable;
+ // bind GLFBODrawable's drawing FBObject
+ // GL_BACK returns the correct FBOObject for single/double buffering, incl. multisampling
+ fboDrawable.getFBObject( GL_BACK ).bind(gl);
+ }
+ // pbuffer
+ else {
+ // Double buffering: read from back buffer, as we don't swap
+ // Even this setting is identical to the initially mode it is set explicitly
+ if (chosenCaps.getDoubleBuffered()) {
+ gl.glReadBuffer(GL_BACK);
+ }
+ else {
+ gl.glReadBuffer(GL_FRONT);
+ }
+ }
+ }
+ }
+ finally {
+ glContext.release();
}
return ctx;
@@ -6254,26 +6422,50 @@ class JoglPipeline extends Pipeline {
boolean offScreen, int width, int height) {
if (VERBOSE) System.err.println("JoglPipeline.createQueryContext()");
- // FIXME: for now, ignoring the "offscreen" flag -- unclear how
- // to create an offscreen buffer at this point -- very likely
- // need Canvas3D.offScreenBufferInfo promoted to an Object --
- // this logic will need to be revisited to make sure we capture
- // all of the functionality of the NativePipeline
+ // Assumes createQueryContext is never called for a drawable != null
+
+ if (offScreen) {
+
+ Drawable offDrawable = createOffScreenBuffer(cv, null, width, height);
+
+ GLDrawable glDrawable = drawable(offDrawable);
+
+ glDrawable.setRealized(true);
+
+ GLContext glContext = glDrawable.createContext(null);
+ glContext.makeCurrent();
+
+ JoglContext ctx = new JoglContext(glContext);
+
+ GL2 gl = glContext.getGL().getGL2();
+
+ // get current context properties
+ getPropertiesFromCurrentContext(ctx, gl);
+ // Set up fields in Canvas3D
+ setupCanvasProperties(cv, ctx, gl);
+
+ // Done !
+
+ glContext.release();
+ glContext.destroy();
+ glDrawable.setRealized(false);
+ }
+ else {
+
+ // TODO can't find an implementation which avoids the use of QueryCanvas
+ // JOGL requires a visible Frame for an onscreen context
Frame f = new Frame();
f.setUndecorated(true);
f.setLayout(new BorderLayout());
- GLCapabilities caps = new GLCapabilities(profile);
+
ContextQuerier querier = new ContextQuerier(cv);
- // FIXME: should know what GraphicsDevice on which to create
- // this Canvas / Frame, and this should probably be known from
- // the incoming "display" parameter
- JoglGraphicsConfiguration joglGraphicsConfiguration = (JoglGraphicsConfiguration) cv.graphicsConfiguration;
- AWTGraphicsDevice awtGraphicsDevice = joglGraphicsConfiguration.getAwtGraphicsDevice();
- AWTGraphicsConfiguration awtGraphicsConfiguration = createAwtGraphicsConfiguration(caps, querier, awtGraphicsDevice/*null*/);
+ AWTGraphicsConfiguration awtConfig =
+ (AWTGraphicsConfiguration)Canvas3D.graphicsConfigTable.get(cv.graphicsConfiguration).getPrivateData();
+
+ QueryCanvas canvas = new QueryCanvas(awtConfig, querier);
- QueryCanvas canvas = new QueryCanvas(awtGraphicsConfiguration, querier);
f.add(canvas, BorderLayout.CENTER);
f.setSize(MIN_FRAME_SIZE, MIN_FRAME_SIZE);
f.setVisible(true);
@@ -6284,7 +6476,8 @@ class JoglPipeline extends Pipeline {
if (!querier.done()) {
try {
querier.wait(WAIT_TIME);
- } catch (InterruptedException e) {
+ }
+ catch (InterruptedException e) {
}
}
}
@@ -6292,49 +6485,108 @@ class JoglPipeline extends Pipeline {
disposeOnEDT(f);
}
+ }
// This is the native for creating an offscreen buffer
Drawable createOffScreenBuffer(Canvas3D cv, Context ctx, int width, int height) {
if (VERBOSE) System.err.println("JoglPipeline.createOffScreenBuffer()");
- // Note 1: when this is called, the incoming Context argument is
- // null because (obviously) no drawable or context has been
- // created for the Canvas3D yet.
+ // ctx unused, doesn't exist yet
+
+ // Offscreen Canvas3D's JoglGraphicsConfiguration
+ JoglGraphicsConfiguration jgc = (JoglGraphicsConfiguration)cv.graphicsConfiguration;
- // Note 2: we ignore the global j3d.usePbuffer flag; JOGL
- // doesn't expose pixmap/bitmap surfaces in its public API.
+ // Retrieve the offscreen Canvas3D's GraphicsConfigInfo
+ GraphicsConfigInfo gcInf0 = Canvas3D.graphicsConfigTable.get(jgc);
- // First pick up the JoglGraphicsConfiguration and from there
- // the GLCapabilities from the Canvas3D
- JoglGraphicsConfiguration jcfg = (JoglGraphicsConfiguration) cv.graphicsConfiguration;
- // Note that we ignore any chosen index from a prior call to getBestConfiguration();
- // those only enumerate the on-screen visuals, and we need to find one which is
- // pbuffer capable
- GLCapabilities caps = jcfg.getGLCapabilities();
+ // Offscreen Canvas3D's graphics configuration, determined in 'getBestConfiguration'
+ AWTGraphicsConfiguration awtConfig = (AWTGraphicsConfiguration)gcInf0.getPrivateData();
- //FIXME use the real AWTGraphicsDevice
- GLPbuffer pbuffer = GLDrawableFactory.getFactory(profile).createGLPbuffer(GLDrawableFactory.getDesktopFactory().getDefaultDevice() ,caps, null,width, height, GLContext.getCurrent());
+ // TODO Offscreen Canvas3D's graphics devise, determined in 'getBestConfiguration'
+ //AbstractGraphicsDevice device = awtConfig.getScreen().getDevice(); // throws exception
+ // Alternative: default graphics device
+ AbstractGraphicsDevice device = GLDrawableFactory.getDesktopFactory().getDefaultDevice();
- return new JoglDrawable(pbuffer, null);
+ // Offscreen Canvas3D's capabilites, determined in 'getBestConfiguration'
+ GLCapabilities canvasCaps = (GLCapabilities)awtConfig.getChosenCapabilities();
+
+ // For further investigations : the user's GraphicsConfigTemplate3D (not used yet)
+ GraphicsConfigTemplate3D gct3D = gcInf0.getGraphicsConfigTemplate3D();
+
+
+ // Assuming that the offscreen drawable will/can support the chosen GLCapabilities
+ // of the offscreen Canvas3D
+
+ final GLCapabilities offCaps = new GLCapabilities(profile);
+ offCaps.copyFrom(canvasCaps);
+
+ // double bufffering only if scene antialiasing is required/preferred and supported
+ if (offCaps.getSampleBuffers() == false) {
+ offCaps.setDoubleBuffered(false);
+ offCaps.setNumSamples(0);
+ }
+
+ // Never stereo
+ offCaps.setStereo(false);
+
+ // Set preferred offscreen drawable : framebuffer object (FBO) or pbuffer
+ offCaps.setFBO(true); // switches to pbuffer if FBO is not supported
+ // caps.setPBuffer(true);
+
+ // !! a 'null' capability chooser; JOGL doesn't call a chooser for offscreen drawable
+
+ // If FBO : 'offDrawable' is of type javax.media.opengl.GLFBODrawable
+ GLDrawable offDrawable = GLDrawableFactory.getFactory(profile).createOffscreenDrawable(device, offCaps, null, width, height);
+
+// !! these chosen caps are not final as long as the corresponding context is made current
+//System.out.println("createOffScreenBuffer chosenCaps = " + offDrawable.getChosenGLCapabilities());
+
+ return new JoglDrawable(offDrawable, null);
}
+ // 'destroyContext' is called first if context exists
void destroyOffScreenBuffer(Canvas3D cv, Context ctx, Drawable drawable) {
if (VERBOSE) System.err.println("JoglPipeline.destroyOffScreenBuffer()");
- JoglDrawable jdraw = (JoglDrawable) drawable;
- GLPbuffer pbuffer = (GLPbuffer) jdraw.getGLDrawable();
- pbuffer.destroy();
+ // it is done in 'destroyContext'
}
// This is the native for reading the image from the offscreen buffer
void readOffScreenBuffer(Canvas3D cv, Context ctx, int format, int dataType, Object data, int width, int height) {
if (VERBOSE) System.err.println("JoglPipeline.readOffScreenBuffer()");
+ GLDrawable glDrawable = ((JoglDrawable)cv.drawable).getGLDrawable();
+ GLCapabilitiesImmutable chosenCaps = glDrawable.getChosenGLCapabilities();
+ GLFBODrawable fboDrawable = null;
+
GL2 gl = context(ctx).getGL().getGL2();
+
+ // If FBO
+ if (chosenCaps.isFBO()) {
+
+ fboDrawable = (GLFBODrawable)glDrawable;
+
+ if (chosenCaps.getDoubleBuffered()) {
+ // swap = resolve multisampling or flip back/front FBO
+ fboDrawable.swapBuffers();
+ // unbind texture render target, we read from FBO
+ gl.glBindTexture(GL.GL_TEXTURE_2D, 0);
+ }
+
+ // bind FBO for reading pixel data
+ // GL_FRONT = SamplingSinkFBO if double buffered and multisampled
+ // GL_FRONT if double buffered ( = GL_BAck before swap was called)
+ // GL_FRONT = GL_BACK if single buffered (single FBO)
+
+ fboDrawable.getFBObject( GL_FRONT ).bind(gl);
+ }
+ // else pbuffer
+
gl.glPixelStorei(GL2.GL_PACK_ROW_LENGTH, width);
gl.glPixelStorei(GL.GL_PACK_ALIGNMENT, 1);
int type = 0;
+
if((dataType == ImageComponentRetained.IMAGE_DATA_TYPE_BYTE_ARRAY) ||
(dataType == ImageComponentRetained.IMAGE_DATA_TYPE_BYTE_BUFFER)) {
@@ -6372,7 +6624,8 @@ class JoglPipeline extends Pipeline {
gl.glReadPixels(0, 0, width, height, type, GL.GL_UNSIGNED_BYTE, ByteBuffer.wrap((byte[]) data));
- } else if((dataType == ImageComponentRetained.IMAGE_DATA_TYPE_INT_ARRAY) ||
+ }
+ else if ((dataType == ImageComponentRetained.IMAGE_DATA_TYPE_INT_ARRAY) ||
(dataType == ImageComponentRetained.IMAGE_DATA_TYPE_INT_BUFFER)) {
int intType = GL2.GL_UNSIGNED_INT_8_8_8_8;
@@ -6417,14 +6670,19 @@ class JoglPipeline extends Pipeline {
gl.glPixelTransferf(GL2.GL_ALPHA_SCALE, 1.0f);
gl.glPixelTransferf(GL2.GL_ALPHA_BIAS, 0.0f);
}
-
- } else {
+ }
+ else {
throw new AssertionError("illegal image data type " + dataType);
+ }
+ // If FBO
+ if (chosenCaps.isFBO()) {
+ // bind FBO for drawing
+ fboDrawable.getFBObject( GL_BACK ).bind(gl);
}
}
-// The native method for swapBuffers
+ // The native method for swapBuffers - onscreen only
void swapBuffers(Canvas3D cv, Context ctx, Drawable drawable) {
if (VERBOSE) System.err.println("JoglPipeline.swapBuffers()");
GLDrawable draw = drawable(drawable);
@@ -6442,14 +6700,19 @@ void swapBuffers(Canvas3D cv, Context ctx, Drawable drawable) {
void destroyContext(Drawable drawable, Context ctx) {
if (VERBOSE) System.err.println("JoglPipeline.destroyContext()");
- GLDrawable draw = drawable(drawable);
+
+ JoglDrawable joglDrawable = (JoglDrawable)drawable;
GLContext context = context(ctx);
+
if (GLContext.getCurrent() == context) {
context.release();
}
context.destroy();
- // FIXME: assuming this is the right point at which to make this call
- draw.setRealized(false);
+
+ // assuming this is the right point at which to make this call
+ joglDrawable.getGLDrawable().setRealized(false);
+
+ joglDrawable.destroyNativeWindow();
}
// This is the native method for doing accumulation.
@@ -7152,19 +7415,19 @@ void swapBuffers(Canvas3D cv, Context ctx, Drawable drawable) {
}
}
-private boolean isOffscreenLayerSurfaceEnabled(Canvas3D cv) {
+static boolean isOffscreenLayerSurfaceEnabled(Canvas3D cv) {
if (cv.drawable == null || cv.offScreen)
return false;
JoglDrawable joglDrawble = (JoglDrawable)cv.drawable;
- final JAWTWindow jawtwindow = (JAWTWindow)joglDrawble.getNativeWindow();
+ JAWTWindow jawtwindow = (JAWTWindow)joglDrawble.getNativeWindow();
if (jawtwindow == null)
return false;
return jawtwindow.isOffscreenLayerSurfaceEnabled();
}
-private boolean hasFBObjectSizeChanged(JoglDrawable jdraw, int width, int height) {
+static boolean hasFBObjectSizeChanged(JoglDrawable jdraw, int width, int height) {
if (!(jdraw.getGLDrawable() instanceof GLFBODrawable))
return false;
@@ -7175,7 +7438,6 @@ private boolean hasFBObjectSizeChanged(JoglDrawable jdraw, int width, int height
return (width != fboBack.getWidth() || height != fboBack.getHeight());
}
- void resizeOffscreenLayer(Canvas3D cv, int width, int height) {}
// The native method for setting the Viewport.
void setViewport(Context ctx, int x, int y, int width, int height) {
@@ -7238,6 +7500,7 @@ private boolean hasFBObjectSizeChanged(JoglDrawable jdraw, int width, int height
GL2 gl = context(ctx).getGL().getGL2();
gl.glDeleteLists(id, 1);
}
+
void freeTexture(Context ctx, int id) {
if (VERBOSE) System.err.println("JoglPipeline.freeTexture()");
@@ -7445,8 +7708,8 @@ private boolean hasFBObjectSizeChanged(JoglDrawable jdraw, int width, int height
// Helper private functions for Canvas3D
//
- private boolean getPropertiesFromCurrentContext(JoglContext ctx) {
- GL gl = GLU.getCurrentGL();
+ private boolean getPropertiesFromCurrentContext(JoglContext ctx, GL2 gl) {
+
// FIXME: this is a heavily abridged set of the stuff in Canvas3D.c;
// probably need to pull much more in
int[] tmp = new int[1];
@@ -7634,9 +7897,7 @@ private boolean hasFBObjectSizeChanged(JoglDrawable jdraw, int width, int height
}
}
- private void setupCanvasProperties(Canvas3D cv,
- JoglContext ctx,
- GL gl) {
+ private void setupCanvasProperties(Canvas3D cv, JoglContext ctx, GL gl) {
// Note: this includes relevant portions from both the
// NativePipeline's getPropertiesFromCurrentContext and setupCanvasProperties
@@ -7896,202 +8157,161 @@ private boolean hasFBObjectSizeChanged(JoglDrawable jdraw, int width, int height
// an exception if one cannot be returned.
GraphicsConfiguration getGraphicsConfig(GraphicsConfiguration gconfig) {
if (VERBOSE) System.err.println("JoglPipeline.getGraphicsConfig()");
- JoglGraphicsConfiguration config = (JoglGraphicsConfiguration) gconfig;
- GLCapabilitiesChooser indexChooser = null;
- if (config.getChosenIndex() >= 0) {
- indexChooser = new IndexCapabilitiesChooser(config.getChosenIndex());
- }
- AWTGraphicsDevice awtGraphicsDevice = ((JoglGraphicsConfiguration)gconfig).getAwtGraphicsDevice()/*new AWTGraphicsDevice(config.getDevice(), 0)*/;
- GraphicsConfigurationFactory factory = GraphicsConfigurationFactory.getFactory(awtGraphicsDevice.getClass(), GLCapabilities.class);
+ GraphicsConfigInfo gcInf0 = Canvas3D.graphicsConfigTable.get(gconfig);
+ AWTGraphicsConfiguration awtConfig = (AWTGraphicsConfiguration)gcInf0.getPrivateData();
- AbstractGraphicsConfiguration absConfig =
- factory.chooseGraphicsConfiguration(config.getGLCapabilities(), config.getGLCapabilities(),
- indexChooser, new AWTGraphicsScreen(awtGraphicsDevice), VisualIDHolder.VID_UNDEFINED);
- if (absConfig == null) {
- return null;
- }
- return ((AWTGraphicsConfiguration) absConfig).getAWTGraphicsConfiguration();
-
- /*
-
- System.err.println("JoglPipeline.getGraphicsConfig()");
- // Just return the input graphics config for now. eventually, we will
- // use the input graphics config to get the GraphicsConfigTemplate3D
- // parameters, which we will use to create a new graphics config with JOGL.
- return gconfig;
- */
+ return awtConfig.getAWTGraphicsConfiguration();
}
- private static final int DISABLE_STEREO = 1;
- private static final int DISABLE_AA = 2;
- private static final int DISABLE_DOUBLE_BUFFER = 3;
-
// Get best graphics config from pipeline
GraphicsConfiguration getBestConfiguration(GraphicsConfigTemplate3D gct,
GraphicsConfiguration[] gc) {
if (VERBOSE) System.err.println("JoglPipeline.getBestConfiguration()");
- /*
- System.err.println("gct.getDoubleBuffer(): " + gct.getDoubleBuffer());
- System.err.println("gct.getStereo(): " + gct.getStereo());
- System.err.println("gct.getDepthBits(): " + gct.getDepthSize());
- System.err.println("gct.getRedSize(): " + gct.getRedSize());
- System.err.println("gct.getGreenSize(): " + gct.getGreenSize());
- System.err.println("gct.getBlueSize(): " + gct.getBlueSize());
- System.err.println("gct.getSceneAntialiasing(): " + gct.getSceneAntialiasing());
- */
+
+ // Device / Screen
+ GraphicsDevice device = gc[0].getDevice();
+ AbstractGraphicsScreen screen = (device != null) ? AWTGraphicsScreen.createScreenDevice(device, AbstractGraphicsDevice.DEFAULT_UNIT) :
+ AWTGraphicsScreen.createDefault();
// Create a GLCapabilities based on the GraphicsConfigTemplate3D
- GLCapabilities caps = new GLCapabilities(profile);
- caps.setDoubleBuffered(gct.getDoubleBuffer() <= GraphicsConfigTemplate.PREFERRED);
- caps.setStereo (gct.getStereo() <= GraphicsConfigTemplate.PREFERRED);
+
+ final GLCapabilities caps = new GLCapabilities(profile);
+
+ // On Linux, Windows
+
+ // Only minimum values and REQUIRED capabilities are set !!
+ // PREFERRED capabilities are checked by J3DCapsChooser
+
+ // TODO GraphicsConfigTemplate3D doesn't support number of antialiasing samples
+ // TODO 4 or 8 samples
+ // 4 samples are taken as default maximum number, a smaller number will be chosen by
+ // J3DCapsChooser if the requested number is not supported
+ // so we require only 2 samples
+ // (all available configs with 2 and more samples can then be checked by J3DCapsChooser)
+
+ // REQUIRED
+
+ caps.setStereo( (gct.getStereo() == GraphicsConfigTemplate.REQUIRED) );
+
+ caps.setDoubleBuffered( (gct.getDoubleBuffer() == GraphicsConfigTemplate.REQUIRED) );
+
+ // Scene antialiasing only if double buffering
+ if (gct.getDoubleBuffer() == GraphicsConfigTemplate.REQUIRED &&
+ gct.getSceneAntialiasing() == GraphicsConfigTemplate.REQUIRED) {
+ caps.setSampleBuffers(true);
+ caps.setNumSamples(2);
+ }
+ else {
+ caps.setSampleBuffers(false);
+ caps.setNumSamples(0);
+ }
+
+ // Minimum values
+
caps.setDepthBits (gct.getDepthSize());
caps.setStencilBits (gct.getStencilSize());
+
caps.setRedBits (Math.max(5, gct.getRedSize()));
caps.setGreenBits (Math.max(5, gct.getGreenSize()));
caps.setBlueBits (Math.max(5, gct.getBlueSize()));
- caps.setSampleBuffers(gct.getSceneAntialiasing() <= GraphicsConfigTemplate.PREFERRED);
- // FIXME: should be smarter about choosing the number of samples
- // (Java3D's native code has a loop trying 8, 6, 4, 3, and 2 samples)
- caps.setNumSamples(4);
// Issue 399: Request alpha buffer if transparentOffScreen is set
if (VirtualUniverse.mc.transparentOffScreen) {
caps.setAlphaBits(1);
}
- java.util.List<Integer> capsToDisable = new ArrayList<Integer>();
- // Add PREFERRED capabilities in order we will try disabling them
- if (gct.getStereo() == GraphicsConfigTemplate.PREFERRED) {
- capsToDisable.add(new Integer(DISABLE_STEREO));
- }
- if (gct.getSceneAntialiasing() == GraphicsConfigTemplate.PREFERRED) {
- capsToDisable.add(new Integer(DISABLE_AA));
- }
- if (gct.getDoubleBuffer() == GraphicsConfigTemplate.PREFERRED) {
- capsToDisable.add(new Integer(DISABLE_DOUBLE_BUFFER));
- }
+ // Custom chooser instead of DefaultGLCapabilitiesChooser
+ J3DCapsChooser chooser = new J3DCapsChooser(gct);
- // Pick the GraphicsDevice from a random configuration
- GraphicsDevice dev = gc[0].getDevice();
+ GraphicsConfigurationFactory gcFactory = GraphicsConfigurationFactory.getFactory(AWTGraphicsDevice.class, GLCapabilitiesImmutable.class);
- // Create a Frame and dummy GLCanvas to perform eager pixel format selection
+ // !! deadlock if getBestConfiguration is called on EDT (calling thread is waitung !!)
+ AWTGraphicsConfiguration awtConfig = getAWTGraphicsConfiguration(gcFactory, caps, chooser, screen);
- // Note that we loop in similar fashion to the NativePipeline's
- // native code in the situation where we need to disable certain
- // capabilities which aren't required
- boolean tryAgain = true;
- CapabilitiesCapturer capturer = null;
- while (tryAgain) {
- Frame f = new Frame(dev.getDefaultConfiguration());
- f.setUndecorated(true);
- f.setLayout(new BorderLayout());
- capturer = new CapabilitiesCapturer();
- try {
- AWTGraphicsConfiguration awtGraphicsConfiguration = createAwtGraphicsConfiguration(caps, capturer, dev/*null*/);
- QueryCanvas canvas = new QueryCanvas(awtGraphicsConfiguration, capturer);
- f.add(canvas, BorderLayout.CENTER);
- f.setSize(MIN_FRAME_SIZE, MIN_FRAME_SIZE);
- f.setVisible(true);
- canvas.doQuery();
- if (DEBUG_CONFIG) {
- System.err.println("Waiting for CapabilitiesCapturer");
- }
- // Try to wait for result without blocking EDT
- if (!EventQueue.isDispatchThread()) {
- synchronized(capturer) {
- if (!capturer.done()) {
- try {
- capturer.wait(WAIT_TIME);
- } catch (InterruptedException e) {
- }
- }
+ // If minimum requirements are fulfilled (awtConfig != null),
+ // but J3DCapsChooser wasn't called ( e.g. on Mac OS X (2.0-rc11) ) :
+ // set also PREFERRED caps and max sample number
+ if (awtConfig != null && chooser.isCalled() == false) {
+
+ // 1. Double buffering and scene antialiasing : let Mac OS X decide
+
+ boolean isDoubleBuffering = ( gct.getDoubleBuffer() == GraphicsConfigTemplate.REQUIRED ||
+ gct.getDoubleBuffer() == GraphicsConfigTemplate.PREFERRED );
+
+ caps.setDoubleBuffered(isDoubleBuffering);
+
+ if (isDoubleBuffering &&
+ (gct.getSceneAntialiasing() == GraphicsConfigTemplate.REQUIRED ||
+ gct.getSceneAntialiasing() == GraphicsConfigTemplate.PREFERRED ) ) {
+ caps.setSampleBuffers(true);
+ caps.setNumSamples(4); // TODO
}
+ else {
+ caps.setSampleBuffers(false);
+ caps.setNumSamples(0);
}
- disposeOnEDT(f);
- tryAgain = false;
- } catch (GLException e) {
- // Failure to select a pixel format; try switching off one
- // of the only-preferred capabilities
- if (capsToDisable.size() == 0) {
- tryAgain = false;
- } else {
- int whichToDisable = capsToDisable.remove(0).intValue();
- switch (whichToDisable) {
- case DISABLE_STEREO:
- caps.setStereo(false);
- break;
-
- case DISABLE_AA:
- caps.setSampleBuffers(false);
- break;
-
- case DISABLE_DOUBLE_BUFFER:
- caps.setDoubleBuffered(false);
- break;
-
- default:
- throw new AssertionError("missing case statement");
+
+ AWTGraphicsConfiguration config = getAWTGraphicsConfiguration(gcFactory, caps, chooser, screen);
+
+ // 2. PREFERRED stereo
+
+ if (gct.getStereo() == GraphicsConfigTemplate.PREFERRED) {
+ // config is fine so far, now add stereo requirement
+ if (config != null) {
+ caps.setStereo(true);
+ AWTGraphicsConfiguration configStereo = getAWTGraphicsConfiguration(gcFactory, caps, chooser, screen);
+ if (configStereo != null) {
+ config = configStereo;
}
}
+ // start again with awtConfig
+ else {
+ GLCapabilities stereoCaps = new GLCapabilities(profile);
+ stereoCaps.copyFrom((GLCapabilities)awtConfig.getChosenCapabilities());
+ stereoCaps.setStereo(true);
+ AWTGraphicsConfiguration configStereo = getAWTGraphicsConfiguration(gcFactory, stereoCaps, chooser, screen);
+ if (configStereo != null) {
+ config = configStereo;
}
}
- int chosenIndex = capturer.getChosenIndex();
- GLCapabilities chosenCaps = null;
- if (chosenIndex < 0) {
- if (DEBUG_CONFIG) {
- System.err.println("CapabilitiesCapturer returned invalid index");
}
- // It's possible some platforms or implementations might not
- // support the GLCapabilitiesChooser mechanism; feed in the
- // same GLCapabilities later which we gave to the selector
- chosenCaps = caps;
- } else {
- if (DEBUG_CONFIG) {
- System.err.println("CapabilitiesCapturer returned index=" + chosenIndex);
+
+ // a 'better' config found ?
+ if (config != null) {
+ awtConfig = config;
}
- chosenCaps = capturer.getCapabilities();
}
- JoglGraphicsConfiguration config = new JoglGraphicsConfiguration(chosenCaps, chosenIndex, dev);
-
- // FIXME: because of the fact that JoglGraphicsConfiguration
- // doesn't override hashCode() or equals(), we will basically be
- // creating a new one each time getBestConfiguration() is
- // called; in theory, we should probably map the same
- // GLCapabilities on the same GraphicsDevice to the same
- // JoglGraphicsConfiguration object
-
- // Cache the GraphicsTemplate3D
- synchronized (Canvas3D.graphicsConfigTable) {
- GraphicsConfigInfo gcInfo = new GraphicsConfigInfo(gct);
- // We don't need this
- // gcInfo.setPrivateData(privateData);
- Canvas3D.graphicsConfigTable.put(config, gcInfo);
+ // GraphicsConfigTemplate3D API :
+ // If no such "best" GraphicsConfiguration is found, null is returned.
+ if (awtConfig == null) {
+ System.out.println("J3D JoglPipeline.getBestConfiguration : no best GraphicsConfiguration is found !");
+ return null;
}
- return config;
-
- /*
-
- // TODO: implement this
+ // !! these chosen caps are not final as long as the corresponding context is made current
+ GLCapabilities chosenCaps = (GLCapabilities)awtConfig.getChosenCapabilities();
+//System.out.println("getBestConfiguration chosenCaps = " + chosenCaps);
+ // Index isn't used anymore
+ JoglGraphicsConfiguration bestGC = new JoglGraphicsConfiguration(chosenCaps, -1, device);
- // TODO: construct a unique GraphicsConfiguration object that will be
- // used the key in the hashmap so we can lookup the GraphicsTemplate3D
- GraphicsConfiguration gc1 = GraphicsEnvironment.getLocalGraphicsEnvironment().
- getDefaultScreenDevice().getDefaultConfiguration();
+ GraphicsConfigInfo gcInf0 = new GraphicsConfigInfo(gct);
+ gcInf0.setPrivateData(awtConfig);
- // Cache the GraphicsTemplate3D
synchronized (Canvas3D.graphicsConfigTable) {
- if (Canvas3D.graphicsConfigTable.get(gc1) == null) {
- GraphicsConfigInfo gcInfo = new GraphicsConfigInfo(gct);
- // gcInfo.setPrivateData(privateData);
- Canvas3D.graphicsConfigTable.put(gc1, gcInfo);
+ Canvas3D.graphicsConfigTable.put(bestGC, gcInf0);
}
+
+ return bestGC;
}
- return gc1;
- */
+ private static AWTGraphicsConfiguration getAWTGraphicsConfiguration(GraphicsConfigurationFactory gcFactory,
+ CapabilitiesImmutable capsRequested,
+ CapabilitiesChooser chooser,
+ AbstractGraphicsScreen screen) {
+ return (AWTGraphicsConfiguration)gcFactory.chooseGraphicsConfiguration(
+ capsRequested, capsRequested, chooser, screen, VisualIDHolder.VID_UNDEFINED);
}
// Determine whether specified graphics config is supported by pipeline
@@ -8202,12 +8422,17 @@ private boolean hasFBObjectSizeChanged(JoglDrawable jdraw, int width, int height
// GLCanvas in order to be able to set up a temporary pixel format
// and OpenGL context. Apparently simply turning off the
// single-threaded mode isn't enough to do this.
- class QueryCanvas extends Canvas {
- private GLDrawable drawable;
+ private final class QueryCanvas extends Canvas {
+
+ private GLDrawable glDrawable;
private ExtendedCapabilitiesChooser chooser;
private boolean alreadyRan;
- public QueryCanvas(AWTGraphicsConfiguration awtGraphicsConfiguration, ExtendedCapabilitiesChooser chooser) {
+ private AWTGraphicsConfiguration awtConfig = null;
+ private JAWTWindow nativeWindow = null;
+
+ private QueryCanvas(AWTGraphicsConfiguration awtConfig,
+ ExtendedCapabilitiesChooser chooser) {
// The platform-specific GLDrawableFactory will only provide a
// non-null GraphicsConfiguration on platforms where this is
// necessary (currently only X11, as Windows allows the pixel
@@ -8217,24 +8442,35 @@ private boolean hasFBObjectSizeChanged(JoglDrawable jdraw, int width, int height
// least in the Sun AWT implementation) that this will result in
// equivalent behavior to calling the no-arg super() constructor
// for Canvas.
- super(unwrap(awtGraphicsConfiguration));
- NativeWindow nativeWindow = NativeWindowFactory.getNativeWindow(this, awtGraphicsConfiguration);
- drawable = GLDrawableFactory.getFactory(profile).createGLDrawable(nativeWindow);
+ super(awtConfig.getAWTGraphicsConfiguration());
+
+ this.awtConfig = awtConfig;
this.chooser = chooser;
}
public void addNotify() {
super.addNotify();
- drawable.setRealized(true);
+
+ nativeWindow = (JAWTWindow)NativeWindowFactory.getNativeWindow(this, awtConfig);
+ nativeWindow.setShallUseOffscreenLayer(false); // TODOcv.shallUseOffscreenLayer
+ nativeWindow.lockSurface();
+ try {
+ glDrawable = GLDrawableFactory.getFactory(profile).createGLDrawable(nativeWindow);
+ }
+ finally {
+ nativeWindow.unlockSurface();
+ }
+
+ glDrawable.setRealized(true);
}
// It seems that at least on Mac OS X we need to do the OpenGL
// context-related work outside of the addNotify call because the
// Canvas hasn't been resized to a non-zero size by that point
- public void doQuery() {
+ private void doQuery() {
if (alreadyRan)
return;
- GLContext context = drawable.createContext(null);
+ GLContext context = glDrawable.createContext(null);
int res = context.makeCurrent();
if (res != GLContext.CONTEXT_NOT_CURRENT) {
try {
@@ -8245,9 +8481,12 @@ private boolean hasFBObjectSizeChanged(JoglDrawable jdraw, int width, int height
}
context.destroy();
alreadyRan = true;
+
+ glDrawable.setRealized(false);
+ nativeWindow.destroy();
}
}
-
+ /*
private static AWTGraphicsConfiguration createAwtGraphicsConfiguration(GLCapabilities capabilities,
CapabilitiesChooser chooser,
GraphicsDevice device) {
@@ -8266,7 +8505,7 @@ private boolean hasFBObjectSizeChanged(JoglDrawable jdraw, int width, int height
AWTGraphicsConfiguration awtGraphicsConfiguration = (AWTGraphicsConfiguration) factory.chooseGraphicsConfiguration(capabilities, capabilities,
chooser, new AWTGraphicsScreen(awtGraphicsDevice), VisualIDHolder.VID_UNDEFINED);
return awtGraphicsConfiguration;
- }
+ }*/
private static GraphicsConfiguration unwrap(AWTGraphicsConfiguration config) {
if (config == null) {
@@ -8275,7 +8514,7 @@ private boolean hasFBObjectSizeChanged(JoglDrawable jdraw, int width, int height
return config.getAWTGraphicsConfiguration();
}
- // Used in conjunction with IndexCapabilitiesChooser in pixel format
+ /* Used in conjunction with IndexCapabilitiesChooser in pixel format
// selection -- see getBestConfiguration
class CapabilitiesCapturer extends DefaultGLCapabilitiesChooser implements ExtendedCapabilitiesChooser {
private boolean done;
@@ -8321,11 +8560,12 @@ private boolean hasFBObjectSizeChanged(JoglDrawable jdraw, int width, int height
notifyAll();
}
}
- }
+ }*/
// Used to support the query context mechanism -- needs to be more
// than just a GLCapabilitiesChooser
- class ContextQuerier extends DefaultGLCapabilitiesChooser implements ExtendedCapabilitiesChooser {
+ private final class ContextQuerier extends DefaultGLCapabilitiesChooser
+ implements ExtendedCapabilitiesChooser {
private Canvas3D canvas;
private boolean done;
@@ -8340,9 +8580,10 @@ private boolean hasFBObjectSizeChanged(JoglDrawable jdraw, int width, int height
public void init(GLContext context) {
// This is basically a temporary
JoglContext jctx = new JoglContext(context);
+ GL2 gl = context.getGL().getGL2();
// Set up various properties
- if (getPropertiesFromCurrentContext(jctx)) {
- setupCanvasProperties(canvas, jctx, context.getGL());
+ if (getPropertiesFromCurrentContext(jctx, gl)) {
+ setupCanvasProperties(canvas, jctx, gl);
}
markDone();
}
@@ -8355,7 +8596,7 @@ private boolean hasFBObjectSizeChanged(JoglDrawable jdraw, int width, int height
}
}
- // Used in two phases of pixel format selection: transforming the
+ /* Used in two phases of pixel format selection: transforming the
// JoglGraphicsConfiguration to a real AWT GraphicsConfiguration and
// during context creation to select exactly the same graphics
// configuration as was done during getBestConfiguration.
@@ -8374,7 +8615,7 @@ private boolean hasFBObjectSizeChanged(JoglDrawable jdraw, int width, int height
}
return indexToChoose;
}
- }
+ }*/
private void disposeOnEDT(final Frame f) {
Runnable r = new Runnable() {
@@ -8434,8 +8675,15 @@ private boolean hasFBObjectSizeChanged(JoglDrawable jdraw, int width, int height
}
GLCapabilities caps(Canvas3D ctx) {
+ if (ctx.drawable != null) {
+ // latest state for on- and offscreen drawables
+ return (GLCapabilities)drawable(ctx.drawable).getChosenGLCapabilities();
+ }
+ else {
+ // state at the time of 'getBestConfiguration'
return ((JoglGraphicsConfiguration) ctx.graphicsConfiguration).getGLCapabilities();
}
+ }
//----------------------------------------------------------------------
// General helper routines
@@ -8604,4 +8852,268 @@ private boolean hasFBObjectSizeChanged(JoglDrawable jdraw, int width, int height
return bufs;
}
+
+ private static final class J3DCapsChooser implements GLCapabilitiesChooser {
+
+ private GraphicsConfigTemplate3D gct3D = null;
+
+ private boolean called = false;
+
+ private J3DCapsChooser(GraphicsConfigTemplate3D gct) {
+ gct3D = gct;
+ }
+
+ private boolean isCalled() {
+ return called;
+ }
+
+ // Interface GLCapabilitiesChooser
+
+ // javadoc : "Some of the entries in the available array may be null;"
+
+ @Override
+ public int chooseCapabilities(final CapabilitiesImmutable desiredCaps,
+ final List<? extends CapabilitiesImmutable> availableCapsList,
+ final int windowSystemRecommendedChoice) {
+ called = true;
+
+ final GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable)desiredCaps;
+
+ List<GLCapabilitiesImmutable> capsList = new ArrayList<GLCapabilitiesImmutable>(availableCapsList.size());
+ for (CapabilitiesImmutable availableCaps : availableCapsList) {
+ if (availableCaps != null)
+ capsList.add((GLCapabilitiesImmutable)availableCaps);
+ }
+
+ List<GLCapabilitiesImmutable> potentialCapsList = new ArrayList<GLCapabilitiesImmutable>();
+
+ int capsListLength = capsList.size();
+
+ int chosenIndex = -1;
+
+ // I. minimum requirements
+
+ // I.a red
+ int num = gct3D.getRedSize();
+ for (int i=capsListLength-1; i >= 0; i--) {
+ if (capsList.get(i).getRedBits() < num) {
+ capsList.remove(i);
+ }
+ }
+ capsListLength = capsList.size();
+ // I.b green
+ num = gct3D.getGreenSize();
+ for (int i=capsListLength-1; i >= 0; i--) {
+ if (capsList.get(i).getGreenBits() < num) {
+ capsList.remove(i);
+ }
+ }
+ capsListLength = capsList.size();
+ // I.c blue
+ num = gct3D.getBlueSize();
+ for (int i=capsListLength-1; i >= 0; i--) {
+ if (capsList.get(i).getBlueBits() < num) {
+ capsList.remove(i);
+ }
+ }
+ capsListLength = capsList.size();
+
+ // I.d depth
+ num = gct3D.getDepthSize();
+ for (int i=capsListLength-1; i >= 0; i--) {
+ if (capsList.get(i).getDepthBits() < num) {
+ capsList.remove(i);
+ }
+ }
+ capsListLength = capsList.size();
+ // I.e stencil
+ num = gct3D.getStencilSize();
+ for (int i=capsListLength-1; i >= 0; i--) {
+ if (capsList.get(i).getStencilBits() < num) {
+ capsList.remove(i);
+ }
+ }
+ capsListLength = capsList.size();
+
+ if (capsListLength < 1)
+ return chosenIndex;
+
+ // II. REQUIRED
+
+ // II.a stereo
+ if (gct3D.getStereo() == GraphicsConfigTemplate3D.REQUIRED) {
+ for (int i=capsListLength-1; i >= 0; i--) {
+ if (capsList.get(i).getStereo() == false) {
+ capsList.remove(i);
+ }
+ }
+ capsListLength = capsList.size();
+ }
+
+ // II.b double buffering
+ if (gct3D.getDoubleBuffer() == GraphicsConfigTemplate3D.REQUIRED) {
+ for (int i=capsListLength-1; i >= 0; i--) {
+ if (capsList.get(i).getDoubleBuffered() == false) {
+ capsList.remove(i);
+ }
+ }
+ capsListLength = capsList.size();
+ }
+
+ // II.c scene antialiasing (implicitly double buffered !)
+ if (gct3D.getSceneAntialiasing() == GraphicsConfigTemplate3D.REQUIRED) {
+ for (int i=capsListLength-1; i >= 0; i--) {
+ if (capsList.get(i).getSampleBuffers() == false) {
+ capsList.remove(i);
+ }
+ }
+ capsListLength = capsList.size();
+
+ // Check num samples
+ if (capsListLength > 0) {
+
+ selectNumSamples(capsList);
+ // capsList now contains only caps with num samples >= min(required number, max supported number)
+
+ capsListLength = capsList.size();
+ }
+ }
+
+ if (capsListLength < 1)
+ return chosenIndex;
+
+ // All remaining member of capsList fulfill the min requirements
+
+ // III. PREFERRED priority : 1. scene antialiasing, 2. db buff, 3. stereo
+
+ // fill potentialCapsList with caps from capsList
+
+ // III.a scene antialiasing (implicitly double buffered !)
+ if (gct3D.getSceneAntialiasing() == GraphicsConfigTemplate3D.PREFERRED &&
+ gct3D.getDoubleBuffer() != GraphicsConfigTemplate3D.UNNECESSARY) {
+ for (GLCapabilitiesImmutable potCaps : capsList) {
+ if (potCaps.getSampleBuffers() && potCaps.getDoubleBuffered()) {
+ potentialCapsList.add(potCaps);
+ }
+ }
+ // Check num samples
+ if (potentialCapsList.size() > 0) {
+ selectNumSamples(potentialCapsList);
+ // potentialCapsList now contains only caps with num samples >= min(required number, max supported number)
+ }
+ // Check stereo
+ if (potentialCapsList.size() > 0 && gct3D.getStereo() == GraphicsConfigTemplate3D.PREFERRED) {
+ selectStereo(potentialCapsList);
+ // potentialCapsList now contains only caps with stereo or is unchanged
+ }
+
+ // if potentialCapsList.size() > 0 => done
+ }
+
+ // potentialCapsList.size() > 0 ???
+
+ // III.b double buffering
+ if (potentialCapsList.isEmpty() && gct3D.getDoubleBuffer() == GraphicsConfigTemplate3D.PREFERRED) {
+ for (GLCapabilitiesImmutable potCaps : capsList) {
+ if (potCaps.getDoubleBuffered()) {
+ potentialCapsList.add(potCaps);
+ }
+ }
+ // Check stereo
+ if (potentialCapsList.size() > 0 && gct3D.getStereo() == GraphicsConfigTemplate3D.PREFERRED) {
+ selectStereo(potentialCapsList);
+ // potentialCapsList now contains only caps with stereo or is unchanged
+ }
+
+ // if potentialCapsList.size() > 0 => done
+ }
+
+ // potentialCapsList.size() > 0 ???
+
+ // III.c stereo
+ if (potentialCapsList.isEmpty() && gct3D.getStereo() == GraphicsConfigTemplate3D.PREFERRED) {
+ for (GLCapabilitiesImmutable potCaps : capsList) {
+ if (potCaps.getStereo()) {
+ potentialCapsList.add(potCaps);
+ }
+ }
+
+ // if potentialCapsList.size() > 0 => done
+ }
+
+ // If no PREFERRED capability exists or no supporting caps were found
+ if (potentialCapsList.isEmpty()) {
+ potentialCapsList.addAll(capsList);
+ }
+
+ capsListLength = potentialCapsList.size();
+
+ // IV. UNNECESSARY - TODO remove those caps ????
+
+
+ // Now choose a caps in potentialCapsList and determine its index in availableCapsList
+
+ if (!potentialCapsList.isEmpty()) {
+ // TODO take the first one
+ chosenIndex = availableCapsList.indexOf(potentialCapsList.get(0));
+ }
+
+ return chosenIndex;
+ }
+
+ // If one caps supports stereo, remove all caps with no stereo support
+ private void selectStereo(List<GLCapabilitiesImmutable> capsList) {
+ boolean isStereoSupported = false;
+ for (GLCapabilitiesImmutable caps : capsList) {
+ if (caps.getStereo()) {
+ isStereoSupported = true;
+ break;
+ }
+ }
+ // Kepp all caps with stereo support
+ if (isStereoSupported) {
+ for (int i=capsList.size()-1; i >= 0; i--) {
+ if (capsList.get(i).getStereo() == false) {
+ capsList.remove(i);
+ }
+ }
+ }
+ }
+
+ // Search for best caps if supported number of samples ( >=0 ) is less than the requested number
+ private void selectNumSamples(List<GLCapabilitiesImmutable> msaaCapsList) {
+ // required number
+ int reqNumSamples = 4; // TODO
+ // Maximum available
+ int maxNumSamples = 0;
+
+ for (GLCapabilitiesImmutable msaaCaps : msaaCapsList) {
+ if (msaaCaps.getNumSamples() > maxNumSamples) {
+ maxNumSamples = msaaCaps.getNumSamples();
+ }
+ }
+
+ // The required number might not be supported
+ reqNumSamples = Math.min(reqNumSamples, maxNumSamples);
+
+ // Kepp all caps with num samples >= reqNumSamples
+ for (int i=msaaCapsList.size()-1; i >= 0; i--) {
+ if (msaaCapsList.get(i).getNumSamples() < reqNumSamples) {
+ msaaCapsList.remove(i);
+ }
+ }
+ }
+ /*
+ private int getMaxPowerOf2LE(int value) {
+ int powerValue = 1;
+ if (value < 1)
+ return value;
+
+ while (value >= powerValue) {
+ powerValue *= 2;
+ }
+ powerValue = (powerValue >> 1);
+ return powerValue;
+ }*/
+ }
}
diff --git a/src/classes/share/javax/media/j3d/Renderer.java b/src/classes/share/javax/media/j3d/Renderer.java
index 6bd08d5..af4aa7e 100644
--- a/src/classes/share/javax/media/j3d/Renderer.java
+++ b/src/classes/share/javax/media/j3d/Renderer.java
@@ -241,7 +241,9 @@ ArrayList<TextureRetained> textureIDResourceTable = new ArrayList<TextureRetaine
if (cv.active && (cv.ctx != null) &&
(cv.view != null) && (cv.imageReady)) {
- if (cv.useDoubleBuffer) {
+ // don't swap double buffered AuoOffScreenCanvas3D/JCanvas3D
+ // manual offscreen rendering doesn't pass this code (opArg == SWAP)
+ if (cv.useDoubleBuffer && !cv.offScreen) {
synchronized (cv.drawingSurfaceObject) {
if (cv.validCtx) {
if (VirtualUniverse.mc.doDsiRenderLock) {
@@ -412,9 +414,9 @@ ArrayList<TextureRetained> textureIDResourceTable = new ArrayList<TextureRetaine
if (reqType == MasterControl.SET_GRAPHICSCONFIG_FEATURES) {
try {
if (c.offScreen) {
- // offScreen canvas neither supports
- // double buffering nor stereo
- c.doubleBufferAvailable = false;
+ // NEW : offscreen supports double buffering
+ c.doubleBufferAvailable = c.hasDoubleBuffer(); // was : false
+ // offScreen canvas doesn't supports stereo
c.stereoAvailable = false;
} else {
c.doubleBufferAvailable = c.hasDoubleBuffer();