diff options
Diffstat (limited to 'src/oculusvr/classes/com/jogamp/opengl')
-rw-r--r-- | src/oculusvr/classes/com/jogamp/opengl/oculusvr/OVRSBSRendererDualFBO.java | 232 | ||||
-rw-r--r-- | src/oculusvr/classes/com/jogamp/opengl/oculusvr/OVRSBSRendererSingleFBO.java | 206 |
2 files changed, 438 insertions, 0 deletions
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); + } + } +} |