diff --git a/jme3-vr/src/main/java/com/jme3/input/vr/OpenVR.java b/jme3-vr/src/main/java/com/jme3/input/vr/OpenVR.java index 509e84987..cb2042885 100644 --- a/jme3-vr/src/main/java/com/jme3/input/vr/OpenVR.java +++ b/jme3-vr/src/main/java/com/jme3/input/vr/OpenVR.java @@ -1,525 +1,524 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package com.jme3.input.vr; - -import com.jme3.app.VREnvironment; -import com.jme3.math.Matrix4f; -import com.jme3.math.Quaternion; -import com.jme3.math.Vector2f; -import com.jme3.math.Vector3f; -import com.jme3.renderer.Camera; -import com.jme3.system.jopenvr.HmdMatrix34_t; -import com.jme3.system.jopenvr.HmdMatrix44_t; -import com.jme3.system.jopenvr.JOpenVRLibrary; -import com.jme3.system.jopenvr.OpenVRUtil; -import com.jme3.system.jopenvr.TrackedDevicePose_t; -import com.jme3.system.jopenvr.VR_IVRCompositor_FnTable; -import com.jme3.system.jopenvr.VR_IVRSystem_FnTable; -import com.jme3.util.VRUtil; -import com.sun.jna.Memory; -import com.sun.jna.Pointer; -import com.sun.jna.ptr.FloatByReference; -import com.sun.jna.ptr.IntByReference; -import com.sun.jna.ptr.LongByReference; - -import java.nio.IntBuffer; -import java.util.Locale; -import java.util.concurrent.TimeUnit; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * A class that wraps an OpenVR system. - * @author reden - phr00t - https://github.com/phr00t - * @author Julien Seinturier - (c) 2016 - JOrigin project - http:/www.jorigin.org - */ -public class OpenVR implements VRAPI { - - private static final Logger logger = Logger.getLogger(OpenVR.class.getName()); - - private static VR_IVRCompositor_FnTable compositorFunctions; - private static VR_IVRSystem_FnTable vrsystemFunctions; - - private static boolean initSuccess = false; - private static boolean flipEyes = false; - - private IntBuffer hmdDisplayFrequency; - private TrackedDevicePose_t.ByReference hmdTrackedDevicePoseReference; - protected TrackedDevicePose_t[] hmdTrackedDevicePoses; - - protected IntByReference hmdErrorStore; - - private final Quaternion rotStore = new Quaternion(); - private final Vector3f posStore = new Vector3f(); - - private static FloatByReference tlastVsync; - - /** - * The actual frame count. - */ - public static LongByReference _tframeCount; - - // for debugging latency - private int frames = 0; - - protected Matrix4f[] poseMatrices; - - private final Matrix4f hmdPose = Matrix4f.IDENTITY.clone(); - private Matrix4f hmdProjectionLeftEye; - private Matrix4f hmdProjectionRightEye; - private Matrix4f hmdPoseLeftEye; - private Matrix4f hmdPoseRightEye; - - private Vector3f hmdPoseLeftEyeVec, hmdPoseRightEyeVec, hmdSeatToStand; - - private float vsyncToPhotons; - private double timePerFrame, frameCountRun; - private long frameCount; - private OpenVRInput VRinput; - - - private VREnvironment environment = null; - - /** - * Create a new OpenVR system - * attached to the given {@link VREnvironment VR environment}. - * @param environment the VR environment to which this API is attached. - */ - public OpenVR(VREnvironment environment){ - this.environment = environment; - } - - @Override - public OpenVRInput getVRinput() { - return VRinput; - } - - @Override - public VR_IVRSystem_FnTable getVRSystem() { - return vrsystemFunctions; - } - - @Override - public VR_IVRCompositor_FnTable getCompositor() { - return compositorFunctions; - } - - @Override - public String getName() { - return "OpenVR"; - } - - private static long latencyWaitTime = 0; - - @Override - public void setFlipEyes(boolean set) { - flipEyes = set; - } - - private boolean enableDebugLatency = false; - - @Override - public void printLatencyInfoToConsole(boolean set) { - enableDebugLatency = set; - } - - @Override - public int getDisplayFrequency() { - if( hmdDisplayFrequency == null ) return 0; - return hmdDisplayFrequency.get(0); - } - - @Override - public boolean initialize() { - - logger.config("Initializing OpenVR system..."); - - hmdErrorStore = new IntByReference(); - vrsystemFunctions = null; - JOpenVRLibrary.VR_InitInternal(hmdErrorStore, JOpenVRLibrary.EVRApplicationType.EVRApplicationType_VRApplication_Scene); - if( hmdErrorStore.getValue() == 0 ) { - vrsystemFunctions = new VR_IVRSystem_FnTable(JOpenVRLibrary.VR_GetGenericInterface(JOpenVRLibrary.IVRSystem_Version, hmdErrorStore).getPointer()); - } - - if( vrsystemFunctions == null || hmdErrorStore.getValue() != 0 ) { - logger.severe("OpenVR Initialize Result: " + JOpenVRLibrary.VR_GetVRInitErrorAsEnglishDescription(hmdErrorStore.getValue()).getString(0)); - logger.severe("Initializing OpenVR system [FAILED]"); - return false; - } else { - logger.config("OpenVR initialized & VR connected."); - - vrsystemFunctions.setAutoSynch(false); - vrsystemFunctions.read(); - - tlastVsync = new FloatByReference(); - _tframeCount = new LongByReference(); - - hmdDisplayFrequency = IntBuffer.allocate(1); - hmdDisplayFrequency.put( (int) JOpenVRLibrary.ETrackedDeviceProperty.ETrackedDeviceProperty_Prop_DisplayFrequency_Float); - hmdTrackedDevicePoseReference = new TrackedDevicePose_t.ByReference(); - hmdTrackedDevicePoses = (TrackedDevicePose_t[])hmdTrackedDevicePoseReference.toArray(JOpenVRLibrary.k_unMaxTrackedDeviceCount); - poseMatrices = new Matrix4f[JOpenVRLibrary.k_unMaxTrackedDeviceCount]; - for(int i=0;i 0 ) VRUtil.sleepNanos(latencyWaitTime); - - vrsystemFunctions.GetTimeSinceLastVsync.apply(tlastVsync, _tframeCount); - float fSecondsUntilPhotons = (float)timePerFrame - tlastVsync.getValue() + vsyncToPhotons; - - if( enableDebugLatency ) { - if( frames == 10 ) { - System.out.println("Waited (nanos): " + Long.toString(latencyWaitTime)); - System.out.println("Predict ahead time: " + Float.toString(fSecondsUntilPhotons)); - } - frames = (frames + 1) % 60; - } - - // handle skipping frame stuff - long nowCount = _tframeCount.getValue(); - if( nowCount - frameCount > 1 ) { - // skipped a frame! - if( enableDebugLatency ) System.out.println("Frame skipped!"); - frameCountRun = 0; - if( latencyWaitTime > 0 ) { - latencyWaitTime -= TimeUnit.MILLISECONDS.toNanos(1); - if( latencyWaitTime < 0 ) latencyWaitTime = 0; - } - } else if( latencyWaitTime < timePerFrame * 1000000000.0 ) { - // didn't skip a frame, lets try waiting longer to improve latency - frameCountRun++; - latencyWaitTime += Math.round(Math.pow(frameCountRun / 10.0, 2.0)); - } - - frameCount = nowCount; - - vrsystemFunctions.GetDeviceToAbsoluteTrackingPose.apply( - environment.isSeatedExperience()?JOpenVRLibrary.ETrackingUniverseOrigin.ETrackingUniverseOrigin_TrackingUniverseSeated: - JOpenVRLibrary.ETrackingUniverseOrigin.ETrackingUniverseOrigin_TrackingUniverseStanding, - fSecondsUntilPhotons, hmdTrackedDevicePoseReference, JOpenVRLibrary.k_unMaxTrackedDeviceCount); - } - - // deal with controllers being plugged in and out - // causing an invalid memory crash... skipping for now - /*boolean hasEvent = false; - while( JOpenVRLibrary.VR_IVRSystem_PollNextEvent(OpenVR.getVRSystemInstance(), tempEvent) != 0 ) { - // wait until the events are clear.. - hasEvent = true; - } - if( hasEvent ) { - // an event probably changed controller state - VRInput._updateConnectedControllers(); - }*/ - //update controllers pose information - environment.getVRinput().updateControllerStates(); - - // read pose data from native - for (int nDevice = 0; nDevice < JOpenVRLibrary.k_unMaxTrackedDeviceCount; ++nDevice ){ - hmdTrackedDevicePoses[nDevice].readField("bPoseIsValid"); - if( hmdTrackedDevicePoses[nDevice].bPoseIsValid != 0 ){ - hmdTrackedDevicePoses[nDevice].readField("mDeviceToAbsoluteTracking"); - VRUtil.convertSteamVRMatrix3ToMatrix4f(hmdTrackedDevicePoses[nDevice].mDeviceToAbsoluteTracking, poseMatrices[nDevice]); - } - } - - if ( hmdTrackedDevicePoses[JOpenVRLibrary.k_unTrackedDeviceIndex_Hmd].bPoseIsValid != 0 ){ - hmdPose.set(poseMatrices[JOpenVRLibrary.k_unTrackedDeviceIndex_Hmd]); - } else { - hmdPose.set(Matrix4f.IDENTITY); - } - } - - @Override - public Matrix4f getHMDMatrixProjectionLeftEye(Camera cam){ - if( hmdProjectionLeftEye != null ) { - return hmdProjectionLeftEye; - } else if(vrsystemFunctions == null){ - return cam.getProjectionMatrix(); - } else { - HmdMatrix44_t mat = vrsystemFunctions.GetProjectionMatrix.apply(JOpenVRLibrary.EVREye.EVREye_Eye_Left, cam.getFrustumNear(), cam.getFrustumFar()); - hmdProjectionLeftEye = new Matrix4f(); - VRUtil.convertSteamVRMatrix4ToMatrix4f(mat, hmdProjectionLeftEye); - return hmdProjectionLeftEye; - } - } - - @Override - public Matrix4f getHMDMatrixProjectionRightEye(Camera cam){ - if( hmdProjectionRightEye != null ) { - return hmdProjectionRightEye; - } else if(vrsystemFunctions == null){ - return cam.getProjectionMatrix(); - } else { - HmdMatrix44_t mat = vrsystemFunctions.GetProjectionMatrix.apply(JOpenVRLibrary.EVREye.EVREye_Eye_Right, cam.getFrustumNear(), cam.getFrustumFar()); - hmdProjectionRightEye = new Matrix4f(); - VRUtil.convertSteamVRMatrix4ToMatrix4f(mat, hmdProjectionRightEye); - return hmdProjectionRightEye; - } - } - - @Override - public Vector3f getHMDVectorPoseLeftEye() { - if( hmdPoseLeftEyeVec == null ) { - hmdPoseLeftEyeVec = getHMDMatrixPoseLeftEye().toTranslationVector(); - // set default IPD if none or broken - if( hmdPoseLeftEyeVec.x <= 0.080f * -0.5f || hmdPoseLeftEyeVec.x >= 0.040f * -0.5f ) { - hmdPoseLeftEyeVec.x = 0.065f * -0.5f; - } - if( flipEyes == false ) hmdPoseLeftEyeVec.x *= -1f; // it seems these need flipping - } - return hmdPoseLeftEyeVec; - } - - @Override - public Vector3f getHMDVectorPoseRightEye() { - if( hmdPoseRightEyeVec == null ) { - hmdPoseRightEyeVec = getHMDMatrixPoseRightEye().toTranslationVector(); - // set default IPD if none or broken - if( hmdPoseRightEyeVec.x >= 0.080f * 0.5f || hmdPoseRightEyeVec.x <= 0.040f * 0.5f ) { - hmdPoseRightEyeVec.x = 0.065f * 0.5f; - } - if( flipEyes == false ) hmdPoseRightEyeVec.x *= -1f; // it seems these need flipping - } - return hmdPoseRightEyeVec; - } - - @Override - public Vector3f getSeatedToAbsolutePosition() { - if( environment.isSeatedExperience() == false ) return Vector3f.ZERO; - if( hmdSeatToStand == null ) { - hmdSeatToStand = new Vector3f(); - HmdMatrix34_t mat = vrsystemFunctions.GetSeatedZeroPoseToStandingAbsoluteTrackingPose.apply(); - Matrix4f tempmat = new Matrix4f(); - VRUtil.convertSteamVRMatrix3ToMatrix4f(mat, tempmat); - tempmat.toTranslationVector(hmdSeatToStand); - } - return hmdSeatToStand; - } - - @Override - public Matrix4f getHMDMatrixPoseLeftEye(){ - if( hmdPoseLeftEye != null ) { - return hmdPoseLeftEye; - } else if(vrsystemFunctions == null) { - return Matrix4f.IDENTITY; - } else { - HmdMatrix34_t mat = vrsystemFunctions.GetEyeToHeadTransform.apply(JOpenVRLibrary.EVREye.EVREye_Eye_Left); - hmdPoseLeftEye = new Matrix4f(); - return VRUtil.convertSteamVRMatrix3ToMatrix4f(mat, hmdPoseLeftEye); - } - } - - @Override - public HmdType getType() { - if( vrsystemFunctions != null ) { - Pointer str1 = new Memory(128); - Pointer str2 = new Memory(128); - String completeName = ""; - vrsystemFunctions.GetStringTrackedDeviceProperty.apply(JOpenVRLibrary.k_unTrackedDeviceIndex_Hmd, - JOpenVRLibrary.ETrackedDeviceProperty.ETrackedDeviceProperty_Prop_ManufacturerName_String, - str1, 128, hmdErrorStore); - if( hmdErrorStore.getValue() == 0 ) completeName += str1.getString(0); - vrsystemFunctions.GetStringTrackedDeviceProperty.apply(JOpenVRLibrary.k_unTrackedDeviceIndex_Hmd, - JOpenVRLibrary.ETrackedDeviceProperty.ETrackedDeviceProperty_Prop_ModelNumber_String, - str2, 128, hmdErrorStore); - if( hmdErrorStore.getValue() == 0 ) completeName += " " + str2.getString(0); - if( completeName.length() > 0 ) { - completeName = completeName.toLowerCase(Locale.ENGLISH).trim(); - if( completeName.contains("htc") || completeName.contains("vive") ) { - return HmdType.HTC_VIVE; - } else if( completeName.contains("osvr") ) { - return HmdType.OSVR; - } else if( completeName.contains("oculus") || completeName.contains("rift") || - completeName.contains("dk1") || completeName.contains("dk2") || completeName.contains("cv1") ) { - return HmdType.OCULUS_RIFT; - } else if( completeName.contains("fove") ) { - return HmdType.FOVE; - } else if( completeName.contains("game") && completeName.contains("face") ) { - return HmdType.GAMEFACE; - } else if( completeName.contains("morpheus") ) { - return HmdType.MORPHEUS; - } else if( completeName.contains("gear") ) { - return HmdType.GEARVR; - } else if( completeName.contains("star") ) { - return HmdType.STARVR; - } else if( completeName.contains("null") ) { - return HmdType.NULL; - } - } - } else return HmdType.NONE; - return HmdType.OTHER; - } - - @Override - public Matrix4f getHMDMatrixPoseRightEye(){ - if( hmdPoseRightEye != null ) { - return hmdPoseRightEye; - } else if(vrsystemFunctions == null) { - return Matrix4f.IDENTITY; - } else { - HmdMatrix34_t mat = vrsystemFunctions.GetEyeToHeadTransform.apply(JOpenVRLibrary.EVREye.EVREye_Eye_Right); - hmdPoseRightEye = new Matrix4f(); - return VRUtil.convertSteamVRMatrix3ToMatrix4f(mat, hmdPoseRightEye); - } - } - -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package com.jme3.input.vr; + +import com.jme3.app.VREnvironment; +import com.jme3.math.Matrix4f; +import com.jme3.math.Quaternion; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.renderer.Camera; +import com.jme3.system.jopenvr.HmdMatrix34_t; +import com.jme3.system.jopenvr.HmdMatrix44_t; +import com.jme3.system.jopenvr.JOpenVRLibrary; +import com.jme3.system.jopenvr.OpenVRUtil; +import com.jme3.system.jopenvr.TrackedDevicePose_t; +import com.jme3.system.jopenvr.VR_IVRCompositor_FnTable; +import com.jme3.system.jopenvr.VR_IVRSystem_FnTable; +import com.jme3.util.VRUtil; +import com.sun.jna.Memory; +import com.sun.jna.Pointer; +import com.sun.jna.ptr.FloatByReference; +import com.sun.jna.ptr.IntByReference; +import com.sun.jna.ptr.LongByReference; + +import java.nio.IntBuffer; +import java.util.Locale; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * A class that wraps an OpenVR system. + * @author reden - phr00t - https://github.com/phr00t + * @author Julien Seinturier - (c) 2016 - JOrigin project - http:/www.jorigin.org + */ +public class OpenVR implements VRAPI { + + private static final Logger logger = Logger.getLogger(OpenVR.class.getName()); + + private static VR_IVRCompositor_FnTable compositorFunctions; + private static VR_IVRSystem_FnTable vrsystemFunctions; + + private static boolean initSuccess = false; + private static boolean flipEyes = false; + + private static IntBuffer hmdDisplayFrequency; + private static TrackedDevicePose_t.ByReference hmdTrackedDevicePoseReference; + protected static TrackedDevicePose_t[] hmdTrackedDevicePoses; + + protected static IntByReference hmdErrorStore; + + private static final Quaternion rotStore = new Quaternion(); + private static final Vector3f posStore = new Vector3f(); + + private static FloatByReference tlastVsync; + + /** + * The actual frame count. + */ + public static LongByReference _tframeCount; + + // for debugging latency + private int frames = 0; + + protected static Matrix4f[] poseMatrices; + + private static final Matrix4f hmdPose = Matrix4f.IDENTITY.clone(); + private static Matrix4f hmdProjectionLeftEye; + private static Matrix4f hmdProjectionRightEye; + private static Matrix4f hmdPoseLeftEye; + private static Matrix4f hmdPoseRightEye; + + private static Vector3f hmdPoseLeftEyeVec, hmdPoseRightEyeVec, hmdSeatToStand; + + private static float vsyncToPhotons; + private static double timePerFrame, frameCountRun; + private static long frameCount; + private static OpenVRInput VRinput; + + private VREnvironment environment = null; + + /** + * Create a new OpenVR system + * attached to the given {@link VREnvironment VR environment}. + * @param environment the VR environment to which this API is attached. + */ + public OpenVR(VREnvironment environment){ + this.environment = environment; + } + + @Override + public OpenVRInput getVRinput() { + return VRinput; + } + + @Override + public VR_IVRSystem_FnTable getVRSystem() { + return vrsystemFunctions; + } + + @Override + public VR_IVRCompositor_FnTable getCompositor() { + return compositorFunctions; + } + + @Override + public String getName() { + return "OpenVR"; + } + + private static long latencyWaitTime = 0; + + @Override + public void setFlipEyes(boolean set) { + flipEyes = set; + } + + private boolean enableDebugLatency = false; + + @Override + public void printLatencyInfoToConsole(boolean set) { + enableDebugLatency = set; + } + + @Override + public int getDisplayFrequency() { + if( hmdDisplayFrequency == null ) return 0; + return hmdDisplayFrequency.get(0); + } + + @Override + public boolean initialize() { + + logger.config("Initializing OpenVR system..."); + + hmdErrorStore = new IntByReference(); + vrsystemFunctions = null; + JOpenVRLibrary.VR_InitInternal(hmdErrorStore, JOpenVRLibrary.EVRApplicationType.EVRApplicationType_VRApplication_Scene); + if( hmdErrorStore.getValue() == 0 ) { + vrsystemFunctions = new VR_IVRSystem_FnTable(JOpenVRLibrary.VR_GetGenericInterface(JOpenVRLibrary.IVRSystem_Version, hmdErrorStore).getPointer()); + } + + if( vrsystemFunctions == null || hmdErrorStore.getValue() != 0 ) { + logger.severe("OpenVR Initialize Result: " + JOpenVRLibrary.VR_GetVRInitErrorAsEnglishDescription(hmdErrorStore.getValue()).getString(0)); + logger.severe("Initializing OpenVR system [FAILED]"); + return false; + } else { + logger.config("OpenVR initialized & VR connected."); + + vrsystemFunctions.setAutoSynch(false); + vrsystemFunctions.read(); + + tlastVsync = new FloatByReference(); + _tframeCount = new LongByReference(); + + hmdDisplayFrequency = IntBuffer.allocate(1); + hmdDisplayFrequency.put( (int) JOpenVRLibrary.ETrackedDeviceProperty.ETrackedDeviceProperty_Prop_DisplayFrequency_Float); + hmdTrackedDevicePoseReference = new TrackedDevicePose_t.ByReference(); + hmdTrackedDevicePoses = (TrackedDevicePose_t[])hmdTrackedDevicePoseReference.toArray(JOpenVRLibrary.k_unMaxTrackedDeviceCount); + poseMatrices = new Matrix4f[JOpenVRLibrary.k_unMaxTrackedDeviceCount]; + for(int i=0;i 0 ) VRUtil.sleepNanos(latencyWaitTime); + + vrsystemFunctions.GetTimeSinceLastVsync.apply(tlastVsync, _tframeCount); + float fSecondsUntilPhotons = (float)timePerFrame - tlastVsync.getValue() + vsyncToPhotons; + + if( enableDebugLatency ) { + if( frames == 10 ) { + System.out.println("Waited (nanos): " + Long.toString(latencyWaitTime)); + System.out.println("Predict ahead time: " + Float.toString(fSecondsUntilPhotons)); + } + frames = (frames + 1) % 60; + } + + // handle skipping frame stuff + long nowCount = _tframeCount.getValue(); + if( nowCount - frameCount > 1 ) { + // skipped a frame! + if( enableDebugLatency ) System.out.println("Frame skipped!"); + frameCountRun = 0; + if( latencyWaitTime > 0 ) { + latencyWaitTime -= TimeUnit.MILLISECONDS.toNanos(1); + if( latencyWaitTime < 0 ) latencyWaitTime = 0; + } + } else if( latencyWaitTime < timePerFrame * 1000000000.0 ) { + // didn't skip a frame, lets try waiting longer to improve latency + frameCountRun++; + latencyWaitTime += Math.round(Math.pow(frameCountRun / 10.0, 2.0)); + } + + frameCount = nowCount; + + vrsystemFunctions.GetDeviceToAbsoluteTrackingPose.apply( + environment.isSeatedExperience()?JOpenVRLibrary.ETrackingUniverseOrigin.ETrackingUniverseOrigin_TrackingUniverseSeated: + JOpenVRLibrary.ETrackingUniverseOrigin.ETrackingUniverseOrigin_TrackingUniverseStanding, + fSecondsUntilPhotons, hmdTrackedDevicePoseReference, JOpenVRLibrary.k_unMaxTrackedDeviceCount); + } + + // deal with controllers being plugged in and out + // causing an invalid memory crash... skipping for now + /*boolean hasEvent = false; + while( JOpenVRLibrary.VR_IVRSystem_PollNextEvent(OpenVR.getVRSystemInstance(), tempEvent) != 0 ) { + // wait until the events are clear.. + hasEvent = true; + } + if( hasEvent ) { + // an event probably changed controller state + VRInput._updateConnectedControllers(); + }*/ + //update controllers pose information + environment.getVRinput().updateControllerStates(); + + // read pose data from native + for (int nDevice = 0; nDevice < JOpenVRLibrary.k_unMaxTrackedDeviceCount; ++nDevice ){ + hmdTrackedDevicePoses[nDevice].readField("bPoseIsValid"); + if( hmdTrackedDevicePoses[nDevice].bPoseIsValid != 0 ){ + hmdTrackedDevicePoses[nDevice].readField("mDeviceToAbsoluteTracking"); + VRUtil.convertSteamVRMatrix3ToMatrix4f(hmdTrackedDevicePoses[nDevice].mDeviceToAbsoluteTracking, poseMatrices[nDevice]); + } + } + + if ( hmdTrackedDevicePoses[JOpenVRLibrary.k_unTrackedDeviceIndex_Hmd].bPoseIsValid != 0 ){ + hmdPose.set(poseMatrices[JOpenVRLibrary.k_unTrackedDeviceIndex_Hmd]); + } else { + hmdPose.set(Matrix4f.IDENTITY); + } + } + + @Override + public Matrix4f getHMDMatrixProjectionLeftEye(Camera cam){ + if( hmdProjectionLeftEye != null ) { + return hmdProjectionLeftEye; + } else if(vrsystemFunctions == null){ + return cam.getProjectionMatrix(); + } else { + HmdMatrix44_t mat = vrsystemFunctions.GetProjectionMatrix.apply(JOpenVRLibrary.EVREye.EVREye_Eye_Left, cam.getFrustumNear(), cam.getFrustumFar()); + hmdProjectionLeftEye = new Matrix4f(); + VRUtil.convertSteamVRMatrix4ToMatrix4f(mat, hmdProjectionLeftEye); + return hmdProjectionLeftEye; + } + } + + @Override + public Matrix4f getHMDMatrixProjectionRightEye(Camera cam){ + if( hmdProjectionRightEye != null ) { + return hmdProjectionRightEye; + } else if(vrsystemFunctions == null){ + return cam.getProjectionMatrix(); + } else { + HmdMatrix44_t mat = vrsystemFunctions.GetProjectionMatrix.apply(JOpenVRLibrary.EVREye.EVREye_Eye_Right, cam.getFrustumNear(), cam.getFrustumFar()); + hmdProjectionRightEye = new Matrix4f(); + VRUtil.convertSteamVRMatrix4ToMatrix4f(mat, hmdProjectionRightEye); + return hmdProjectionRightEye; + } + } + + @Override + public Vector3f getHMDVectorPoseLeftEye() { + if( hmdPoseLeftEyeVec == null ) { + hmdPoseLeftEyeVec = getHMDMatrixPoseLeftEye().toTranslationVector(); + // set default IPD if none or broken + if( hmdPoseLeftEyeVec.x <= 0.080f * -0.5f || hmdPoseLeftEyeVec.x >= 0.040f * -0.5f ) { + hmdPoseLeftEyeVec.x = 0.065f * -0.5f; + } + if( flipEyes == false ) hmdPoseLeftEyeVec.x *= -1f; // it seems these need flipping + } + return hmdPoseLeftEyeVec; + } + + @Override + public Vector3f getHMDVectorPoseRightEye() { + if( hmdPoseRightEyeVec == null ) { + hmdPoseRightEyeVec = getHMDMatrixPoseRightEye().toTranslationVector(); + // set default IPD if none or broken + if( hmdPoseRightEyeVec.x >= 0.080f * 0.5f || hmdPoseRightEyeVec.x <= 0.040f * 0.5f ) { + hmdPoseRightEyeVec.x = 0.065f * 0.5f; + } + if( flipEyes == false ) hmdPoseRightEyeVec.x *= -1f; // it seems these need flipping + } + return hmdPoseRightEyeVec; + } + + @Override + public Vector3f getSeatedToAbsolutePosition() { + if( environment.isSeatedExperience() == false ) return Vector3f.ZERO; + if( hmdSeatToStand == null ) { + hmdSeatToStand = new Vector3f(); + HmdMatrix34_t mat = vrsystemFunctions.GetSeatedZeroPoseToStandingAbsoluteTrackingPose.apply(); + Matrix4f tempmat = new Matrix4f(); + VRUtil.convertSteamVRMatrix3ToMatrix4f(mat, tempmat); + tempmat.toTranslationVector(hmdSeatToStand); + } + return hmdSeatToStand; + } + + @Override + public Matrix4f getHMDMatrixPoseLeftEye(){ + if( hmdPoseLeftEye != null ) { + return hmdPoseLeftEye; + } else if(vrsystemFunctions == null) { + return Matrix4f.IDENTITY; + } else { + HmdMatrix34_t mat = vrsystemFunctions.GetEyeToHeadTransform.apply(JOpenVRLibrary.EVREye.EVREye_Eye_Left); + hmdPoseLeftEye = new Matrix4f(); + return VRUtil.convertSteamVRMatrix3ToMatrix4f(mat, hmdPoseLeftEye); + } + } + + @Override + public HmdType getType() { + if( vrsystemFunctions != null ) { + Pointer str1 = new Memory(128); + Pointer str2 = new Memory(128); + String completeName = ""; + vrsystemFunctions.GetStringTrackedDeviceProperty.apply(JOpenVRLibrary.k_unTrackedDeviceIndex_Hmd, + JOpenVRLibrary.ETrackedDeviceProperty.ETrackedDeviceProperty_Prop_ManufacturerName_String, + str1, 128, hmdErrorStore); + if( hmdErrorStore.getValue() == 0 ) completeName += str1.getString(0); + vrsystemFunctions.GetStringTrackedDeviceProperty.apply(JOpenVRLibrary.k_unTrackedDeviceIndex_Hmd, + JOpenVRLibrary.ETrackedDeviceProperty.ETrackedDeviceProperty_Prop_ModelNumber_String, + str2, 128, hmdErrorStore); + if( hmdErrorStore.getValue() == 0 ) completeName += " " + str2.getString(0); + if( completeName.length() > 0 ) { + completeName = completeName.toLowerCase(Locale.ENGLISH).trim(); + if( completeName.contains("htc") || completeName.contains("vive") ) { + return HmdType.HTC_VIVE; + } else if( completeName.contains("osvr") ) { + return HmdType.OSVR; + } else if( completeName.contains("oculus") || completeName.contains("rift") || + completeName.contains("dk1") || completeName.contains("dk2") || completeName.contains("cv1") ) { + return HmdType.OCULUS_RIFT; + } else if( completeName.contains("fove") ) { + return HmdType.FOVE; + } else if( completeName.contains("game") && completeName.contains("face") ) { + return HmdType.GAMEFACE; + } else if( completeName.contains("morpheus") ) { + return HmdType.MORPHEUS; + } else if( completeName.contains("gear") ) { + return HmdType.GEARVR; + } else if( completeName.contains("star") ) { + return HmdType.STARVR; + } else if( completeName.contains("null") ) { + return HmdType.NULL; + } + } + } else return HmdType.NONE; + return HmdType.OTHER; + } + + @Override + public Matrix4f getHMDMatrixPoseRightEye(){ + if( hmdPoseRightEye != null ) { + return hmdPoseRightEye; + } else if(vrsystemFunctions == null) { + return Matrix4f.IDENTITY; + } else { + HmdMatrix34_t mat = vrsystemFunctions.GetEyeToHeadTransform.apply(JOpenVRLibrary.EVREye.EVREye_Eye_Right); + hmdPoseRightEye = new Matrix4f(); + return VRUtil.convertSteamVRMatrix3ToMatrix4f(mat, hmdPoseRightEye); + } + } + +}