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