package com.jme3.app;
import com.jme3.app.AppTask;
import com.jme3.app.Application;
import com.jme3.app.LegacyApplication;
import com.jme3.app.LostFocusBehavior;
import com.jme3.app.ResetStatsState;
import com.jme3.app.SimpleApplication;
import com.jme3.app.state.AppState;
import com.jme3.app.state.AppStateManager;
import com.jme3.asset.AssetManager;
import com.jme3.audio.AudioContext;
import com.jme3.audio.AudioRenderer;
import com.jme3.audio.Listener;
import com.jme3.input.InputManager;
import com.jme3.input.JoyInput;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.TouchInput;
import com.jme3.input.controls.KeyTrigger;
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.profile.AppProfiler;
import com.jme3.renderer.Camera;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.Renderer;
import com.jme3.renderer.ViewPort;
import com.jme3.renderer.queue.RenderQueue.Bucket;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.Spatial.CullHint;
import com.jme3.system.AppSettings;
import com.jme3.system.JmeContext;
import com.jme3.system.JmeContext.Type;
import com.jme3.system.jopenvr.JOpenVRLibrary;
import com.jme3.system.JmeSystem;
import com.jme3.system.NanoTimer;
import com.jme3.system.SystemListener;
import com.jme3.system.Timer;
import com.jme3.system.lwjgl.LwjglDisplayVR;
import com.jme3.system.lwjgl.LwjglOffscreenBufferVR;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.HeadlessException;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Locale;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;
import jmevr.util.VRViewManager;
import jmevr.util.VRGuiManager;
import jmevr.util.VRGuiManager.POSITIONING_MODE;
import jmevr.util.VRMouseManager;
import org.lwjgl.system.Platform;
/**
* A JMonkey application dedicated to Virtual Reality. An application that use VR devices (HTC vive, ...) has to extends this one.
*
* This class is no more functional and is deprecated. Please use {@link VRAppState VRAppState} instead.
* @author reden - phr00t - https://github.com/phr00t
* @author Julien Seinturier - (c) 2016 - JOrigin project - http:/www.jorigin.org
* @deprecated use {@link VRAppState VRAppState} instead.
*/
public abstract class VRApplication implements Application, SystemListener {
private static final Logger logger = Logger.getLogger(LegacyApplication.class.getName());
/**
* The default FOV.
*/
public float DEFAULT_FOV = 108f;
/**
* The default aspect ratio.
*/
public float DEFAULT_ASPECT = 1f;
/**
* Is the application is based on OSVR (default is
* Examples of display parameters include display frame {@link AppSettings#getWidth() width} and {@link AppSettings#getHeight() height},
* pixel {@link AppSettings#getBitsPerPixel() color bit depth}, {@link AppSettings#getDepthBits() z-buffer bits}, {@link AppSettings#getSamples() anti-aliasing samples}, {@link AppSettings#getFrequency() update frequency}, ...
*
* By default, pause on lost focus is enabled.
* If enabled, the application will stop updating
* when it loses focus or becomes inactive (e.g. alt-tab).
* For online or real-time applications, this might not be preferable,
* so this feature should be set to disabled. For other applications,
* it is best to keep it on so that CPU usage is not used when
* not necessary.
*
* @param pauseOnLostFocus false
).
*/
public boolean CONSTRUCT_WITH_OSVR = false;
/**
* Is the application has not to start within VR mode (default is false
).
*/
public boolean DISABLE_VR = false;
/**
* VR application configuration parameters.
* @author reden - phr00t - https://github.com/phr00t
* @author Julien Seinturier - (c) 2016 - JOrigin project - http:/www.jorigin.org
*
*/
public static enum PreconfigParameter {
/**
* Is the SteamVR compositor is used (kinda needed at the moment)
*/
USE_VR_COMPOSITOR,
/**
* Render two eyes, regardless of VR API detection.
*/
FORCE_VR_MODE,
/**
* Invert the eyes.
*/
FLIP_EYES,
/**
* Show GUI even if it is behind objects.
*/
SET_GUI_OVERDRAW,
/**
*
*/
SET_GUI_CURVED_SURFACE,
/**
* Display a mirror rendering on the screen. Runs faster when set to false
.
*/
ENABLE_MIRROR_WINDOW,
/**
*
*/
PREFER_OPENGL3,
/**
* Disable VR rendering, regardless VR API and devices are presents.
*/
DISABLE_VR,
/**
*
*/
SEATED_EXPERIENCE,
/**
* Remove GUI node from the application.
*/
NO_GUI,
/**
* Faster VR rendering, requires some vertex shader changes (see Common/MatDefs/VR/Unshaded.j3md)
*/
INSTANCE_VR_RENDERING,
/**
*
*/
FORCE_DISABLE_MSAA
}
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;
private boolean VRSupportedOS;
private boolean forceVR;
private boolean disableSwapBuffers = true;
private boolean tryOpenGL3 = true;
private boolean seated;
private boolean nogui;
private boolean instanceVR;
private boolean forceDisableMSAA;
// things taken from LegacyApplication
private AppStateManager stateManager;
private Camera cam;
private AppSettings settings;
private JmeContext context;
private float speed = 1f;
private AudioRenderer audioRenderer;
private LostFocusBehavior lostFocusBehavior = LostFocusBehavior.ThrottleOnLostFocus;
private final ConcurrentLinkedQueue
* The application scene is made of a {@link #getRootNode() root node} that holds the scene spatials
* and a {@link #getGuiNode() GUI node} that is the root of the Graphical user interface.
* @param initialStates the {@link AppState app states} to attach to the application.
*/
public VRApplication(AppState... initialStates) {
this();
if (initialStates != null) {
for (AppState a : initialStates) {
if (a != null) {
stateManager.attach(a);
}
}
}
}
/**
* Create a new VR application.
* The application scene is made of a {@link #getRootNode() root node} that holds the scene spatials
* and a {@link #getGuiNode() GUI node} that is the root of the Graphical user interface.
*/
public VRApplication() {
super();
rootNode = new Node("root");
guiNode = new Node("guiNode");
guiNode.setQueueBucket(Bucket.Gui);
guiNode.setCullHint(CullHint.Never);
dummyCam = new Camera();
initStateManager();
// Create the GUI manager.
guiManager = new VRGuiManager();
// Create a new view manager.
viewmanager = new VRViewManager();
// Create a new mouse manager.
mouseManager = new VRMouseManager();
// 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 ) {
logger.warning("Non-supported OS: " + OS + ", architecture: " + System.getProperty("sun.arch.data.model"));
} else if( DISABLE_VR ) {
logger.warning("VR disabled via code.");
} else if( VRSupportedOS && DISABLE_VR == false ) {
if( CONSTRUCT_WITH_OSVR ) {
//FIXME: WARNING !!
VRhardware = new OSVR(null);
logger.config("Creating OSVR wrapper [SUCCESS]");
} else {
//FIXME: WARNING !!
VRhardware = new OpenVR(null);
logger.config("Creating OpenVR wrapper [SUCCESS]");
}
if( VRhardware.initialize() ) {
setPauseOnLostFocus(false);
}
}
}
/**
* 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;
}
/**
* 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 SteamVR compositor is active.
* @return true
if the SteamVR compositor is active and false
otherwise.
*/
public boolean compositorAllowed() {
return useCompositor && compositorOS;
}
/**
* Get if the system currently support VR.
* @return true
if the system currently support VR and false
otherwise.
*/
public boolean isOSVRSupported() {
return VRSupportedOS;
}
/**
* Simple update of the application, this method should contains {@link #getRootNode() root node} updates.
* This method is called by the {@link #update() update()} method and should not be called manually.
* @param tpf the application time.
*/
public void simpleUpdate(float tpf) { }
/**
* Rendering callback of the application. This method is called by the {@link #update() update()} method and should not be called manually.
* @param renderManager the {@link RenderManager render manager}.
*/
public void simpleRender(RenderManager renderManager) {
PreNormalCaching.resetCache(isInVR());
}
/*
we do NOT want to get & modify the distortion scene camera, so
return the left viewport camera instead if we are in VR mode
*/
@Override
public Camera getCamera() {
if( isInVR() && viewmanager != null && viewmanager.getLeftCamera() != null ) {
return dummyCam;
}
return cam;
}
/**
* Get the application internal camera.
* @return the application internal camera.
* @see #getCamera()
*/
public Camera getBaseCamera() {
return cam;
}
@Override
public JmeContext getContext(){
return context;
}
@Override
public AssetManager getAssetManager(){
return assetManager;
}
@Override
public InputManager getInputManager(){
return inputManager;
}
@Override
public AppStateManager getStateManager() {
return stateManager;
}
@Override
public RenderManager getRenderManager() {
return renderManager;
}
@Override
public Renderer getRenderer(){
return renderer;
}
@Override
public AudioRenderer getAudioRenderer() {
return audioRenderer;
}
@Override
public Listener getListener() {
return listener;
}
@Override
public Timer getTimer(){
return timer;
}
/**
* Handle the error given in parameters by creating a log entry and a dialog window. Internal use only.
*/
public void handleError(String errMsg, Throwable t){
// Print error to log.
logger.log(Level.SEVERE, errMsg, t);
// Display error message on screen if not in headless mode
if (context.getType() != JmeContext.Type.Headless) {
if (t != null) {
JmeSystem.showErrorDialog(errMsg + "\n" + t.getClass().getSimpleName() +
(t.getMessage() != null ? ": " + t.getMessage() : ""));
} else {
JmeSystem.showErrorDialog(errMsg);
}
}
stop(); // stop the application
}
/**
* Force the focus gain for the application. Internal use only.
*/
public void gainFocus(){
if (lostFocusBehavior != LostFocusBehavior.Disabled) {
if (lostFocusBehavior == LostFocusBehavior.PauseOnLostFocus) {
paused = false;
}
context.setAutoFlushFrames(true);
if (inputManager != null) {
inputManager.reset();
}
}
}
/**
* Force the focus lost for the application. Internal use only.
*/
public void loseFocus(){
if (lostFocusBehavior != LostFocusBehavior.Disabled){
if (lostFocusBehavior == LostFocusBehavior.PauseOnLostFocus) {
paused = true;
}
context.setAutoFlushFrames(false);
}
}
/**
* Reshape the display window. Internal use only.
*/
public void reshape(int w, int h){
if (renderManager != null) {
renderManager.notifyReshape(w, h);
}
}
/**
* Request the application to close. Internal use only.
*/
public void requestClose(boolean esc){
context.destroy(false);
}
/**
* Set the {@link AppSettings display settings} to define the display created.
*
If this method is called while the application is already running, then
* {@link #restart() } must be called to apply the settings to the display.
*
* @param settings The settings to set.
*/
public void setSettings(AppSettings settings){
this.settings = settings;
if (context != null && settings.useInput() != inputEnabled){
// may need to create or destroy input based
// on settings change
inputEnabled = !inputEnabled;
if (inputEnabled){
initInput();
}else{
destroyInput();
}
}else{
inputEnabled = settings.useInput();
}
}
/**
* Sets the {@link Timer} implementation that will be used for calculating
* frame times.
* By default, Application will use the Timer as returned by the current {@link JmeContext} implementation.
* @param timer the timer to use.
*/
public void setTimer(Timer timer){
this.timer = timer;
if (timer != null) {
timer.reset();
}
if (renderManager != null) {
renderManager.setTimer(timer);
}
}
/**
* Determine the application's behavior when unfocused.
* @return The lost focus behavior of the application.
*/
public LostFocusBehavior getLostFocusBehavior() {
return lostFocusBehavior;
}
/**
* Change the application's behavior when unfocused. By default, the application will
* {@link LostFocusBehavior#ThrottleOnLostFocus throttle the update loop}
* so as to not take 100% CPU usage when it is not in focus, e.g.
* alt-tabbed, minimized, or obstructed by another window.
*
* @param lostFocusBehavior The new {@link LostFocusBehavior lost focus behavior} to use.
*/
public void setLostFocusBehavior(LostFocusBehavior lostFocusBehavior) {
this.lostFocusBehavior = lostFocusBehavior;
}
/**
* Get if the application has to pause then it lost the focus.
* @return true
if pause on lost focus is enabled, false
otherwise.
* @see #getLostFocusBehavior()
*/
public boolean isPauseOnLostFocus() {
return getLostFocusBehavior() == LostFocusBehavior.PauseOnLostFocus;
}
/**
* Enable or disable pause on lost focus.
* true
to enable pause on lost focus, false
* otherwise.
*
* @see #setLostFocusBehavior(com.jme3.app.LostFocusBehavior)
*/
public void setPauseOnLostFocus(boolean pauseOnLostFocus) {
if (pauseOnLostFocus) {
setLostFocusBehavior(LostFocusBehavior.PauseOnLostFocus);
} else {
setLostFocusBehavior(LostFocusBehavior.Disabled);
}
}
@Override
public void start() {
logger.config("Starting application...");
// set some default settings in-case
// settings dialog is not shown
boolean loadSettings = false;
if (settings == null) {
setSettings(new AppSettings(true));
loadSettings = true;
}
GraphicsDevice defDev = null;
try {
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
defDev = ge.getDefaultScreenDevice();
} catch (Throwable e1) {
logger.log(Level.SEVERE, "Cannot access default screen device: "+e1.getMessage(), e1);
}
if( isInVR() && !compositorAllowed() ) {
logger.warning("VR Composition is not allowed.");
// "easy extended" mode
// TO-DO: JFrame was removed in LWJGL 3, need to use new GLFW library to pick "monitor" display of VR 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
setSettings(settings);
//VRdev.setFullScreenWindow(VRwindow);
// make sure we are in the right display mode
if( VRdev.getDisplayMode().equals(useDM) == false ) {
VRdev.setDisplayMode(useDM);
}
// make a blank cursor to hide it
//BufferedImage cursorImg = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);
//Cursor blankCursor = Toolkit.getDefaultToolkit().createCustomCursor(cursorImg, new Point(0, 0), "blank cursor");
//VRwindow.setCursor(blankCursor);
//jmeCanvas.getCanvas().setCursor(blankCursor);
//VRwindow.pack();
//VRwindow.setVisible(true);
//startCanvas();
logger.config("Starting application [SUCCESS]");
return;
} catch(Exception e) {
logger.log(Level.SEVERE, "Error during application start: "+e.getMessage(), e);
}
}
}
if( !isInVR() ) {
logger.config("VR mode disabled.");
// not in VR, show settings dialog
if( Platform.get() != Platform.MACOSX ) {
if (!JmeSystem.showSettingsDialog(settings, loadSettings)) {
logger.config("Starting application [SUCCESS]");
return;
}
} else {
// 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 {
logger.config("VR mode enabled.");
// use basic mirroring window, skip settings window
settings.setWidth(xWin);
settings.setHeight(yWin);
settings.setBitsPerPixel(24);
settings.setFrameRate(0); // never sleep in main loop
settings.setFrequency(VRhardware.getDisplayFrequency());
settings.setFullscreen(false);
settings.setVSync(false); // stop vsyncing on primary monitor!
settings.setSwapBuffers(!disableSwapBuffers || VRhardware instanceof OSVR);
settings.setTitle("Put Headset On Now: " + settings.getTitle());
settings.setResizable(true);
}
if( forceDisableMSAA ) {
logger.config("Disabling multisampling.");
// disable multisampling, which is more likely to break things than be useful
settings.setSamples(1);
}
// set opengl mode
if( tryOpenGL3 ) {
logger.config("Using LWJGL OpenGL 3 renderer.");
settings.setRenderer(AppSettings.LWJGL_OPENGL3);
} else {
logger.config("Using LWJGL OpenGL 2 renderer.");
settings.setRenderer(AppSettings.LWJGL_OPENGL2);
}
setSettings(settings);
start(JmeContext.Type.Display, false);
// 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);
}
/**
* Starts the application in {@link com.jme3.system.JmeContext.Type#Display display} mode.
* @param waitFor if true
, the method will wait until the application is started.
* @see #start(com.jme3.system.JmeContext.Type, boolean)
*/
public void start(boolean waitFor){
start(JmeContext.Type.Display, waitFor);
}
/**
* Starts the application.
* Creating a rendering context and executing the main loop in a separate thread.
* @param contextType the {@link com.jme3.system.JmeContext.Type type} of the context to create.
* @param waitFor if true
, the method will wait until the application is started.
* @throws IllegalArgumentException if the context type is not supported.
*/
public void start(JmeContext.Type contextType, boolean waitFor){
if (context != null && context.isCreated()){
logger.warning("start() called when application already created!");
return;
}
if (settings == null){
settings = new AppSettings(true);
}
logger.log(Level.FINE, "Starting application: {0}", getClass().getName());
// Create VR decicated context
if (contextType == Type.Display){
context = new LwjglDisplayVR();
context.setSettings(settings);
} else if (contextType == Type.OffscreenSurface){
context = new LwjglOffscreenBufferVR();
context.setSettings(settings);
} else {
logger.severe("Unsupported context type \""+contextType+"\". Supported are \"Display\" and \"OffscreenSurface\"");
throw new IllegalArgumentException("Unsupported context type \""+contextType+"\". Supported are \"Display\" and \"OffscreenSurface\"");
}
context.setSystemListener(this);
context.create(waitFor);
}
/**
* Move filters from the main scene into the eye's.
* This removes filters from the main scene.
*/
public void moveScreenProcessingToVR() {
if( isInVR() ) {
viewmanager.moveScreenProcessingToEyes();
}
}
/**
* Set VR application {@link PreconfigParameter specific parameter}.
* If making changes to default values, this must be called before the VRApplication starts
* @param parm the parameter to set.
* @param value the value of the parameter.
*/
public void preconfigureVRApp(PreconfigParameter parm, boolean value) {
switch( parm ) {
case SET_GUI_OVERDRAW:
guiManager._enableGuiOverdraw(value);
break;
case SET_GUI_CURVED_SURFACE:
guiManager._enableCurvedSuface(value);
break;
case FORCE_VR_MODE:
forceVR = value;
break;
//case USE_CUSTOM_DISTORTION: //deprecated, always using a render manager
// VRViewManager._setCustomDistortion(value);
// break;
case USE_VR_COMPOSITOR:
useCompositor = value;
if( value == false ) disableSwapBuffers = false;
break;
case FLIP_EYES:
if( VRhardware == null ) return;
VRhardware._setFlipEyes(value);
break;
case INSTANCE_VR_RENDERING:
instanceVR = value;
break;
case ENABLE_MIRROR_WINDOW:
if( useCompositor == false ) {
disableSwapBuffers = false;
} else disableSwapBuffers = !value;
break;
case PREFER_OPENGL3:
tryOpenGL3 = value;
break;
case DISABLE_VR:
DISABLE_VR = value;
break;
case NO_GUI:
nogui = value;
break;
case SEATED_EXPERIENCE:
seated = value;
break;
case FORCE_DISABLE_MSAA:
forceDisableMSAA = value;
break;
}
}
/**
* Can be used to change seated experience during runtime.
* @param isSeated true
if designed for sitting, false
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 true
if the application is configured as a seated experience and false
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 Geometry instancing).
* @return true
if the rendering is instanced and false
otherwise.
*/
public boolean isInstanceVRRendering() {
return instanceVR && isInVR();
}
/**
* Check if the VR mode is enabled.
* @return true
if the VR mode is enabled and false
otherwise.
*/
public boolean isInVR() {
return DISABLE_VR == false && (forceVR || VRSupportedOS && VRhardware != null && VRhardware.isInitialized());
}
/**
* Get the GUI node from the application.
* @return the GUI node from the application.
* @see #setGuiNode(Node)
*/
public Node getGuiNode(){
return guiNode;
}
/**
* Set the GUI node that is displayed within the GUI viewport.
* Calling this method involve clearing all the scenes previously attached to the gui viewport.
* @param node the GUI node to attach.
* @see #getGuiNode()
*/
public void setGuiNode(Node node){
if (node != null){
if (guiViewPort != null){
enqueue(new Callable