blob: c98df2447a417f673778e0b47c38302e8a48f269 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2018 Agence spatiale canadienne / Canadian Space Agency
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pierre Allard,
* Regent L'Archeveque,
<<<<<<< HEAD
* Sebastien Gemme
*
=======
* Sebastien Gemme - initial API and implementation
*
>>>>>>> refs/heads/eclipse_pa
* SPDX-License-Identifier: EPL-1.0
*
*******************************************************************************/
package org.eclipse.apogy.common.topology.ui.jme3;
import java.awt.Frame;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.Callable;
import org.eclipse.apogy.common.topology.AbstractViewPoint;
import org.eclipse.apogy.common.topology.AttachedViewPoint;
import org.eclipse.apogy.common.topology.ui.jme3.internal.CreateSceneGraphHTMLActionListener;
import org.eclipse.apogy.common.topology.ui.jme3.internal.CustomCameraControl;
import org.eclipse.apogy.common.topology.ui.jme3.internal.CustomScreenshotAppState;
import org.eclipse.apogy.common.topology.ui.jme3.internal.ICameraControl;
import org.eclipse.apogy.common.topology.ui.jme3.internal.MouseClickListener;
import org.eclipse.apogy.common.topology.ui.jme3.internal.MousePickListener;
import org.eclipse.apogy.common.topology.ui.viewer.MouseButton;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.awt.SWT_AWT;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Composite;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.jme3.app.SimpleApplication;
import com.jme3.asset.AssetManager;
import com.jme3.input.MouseInput;
import com.jme3.light.DirectionalLight;
import com.jme3.light.Light;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.system.AppSettings;
import com.jme3.system.JmeContext;
import com.jme3.system.lwjgl.LwjglCanvas;
//FIXME Is it a test or a Apogy asset.
public class JME3Application extends SimpleApplication {
private static final Logger Logger = LoggerFactory.getLogger(JME3Application.class);
public static final String JME3_CANVAS_INIT_DELAY_ENV_VAR = "JME3_CANVAS_INIT_DELAY";
public static final long DEFAULT_JME3_CANVAS_DELAY = 5000;
private JME3RenderEngineDelegate jme3RenderEngineDelegate;
private final Composite jme3Window;
private final Frame jme3awtFrame;
private boolean ambientLightEnabled = false;
// Scene nodes.
private com.jme3.scene.Node sceneCentreTransform;
private com.jme3.scene.Node sceneRoot;
private ICameraControl customCamera;
private CustomScreenshotAppState customScreenshotAppState;
private CreateSceneGraphHTMLActionListener createSceneGraphHTMLActionListener;
private MousePickListener mousePickListener;
private MouseClickListener mouseClickListener;
private final DirectionalLight skyLight = new DirectionalLight();
private final List<Light> lights = new ArrayList<Light>();
public JME3Application(Composite parent) {
super();
AppSettings newSetting = new AppSettings(true);
newSetting
.setFrameRate(org.eclipse.apogy.common.topology.ui.viewer.Activator.getDefault().getMaximumFrameRate());
if (org.eclipse.apogy.common.topology.ui.viewer.Activator.getDefault().isAntialiasing()) {
newSetting.setSamples(4);
} else {
newSetting.setSamples(0);
}
// newSetting.setMinResolution(1280, 960);
newSetting.setMinResolution(640, 480);
setSettings(newSetting);
start(JmeContext.Type.Canvas);
LwjglCanvas canvas = (LwjglCanvas) getContext();
// Force to wait for canvas to have started.
startCanvas(true);
this.jme3Window = new Composite(parent, SWT.EMBEDDED);
this.jme3Window.addFocusListener(new FocusListener() {
private long focusLostTime = 0;
@Override
public void focusLost(FocusEvent e) {
this.focusLostTime = System.currentTimeMillis();
enableMouseNavigation(false);
}
@Override
public void focusGained(FocusEvent e) {
long now = System.currentTimeMillis();
if ((now - this.focusLostTime) > 1000) {
enableMouseNavigation(true);
} else {
enableMouseNavigation(false);
}
}
});
this.jme3awtFrame = SWT_AWT.new_Frame(this.jme3Window);
this.jme3awtFrame.add(canvas.getCanvas());
canvas.getCanvas().setFocusable(false);
setShowStatisticsEnabled(false);
}
public void setJMERenderEngineDelegate(JME3RenderEngineDelegate jme3RenderEngineDelegate) {
this.jme3RenderEngineDelegate = jme3RenderEngineDelegate;
}
public JME3RenderEngineDelegate getJMERenderEngineDelegate() {
return this.jme3RenderEngineDelegate;
}
@Override
public void simpleInitApp() {
// Wait for canvas initialization. Temporary fix to BUG 1555.
waitForCanvasInitialization();
setPauseOnLostFocus(false);
// Creates the scene graph.
createSceneGraph();
// Sets the far clipping plane to 25 km.
getCamera().setFrustumFar(25000f);
// Position the camera
getCamera().setLocation(new Vector3f(-10, 0, 0));
getCamera().lookAt(new Vector3f(), Vector3f.UNIT_Z);
// Initialize the lighting.
initLighting();
// Attach Camera Control.
getFlyByCamera().setEnabled(false);
this.customCamera = new CustomCameraControl(getCamera(), getSceneRoot(), this.inputManager, this);
this.customCamera.setEnabled(true);
// Configure the Screen Shot Action listener.
this.createSceneGraphHTMLActionListener = new CreateSceneGraphHTMLActionListener(this.inputManager, this);
this.createSceneGraphHTMLActionListener.setEnabled(true);
// Add the mouse listener used for picking objects.
getMousePickListener();
// Add the mouse listener used for detecting mouse clicks.
getMouseClickListener();
}
@Override
public AssetManager getAssetManager() {
int tries = 0;
while (super.getAssetManager() == null && tries < 20) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Logger.error(e.getMessage(), e);
}
}
return super.getAssetManager();
}
public void setShowStatisticsEnabled(boolean enable) {
setDisplayFps(enable);
setDisplayStatView(enable);
}
public void setAntiAliasing(boolean enable) {
Logger.info("Setting anti aliasing to <" + enable + ">.");
this.settings
.setFrameRate(org.eclipse.apogy.common.topology.ui.viewer.Activator.getDefault().getMaximumFrameRate());
if (enable) {
this.settings.setSamples(4);
} else {
this.settings.setSamples(0);
}
enqueue(new Callable<Object>() {
@Override
public Object call() throws Exception {
setSettings(JME3Application.this.settings);
restart();
return null;
}
});
}
public void setMaximumFrameRate(int maximumFrameRate) {
Logger.info("Setting Maximum Frame Rate to <" + maximumFrameRate + "> fps.");
if (this.settings == null) {
this.settings = new AppSettings(true);
}
this.settings.setFrameRate(maximumFrameRate);
setSettings(this.settings);
}
public void setSkyLightEnabled(boolean enable) {
Logger.info("Setting Sky Light Enabled to <" + enable + ">.");
boolean previousSkyLightEnabled = this.ambientLightEnabled;
this.ambientLightEnabled = enable;
if (previousSkyLightEnabled == true && enable == false) {
// Attaches all lights.
for (Light light : this.lights) {
if (!lightIsAttached(light))
this.rootNode.addLight(light);
}
// Detaches skyLight
this.rootNode.removeLight(this.skyLight);
} else if (previousSkyLightEnabled == false && enable == true) {
// Needs to remove all lights previously there
this.lights.clear();
// Remembers all light that were attached before.
Iterator<Light> it = this.rootNode.getLocalLightList().iterator();
while (it.hasNext()) {
this.lights.add(it.next());
}
// Detaches all lights.
for (Light light : this.lights) {
this.rootNode.removeLight(light);
}
// Re-Attaches the skylight
if (!lightIsAttached(this.skyLight))
this.rootNode.addLight(this.skyLight);
}
}
public void setSkyLightColor(int red, int green, int blue) {
Logger.info("Setting Sky Light Color to <" + red + ", " + green + ", " + blue + "> .");
this.skyLight.setColor(new ColorRGBA(red / 255.0f, green / 255.0f, blue / 255.0f, 1f));
}
public void setSkyLightDirection(float x, float y, float z) {
Logger.info("Setting Sky Light Direction to <" + x + ", " + y + ", " + z + "> .");
this.skyLight.setDirection(new Vector3f(x, y, z));
}
public BufferedImage takeScreenshot() {
getCustomScreenshotAppState().takeSnapshot();
int tries = 0;
while (getCustomScreenshotAppState().getCapturedImage() == null && tries < 5) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Logger.error(e.getMessage(), e);
}
tries++;
}
return getCustomScreenshotAppState().getCapturedImage();
}
/**
* Cause the viewpoint orientation to be updated such that the view has the +Z
* in the up direction.
*/
public void levelViewPoint() {
if (this.customCamera != null) {
this.customCamera.levelPose();
}
}
public void setHighSpeedMotionEnabled(boolean highSpeedMotionEnabled) {
if (this.customCamera != null) {
this.customCamera.setHighSpeedMotionEnabled(highSpeedMotionEnabled);
}
}
public void setPickingModeEnabled(boolean pickingModeEnabled) {
if (this.mousePickListener != null) {
this.mousePickListener.setPickEnabled(pickingModeEnabled);
}
}
public void dispose() {
// Disbale the Screen Shot Action Listener.
getCustomScreenshotAppState().setEnabled(false);
// Stops the viewer.
stop();
// Dispose of the AWt Frame.
if (this.jme3awtFrame != null) {
this.jme3awtFrame.dispose();
}
}
public void setArbitraryViewPointLocation(Vector3f newLocation) {
if (this.customCamera != null) {
this.customCamera.setCurrentLocation(newLocation);
}
}
public Vector3f getArbitraryViewPointLocation() {
if (this.customCamera != null) {
return this.customCamera.getCurrentLocation();
} else {
return new Vector3f();
}
}
public void setArbitraryViewPointRotation(Quaternion newRotation) {
if (this.customCamera != null) {
this.customCamera.setCurrentOrientation(newRotation);
}
}
public Quaternion getArbitraryViewPointRotation() {
if (this.customCamera != null) {
return this.customCamera.getCurrentOrientation();
} else {
return new Quaternion();
}
}
public void attachViewPoint(final AbstractViewPoint viewPoint) {
enqueue(new Callable<Object>() {
@Override
public Object call() throws Exception {
try {
if (JME3Application.this.customCamera != null && viewPoint != null) {
JME3Application.this.customCamera.attachViewPoint(viewPoint);
if (viewPoint instanceof AttachedViewPoint) {
AttachedViewPoint attachedViewPoint = (AttachedViewPoint) viewPoint;
JME3Application.this.customCamera
.setTranslationEnabled(attachedViewPoint.isAllowTranslation());
JME3Application.this.customCamera.setRotationEnabled(attachedViewPoint.isAllowRotation());
} else {
JME3Application.this.customCamera.setTranslationEnabled(true);
JME3Application.this.customCamera.setRotationEnabled(true);
}
}
} catch (Exception e) {
Logger.error(e.getMessage(), e);
}
return null;
}
});
}
public void setTranslationEnabled(boolean translationEnabled) {
if (this.customCamera != null) {
this.customCamera.setTranslationEnabled(translationEnabled);
}
}
public void setRotationEnabled(boolean rotationEnabled) {
if (this.customCamera != null) {
this.customCamera.setRotationEnabled(rotationEnabled);
}
}
public com.jme3.scene.Node getSceneRoot() {
if (this.sceneRoot == null) {
this.sceneRoot = new com.jme3.scene.Node("Scene Root");
this.rootNode.attachChild(this.sceneRoot);
}
return this.sceneRoot;
}
public AppSettings getAppSettings() {
return this.settings;
}
protected void initLighting() {
this.skyLight.setDirection(JME3Utilities.convertToVector3f(org.eclipse.apogy.common.topology.ui.viewer.Activator
.getDefault().getAmbientLightDirection().asTuple3d()));
RGB rgb = org.eclipse.apogy.common.topology.ui.viewer.Activator.getDefault().getAmbientLightColor();
if (rgb != null) {
this.skyLight.setColor(new ColorRGBA(rgb.red / 255f, rgb.green / 255f, rgb.blue / 255f, 1f));
} else {
this.skyLight.setColor(new ColorRGBA(1f, 1f, 1f, 1f));
}
if (this.ambientLightEnabled) {
this.rootNode.addLight(this.skyLight);
}
}
private boolean lightIsAttached(Light light) {
boolean isAttached = false;
Iterator<Light> it = this.rootNode.getWorldLightList().iterator();
while (it.hasNext() && !isAttached) {
if (it.next() == light) {
isAttached = true;
}
}
return isAttached;
}
private void waitForCanvasInitialization() {
long delay = DEFAULT_JME3_CANVAS_DELAY;
// Check to see if the JME3_CANVAS_INIT_DELAY env variable has been set.
String delayString = System.getenv(JME3_CANVAS_INIT_DELAY_ENV_VAR);
if (delayString != null) {
try {
delay = Math.round(Math.abs((Double.parseDouble(delayString) * 1000)));
} catch (Exception e) {
Logger.error("Invalid value of <" + delayString + "> found for " + JME3_CANVAS_INIT_DELAY_ENV_VAR
+ ", using default value of <" + DEFAULT_JME3_CANVAS_DELAY + "> ms.");
}
}
// Wait for delay.
try {
Logger.info("Waiting for <" + delay + "> ms for JMECanvas to initialize.");
Thread.sleep(delay);
Logger.info("Waiting for <" + delay + "> ms for JMECanvas to initialize completed.");
} catch (InterruptedException e) {
Logger.error("Unable to sleep.", e);
}
}
private void createSceneGraph() {
this.sceneCentreTransform = new com.jme3.scene.Node("Scene Centre Transform");
getSceneRoot().attachChild(this.sceneCentreTransform);
}
private CustomScreenshotAppState getCustomScreenshotAppState() {
if (this.customScreenshotAppState == null) {
this.customScreenshotAppState = new CustomScreenshotAppState();
this.stateManager.attach(this.customScreenshotAppState);
}
return this.customScreenshotAppState;
}
private void enableMouseNavigation(boolean mouseNavigationEnabled) {
LwjglCanvas canvas = (LwjglCanvas) getContext();
if (canvas != null) {
canvas.getCanvas().setFocusable(mouseNavigationEnabled);
}
}
private MousePickListener getMousePickListener() {
if (this.mousePickListener == null) {
this.mousePickListener = new MousePickListener(getCamera(), this, getInputManager()) {
@Override
protected void pickingEnabled(boolean enable) {
// Disables navigation when picking.
if (JME3Application.this.customCamera != null) {
JME3Application.this.customCamera.setEnabled(!enable);
}
}
@Override
protected void fireSelectionChanged(SelectionChangedEvent event) {
JME3Application.this.jme3RenderEngineDelegate.getTopologyViewer()
.setSelection(event.getSelection());
}
};
}
return this.mousePickListener;
}
private MouseClickListener getMouseClickListener() {
if (this.mouseClickListener == null) {
this.mouseClickListener = new MouseClickListener(getCamera(), this, getInputManager()) {
@Override
protected void mouseClicked(int mouseButton) {
MouseButton button = null;
switch (mouseButton) {
case MouseInput.BUTTON_LEFT:
button = MouseButton.LEFT;
break;
case MouseInput.BUTTON_MIDDLE:
button = MouseButton.MIDDLE;
break;
case MouseInput.BUTTON_RIGHT:
button = MouseButton.RIGHT;
break;
default:
break;
}
if (button != null)
JME3Application.this.jme3RenderEngineDelegate.getTopologyViewer().mouseClicked(button);
}
};
this.mouseClickListener.setEnabled(true);
}
return this.mouseClickListener;
}
}