| /******************************************************************************* |
| * 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; |
| } |
| } |