Просмотр исходного кода

Some fixes in jme-vr (#1163)

* Added Valve Index to the recognized HMD list

* Fix lwjgl version mismatch

* Removing linux from the blacklist
grizeldi 6 лет назад
Родитель
Сommit
484d192467

+ 1 - 1
jme3-vr/build.gradle

@@ -2,7 +2,7 @@ if (!hasProperty('mainClass')) {
     ext.mainClass = ''
 }
 
-def lwjglVersion = '3.2.0'
+def lwjglVersion = '3.2.1'
 
 sourceCompatibility = '1.8'
 

+ 555 - 550
jme3-vr/src/main/java/com/jme3/app/VREnvironment.java

@@ -1,550 +1,555 @@
-package com.jme3.app;
-
-import java.util.Locale;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import com.jme3.app.state.AppState;
-import com.jme3.input.vr.VRAPI;
-import com.jme3.input.vr.VRBounds;
-import com.jme3.input.vr.VRInputAPI;
-import com.jme3.input.vr.VRMouseManager;
-import com.jme3.input.vr.VRViewManager;
-import com.jme3.input.vr.lwjgl_openvr.LWJGLOpenVR;
-import com.jme3.input.vr.lwjgl_openvr.LWJGLOpenVRMouseManager;
-import com.jme3.input.vr.lwjgl_openvr.LWJGLOpenVRViewManager;
-import com.jme3.input.vr.oculus.OculusMouseManager;
-import com.jme3.input.vr.oculus.OculusVR;
-import com.jme3.input.vr.oculus.OculusViewManager;
-import com.jme3.input.vr.openvr.OpenVR;
-import com.jme3.input.vr.openvr.OpenVRMouseManager;
-import com.jme3.input.vr.openvr.OpenVRViewManager;
-import com.jme3.input.vr.osvr.OSVR;
-import com.jme3.input.vr.osvr.OSVRViewManager;
-import com.jme3.renderer.Camera;
-import com.jme3.scene.Spatial;
-import com.jme3.system.AppSettings;
-import com.jme3.system.jopenvr.JOpenVRLibrary;
-import com.jme3.util.VRGuiManager;
-
-/**
- * 
- * @author Julien Seinturier - COMEX SA - <a href="http://www.seinturier.fr">http://www.seinturier.fr</a>
- *
- */
-public class VREnvironment {
-	
-	private static final Logger logger = Logger.getLogger(VREnvironment.class.getName());
-	
-    private VRAPI hardware              = null;
-    private VRGuiManager guiManager     = null;
-    private VRMouseManager mouseManager = null;
-    private VRViewManager viewmanager   = null;
-    
-    private VRBounds bounds             = null;
-    
-    /**
-     * The underlying system VR API. By default set to {@link VRConstants#SETTING_VRAPI_OPENVR_VALUE}.
-     */
-    public int vrBinding = VRConstants.SETTING_VRAPI_OPENVR_VALUE;
-    
-    private boolean seated        = false;
-    
-    private Spatial observer      = null;
-    
-    private boolean forceVR       = false;
-    
-    private boolean vrSupportedOS = false;
-    
-    private boolean nogui = false;
-    
-    private boolean compositorOS;
-    
-    private boolean useCompositor = true;
-    
-    private boolean instanceRendering = false;
-    
-    private boolean disableSwapBuffers = true;
-    
-	private float defaultFOV           = 108f;
-	
-    private float defaultAspect        = 1f;
-    
-    private AppSettings settings = null;
-    
-    private Application application = null;
-    
-    private Camera dummyCam = null;
-    
-    private AppState app = null;
-    
-    private boolean initialized = false;
-    
-    
-    public VREnvironment(AppSettings settings){
-    	
-    	this.settings = settings;
-
-        bounds       = null;
-        
-        processSettings();
-    }
-    
-	/**
-	 * Get the VR underlying hardware.
-	 * @return the VR underlying hardware.
-	 */
-	public VRAPI getVRHardware() {
-	    return hardware;
-	}
-	
-	/**
-	 * Set the VR bounds.
-	 * @see #getVRBounds()
-	 */
-	public void setVRBounds(VRBounds bounds){
-		this.bounds = bounds;
-	}
-	
-	/**
-	 * Get the VR bounds.
-	 * @return the VR bounds.
-	 * @see #setVRBounds(VRBounds)
-	 */
-	public VRBounds getVRBounds(){
-		return bounds;
-	}
-	
-	/**
-	 * Get the VR dedicated input.
-	 * @return the VR dedicated input.
-	 */
-	public VRInputAPI getVRinput() {
-	    if( hardware == null ){
-	    	return null;
-	    }
-	    
-	    return hardware.getVRinput();
-	}
-	
-	/**
-	 * Get the VR view manager.
-	 * @return the VR view manager.
-	 */
-	public VRViewManager getVRViewManager() {
-	    return viewmanager;
-	}
-	
-	/**
-	 * Get the GUI manager attached to this environment.
-	 * @return the GUI manager attached to this environment.
-	 */
-	public VRGuiManager getVRGUIManager(){
-		return guiManager;
-	}
-	
-	/**
-	 * Get the VR mouse manager attached to this environment.
-	 * @return the VR mouse manager attached to this environment.
-	 */
-	public VRMouseManager getVRMouseManager(){
-		return mouseManager;
-	}
-
-    /**
-     * Can be used to change seated experience during runtime.
-     * @param isSeated <code>true</code> if designed for sitting, <code>false</code> for standing/roomscale
-     * @see #isSeatedExperience()
-     */
-    public void setSeatedExperience(boolean isSeated) {
-        seated = isSeated;
-        if( hardware instanceof OpenVR ) {
-            if( hardware.getCompositor() == null ) {
-            	return;
-            }
-            
-            if( seated ) {
-                ((OpenVR)hardware).getCompositor().SetTrackingSpace.apply(JOpenVRLibrary.ETrackingUniverseOrigin.ETrackingUniverseOrigin_TrackingUniverseSeated);
-            } else {
-                ((OpenVR)hardware).getCompositor().SetTrackingSpace.apply(JOpenVRLibrary.ETrackingUniverseOrigin.ETrackingUniverseOrigin_TrackingUniverseStanding);                
-            }        
-        } else if (hardware instanceof LWJGLOpenVR) {
-        	if( ((LWJGLOpenVR)hardware).isInitialized() ) {
-            	((LWJGLOpenVR)hardware).setTrackingSpace(seated);
-            }
-        }
-    }
-    
-    /**
-     * Check if the application is configured as a seated experience.
-     * @return <code>true</code> if the application is configured as a seated experience and <code>false</code> otherwise.
-     * @see #setSeatedExperience(boolean)
-     */
-    public boolean isSeatedExperience() {
-        return seated;
-    }
-    
-    /**
-     * Set the VR headset height from the ground.
-     * @param amount the VR headset height from the ground.
-     * @see #getVRHeightAdjustment()
-     */
-    public void setVRHeightAdjustment(float amount) {
-        if( viewmanager != null ){
-        	viewmanager.setHeightAdjustment(amount);
-        }
-    }
-    
-    /**
-     * Get the VR headset height from the ground.
-     * @return the VR headset height from the ground.
-     * @see #setVRHeightAdjustment(float)
-     */
-    public float getVRHeightAdjustment() {
-        if( viewmanager != null ){
-        	return viewmanager.getHeightAdjustment();
-        }
-        return 0f;
-    }
-    
-    /**
-     * Get the scene observer. If no observer has been set, this method return the application {@link #getCamera() camera}.
-     * @return the scene observer. 
-     * @see #setObserver(Spatial)
-     */
-    public Object getObserver() {
-        if( observer == null ) {
-        	
-        	if (application != null){
-              return application.getCamera();
-        	} else {
-        		throw new IllegalStateException("VR environment is not attached to any application.");
-        	}
-        }
-        return observer;
-    }
-    
-    /**
-     * Set the scene observer. The VR headset will be linked to it. If no observer is set, the VR headset is linked to the application {@link #getCamera() camera}.
-     * @param observer the scene observer.
-     */
-    public void setObserver(Spatial observer) {
-       this.observer = observer;
-    }
-    
-    /**
-     * Get the default Field Of View (FOV) value.
-     * @return the default Field Of View (FOV) value.
-     * @see #setDefaultFOV(float)
-     */
-    public float getDefaultFOV() {
-		return defaultFOV;
-	}
-
-    /**
-     * Set the default Field Of View (FOV) value.
-     * @param defaultFOV the default Field Of View (FOV) value.
-     * @see #getDefaultFOV()
-     */
-	public void setDefaultFOV(float defaultFOV) {
-		this.defaultFOV = defaultFOV;
-	}
-
-	/**
-	 * Get the default aspect ratio.
-	 * @return the default aspect ratio.
-	 * @see #setDefaultAspect(float)
-	 */
-	public float getDefaultAspect() {
-		return defaultAspect;
-	}
-
-	/**
-	 * Set the default aspect ratio.
-	 * @param defaultAspect the default aspect ratio.
-	 * @see #getDefaultAspect()
-	 */
-	public void setDefaultAspect(float defaultAspect) {
-		this.defaultAspect = defaultAspect;
-	}
-    
-	/**
-	 * Get the {@link AppSettings settings} attached to this environment.
-	 * @return the {@link AppSettings settings} attached to this environment.
-	 * @see #setSettings(AppSettings)
-	 */
-	public AppSettings getSettings(){
-		return settings;
-	}
-	
-	/**
-	 * Set the {@link AppSettings settings} attached to this environment.
-	 * @param settings the {@link AppSettings settings} attached to this environment.
-	 * @see #getSettings()
-	 */
-	public void setSettings(AppSettings settings){
-		this.settings = settings;
-		processSettings();
-	}
-    
-    /**
-     * Get if the system currently support VR.
-     * @return <code>true</code> if the system currently support VR and <code>false</Code> otherwise.
-     */
-    public boolean isVRSupported() {
-        return vrSupportedOS;
-    }
-	
-    /**
-     * Check if the VR mode is enabled.
-     * @return <code>true</code> if the VR mode is enabled and <code>false</code> otherwise.
-     */
-    public boolean isInVR() {
-        return (forceVR || vrSupportedOS && hardware != null && hardware.isInitialized() && isInitialized());
-    }
-
-    /**
-     * Check if the rendering is instanced (see <a href="https://en.wikipedia.org/wiki/Geometry_instancing">Geometry instancing</a>).
-     * @return <code>true</code> if the rendering is instanced and <code>false</code> otherwise.
-     */
-    public boolean isInstanceRendering() {
-        return instanceRendering;
-    }
-    
-    public boolean isSwapBuffers(){
-    	return disableSwapBuffers;
-    }
-    
-    /**
-     * Check if the application has a GUI overlay attached.
-     * @return <code>true</code> if the application has a GUI overlay attached and <code>false</code> otherwise.
-     */
-    public boolean hasTraditionalGUIOverlay() {
-        return !nogui;
-    }
-    
-    /**
-     * Check if the VR environment is initialized. A call to the {@link #initialize() initialize()} method should set this value to <code>true</code>
-     * @return <code>true</code> if the VR environment is initialized and <code>false</code> otherwise.
-     */
-    public boolean isInitialized(){
-    	return initialized;
-    }
-    
-    /**
-     * Is the VR compositor is active.
-     * @return <code>true</code> if the VR compositor is active and <code>false</code> otherwise.
-     */
-    public boolean compositorAllowed() {
-        return useCompositor && compositorOS;
-    }
-
-    /**
-     * Reset headset pose if seating experience.
-     */
-    public void resetSeatedPose(){
-        if( vrSupportedOS == false || isSeatedExperience() == false ){
-        	return;
-        }
-        getVRHardware().reset();
-    }
-    
-    public AppState getAppState(){
-    	return app;
-    }
-    
-    public Application getApplication(){
-    	return application;
-    }
-    
-    /**
-     * Get the {@link Camera camera} used for rendering. 
-     * If the VR mode is {@link #isInVR() active}, this method return a dummy camera, otherwise, 
-     * this method return the camera of the attached application.
-     * @return the camera attached used for rendering.
-     */
-    public Camera getCamera() {
-        if( isInVR() && getVRViewManager() != null && getVRViewManager().getLeftCamera() != null ) {
-            return getDummyCamera();
-        }
-        
-        return application.getCamera();
-    }
-    
-    public Camera getDummyCamera(){
-    	
-    	if (dummyCam == null){
-    		
-    		if (application != null){
-    			
-    			if (application.getCamera() != null){
-    				dummyCam = application.getCamera().clone();
-    			} else {
-    				
-    				if ((settings != null) && (settings.getWidth() != 0) && (settings.getHeight() != 0)){
-    		        	dummyCam = new Camera(settings.getWidth(), settings.getHeight());
-    		        } else {
-    		        	dummyCam = new Camera();
-    		        }
-    			}
-    		} else {
-    			throw new IllegalStateException("VR environment is not attached to any application.");
-    		}
-    	}
-    	return dummyCam;
-    }
-    
-    /**
-     * Attach the VR environment to the given app state and application. 
-     * This method should be called within the {@link AppState#stateAttached(com.jme3.app.state.AppStateManager) stateAttached(com.jme3.app.state.AppStateManager)} method 
-     * from the app state.
-     * @param appState the app state to attach.
-     * @param application the application to attach.
-     */
-    public void atttach(AppState appState, Application application){    	
-    	this.application = application;
-    	this.app         = appState;
-    	
-    	// Instanciate view manager
-    	if (vrBinding == VRConstants.SETTING_VRAPI_OPENVR_VALUE){
-    		viewmanager = new OpenVRViewManager(this);
-    	} else if (vrBinding == VRConstants.SETTING_VRAPI_OSVR_VALUE){
-    		viewmanager = new OSVRViewManager(this);
-    	} else if (vrBinding == VRConstants.SETTING_VRAPI_OCULUSVR_VALUE) {
-    		viewmanager = new OculusViewManager(this);
-    	} else if (vrBinding == VRConstants.SETTING_VRAPI_OPENVR_LWJGL_VALUE) {
-    		viewmanager = new LWJGLOpenVRViewManager(this);
-    	} else {
-    		logger.severe("Cannot instanciate view manager, unknown VRAPI type: "+vrBinding);
-    	}
-    }
-    
-    /**
-     * Initialize this VR environment. This method enable the system bindings and configure all the VR system modules. 
-     * A call to this method has to be made before any use of VR capabilities.
-     * @return <code>true</code> if the VR environment is successfully initialized and <code>false</code> otherwise.
-     */
-    public boolean initialize(){
-    	
-    	logger.config("Initializing VR environment.");
-    	
-    	initialized = false;
-    	
-        // we are going to use OpenVR now, not the Oculus Rift
-        // OpenVR does support the Rift
-        String OS     = System.getProperty("os.name", "generic").toLowerCase(Locale.ENGLISH);
-        vrSupportedOS = !OS.contains("nux") && System.getProperty("sun.arch.data.model").equalsIgnoreCase("64"); //for the moment, linux/unix causes crashes, 64-bit only
-        compositorOS  = OS.contains("indows");
-        
-        if( vrSupportedOS) {
-        	if( vrBinding == VRConstants.SETTING_VRAPI_OSVR_VALUE ) {
-        		
-                guiManager   = new VRGuiManager(this);
-                mouseManager = new OpenVRMouseManager(this);
-        		
-                hardware = new OSVR(this);
-                initialized = true;
-                logger.config("Creating OSVR wrapper [SUCCESS]");
-            } else if( vrBinding == VRConstants.SETTING_VRAPI_OPENVR_VALUE ) {
-            	
-                guiManager   = new VRGuiManager(this);
-                mouseManager = new OpenVRMouseManager(this);
-
-            	hardware = new OpenVR(this);
-            	initialized = true;
-                logger.config("Creating OpenVR wrapper [SUCCESS]");
-            } else if (vrBinding == VRConstants.SETTING_VRAPI_OCULUSVR_VALUE) {
-            	
-                guiManager   = new VRGuiManager(this);
-                mouseManager = new OculusMouseManager(this);
-            	
-                hardware = new OculusVR(this);
-            	initialized = true;
-            	logger.config("Creating Occulus Rift wrapper [SUCCESS]");
-            } else if (vrBinding == VRConstants.SETTING_VRAPI_OPENVR_LWJGL_VALUE) {
-            	
-            	guiManager   = new VRGuiManager(this);
-                mouseManager = new LWJGLOpenVRMouseManager(this);
-
-            	hardware = new LWJGLOpenVR(this);
-            	initialized = true;
-                logger.config("Creating OpenVR/LWJGL wrapper [SUCCESS]");
-            } else {
-            	logger.config("Cannot create VR binding: "+vrBinding+" [FAILED]");
-            	logger.log(Level.SEVERE, "Cannot initialize VR environment [FAILED]");
-            }
-        	
-            if( hardware.initialize() ) {
-            	initialized &= true;
-            	logger.config("VR native wrapper initialized [SUCCESS]");
-            } else {
-            	initialized &= false;
-            	logger.warning("VR native wrapper initialized [FAILED]");
-            	logger.log(Level.SEVERE, "Cannot initialize VR environment [FAILED]");
-            }
-        } else {
-        	logger.log(Level.SEVERE, "System does not support VR capabilities.");
-        	logger.log(Level.SEVERE, "Cannot initialize VR environment [FAILED]");
-        }
-    	
-    	return initialized;
-    }
-    
-    private void processSettings(){
-    	if (settings != null){
-    		
-    		if (settings.get(VRConstants.SETTING_USE_COMPOSITOR) != null){
-    			useCompositor = settings.getBoolean(VRConstants.SETTING_USE_COMPOSITOR);
-                if( useCompositor == false ){
-                	disableSwapBuffers = false;
-                }
-    		}
-    		
-            if (settings.get(VRConstants.SETTING_ENABLE_MIRROR_WINDOW) != null){
-                if( useCompositor == false ) {
-                    disableSwapBuffers = false;
-                } else {
-                	disableSwapBuffers = !settings.getBoolean(VRConstants.SETTING_ENABLE_MIRROR_WINDOW);
-                }
-    		}
-    		
-            if (settings.get(VRConstants.SETTING_GUI_OVERDRAW) != null){
-            	getVRGUIManager().setGuiOverdraw(settings.getBoolean(VRConstants.SETTING_GUI_OVERDRAW));
-    		}
-    	    
-            if (settings.get(VRConstants.SETTING_GUI_CURVED_SURFACE) != null){
-            	getVRGUIManager().setCurvedSurface(settings.getBoolean(VRConstants.SETTING_GUI_CURVED_SURFACE));
-    		}
-    		
-    		if (settings.get(VRConstants.SETTING_NO_GUI) != null){
-            	nogui = settings.getBoolean(VRConstants.SETTING_NO_GUI);
-    		}
-    		
-            if (settings.get(VRConstants.SETTING_VRAPI) != null){
-            	vrBinding = settings.getInteger(VRConstants.SETTING_VRAPI);
-    		}
-            
-            if (settings.get(VRConstants.SETTING_SEATED_EXPERIENCE) != null){
-            	seated = settings.getBoolean(VRConstants.SETTING_SEATED_EXPERIENCE);
-    		}
-            
-            if (settings.get(VRConstants.SETTING_INSTANCE_RENDERING) != null){
-            	instanceRendering = settings.getBoolean(VRConstants.SETTING_INSTANCE_RENDERING);
-    		}
-
-            if (settings.get(VRConstants.SETTING_DEFAULT_FOV) != null){
-            	defaultFOV = settings.getFloat(VRConstants.SETTING_DEFAULT_FOV);
-    		}
-            
-            if (settings.get(VRConstants.SETTING_DEFAULT_ASPECT_RATIO) != null){
-            	defaultAspect = settings.getFloat(VRConstants.SETTING_DEFAULT_ASPECT_RATIO);
-    		}
-            
-            if (settings.get(VRConstants.SETTING_FLIP_EYES) != null){
-                if( getVRHardware() != null ){
-                	getVRHardware().setFlipEyes(settings.getBoolean(VRConstants.SETTING_FLIP_EYES));
-                } 
-    		}
-    	}
-    }
-}
+package com.jme3.app;
+
+import java.util.Locale;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.jme3.app.state.AppState;
+import com.jme3.input.vr.VRAPI;
+import com.jme3.input.vr.VRBounds;
+import com.jme3.input.vr.VRInputAPI;
+import com.jme3.input.vr.VRMouseManager;
+import com.jme3.input.vr.VRViewManager;
+import com.jme3.input.vr.lwjgl_openvr.LWJGLOpenVR;
+import com.jme3.input.vr.lwjgl_openvr.LWJGLOpenVRMouseManager;
+import com.jme3.input.vr.lwjgl_openvr.LWJGLOpenVRViewManager;
+import com.jme3.input.vr.oculus.OculusMouseManager;
+import com.jme3.input.vr.oculus.OculusVR;
+import com.jme3.input.vr.oculus.OculusViewManager;
+import com.jme3.input.vr.openvr.OpenVR;
+import com.jme3.input.vr.openvr.OpenVRMouseManager;
+import com.jme3.input.vr.openvr.OpenVRViewManager;
+import com.jme3.input.vr.osvr.OSVR;
+import com.jme3.input.vr.osvr.OSVRViewManager;
+import com.jme3.renderer.Camera;
+import com.jme3.scene.Spatial;
+import com.jme3.system.AppSettings;
+import com.jme3.system.jopenvr.JOpenVRLibrary;
+import com.jme3.util.VRGuiManager;
+
+/**
+ * 
+ * @author Julien Seinturier - COMEX SA - <a href="http://www.seinturier.fr">http://www.seinturier.fr</a>
+ *
+ */
+public class VREnvironment {
+	
+	private static final Logger logger = Logger.getLogger(VREnvironment.class.getName());
+	
+    private VRAPI hardware              = null;
+    private VRGuiManager guiManager     = null;
+    private VRMouseManager mouseManager = null;
+    private VRViewManager viewmanager   = null;
+    
+    private VRBounds bounds             = null;
+    
+    /**
+     * The underlying system VR API. By default set to {@link VRConstants#SETTING_VRAPI_OPENVR_VALUE}.
+     */
+    public int vrBinding = VRConstants.SETTING_VRAPI_OPENVR_VALUE;
+    
+    private boolean seated        = false;
+    
+    private Spatial observer      = null;
+    
+    private boolean forceVR       = false;
+    
+    private boolean vrSupportedOS = false;
+    
+    private boolean nogui = false;
+    
+    private boolean compositorOS;
+    
+    private boolean useCompositor = true;
+    
+    private boolean instanceRendering = false;
+    
+    private boolean disableSwapBuffers = true;
+    
+	private float defaultFOV           = 108f;
+	
+    private float defaultAspect        = 1f;
+    
+    private AppSettings settings = null;
+    
+    private Application application = null;
+    
+    private Camera dummyCam = null;
+    
+    private AppState app = null;
+    
+    private boolean initialized = false;
+    
+    
+    public VREnvironment(AppSettings settings){
+    	
+    	this.settings = settings;
+
+        bounds       = null;
+        
+        processSettings();
+    }
+    
+	/**
+	 * Get the VR underlying hardware.
+	 * @return the VR underlying hardware.
+	 */
+	public VRAPI getVRHardware() {
+	    return hardware;
+	}
+	
+	/**
+	 * Set the VR bounds.
+	 * @see #getVRBounds()
+	 */
+	public void setVRBounds(VRBounds bounds){
+		this.bounds = bounds;
+	}
+	
+	/**
+	 * Get the VR bounds.
+	 * @return the VR bounds.
+	 * @see #setVRBounds(VRBounds)
+	 */
+	public VRBounds getVRBounds(){
+		return bounds;
+	}
+	
+	/**
+	 * Get the VR dedicated input.
+	 * @return the VR dedicated input.
+	 */
+	public VRInputAPI getVRinput() {
+	    if( hardware == null ){
+	    	return null;
+	    }
+	    
+	    return hardware.getVRinput();
+	}
+	
+	/**
+	 * Get the VR view manager.
+	 * @return the VR view manager.
+	 */
+	public VRViewManager getVRViewManager() {
+	    return viewmanager;
+	}
+	
+	/**
+	 * Get the GUI manager attached to this environment.
+	 * @return the GUI manager attached to this environment.
+	 */
+	public VRGuiManager getVRGUIManager(){
+		return guiManager;
+	}
+	
+	/**
+	 * Get the VR mouse manager attached to this environment.
+	 * @return the VR mouse manager attached to this environment.
+	 */
+	public VRMouseManager getVRMouseManager(){
+		return mouseManager;
+	}
+
+    /**
+     * Can be used to change seated experience during runtime.
+     * @param isSeated <code>true</code> if designed for sitting, <code>false</code> for standing/roomscale
+     * @see #isSeatedExperience()
+     */
+    public void setSeatedExperience(boolean isSeated) {
+        seated = isSeated;
+        if( hardware instanceof OpenVR ) {
+            if( hardware.getCompositor() == null ) {
+            	return;
+            }
+            
+            if( seated ) {
+                ((OpenVR)hardware).getCompositor().SetTrackingSpace.apply(JOpenVRLibrary.ETrackingUniverseOrigin.ETrackingUniverseOrigin_TrackingUniverseSeated);
+            } else {
+                ((OpenVR)hardware).getCompositor().SetTrackingSpace.apply(JOpenVRLibrary.ETrackingUniverseOrigin.ETrackingUniverseOrigin_TrackingUniverseStanding);                
+            }        
+        } else if (hardware instanceof LWJGLOpenVR) {
+        	if( ((LWJGLOpenVR)hardware).isInitialized() ) {
+            	((LWJGLOpenVR)hardware).setTrackingSpace(seated);
+            }
+        }
+    }
+    
+    /**
+     * Check if the application is configured as a seated experience.
+     * @return <code>true</code> if the application is configured as a seated experience and <code>false</code> otherwise.
+     * @see #setSeatedExperience(boolean)
+     */
+    public boolean isSeatedExperience() {
+        return seated;
+    }
+    
+    /**
+     * Set the VR headset height from the ground.
+     * @param amount the VR headset height from the ground.
+     * @see #getVRHeightAdjustment()
+     */
+    public void setVRHeightAdjustment(float amount) {
+        if( viewmanager != null ){
+        	viewmanager.setHeightAdjustment(amount);
+        }
+    }
+    
+    /**
+     * Get the VR headset height from the ground.
+     * @return the VR headset height from the ground.
+     * @see #setVRHeightAdjustment(float)
+     */
+    public float getVRHeightAdjustment() {
+        if( viewmanager != null ){
+        	return viewmanager.getHeightAdjustment();
+        }
+        return 0f;
+    }
+    
+    /**
+     * Get the scene observer. If no observer has been set, this method return the application {@link #getCamera() camera}.
+     * @return the scene observer. 
+     * @see #setObserver(Spatial)
+     */
+    public Object getObserver() {
+        if( observer == null ) {
+        	
+        	if (application != null){
+              return application.getCamera();
+        	} else {
+        		throw new IllegalStateException("VR environment is not attached to any application.");
+        	}
+        }
+        return observer;
+    }
+    
+    /**
+     * Set the scene observer. The VR headset will be linked to it. If no observer is set, the VR headset is linked to the application {@link #getCamera() camera}.
+     * @param observer the scene observer.
+     */
+    public void setObserver(Spatial observer) {
+       this.observer = observer;
+    }
+    
+    /**
+     * Get the default Field Of View (FOV) value.
+     * @return the default Field Of View (FOV) value.
+     * @see #setDefaultFOV(float)
+     */
+    public float getDefaultFOV() {
+		return defaultFOV;
+	}
+
+    /**
+     * Set the default Field Of View (FOV) value.
+     * @param defaultFOV the default Field Of View (FOV) value.
+     * @see #getDefaultFOV()
+     */
+	public void setDefaultFOV(float defaultFOV) {
+		this.defaultFOV = defaultFOV;
+	}
+
+	/**
+	 * Get the default aspect ratio.
+	 * @return the default aspect ratio.
+	 * @see #setDefaultAspect(float)
+	 */
+	public float getDefaultAspect() {
+		return defaultAspect;
+	}
+
+	/**
+	 * Set the default aspect ratio.
+	 * @param defaultAspect the default aspect ratio.
+	 * @see #getDefaultAspect()
+	 */
+	public void setDefaultAspect(float defaultAspect) {
+		this.defaultAspect = defaultAspect;
+	}
+    
+	/**
+	 * Get the {@link AppSettings settings} attached to this environment.
+	 * @return the {@link AppSettings settings} attached to this environment.
+	 * @see #setSettings(AppSettings)
+	 */
+	public AppSettings getSettings(){
+		return settings;
+	}
+	
+	/**
+	 * Set the {@link AppSettings settings} attached to this environment.
+	 * @param settings the {@link AppSettings settings} attached to this environment.
+	 * @see #getSettings()
+	 */
+	public void setSettings(AppSettings settings){
+		this.settings = settings;
+		processSettings();
+	}
+    
+    /**
+     * Get if the system currently support VR.
+     * @return <code>true</code> if the system currently support VR and <code>false</Code> otherwise.
+     */
+    public boolean isVRSupported() {
+        return vrSupportedOS;
+    }
+	
+    /**
+     * Check if the VR mode is enabled.
+     * @return <code>true</code> if the VR mode is enabled and <code>false</code> otherwise.
+     */
+    public boolean isInVR() {
+        return (forceVR || vrSupportedOS && hardware != null && hardware.isInitialized() && isInitialized());
+    }
+
+    /**
+     * Check if the rendering is instanced (see <a href="https://en.wikipedia.org/wiki/Geometry_instancing">Geometry instancing</a>).
+     * @return <code>true</code> if the rendering is instanced and <code>false</code> otherwise.
+     */
+    public boolean isInstanceRendering() {
+        return instanceRendering;
+    }
+    
+    public boolean isSwapBuffers(){
+    	return disableSwapBuffers;
+    }
+    
+    /**
+     * Check if the application has a GUI overlay attached.
+     * @return <code>true</code> if the application has a GUI overlay attached and <code>false</code> otherwise.
+     */
+    public boolean hasTraditionalGUIOverlay() {
+        return !nogui;
+    }
+    
+    /**
+     * Check if the VR environment is initialized. A call to the {@link #initialize() initialize()} method should set this value to <code>true</code>
+     * @return <code>true</code> if the VR environment is initialized and <code>false</code> otherwise.
+     */
+    public boolean isInitialized(){
+    	return initialized;
+    }
+    
+    /**
+     * Is the VR compositor is active.
+     * @return <code>true</code> if the VR compositor is active and <code>false</code> otherwise.
+     */
+    public boolean compositorAllowed() {
+        return useCompositor && compositorOS;
+    }
+
+    /**
+     * Reset headset pose if seating experience.
+     */
+    public void resetSeatedPose(){
+        if( vrSupportedOS == false || isSeatedExperience() == false ){
+        	return;
+        }
+        getVRHardware().reset();
+    }
+    
+    public AppState getAppState(){
+    	return app;
+    }
+    
+    public Application getApplication(){
+    	return application;
+    }
+    
+    /**
+     * Get the {@link Camera camera} used for rendering. 
+     * If the VR mode is {@link #isInVR() active}, this method return a dummy camera, otherwise, 
+     * this method return the camera of the attached application.
+     * @return the camera attached used for rendering.
+     */
+    public Camera getCamera() {
+        if( isInVR() && getVRViewManager() != null && getVRViewManager().getLeftCamera() != null ) {
+            return getDummyCamera();
+        }
+        
+        return application.getCamera();
+    }
+    
+    public Camera getDummyCamera(){
+    	
+    	if (dummyCam == null){
+    		
+    		if (application != null){
+    			
+    			if (application.getCamera() != null){
+    				dummyCam = application.getCamera().clone();
+    			} else {
+    				
+    				if ((settings != null) && (settings.getWidth() != 0) && (settings.getHeight() != 0)){
+    		        	dummyCam = new Camera(settings.getWidth(), settings.getHeight());
+    		        } else {
+    		        	dummyCam = new Camera();
+    		        }
+    			}
+    		} else {
+    			throw new IllegalStateException("VR environment is not attached to any application.");
+    		}
+    	}
+    	return dummyCam;
+    }
+    
+    /**
+     * Attach the VR environment to the given app state and application. 
+     * This method should be called within the {@link AppState#stateAttached(com.jme3.app.state.AppStateManager) stateAttached(com.jme3.app.state.AppStateManager)} method 
+     * from the app state.
+     * @param appState the app state to attach.
+     * @param application the application to attach.
+     */
+    public void atttach(AppState appState, Application application){    	
+    	this.application = application;
+    	this.app         = appState;
+    	
+    	// Instanciate view manager
+    	if (vrBinding == VRConstants.SETTING_VRAPI_OPENVR_VALUE){
+    		viewmanager = new OpenVRViewManager(this);
+    	} else if (vrBinding == VRConstants.SETTING_VRAPI_OSVR_VALUE){
+    		viewmanager = new OSVRViewManager(this);
+    	} else if (vrBinding == VRConstants.SETTING_VRAPI_OCULUSVR_VALUE) {
+    		viewmanager = new OculusViewManager(this);
+    	} else if (vrBinding == VRConstants.SETTING_VRAPI_OPENVR_LWJGL_VALUE) {
+    		viewmanager = new LWJGLOpenVRViewManager(this);
+    	} else {
+    		logger.severe("Cannot instanciate view manager, unknown VRAPI type: "+vrBinding);
+    	}
+    }
+    
+    /**
+     * Initialize this VR environment. This method enable the system bindings and configure all the VR system modules. 
+     * A call to this method has to be made before any use of VR capabilities.
+     * @return <code>true</code> if the VR environment is successfully initialized and <code>false</code> otherwise.
+     */
+    public boolean initialize(){
+    	
+    	logger.config("Initializing VR environment.");
+    	
+    	initialized = false;
+    	
+        // we are going to use OpenVR now, not the Oculus Rift
+        // OpenVR does support the Rift
+        String OS     = System.getProperty("os.name", "generic").toLowerCase(Locale.ENGLISH);
+        vrSupportedOS = System.getProperty("sun.arch.data.model").equalsIgnoreCase("64"); //64-bit only
+        compositorOS  = OS.contains("indows") || OS.contains("nux");
+
+        if (OS.contains("nux") && vrBinding != VRConstants.SETTING_VRAPI_OPENVR_LWJGL_VALUE){
+        	logger.severe("Only LWJGL VR backend is currently (partially) supported on Linux.");
+        	vrSupportedOS = false;
+        }
+
+        if( vrSupportedOS) {
+        	if( vrBinding == VRConstants.SETTING_VRAPI_OSVR_VALUE ) {
+        		
+                guiManager   = new VRGuiManager(this);
+                mouseManager = new OpenVRMouseManager(this);
+        		
+                hardware = new OSVR(this);
+                initialized = true;
+                logger.config("Creating OSVR wrapper [SUCCESS]");
+            } else if( vrBinding == VRConstants.SETTING_VRAPI_OPENVR_VALUE ) {
+            	
+                guiManager   = new VRGuiManager(this);
+                mouseManager = new OpenVRMouseManager(this);
+
+            	hardware = new OpenVR(this);
+            	initialized = true;
+                logger.config("Creating OpenVR wrapper [SUCCESS]");
+            } else if (vrBinding == VRConstants.SETTING_VRAPI_OCULUSVR_VALUE) {
+            	
+                guiManager   = new VRGuiManager(this);
+                mouseManager = new OculusMouseManager(this);
+            	
+                hardware = new OculusVR(this);
+            	initialized = true;
+            	logger.config("Creating Occulus Rift wrapper [SUCCESS]");
+            } else if (vrBinding == VRConstants.SETTING_VRAPI_OPENVR_LWJGL_VALUE) {
+            	
+            	guiManager   = new VRGuiManager(this);
+                mouseManager = new LWJGLOpenVRMouseManager(this);
+
+            	hardware = new LWJGLOpenVR(this);
+            	initialized = true;
+                logger.config("Creating OpenVR/LWJGL wrapper [SUCCESS]");
+            } else {
+            	logger.config("Cannot create VR binding: "+vrBinding+" [FAILED]");
+            	logger.log(Level.SEVERE, "Cannot initialize VR environment [FAILED]");
+            }
+        	
+            if( hardware.initialize() ) {
+            	initialized &= true;
+            	logger.config("VR native wrapper initialized [SUCCESS]");
+            } else {
+            	initialized &= false;
+            	logger.warning("VR native wrapper initialized [FAILED]");
+            	logger.log(Level.SEVERE, "Cannot initialize VR environment [FAILED]");
+            }
+        } else {
+        	logger.log(Level.SEVERE, "System does not support VR capabilities.");
+        	logger.log(Level.SEVERE, "Cannot initialize VR environment [FAILED]");
+        }
+    	
+    	return initialized;
+    }
+    
+    private void processSettings(){
+    	if (settings != null){
+    		
+    		if (settings.get(VRConstants.SETTING_USE_COMPOSITOR) != null){
+    			useCompositor = settings.getBoolean(VRConstants.SETTING_USE_COMPOSITOR);
+                if( useCompositor == false ){
+                	disableSwapBuffers = false;
+                }
+    		}
+    		
+            if (settings.get(VRConstants.SETTING_ENABLE_MIRROR_WINDOW) != null){
+                if( useCompositor == false ) {
+                    disableSwapBuffers = false;
+                } else {
+                	disableSwapBuffers = !settings.getBoolean(VRConstants.SETTING_ENABLE_MIRROR_WINDOW);
+                }
+    		}
+    		
+            if (settings.get(VRConstants.SETTING_GUI_OVERDRAW) != null){
+            	getVRGUIManager().setGuiOverdraw(settings.getBoolean(VRConstants.SETTING_GUI_OVERDRAW));
+    		}
+    	    
+            if (settings.get(VRConstants.SETTING_GUI_CURVED_SURFACE) != null){
+            	getVRGUIManager().setCurvedSurface(settings.getBoolean(VRConstants.SETTING_GUI_CURVED_SURFACE));
+    		}
+    		
+    		if (settings.get(VRConstants.SETTING_NO_GUI) != null){
+            	nogui = settings.getBoolean(VRConstants.SETTING_NO_GUI);
+    		}
+    		
+            if (settings.get(VRConstants.SETTING_VRAPI) != null){
+            	vrBinding = settings.getInteger(VRConstants.SETTING_VRAPI);
+    		}
+            
+            if (settings.get(VRConstants.SETTING_SEATED_EXPERIENCE) != null){
+            	seated = settings.getBoolean(VRConstants.SETTING_SEATED_EXPERIENCE);
+    		}
+            
+            if (settings.get(VRConstants.SETTING_INSTANCE_RENDERING) != null){
+            	instanceRendering = settings.getBoolean(VRConstants.SETTING_INSTANCE_RENDERING);
+    		}
+
+            if (settings.get(VRConstants.SETTING_DEFAULT_FOV) != null){
+            	defaultFOV = settings.getFloat(VRConstants.SETTING_DEFAULT_FOV);
+    		}
+            
+            if (settings.get(VRConstants.SETTING_DEFAULT_ASPECT_RATIO) != null){
+            	defaultAspect = settings.getFloat(VRConstants.SETTING_DEFAULT_ASPECT_RATIO);
+    		}
+            
+            if (settings.get(VRConstants.SETTING_FLIP_EYES) != null){
+                if( getVRHardware() != null ){
+                	getVRHardware().setFlipEyes(settings.getBoolean(VRConstants.SETTING_FLIP_EYES));
+                } 
+    		}
+    	}
+    }
+}

+ 68 - 63
jme3-vr/src/main/java/com/jme3/input/vr/HmdType.java

@@ -1,64 +1,69 @@
-package com.jme3.input.vr;
-
-/**
- * The type of VR Head Mounted Device (HMD)
- * @author reden - phr00t - https://github.com/phr00t
- * @author Julien Seinturier - COMEX SA - <a href="http://www.seinturier.fr">http://www.seinturier.fr</a>
- */
-public enum HmdType {
-	
-	/**
-	 * <a href="https://www.vive.com/fr/">HTC vive</a> Head Mounted Device (HMD).
-	 */
-    HTC_VIVE, 
-    
-    /**
-     * <a href="https://www3.oculus.com/en-us/rift/">Occulus Rift</a> Head Mounted Device (HMD).
-     */
-    OCULUS_RIFT, 
-    
-    /**
-     * <a href="http://www.osvr.org/">OSVR</a> generic Head Mounted Device (HMD).
-     */
-    OSVR, 
-    
-    /**
-     * <a href="https://www.getfove.com/">FOVE</a> Head Mounted Device (HMD).
-     */
-    FOVE, 
-    
-    /**
-     * <a href="http://www.starvr.com/">STARVR</a> Head Mounted Device (HMD).
-     */
-    STARVR, 
-    
-    /**
-     * <a href="http://gamefacelabs.com/">GameFace</a> Head Mounted Device (HMD).
-     */
-    GAMEFACE, 
-    
-    /**
-     * <a href="https://www.playstation.com/en-us/explore/playstation-vr/">PlayStation VR</a> (formely Morpheus) Head Mounted Device (HMD).
-     */
-    MORPHEUS, 
-    
-    /**
-     * <a href="http://www.samsung.com/fr/galaxynote4/gear-vr/">Samsung GearVR</a> Head Mounted Device (HMD).
-     */
-    GEARVR, 
-    
-    /**
-     * a null Head Mounted Device (HMD).
-     */
-    NULL, 
-    
-    /**
-     * a none Head Mounted Device (HMD).
-     */
-    NONE, 
-    
-    /**
-     * a not referenced Head Mounted Device (HMD).
-     */
-    OTHER
+package com.jme3.input.vr;
+
+/**
+ * The type of VR Head Mounted Device (HMD)
+ * @author reden - phr00t - https://github.com/phr00t
+ * @author Julien Seinturier - COMEX SA - <a href="http://www.seinturier.fr">http://www.seinturier.fr</a>
+ */
+public enum HmdType {
+	
+	/**
+	 * <a href="https://www.vive.com/fr/">HTC vive</a> Head Mounted Device (HMD).
+	 */
+    HTC_VIVE,
+
+    /**
+     * <a href="https://www.valvesoftware.com/en/index">Valve Index</a> Head Mounted Device (HMD).
+     */
+    VALVE_INDEX,
+
+    /**
+     * <a href="https://www3.oculus.com/en-us/rift/">Occulus Rift</a> Head Mounted Device (HMD).
+     */
+    OCULUS_RIFT, 
+    
+    /**
+     * <a href="http://www.osvr.org/">OSVR</a> generic Head Mounted Device (HMD).
+     */
+    OSVR, 
+    
+    /**
+     * <a href="https://www.getfove.com/">FOVE</a> Head Mounted Device (HMD).
+     */
+    FOVE, 
+    
+    /**
+     * <a href="http://www.starvr.com/">STARVR</a> Head Mounted Device (HMD).
+     */
+    STARVR, 
+    
+    /**
+     * <a href="http://gamefacelabs.com/">GameFace</a> Head Mounted Device (HMD).
+     */
+    GAMEFACE, 
+    
+    /**
+     * <a href="https://www.playstation.com/en-us/explore/playstation-vr/">PlayStation VR</a> (formely Morpheus) Head Mounted Device (HMD).
+     */
+    MORPHEUS, 
+    
+    /**
+     * <a href="http://www.samsung.com/fr/galaxynote4/gear-vr/">Samsung GearVR</a> Head Mounted Device (HMD).
+     */
+    GEARVR, 
+    
+    /**
+     * a null Head Mounted Device (HMD).
+     */
+    NULL, 
+    
+    /**
+     * a none Head Mounted Device (HMD).
+     */
+    NONE, 
+    
+    /**
+     * a not referenced Head Mounted Device (HMD).
+     */
+    OTHER
 }

+ 2 - 0
jme3-vr/src/main/java/com/jme3/input/vr/lwjgl_openvr/LWJGLOpenVR.java

@@ -421,6 +421,8 @@ public class LWJGLOpenVR implements VRAPI {
                 completeName = completeName.toLowerCase(Locale.ENGLISH).trim();
                 if( completeName.contains("htc") || completeName.contains("vive") ) {
                     return HmdType.HTC_VIVE;
+                } else if ( completeName.contains("index") ) {
+                    return HmdType.VALVE_INDEX;
                 } else if( completeName.contains("osvr") ) {
                     return HmdType.OSVR;
                 } else if( completeName.contains("oculus") || completeName.contains("rift") ||

+ 597 - 595
jme3-vr/src/main/java/com/jme3/input/vr/openvr/OpenVR.java

@@ -1,595 +1,597 @@
-/*
- * 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.openvr;
-
-import com.jme3.app.VREnvironment;
-import com.jme3.input.vr.HmdType;
-import com.jme3.input.vr.VRAPI;
-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.system.jopenvr.VR_IVRTrackedCamera_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 <a href="https://github.com/ValveSoftware/openvr/wiki/API-Documentation">OpenVR</a> system. 
- * @author reden - phr00t - https://github.com/phr00t
- * @author Julien Seinturier - COMEX SA - <a href="http://www.seinturier.fr">http://www.seinturier.fr</a>
- */
-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 VR_IVRTrackedCamera_FnTable cameraFunctions;
-    
-    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;
-    
-    /**
-     * Convert specific OpenVR {@link com.jme3.system.jopenvr.HmdMatrix34_t HmdMatrix34_t} into JME {@link Matrix4f Matrix4f}
-     * @param hmdMatrix the input matrix
-     * @param mat the converted matrix
-     * @return the converted matrix
-     */
-    public static Matrix4f convertSteamVRMatrix3ToMatrix4f(com.jme3.system.jopenvr.HmdMatrix34_t hmdMatrix, Matrix4f mat){
-        mat.set(hmdMatrix.m[0], hmdMatrix.m[1], hmdMatrix.m[2], hmdMatrix.m[3], 
-                hmdMatrix.m[4], hmdMatrix.m[5], hmdMatrix.m[6], hmdMatrix.m[7], 
-                hmdMatrix.m[8], hmdMatrix.m[9], hmdMatrix.m[10], hmdMatrix.m[11], 
-                0f, 0f, 0f, 1f);
-        return mat;
-    }
-    
-    /**
-     * Convert specific OpenVR {@link com.jme3.system.jopenvr.HmdMatrix44_t HmdMatrix34_t} into JME {@link Matrix4f Matrix4f}
-     * @param hmdMatrix the input matrix
-     * @param mat the converted matrix
-     * @return the converted matrix
-     */
-    public static Matrix4f convertSteamVRMatrix4ToMatrix4f(com.jme3.system.jopenvr.HmdMatrix44_t hmdMatrix, Matrix4f mat){
-        mat.set(hmdMatrix.m[0], hmdMatrix.m[1], hmdMatrix.m[2], hmdMatrix.m[3], 
-                hmdMatrix.m[4], hmdMatrix.m[5], hmdMatrix.m[6], hmdMatrix.m[7],
-                hmdMatrix.m[8], hmdMatrix.m[9], hmdMatrix.m[10], hmdMatrix.m[11], 
-                hmdMatrix.m[12], hmdMatrix.m[13], hmdMatrix.m[14], hmdMatrix.m[15]);
-        return mat;
-    }
-    
-    
-    /**
-     * Create a new <a href="https://github.com/ValveSoftware/openvr/wiki/API-Documentation">OpenVR</a> 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;
-    }
-    
-    public VR_IVRTrackedCamera_FnTable getTrackedCamera(){
-      return cameraFunctions;
-    }
-    
-    @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;
-        
-        // Init the native linking to the OpenVR library.
-        try{
-          JOpenVRLibrary.init();
-        } catch(Throwable t){
-          logger.log(Level.SEVERE, "Cannot link to OpenVR system library: "+t.getMessage(), t);
-          return false;
-        }
-        
-        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<poseMatrices.length;i++) poseMatrices[i] = new Matrix4f();
-
-            timePerFrame = 1.0 / hmdDisplayFrequency.get(0);
-            
-            // disable all this stuff which kills performance
-            hmdTrackedDevicePoseReference.setAutoRead(false);
-            hmdTrackedDevicePoseReference.setAutoWrite(false);
-            hmdTrackedDevicePoseReference.setAutoSynch(false);
-            for(int i=0;i<JOpenVRLibrary.k_unMaxTrackedDeviceCount;i++) {
-                hmdTrackedDevicePoses[i].setAutoRead(false);
-                hmdTrackedDevicePoses[i].setAutoWrite(false);
-                hmdTrackedDevicePoses[i].setAutoSynch(false);
-            }
-            
-            // init controllers for the first time
-            VRinput = new OpenVRInput(environment);
-            VRinput.init();
-            VRinput.updateConnectedControllers();
-            
-            // init bounds & chaperone info
-            OpenVRBounds bounds = new OpenVRBounds();
-            bounds.init(this);
-            environment.setVRBounds(bounds);
-            
-            logger.config("Initializing OpenVR system [SUCCESS]");
-            initSuccess = true;
-            return true;
-        }
-    }
-    
-    @Override
-    public boolean initVRCompositor(boolean allowed) {
-        hmdErrorStore.setValue(0); // clear the error store
-        if( allowed && vrsystemFunctions != null ) {
-        	
-        	IntByReference intptr = JOpenVRLibrary.VR_GetGenericInterface(JOpenVRLibrary.IVRCompositor_Version, hmdErrorStore);
-        	if (intptr != null){
-        	
-        		if (intptr.getPointer() != null){
-            		compositorFunctions = new VR_IVRCompositor_FnTable(intptr.getPointer());
-                    if(compositorFunctions != null && hmdErrorStore.getValue() == 0 ){          
-                        compositorFunctions.setAutoSynch(false);
-                        compositorFunctions.read();
-                        if( environment.isSeatedExperience() ) {                    
-                            compositorFunctions.SetTrackingSpace.apply(JOpenVRLibrary.ETrackingUniverseOrigin.ETrackingUniverseOrigin_TrackingUniverseSeated);
-                        } else {
-                            compositorFunctions.SetTrackingSpace.apply(JOpenVRLibrary.ETrackingUniverseOrigin.ETrackingUniverseOrigin_TrackingUniverseStanding);                
-                        }
-                        logger.config("OpenVR Compositor initialized");
-                    } else {
-                        logger.severe("OpenVR Compositor error: " + hmdErrorStore.getValue());
-                        compositorFunctions = null;
-                    }
-        		} else {
-        			logger.log(Level.SEVERE, "Cannot get valid pointer for generic interface \""+JOpenVRLibrary.IVRCompositor_Version+"\", "+OpenVRUtil.getEVRInitErrorString(hmdErrorStore.getValue())+" ("+hmdErrorStore.getValue()+")");
-        			compositorFunctions = null;
-        		}
-
-        	} else {
-        		logger.log(Level.SEVERE, "Cannot get generic interface for \""+JOpenVRLibrary.IVRCompositor_Version+"\", "+OpenVRUtil.getEVRInitErrorString(hmdErrorStore.getValue())+" ("+hmdErrorStore.getValue()+")");
-        		compositorFunctions = null;
-        	}
-        	
-            
-        }
-        if( compositorFunctions == null ) {
-            logger.severe("Skipping VR Compositor...");
-            if( vrsystemFunctions != null ) {
-                vsyncToPhotons = vrsystemFunctions.GetFloatTrackedDeviceProperty.apply(JOpenVRLibrary.k_unTrackedDeviceIndex_Hmd, JOpenVRLibrary.ETrackedDeviceProperty.ETrackedDeviceProperty_Prop_SecondsFromVsyncToPhotons_Float, hmdErrorStore);
-            } else {
-                vsyncToPhotons = 0f;
-            }
-        }
-        return compositorFunctions != null;
-    }
-
-    /**
-     * Initialize the headset camera.
-     * @param allowed <code>true</code> is the use of the headset camera is allowed and <code>false</code> otherwise.
-     */
-    public void initCamera(boolean allowed) {
-      hmdErrorStore.setValue(0); // clear the error store
-      
-      if( allowed && vrsystemFunctions != null ) {
-        IntByReference intptr = JOpenVRLibrary.VR_GetGenericInterface(JOpenVRLibrary.IVRTrackedCamera_Version, hmdErrorStore);
-    	  if (intptr != null){
-    	    cameraFunctions = new VR_IVRTrackedCamera_FnTable(intptr.getPointer());
-    	    if(cameraFunctions != null && hmdErrorStore.getValue() == 0 ){
-    	      cameraFunctions.setAutoSynch(false);
-    	        cameraFunctions.read();
-    	        logger.config("OpenVR Camera initialized");
-    	    }
-    	  }
-       }
-    }
-    
-    @Override
-    public void destroy() {
-        JOpenVRLibrary.VR_ShutdownInternal();
-    }
-
-    @Override
-    public boolean isInitialized() {
-        return initSuccess;
-    }
-
-    @Override
-    public void reset() {
-        if( vrsystemFunctions == null ) return;
-        vrsystemFunctions.ResetSeatedZeroPose.apply();
-        hmdSeatToStand = null;
-    }
-
-    @Override
-    public void getRenderSize(Vector2f store) {
-        if( vrsystemFunctions == null ) {
-            // 1344x1512
-            store.x = 1344f;
-            store.y = 1512f;
-        } else {
-            IntByReference x = new IntByReference();
-            IntByReference y = new IntByReference();
-            vrsystemFunctions.GetRecommendedRenderTargetSize.apply(x, y);
-            store.x = x.getValue();
-            store.y = y.getValue();
-        }
-    }
-    /*
-    @Override
-    public float getFOV(int dir) {
-        float val = 0f;
-        if( vrsystemFunctions != null ) {      
-            val = vrsystemFunctions.GetFloatTrackedDeviceProperty.apply(JOpenVRLibrary.k_unTrackedDeviceIndex_Hmd, dir, hmdErrorStore);
-        }
-        // verification of number
-        if( val == 0f ) {
-            return 55f;
-        } else if( val <= 10f ) {
-            // most likely a radian number
-            return val * 57.2957795f;
-        }
-        return val;
-    }
-    */
-    
-    @Override
-    public float getInterpupillaryDistance() {
-        if( vrsystemFunctions == null ) return 0.065f;
-        return vrsystemFunctions.GetFloatTrackedDeviceProperty.apply(JOpenVRLibrary.k_unTrackedDeviceIndex_Hmd, JOpenVRLibrary.ETrackedDeviceProperty.ETrackedDeviceProperty_Prop_UserIpdMeters_Float, hmdErrorStore);
-    }
-    
-    @Override
-    public Quaternion getOrientation() {
-        VRUtil.convertMatrix4toQuat(hmdPose, rotStore);
-        return rotStore;
-    }
-
-    @Override
-    public Vector3f getPosition() {
-        // the hmdPose comes in rotated funny, fix that here
-        hmdPose.toTranslationVector(posStore);
-        posStore.x = -posStore.x;
-        posStore.z = -posStore.z;
-        return posStore;
-    }
-    
-    @Override
-    public void getPositionAndOrientation(Vector3f storePos, Quaternion storeRot) {
-        hmdPose.toTranslationVector(storePos);
-        storePos.x = -storePos.x;
-        storePos.z = -storePos.z;
-        storeRot.set(getOrientation());
-    }    
-    
-    @Override
-    public void updatePose(){
-        if(vrsystemFunctions == null) return;
-        if(compositorFunctions != null) {
-           compositorFunctions.WaitGetPoses.apply(hmdTrackedDevicePoseReference, JOpenVRLibrary.k_unMaxTrackedDeviceCount, null, 0);
-        } else {
-            // wait
-            if( latencyWaitTime > 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");
-                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();
-            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();
-            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();
-            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 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 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.openvr;
+
+import com.jme3.app.VREnvironment;
+import com.jme3.input.vr.HmdType;
+import com.jme3.input.vr.VRAPI;
+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.system.jopenvr.VR_IVRTrackedCamera_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 <a href="https://github.com/ValveSoftware/openvr/wiki/API-Documentation">OpenVR</a> system. 
+ * @author reden - phr00t - https://github.com/phr00t
+ * @author Julien Seinturier - COMEX SA - <a href="http://www.seinturier.fr">http://www.seinturier.fr</a>
+ */
+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 VR_IVRTrackedCamera_FnTable cameraFunctions;
+    
+    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;
+    
+    /**
+     * Convert specific OpenVR {@link com.jme3.system.jopenvr.HmdMatrix34_t HmdMatrix34_t} into JME {@link Matrix4f Matrix4f}
+     * @param hmdMatrix the input matrix
+     * @param mat the converted matrix
+     * @return the converted matrix
+     */
+    public static Matrix4f convertSteamVRMatrix3ToMatrix4f(com.jme3.system.jopenvr.HmdMatrix34_t hmdMatrix, Matrix4f mat){
+        mat.set(hmdMatrix.m[0], hmdMatrix.m[1], hmdMatrix.m[2], hmdMatrix.m[3], 
+                hmdMatrix.m[4], hmdMatrix.m[5], hmdMatrix.m[6], hmdMatrix.m[7], 
+                hmdMatrix.m[8], hmdMatrix.m[9], hmdMatrix.m[10], hmdMatrix.m[11], 
+                0f, 0f, 0f, 1f);
+        return mat;
+    }
+    
+    /**
+     * Convert specific OpenVR {@link com.jme3.system.jopenvr.HmdMatrix44_t HmdMatrix34_t} into JME {@link Matrix4f Matrix4f}
+     * @param hmdMatrix the input matrix
+     * @param mat the converted matrix
+     * @return the converted matrix
+     */
+    public static Matrix4f convertSteamVRMatrix4ToMatrix4f(com.jme3.system.jopenvr.HmdMatrix44_t hmdMatrix, Matrix4f mat){
+        mat.set(hmdMatrix.m[0], hmdMatrix.m[1], hmdMatrix.m[2], hmdMatrix.m[3], 
+                hmdMatrix.m[4], hmdMatrix.m[5], hmdMatrix.m[6], hmdMatrix.m[7],
+                hmdMatrix.m[8], hmdMatrix.m[9], hmdMatrix.m[10], hmdMatrix.m[11], 
+                hmdMatrix.m[12], hmdMatrix.m[13], hmdMatrix.m[14], hmdMatrix.m[15]);
+        return mat;
+    }
+    
+    
+    /**
+     * Create a new <a href="https://github.com/ValveSoftware/openvr/wiki/API-Documentation">OpenVR</a> 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;
+    }
+    
+    public VR_IVRTrackedCamera_FnTable getTrackedCamera(){
+      return cameraFunctions;
+    }
+    
+    @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;
+        
+        // Init the native linking to the OpenVR library.
+        try{
+          JOpenVRLibrary.init();
+        } catch(Throwable t){
+          logger.log(Level.SEVERE, "Cannot link to OpenVR system library: "+t.getMessage(), t);
+          return false;
+        }
+        
+        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<poseMatrices.length;i++) poseMatrices[i] = new Matrix4f();
+
+            timePerFrame = 1.0 / hmdDisplayFrequency.get(0);
+            
+            // disable all this stuff which kills performance
+            hmdTrackedDevicePoseReference.setAutoRead(false);
+            hmdTrackedDevicePoseReference.setAutoWrite(false);
+            hmdTrackedDevicePoseReference.setAutoSynch(false);
+            for(int i=0;i<JOpenVRLibrary.k_unMaxTrackedDeviceCount;i++) {
+                hmdTrackedDevicePoses[i].setAutoRead(false);
+                hmdTrackedDevicePoses[i].setAutoWrite(false);
+                hmdTrackedDevicePoses[i].setAutoSynch(false);
+            }
+            
+            // init controllers for the first time
+            VRinput = new OpenVRInput(environment);
+            VRinput.init();
+            VRinput.updateConnectedControllers();
+            
+            // init bounds & chaperone info
+            OpenVRBounds bounds = new OpenVRBounds();
+            bounds.init(this);
+            environment.setVRBounds(bounds);
+            
+            logger.config("Initializing OpenVR system [SUCCESS]");
+            initSuccess = true;
+            return true;
+        }
+    }
+    
+    @Override
+    public boolean initVRCompositor(boolean allowed) {
+        hmdErrorStore.setValue(0); // clear the error store
+        if( allowed && vrsystemFunctions != null ) {
+        	
+        	IntByReference intptr = JOpenVRLibrary.VR_GetGenericInterface(JOpenVRLibrary.IVRCompositor_Version, hmdErrorStore);
+        	if (intptr != null){
+        	
+        		if (intptr.getPointer() != null){
+            		compositorFunctions = new VR_IVRCompositor_FnTable(intptr.getPointer());
+                    if(compositorFunctions != null && hmdErrorStore.getValue() == 0 ){          
+                        compositorFunctions.setAutoSynch(false);
+                        compositorFunctions.read();
+                        if( environment.isSeatedExperience() ) {                    
+                            compositorFunctions.SetTrackingSpace.apply(JOpenVRLibrary.ETrackingUniverseOrigin.ETrackingUniverseOrigin_TrackingUniverseSeated);
+                        } else {
+                            compositorFunctions.SetTrackingSpace.apply(JOpenVRLibrary.ETrackingUniverseOrigin.ETrackingUniverseOrigin_TrackingUniverseStanding);                
+                        }
+                        logger.config("OpenVR Compositor initialized");
+                    } else {
+                        logger.severe("OpenVR Compositor error: " + hmdErrorStore.getValue());
+                        compositorFunctions = null;
+                    }
+        		} else {
+        			logger.log(Level.SEVERE, "Cannot get valid pointer for generic interface \""+JOpenVRLibrary.IVRCompositor_Version+"\", "+OpenVRUtil.getEVRInitErrorString(hmdErrorStore.getValue())+" ("+hmdErrorStore.getValue()+")");
+        			compositorFunctions = null;
+        		}
+
+        	} else {
+        		logger.log(Level.SEVERE, "Cannot get generic interface for \""+JOpenVRLibrary.IVRCompositor_Version+"\", "+OpenVRUtil.getEVRInitErrorString(hmdErrorStore.getValue())+" ("+hmdErrorStore.getValue()+")");
+        		compositorFunctions = null;
+        	}
+        	
+            
+        }
+        if( compositorFunctions == null ) {
+            logger.severe("Skipping VR Compositor...");
+            if( vrsystemFunctions != null ) {
+                vsyncToPhotons = vrsystemFunctions.GetFloatTrackedDeviceProperty.apply(JOpenVRLibrary.k_unTrackedDeviceIndex_Hmd, JOpenVRLibrary.ETrackedDeviceProperty.ETrackedDeviceProperty_Prop_SecondsFromVsyncToPhotons_Float, hmdErrorStore);
+            } else {
+                vsyncToPhotons = 0f;
+            }
+        }
+        return compositorFunctions != null;
+    }
+
+    /**
+     * Initialize the headset camera.
+     * @param allowed <code>true</code> is the use of the headset camera is allowed and <code>false</code> otherwise.
+     */
+    public void initCamera(boolean allowed) {
+      hmdErrorStore.setValue(0); // clear the error store
+      
+      if( allowed && vrsystemFunctions != null ) {
+        IntByReference intptr = JOpenVRLibrary.VR_GetGenericInterface(JOpenVRLibrary.IVRTrackedCamera_Version, hmdErrorStore);
+    	  if (intptr != null){
+    	    cameraFunctions = new VR_IVRTrackedCamera_FnTable(intptr.getPointer());
+    	    if(cameraFunctions != null && hmdErrorStore.getValue() == 0 ){
+    	      cameraFunctions.setAutoSynch(false);
+    	        cameraFunctions.read();
+    	        logger.config("OpenVR Camera initialized");
+    	    }
+    	  }
+       }
+    }
+    
+    @Override
+    public void destroy() {
+        JOpenVRLibrary.VR_ShutdownInternal();
+    }
+
+    @Override
+    public boolean isInitialized() {
+        return initSuccess;
+    }
+
+    @Override
+    public void reset() {
+        if( vrsystemFunctions == null ) return;
+        vrsystemFunctions.ResetSeatedZeroPose.apply();
+        hmdSeatToStand = null;
+    }
+
+    @Override
+    public void getRenderSize(Vector2f store) {
+        if( vrsystemFunctions == null ) {
+            // 1344x1512
+            store.x = 1344f;
+            store.y = 1512f;
+        } else {
+            IntByReference x = new IntByReference();
+            IntByReference y = new IntByReference();
+            vrsystemFunctions.GetRecommendedRenderTargetSize.apply(x, y);
+            store.x = x.getValue();
+            store.y = y.getValue();
+        }
+    }
+    /*
+    @Override
+    public float getFOV(int dir) {
+        float val = 0f;
+        if( vrsystemFunctions != null ) {      
+            val = vrsystemFunctions.GetFloatTrackedDeviceProperty.apply(JOpenVRLibrary.k_unTrackedDeviceIndex_Hmd, dir, hmdErrorStore);
+        }
+        // verification of number
+        if( val == 0f ) {
+            return 55f;
+        } else if( val <= 10f ) {
+            // most likely a radian number
+            return val * 57.2957795f;
+        }
+        return val;
+    }
+    */
+    
+    @Override
+    public float getInterpupillaryDistance() {
+        if( vrsystemFunctions == null ) return 0.065f;
+        return vrsystemFunctions.GetFloatTrackedDeviceProperty.apply(JOpenVRLibrary.k_unTrackedDeviceIndex_Hmd, JOpenVRLibrary.ETrackedDeviceProperty.ETrackedDeviceProperty_Prop_UserIpdMeters_Float, hmdErrorStore);
+    }
+    
+    @Override
+    public Quaternion getOrientation() {
+        VRUtil.convertMatrix4toQuat(hmdPose, rotStore);
+        return rotStore;
+    }
+
+    @Override
+    public Vector3f getPosition() {
+        // the hmdPose comes in rotated funny, fix that here
+        hmdPose.toTranslationVector(posStore);
+        posStore.x = -posStore.x;
+        posStore.z = -posStore.z;
+        return posStore;
+    }
+    
+    @Override
+    public void getPositionAndOrientation(Vector3f storePos, Quaternion storeRot) {
+        hmdPose.toTranslationVector(storePos);
+        storePos.x = -storePos.x;
+        storePos.z = -storePos.z;
+        storeRot.set(getOrientation());
+    }    
+    
+    @Override
+    public void updatePose(){
+        if(vrsystemFunctions == null) return;
+        if(compositorFunctions != null) {
+           compositorFunctions.WaitGetPoses.apply(hmdTrackedDevicePoseReference, JOpenVRLibrary.k_unMaxTrackedDeviceCount, null, 0);
+        } else {
+            // wait
+            if( latencyWaitTime > 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");
+                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();
+            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();
+            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();
+            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 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("index") ) {
+                    return HmdType.VALVE_INDEX;
+                } 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 convertSteamVRMatrix3ToMatrix4f(mat, hmdPoseRightEye);
+        }
+    }
+  
+}