jogamp.opengl.oculusvr.OVRStereoDeviceRenderer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jogl-all-android Show documentation
Show all versions of jogl-all-android Show documentation
Java™ Binding for the OpenGL® API (Android)
The newest version!
/**
* 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 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;
import com.jogamp.opengl.GL;
import com.jogamp.opengl.GL2ES2;
import com.jogamp.opengl.GLArrayData;
import com.jogamp.opengl.GLException;
import com.jogamp.opengl.GLUniformData;
import jogamp.common.os.PlatformPropsImpl;
import com.jogamp.common.nio.Buffers;
import com.jogamp.oculusvr.OVR;
import com.jogamp.oculusvr.OVRException;
import com.jogamp.oculusvr.ovrDistortionMesh;
import com.jogamp.oculusvr.ovrDistortionVertex;
import com.jogamp.oculusvr.ovrEyeRenderDesc;
import com.jogamp.oculusvr.ovrFovPort;
import com.jogamp.oculusvr.ovrFrameTiming;
import com.jogamp.oculusvr.ovrHmdDesc;
import com.jogamp.oculusvr.ovrMatrix4f;
import com.jogamp.oculusvr.ovrPosef;
import com.jogamp.oculusvr.ovrRecti;
import com.jogamp.oculusvr.ovrSizei;
import com.jogamp.oculusvr.ovrTrackingState;
import com.jogamp.oculusvr.ovrVector2f;
import com.jogamp.oculusvr.ovrVector3f;
import com.jogamp.opengl.JoglVersion;
import com.jogamp.opengl.math.FloatUtil;
import com.jogamp.opengl.util.GLArrayDataServer;
import com.jogamp.opengl.util.glsl.ShaderCode;
import com.jogamp.opengl.util.glsl.ShaderProgram;
import com.jogamp.opengl.util.stereo.EyeParameter;
import com.jogamp.opengl.util.stereo.ViewerPose;
import com.jogamp.opengl.util.stereo.StereoDevice;
import com.jogamp.opengl.util.stereo.StereoDeviceRenderer;
import com.jogamp.opengl.util.stereo.StereoUtil;
/**
* OculusVR Stereo Device Distortion and OpenGL Renderer Utility
*/
public class OVRStereoDeviceRenderer implements StereoDeviceRenderer {
private static final String shaderPrefix01 = "dist01";
private static final String shaderTimewarpSuffix = "_timewarp";
private static final String shaderChromaSuffix = "_chroma";
private static final String shaderPlainSuffix = "_plain";
public static class OVREye implements StereoDeviceRenderer.Eye {
private final int eyeName;
private final int distortionBits;
private final int vertexCount;
private final int indexCount;
private final RectangleImmutable viewport;
private final GLUniformData eyeToSourceUVScale;
private final GLUniformData eyeToSourceUVOffset;
private final GLUniformData eyeRotationStart;
private final GLUniformData eyeRotationEnd;
/** 2+2+2+2+2: { vec2 position, vec2 color, vec2 texCoordR, vec2 texCoordG, vec2 texCoordB } */
private final GLArrayDataServer iVBO;
private final GLArrayData vboPos, vboParams, vboTexCoordsR, vboTexCoordsG, vboTexCoordsB;
private final GLArrayDataServer indices;
/* pp */ final ovrEyeRenderDesc ovrEyeDesc;
private final ovrFovPort ovrEyeFov;
private final EyeParameter eyeParameter;
private final ovrMatrix4f[] timeWarpMatrices;
@Override
public final RectangleImmutable getViewport() { return viewport; }
@Override
public final EyeParameter getEyeParameter() { return eyeParameter; }
/* pp */ OVREye(final ovrHmdDesc hmdDesc, final int distortionBits,
final float[] eyePositionOffset, final ovrEyeRenderDesc eyeDesc,
final ovrSizei ovrTextureSize, final RectangleImmutable eyeViewport) {
this.eyeName = eyeDesc.getEye();
this.distortionBits = distortionBits;
this.viewport = eyeViewport;
final boolean usesTimewarp = StereoUtil.usesTimewarpDistortion(distortionBits);
final FloatBuffer fstash = Buffers.newDirectFloatBuffer( 2 + 2 + ( usesTimewarp ? 16 + 16 : 0 ) ) ;
eyeToSourceUVScale = new GLUniformData("ovr_EyeToSourceUVScale", 2, Buffers.slice2Float(fstash, 0, 2));
eyeToSourceUVOffset = new GLUniformData("ovr_EyeToSourceUVOffset", 2, Buffers.slice2Float(fstash, 2, 2));
if( usesTimewarp ) {
eyeRotationStart = new GLUniformData("ovr_EyeRotationStart", 4, 4, Buffers.slice2Float(fstash, 4, 16));
eyeRotationEnd = new GLUniformData("ovr_EyeRotationEnd", 4, 4, Buffers.slice2Float(fstash, 20, 16));
timeWarpMatrices = new ovrMatrix4f[2];
timeWarpMatrices[0] = ovrMatrix4f.create();
timeWarpMatrices[1] = ovrMatrix4f.create();
} else {
eyeRotationStart = null;
eyeRotationEnd = null;
timeWarpMatrices = null;
}
this.ovrEyeDesc = eyeDesc;
this.ovrEyeFov = eyeDesc.getFov();
final ovrVector3f eyeViewAdjust = eyeDesc.getHmdToEyeViewOffset();
this.eyeParameter = new EyeParameter(eyeName, eyePositionOffset, OVRUtil.getFovHV(ovrEyeFov),
eyeViewAdjust.getX(), eyeViewAdjust.getY(), eyeViewAdjust.getZ());
// Setup: eyeToSourceUVScale, eyeToSourceUVOffset
{
final ovrVector2f[] uvScaleOffsetOut = new ovrVector2f[2];
uvScaleOffsetOut[0] = ovrVector2f.create();
uvScaleOffsetOut[1] = ovrVector2f.create();
final ovrRecti ovrEyeRenderViewport = OVRUtil.createOVRRecti(eyeViewport);
OVR.ovrHmd_GetRenderScaleAndOffset(ovrEyeFov, ovrTextureSize, ovrEyeRenderViewport, uvScaleOffsetOut);
if( StereoDevice.DEBUG ) {
System.err.println("XXX."+eyeName+": eyeParam "+eyeParameter);
System.err.println("XXX."+eyeName+": uvScale "+OVRUtil.toString(uvScaleOffsetOut[0]));
System.err.println("XXX."+eyeName+": uvOffset "+OVRUtil.toString(uvScaleOffsetOut[1]));
System.err.println("XXX."+eyeName+": textureSize "+OVRUtil.toString(ovrTextureSize));
System.err.println("XXX."+eyeName+": viewport "+OVRUtil.toString(ovrEyeRenderViewport));
}
final FloatBuffer eyeToSourceUVScaleFB = eyeToSourceUVScale.floatBufferValue();
eyeToSourceUVScaleFB.put(0, uvScaleOffsetOut[0].getX());
eyeToSourceUVScaleFB.put(1, uvScaleOffsetOut[0].getY());
final FloatBuffer eyeToSourceUVOffsetFB = eyeToSourceUVOffset.floatBufferValue();
eyeToSourceUVOffsetFB.put(0, uvScaleOffsetOut[1].getX());
eyeToSourceUVOffsetFB.put(1, uvScaleOffsetOut[1].getY());
}
final ovrDistortionMesh meshData = ovrDistortionMesh.create();
final int ovrDistortionCaps = distBits2OVRDistCaps(distortionBits);
if( !OVR.ovrHmd_CreateDistortionMesh(hmdDesc, eyeName, ovrEyeFov, ovrDistortionCaps, meshData) ) {
throw new OVRException("Failed to create meshData for eye "+eyeName+", "+OVRUtil.toString(ovrEyeFov)+" and "+StereoUtil.distortionBitsToString(distortionBits));
}
vertexCount = meshData.getVertexCount();
indexCount = meshData.getIndexCount();
/** 2+2+2+2+2: { vec2 position, vec2 color, vec2 texCoordR, vec2 texCoordG, vec2 texCoordB } */
final boolean useChromatic = StereoUtil.usesChromaticDistortion(distortionBits);
final boolean useVignette = StereoUtil.usesVignetteDistortion(distortionBits);
final int compsPerElement = 2+2+2+( useChromatic ? 2+2 /* texCoordG + texCoordB */: 0 );
iVBO = GLArrayDataServer.createGLSLInterleaved(compsPerElement, GL.GL_FLOAT, false, vertexCount, GL.GL_STATIC_DRAW);
vboPos = iVBO.addGLSLSubArray("ovr_Position", 2, GL.GL_ARRAY_BUFFER);
vboParams = iVBO.addGLSLSubArray("ovr_Params", 2, GL.GL_ARRAY_BUFFER);
vboTexCoordsR = iVBO.addGLSLSubArray("ovr_TexCoordR", 2, GL.GL_ARRAY_BUFFER);
if( useChromatic ) {
vboTexCoordsG = iVBO.addGLSLSubArray("ovr_TexCoordG", 2, GL.GL_ARRAY_BUFFER);
vboTexCoordsB = iVBO.addGLSLSubArray("ovr_TexCoordB", 2, GL.GL_ARRAY_BUFFER);
} else {
vboTexCoordsG = null;
vboTexCoordsB = null;
}
indices = GLArrayDataServer.createData(1, GL.GL_SHORT, indexCount, GL.GL_STATIC_DRAW, GL.GL_ELEMENT_ARRAY_BUFFER);
/** 2+2+2+2+2: { vec2 position, vec2 color, vec2 texCoordR, vec2 texCoordG, vec2 texCoordB } */
final FloatBuffer iVBOFB = (FloatBuffer)iVBO.getBuffer();
final ovrDistortionVertex[] ovRes = new ovrDistortionVertex[1];
ovRes[0] = ovrDistortionVertex.create();
for ( int vertNum = 0; vertNum < vertexCount; vertNum++ ) {
final ovrDistortionVertex ov = meshData.getPVertexData(vertNum, ovRes)[0];
ovrVector2f v;
if( StereoDevice.DUMP_DATA ) {
System.err.println("XXX."+eyeName+": START VERTEX "+vertNum+" / "+vertexCount);
}
// pos
v = ov.getScreenPosNDC();
if( StereoDevice.DUMP_DATA ) {
System.err.println("XXX."+eyeName+": pos "+OVRUtil.toString(v));
}
iVBOFB.put(v.getX());
iVBOFB.put(v.getY());
// params
if( useVignette ) {
if( StereoDevice.DUMP_DATA ) {
System.err.println("XXX."+eyeName+": vignette "+ov.getVignetteFactor());
}
iVBOFB.put(ov.getVignetteFactor());
} else {
iVBOFB.put(1.0f);
}
if( StereoDevice.DUMP_DATA ) {
System.err.println("XXX."+eyeName+": timewarp "+ov.getTimeWarpFactor());
}
iVBOFB.put(ov.getTimeWarpFactor());
// texCoordR
v = ov.getTanEyeAnglesR();
if( StereoDevice.DUMP_DATA ) {
System.err.println("XXX."+eyeName+": texR "+OVRUtil.toString(v));
}
iVBOFB.put(v.getX());
iVBOFB.put(v.getY());
if( useChromatic ) {
// texCoordG
v = ov.getTanEyeAnglesG();
if( StereoDevice.DUMP_DATA ) {
System.err.println("XXX."+eyeName+": texG "+OVRUtil.toString(v));
}
iVBOFB.put(v.getX());
iVBOFB.put(v.getY());
// texCoordB
v = ov.getTanEyeAnglesB();
if( StereoDevice.DUMP_DATA ) {
System.err.println("XXX."+eyeName+": texB "+OVRUtil.toString(v));
}
iVBOFB.put(v.getX());
iVBOFB.put(v.getY());
}
}
if( StereoDevice.DUMP_DATA ) {
System.err.println("XXX."+eyeName+": iVBO "+iVBO);
}
{
final ShortBuffer in = meshData.getPIndexData();
if( StereoDevice.DUMP_DATA ) {
System.err.println("XXX."+eyeName+": idx "+indices+", count "+indexCount);
for(int i=0; i< indexCount; i++) {
if( 0 == i % 16 ) {
System.err.printf("%n%5d: ", i);
}
System.err.printf("%5d, ", (int)in.get(i));
}
System.err.println();
}
final ShortBuffer out = (ShortBuffer) indices.getBuffer();
out.put(in);
}
if( StereoDevice.DEBUG ) {
System.err.println("XXX."+eyeName+": "+this);
}
OVR.ovrHmd_DestroyDistortionMesh(meshData);
}
/* pp */ void linkData(final GL2ES2 gl, final ShaderProgram sp) {
if( 0 > vboPos.setLocation(gl, sp.program()) ) {
throw new GLException("Couldn't locate "+vboPos);
}
if( 0 > vboParams.setLocation(gl, sp.program()) ) {
throw new GLException("Couldn't locate "+vboParams);
}
if( 0 > vboTexCoordsR.setLocation(gl, sp.program()) ) {
throw new GLException("Couldn't locate "+vboTexCoordsR);
}
if( StereoUtil.usesChromaticDistortion(distortionBits) ) {
if( 0 > vboTexCoordsG.setLocation(gl, sp.program()) ) {
throw new GLException("Couldn't locate "+vboTexCoordsG);
}
if( 0 > vboTexCoordsB.setLocation(gl, sp.program()) ) {
throw new GLException("Couldn't locate "+vboTexCoordsB);
}
}
if( 0 > eyeToSourceUVScale.setLocation(gl, sp.program()) ) {
throw new GLException("Couldn't locate "+eyeToSourceUVScale);
}
if( 0 > eyeToSourceUVOffset.setLocation(gl, sp.program()) ) {
throw new GLException("Couldn't locate "+eyeToSourceUVOffset);
}
if( StereoUtil.usesTimewarpDistortion(distortionBits) ) {
if( 0 > eyeRotationStart.setLocation(gl, sp.program()) ) {
throw new GLException("Couldn't locate "+eyeRotationStart);
}
if( 0 > eyeRotationEnd.setLocation(gl, sp.program()) ) {
throw new GLException("Couldn't locate "+eyeRotationEnd);
}
}
iVBO.seal(gl, true);
iVBO.enableBuffer(gl, false);
indices.seal(gl, true);
indices.enableBuffer(gl, false);
}
/* pp */ void dispose(final GL2ES2 gl) {
iVBO.destroy(gl);
indices.destroy(gl);
}
/* pp */ void enableVBO(final GL2ES2 gl, final boolean enable) {
iVBO.enableBuffer(gl, enable);
indices.bindBuffer(gl, enable); // keeps VBO binding if enable:=true
}
/* pp */ void updateUniform(final GL2ES2 gl, final ShaderProgram sp) {
gl.glUniform(eyeToSourceUVScale);
gl.glUniform(eyeToSourceUVOffset);
if( StereoUtil.usesTimewarpDistortion(distortionBits) ) {
gl.glUniform(eyeRotationStart);
gl.glUniform(eyeRotationEnd);
}
}
/* pp */ void updateTimewarp(final ovrHmdDesc hmdDesc, final ovrPosef eyeRenderPose, final float[] mat4Tmp1, final float[] mat4Tmp2) {
OVR.ovrHmd_GetEyeTimewarpMatrices(hmdDesc, eyeName, eyeRenderPose, timeWarpMatrices);
final float[] eyeRotationStartM = FloatUtil.transposeMatrix(timeWarpMatrices[0].getM(0, mat4Tmp1), mat4Tmp2);
final FloatBuffer eyeRotationStartU = eyeRotationStart.floatBufferValue();
eyeRotationStartU.put(eyeRotationStartM);
eyeRotationStartU.rewind();
final float[] eyeRotationEndM = FloatUtil.transposeMatrix(timeWarpMatrices[1].getM(0, mat4Tmp1), mat4Tmp2);
final FloatBuffer eyeRotationEndU = eyeRotationEnd.floatBufferValue();
eyeRotationEndU.put(eyeRotationEndM);
eyeRotationEndU.rewind();
}
@Override
public String toString() {
return "Eye["+eyeName+", viewport "+viewport+
", "+eyeParameter+
", vertices "+vertexCount+", indices "+indexCount+
", uvScale["+eyeToSourceUVScale.floatBufferValue().get(0)+", "+eyeToSourceUVScale.floatBufferValue().get(1)+
"], uvOffset["+eyeToSourceUVOffset.floatBufferValue().get(0)+", "+eyeToSourceUVOffset.floatBufferValue().get(1)+
"], desc"+OVRUtil.toString(ovrEyeDesc)+"]";
}
}
private final OVRStereoDevice context;
private final OVREye[] eyes;
private final ovrPosef[] ovrEyePoses;
private final ovrVector3f[] hmdToEyeViewOffset;
private final ViewerPose viewerPose;
private final ovrTrackingState trackingState;
private final int distortionBits;
private final int textureCount;
private final DimensionImmutable[] eyeTextureSizes;
private final DimensionImmutable totalTextureSize;
private final GLUniformData texUnit0;
private final float[] mat4Tmp1 = new float[16];
private final float[] mat4Tmp2 = new float[16];
private ShaderProgram sp;
private ovrFrameTiming frameTiming;
private int frameCount;
@Override
public String toString() {
return "OVRDist[distortion["+StereoUtil.distortionBitsToString(distortionBits)+
"], eyeTexSize "+Arrays.toString(eyeTextureSizes)+
", sbsSize "+totalTextureSize+
", texCount "+textureCount+", texUnit "+getTextureUnit()+
", "+PlatformPropsImpl.NEWLINE+" "+eyes[0]+", "+PlatformPropsImpl.NEWLINE+" "+eyes[1]+"]";
}
private static int distBits2OVRDistCaps(final int distortionBits) {
int caps = 0;
if( StereoUtil.usesTimewarpDistortion(distortionBits) ) {
caps |= OVR.ovrDistortionCap_TimeWarp;
}
if( StereoUtil.usesChromaticDistortion(distortionBits) ) {
caps |= OVR.ovrDistortionCap_Chromatic;
}
if( StereoUtil.usesVignetteDistortion(distortionBits) ) {
caps |= OVR.ovrDistortionCap_Vignette;
}
return caps;
}
/* pp */ OVRStereoDeviceRenderer(final OVRStereoDevice context, final int distortionBits,
final int textureCount, final float[] eyePositionOffset,
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);
}
this.context = context;
this.eyes = new OVREye[2];
this.distortionBits = ( distortionBits | context.getMinimumDistortionBits() ) & context.getSupportedDistortionBits();
this.textureCount = textureCount;
this.eyeTextureSizes = eyeTextureSizes;
this.totalTextureSize = totalTextureSize;
texUnit0 = new GLUniformData("ovr_Texture0", textureUnit);
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.hmdDesc, this.distortionBits, eyePositionOffset, eyeRenderDescs[0], ovrTexture0Size, eyeViewports[0]);
eyes[1] = new OVREye(context.hmdDesc, this.distortionBits, eyePositionOffset, eyeRenderDescs[1], ovrTexture1Size, eyeViewports[1]);
ovrEyePoses = new ovrPosef[2];
ovrEyePoses[0] = ovrPosef.create();
ovrEyePoses[1] = ovrPosef.create();
hmdToEyeViewOffset = new ovrVector3f[2];
hmdToEyeViewOffset[0] = eyes[0].ovrEyeDesc.getHmdToEyeViewOffset();
hmdToEyeViewOffset[1] = eyes[1].ovrEyeDesc.getHmdToEyeViewOffset();
viewerPose = new ViewerPose();
trackingState = ovrTrackingState.create();
sp = null;
frameTiming = null;
frameCount = 0;
}
@Override
public StereoDevice getDevice() {
return context;
}
@Override
public final int getDistortionBits() { return distortionBits; }
@Override
public final boolean usesSideBySideStereo() { return true; }
@Override
public final DimensionImmutable[] getEyeSurfaceSize() { return eyeTextureSizes; }
@Override
public final DimensionImmutable getTotalSurfaceSize() { return totalTextureSize; }
@Override
public final int getTextureCount() { return textureCount; }
@Override
public final int getTextureUnit() { return texUnit0.intValue(); }
@Override
public final boolean ppAvailable() { return 0 != distortionBits; }
@Override
public final void init(final GL gl) {
if( StereoDevice.DEBUG ) {
System.err.println(JoglVersion.getGLInfo(gl, null).toString());
}
if( null != sp ) {
throw new IllegalStateException("Already initialized");
}
final GL2ES2 gl2es2 = gl.getGL2ES2();
final String vertexShaderBasename;
final String fragmentShaderBasename;
{
final boolean usesTimewarp = StereoUtil.usesTimewarpDistortion(distortionBits);
final boolean usesChromatic = StereoUtil.usesChromaticDistortion(distortionBits);
final StringBuilder sb = new StringBuilder();
sb.append(shaderPrefix01);
if( !usesChromatic && !usesTimewarp ) {
sb.append(shaderPlainSuffix);
} else if( usesChromatic && !usesTimewarp ) {
sb.append(shaderChromaSuffix);
} else if( usesTimewarp ) {
sb.append(shaderTimewarpSuffix);
if( usesChromatic ) {
sb.append(shaderChromaSuffix);
}
}
vertexShaderBasename = sb.toString();
sb.setLength(0);
sb.append(shaderPrefix01);
if( usesChromatic ) {
sb.append(shaderChromaSuffix);
} else {
sb.append(shaderPlainSuffix);
}
fragmentShaderBasename = sb.toString();
}
final ShaderCode vp0 = ShaderCode.create(gl2es2, GL2ES2.GL_VERTEX_SHADER, OVRStereoDeviceRenderer.class, "shader",
"shader/bin", vertexShaderBasename, true);
final ShaderCode fp0 = ShaderCode.create(gl2es2, GL2ES2.GL_FRAGMENT_SHADER, OVRStereoDeviceRenderer.class, "shader",
"shader/bin", fragmentShaderBasename, true);
vp0.defaultShaderCustomization(gl2es2, true, true);
fp0.defaultShaderCustomization(gl2es2, true, true);
sp = new ShaderProgram();
sp.add(gl2es2, vp0, System.err);
sp.add(gl2es2, fp0, System.err);
if(!sp.link(gl2es2, System.err)) {
throw new GLException("could not link program: "+sp);
}
sp.useProgram(gl2es2, true);
if( 0 > texUnit0.setLocation(gl2es2, sp.program()) ) {
throw new OVRException("Couldn't locate "+texUnit0);
}
eyes[0].linkData(gl2es2, sp);
eyes[1].linkData(gl2es2, sp);
sp.useProgram(gl2es2, false);
}
@Override
public final void dispose(final GL gl) {
final GL2ES2 gl2es2 = gl.getGL2ES2();
sp.useProgram(gl2es2, false);
eyes[0].dispose(gl2es2);
eyes[1].dispose(gl2es2);
sp.destroy(gl2es2);
frameTiming = null;
}
@Override
public final Eye getEye(final int eyeNum) {
return eyes[eyeNum];
}
@Override
public final ViewerPose updateViewerPose() {
final ovrTrackingState trackingState;
trackingState = this.trackingState;
OVR.ovrHmd_GetEyePoses(context.hmdDesc, frameCount, hmdToEyeViewOffset, ovrEyePoses, trackingState);
context.updateUsedSensorBits(trackingState);
// Use headPose of tracking state, since it points to the viewer
// where ovrEyePoses already have hmdToEyeViewOffset applied (IPD .. etc).
final ovrPosef pose = trackingState.getHeadPose().getThePose();
final ovrVector3f pos = pose.getPosition();
viewerPose.setPosition(pos.getX(), pos.getY(), pos.getZ());
OVRUtil.copyToQuaternion(pose.getOrientation(), viewerPose.orientation);
// System.err.println("Viewer: "+OVRUtil.toString(pos));
// System.err.println("Camera: "+OVRUtil.toString(trackingState.getCameraPose().getPosition()));
// System.err.println("Leveld: "+OVRUtil.toString(trackingState.getLeveledCameraPose().getPosition()));
return viewerPose;
}
@Override
public final ViewerPose getLastViewerPose() {
return viewerPose;
}
@Override
public final void beginFrame(final GL gl) {
frameTiming = OVR.ovrHmd_BeginFrameTiming(context.hmdDesc, frameCount); // ovrHmd_GetFrameTiming not used, otherwise: frameCount);
}
@Override
public final void endFrame(final GL gl) {
if( null == frameTiming ) {
throw new IllegalStateException("beginFrame not called");
}
OVR.ovrHmd_EndFrameTiming(context.hmdDesc);
frameTiming = null;
frameCount++;
}
@Override
public final void ppBegin(final GL gl) {
if( null == sp ) {
throw new IllegalStateException("Not initialized");
}
if( null == frameTiming ) {
throw new IllegalStateException("beginFrame not called");
}
if( StereoUtil.usesTimewarpDistortion(distortionBits) ) {
// minimize latency
OVR.ovr_WaitTillTime(frameTiming.getTimewarpPointSeconds());
// {@link OVREye#updateTimewarp(ovrHmdDesc, ovrPosef, float[], float[])} will be called in {@link #ppOneEye}
}
final GL2ES2 gl2es2 = gl.getGL2ES2();
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
gl.glClear(GL.GL_COLOR_BUFFER_BIT);
gl.glActiveTexture(GL.GL_TEXTURE0 + getTextureUnit());
gl2es2.glDisable(GL.GL_CULL_FACE);
gl2es2.glDisable(GL.GL_DEPTH_TEST);
gl2es2.glDisable(GL.GL_BLEND);
if( !gl2es2.isGLcore() ) {
gl2es2.glEnable(GL.GL_TEXTURE_2D);
}
sp.useProgram(gl2es2, true);
gl2es2.glUniform(texUnit0);
}
@Override
public final void ppOneEye(final GL gl, final int eyeNum) {
final OVREye eye = eyes[eyeNum];
if( StereoUtil.usesTimewarpDistortion(distortionBits) ) {
eye.updateTimewarp(context.hmdDesc, ovrEyePoses[eyeNum], mat4Tmp1, mat4Tmp2);
}
final GL2ES2 gl2es2 = gl.getGL2ES2();
eye.updateUniform(gl2es2, sp);
eye.enableVBO(gl2es2, true);
gl2es2.glDrawElements(GL.GL_TRIANGLES, eye.indexCount, GL.GL_UNSIGNED_SHORT, 0);
eyes[eyeNum].enableVBO(gl2es2, false);
}
@Override
public final void ppEnd(final GL gl) {
sp.useProgram(gl.getGL2ES2(), false);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy