summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2015-03-21 04:31:27 +0100
committerSven Gothel <[email protected]>2015-03-21 04:31:27 +0100
commit32fc8f3a64cfeee8936af98ae49f8e7c8dfe982f (patch)
tree9f4a250b235bcf6c41bd5c98f19c7e2666e45e57 /src
parent2c88b6dfd4eb7e2cd9a50fa48e08ecafc980931a (diff)
Bug 1116 - Add OculusVR DK2 Support - Part-1 (DK2 on DK1 SDK w/o Eye Tracker)
- DK2's screen on X11 (at least) starts in rotated mode, detect and apply MonitorDevice rotation via NEWT's OpenGL StereoDeviceUtil - Move StereoDevice.Config -> StereoDeviceConfig - Expose generic StereoDevice to public: GenericStereoDeviceConfig + GenericStereoDeviceFactory - GenericStereoDeviceFactory exposes public GenericStereoDeviceConfig creation for mono, sbs-stereo and lense-sbs-stereo w/ diff. parameters. - Pass eye surface/texture size for each eye from device to renderer, instead of assuming unified values. - Unify GenericStereoDevice.createRenderer(..) and OVRStereoDevice.createRenderer(..) code
Diffstat (limited to 'src')
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/stereo/StereoClientRenderer.java10
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDevice.java13
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDeviceConfig.java (renamed from src/jogl/classes/jogamp/opengl/util/stereo/GenericStereoDeviceFactory.java)22
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDeviceFactory.java21
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDeviceRenderer.java8
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/stereo/StereoUtil.java30
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/stereo/generic/GenericStereoDeviceConfig.java177
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/stereo/generic/GenericStereoDeviceFactory.java193
-rw-r--r--src/jogl/classes/jogamp/opengl/util/stereo/DistortionMesh.java10
-rw-r--r--src/jogl/classes/jogamp/opengl/util/stereo/GenericStereoDevice.java373
-rw-r--r--src/jogl/classes/jogamp/opengl/util/stereo/GenericStereoDeviceRenderer.java36
-rw-r--r--src/newt/classes/com/jogamp/newt/opengl/util/stereo/StereoDeviceUtil.java91
-rw-r--r--src/oculusvr/classes/jogamp/opengl/oculusvr/OVRStereoDevice.java97
-rw-r--r--src/oculusvr/classes/jogamp/opengl/oculusvr/OVRStereoDeviceFactory.java4
-rw-r--r--src/oculusvr/classes/jogamp/opengl/oculusvr/OVRStereoDeviceRenderer.java25
-rw-r--r--src/test/com/jogamp/opengl/test/junit/jogl/stereo/StereoDemo01.java18
16 files changed, 756 insertions, 372 deletions
diff --git a/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoClientRenderer.java b/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoClientRenderer.java
index fad07b026..b1a38ab06 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoClientRenderer.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoClientRenderer.java
@@ -85,9 +85,9 @@ public class StereoClientRenderer implements GLEventListener {
this.fboTexs = new TextureAttachment[fboCount];
}
- private void initFBOs(final GL gl, final DimensionImmutable size) {
+ private void initFBOs(final GL gl, final DimensionImmutable[] sizes) {
for(int i=0; i<fbos.length; i++) {
- fbos[i].init(gl, size.getWidth(), size.getHeight(), numSamples);
+ fbos[i].init(gl, sizes[i].getWidth(), sizes[i].getHeight(), numSamples);
if( i>0 && fbos[i-1].getNumSamples() != fbos[i].getNumSamples()) {
throw new InternalError("sample size mismatch: \n\t0: "+fbos[i-1]+"\n\t1: "+fbos[i]);
}
@@ -98,7 +98,7 @@ public class StereoClientRenderer implements GLEventListener {
fbos[i].attachRenderbuffer(gl, Type.DEPTH, FBObject.DEFAULT_BITS);
final FBObject ssink = new FBObject();
{
- ssink.init(gl, size.getWidth(), size.getHeight(), 0);
+ ssink.init(gl, sizes[i].getWidth(), sizes[i].getHeight(), 0);
ssink.attachTexture2D(gl, 0, false, magFilter, minFilter, GL.GL_CLAMP_TO_EDGE, GL.GL_CLAMP_TO_EDGE);
ssink.attachRenderbuffer(gl, Attachment.Type.DEPTH, FBObject.DEFAULT_BITS);
}
@@ -146,7 +146,9 @@ public class StereoClientRenderer implements GLEventListener {
deviceRenderer.init(gl);
// We will do some offscreen rendering, setup FBO...
- final DimensionImmutable textureSize = deviceRenderer.getTextureCount() > 1 ? deviceRenderer.getSingleSurfaceSize() : deviceRenderer.getTotalSurfaceSize();
+ final DimensionImmutable[] textureSize = deviceRenderer.getTextureCount() > 1 ?
+ deviceRenderer.getEyeSurfaceSize() :
+ new DimensionImmutable[] { deviceRenderer.getTotalSurfaceSize() };
initFBOs(gl, textureSize);
helper.init(drawable, false);
diff --git a/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDevice.java b/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDevice.java
index 302e783a2..6d8b85d8e 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDevice.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDevice.java
@@ -41,11 +41,6 @@ public interface StereoDevice {
public static final boolean DEBUG = Debug.debug("StereoDevice");
public static final boolean DUMP_DATA = Debug.isPropertyDefined("jogl.debug.StereoDevice.DumpData", true);
- /** Merely a class providing a type-tag for extensions */
- public static class Config {
- // NOP
- }
-
/** Return the factory used to create this device. */
public StereoDeviceFactory getFactory();
@@ -62,11 +57,17 @@ public interface StereoDevice {
public PointImmutable getPosition();
/**
- * Returns the required surface size in pixel.
+ * Returns the required surface size in pixel
+ * in target space.
*/
public DimensionImmutable getSurfaceSize();
/**
+ * Returns the CCW rotation as required by this display device.
+ */
+ public int getRequiredRotation();
+
+ /**
* Return the device default eye position offset for {@link #createRenderer(int, int, float[], FovHVHalves[], float)}.
* <p>
* Result is an array of float values for
diff --git a/src/jogl/classes/jogamp/opengl/util/stereo/GenericStereoDeviceFactory.java b/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDeviceConfig.java
index f2fa74743..c91935e80 100644
--- a/src/jogl/classes/jogamp/opengl/util/stereo/GenericStereoDeviceFactory.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDeviceConfig.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2014 JogAmp Community. All rights reserved.
+ * Copyright 2015 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
@@ -25,19 +25,9 @@
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of JogAmp Community.
*/
-package jogamp.opengl.util.stereo;
+package com.jogamp.opengl.util.stereo;
-import com.jogamp.opengl.util.stereo.StereoDevice;
-import com.jogamp.opengl.util.stereo.StereoDeviceFactory;
-
-public class GenericStereoDeviceFactory extends StereoDeviceFactory {
-
- public static boolean isAvailable() {
- return true;
- }
-
- @Override
- public final StereoDevice createDevice(final int deviceIndex, final StereoDevice.Config config, final boolean verbose) {
- return new GenericStereoDevice(this, deviceIndex, config);
- }
-}
+/** Merely a class providing a type-tag for extended configuration. */
+public class StereoDeviceConfig {
+ // NOP
+} \ No newline at end of file
diff --git a/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDeviceFactory.java b/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDeviceFactory.java
index c4180585c..13aa2e891 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDeviceFactory.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDeviceFactory.java
@@ -42,7 +42,7 @@ import com.jogamp.common.util.ReflectionUtil;
*/
public abstract class StereoDeviceFactory {
private static final String OVRStereoDeviceClazzName = "jogamp.opengl.oculusvr.OVRStereoDeviceFactory";
- private static final String GenericStereoDeviceClazzName = "jogamp.opengl.util.stereo.GenericStereoDeviceFactory";
+ private static final String GenericStereoDeviceClazzName = com.jogamp.opengl.util.stereo.generic.GenericStereoDeviceFactory.class.getName();
private static final String isAvailableMethodName = "isAvailable";
/** {@link StereoDevice} type used for {@link StereoDeviceFactory#createFactory(DeviceType) createFactory(type)}. */
@@ -60,9 +60,13 @@ public abstract class StereoDeviceFactory {
*/
Generic,
/**
- * OculusVR implementation.
+ * OculusVR DK1 implementation.
*/
- OculusVR
+ OculusVR,
+ /**
+ * OculusVR DK2 implementation.
+ */
+ OculusVR_DK2
};
public static StereoDeviceFactory createDefaultFactory() {
@@ -80,7 +84,7 @@ public abstract class StereoDeviceFactory {
case Default: return createDefaultFactory();
case Generic: className = GenericStereoDeviceClazzName; break;
case OculusVR: className = OVRStereoDeviceClazzName; break;
- default: throw new InternalError("XXX");
+ default: throw new InternalError("Unsupported type "+type);
}
final ClassLoader cl = StereoDeviceFactory.class.getClassLoader();
return createFactory(cl, className);
@@ -95,5 +99,12 @@ public abstract class StereoDeviceFactory {
return null;
}
- public abstract StereoDevice createDevice(final int deviceIndex, final StereoDevice.Config config, final boolean verbose);
+ /**
+ *
+ * @param deviceIndex
+ * @param config optional custom configuration, matching the implementation, i.e. {@link StereoDeviceConfig.GenericStereoDeviceConfig}.
+ * @param verbose
+ * @return
+ */
+ public abstract StereoDevice createDevice(final int deviceIndex, final StereoDeviceConfig config, final boolean verbose);
}
diff --git a/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDeviceRenderer.java b/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDeviceRenderer.java
index 68ae3241b..2078a00a2 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDeviceRenderer.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoDeviceRenderer.java
@@ -155,17 +155,17 @@ public interface StereoDeviceRenderer {
public boolean usesSideBySideStereo();
/**
- * Returns the unified surface size of one eye's a single image in pixel units.
+ * Returns the surface size for each eye's a single image in pixel units.
*/
- public DimensionImmutable getSingleSurfaceSize();
+ public DimensionImmutable[] getEyeSurfaceSize();
/**
* Returns the total surface size required for the complete images in pixel units.
* <p>
- * If {@link #usesSideBySideStereo()} the total size spans over both {@link #getSingleSurfaceSize()}, side-by-side.
+ * If {@link #usesSideBySideStereo()} the total size spans over both {@link #getEyeSurfaceSize()}, side-by-side.
* </p>
* <p>
- * Otherwise the size is equal to {@link #getSingleSurfaceSize()}.
+ * Otherwise the size is equal to {@link #getEyeSurfaceSize()}.
* </p>
*/
public DimensionImmutable getTotalSurfaceSize();
diff --git a/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoUtil.java b/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoUtil.java
index 3e4e7ccd9..b0ca4ddb2 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoUtil.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/stereo/StereoUtil.java
@@ -34,6 +34,36 @@ import com.jogamp.opengl.util.CustomGLEventListener;
import com.jogamp.opengl.util.stereo.StereoDeviceRenderer.Eye;
public class StereoUtil {
+ /**
+ * Return the vertical pupil center from the screen top in the range [0..1].
+ * @param screenHeightInMeters
+ * @param pupilCenterFromScreenTopInMeters
+ */
+ public static float getVertPupilCenterFromTop(final float screenHeightInMeters, final float pupilCenterFromScreenTopInMeters) {
+ return pupilCenterFromScreenTopInMeters / screenHeightInMeters;
+ }
+
+ /**
+ * Return the horizontal pupil center from the left side for both eyes in the range [0..1].
+ * <pre>
+ <-------------left eye------------->| |<-----------right eye-------------->
+ <------------------------------------screenSizeInMeters.Width----------------------------------->
+ <------interpupillaryDistanceInMeters------>
+ <--centerFromLeftInMeters->
+ ^
+ center of pupil
+ * </pre>
+ *
+ * @param screenWidthInMeters
+ * @param interpupillaryDistanceInMeters
+ */
+ public static float[] getHorizPupilCenterFromLeft(final float screenWidthInMeters, final float interpupillaryDistanceInMeters) {
+ final float visibleWidthOfOneEye = 0.5f * screenWidthInMeters;
+ final float leftPupilCenterFromLeftInMeters = ( screenWidthInMeters - interpupillaryDistanceInMeters ) * 0.5f;
+ final float rightPupilCenterFromMiddleInMeters = leftPupilCenterFromLeftInMeters + interpupillaryDistanceInMeters - visibleWidthOfOneEye;
+ return new float[] { leftPupilCenterFromLeftInMeters / visibleWidthOfOneEye,
+ rightPupilCenterFromMiddleInMeters / visibleWidthOfOneEye };
+ }
/** See {@link StereoDeviceRenderer#getDistortionBits()}. */
public static boolean usesBarrelDistortion(final int distortionBits) { return 0 != ( distortionBits & StereoDeviceRenderer.DISTORTION_BARREL ) ; }
diff --git a/src/jogl/classes/com/jogamp/opengl/util/stereo/generic/GenericStereoDeviceConfig.java b/src/jogl/classes/com/jogamp/opengl/util/stereo/generic/GenericStereoDeviceConfig.java
new file mode 100644
index 000000000..04fd8343c
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/util/stereo/generic/GenericStereoDeviceConfig.java
@@ -0,0 +1,177 @@
+/**
+ * Copyright 2015 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.opengl.util.stereo.generic;
+
+import java.util.Arrays;
+
+import jogamp.opengl.util.stereo.DistortionMesh;
+import jogamp.opengl.util.stereo.GenericStereoDevice;
+
+import com.jogamp.nativewindow.util.DimensionImmutable;
+import com.jogamp.opengl.util.stereo.EyeParameter;
+import com.jogamp.opengl.util.stereo.StereoDeviceConfig;
+import com.jogamp.opengl.util.stereo.StereoDeviceRenderer;
+import com.jogamp.opengl.util.stereo.StereoUtil;
+
+/**
+ * Configuration for {@link GenericStereoDevice}s.
+ */
+public class GenericStereoDeviceConfig extends StereoDeviceConfig {
+ public static enum ShutterType {
+ Global, RollingLeftToRight, RollingRightToLeft, RollingTopToBottom
+ }
+ public GenericStereoDeviceConfig(final String name,
+ final GenericStereoDeviceConfig.ShutterType shutterType,
+ final DimensionImmutable surfaceSizeInPixels,
+ final float[] screenSizeInMeters,
+ final DimensionImmutable[/*pre-eye*/] eyeTextureSize,
+ final float pupilCenterFromScreenTopInMeters,
+ final float interpupillaryDistanceInMeters,
+ final int[] eyeRenderOrder,
+ final EyeParameter[] defaultEyeParam,
+ final DistortionMesh.Producer distortionMeshProducer,
+ final int supportedDistortionBits,
+ final int recommendedDistortionBits,
+ final int minimumDistortionBits
+ ) {
+ if( eyeRenderOrder.length != defaultEyeParam.length ) {
+ throw new IllegalArgumentException("eye arrays of different length");
+ }
+ this.name = name;
+ this.shutterType = shutterType;
+ this.surfaceSizeInPixels = surfaceSizeInPixels;
+ this.screenSizeInMeters = screenSizeInMeters;
+ this.eyeTextureSizes = eyeTextureSize;
+ this.pupilCenterFromScreenTopInMeters = pupilCenterFromScreenTopInMeters;
+ this.interpupillaryDistanceInMeters = interpupillaryDistanceInMeters;
+ this.eyeRenderOrder = eyeRenderOrder;
+ this.defaultEyeParam = defaultEyeParam;
+ this.distortionMeshProducer = distortionMeshProducer;
+ this.supportedDistortionBits = supportedDistortionBits;
+ this.recommendedDistortionBits = recommendedDistortionBits;
+ this.minimumDistortionBits = minimumDistortionBits;
+ this.pupilCenterFromTopLeft = new float[2][2];
+ calcPupilCenterFromTopLeft();
+ }
+ /** A variation w/ different surface/screen specs */
+ public GenericStereoDeviceConfig(final GenericStereoDeviceConfig source,
+ final DimensionImmutable surfaceSizeInPixels,
+ final float[] screenSizeInMeters,
+ final DimensionImmutable[/*pre-eye*/] eyeTextureSize) {
+ this.name = source.name;
+ this.shutterType = source.shutterType;
+ this.surfaceSizeInPixels = surfaceSizeInPixels;
+ this.screenSizeInMeters = screenSizeInMeters;
+ this.eyeTextureSizes = eyeTextureSize;
+ this.pupilCenterFromScreenTopInMeters = source.pupilCenterFromScreenTopInMeters;
+ this.interpupillaryDistanceInMeters = source.interpupillaryDistanceInMeters;
+ this.eyeRenderOrder = source.eyeRenderOrder;
+ this.defaultEyeParam = source.defaultEyeParam;
+ this.distortionMeshProducer = source.distortionMeshProducer;
+ this.supportedDistortionBits = source.supportedDistortionBits;
+ this.recommendedDistortionBits = source.recommendedDistortionBits;
+ this.minimumDistortionBits = source.minimumDistortionBits;
+ this.pupilCenterFromTopLeft = new float[2][2];
+ calcPupilCenterFromTopLeft();
+ }
+ private void calcPupilCenterFromTopLeft() {
+ final float visibleWidthOfOneEye = 0.5f * screenSizeInMeters[0];
+ final float leftPupilCenterFromLeftInMeters = ( screenSizeInMeters[0] - interpupillaryDistanceInMeters ) * 0.5f;
+ final float rightPupilCenterFromMiddleInMeters = leftPupilCenterFromLeftInMeters + interpupillaryDistanceInMeters - visibleWidthOfOneEye;
+ pupilCenterFromTopLeft[0][0] = leftPupilCenterFromLeftInMeters / visibleWidthOfOneEye;
+ pupilCenterFromTopLeft[0][1] = pupilCenterFromScreenTopInMeters / screenSizeInMeters[1];
+ pupilCenterFromTopLeft[1][0] = rightPupilCenterFromMiddleInMeters / visibleWidthOfOneEye;
+ pupilCenterFromTopLeft[1][1] = pupilCenterFromTopLeft[0][1];
+ }
+
+ /**
+ * One time lazy initialization before use.
+ * @see #isInitialized()
+ */
+ public synchronized void init() {
+ if( !isInitialized ) {
+ if( null != distortionMeshProducer ) {
+ final float[] eyeReliefInMeters = new float[defaultEyeParam.length];
+ if( 0 < defaultEyeParam.length ) {
+ eyeReliefInMeters[0] = defaultEyeParam[0].eyeReliefZ;
+ }
+ if( 1 < defaultEyeParam.length ) {
+ eyeReliefInMeters[1] = defaultEyeParam[1].eyeReliefZ;
+ }
+ distortionMeshProducer.init(this, eyeReliefInMeters);
+ }
+ isInitialized = true;
+ }
+ }
+ /**
+ * Returns {@code true} if {@link #init() initialized}, otherwise {@code false}.
+ * @see #init()
+ */
+ public final boolean isInitialized() { return isInitialized; }
+
+ @Override
+ public String toString() { return "StereoConfig["+name+", shutter "+shutterType+", surfaceSize "+surfaceSizeInPixels+
+ ", screenSize "+screenSizeInMeters[0]+" x "+screenSizeInMeters[0]+
+ " [m], eyeTexSize "+Arrays.toString(eyeTextureSizes)+", IPD "+interpupillaryDistanceInMeters+
+ " [m], eyeParam "+Arrays.toString(defaultEyeParam)+
+ ", distortionBits[supported ["+StereoUtil.distortionBitsToString(supportedDistortionBits)+
+ "], recommended ["+StereoUtil.distortionBitsToString(recommendedDistortionBits)+
+ "], minimum ["+StereoUtil.distortionBitsToString(minimumDistortionBits)+"]]]";
+ }
+
+ /** Configuration Name */
+ public final String name;
+ public final GenericStereoDeviceConfig.ShutterType shutterType;
+
+ public final DimensionImmutable surfaceSizeInPixels;
+ public final float[] screenSizeInMeters;
+ /** Texture size per eye */
+ public final DimensionImmutable[/*pre-eye*/] eyeTextureSizes;
+
+ /** Vertical distance from pupil to screen-top in meters */
+ public final float pupilCenterFromScreenTopInMeters;
+ /** Horizontal interpupillary distance (IPD) in meters */
+ public final float interpupillaryDistanceInMeters;
+ /**
+ * Pupil center from top left per eye, ranging from [0..1], maybe used to produce FovHVHalves,
+ * see {@link #getHorizPupilCenterFromLeft(float, float)} and {@link #getVertPupilCenterFromTop(float, float)}.
+ */
+ public final float[/*per-eye*/][/*xy*/] pupilCenterFromTopLeft;
+ public final int[] eyeRenderOrder;
+ public final EyeParameter[] defaultEyeParam;
+ public final DistortionMesh.Producer distortionMeshProducer;
+
+ /** Supported distortion bits, see {@link StereoDeviceRenderer.DISTORTION_BARREL}. */
+ public final int supportedDistortionBits;
+ /** Recommended distortion bits, see {@link StereoDeviceRenderer.DISTORTION_BARREL}. */
+ public final int recommendedDistortionBits;
+ /** Required distortion bits, see {@link StereoDeviceRenderer.DISTORTION_BARREL}. */
+ public final int minimumDistortionBits;
+
+ private boolean isInitialized = false;
+} \ No newline at end of file
diff --git a/src/jogl/classes/com/jogamp/opengl/util/stereo/generic/GenericStereoDeviceFactory.java b/src/jogl/classes/com/jogamp/opengl/util/stereo/generic/GenericStereoDeviceFactory.java
new file mode 100644
index 000000000..1d5000c97
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/util/stereo/generic/GenericStereoDeviceFactory.java
@@ -0,0 +1,193 @@
+/**
+ * Copyright 2014 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.opengl.util.stereo.generic;
+
+import jogamp.opengl.util.stereo.DistortionMesh;
+import jogamp.opengl.util.stereo.GenericStereoDevice;
+
+import com.jogamp.common.util.ReflectionUtil;
+import com.jogamp.nativewindow.util.Dimension;
+import com.jogamp.nativewindow.util.DimensionImmutable;
+import com.jogamp.opengl.math.FloatUtil;
+import com.jogamp.opengl.math.FovHVHalves;
+import com.jogamp.opengl.util.stereo.EyeParameter;
+import com.jogamp.opengl.util.stereo.StereoDevice;
+import com.jogamp.opengl.util.stereo.StereoDeviceConfig;
+import com.jogamp.opengl.util.stereo.StereoDeviceFactory;
+import com.jogamp.opengl.util.stereo.StereoDeviceRenderer;
+import com.jogamp.opengl.util.stereo.StereoUtil;
+
+public class GenericStereoDeviceFactory extends StereoDeviceFactory {
+
+ /**
+ * Create a generic monoscopic {@link GenericStereoDeviceConfig generic device config}.
+ * @param name
+ * @param surfaceSizeInPixel
+ * @param screenSizeInMeters
+ * @param defaultEyePositionOffset
+ */
+ public static GenericStereoDeviceConfig createMono(final String name,
+ final DimensionImmutable surfaceSizeInPixel, final float[] screenSizeInMeters,
+ final float[] defaultEyePositionOffset) {
+ final float pupilCenterFromScreenTopInMeters = screenSizeInMeters[1] / 2f;
+ final float d2r = FloatUtil.PI / 180.0f;
+ return new GenericStereoDeviceConfig(
+ name,
+ GenericStereoDeviceConfig.ShutterType.RollingTopToBottom,
+ surfaceSizeInPixel, // resolution
+ screenSizeInMeters, // screenSize [m]
+ new DimensionImmutable[] { surfaceSizeInPixel }, // eye textureSize
+ pupilCenterFromScreenTopInMeters, // pupilCenterFromScreenTop [m]
+ 0f, // IPD [m]
+ new int[] { 0 }, // eye order
+ new EyeParameter[] {
+ new EyeParameter(0, defaultEyePositionOffset,
+ // degrees: 45/2 l, 45/2 r, 45/2 * aspect t, 45/2 * aspect b
+ FovHVHalves.byFovyRadianAndAspect(45f*d2r, 1280f / 800f),
+ 0f /* distNoseToPupil */, 0f /* verticalDelta */, 0f /* eyeReliefInMeters */) },
+ null, // mash producer distortion bits
+ 0, // supported distortion bits
+ 0, // recommended distortion bits
+ 0 // minimum distortion bits
+ );
+ }
+
+ /**
+ * Create a generic homogenous side-by-side stereoscopic {@link GenericStereoDeviceConfig generic device config}.
+ * @param name
+ * @param surfaceSizeInPixel
+ * @param screenSizeInMeters
+ * @param interpupillaryDistanceInMeters
+ * @param fovy
+ * @param defaultEyePositionOffset
+ */
+ public static GenericStereoDeviceConfig createStereoSBS(final String name,
+ final DimensionImmutable surfaceSizeInPixel, final float[] screenSizeInMeters,
+ final float interpupillaryDistanceInMeters, final float fovy,
+ final float[] defaultEyePositionOffset) {
+ final float pupilCenterFromScreenTopInMeters = screenSizeInMeters[1] / 2f;
+ final float d2r = FloatUtil.PI / 180.0f;
+
+ final DimensionImmutable eyeTextureSize = new Dimension(surfaceSizeInPixel.getWidth()/2, surfaceSizeInPixel.getHeight());
+ final float[] horizPupilCenterFromLeft = StereoUtil.getHorizPupilCenterFromLeft(screenSizeInMeters[0], interpupillaryDistanceInMeters);
+ final float vertPupilCenterFromTop = StereoUtil.getVertPupilCenterFromTop(screenSizeInMeters[1], pupilCenterFromScreenTopInMeters);
+ final float aspect = (float)eyeTextureSize.getWidth() / (float)eyeTextureSize.getHeight();
+ final FovHVHalves defaultSBSEyeFovLeft = FovHVHalves.byFovyRadianAndAspect(fovy * d2r, vertPupilCenterFromTop, aspect, horizPupilCenterFromLeft[0]);
+ final FovHVHalves defaultSBSEyeFovRight = FovHVHalves.byFovyRadianAndAspect(fovy * d2r, vertPupilCenterFromTop, aspect, horizPupilCenterFromLeft[1]);
+
+ return new GenericStereoDeviceConfig(
+ name,
+ GenericStereoDeviceConfig.ShutterType.RollingTopToBottom,
+ surfaceSizeInPixel, // resolution
+ screenSizeInMeters, // screenSize [m]
+ new DimensionImmutable[] { eyeTextureSize, eyeTextureSize }, // eye textureSize
+ pupilCenterFromScreenTopInMeters, // pupilCenterFromScreenTop [m]
+ interpupillaryDistanceInMeters, // IPD [m]
+ new int[] { 0, 1 }, // eye order
+ new EyeParameter[] {
+ new EyeParameter(0, defaultEyePositionOffset, defaultSBSEyeFovLeft,
+ interpupillaryDistanceInMeters/2f /* distNoseToPupil */, 0f /* verticalDelta */, 0.010f /* eyeReliefInMeters */),
+ new EyeParameter(1, defaultEyePositionOffset, defaultSBSEyeFovRight,
+ -interpupillaryDistanceInMeters/2f /* distNoseToPupil */, 0f /* verticalDelta */, 0.010f /* eyeReliefInMeters */) },
+ null, // mash producer distortion bits
+ 0, // supported distortion bits
+ 0, // recommended distortion bits
+ 0 // minimum distortion bits
+ );
+
+ }
+
+ /**
+ * Create a generic lense distorted side-by-side stereoscopic {@link GenericStereoDeviceConfig generic device config}.
+ * @param name
+ * @param surfaceSizeInPixel
+ * @param screenSizeInMeters
+ * @param interpupillaryDistanceInMeters
+ * @param fovy
+ * @param eyeTextureSize
+ * @param defaultEyePositionOffset
+ */
+ public static GenericStereoDeviceConfig createStereoSBSLense(final String name,
+ final DimensionImmutable surfaceSizeInPixel, final float[] screenSizeInMeters,
+ final float interpupillaryDistanceInMeters, final float fovy,
+ final DimensionImmutable eyeTextureSize,
+ final float[] defaultEyePositionOffset) {
+ DistortionMesh.Producer lenseDistMeshProduce = null;
+ try {
+ lenseDistMeshProduce =
+ (DistortionMesh.Producer)
+ ReflectionUtil.createInstance("jogamp.opengl.oculusvr.stereo.lense.DistortionMeshProducer", GenericStereoDevice.class.getClassLoader());
+ } catch (final Throwable t) {
+ if(StereoDevice.DEBUG) { System.err.println("Caught: "+t.getMessage()); t.printStackTrace(); }
+ }
+ if( null == lenseDistMeshProduce ) {
+ return null;
+ }
+ final float pupilCenterFromScreenTopInMeters = screenSizeInMeters[1] / 2f;
+ final float d2r = FloatUtil.PI / 180.0f;
+
+ final float[] horizPupilCenterFromLeft = StereoUtil.getHorizPupilCenterFromLeft(screenSizeInMeters[0], interpupillaryDistanceInMeters);
+ final float vertPupilCenterFromTop = StereoUtil.getVertPupilCenterFromTop(screenSizeInMeters[1], pupilCenterFromScreenTopInMeters);
+ final float aspect = (float)eyeTextureSize.getWidth() / (float)eyeTextureSize.getHeight();
+ final FovHVHalves defaultSBSEyeFovLeft = FovHVHalves.byFovyRadianAndAspect(fovy * d2r, vertPupilCenterFromTop, aspect, horizPupilCenterFromLeft[0]);
+ final FovHVHalves defaultSBSEyeFovRight = FovHVHalves.byFovyRadianAndAspect(fovy * d2r, vertPupilCenterFromTop, aspect, horizPupilCenterFromLeft[1]);
+
+ return new GenericStereoDeviceConfig(
+ name,
+ GenericStereoDeviceConfig.ShutterType.RollingTopToBottom,
+ surfaceSizeInPixel, // resolution
+ screenSizeInMeters, // screenSize [m]
+ new DimensionImmutable[] { eyeTextureSize, eyeTextureSize }, // eye textureSize
+ pupilCenterFromScreenTopInMeters, // pupilCenterFromScreenTop [m]
+ interpupillaryDistanceInMeters, // IPD [m]
+ new int[] { 0, 1 }, // eye order
+ new EyeParameter[] {
+ new EyeParameter(0, defaultEyePositionOffset, defaultSBSEyeFovLeft,
+ interpupillaryDistanceInMeters/2f /* distNoseToPupil */, 0f /* verticalDelta */, 0.010f /* eyeReliefInMeters */),
+ new EyeParameter(1, defaultEyePositionOffset, defaultSBSEyeFovRight,
+ -interpupillaryDistanceInMeters/2f /* distNoseToPupil */, 0f /* verticalDelta */, 0.010f /* eyeReliefInMeters */) },
+ lenseDistMeshProduce,
+ // supported distortion bits
+ StereoDeviceRenderer.DISTORTION_BARREL | StereoDeviceRenderer.DISTORTION_CHROMATIC | StereoDeviceRenderer.DISTORTION_VIGNETTE,
+ // recommended distortion bits
+ StereoDeviceRenderer.DISTORTION_BARREL | StereoDeviceRenderer.DISTORTION_CHROMATIC | StereoDeviceRenderer.DISTORTION_VIGNETTE,
+ // minimum distortion bits
+ StereoDeviceRenderer.DISTORTION_BARREL
+ );
+ }
+
+
+ public static boolean isAvailable() {
+ return true;
+ }
+
+ @Override
+ public final StereoDevice createDevice(final int deviceIndex, final StereoDeviceConfig config, final boolean verbose) {
+ return new GenericStereoDevice(this, deviceIndex, config);
+ }
+}
diff --git a/src/jogl/classes/jogamp/opengl/util/stereo/DistortionMesh.java b/src/jogl/classes/jogamp/opengl/util/stereo/DistortionMesh.java
index 7a2483121..5270b5956 100644
--- a/src/jogl/classes/jogamp/opengl/util/stereo/DistortionMesh.java
+++ b/src/jogl/classes/jogamp/opengl/util/stereo/DistortionMesh.java
@@ -28,11 +28,17 @@
package jogamp.opengl.util.stereo;
import com.jogamp.opengl.util.stereo.EyeParameter;
+import com.jogamp.opengl.util.stereo.generic.GenericStereoDeviceConfig;
public class DistortionMesh {
public static interface Producer {
- /** Initialize */
- void init(final GenericStereoDevice.Config deviceConfig, final float[] eyeReliefInMeters);
+ /**
+ * Initialize
+ * @param deviceConfig
+ * @param eyeReliefInMeters
+ * @throws IllegalStateException if already initialized
+ */
+ void init(final GenericStereoDeviceConfig deviceConfig, final float[] eyeReliefInMeters) throws IllegalStateException;
/** Distortion Mesh Producer */
DistortionMesh create(final EyeParameter eyeParam, final int distortionBits);
diff --git a/src/jogl/classes/jogamp/opengl/util/stereo/GenericStereoDevice.java b/src/jogl/classes/jogamp/opengl/util/stereo/GenericStereoDevice.java
index 69a3f2eda..5bfc775fa 100644
--- a/src/jogl/classes/jogamp/opengl/util/stereo/GenericStereoDevice.java
+++ b/src/jogl/classes/jogamp/opengl/util/stereo/GenericStereoDevice.java
@@ -27,304 +27,104 @@
*/
package jogamp.opengl.util.stereo;
-import java.util.Arrays;
-
import com.jogamp.nativewindow.util.Dimension;
import com.jogamp.nativewindow.util.DimensionImmutable;
import com.jogamp.nativewindow.util.Point;
import com.jogamp.nativewindow.util.PointImmutable;
import com.jogamp.nativewindow.util.Rectangle;
import com.jogamp.nativewindow.util.RectangleImmutable;
-
-import com.jogamp.common.util.ReflectionUtil;
-import com.jogamp.opengl.math.FloatUtil;
import com.jogamp.opengl.math.FovHVHalves;
+import com.jogamp.opengl.util.stereo.StereoDeviceConfig;
import com.jogamp.opengl.util.stereo.EyeParameter;
import com.jogamp.opengl.util.stereo.StereoDevice;
import com.jogamp.opengl.util.stereo.StereoDeviceFactory;
import com.jogamp.opengl.util.stereo.StereoDeviceRenderer;
-import com.jogamp.opengl.util.stereo.StereoUtil;
+import com.jogamp.opengl.util.stereo.generic.GenericStereoDeviceConfig;
+import com.jogamp.opengl.util.stereo.generic.GenericStereoDeviceFactory;
public class GenericStereoDevice implements StereoDevice {
- public static enum ShutterType {
- Global, RollingLeftToRight, RollingRightToLeft, RollingTopToBottom
- }
- public static class Config extends StereoDevice.Config {
- public Config(final String name,
- final ShutterType shutterType,
- final DimensionImmutable surfaceSizeInPixels,
- final float[] screenSizeInMeters,
- final DimensionImmutable eyeTextureSize,
- final float pupilCenterFromScreenTopInMeters,
- final float interpupillaryDistanceInMeters,
- final int[] eyeRenderOrder,
- final EyeParameter[] defaultEyeParam,
- final DistortionMesh.Producer distortionMeshProducer,
- final int supportedDistortionBits,
- final int recommendedDistortionBits,
- final int minimumDistortionBits
- ) {
- this.name = name;
- this.shutterType = shutterType;
- this.surfaceSizeInPixels = surfaceSizeInPixels;
- this.screenSizeInMeters = screenSizeInMeters;
- this.eyeTextureSize = eyeTextureSize;
- this.pupilCenterFromScreenTopInMeters = pupilCenterFromScreenTopInMeters;
- this.interpupillaryDistanceInMeters = interpupillaryDistanceInMeters;
- this.eyeRenderOrder = eyeRenderOrder;
- this.defaultEyeParam = defaultEyeParam;
- this.distortionMeshProducer = distortionMeshProducer;
- this.supportedDistortionBits = supportedDistortionBits;
- this.recommendedDistortionBits = recommendedDistortionBits;
- this.minimumDistortionBits = minimumDistortionBits;
- this.pupilCenterFromTopLeft = new float[2][2];
- calcPupilCenterFromTopLeft();
- }
- /** A variation w/ different surface/screen specs */
- public Config(final Config source,
- final DimensionImmutable surfaceSizeInPixels,
- final float[] screenSizeInMeters,
- final DimensionImmutable eyeTextureSize) {
- this.name = source.name;
- this.shutterType = source.shutterType;
- this.surfaceSizeInPixels = surfaceSizeInPixels;
- this.screenSizeInMeters = screenSizeInMeters;
- this.eyeTextureSize = eyeTextureSize;
- this.pupilCenterFromScreenTopInMeters = source.pupilCenterFromScreenTopInMeters;
- this.interpupillaryDistanceInMeters = source.interpupillaryDistanceInMeters;
- this.eyeRenderOrder = source.eyeRenderOrder;
- this.defaultEyeParam = source.defaultEyeParam;
- this.distortionMeshProducer = source.distortionMeshProducer;
- this.supportedDistortionBits = source.supportedDistortionBits;
- this.recommendedDistortionBits = source.recommendedDistortionBits;
- this.minimumDistortionBits = source.minimumDistortionBits;
- this.pupilCenterFromTopLeft = new float[2][2];
- calcPupilCenterFromTopLeft();
- }
- private void calcPupilCenterFromTopLeft() {
- final float visibleWidthOfOneEye = 0.5f * screenSizeInMeters[0];
- final float leftPupilCenterFromLeftInMeters = ( screenSizeInMeters[0] - interpupillaryDistanceInMeters ) * 0.5f;
- final float rightPupilCenterFromMiddleInMeters = leftPupilCenterFromLeftInMeters + interpupillaryDistanceInMeters - visibleWidthOfOneEye;
- pupilCenterFromTopLeft[0][0] = leftPupilCenterFromLeftInMeters / visibleWidthOfOneEye;
- pupilCenterFromTopLeft[0][1] = pupilCenterFromScreenTopInMeters / screenSizeInMeters[1];
- pupilCenterFromTopLeft[1][0] = rightPupilCenterFromMiddleInMeters / visibleWidthOfOneEye;
- pupilCenterFromTopLeft[1][1] = pupilCenterFromTopLeft[0][1];
- }
-
- /**
- * Return the vertical pupil center from the screen top in the range [0..1].
- * @param screenHeightInMeters
- * @param pupilCenterFromScreenTopInMeters
- */
- public static float getVertPupilCenterFromTop(final float screenHeightInMeters, final float pupilCenterFromScreenTopInMeters) {
- return pupilCenterFromScreenTopInMeters / screenHeightInMeters;
- }
-
- /**
- * Return the horizontal pupil center from the left side for both eyes in the range [0..1].
- * <pre>
- <-------------left eye------------->| |<-----------right eye-------------->
- <------------------------------------screenSizeInMeters.Width----------------------------------->
- <------interpupillaryDistanceInMeters------>
- <--centerFromLeftInMeters->
- ^
- center of pupil
- * </pre>
- *
- * @param screenWidthInMeters
- * @param interpupillaryDistanceInMeters
- */
- public static float[] getHorizPupilCenterFromLeft(final float screenWidthInMeters, final float interpupillaryDistanceInMeters) {
- final float visibleWidthOfOneEye = 0.5f * screenWidthInMeters;
- final float leftPupilCenterFromLeftInMeters = ( screenWidthInMeters - interpupillaryDistanceInMeters ) * 0.5f;
- final float rightPupilCenterFromMiddleInMeters = leftPupilCenterFromLeftInMeters + interpupillaryDistanceInMeters - visibleWidthOfOneEye;
- return new float[] { leftPupilCenterFromLeftInMeters / visibleWidthOfOneEye,
- rightPupilCenterFromMiddleInMeters / visibleWidthOfOneEye };
- }
-
- void init() {
- final float[] eyeReliefInMeters = new float[defaultEyeParam.length];
- if( 0 < defaultEyeParam.length ) {
- eyeReliefInMeters[0] = defaultEyeParam[0].eyeReliefZ;
- }
- if( 1 < defaultEyeParam.length ) {
- eyeReliefInMeters[1] = defaultEyeParam[1].eyeReliefZ;
- }
- if( null != distortionMeshProducer ) {
- distortionMeshProducer.init(this, eyeReliefInMeters);
- }
- }
+ /** A mono view configuration DK1, only one eye is supported */
+ public static final GenericStereoDeviceConfig config01Mono01;
+ /** A mono view configuration DK2, only one eye is supported */
+ public static final GenericStereoDeviceConfig config01Mono02;
- @Override
- public String toString() { return "StereoConfig["+name+", shutter "+shutterType+", surfaceSize "+surfaceSizeInPixels+
- ", screenSize "+screenSizeInMeters[0]+" x "+screenSizeInMeters[0]+
- " [m], eyeTexSize "+eyeTextureSize+", IPD "+interpupillaryDistanceInMeters+
- " [m], eyeParam "+Arrays.toString(defaultEyeParam)+
- ", distortionBits[supported ["+StereoUtil.distortionBitsToString(supportedDistortionBits)+
- "], recommended ["+StereoUtil.distortionBitsToString(recommendedDistortionBits)+
- "], minimum ["+StereoUtil.distortionBitsToString(minimumDistortionBits)+"]]]";
- }
-
- /** Configuration Name */
- public final String name;
- public final ShutterType shutterType;
-
- public final DimensionImmutable surfaceSizeInPixels;
- public final float[] screenSizeInMeters;
- /** Texture size per eye */
- public final DimensionImmutable eyeTextureSize;
-
- /** Vertical distance from pupil to screen-top in meters */
- public final float pupilCenterFromScreenTopInMeters;
- /** Horizontal interpupillary distance (IPD) in meters */
- public final float interpupillaryDistanceInMeters;
- /**
- * Pupil center from top left per eye, ranging from [0..1], maybe used to produce FovHVHalves,
- * see {@link #getHorizPupilCenterFromLeft(float, float)} and {@link #getVertPupilCenterFromTop(float, float)}.
- */
- public final float[/*per-eye*/][/*xy*/] pupilCenterFromTopLeft;
- public final int[] eyeRenderOrder;
- public final EyeParameter[] defaultEyeParam;
- public final DistortionMesh.Producer distortionMeshProducer;
-
- public final int supportedDistortionBits;
- public final int recommendedDistortionBits;
- public final int minimumDistortionBits;
- }
-
- /** A mono view configuration, only one eye is supported */
- public static final Config config01Mono01;
+ /** A default stereo SBS view configuration DK1 */
+ public static final GenericStereoDeviceConfig config02StereoSBS01;
+ /** A default stereo SBS view configuration DK2 */
+ public static final GenericStereoDeviceConfig config02StereoSBS02;
- /** A default stereo SBS view configuration */
- public static final Config config02StereoSBS01;
+ /** A default stereo SBS lense view configuration DK1, utilizing similar settings as OculusVR DK1 */
+ public static final GenericStereoDeviceConfig config03StereoSBSLense01;
+ /** A default stereo SBS lense view configuration DK2, utilizing similar settings as OculusVR DK1 */
+ public static final GenericStereoDeviceConfig config03StereoSBSLense02;
- /** A default stereo SBS lense view configuration, utilizing similar settings as OculusVR DK1 */
- public static final Config config03StereoSBSLense01;
-
- private static final Config[] configs;
+ private static final GenericStereoDeviceConfig[] configs;
static {
final float[] DEFAULT_EYE_POSITION_OFFSET_STEREO_LENSES = { 0.0f, 1.6f, -5.0f }; // 1.6 up, 5 forward
final float[] DEFAULT_EYE_POSITION_OFFSET_STEREO = { 0.0f, 0.3f, 3.0f }; // 0.3 up, 3 back
final float[] DEFAULT_EYE_POSITION_OFFSET_MONO = { 0.0f, 0.0f, 3.0f }; // 3 back
- final DimensionImmutable surfaceSizeInPixel = new Dimension(1280, 800);
- final float[] screenSizeInMeters = new float[] { 0.1498f, 0.0936f };
- final float interpupillaryDistanceInMeters = 0.0635f;
- final float pupilCenterFromScreenTopInMeters = screenSizeInMeters[1] / 2f;
- final float d2r = FloatUtil.PI / 180.0f;
- {
- config01Mono01 = new Config(
- "Def01Mono01",
- ShutterType.RollingTopToBottom,
- surfaceSizeInPixel, // resolution
- screenSizeInMeters, // screenSize [m]
- surfaceSizeInPixel, // eye textureSize
- pupilCenterFromScreenTopInMeters, // pupilCenterFromScreenTop [m]
- interpupillaryDistanceInMeters, // IPD [m]
- new int[] { 0 }, // eye order
- new EyeParameter[] {
- new EyeParameter(0, DEFAULT_EYE_POSITION_OFFSET_MONO,
- // degrees: 45/2 l, 45/2 r, 45/2 * aspect t, 45/2 * aspect b
- FovHVHalves.byFovyRadianAndAspect(45f*d2r, 1280f / 800f),
- 0f /* distNoseToPupil */, 0f /* verticalDelta */, 0f /* eyeReliefInMeters */) },
- null, // mash producer distortion bits
- 0, // supported distortion bits
- 0, // recommended distortion bits
- 0 // minimum distortion bits
- );
- }
+ final DimensionImmutable surfaceSizeInPixelDK1 = new Dimension(1280, 800);
+ final float[] screenSizeInMetersDK1 = new float[] { 0.14976f, 0.0936f };
+ final DimensionImmutable eyeTextureSizeDK1 = new Dimension(1122, 1553);
- {
- final DimensionImmutable eyeTextureSize = new Dimension(surfaceSizeInPixel.getWidth()/2, surfaceSizeInPixel.getHeight());
- final float[] horizPupilCenterFromLeft = Config.getHorizPupilCenterFromLeft(screenSizeInMeters[0], interpupillaryDistanceInMeters);
- final float vertPupilCenterFromTop = Config.getVertPupilCenterFromTop(screenSizeInMeters[1], pupilCenterFromScreenTopInMeters);
- final float fovy = 45f;
- final float aspect = (float)eyeTextureSize.getWidth() / (float)eyeTextureSize.getHeight();
- final FovHVHalves defaultSBSEyeFovLeft = FovHVHalves.byFovyRadianAndAspect(fovy * d2r, vertPupilCenterFromTop, aspect, horizPupilCenterFromLeft[0]);
- final FovHVHalves defaultSBSEyeFovRight = FovHVHalves.byFovyRadianAndAspect(fovy * d2r, vertPupilCenterFromTop, aspect, horizPupilCenterFromLeft[1]);
-
- config02StereoSBS01 = new Config(
- "Def02StereoSBS01",
- ShutterType.RollingTopToBottom,
- surfaceSizeInPixel, // resolution
- screenSizeInMeters, // screenSize [m]
- eyeTextureSize, // eye textureSize
- pupilCenterFromScreenTopInMeters, // pupilCenterFromScreenTop [m]
- interpupillaryDistanceInMeters, // IPD [m]
- new int[] { 0, 1 }, // eye order
- new EyeParameter[] {
- new EyeParameter(0, DEFAULT_EYE_POSITION_OFFSET_STEREO, defaultSBSEyeFovLeft,
- 0.032f /* distNoseToPupil */, 0f /* verticalDelta */, 0.010f /* eyeReliefInMeters */),
- new EyeParameter(1, DEFAULT_EYE_POSITION_OFFSET_STEREO, defaultSBSEyeFovRight,
- -0.032f /* distNoseToPupil */, 0f /* verticalDelta */, 0.010f /* eyeReliefInMeters */) },
- null, // mash producer distortion bits
- 0, // supported distortion bits
- 0, // recommended distortion bits
- 0 // minimum distortion bits
- );
- }
+ final DimensionImmutable surfaceSizeInPixelDK2 = new Dimension(1920, 1080);
+ final float[] screenSizeInMetersDK2 = new float[] { 0.12576f, 0.07074f };
+ final DimensionImmutable eyeTextureSizeDK2 = new Dimension(1182, 1461);
- {
- DistortionMesh.Producer lenseDistMeshProduce = null;
- try {
- lenseDistMeshProduce =
- (DistortionMesh.Producer)
- ReflectionUtil.createInstance("jogamp.opengl.oculusvr.stereo.lense.DistortionMeshProducer", GenericStereoDevice.class.getClassLoader());
- } catch (final Throwable t) {
- if(StereoDevice.DEBUG) { System.err.println("Caught: "+t.getMessage()); t.printStackTrace(); }
- }
+ final float interpupillaryDistanceInMeters = 0.0635f;
- final DimensionImmutable eyeTextureSize = new Dimension(1122, 1553);
- final float[] horizPupilCenterFromLeft = Config.getHorizPupilCenterFromLeft(screenSizeInMeters[0], interpupillaryDistanceInMeters);
- final float vertPupilCenterFromTop = Config.getVertPupilCenterFromTop(screenSizeInMeters[1], pupilCenterFromScreenTopInMeters);
- final float fovy = 129f;
- final float aspect = (float)eyeTextureSize.getWidth() / (float)eyeTextureSize.getHeight();
- final FovHVHalves defaultSBSEyeFovLenseLeft = FovHVHalves.byFovyRadianAndAspect(fovy * d2r, vertPupilCenterFromTop, aspect, horizPupilCenterFromLeft[0]);
- final FovHVHalves defaultSBSEyeFovLenseRight = FovHVHalves.byFovyRadianAndAspect(fovy * d2r, vertPupilCenterFromTop, aspect, horizPupilCenterFromLeft[1]);
-
- config03StereoSBSLense01 = null == lenseDistMeshProduce ? null :
- new Config(
- "Def03StereoSBSLense01",
- ShutterType.RollingTopToBottom,
- surfaceSizeInPixel, // resolution
- screenSizeInMeters, // screenSize [m]
- eyeTextureSize, // eye textureSize
- pupilCenterFromScreenTopInMeters, // pupilCenterFromScreenTop [m]
- interpupillaryDistanceInMeters, // IPD [m]
- new int[] { 0, 1 }, // eye order
- new EyeParameter[] {
- new EyeParameter(0, DEFAULT_EYE_POSITION_OFFSET_STEREO_LENSES, defaultSBSEyeFovLenseLeft,
- 0.032f /* distNoseToPupil */, 0f /* verticalDelta */, 0.010f /* eyeReliefInMeters */),
- new EyeParameter(1, DEFAULT_EYE_POSITION_OFFSET_STEREO_LENSES, defaultSBSEyeFovLenseRight,
- -0.032f /* distNoseToPupil */, 0f /* verticalDelta */, 0.010f /* eyeReliefInMeters */) },
- lenseDistMeshProduce,
- // supported distortion bits
- StereoDeviceRenderer.DISTORTION_BARREL | StereoDeviceRenderer.DISTORTION_CHROMATIC | StereoDeviceRenderer.DISTORTION_VIGNETTE,
- // recommended distortion bits
- StereoDeviceRenderer.DISTORTION_BARREL | StereoDeviceRenderer.DISTORTION_CHROMATIC | StereoDeviceRenderer.DISTORTION_VIGNETTE,
- // minimum distortion bits
- StereoDeviceRenderer.DISTORTION_BARREL
- );
- }
- configs = new Config[] { config01Mono01, config02StereoSBS01, config03StereoSBSLense01 };
+ config01Mono01 = GenericStereoDeviceFactory.createMono("Def01Mono01",
+ surfaceSizeInPixelDK1, screenSizeInMetersDK1,
+ DEFAULT_EYE_POSITION_OFFSET_MONO);
+
+ config02StereoSBS01 = GenericStereoDeviceFactory.createStereoSBS("Def02StereoSBS01",
+ surfaceSizeInPixelDK1, screenSizeInMetersDK1,
+ interpupillaryDistanceInMeters, 45f /* fovy */,
+ DEFAULT_EYE_POSITION_OFFSET_STEREO);
+
+ config03StereoSBSLense01 = GenericStereoDeviceFactory.createStereoSBSLense("Def03StereoSBSLense01",
+ surfaceSizeInPixelDK1, screenSizeInMetersDK1,
+ interpupillaryDistanceInMeters, 129f /* fovy */,
+ eyeTextureSizeDK1,
+ DEFAULT_EYE_POSITION_OFFSET_STEREO_LENSES);
+
+ config01Mono02 = GenericStereoDeviceFactory.createMono("Def01Mono02",
+ surfaceSizeInPixelDK2, screenSizeInMetersDK2,
+ DEFAULT_EYE_POSITION_OFFSET_MONO);
+
+ config02StereoSBS02 = GenericStereoDeviceFactory.createStereoSBS("Def02StereoSBS02",
+ surfaceSizeInPixelDK2, screenSizeInMetersDK2,
+ interpupillaryDistanceInMeters, 45f /* fovy */,
+ DEFAULT_EYE_POSITION_OFFSET_STEREO);
+
+ config03StereoSBSLense02 = GenericStereoDeviceFactory.createStereoSBSLense("Def03StereoSBSLense02",
+ surfaceSizeInPixelDK2, screenSizeInMetersDK2,
+ interpupillaryDistanceInMeters, 129f /* fovy */,
+ eyeTextureSizeDK2,
+ DEFAULT_EYE_POSITION_OFFSET_STEREO_LENSES);
+
+ configs = new GenericStereoDeviceConfig[] {
+ config01Mono01, config02StereoSBS01, config03StereoSBSLense01,
+ config01Mono02, config02StereoSBS02, config03StereoSBSLense02 };
}
private final StereoDeviceFactory factory;
public final int deviceIndex;
- public final Config config;
+ public final GenericStereoDeviceConfig config;
public final Point surfacePos;
private final FovHVHalves[] defaultEyeFov;
private boolean sensorsStarted = false;
- public GenericStereoDevice(final StereoDeviceFactory factory, final int deviceIndex, final StereoDevice.Config customConfig) {
+ public GenericStereoDevice(final StereoDeviceFactory factory, final int deviceIndex, final StereoDeviceConfig customConfig) {
this.factory = factory;
this.deviceIndex = deviceIndex;
- if( customConfig instanceof GenericStereoDevice.Config) {
- this.config = (GenericStereoDevice.Config) customConfig;
+ if( customConfig instanceof GenericStereoDeviceConfig) {
+ this.config = (GenericStereoDeviceConfig) customConfig;
} else {
final int cfgIdx = Math.min(deviceIndex % 10, configs.length-1);
this.config = null != configs[cfgIdx] ? configs[cfgIdx] : config02StereoSBS01;
@@ -365,6 +165,8 @@ public class GenericStereoDevice implements StereoDevice {
public final DimensionImmutable getSurfaceSize() {
return config.surfaceSizeInPixels;
}
+ @Override
+ public int getRequiredRotation() { return 0; }
@Override
public float[] getDefaultEyePositionOffset() {
@@ -425,7 +227,8 @@ public class GenericStereoDevice implements StereoDevice {
@Override
public final StereoDeviceRenderer createRenderer(final int distortionBits,
final int textureCount, final float[] eyePositionOffset,
- final FovHVHalves[] eyeFov, final float pixelsPerDisplayPixel, final int textureUnit) {
+ final FovHVHalves[] eyeFov, final float pixelsPerDisplayPixel,
+ final int textureUnit) {
final EyeParameter[] eyeParam = new EyeParameter[eyeFov.length];
for(int i=0; i<eyeParam.length; i++) {
final EyeParameter defaultEyeParam = config.defaultEyeParam[i];
@@ -436,33 +239,47 @@ public class GenericStereoDevice implements StereoDevice {
final boolean usePP = null != config.distortionMeshProducer && 0 != distortionBits; // use post-processing
final RectangleImmutable[] eyeViewports = new RectangleImmutable[eyeParam.length];
- final DimensionImmutable eyeTextureSize = config.eyeTextureSize;
final DimensionImmutable totalTextureSize;
if( 1 < eyeParam.length ) {
// Stereo SBS
- totalTextureSize = new Dimension(eyeTextureSize.getWidth()*2, eyeTextureSize.getHeight());
+ final DimensionImmutable eye0TextureSize = config.eyeTextureSizes[0];
+ final DimensionImmutable eye1TextureSize = config.eyeTextureSizes[1];
+ final int maxHeight = Math.max(eye0TextureSize.getHeight(), eye1TextureSize.getHeight());
+ totalTextureSize = new Dimension(eye0TextureSize.getWidth()+eye1TextureSize.getWidth(), maxHeight);
if( 1 == textureCount ) { // validated in ctor below!
+ // one big texture/FBO, viewport to target space
eyeViewports[0] = new Rectangle(0, 0,
- eyeTextureSize.getWidth(), eyeTextureSize.getHeight());
-
- eyeViewports[1] = new Rectangle(eyeTextureSize.getWidth(), 0,
- eyeTextureSize.getWidth(), eyeTextureSize.getHeight());
+ eye0TextureSize.getWidth(),
+ maxHeight);
+ eyeViewports[1] = new Rectangle(eye0TextureSize.getWidth(), 0,
+ eye1TextureSize.getWidth(),
+ maxHeight);
+ } else if( usePP ) {
+ // two textures/FBOs w/ postprocessing, which renders textures/FBOs into target space
+ eyeViewports[0] = new Rectangle(0, 0,
+ eye0TextureSize.getWidth(),
+ eye0TextureSize.getHeight());
+ eyeViewports[1] = new Rectangle(0, 0,
+ eye1TextureSize.getWidth(),
+ eye1TextureSize.getHeight());
} else {
- eyeViewports[0] = new Rectangle(0, 0, eyeTextureSize.getWidth(), eyeTextureSize.getHeight());
- if( usePP ) {
- eyeViewports[1] = eyeViewports[0];
- } else {
- eyeViewports[1] = new Rectangle(eyeTextureSize.getWidth(), 0,
- eyeTextureSize.getWidth(), eyeTextureSize.getHeight());
- }
+ // two textures/FBOs w/o postprocessing, viewport to target space
+ eyeViewports[0] = new Rectangle(0, 0,
+ eye0TextureSize.getWidth(),
+ eye0TextureSize.getHeight());
+ eyeViewports[1] = new Rectangle(eye0TextureSize.getWidth(), 0,
+ eye1TextureSize.getWidth(),
+ eye1TextureSize.getHeight());
}
} else {
// Mono
- totalTextureSize = eyeTextureSize;
- eyeViewports[0] = new Rectangle(0, 0, eyeTextureSize.getWidth(), eyeTextureSize.getHeight());
+ final DimensionImmutable eye0TextureSize = config.eyeTextureSizes[0];
+ totalTextureSize = eye0TextureSize;
+ eyeViewports[0] = new Rectangle(0, 0, eye0TextureSize.getWidth(), eye0TextureSize.getHeight());
}
- return new GenericStereoDeviceRenderer(this, distortionBits, textureCount, eyePositionOffset, eyeParam, pixelsPerDisplayPixel, textureUnit,
- eyeTextureSize, totalTextureSize, eyeViewports);
+ return new GenericStereoDeviceRenderer(this, distortionBits, textureCount, eyePositionOffset, eyeParam,
+ pixelsPerDisplayPixel, textureUnit,
+ config.eyeTextureSizes, totalTextureSize, eyeViewports);
}
} \ No newline at end of file
diff --git a/src/jogl/classes/jogamp/opengl/util/stereo/GenericStereoDeviceRenderer.java b/src/jogl/classes/jogamp/opengl/util/stereo/GenericStereoDeviceRenderer.java
index 3b9fb9c26..6650342e7 100644
--- a/src/jogl/classes/jogamp/opengl/util/stereo/GenericStereoDeviceRenderer.java
+++ b/src/jogl/classes/jogamp/opengl/util/stereo/GenericStereoDeviceRenderer.java
@@ -29,6 +29,7 @@ package jogamp.opengl.util.stereo;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
+import java.util.Arrays;
import com.jogamp.nativewindow.util.Dimension;
import com.jogamp.nativewindow.util.DimensionImmutable;
@@ -380,7 +381,7 @@ public class GenericStereoDeviceRenderer implements StereoDeviceRenderer {
private final GenericEye[] eyes;
private final int distortionBits;
private final int textureCount;
- private final DimensionImmutable singleTextureSize;
+ private final DimensionImmutable[] eyeTextureSizes;
private final DimensionImmutable totalTextureSize;
/** if texUnit0 is null: no post-processing */
private final GLUniformData texUnit0;
@@ -391,7 +392,7 @@ public class GenericStereoDeviceRenderer implements StereoDeviceRenderer {
@Override
public String toString() {
return "GenericStereo[distortion["+StereoUtil.distortionBitsToString(distortionBits)+
- "], singleSize "+singleTextureSize+
+ "], eyeTexSize "+Arrays.toString(eyeTextureSizes)+
", sbsSize "+totalTextureSize+
", texCount "+textureCount+", texUnit "+(null != texUnit0 ? texUnit0.intValue() : "n/a")+
", "+PlatformPropsImpl.NEWLINE+" "+(0 < eyes.length ? eyes[0] : "none")+
@@ -404,13 +405,17 @@ public class GenericStereoDeviceRenderer implements StereoDeviceRenderer {
/* pp */ GenericStereoDeviceRenderer(final GenericStereoDevice context, final int distortionBits,
final int textureCount, final float[] eyePositionOffset,
final EyeParameter[] eyeParam, final float pixelsPerDisplayPixel, final int textureUnit,
- final DimensionImmutable singleTextureSize, final DimensionImmutable totalTextureSize,
+ final DimensionImmutable[] eyeTextureSizes, final DimensionImmutable totalTextureSize,
final RectangleImmutable[] eyeViewports) {
+ if( eyeParam.length != eyeTextureSizes.length ||
+ eyeParam.length != eyeViewports.length ) {
+ throw new IllegalArgumentException("eye arrays of different length");
+ }
this.device = context;
this.eyes = new GenericEye[eyeParam.length];
this.distortionBits = ( distortionBits | context.getMinimumDistortionBits() ) & context.getSupportedDistortionBits();
final boolean usePP = null != device.config.distortionMeshProducer && 0 != this.distortionBits;
- final DimensionImmutable textureSize;
+ final DimensionImmutable[] textureSizes;
if( usePP ) {
if( 1 > textureCount || 2 < textureCount ) {
@@ -418,19 +423,30 @@ public class GenericStereoDeviceRenderer implements StereoDeviceRenderer {
} else {
this.textureCount = textureCount;
}
- this.singleTextureSize = singleTextureSize;
+ this.eyeTextureSizes = eyeTextureSizes;
this.totalTextureSize = totalTextureSize;
- textureSize = 1 == textureCount ? totalTextureSize : singleTextureSize;
+ if( 1 == textureCount ) {
+ textureSizes = new DimensionImmutable[eyeParam.length];
+ for(int i=0; i<eyeParam.length; i++) {
+ textureSizes[i] = totalTextureSize;
+ }
+ } else {
+ textureSizes = eyeTextureSizes;
+ }
texUnit0 = new GLUniformData("svr_Texture0", textureUnit);
} else {
this.textureCount = 0;
- this.singleTextureSize = zeroSize;
+ this.eyeTextureSizes = new DimensionImmutable[eyeParam.length];
+ textureSizes = new DimensionImmutable[eyeParam.length];
+ for(int i=0; i<eyeParam.length; i++) {
+ this.eyeTextureSizes[i] = zeroSize;
+ textureSizes[i] = zeroSize;
+ }
this.totalTextureSize = zeroSize;
- textureSize = zeroSize;
texUnit0 = null;
}
for(int i=0; i<eyeParam.length; i++) {
- eyes[i] = new GenericEye(context, this.distortionBits, eyePositionOffset, eyeParam[i], textureSize, eyeViewports[i]);
+ eyes[i] = new GenericEye(context, this.distortionBits, eyePositionOffset, eyeParam[i], textureSizes[i], eyeViewports[i]);
}
sp = null;
}
@@ -445,7 +461,7 @@ public class GenericStereoDeviceRenderer implements StereoDeviceRenderer {
public final boolean usesSideBySideStereo() { return true; }
@Override
- public final DimensionImmutable getSingleSurfaceSize() { return singleTextureSize; }
+ public final DimensionImmutable[] getEyeSurfaceSize() { return eyeTextureSizes; }
@Override
public final DimensionImmutable getTotalSurfaceSize() { return totalTextureSize; }
diff --git a/src/newt/classes/com/jogamp/newt/opengl/util/stereo/StereoDeviceUtil.java b/src/newt/classes/com/jogamp/newt/opengl/util/stereo/StereoDeviceUtil.java
new file mode 100644
index 000000000..762608fd4
--- /dev/null
+++ b/src/newt/classes/com/jogamp/newt/opengl/util/stereo/StereoDeviceUtil.java
@@ -0,0 +1,91 @@
+/**
+ * Copyright 2015 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.newt.opengl.util.stereo;
+
+import java.util.List;
+
+import com.jogamp.nativewindow.util.Dimension;
+import com.jogamp.nativewindow.util.DimensionImmutable;
+import com.jogamp.nativewindow.util.PointImmutable;
+import com.jogamp.nativewindow.util.Rectangle;
+import com.jogamp.nativewindow.util.RectangleImmutable;
+
+import com.jogamp.newt.Display;
+import com.jogamp.newt.MonitorDevice;
+import com.jogamp.newt.MonitorMode;
+import com.jogamp.newt.NewtFactory;
+import com.jogamp.newt.Screen;
+import com.jogamp.newt.util.MonitorModeUtil;
+import com.jogamp.opengl.util.stereo.StereoDevice;
+
+/**
+ * {@link StereoDevice} NEWT related utilities.
+ */
+public class StereoDeviceUtil {
+ /**
+ * Returns the {@link StereoDevice}'s associated {@link MonitorDevice} or {@code null}, if none is attached.
+ * <p>
+ * The returned {@link MonitorDevice}'s {@link Screen}, retrieved via {@link MonitorDevice#getScreen()},
+ * has been natively created via {@link Screen#addReference()} and caller shall ensure
+ * {@link Screen#removeReference()} will be called when no more in use.
+ * </p>
+ * <p>
+ * If {@code adjustRotation} is {@code true} and the {@link StereoDevice}
+ * {@link StereoDevice#getRequiredRotation() requires rotation}, the {@link MonitorDevice}
+ * will be rotated.
+ * </p>
+ * @param stereoDevice the {@link StereoDevice}
+ * @param adjustRotation if {@code true} rotate the {@link MonitorDevice} if {@link StereoDevice#getRequiredRotation() required}.
+ */
+ public static MonitorDevice getMonitorDevice(final StereoDevice stereoDevice, final boolean adjustRotation) {
+ final PointImmutable devicePos = stereoDevice.getPosition();
+ final DimensionImmutable deviceRes = stereoDevice.getSurfaceSize();
+ final int deviceReqRotation = stereoDevice.getRequiredRotation();
+ final RectangleImmutable rect = new Rectangle(devicePos.getX(), devicePos.getY(), 128, 128);
+
+ final Display display = NewtFactory.createDisplay(null);
+ final Screen screen = NewtFactory.createScreen(display, 0);
+ screen.addReference();
+ final MonitorDevice monitor = screen.getMainMonitor(rect);
+ if( adjustRotation && 0 != deviceReqRotation ) {
+ final DimensionImmutable deviceRotRes;
+ if( 90 == deviceReqRotation || 270 == deviceReqRotation ) {
+ deviceRotRes = new Dimension(deviceRes.getHeight(), deviceRes.getWidth());
+ } else {
+ deviceRotRes = deviceRes;
+ }
+ final List<MonitorMode> mmodes0 = monitor.getSupportedModes();
+ final List<MonitorMode> mmodes1 = MonitorModeUtil.filterByResolution(mmodes0, deviceRotRes);
+ final List<MonitorMode> mmodes2 = MonitorModeUtil.filterByRotation(mmodes1, deviceReqRotation);
+ if( mmodes2.size() > 0 ) {
+ monitor.setCurrentMode(mmodes2.get(0));
+ }
+ }
+ return monitor;
+ }
+}
diff --git a/src/oculusvr/classes/jogamp/opengl/oculusvr/OVRStereoDevice.java b/src/oculusvr/classes/jogamp/opengl/oculusvr/OVRStereoDevice.java
index d0d9f5a85..3dadb94b0 100644
--- a/src/oculusvr/classes/jogamp/opengl/oculusvr/OVRStereoDevice.java
+++ b/src/oculusvr/classes/jogamp/opengl/oculusvr/OVRStereoDevice.java
@@ -32,7 +32,6 @@ import com.jogamp.nativewindow.util.DimensionImmutable;
import com.jogamp.nativewindow.util.PointImmutable;
import com.jogamp.nativewindow.util.Rectangle;
import com.jogamp.nativewindow.util.RectangleImmutable;
-
import com.jogamp.oculusvr.OVR;
import com.jogamp.oculusvr.OvrHmdContext;
import com.jogamp.oculusvr.ovrEyeRenderDesc;
@@ -59,6 +58,12 @@ public class OVRStereoDevice implements StereoDevice {
private final int[] eyeRenderOrder;
private final int supportedDistortionBits, recommendedDistortionBits, minimumDistortionBits;
+ private final String deviceName;
+ private final DimensionImmutable resolution;
+ private final int requiredRotation;
+ private final PointImmutable position;
+ private final int dkVersion;
+
public OVRStereoDevice(final StereoDeviceFactory factory, final OvrHmdContext nativeContext, final int deviceIndex) {
if( null == nativeContext ) {
throw new IllegalArgumentException("Passed null nativeContext");
@@ -68,16 +73,30 @@ public class OVRStereoDevice implements StereoDevice {
this.deviceIndex = deviceIndex;
this.hmdDesc = ovrHmdDesc.create();
OVR.ovrHmd_GetDesc(handle, hmdDesc);
- final ovrFovPort[] defaultOVREyeFov = hmdDesc.getDefaultEyeFov(0, new ovrFovPort[hmdDesc.getEyeRenderOrderArrayLength()]);
+ final ovrFovPort[] defaultOVREyeFov = hmdDesc.getDefaultEyeFov(0, new ovrFovPort[ovrHmdDesc.getEyeRenderOrderArrayLength()]);
defaultEyeFov = new FovHVHalves[defaultOVREyeFov.length];
for(int i=0; i<defaultEyeFov.length; i++) {
defaultEyeFov[i] = OVRUtil.getFovHV(defaultOVREyeFov[i]);
}
- eyeRenderOrder = new int[hmdDesc.getEyeRenderOrderArrayLength()];
+ eyeRenderOrder = new int[ovrHmdDesc.getEyeRenderOrderArrayLength()];
hmdDesc.getEyeRenderOrder(0, eyeRenderOrder);
supportedDistortionBits = OVRUtil.ovrDistCaps2DistBits(hmdDesc.getDistortionCaps());
recommendedDistortionBits = supportedDistortionBits & ~StereoDeviceRenderer.DISTORTION_TIMEWARP;
minimumDistortionBits = StereoDeviceRenderer.DISTORTION_BARREL;
+
+ // DK1 delivers unrotated resolution in target orientation
+ // DK2 delivers rotated resolution in target orientation, monitor screen is rotated 90deg clockwise
+ deviceName = hmdDesc.getDisplayDeviceNameAsString();
+ final ovrSizei res = hmdDesc.getResolution();
+ resolution = new Dimension(res.getW(), res.getH());
+ if( "OVR0002".equals(deviceName) || "OVR0003".equals(deviceName) ) {
+ dkVersion = 2;
+ requiredRotation = 90;
+ } else {
+ dkVersion = 1;
+ requiredRotation = 0;
+ }
+ position = OVRUtil.getVec2iAsPoint(hmdDesc.getWindowsPos());
}
@Override
@@ -88,8 +107,9 @@ public class OVRStereoDevice implements StereoDevice {
final StringBuilder sb = new StringBuilder();
sb.append("OVRStereoDevice[product "+hmdDesc.getProductNameAsString());
sb.append(", vendor "+hmdDesc.getManufacturerAsString());
- sb.append(", device "+hmdDesc.getDisplayDeviceNameAsString());
- sb.append(", surfaceSize "+getSurfaceSize());
+ sb.append(", device "+deviceName);
+ sb.append(", DK "+dkVersion);
+ sb.append(", surfaceSize "+getSurfaceSize()+", reqRotation "+requiredRotation+" ccw-deg");
sb.append(", surfacePos "+getPosition());
sb.append(", distortionBits[supported ["+StereoUtil.distortionBitsToString(getSupportedDistortionBits())+
"], recommended ["+StereoUtil.distortionBitsToString(getRecommendedDistortionBits())+
@@ -103,14 +123,12 @@ public class OVRStereoDevice implements StereoDevice {
}
@Override
- public final PointImmutable getPosition() {
- return OVRUtil.getVec2iAsPoint(hmdDesc.getWindowsPos());
- }
+ public final PointImmutable getPosition() { return position; }
@Override
- public final DimensionImmutable getSurfaceSize() {
- return OVRUtil.getOVRSizei(hmdDesc.getResolution());
- }
+ public final DimensionImmutable getSurfaceSize() { return resolution; }
+ @Override
+ public int getRequiredRotation() { return requiredRotation; }
@Override
public float[] getDefaultEyePositionOffset() {
@@ -182,38 +200,51 @@ public class OVRStereoDevice implements StereoDevice {
System.err.println("XXX: eyeRenderDesc[1] "+OVRUtil.toString(eyeRenderDesc[1]));
}
- final ovrSizei recommenedTex0Size = OVR.ovrHmd_GetFovTextureSize(handle, OVR.ovrEye_Left, eyeRenderDesc[0].getFov(), pixelsPerDisplayPixel);
- final ovrSizei recommenedTex1Size = OVR.ovrHmd_GetFovTextureSize(handle, OVR.ovrEye_Right, eyeRenderDesc[1].getFov(), pixelsPerDisplayPixel);
+ final DimensionImmutable eye0TextureSize = OVRUtil.getOVRSizei(OVR.ovrHmd_GetFovTextureSize(handle, OVR.ovrEye_Left, eyeRenderDesc[0].getFov(), pixelsPerDisplayPixel));
+ final DimensionImmutable eye1TextureSize = OVRUtil.getOVRSizei(OVR.ovrHmd_GetFovTextureSize(handle, OVR.ovrEye_Right, eyeRenderDesc[1].getFov(), pixelsPerDisplayPixel));
if( StereoDevice.DEBUG ) {
- System.err.println("XXX: recommenedTex0Size "+OVRUtil.toString(recommenedTex0Size));
- System.err.println("XXX: recommenedTex1Size "+OVRUtil.toString(recommenedTex1Size));
+ System.err.println("XXX: recommenedTex0Size "+eye0TextureSize);
+ System.err.println("XXX: recommenedTex1Size "+eye1TextureSize);
}
- final int unifiedW = Math.max(recommenedTex0Size.getW(), recommenedTex1Size.getW());
- final int unifiedH = Math.max(recommenedTex0Size.getH(), recommenedTex1Size.getH());
+ final int maxWidth = Math.max(eye0TextureSize.getWidth(), eye1TextureSize.getWidth());
+ final int maxHeight = Math.max(eye0TextureSize.getHeight(), eye1TextureSize.getHeight());
- final DimensionImmutable singleTextureSize = new Dimension(unifiedW, unifiedH);
- final DimensionImmutable totalTextureSize = new Dimension(recommenedTex0Size.getW() + recommenedTex1Size.getW(), unifiedH);
+ final DimensionImmutable[] eyeTextureSizes = new DimensionImmutable[] { eye0TextureSize, eye1TextureSize };
+ final DimensionImmutable totalTextureSize = new Dimension(eye0TextureSize.getWidth() + eye1TextureSize.getWidth(), maxHeight);
if( StereoDevice.DEBUG ) {
- System.err.println("XXX: textureSize Single "+singleTextureSize);
+ System.err.println("XXX: textureSize Single "+eyeTextureSizes);
System.err.println("XXX: textureSize Total "+totalTextureSize);
}
- final RectangleImmutable[] eyeRenderViewports = new RectangleImmutable[2];
+ final RectangleImmutable[] eyeViewports = new RectangleImmutable[2];
if( 1 == textureCount ) { // validated in ctor below!
- eyeRenderViewports[0] = new Rectangle(0, 0,
- totalTextureSize.getWidth() / 2,
- totalTextureSize.getHeight());
-
- eyeRenderViewports[1] = new Rectangle((totalTextureSize.getWidth() + 1) / 2, 0,
- totalTextureSize.getWidth() / 2,
- totalTextureSize.getHeight());
+ // one big texture/FBO, viewport to target space
+ if( false && 2 == dkVersion ) {
+ eyeViewports[0] = new Rectangle(0, 0,
+ maxWidth,
+ eye0TextureSize.getHeight());
+ eyeViewports[1] = new Rectangle(0, eye0TextureSize.getHeight(),
+ maxWidth,
+ eye1TextureSize.getHeight());
+ } else {
+ eyeViewports[0] = new Rectangle(0, 0,
+ eye0TextureSize.getWidth(),
+ maxHeight);
+ eyeViewports[1] = new Rectangle(eye0TextureSize.getWidth(), 0,
+ eye1TextureSize.getWidth(),
+ maxHeight);
+ }
} else {
- eyeRenderViewports[0] = new Rectangle(0, 0,
- singleTextureSize.getWidth(),
- singleTextureSize.getHeight());
- eyeRenderViewports[1] = eyeRenderViewports[0];
+ // two textures/FBOs w/ postprocessing, which renders textures/FBOs into target space
+ // FIXME: DK2
+ eyeViewports[0] = new Rectangle(0, 0,
+ eye0TextureSize.getWidth(),
+ eye0TextureSize.getHeight());
+ eyeViewports[1] = new Rectangle(0, 0,
+ eye1TextureSize.getWidth(),
+ eye1TextureSize.getHeight());
}
return new OVRStereoDeviceRenderer(this, distortionBits, textureCount, eyePositionOffset,
- eyeRenderDesc, singleTextureSize, totalTextureSize, eyeRenderViewports, textureUnit);
+ eyeRenderDesc, eyeTextureSizes, totalTextureSize, eyeViewports, textureUnit);
}
} \ No newline at end of file
diff --git a/src/oculusvr/classes/jogamp/opengl/oculusvr/OVRStereoDeviceFactory.java b/src/oculusvr/classes/jogamp/opengl/oculusvr/OVRStereoDeviceFactory.java
index 06f716ddc..dfaead1ea 100644
--- a/src/oculusvr/classes/jogamp/opengl/oculusvr/OVRStereoDeviceFactory.java
+++ b/src/oculusvr/classes/jogamp/opengl/oculusvr/OVRStereoDeviceFactory.java
@@ -30,8 +30,8 @@ package jogamp.opengl.oculusvr;
import com.jogamp.oculusvr.OVR;
import com.jogamp.oculusvr.OVRVersion;
import com.jogamp.oculusvr.OvrHmdContext;
+import com.jogamp.opengl.util.stereo.StereoDeviceConfig;
import com.jogamp.opengl.util.stereo.StereoDevice;
-import com.jogamp.opengl.util.stereo.StereoDevice.Config;
import com.jogamp.opengl.util.stereo.StereoDeviceFactory;
public class OVRStereoDeviceFactory extends StereoDeviceFactory {
@@ -44,7 +44,7 @@ public class OVRStereoDeviceFactory extends StereoDeviceFactory {
}
@Override
- public final StereoDevice createDevice(final int deviceIndex, final Config config, final boolean verbose) {
+ public final StereoDevice createDevice(final int deviceIndex, final StereoDeviceConfig config, final boolean verbose) {
final OvrHmdContext hmdCtx = OVR.ovrHmd_Create(deviceIndex);
if( null == hmdCtx ) {
if( verbose ) {
diff --git a/src/oculusvr/classes/jogamp/opengl/oculusvr/OVRStereoDeviceRenderer.java b/src/oculusvr/classes/jogamp/opengl/oculusvr/OVRStereoDeviceRenderer.java
index 1e5656129..5da5cbeca 100644
--- a/src/oculusvr/classes/jogamp/opengl/oculusvr/OVRStereoDeviceRenderer.java
+++ b/src/oculusvr/classes/jogamp/opengl/oculusvr/OVRStereoDeviceRenderer.java
@@ -29,6 +29,7 @@ package jogamp.opengl.oculusvr;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
+import java.util.Arrays;
import com.jogamp.nativewindow.util.DimensionImmutable;
import com.jogamp.nativewindow.util.RectangleImmutable;
@@ -375,7 +376,7 @@ public class OVRStereoDeviceRenderer implements StereoDeviceRenderer {
private final OVREye[] eyes;
private final int distortionBits;
private final int textureCount;
- private final DimensionImmutable singleTextureSize;
+ private final DimensionImmutable[] eyeTextureSizes;
private final DimensionImmutable totalTextureSize;
private final GLUniformData texUnit0;
@@ -389,7 +390,7 @@ public class OVRStereoDeviceRenderer implements StereoDeviceRenderer {
@Override
public String toString() {
return "OVRDist[distortion["+StereoUtil.distortionBitsToString(distortionBits)+
- "], singleSize "+singleTextureSize+
+ "], eyeTexSize "+Arrays.toString(eyeTextureSizes)+
", sbsSize "+totalTextureSize+
", texCount "+textureCount+", texUnit "+getTextureUnit()+
", "+PlatformPropsImpl.NEWLINE+" "+eyes[0]+", "+PlatformPropsImpl.NEWLINE+" "+eyes[1]+"]";
@@ -412,7 +413,8 @@ public class OVRStereoDeviceRenderer implements StereoDeviceRenderer {
/* pp */ OVRStereoDeviceRenderer(final OVRStereoDevice context, final int distortionBits,
final int textureCount, final float[] eyePositionOffset,
- final ovrEyeRenderDesc[] eyeRenderDescs, final DimensionImmutable singleTextureSize, final DimensionImmutable totalTextureSize,
+ final ovrEyeRenderDesc[] eyeRenderDescs,
+ final DimensionImmutable[] eyeTextureSizes, final DimensionImmutable totalTextureSize,
final RectangleImmutable[] eyeViewports, final int textureUnit) {
if( 1 > textureCount || 2 < textureCount ) {
throw new IllegalArgumentException("textureCount can only be 1 or 2, has "+textureCount);
@@ -421,14 +423,21 @@ public class OVRStereoDeviceRenderer implements StereoDeviceRenderer {
this.eyes = new OVREye[2];
this.distortionBits = ( distortionBits | context.getMinimumDistortionBits() ) & context.getSupportedDistortionBits();
this.textureCount = textureCount;
- this.singleTextureSize = singleTextureSize;
+ this.eyeTextureSizes = eyeTextureSizes;
this.totalTextureSize = totalTextureSize;
texUnit0 = new GLUniformData("ovr_Texture0", textureUnit);
- final ovrSizei ovrTextureSize = OVRUtil.createOVRSizei( 1 == textureCount ? totalTextureSize : singleTextureSize );
- eyes[0] = new OVREye(context.handle, this.distortionBits, eyePositionOffset, eyeRenderDescs[0], ovrTextureSize, eyeViewports[0]);
- eyes[1] = new OVREye(context.handle, this.distortionBits, eyePositionOffset, eyeRenderDescs[1], ovrTextureSize, eyeViewports[1]);
+ final ovrSizei ovrTexture0Size, ovrTexture1Size;
+ if( 1 == textureCount ) {
+ ovrTexture0Size = OVRUtil.createOVRSizei(totalTextureSize);
+ ovrTexture1Size = ovrTexture0Size;
+ } else {
+ ovrTexture0Size = OVRUtil.createOVRSizei(eyeTextureSizes[0]);
+ ovrTexture1Size = OVRUtil.createOVRSizei(eyeTextureSizes[1]);
+ }
+ eyes[0] = new OVREye(context.handle, this.distortionBits, eyePositionOffset, eyeRenderDescs[0], ovrTexture0Size, eyeViewports[0]);
+ eyes[1] = new OVREye(context.handle, this.distortionBits, eyePositionOffset, eyeRenderDescs[1], ovrTexture1Size, eyeViewports[1]);
sp = null;
frameTiming = null;
}
@@ -445,7 +454,7 @@ public class OVRStereoDeviceRenderer implements StereoDeviceRenderer {
public final boolean usesSideBySideStereo() { return true; }
@Override
- public final DimensionImmutable getSingleSurfaceSize() { return singleTextureSize; }
+ public final DimensionImmutable[] getEyeSurfaceSize() { return eyeTextureSizes; }
@Override
public final DimensionImmutable getTotalSurfaceSize() { return totalTextureSize; }
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/stereo/StereoDemo01.java b/src/test/com/jogamp/opengl/test/junit/jogl/stereo/StereoDemo01.java
index 4f8fb3bd2..39ca85527 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/stereo/StereoDemo01.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/stereo/StereoDemo01.java
@@ -40,9 +40,12 @@ import com.jogamp.opengl.GLProfile;
import jogamp.opengl.util.stereo.GenericStereoDevice;
import com.jogamp.common.net.Uri;
+import com.jogamp.newt.MonitorDevice;
+import com.jogamp.newt.Screen;
import com.jogamp.newt.event.KeyAdapter;
import com.jogamp.newt.event.KeyEvent;
import com.jogamp.newt.opengl.GLWindow;
+import com.jogamp.newt.opengl.util.stereo.StereoDeviceUtil;
import com.jogamp.opengl.math.FovHVHalves;
import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2;
import com.jogamp.opengl.test.junit.jogl.demos.es2.av.MovieSBSStereo;
@@ -249,15 +252,21 @@ public class StereoDemo01 {
//
//
//
- final GLCapabilities caps = new GLCapabilities(GLProfile.getMaxProgrammable(true /* favorHardwareRasterizer */));
- final GLWindow window = GLWindow.create(caps);
-
final PointImmutable devicePos = stereoDevice.getPosition();
final DimensionImmutable deviceRes = stereoDevice.getSurfaceSize();
+ System.err.println("Device Res "+deviceRes+", reqRotation "+stereoDevice.getRequiredRotation());
+ System.err.println("Device Pos "+devicePos);
+
+ final MonitorDevice monitor = StereoDeviceUtil.getMonitorDevice(stereoDevice, true);
+ final Screen screen = monitor.getScreen();
+
+ final GLCapabilities caps = new GLCapabilities(GLProfile.getMaxProgrammable(true /* favorHardwareRasterizer */));
+ final GLWindow window = GLWindow.create(screen, caps);
+
if( useStereoScreen ) {
window.setPosition(devicePos.getX(), devicePos.getY());
}
- window.setSurfaceSize(deviceRes.getWidth(), deviceRes.getHeight()); // might be not correct ..
+ window.setSurfaceSize(deviceRes.getWidth(), deviceRes.getHeight());
window.setAutoSwapBufferMode(useAutoSwap);
window.setUndecorated(true);
@@ -361,6 +370,7 @@ public class StereoDemo01 {
animator.stop();
}
window.destroy();
+ screen.removeReference(); // StereoDeviceUtil.getMonitorDevice(stereoDevice, true);
stereoDevice.dispose();
}
}