blob: 383933234670a0aa6c310d1f19bf754cf3870e84 [file] [log] [blame]
package org.eclipse.apogy.addons.sensors.fov.ui.jme3.scene_objects;
/*******************************************************************************
* 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 - initial API and implementation
* Regent L'Archeveque
* SPDX-License-Identifier: EPL-1.0
*******************************************************************************/
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import org.eclipse.apogy.addons.sensors.fov.ApogyAddonsSensorsFOVPackage;
import org.eclipse.apogy.addons.sensors.fov.DistanceRange;
import org.eclipse.apogy.addons.sensors.fov.RectangularFrustrumFieldOfView;
import org.eclipse.apogy.addons.sensors.fov.ui.jme3.utils.AbstractFieldOfViewImageProjectorControl;
import org.eclipse.apogy.addons.sensors.fov.ui.jme3.utils.JME3FovUtilities;
import org.eclipse.apogy.addons.sensors.fov.ui.jme3.utils.RectangularFrustrumFieldOfViewImageProjectorControl;
import org.eclipse.apogy.addons.sensors.fov.ui.scene_objects.RectangularFrustrumFieldOfViewSceneObject;
import org.eclipse.apogy.common.topology.ui.MeshPresentationMode;
import org.eclipse.apogy.common.topology.ui.jme3.JME3RenderEngineDelegate;
import org.eclipse.apogy.common.topology.ui.jme3.JME3Utilities;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.impl.AdapterImpl;
import org.eclipse.swt.graphics.RGB;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.jme3.asset.AssetManager;
import com.jme3.asset.plugins.FileLocator;
import com.jme3.material.Material;
import com.jme3.material.RenderState.FaceCullMode;
import com.jme3.math.ColorRGBA;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
public class RectangularFrustumFieldOfViewJME3Object
extends AbstractFieldOfViewJME3Object<RectangularFrustrumFieldOfView>
implements RectangularFrustrumFieldOfViewSceneObject {
private static final Logger Logger = LoggerFactory.getLogger(RectangularFrustumFieldOfViewJME3Object.class);
public static ColorRGBA DEFAULT_CIRCULAR_SECTOR_FOV_COLOR = new ColorRGBA(0f, 1f, 0.0f, 1.0f);
public static float DEFAULT_ANGLE_INCREMENT = (float) Math.toRadians(10.0);
private float previousAxisLength = 1.0f;
private boolean axisVisible = true;
private MeshPresentationMode meshPresentationMode = MeshPresentationMode.WIREFRAME;
private Adapter fovAdapter;
private Adapter rangeAdapter;
private AssetManager assetManager;
private Geometry fovGeometry = null;
private Geometry axisGeometry = null;
// Projective textures
private RectangularFrustrumFieldOfViewImageProjectorControl rectangularFrustrumFieldOfViewImageProjectorControl;
public RectangularFrustumFieldOfViewJME3Object(RectangularFrustrumFieldOfView node,
JME3RenderEngineDelegate jme3RenderEngineDelegate) {
super(node, jme3RenderEngineDelegate);
this.assetManager = this.jme3Application.getAssetManager();
this.assetManager.registerLocator("/", FileLocator.class);
// Creates the 3DAxis.
this.axisGeometry = JME3Utilities.createAxis3D(1.0f, this.assetManager);
this.jme3Application.enqueue(new Callable<Object>() {
@Override
public Object call() throws Exception {
// updateGeometry();
requestUpdate();
// Listens for change on the RectangularFrustrumFieldOfView.
node.eAdapters().add(getFOVAdapter());
if (node.getRange() != null) {
node.getRange().eAdapters().add(getRangeAdapter());
}
return null;
}
});
}
@Override
public void updateGeometry(float tpf) {
// Removes previous geometry if applicable.
if (this.fovGeometry != null) {
getFovNode().detachChild(this.fovGeometry);
}
int numberOfDivision = 5;
if (getTopologyNode().getHorizontalFieldOfViewAngle() > 5 * DEFAULT_ANGLE_INCREMENT) {
numberOfDivision = (int) Math
.round(getTopologyNode().getHorizontalFieldOfViewAngle() / DEFAULT_ANGLE_INCREMENT);
} else {
numberOfDivision = 5;
}
Mesh mesh = JME3FovUtilities.createRectangularFrustum(getTopologyNode(), numberOfDivision, numberOfDivision);
// Creates new geometry.
if (getTopologyNode().getNodeId() != null)
this.fovGeometry = new Geometry(getTopologyNode().getNodeId(), mesh);
else
this.fovGeometry = new Geometry("?", mesh);
this.fovGeometry.setMaterial(createMaterial());
// Attaches new geometry.
getFovNode().attachChild(this.fovGeometry);
// Sets the presentation mode.
internalSetPresentationMode(this.meshPresentationMode);
// Attaches the image projector to the root node so that image projector
// continues to work even if the node is invisible.
getAttachmentNode().addControl(getRectangularFrustrumFieldOfViewImageProjectorControl());
}
@Override
public void dispose() {
if (getTopologyNode() != null) {
getTopologyNode().eAdapters().remove(getFOVAdapter());
if (getTopologyNode().getRange() != null) {
getTopologyNode().getRange().eAdapters().remove(getRangeAdapter());
}
}
if (this.rectangularFrustrumFieldOfViewImageProjectorControl != null) {
this.rectangularFrustrumFieldOfViewImageProjectorControl.dispose();
this.rectangularFrustrumFieldOfViewImageProjectorControl = null;
}
super.dispose();
}
@Override
public List<Geometry> getGeometries() {
List<Geometry> geometries = new ArrayList<Geometry>();
geometries.add(this.fovGeometry);
if (this.axisGeometry != null)
geometries.add(this.axisGeometry);
return geometries;
}
@Override
public void setColor(RGB rgb) {
Logger.info("Set Color <" + rgb + ").");
super.setColor(rgb);
try {
if (this.fovGeometry != null) {
final Material mat = createMaterial();
mat.setColor("Diffuse", this.fovColor);
mat.setColor("Ambient", this.fovColor);
mat.setColor("Specular", this.fovColor);
this.jme3Application.enqueue(new Callable<Object>() {
@Override
public Object call() throws Exception {
RectangularFrustumFieldOfViewJME3Object.this.fovGeometry.setMaterial(mat);
return null;
}
});
}
} catch (Throwable t) {
Logger.error("Failed to set color to <" + rgb + ">.", t);
}
}
@Override
public void setPresentationMode(MeshPresentationMode mode) {
Logger.info("setPresentationMode(" + mode + ").");
this.meshPresentationMode = mode;
if (this.fovGeometry != null && this.fovGeometry.getMaterial() != null) {
this.jme3Application.enqueue(new Callable<Object>() {
@Override
public Object call() throws Exception {
internalSetPresentationMode(mode);
return null;
}
});
}
}
@Override
public void setShowProjection(final boolean showProjection) {
Logger.info("setShowProjection(" + showProjection + ")");
// Set the image projector enablement.
this.jme3Application.enqueue(new Callable<Object>() {
@Override
public Object call() throws Exception {
getRectangularFrustrumFieldOfViewImageProjectorControl().setEnabled(showProjection);
return null;
}
});
this.showProjection = showProjection;
}
@Override
public void setShowOutlineOnly(boolean showOutlineOnly) {
}
@Override
public AbstractFieldOfViewImageProjectorControl<RectangularFrustrumFieldOfView> getAbstractFieldOfViewImageProjectorControl() {
return getRectangularFrustrumFieldOfViewImageProjectorControl();
}
@Override
public void setAxisVisible(final boolean visible) {
Logger.info("Setting axis visible to <" + visible + ">.");
this.axisVisible = visible;
this.jme3Application.enqueue(new Callable<Object>() {
@Override
public Object call() throws Exception {
if (RectangularFrustumFieldOfViewJME3Object.this.axisVisible) {
getAttachmentNode().attachChild(RectangularFrustumFieldOfViewJME3Object.this.axisGeometry);
} else {
getAttachmentNode().detachChild(RectangularFrustumFieldOfViewJME3Object.this.axisGeometry);
}
return null;
}
});
}
@Override
public void setAxisLength(double length) {
if (length > 0) {
Logger.info("Setting axis length to <" + length + ">.");
this.jme3Application.enqueue(new Callable<Object>() {
@Override
public Object call() throws Exception {
try {
float scale = (float) Math.abs(length)
/ RectangularFrustumFieldOfViewJME3Object.this.previousAxisLength;
// Scales existing axis.
if (RectangularFrustumFieldOfViewJME3Object.this.axisGeometry != null)
RectangularFrustumFieldOfViewJME3Object.this.axisGeometry.scale(scale);
RectangularFrustumFieldOfViewJME3Object.this.previousAxisLength = (float) length;
} catch (Throwable t) {
Logger.error("Failed to setAxisLength(" + length + ").", t);
}
return null;
}
});
} else {
Logger.error("Setting axis length to <" + length + "> failed : Length must be greater than zero.");
}
}
private void internalSetPresentationMode(MeshPresentationMode mode) {
if (this.fovGeometry != null && this.fovGeometry.getMesh() != null) {
Mesh mesh = this.fovGeometry.getMesh();
switch (mode.getValue()) {
case MeshPresentationMode.SURFACE_VALUE:
this.fovGeometry.getMaterial().getAdditionalRenderState().setWireframe(false);
if (mesh != null)
mesh.setMode(com.jme3.scene.Mesh.Mode.Triangles);
break;
case MeshPresentationMode.WIREFRAME_VALUE:
this.fovGeometry.getMaterial().getAdditionalRenderState().setWireframe(true);
if (mesh != null)
mesh.setMode(com.jme3.scene.Mesh.Mode.Triangles);
break;
case MeshPresentationMode.POINTS_VALUE:
this.fovGeometry.getMaterial().getAdditionalRenderState().setWireframe(false);
if (mesh != null)
mesh.setMode(com.jme3.scene.Mesh.Mode.Points);
break;
default:
break;
}
}
}
// private void updateGeometry()
// {
// jme3Application.enqueue(new Callable<Object>()
// {
// @Override
// public Object call() throws Exception
// {
// // Removes previous geometry if applicable.
// if(fovGeometry != null)
// {
// getFovNode().detachChild(fovGeometry);
// }
//
// int numberOfDivision = 5;
//
// if(getTopologyNode().getHorizontalFieldOfViewAngle() > 5*DEFAULT_ANGLE_INCREMENT)
// {
// numberOfDivision = (int) Math.round(getTopologyNode().getHorizontalFieldOfViewAngle() / DEFAULT_ANGLE_INCREMENT);
// }
// else
// {
// numberOfDivision = 5;
// }
//
//
// Mesh mesh = JME3FovUtilities.createRectangularFrustum(getTopologyNode(), numberOfDivision, numberOfDivision);
//
// // Creates new geometry.
// if(getTopologyNode().getNodeId() != null) fovGeometry = new Geometry(getTopologyNode().getNodeId(), mesh);
// else fovGeometry = new Geometry("?", mesh);
// fovGeometry.setMaterial(createMaterial());
//
// // Attaches new geometry.
// getFovNode().attachChild(fovGeometry);
//
// // Sets the presentation mode.
// internalSetPresentationMode(meshPresentationMode);
//
// // Attaches the image projector to the root node so that image projector continues to work even if the node is invisible.
// getAttachmentNode().addControl(getRectangularFrustrumFieldOfViewImageProjectorControl());
//
// return null;
// }
// });
//
// }
private Material createMaterial() {
Material mat = new Material(this.assetManager, "Common/MatDefs/Light/Lighting.j3md");
if (getColor() != null) {
mat.setColor("Diffuse", JME3Utilities.convertToColorRGBA(getColor()));
mat.setColor("Ambient", JME3Utilities.convertToColorRGBA(getColor()));
mat.setColor("Specular", JME3Utilities.convertToColorRGBA(getColor()));
} else {
mat.setColor("Diffuse", DEFAULT_CIRCULAR_SECTOR_FOV_COLOR.clone());
mat.setColor("Ambient", DEFAULT_CIRCULAR_SECTOR_FOV_COLOR.clone());
mat.setColor("Specular", DEFAULT_CIRCULAR_SECTOR_FOV_COLOR.clone());
}
mat.setFloat("Shininess", 64f);
mat.setBoolean("UseMaterialColors", true);
mat.getAdditionalRenderState().setFaceCullMode(FaceCullMode.Off);
return mat;
}
private Adapter getFOVAdapter() {
if (this.fovAdapter == null) {
this.fovAdapter = new AdapterImpl() {
@Override
public void notifyChanged(Notification notification) {
if (notification.getNotifier() instanceof RectangularFrustrumFieldOfView) {
int featureId = notification.getFeatureID(RectangularFrustrumFieldOfView.class);
if (featureId == ApogyAddonsSensorsFOVPackage.RECTANGULAR_FRUSTRUM_FIELD_OF_VIEW__HORIZONTAL_FIELD_OF_VIEW_ANGLE
|| featureId == ApogyAddonsSensorsFOVPackage.RECTANGULAR_FRUSTRUM_FIELD_OF_VIEW__VERTICAL_FIELD_OF_VIEW_ANGLE) {
// updateGeometry();
requestUpdate();
// Updates the FOV Settings of the projector.
getRectangularFrustrumFieldOfViewImageProjectorControl().updateProjectorFOVSettings();
} else if (featureId == ApogyAddonsSensorsFOVPackage.RECTANGULAR_FRUSTRUM_FIELD_OF_VIEW__RANGE) {
if (notification.getOldValue() instanceof DistanceRange) {
DistanceRange oldDistanceRange = (DistanceRange) notification.getOldValue();
oldDistanceRange.eAdapters().remove(getRangeAdapter());
}
// updateGeometry();
requestUpdate();
if (notification.getNewValue() instanceof DistanceRange) {
DistanceRange newDistanceRange = (DistanceRange) notification.getNewValue();
// Add adapter to the new range.
newDistanceRange.eAdapters().add(getRangeAdapter());
}
}
}
}
};
}
return this.fovAdapter;
}
private Adapter getRangeAdapter() {
if (this.rangeAdapter == null) {
this.rangeAdapter = new AdapterImpl() {
@Override
public void notifyChanged(Notification notification) {
if (notification.getNotifier() instanceof DistanceRange) {
int featureId = notification.getFeatureID(DistanceRange.class);
if (featureId == ApogyAddonsSensorsFOVPackage.DISTANCE_RANGE__MAXIMUM_DISTANCE
|| featureId == ApogyAddonsSensorsFOVPackage.DISTANCE_RANGE__MAXIMUM_DISTANCE) {
// updateGeometry();
requestUpdate();
}
}
}
};
}
return this.rangeAdapter;
}
private RectangularFrustrumFieldOfViewImageProjectorControl getRectangularFrustrumFieldOfViewImageProjectorControl() {
if (this.rectangularFrustrumFieldOfViewImageProjectorControl == null) {
this.rectangularFrustrumFieldOfViewImageProjectorControl = new RectangularFrustrumFieldOfViewImageProjectorControl(
this.jme3Application, getTopologyNode());
}
return this.rectangularFrustrumFieldOfViewImageProjectorControl;
}
}