parent
b9071513e7
commit
41bead60e3
@ -0,0 +1,843 @@ |
|||||||
|
package com.jme3.app; |
||||||
|
|
||||||
|
|
||||||
|
import com.jme3.app.Application; |
||||||
|
import com.jme3.app.state.AbstractAppState; |
||||||
|
import com.jme3.app.state.AppStateManager; |
||||||
|
import com.jme3.input.vr.OSVR; |
||||||
|
import com.jme3.input.vr.OpenVR; |
||||||
|
import com.jme3.input.vr.VRAPI; |
||||||
|
import com.jme3.input.vr.VRInputAPI; |
||||||
|
import com.jme3.math.ColorRGBA; |
||||||
|
import com.jme3.math.Quaternion; |
||||||
|
import com.jme3.math.Vector3f; |
||||||
|
import com.jme3.post.PreNormalCaching; |
||||||
|
import com.jme3.renderer.Camera; |
||||||
|
import com.jme3.renderer.RenderManager; |
||||||
|
import com.jme3.renderer.ViewPort; |
||||||
|
import com.jme3.scene.Spatial; |
||||||
|
import com.jme3.system.AppSettings; |
||||||
|
import com.jme3.system.jopenvr.JOpenVRLibrary; |
||||||
|
|
||||||
|
import java.awt.GraphicsDevice; |
||||||
|
import java.awt.GraphicsEnvironment; |
||||||
|
|
||||||
|
import java.io.BufferedReader; |
||||||
|
import java.io.File; |
||||||
|
import java.io.FileReader; |
||||||
|
import java.util.Iterator; |
||||||
|
import java.util.Locale; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
|
||||||
|
import jmevr.util.VRGuiManager; |
||||||
|
import jmevr.util.VRMouseManager; |
||||||
|
import jmevr.util.VRViewManager; |
||||||
|
import jmevr.util.VRGuiManager.POSITIONING_MODE; |
||||||
|
|
||||||
|
/** |
||||||
|
* A JMonkey app state dedicated to Virtual Reality. |
||||||
|
* An application that want to use VR devices (HTC vive, ...) has to use this app state.<br> |
||||||
|
* As this app state and the main {@link Application application} have to share {@link AppSettings application settings}, |
||||||
|
* the common way to use this app state is:<br> |
||||||
|
* <ul> |
||||||
|
* <li>To create {@link AppSettings application settings} and set the VR related settings (see {@link VRConstants}). |
||||||
|
* <li>To instantiate this app state with the created settings. |
||||||
|
* <li>To instantiate the main {@link Application application} and to attach it to the created settings (with {@link Application#setSettings(AppSettings) setSettings(AppSettings)}). |
||||||
|
* <li>To start the main {@link Application application}. |
||||||
|
* </ul> |
||||||
|
* Attaching an instance of this app state to an already started application may cause crashes. |
||||||
|
* @author Julien Seinturier - JOrigin project - <a href="http://www.jorigin.org">http:/www.jorigin.org</a> |
||||||
|
*/ |
||||||
|
public class VRAppState extends AbstractAppState { |
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(VRAppState.class.getName()); |
||||||
|
|
||||||
|
/** |
||||||
|
* The underlying system VR API. By default set to {@link VRConstants#SETTING_VRAPI_OPENVR_VALUE}. |
||||||
|
*/ |
||||||
|
public int vrBinding = VRConstants.SETTING_VRAPI_OPENVR_VALUE; |
||||||
|
|
||||||
|
/** |
||||||
|
* Is the application has not to start within VR mode (default is <code>false</code>). |
||||||
|
*/ |
||||||
|
public boolean DISABLE_VR = false; |
||||||
|
|
||||||
|
private VRAPI VRhardware = null; |
||||||
|
private VRGuiManager guiManager = null; |
||||||
|
private VRMouseManager mouseManager = null; |
||||||
|
private VRViewManager viewmanager = null; |
||||||
|
|
||||||
|
private String OS; |
||||||
|
|
||||||
|
private Camera dummyCam; |
||||||
|
|
||||||
|
private Spatial observer = null; |
||||||
|
|
||||||
|
private boolean VRSupportedOS; |
||||||
|
private boolean forceVR = false;; |
||||||
|
private boolean disableSwapBuffers = true; |
||||||
|
private boolean disableVR = false; |
||||||
|
private boolean seated; |
||||||
|
private boolean nogui; |
||||||
|
private boolean instanceVR = false; |
||||||
|
|
||||||
|
private float defaultFOV = 108f; |
||||||
|
private float defaultAspect = 1f; |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private float fFar = 1000f; |
||||||
|
private float fNear = 0.1f; |
||||||
|
private int xWin = 1920; |
||||||
|
private int yWin = 1080; |
||||||
|
|
||||||
|
private float resMult = 1f; |
||||||
|
|
||||||
|
private boolean useCompositor = true; |
||||||
|
private boolean compositorOS; |
||||||
|
|
||||||
|
/* |
||||||
|
where is the headset pointing, after all rotations are combined? |
||||||
|
depends on observer rotation, if any |
||||||
|
*/ |
||||||
|
private Quaternion tempq = new Quaternion(); |
||||||
|
|
||||||
|
private Application application = null; |
||||||
|
private AppStateManager stateManager = null; |
||||||
|
private AppSettings settings = null; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Create a new default VR app state. |
||||||
|
*/ |
||||||
|
public VRAppState() { |
||||||
|
super(); |
||||||
|
|
||||||
|
dummyCam = new Camera(); |
||||||
|
|
||||||
|
// Create the GUI manager.
|
||||||
|
guiManager = new VRGuiManager(); |
||||||
|
|
||||||
|
// Create a new view manager.
|
||||||
|
viewmanager = new VRViewManager(); |
||||||
|
|
||||||
|
// Create a new mouse manager.
|
||||||
|
mouseManager = new VRMouseManager(); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Create a new VR app state with given settings. |
||||||
|
* @param settings the settings to use. |
||||||
|
*/ |
||||||
|
public VRAppState(AppSettings settings){ |
||||||
|
this(); |
||||||
|
this.settings = settings; |
||||||
|
processSettings(settings); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Simple update of the app state, this method should contains any spatial updates. |
||||||
|
* This method is called by the {@link #update(float) update()} method and should not be called manually. |
||||||
|
* @param tpf the application time. |
||||||
|
*/ |
||||||
|
public void simpleUpdate(float tpf) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Rendering callback of the app state. This method is called by the {@link #update(float) update()} method and should not be called manually. |
||||||
|
* @param renderManager the {@link RenderManager render manager}. |
||||||
|
*/ |
||||||
|
public void simpleRender(RenderManager renderManager) { |
||||||
|
PreNormalCaching.resetCache(isInVR()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the frustrum values for the application. |
||||||
|
* @param near the frustrum near value. |
||||||
|
* @param far the frustrum far value. |
||||||
|
*/ |
||||||
|
public void setFrustrumNearFar(float near, float far) { |
||||||
|
fNear = near; |
||||||
|
fFar = far; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the mirror window size in pixel. |
||||||
|
* @param width the width of the mirror window in pixel. |
||||||
|
* @param height the height of the mirror window in pixel. |
||||||
|
*/ |
||||||
|
public void setMirrorWindowSize(int width, int height) { |
||||||
|
xWin = width; |
||||||
|
yWin = height; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the resolution multiplier. |
||||||
|
* @param val the resolution multiplier. |
||||||
|
*/ |
||||||
|
public void setResolutionMultiplier(float val) { |
||||||
|
resMult = val; |
||||||
|
if( viewmanager != null ){ |
||||||
|
viewmanager.setResolutionMultiplier(resMult); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 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; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 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; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the {@link Camera camera} attached to this application state. |
||||||
|
* 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 to this application state. |
||||||
|
*/ |
||||||
|
public Camera getCamera() { |
||||||
|
if( isInVR() && viewmanager != null && viewmanager.getLeftCamera() != null ) { |
||||||
|
return dummyCam; |
||||||
|
} |
||||||
|
|
||||||
|
return application.getCamera(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 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( VRhardware instanceof OpenVR ) { |
||||||
|
if( VRhardware.getCompositor() == null ) return; |
||||||
|
if( seated ) { |
||||||
|
((OpenVR)VRhardware).getCompositor().SetTrackingSpace.apply(JOpenVRLibrary.ETrackingUniverseOrigin.ETrackingUniverseOrigin_TrackingUniverseSeated); |
||||||
|
} else { |
||||||
|
((OpenVR)VRhardware).getCompositor().SetTrackingSpace.apply(JOpenVRLibrary.ETrackingUniverseOrigin.ETrackingUniverseOrigin_TrackingUniverseStanding); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 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; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Reset headset pose if seating experience. |
||||||
|
*/ |
||||||
|
public void resetSeatedPose(){ |
||||||
|
if( VRSupportedOS == false || isSeatedExperience() == false ) return; |
||||||
|
VRhardware.reset(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 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 isInstanceVRRendering() { |
||||||
|
return instanceVR && isInVR(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 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 DISABLE_VR == false && (forceVR || VRSupportedOS && VRhardware != null && VRhardware.isInitialized()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 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; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Move filters from the main scene into the eye's. |
||||||
|
* This removes filters from the main scene. |
||||||
|
*/ |
||||||
|
public void moveScreenProcessingToVR() { |
||||||
|
if( isInVR() ) { |
||||||
|
viewmanager.moveScreenProcessingToEyes(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 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; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 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 ) { |
||||||
|
return getCamera(); |
||||||
|
} |
||||||
|
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 the application {@link #getCamera() camera}. |
||||||
|
* @param observer the scene observer. |
||||||
|
*/ |
||||||
|
public void setObserver(Spatial observer) { |
||||||
|
this.observer = observer; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the observer final rotation within the scene. |
||||||
|
* @return the observer final rotation within the scene. |
||||||
|
* @see #getFinalObserverPosition() |
||||||
|
*/ |
||||||
|
public Quaternion getFinalObserverRotation() { |
||||||
|
if( viewmanager == null ) { |
||||||
|
if( observer == null ) { |
||||||
|
return getCamera().getRotation(); |
||||||
|
} else return observer.getWorldRotation(); |
||||||
|
} |
||||||
|
if( observer == null ) { |
||||||
|
tempq.set(dummyCam.getRotation()); |
||||||
|
} else { |
||||||
|
tempq.set(observer.getWorldRotation()); |
||||||
|
} |
||||||
|
return tempq.multLocal(VRhardware.getOrientation()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the observer final position within the scene. |
||||||
|
* @return the observer position. |
||||||
|
* @see #getFinalObserverRotation() |
||||||
|
*/ |
||||||
|
public Vector3f getFinalObserverPosition() { |
||||||
|
if( viewmanager == null ) { |
||||||
|
if( observer == null ) { |
||||||
|
return getCamera().getLocation(); |
||||||
|
} else return observer.getWorldTranslation(); |
||||||
|
} |
||||||
|
Vector3f pos = VRhardware.getPosition(); |
||||||
|
if( observer == null ) { |
||||||
|
dummyCam.getRotation().mult(pos, pos); |
||||||
|
return pos.addLocal(dummyCam.getLocation()); |
||||||
|
} else { |
||||||
|
observer.getWorldRotation().mult(pos, pos); |
||||||
|
return pos.addLocal(observer.getWorldTranslation()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 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 VR headset left viewport. |
||||||
|
* @return the VR headset left viewport. |
||||||
|
* @see #getRightViewPort() |
||||||
|
*/ |
||||||
|
public ViewPort getLeftViewPort() { |
||||||
|
if( viewmanager == null ) return application.getViewPort(); |
||||||
|
return viewmanager.getLeftViewport(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the VR headset right viewport. |
||||||
|
* @return the VR headset right viewport. |
||||||
|
* @see #getLeftViewPort() |
||||||
|
*/ |
||||||
|
public ViewPort getRightViewPort() { |
||||||
|
if( viewmanager == null ) return application.getViewPort(); |
||||||
|
return viewmanager.getRightViewport(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the background color for both left and right view ports. |
||||||
|
* @param clr the background color. |
||||||
|
*/ |
||||||
|
public void setBackgroundColors(ColorRGBA clr) { |
||||||
|
if( viewmanager == null ) { |
||||||
|
application.getViewPort().setBackgroundColor(clr); |
||||||
|
} else if( viewmanager.getLeftViewport() != null ) { |
||||||
|
viewmanager.getLeftViewport().setBackgroundColor(clr); |
||||||
|
if( viewmanager.getRightViewport() != null ) viewmanager.getRightViewport().setBackgroundColor(clr); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the {@link Application} to which this app state is attached. |
||||||
|
* @return the {@link Application} to which this app state is attached. |
||||||
|
* @see #getStateManager() |
||||||
|
*/ |
||||||
|
public Application getApplication(){ |
||||||
|
return application; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the {@link AppStateManager state manager} to which this app state is attached. |
||||||
|
* @return the {@link AppStateManager state manager} to which this app state is attached. |
||||||
|
* @see #getApplication() |
||||||
|
*/ |
||||||
|
public AppStateManager getStateManager(){ |
||||||
|
return stateManager; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the VR underlying hardware. |
||||||
|
* @return the VR underlying hardware. |
||||||
|
*/ |
||||||
|
public VRAPI getVRHardware() { |
||||||
|
return VRhardware; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the VR dedicated input. |
||||||
|
* @return the VR dedicated input. |
||||||
|
*/ |
||||||
|
public VRInputAPI getVRinput() { |
||||||
|
if( VRhardware == null ){ |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
return VRhardware.getVRinput(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the VR view manager. |
||||||
|
* @return the VR view manager. |
||||||
|
*/ |
||||||
|
public VRViewManager getVRViewManager() { |
||||||
|
return viewmanager; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the GUI manager attached to this application. |
||||||
|
* @return the GUI manager attached to this application. |
||||||
|
*/ |
||||||
|
public VRGuiManager getVRGUIManager(){ |
||||||
|
return guiManager; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the VR mouse manager attached to this application. |
||||||
|
* @return the VR mouse manager attached to this application. |
||||||
|
*/ |
||||||
|
public VRMouseManager getVRMouseManager(){ |
||||||
|
return mouseManager; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the {@link AppSettings settings} attached to this app state. |
||||||
|
* @return the {@link AppSettings settings} attached to this app state. |
||||||
|
* @see #setSettings(AppSettings) |
||||||
|
*/ |
||||||
|
public AppSettings getSettings(){ |
||||||
|
return settings; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the {@link AppSettings settings} attached to this app state. |
||||||
|
* @param settings the {@link AppSettings settings} attached to this app state. |
||||||
|
* @see #getSettings() |
||||||
|
*/ |
||||||
|
public void setSettings(AppSettings settings){ |
||||||
|
this.settings = settings; |
||||||
|
processSettings(settings); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void update(float tpf) { |
||||||
|
|
||||||
|
// update VR pose & cameras
|
||||||
|
if( viewmanager != null ) { |
||||||
|
viewmanager.update(tpf); |
||||||
|
} else if( observer != null ) { |
||||||
|
getCamera().setFrame(observer.getWorldTranslation(), observer.getWorldRotation()); |
||||||
|
} |
||||||
|
|
||||||
|
//FIXME: check if this code is necessary.
|
||||||
|
// Updates scene and gui states.
|
||||||
|
Iterator<Spatial> spatialIter = application.getViewPort().getScenes().iterator(); |
||||||
|
Spatial spatial = null; |
||||||
|
while(spatialIter.hasNext()){ |
||||||
|
spatial = spatialIter.next(); |
||||||
|
spatial.updateLogicalState(tpf); |
||||||
|
spatial.updateGeometricState(); |
||||||
|
} |
||||||
|
|
||||||
|
if( isInVR() == false || guiManager.getPositioningMode() == POSITIONING_MODE.MANUAL ) { |
||||||
|
// only update geometric state here if GUI is in manual mode, or not in VR
|
||||||
|
// it will get updated automatically in the viewmanager update otherwise
|
||||||
|
spatialIter = application.getGuiViewPort().getScenes().iterator(); |
||||||
|
spatial = null; |
||||||
|
while(spatialIter.hasNext()){ |
||||||
|
spatial = spatialIter.next(); |
||||||
|
spatial.updateGeometricState(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
// use the analog control on the first tracked controller to push around the mouse
|
||||||
|
getVRMouseManager().updateAnalogAsMouse(0, null, null, null, tpf); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void postRender() { |
||||||
|
super.postRender(); |
||||||
|
// update compositor?
|
||||||
|
if( viewmanager != null ) { |
||||||
|
viewmanager.sendTextures(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void initialize(AppStateManager stateManager, Application app) { |
||||||
|
super.initialize(stateManager, app); |
||||||
|
|
||||||
|
this.application = app; |
||||||
|
this.stateManager = stateManager; |
||||||
|
|
||||||
|
// disable annoying warnings about GUI stuff being updated, which is normal behavior
|
||||||
|
// for late GUI placement for VR purposes
|
||||||
|
Logger.getLogger("com.jme3").setLevel(Level.SEVERE); |
||||||
|
|
||||||
|
// VR module attch
|
||||||
|
guiManager.attach(this, app); |
||||||
|
viewmanager.attach(this, app); |
||||||
|
mouseManager.attach(this, app); |
||||||
|
|
||||||
|
app.getCamera().setFrustumFar(fFar); |
||||||
|
app.getCamera().setFrustumNear(fNear); |
||||||
|
dummyCam = app.getCamera().clone(); |
||||||
|
|
||||||
|
if( isInVR() ) { |
||||||
|
|
||||||
|
logger.config("VR mode enabled."); |
||||||
|
|
||||||
|
if( VRhardware != null ) { |
||||||
|
VRhardware.initVRCompositor(compositorAllowed()); |
||||||
|
} else { |
||||||
|
logger.warning("No VR system found."); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
viewmanager.setResolutionMultiplier(resMult); |
||||||
|
//inputManager.addMapping(RESET_HMD, new KeyTrigger(KeyInput.KEY_F9));
|
||||||
|
//setLostFocusBehavior(LostFocusBehavior.Disabled);
|
||||||
|
} else { |
||||||
|
logger.config("VR mode disabled."); |
||||||
|
//viewPort.attachScene(rootNode);
|
||||||
|
//guiViewPort.attachScene(guiNode);
|
||||||
|
} |
||||||
|
|
||||||
|
if( viewmanager != null ) { |
||||||
|
viewmanager.initialize(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void stateAttached(AppStateManager stateManager) { |
||||||
|
super.stateAttached(stateManager); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
|
||||||
|
if (settings == null) { |
||||||
|
settings = new AppSettings(true); |
||||||
|
logger.config("Using default settings."); |
||||||
|
} else { |
||||||
|
logger.config("Using given settings."); |
||||||
|
} |
||||||
|
|
||||||
|
// we are going to use OpenVR now, not the Oculus Rift
|
||||||
|
// OpenVR does support the Rift
|
||||||
|
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 && disableVR == false ) { |
||||||
|
if( vrBinding == VRConstants.SETTING_VRAPI_OSVR_VALUE ) { |
||||||
|
VRhardware = new OSVR(this); |
||||||
|
logger.config("Creating OSVR wrapper [SUCCESS]"); |
||||||
|
} else if( vrBinding == VRConstants.SETTING_VRAPI_OPENVR_VALUE ) { |
||||||
|
VRhardware = new OpenVR(this); |
||||||
|
logger.config("Creating OpenVR wrapper [SUCCESS]"); |
||||||
|
} else { |
||||||
|
logger.config("Cannot create VR binding: "+vrBinding+" [FAILED]"); |
||||||
|
} |
||||||
|
|
||||||
|
if( VRhardware.initialize() ) { |
||||||
|
logger.config("VR native wrapper initialized [SUCCESS]"); |
||||||
|
} else { |
||||||
|
logger.warning("VR native wrapper initialized [FAILED]"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
GraphicsDevice defDev = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); |
||||||
|
|
||||||
|
if( isInVR() && !compositorAllowed() ) { |
||||||
|
// "easy extended" mode
|
||||||
|
// setup experimental JFrame on external device
|
||||||
|
// first, find the VR device
|
||||||
|
GraphicsDevice VRdev = null; |
||||||
|
GraphicsDevice[] devs = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices(); |
||||||
|
// pick the display that isn't the default one
|
||||||
|
for(GraphicsDevice gd : devs) { |
||||||
|
if( gd != defDev ) { |
||||||
|
VRdev = gd; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// did we get the VR device?
|
||||||
|
if( VRdev != null ) { |
||||||
|
// set properties for VR acceleration
|
||||||
|
try { |
||||||
|
java.awt.DisplayMode useDM = null; |
||||||
|
int max = 0; |
||||||
|
for(java.awt.DisplayMode dm : VRdev.getDisplayModes()) { |
||||||
|
int check = dm.getHeight() + dm.getWidth() + dm.getRefreshRate() + dm.getBitDepth(); |
||||||
|
if( check > max ) { |
||||||
|
max = check; |
||||||
|
useDM = dm; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// create a window for the VR device
|
||||||
|
settings.setWidth(useDM.getWidth()); |
||||||
|
settings.setHeight(useDM.getHeight()); |
||||||
|
settings.setBitsPerPixel(useDM.getBitDepth()); |
||||||
|
settings.setFrequency(useDM.getRefreshRate()); |
||||||
|
settings.setSwapBuffers(true); |
||||||
|
settings.setVSync(true); // allow vsync on this display
|
||||||
|
stateManager.getApplication().setSettings(settings); |
||||||
|
logger.config("Updated underlying application settings."); |
||||||
|
|
||||||
|
//VRdev.setFullScreenWindow(VRwindow);
|
||||||
|
// make sure we are in the right display mode
|
||||||
|
if( VRdev.getDisplayMode().equals(useDM) == false ) { |
||||||
|
VRdev.setDisplayMode(useDM); |
||||||
|
} |
||||||
|
|
||||||
|
return; |
||||||
|
} catch(Exception e) { |
||||||
|
logger.log(Level.SEVERE, e.getMessage(), e); |
||||||
|
} |
||||||
|
} else { |
||||||
|
logger.config("Cannot access to external screen."); |
||||||
|
} |
||||||
|
} else { |
||||||
|
if (!isInVR()){ |
||||||
|
logger.config("Cannot switch to VR mode (VR disabled by user)."); |
||||||
|
} else if (!compositorAllowed()){ |
||||||
|
logger.warning("Cannot switch to VR mode (VR not supported)."); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if( !isInVR() ) { |
||||||
|
|
||||||
|
//FIXME: Handling GLFW workaround on MacOS
|
||||||
|
boolean macOs = false; |
||||||
|
if (macOs) { |
||||||
|
// GLFW workaround on macs
|
||||||
|
settings.setFrequency(defDev.getDisplayMode().getRefreshRate()); |
||||||
|
settings.setDepthBits(24); |
||||||
|
settings.setVSync(true); |
||||||
|
// try and read resolution from file in local dir
|
||||||
|
File resfile = new File("resolution.txt"); |
||||||
|
if( resfile.exists() ) { |
||||||
|
try { |
||||||
|
BufferedReader br = new BufferedReader(new FileReader(resfile)); |
||||||
|
settings.setWidth(Integer.parseInt(br.readLine())); |
||||||
|
settings.setHeight(Integer.parseInt(br.readLine())); |
||||||
|
try { |
||||||
|
settings.setFullscreen(br.readLine().toLowerCase(Locale.ENGLISH).contains("full")); |
||||||
|
} catch(Exception e) { |
||||||
|
settings.setFullscreen(false); |
||||||
|
} |
||||||
|
br.close(); |
||||||
|
} catch(Exception e) { |
||||||
|
settings.setWidth(1280); |
||||||
|
settings.setHeight(720); |
||||||
|
} |
||||||
|
} else { |
||||||
|
settings.setWidth(1280); |
||||||
|
settings.setHeight(720); |
||||||
|
settings.setFullscreen(false); |
||||||
|
} |
||||||
|
settings.setResizable(false); |
||||||
|
} |
||||||
|
settings.setSwapBuffers(true); |
||||||
|
} else { |
||||||
|
// use basic mirroring window, skip settings window
|
||||||
|
settings.setSamples(1); |
||||||
|
settings.setWidth(xWin); |
||||||
|
settings.setHeight(yWin); |
||||||
|
settings.setBitsPerPixel(32); |
||||||
|
settings.setFrameRate(0); |
||||||
|
settings.setFrequency(VRhardware.getDisplayFrequency()); |
||||||
|
settings.setFullscreen(false); |
||||||
|
settings.setVSync(false); // stop vsyncing on primary monitor!
|
||||||
|
settings.setSwapBuffers(disableSwapBuffers); |
||||||
|
} |
||||||
|
|
||||||
|
// Updating application settings
|
||||||
|
stateManager.getApplication().setSettings(settings); |
||||||
|
logger.config("Updated underlying application settings."); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void cleanup() { |
||||||
|
if( VRhardware != null ) { |
||||||
|
VRhardware.destroy(); |
||||||
|
VRhardware = null; |
||||||
|
} |
||||||
|
disableVR = true; |
||||||
|
|
||||||
|
this.application = null; |
||||||
|
this.stateManager = null; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void stateDetached(AppStateManager stateManager) { |
||||||
|
super.stateDetached(stateManager); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Process the attached settings and apply changes to this app state. |
||||||
|
* @param settings the app settings to process. |
||||||
|
*/ |
||||||
|
protected void processSettings(AppSettings settings){ |
||||||
|
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_VR_FORCE) != null){ |
||||||
|
forceVR = settings.getBoolean(VRConstants.SETTING_VR_FORCE); |
||||||
|
} |
||||||
|
|
||||||
|
if (settings.get(VRConstants.SETTING_FLIP_EYES) != null){ |
||||||
|
if( VRhardware != null ){ |
||||||
|
VRhardware._setFlipEyes(settings.getBoolean(VRConstants.SETTING_FLIP_EYES)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (settings.get(VRConstants.SETTING_GUI_OVERDRAW) != null){ |
||||||
|
guiManager._enableGuiOverdraw(settings.getBoolean(VRConstants.SETTING_GUI_OVERDRAW)); |
||||||
|
} |
||||||
|
|
||||||
|
if (settings.get(VRConstants.SETTING_GUI_CURVED_SURFACE) != null){ |
||||||
|
guiManager._enableCurvedSuface(settings.getBoolean(VRConstants.SETTING_GUI_CURVED_SURFACE)); |
||||||
|
} |
||||||
|
|
||||||
|
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_DISABLE_VR) != null){ |
||||||
|
DISABLE_VR = settings.getBoolean(VRConstants.SETTING_DISABLE_VR); |
||||||
|
} |
||||||
|
|
||||||
|
if (settings.get(VRConstants.SETTING_SEATED_EXPERIENCE) != null){ |
||||||
|
seated = settings.getBoolean(VRConstants.SETTING_SEATED_EXPERIENCE); |
||||||
|
} |
||||||
|
|
||||||
|
if (settings.get(VRConstants.SETTING_NO_GUI) != null){ |
||||||
|
nogui = settings.getBoolean(VRConstants.SETTING_NO_GUI); |
||||||
|
} |
||||||
|
|
||||||
|
if (settings.get(VRConstants.SETTING_INSTANCE_RENDERING) != null){ |
||||||
|
instanceVR = 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_VRAPI) != null){ |
||||||
|
vrBinding = settings.getInteger(VRConstants.SETTING_VRAPI); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,147 @@ |
|||||||
|
package com.jme3.app; |
||||||
|
|
||||||
|
import java.util.HashMap; |
||||||
|
|
||||||
|
import com.jme3.system.AppSettings; |
||||||
|
|
||||||
|
/** |
||||||
|
* Some constants dedicated to the VR module. |
||||||
|
* @author Julien Seinturier - JOrigin project - <a href="http://www.jorigin.org">http:/www.jorigin.org</a> |
||||||
|
* @since 3.1.0 |
||||||
|
*/ |
||||||
|
public class VRConstants { |
||||||
|
|
||||||
|
/** |
||||||
|
* An AppSettings parameter that set if the VR compositor has to be used. |
||||||
|
* <p> |
||||||
|
* <b>Type: </b><code>boolean</code><br> |
||||||
|
* <b>Usage: </b><code>{@link AppSettings appSettings}.{@link HashMap#put(Object, Object) put}(VRConstants.SETTING_USE_COMPOSITOR, value)</code> |
||||||
|
*/ |
||||||
|
public static final String SETTING_USE_COMPOSITOR = "VRUseCompositor"; |
||||||
|
|
||||||
|
/** |
||||||
|
* An AppSettings parameter that set if the rendering has to use two eyes, |
||||||
|
* regardless of VR API detection (turning this setting on without a VR system should lead to errors). |
||||||
|
* <p> |
||||||
|
* <b>Type: </b><code>boolean</code><br> |
||||||
|
* <b>Usage: </b><code>{@link AppSettings appSettings}.{@link HashMap#put(Object, Object) put}(VRConstants.SETTING_VR_FORCE, value)</code> |
||||||
|
|
||||||
|
*/ |
||||||
|
public static final String SETTING_VR_FORCE = "VRForce"; |
||||||
|
|
||||||
|
/** |
||||||
|
* An AppSettings parameter that set to invert the eyes of the HMD. |
||||||
|
* <b>Type: </b><code>boolean</code><br> |
||||||
|
* <b>Usage: </b><code>{@link AppSettings appSettings}.{@link HashMap#put(Object, Object) put}(VRConstants.SETTING_FLIP_EYES, value)</code> |
||||||
|
*/ |
||||||
|
public static final String SETTING_FLIP_EYES = "VRFlipEyes"; |
||||||
|
|
||||||
|
/** |
||||||
|
* An AppSettings parameter that set if the GUI has to be displayed even if it is behind objects. |
||||||
|
* <b>Type: </b><code>boolean</code><br> |
||||||
|
* <b>Usage: </b><code>{@link AppSettings appSettings}.{@link HashMap#put(Object, Object) put}(VRConstants.SETTING_GUI_OVERDRAW, value)</code> |
||||||
|
* |
||||||
|
*/ |
||||||
|
public static final String SETTING_GUI_OVERDRAW = "VRGUIOverdraw"; |
||||||
|
|
||||||
|
/** |
||||||
|
* An AppSettings parameter that set if the GUI surface has to be curved. |
||||||
|
* <b>Type: </b><code>boolean</code><br> |
||||||
|
* <b>Usage: </b><code>{@link AppSettings appSettings}.{@link HashMap#put(Object, Object) put}(VRConstants.SETTING_GUI_CURVED_SURFACE, value)</code> |
||||||
|
*/ |
||||||
|
public static final String SETTING_GUI_CURVED_SURFACE = "VRGUICurvedSurface"; |
||||||
|
|
||||||
|
/** |
||||||
|
* An AppSettings parameter that set if a mirror rendering has to be displayed on the screen. |
||||||
|
* Runs faster when set to <code>false</code>. |
||||||
|
* <b>Type: </b><code>boolean</code><br> |
||||||
|
* <b>Usage: </b><code>{@link AppSettings appSettings}.{@link HashMap#put(Object, Object) put}(VRConstants.SETTING_ENABLE_MIRROR_WINDOW, value)</code> |
||||||
|
*/ |
||||||
|
public static final String SETTING_ENABLE_MIRROR_WINDOW = "VREnableMirrorWindow"; |
||||||
|
|
||||||
|
/** |
||||||
|
* An AppSettings parameter that set if the VR rendering has to be disabled, |
||||||
|
* regardless VR API and devices are presents. |
||||||
|
* <b>Type: </b><code>boolean</code><br> |
||||||
|
* <b>Usage: </b><code>{@link AppSettings appSettings}.{@link HashMap#put(Object, Object) put}(VRConstants.SETTING_DISABLE_VR, value)</code> |
||||||
|
*/ |
||||||
|
public static final String SETTING_DISABLE_VR = "VRDisable"; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* An AppSettings parameter that set if the VR user is seated. |
||||||
|
* <b>Type: </b><code>boolean</code><br> |
||||||
|
* <b>Usage: </b><code>{@link AppSettings appSettings}.{@link HashMap#put(Object, Object) put}(VRConstants.SETTING_SEATED_EXPERIENCE, value)</code> |
||||||
|
*/ |
||||||
|
public static final String SETTING_SEATED_EXPERIENCE = "VRSeatedExperience"; |
||||||
|
|
||||||
|
/** |
||||||
|
* An AppSettings parameter that set if the GUI has to be ignored. |
||||||
|
* <b>Type: </b><code>boolean</code><br> |
||||||
|
* <b>Usage: </b><code>{@link AppSettings appSettings}.{@link HashMap#put(Object, Object) put}(VRConstants.SETTING_NO_GUI, value)</code> |
||||||
|
*/ |
||||||
|
public static final String SETTING_NO_GUI = "VRNoGUI"; |
||||||
|
|
||||||
|
/** |
||||||
|
* An AppSettings parameter that set if instance rendering has to be used. |
||||||
|
* This setting requires some vertex shader changes (see Common/MatDefs/VR/Unshaded.j3md). |
||||||
|
* <b>Type: </b><code>boolean</code><br> |
||||||
|
* <b>Usage: </b><code>{@link AppSettings appSettings}.{@link HashMap#put(Object, Object) put}(VRConstants.SETTING_INSTANCE_RENDERING, value)</code> |
||||||
|
*/ |
||||||
|
public static final String SETTING_INSTANCE_RENDERING = "VRInstanceRendering"; |
||||||
|
|
||||||
|
/** |
||||||
|
* An AppSettings parameter that set if Multi Sample Anti Aliasing has to be enabled. |
||||||
|
* <b>Type: </b><code>boolean</code><br> |
||||||
|
* <b>Usage: </b><code>{@link AppSettings appSettings}.{@link HashMap#put(Object, Object) put}(VRConstants.SETTING_DISABLE_MSAA, value)</code> |
||||||
|
*/ |
||||||
|
public static final String SETTING_DISABLE_MSAA = "VRDisableMSAA"; |
||||||
|
|
||||||
|
/** |
||||||
|
* An AppSettings parameter that set the default field of view (FOV) value. |
||||||
|
* <b>Type: </b><code>float</code><br> |
||||||
|
* <b>Usage: </b><code>{@link AppSettings appSettings}.{@link HashMap#put(Object, Object) put}(VRConstants.SETTING_DEFAULT_FOV, value)</code> |
||||||
|
*/ |
||||||
|
public static final String SETTING_DEFAULT_FOV = "VRDefaultFOV"; |
||||||
|
|
||||||
|
/** |
||||||
|
* An AppSettings parameter that set the default aspect ratio. |
||||||
|
* <b>Type: </b><code>float</code><br> |
||||||
|
* <b>Usage: </b><code>{@link AppSettings appSettings}.{@link HashMap#put(Object, Object) put}(VRConstants.SETTING_DEFAULT_ASPECT_RATIO, value)</code> |
||||||
|
*/ |
||||||
|
public static final String SETTING_DEFAULT_ASPECT_RATIO = "VRDefaultAspectRatio"; |
||||||
|
|
||||||
|
/** |
||||||
|
* An AppSettings parameter that specifies the underlying VR API. Possible values are:<br> |
||||||
|
* <ul> |
||||||
|
* <li>{@link VRConstants#SETTING_VRAPI_OPENVR_VALUE SETTING_VRAPI_OPENVR_VALUE}: Use OpenVR binding. |
||||||
|
* <li>{@link VRConstants#SETTING_VRAPI_OSVR_VALUE SETTING_VRAPI_OSVR_VALUE}: Use OSVR binding. |
||||||
|
* <li>{@link VRConstants#SETTING_VRAPI_OPENVR_LWJGL_VALUE SETTING_VRAPI_OPENVR_LWJGL_VALUE}: Use OpenVR binding from LWJGL. |
||||||
|
* </ul> |
||||||
|
* <b>Type: </b><code>int</code><br> |
||||||
|
* <b>Usage: </b><code>{@link AppSettings appSettings}.{@link HashMap#put(Object, Object) put}(VRConstants.SETTING_VRAPI, value)</code> |
||||||
|
|
||||||
|
*/ |
||||||
|
public static final String SETTING_VRAPI = "VRAPI"; |
||||||
|
|
||||||
|
/** |
||||||
|
* The identifier of the OpenVR system. |
||||||
|
* @see #SETTING_VRAPI |
||||||
|
*/ |
||||||
|
public static final int SETTING_VRAPI_OPENVR_VALUE = 1; |
||||||
|
|
||||||
|
/** |
||||||
|
* The identifier of the OSVR system. |
||||||
|
* @see #SETTING_VRAPI |
||||||
|
*/ |
||||||
|
public static final int SETTING_VRAPI_OSVR_VALUE = 2; |
||||||
|
|
||||||
|
/** |
||||||
|
* The identifier of the OpenVR from LWJGL system. |
||||||
|
* @see #SETTING_VRAPI |
||||||
|
*/ |
||||||
|
public static final int SETTING_VRAPI_OPENVR_LWJGL_VALUE = 3; |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} |
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue