summaryrefslogtreecommitdiffstats
path: root/src/oculusvr/classes/com
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2014-07-01 21:02:21 +0200
committerSven Gothel <[email protected]>2014-07-01 21:02:21 +0200
commit36327e24cf586b50bf18e87d7d13d53eb41cf1d9 (patch)
treeb34c88274eebce4839ee18b5958a2019de565b87 /src/oculusvr/classes/com
parenta0498e240b9dfde345a704ec6de1d6abcee7b318 (diff)
Bug 1021: Add OculusVR distortion renderer (single FBO and dual FBO); Add GLEventListener2 (WIP); Refine FloatUtil
- GLEventListener2 extends GLEventListener adds refined control: - display w/ flags, i.e. repeat, don't clear - setProjectionModelview(..) - FloatUtil.* Add return value for chaining, where missing +++ - jogamp.opengl.oculusvr.OVRDistortion - Handles all OVR related data and maps it to shader + GL buffers - display method - com.jogamp.opengl.oculusvr.OVRSBSRendererSingleFBO implements GLEventListener - Simple OVRDistortion renderer using single FBO - Using upstream GLEventListener2 (the content) - com.jogamp.opengl.oculusvr.OVRSBSRendererDualFBO implements GLEventListener - Simple OVRDistortion renderer using two FBOs - Using upstream GLEventListener2 (the content) Manual Test: com.jogamp.opengl.test.junit.jogl.stereo.ovr.OVRDemo01
Diffstat (limited to 'src/oculusvr/classes/com')
-rw-r--r--src/oculusvr/classes/com/jogamp/oculusvr/OVRDynamicLibraryBundleInfo.java6
-rw-r--r--src/oculusvr/classes/com/jogamp/oculusvr/OVRException.java43
-rw-r--r--src/oculusvr/classes/com/jogamp/oculusvr/OVRVersion.java7
-rw-r--r--src/oculusvr/classes/com/jogamp/opengl/oculusvr/OVRSBSRendererDualFBO.java232
-rw-r--r--src/oculusvr/classes/com/jogamp/opengl/oculusvr/OVRSBSRendererSingleFBO.java206
5 files changed, 472 insertions, 22 deletions
diff --git a/src/oculusvr/classes/com/jogamp/oculusvr/OVRDynamicLibraryBundleInfo.java b/src/oculusvr/classes/com/jogamp/oculusvr/OVRDynamicLibraryBundleInfo.java
index 6bd9d1a64..8eafb9927 100644
--- a/src/oculusvr/classes/com/jogamp/oculusvr/OVRDynamicLibraryBundleInfo.java
+++ b/src/oculusvr/classes/com/jogamp/oculusvr/OVRDynamicLibraryBundleInfo.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2010 JogAmp Community. All rights reserved.
+ * 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:
@@ -95,12 +95,12 @@ import java.util.*;
}
@Override
- public final long toolGetProcAddress(long toolGetProcAddressHandle, String funcName) {
+ public final long toolGetProcAddress(final long toolGetProcAddressHandle, final String funcName) {
return 0;
}
@Override
- public final boolean useToolGetProcAdressFirst(String funcName) {
+ public final boolean useToolGetProcAdressFirst(final String funcName) {
return false;
}
diff --git a/src/oculusvr/classes/com/jogamp/oculusvr/OVRException.java b/src/oculusvr/classes/com/jogamp/oculusvr/OVRException.java
index e65338025..f2a254e14 100644
--- a/src/oculusvr/classes/com/jogamp/oculusvr/OVRException.java
+++ b/src/oculusvr/classes/com/jogamp/oculusvr/OVRException.java
@@ -1,22 +1,29 @@
/**
- * Copyright (C) 2014 JogAmp Community. All rights reserved.
+ * Copyright 2014 JogAmp Community. All rights reserved.
*
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
*
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
*
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ * 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.oculusvr;
@@ -32,19 +39,19 @@ public class OVRException extends RuntimeException {
/** Constructs an ALException object with the specified detail
message. */
- public OVRException(String message) {
+ public OVRException(final String message) {
super(message);
}
/** Constructs an ALException object with the specified detail
message and root cause. */
- public OVRException(String message, Throwable cause) {
+ public OVRException(final String message, final Throwable cause) {
super(message, cause);
}
/** Constructs an ALException object with the specified root
cause. */
- public OVRException(Throwable cause) {
+ public OVRException(final Throwable cause) {
super(cause);
}
}
diff --git a/src/oculusvr/classes/com/jogamp/oculusvr/OVRVersion.java b/src/oculusvr/classes/com/jogamp/oculusvr/OVRVersion.java
index 25db640e4..eebd771d8 100644
--- a/src/oculusvr/classes/com/jogamp/oculusvr/OVRVersion.java
+++ b/src/oculusvr/classes/com/jogamp/oculusvr/OVRVersion.java
@@ -29,10 +29,15 @@
package com.jogamp.oculusvr;
import com.jogamp.common.GlueGenVersion;
-
import com.jogamp.common.os.Platform;
import com.jogamp.common.util.VersionUtil;
import com.jogamp.common.util.JogampVersion;
+import com.jogamp.oculusvr.OVR;
+import com.jogamp.oculusvr.OvrHmdContext;
+import com.jogamp.oculusvr.ovrHmdDesc;
+import com.jogamp.oculusvr.ovrSensorDesc;
+import com.jogamp.oculusvr.ovrSizei;
+import com.jogamp.oculusvr.ovrVector2i;
import java.util.jar.Manifest;
diff --git a/src/oculusvr/classes/com/jogamp/opengl/oculusvr/OVRSBSRendererDualFBO.java b/src/oculusvr/classes/com/jogamp/opengl/oculusvr/OVRSBSRendererDualFBO.java
new file mode 100644
index 000000000..b10a58842
--- /dev/null
+++ b/src/oculusvr/classes/com/jogamp/opengl/oculusvr/OVRSBSRendererDualFBO.java
@@ -0,0 +1,232 @@
+/**
+ * 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.oculusvr;
+
+import javax.media.opengl.GL;
+import javax.media.opengl.GL2ES2;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLEventListener;
+import javax.media.opengl.GLEventListener2;
+
+import jogamp.opengl.oculusvr.OVRDistortion;
+
+import com.jogamp.oculusvr.OVR;
+import com.jogamp.oculusvr.ovrFrameTiming;
+import com.jogamp.opengl.FBObject;
+import com.jogamp.opengl.FBObject.TextureAttachment;
+import com.jogamp.opengl.FBObject.Attachment.Type;
+import com.jogamp.opengl.math.FloatUtil;
+
+/**
+ * OculusVR (OVR) <i>Side By Side</i> Distortion Renderer utilizing {@link OVRDistortion}
+ * implementing {@link GLEventListener} for convenience.
+ * <p>
+ * Implementation renders an {@link GLEventListener2} instance
+ * side-by-side using two {@link FBObject}s according to {@link OVRDistortion}.
+ * </p>
+ */
+public class OVRSBSRendererDualFBO implements GLEventListener {
+
+ private final float[] mat4Projection = new float[16];
+ private final float[] mat4Modelview = new float[16];
+ private final OVRDistortion dist;
+ private final boolean ownsDist;
+ private final GLEventListener2 upstream;
+ private final FBObject[] fbos;
+
+ // final float[] eyePos = { 0.0f, 1.6f, -5.0f };
+ private final float[] eyePos = { 0.0f, 0.0f, -20.0f };
+ // EyePos.y = ovrHmd_GetFloat(HMD, OVR_KEY_EYE_HEIGHT, EyePos.y);
+ private float eyeYaw = FloatUtil.PI; // 180 degrees in radians
+ private float frustumNear = 0.1f;
+ private float frustumFar = 7000f;
+ private int numSamples;
+ private final TextureAttachment[] fboTexs;
+
+ public OVRSBSRendererDualFBO(final OVRDistortion dist, final boolean ownsDist, final GLEventListener2 upstream, final int numSamples) {
+ this.dist = dist;
+ this.ownsDist = ownsDist;
+ this.upstream = upstream;
+ this.numSamples = numSamples;
+ fbos = new FBObject[2];
+ fbos[0] = new FBObject();
+ fbos[1] = new FBObject();
+ fboTexs = new TextureAttachment[2];
+ }
+
+ /**
+ *
+ * @param eyePos
+ * @param eyeYaw
+ * @param frustumNear
+ * @param frustumFar
+ */
+ public void setUpstreamPMVParams(final float[] eyePos, final float eyeYaw, final float frustumNear, final float frustumFar) {
+ System.arraycopy(eyePos, 0, this.eyePos, 0, 3);
+ this.eyeYaw = eyeYaw;
+ this.frustumNear = frustumNear;
+ this.frustumFar = frustumFar;
+ }
+
+ private void initFBOs(final GL gl, final int width, final int height) {
+ // remove all texture attachments, since MSAA uses just color-render-buffer
+ // and non-MSAA uses texture2d-buffer
+ fbos[0].detachAllColorbuffer(gl);
+ fbos[1].detachAllColorbuffer(gl);
+
+ fbos[0].reset(gl, width, height, numSamples, false);
+ fbos[1].reset(gl, width, height, numSamples, false);
+ if(fbos[0].getNumSamples() != fbos[1].getNumSamples()) {
+ throw new InternalError("sample size mismatch: \n\t0: "+fbos[0]+"\n\t1: "+fbos[1]);
+ }
+ numSamples = fbos[0].getNumSamples();
+
+ if(numSamples>0) {
+ fbos[0].attachColorbuffer(gl, 0, true);
+ fbos[0].resetSamplingSink(gl);
+ fbos[1].attachColorbuffer(gl, 0, true);
+ fbos[1].resetSamplingSink(gl);
+ fboTexs[0] = fbos[0].getSamplingSink();
+ fboTexs[1] = fbos[1].getSamplingSink();
+ } else {
+ fboTexs[0] = fbos[0].attachTexture2D(gl, 0, true);
+ fboTexs[1] = fbos[1].attachTexture2D(gl, 0, true);
+ }
+ numSamples=fbos[0].getNumSamples();
+ fbos[0].attachRenderbuffer(gl, Type.DEPTH, 24);
+ fbos[0].unbind(gl);
+ fbos[1].attachRenderbuffer(gl, Type.DEPTH, 24);
+ fbos[1].unbind(gl);
+ }
+
+ @SuppressWarnings("unused")
+ private void resetFBOs(final GL gl, final int width, final int height) {
+ fbos[0].reset(gl, width, height, numSamples, true);
+ fbos[1].reset(gl, width, height, numSamples, true);
+ if(fbos[0].getNumSamples() != fbos[1].getNumSamples()) {
+ throw new InternalError("sample size mismatch: \n\t0: "+fbos[0]+"\n\t1: "+fbos[1]);
+ }
+ numSamples = fbos[0].getNumSamples();
+ if(numSamples>0) {
+ fboTexs[0] = fbos[0].getSamplingSink();
+ fboTexs[1] = fbos[1].getSamplingSink();
+ } else {
+ fboTexs[0] = (TextureAttachment) fbos[0].getColorbuffer(0);
+ fboTexs[1] = (TextureAttachment) fbos[1].getColorbuffer(0);
+ }
+ }
+
+ @Override
+ public void init(final GLAutoDrawable drawable) {
+ final GL2ES2 gl = drawable.getGL().getGL2ES2();
+ dist.init(gl);
+
+ // We will do some offscreen rendering, setup FBO...
+ if( null != upstream ) {
+ final int[] textureSize = dist.textureSize;
+ initFBOs(gl, textureSize[0], textureSize[1]);
+ upstream.init(drawable);
+ }
+
+ gl.setSwapInterval(1);
+ }
+
+ @Override
+ public void dispose(final GLAutoDrawable drawable) {
+ final GL2ES2 gl = drawable.getGL().getGL2ES2();
+ // FIXME complete release
+ if( null != upstream ) {
+ upstream.dispose(drawable);
+ fbos[0].destroy(gl);
+ fbos[1].destroy(gl);
+ }
+ if( ownsDist ) {
+ dist.dispose(gl);
+ }
+ }
+
+ @Override
+ public void display(final GLAutoDrawable drawable) {
+ final ovrFrameTiming frameTiming = OVR.ovrHmd_BeginFrameTiming(dist.hmdCtx, 0);
+
+ final GL2ES2 gl = drawable.getGL().getGL2ES2();
+ if(0 < numSamples) {
+ gl.glEnable(GL.GL_MULTISAMPLE);
+ }
+
+ // FIXME: Instead of setting the viewport,
+ // it's better to change the projection matrix!
+ if( null != upstream ) {
+ for(int eyeNum=0; eyeNum<2; eyeNum++) {
+ // final ovrPosef eyeRenderPose = OVR.ovrHmd_GetEyePose(hmdCtx, eyeNum);
+ // final float[] eyePos = OVRUtil.getVec3f(eyeRenderPose.getPosition());
+ fbos[eyeNum].bind(gl);
+
+ final OVRDistortion.EyeData eyeDist = dist.eyes[eyeNum];
+ final int[] viewport = eyeDist.viewport;
+ gl.glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
+
+ dist.getSBSUpstreamPMV(eyeNum, eyePos, eyeYaw, frustumNear, frustumFar, mat4Projection, mat4Modelview);
+ upstream.setProjectionModelview(drawable, mat4Projection, mat4Modelview);
+ upstream.display(drawable, eyeNum > 0 ? GLEventListener2.DISPLAY_REPEAT : 0);
+ fbos[eyeNum].unbind(gl);
+ }
+ gl.glViewport(0, 0, drawable.getSurfaceWidth(), drawable.getSurfaceHeight());
+ }
+
+ gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ gl.glClear(GL.GL_COLOR_BUFFER_BIT);
+ gl.glActiveTexture(GL.GL_TEXTURE0 + dist.texUnit0.intValue());
+
+ if( null != upstream ) {
+ dist.displayOneEyePre(gl, frameTiming.getTimewarpPointSeconds());
+ fbos[0].use(gl, fboTexs[0]);
+ dist.displayOneEye(gl, 0);
+ fbos[0].unuse(gl);
+ fbos[1].use(gl, fboTexs[1]);
+ dist.displayOneEye(gl, 1);
+ fbos[1].unuse(gl);
+ dist.displayOneEyePost(gl);
+ } else {
+ dist.display(gl, frameTiming.getTimewarpPointSeconds());
+ }
+
+ if( !drawable.getAutoSwapBufferMode() ) {
+ drawable.swapBuffers();
+ }
+ OVR.ovrHmd_EndFrameTiming(dist.hmdCtx);
+ }
+
+ @Override
+ public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) {
+ if( !drawable.getAutoSwapBufferMode() ) {
+ final GL2ES2 gl = drawable.getGL().getGL2ES2();
+ gl.glViewport(0, 0, width, height);
+ }
+ }
+}
diff --git a/src/oculusvr/classes/com/jogamp/opengl/oculusvr/OVRSBSRendererSingleFBO.java b/src/oculusvr/classes/com/jogamp/opengl/oculusvr/OVRSBSRendererSingleFBO.java
new file mode 100644
index 000000000..22b8b37ce
--- /dev/null
+++ b/src/oculusvr/classes/com/jogamp/opengl/oculusvr/OVRSBSRendererSingleFBO.java
@@ -0,0 +1,206 @@
+/**
+ * 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.oculusvr;
+
+import javax.media.opengl.GL;
+import javax.media.opengl.GL2ES2;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLEventListener;
+import javax.media.opengl.GLEventListener2;
+
+import jogamp.opengl.oculusvr.OVRDistortion;
+
+import com.jogamp.oculusvr.OVR;
+import com.jogamp.oculusvr.ovrFrameTiming;
+import com.jogamp.opengl.FBObject;
+import com.jogamp.opengl.FBObject.TextureAttachment;
+import com.jogamp.opengl.FBObject.Attachment.Type;
+import com.jogamp.opengl.math.FloatUtil;
+
+/**
+ * OculusVR (OVR) <i>Side By Side</i> Distortion Renderer utilizing {@link OVRDistortion}
+ * implementing {@link GLEventListener} for convenience.
+ * <p>
+ * Implementation renders an {@link GLEventListener2} instance
+ * side-by-side within one {@link FBObject} according to {@link OVRDistortion}.
+ * </p>
+ */
+public class OVRSBSRendererSingleFBO implements GLEventListener {
+
+ private final float[] mat4Projection = new float[16];
+ private final float[] mat4Modelview = new float[16];
+ private final OVRDistortion dist;
+ private final boolean ownsDist;
+ private final GLEventListener2 upstream;
+ private final FBObject fbo0;
+
+ // final float[] eyePos = { 0.0f, 1.6f, -5.0f };
+ private final float[] eyePos = { 0.0f, 0.0f, -20.0f };
+ // EyePos.y = ovrHmd_GetFloat(HMD, OVR_KEY_EYE_HEIGHT, EyePos.y);
+ private float eyeYaw = FloatUtil.PI; // 180 degrees in radians
+ private float frustumNear = 0.1f;
+ private float frustumFar = 7000f;
+ private int numSamples;
+ private TextureAttachment fbo0Tex;
+
+ public OVRSBSRendererSingleFBO(final OVRDistortion dist, final boolean ownsDist, final GLEventListener2 upstream, final int numSamples) {
+ this.dist = dist;
+ this.ownsDist = ownsDist;
+ this.upstream = upstream;
+ this.numSamples = numSamples;
+ fbo0 = new FBObject();
+ }
+
+ /**
+ *
+ * @param eyePos
+ * @param eyeYaw
+ * @param frustumNear
+ * @param frustumFar
+ */
+ public void setUpstreamPMVParams(final float[] eyePos, final float eyeYaw, final float frustumNear, final float frustumFar) {
+ System.arraycopy(eyePos, 0, this.eyePos, 0, 3);
+ this.eyeYaw = eyeYaw;
+ this.frustumNear = frustumNear;
+ this.frustumFar = frustumFar;
+ }
+
+ private void initFBOs(final GL gl, final int width, final int height) {
+ // remove all texture attachments, since MSAA uses just color-render-buffer
+ // and non-MSAA uses texture2d-buffer
+ fbo0.detachAllColorbuffer(gl);
+
+ fbo0.reset(gl, width, height, numSamples, false);
+ numSamples = fbo0.getNumSamples();
+
+ if(numSamples>0) {
+ fbo0.attachColorbuffer(gl, 0, true);
+ fbo0.resetSamplingSink(gl);
+ fbo0Tex = fbo0.getSamplingSink();
+ } else {
+ fbo0Tex = fbo0.attachTexture2D(gl, 0, true);
+ }
+ numSamples=fbo0.getNumSamples();
+ fbo0.attachRenderbuffer(gl, Type.DEPTH, 24);
+ fbo0.unbind(gl);
+ }
+
+ @SuppressWarnings("unused")
+ private void resetFBOs(final GL gl, final int width, final int height) {
+ fbo0.reset(gl, width, height, numSamples, true);
+ numSamples = fbo0.getNumSamples();
+ if(numSamples>0) {
+ fbo0Tex = fbo0.getSamplingSink();
+ } else {
+ fbo0Tex = (TextureAttachment) fbo0.getColorbuffer(0);
+ }
+ }
+
+ @Override
+ public void init(final GLAutoDrawable drawable) {
+ final GL2ES2 gl = drawable.getGL().getGL2ES2();
+ dist.init(gl);
+
+ // We will do some offscreen rendering, setup FBO...
+ if( null != upstream ) {
+ final int[] textureSize = dist.textureSize;
+ initFBOs(gl, textureSize[0], textureSize[1]);
+ upstream.init(drawable);
+ }
+
+ gl.setSwapInterval(1);
+ }
+
+ @Override
+ public void dispose(final GLAutoDrawable drawable) {
+ final GL2ES2 gl = drawable.getGL().getGL2ES2();
+ // FIXME complete release
+ if( null != upstream ) {
+ upstream.dispose(drawable);
+ fbo0.destroy(gl);
+ }
+ if( ownsDist ) {
+ dist.dispose(gl);
+ }
+ }
+
+ @Override
+ public void display(final GLAutoDrawable drawable) {
+ final ovrFrameTiming frameTiming = OVR.ovrHmd_BeginFrameTiming(dist.hmdCtx, 0);
+
+ final GL2ES2 gl = drawable.getGL().getGL2ES2();
+ if(0 < numSamples) {
+ gl.glEnable(GL.GL_MULTISAMPLE);
+ }
+
+ // FIXME: Instead of setting the viewport,
+ // it's better to change the projection matrix!
+ if( null != upstream ) {
+ fbo0.bind(gl);
+
+ for(int eyeNum=0; eyeNum<2; eyeNum++) {
+ // final ovrPosef eyeRenderPose = OVR.ovrHmd_GetEyePose(hmdCtx, eyeNum);
+ // final float[] eyePos = OVRUtil.getVec3f(eyeRenderPose.getPosition());
+ final OVRDistortion.EyeData eyeDist = dist.eyes[eyeNum];
+ final int[] viewport = eyeDist.viewport;
+ gl.glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
+
+ dist.getSBSUpstreamPMV(eyeNum, eyePos, eyeYaw, frustumNear, frustumFar, mat4Projection, mat4Modelview);
+ upstream.setProjectionModelview(drawable, mat4Projection, mat4Modelview);
+ upstream.display(drawable, eyeNum > 0 ? GLEventListener2.DISPLAY_REPEAT | GLEventListener2.DISPLAY_DONTCLEAR : 0);
+ }
+ fbo0.unbind(gl);
+ gl.glViewport(0, 0, drawable.getSurfaceWidth(), drawable.getSurfaceHeight());
+ }
+
+ gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ gl.glClear(GL.GL_COLOR_BUFFER_BIT);
+ gl.glActiveTexture(GL.GL_TEXTURE0 + dist.texUnit0.intValue());
+
+ if( null != upstream ) {
+ fbo0.use(gl, fbo0Tex);
+ dist.display(gl, frameTiming.getTimewarpPointSeconds());
+ fbo0.unuse(gl);
+ } else {
+ dist.display(gl, frameTiming.getTimewarpPointSeconds());
+ }
+
+ if( !drawable.getAutoSwapBufferMode() ) {
+ drawable.swapBuffers();
+ }
+ OVR.ovrHmd_EndFrameTiming(dist.hmdCtx);
+ }
+
+ @Override
+ public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) {
+ if( !drawable.getAutoSwapBufferMode() ) {
+ final GL2ES2 gl = drawable.getGL().getGL2ES2();
+ gl.glViewport(0, 0, width, height);
+ }
+ }
+}