blob: c0cce4099475e497b2070daf5723b1b913b9b5a0 [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 - initial API and implementation
*
* SPDX-License-Identifier: EPL-1.0
*
*******************************************************************************/
package org.eclipse.apogy.common.geometry.data3d.ui.jme3.scene_objects;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import javax.vecmath.Point3d;
import org.eclipse.apogy.common.geometry.data3d.ApogyCommonGeometryData3DPackage;
import org.eclipse.apogy.common.geometry.data3d.CartesianPositionCoordinates;
import org.eclipse.apogy.common.geometry.data3d.CartesianTriangularMesh;
import org.eclipse.apogy.common.geometry.data3d.ColoredCartesianTriangularMesh;
import org.eclipse.apogy.common.geometry.data3d.ui.jme3.Data3dJME3Utilities;
import org.eclipse.apogy.common.geometry.data3d.ui.preferences.MRTData3DUIPreferencesConstants;
import org.eclipse.apogy.common.geometry.data3d.ui.scene_objects.CartesianTriangularMeshSceneObject;
import org.eclipse.apogy.common.geometry.data3d.ui.scene_objects.ColoredCartesianTriangularMeshSceneObject;
import org.eclipse.apogy.common.topology.ApogyCommonTopologyPackage;
import org.eclipse.apogy.common.topology.ContentNode;
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.apogy.common.topology.ui.jme3.scene_objects.DefaultJME3SceneObject;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
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.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferenceConverter;
import org.eclipse.swt.graphics.RGB;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.jme3.asset.AssetManager;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
/**
* JME3 Scene Object for ColoredCartesianTriangularMeshSceneObject.
*
* @author pallard
*
*/
public class ColoredCartesianTriangularMeshJM3SceneObject
extends DefaultJME3SceneObject<ContentNode<ColoredCartesianTriangularMesh>>
implements CartesianTriangularMeshSceneObject, ColoredCartesianTriangularMeshSceneObject {
private static final Logger Logger = LoggerFactory.getLogger(ColoredCartesianTriangularMeshJM3SceneObject.class);
private boolean useShading = true;
private boolean overrideColor = false;
private ColorRGBA meshColor = getDefaultMeshColor();
private RGB rgb;
private MeshPresentationMode meshPresentationMode = MeshPresentationMode.SURFACE;
private Adapter contentAdapter = null;
private Adapter pointsAdapter = null;
private Adapter polygonsAdapter = null;
private Point3d centroid = null;
private CartesianTriangularMesh mesh = null;
private AssetManager assetManager;
private Geometry meshGeometry = null;
private com.jme3.scene.Mesh jme3mMesh = null;
public ColoredCartesianTriangularMeshJM3SceneObject(ContentNode<ColoredCartesianTriangularMesh> meshContentNode,
JME3RenderEngineDelegate jme3RenderEngineDelegate) {
super(meshContentNode, jme3RenderEngineDelegate);
if (meshContentNode == null || jme3RenderEngineDelegate == null) {
throw new IllegalArgumentException();
}
this.assetManager = this.jme3Application.getAssetManager();
this.mesh = meshContentNode.getContent();
// Updates the geometry.
Job job = new Job("TriangularMeshJM3SceneObject : Updating Geometry.") {
@Override
protected IStatus run(IProgressMonitor monitor) {
// Creates the new mesh.
final Mesh newMesh = Data3dJME3Utilities.createMesh(
ColoredCartesianTriangularMeshJM3SceneObject.this.mesh,
ColoredCartesianTriangularMeshJM3SceneObject.this.overrideColor,
ColoredCartesianTriangularMeshJM3SceneObject.this.meshColor);
ColoredCartesianTriangularMeshJM3SceneObject.this.jme3Application.enqueue(new Callable<Object>() {
@Override
public Object call() throws Exception {
updateGeometryInternal(newMesh);
setPresentationMode(ColoredCartesianTriangularMeshJM3SceneObject.this.meshPresentationMode);
return null;
}
});
return Status.OK_STATUS;
}
};
job.schedule();
meshContentNode.eAdapters().add(getContentAdapter());
this.mesh = meshContentNode.getContent();
this.mesh.eAdapters().add(getPointsAdapter());
this.mesh.eAdapters().add(getPolygonsAdapter());
}
@Override
public void updateGeometry(float tpf) {
final Mesh newMesh = Data3dJME3Utilities.createMesh(this.mesh, this.overrideColor, this.meshColor);
updateGeometryInternal(newMesh);
}
@Override
public Point3d getCentroid() {
if (this.centroid == null) {
this.centroid = new Point3d(0.0, 0.0, 0.0);
if (this.mesh != null && this.mesh.getPoints().size() > 0) {
for (CartesianPositionCoordinates point : this.mesh.getPoints()) {
this.centroid.x += point.getX();
this.centroid.y += point.getY();
this.centroid.z += point.getZ();
}
this.centroid.scale(1.0 / this.mesh.getPoints().size());
}
}
return this.centroid;
}
@Override
public void setColor(RGB rgb) {
Logger.info("Setting color to <" + rgb + ">.");
this.rgb = rgb;
this.meshColor = JME3Utilities.convertToColorRGBA(rgb);
// Change the material in the Renderer thread.
this.jme3Application.enqueue(new Callable<Object>() {
@Override
public Object call() throws Exception {
if (ColoredCartesianTriangularMeshJM3SceneObject.this.meshGeometry != null) {
final Mesh newMesh = Data3dJME3Utilities.createMesh(
ColoredCartesianTriangularMeshJM3SceneObject.this.mesh,
ColoredCartesianTriangularMeshJM3SceneObject.this.overrideColor,
ColoredCartesianTriangularMeshJM3SceneObject.this.meshColor);
updateGeometryInternal(newMesh);
Material mat = createMaterial();
if (ColoredCartesianTriangularMeshJM3SceneObject.this.useShading) {
mat.setColor("Diffuse", ColoredCartesianTriangularMeshJM3SceneObject.this.meshColor);
mat.setColor("Ambient", ColoredCartesianTriangularMeshJM3SceneObject.this.meshColor);
mat.setColor("Specular", ColoredCartesianTriangularMeshJM3SceneObject.this.meshColor);
} else {
mat.setColor("Color", ColoredCartesianTriangularMeshJM3SceneObject.this.meshColor);
}
ColoredCartesianTriangularMeshJM3SceneObject.this.meshGeometry.setMaterial(mat);
}
return null;
}
});
}
@Override
public RGB getColor() {
return this.rgb;
}
@Override
public void setOverrideColor(boolean overrideColor) {
Logger.info("Setting Override Color flag to " + overrideColor);
this.overrideColor = overrideColor;
// Creates the new mesh.
final Mesh newMesh = Data3dJME3Utilities.createMesh(this.mesh, overrideColor, this.meshColor);
// Updates mesh in renderer thread.
this.jme3Application.enqueue(new Callable<Object>() {
@Override
public Object call() throws Exception {
updateGeometryInternal(newMesh);
setPresentationMode(ColoredCartesianTriangularMeshJM3SceneObject.this.meshPresentationMode);
return null;
}
});
}
@Override
public List<Geometry> getGeometries() {
List<Geometry> geometries = new ArrayList<Geometry>();
geometries.add(this.meshGeometry);
return geometries;
}
@Override
public void dispose() {
// Unregister listener from content node.
if (getTopologyNode() != null) {
getTopologyNode().eAdapters().remove(getContentAdapter());
}
// Unregister listeners from mesh.
if (this.mesh != null) {
this.mesh.eAdapters().remove(getPointsAdapter());
this.mesh.eAdapters().remove(getPolygonsAdapter());
}
// Removes references.
this.assetManager = null;
this.centroid = null;
this.mesh = null;
this.pointsAdapter = null;
this.contentAdapter = null;
super.dispose();
}
@Override
public void setPresentationMode(MeshPresentationMode mode) {
Logger.info("Setting presentation mode to " + mode);
this.meshPresentationMode = mode;
if (this.meshGeometry != null && this.meshGeometry.getMaterial() != null) {
this.jme3Application.enqueue(new Callable<Object>() {
@Override
public Object call() throws Exception {
switch (ColoredCartesianTriangularMeshJM3SceneObject.this.meshPresentationMode.getValue()) {
case MeshPresentationMode.SURFACE_VALUE:
ColoredCartesianTriangularMeshJM3SceneObject.this.meshGeometry.getMaterial()
.getAdditionalRenderState().setWireframe(false);
if (ColoredCartesianTriangularMeshJM3SceneObject.this.meshGeometry.getMesh() != null)
ColoredCartesianTriangularMeshJM3SceneObject.this.meshGeometry.getMesh()
.setMode(com.jme3.scene.Mesh.Mode.Triangles);
break;
case MeshPresentationMode.WIREFRAME_VALUE:
ColoredCartesianTriangularMeshJM3SceneObject.this.meshGeometry.getMaterial()
.getAdditionalRenderState().setWireframe(true);
if (ColoredCartesianTriangularMeshJM3SceneObject.this.meshGeometry.getMesh() != null)
ColoredCartesianTriangularMeshJM3SceneObject.this.meshGeometry.getMesh()
.setMode(com.jme3.scene.Mesh.Mode.Triangles);
break;
case MeshPresentationMode.POINTS_VALUE:
ColoredCartesianTriangularMeshJM3SceneObject.this.meshGeometry.getMaterial()
.getAdditionalRenderState().setWireframe(false);
if (ColoredCartesianTriangularMeshJM3SceneObject.this.meshGeometry.getMesh() != null)
ColoredCartesianTriangularMeshJM3SceneObject.this.meshGeometry.getMesh()
.setMode(com.jme3.scene.Mesh.Mode.Points);
break;
default:
break;
}
return null;
}
});
} else {
Logger.error("Failed to set presentation mode to " + mode);
}
}
@Override
public void setPointSize(int pointSize) {
Logger.info("Setting point size to " + pointSize);
if (this.jme3mMesh != null) {
this.jme3Application.enqueue(new Callable<Object>() {
@Override
public Object call() throws Exception {
ColoredCartesianTriangularMeshJM3SceneObject.this.jme3mMesh.setPointSize(pointSize);
return null;
}
});
}
}
@Override
public void setUseShading(boolean useShading) {
Logger.info("Setting use shading to " + useShading);
this.useShading = useShading;
// Update material.
if (this.jme3mMesh != null) {
this.jme3Application.enqueue(new Callable<Object>() {
@Override
public Object call() throws Exception {
Material mat = createMaterial();
if (useShading) {
mat.setColor("Diffuse", ColoredCartesianTriangularMeshJM3SceneObject.this.meshColor);
mat.setColor("Ambient", ColoredCartesianTriangularMeshJM3SceneObject.this.meshColor);
mat.setColor("Specular", ColoredCartesianTriangularMeshJM3SceneObject.this.meshColor);
} else {
// mat.setColor("Color", meshColor);
}
ColoredCartesianTriangularMeshJM3SceneObject.this.meshGeometry.setMaterial(mat);
return null;
}
});
}
}
/**
* Updates geometry. NOT THREAD SAFE.
*/
private void updateGeometryInternal(final Mesh newMesh) {
try {
if (!this.busy) {
this.busy = true;
// Invalidate the centroid.
this.centroid = null;
// Detach previous geometry if required.
if (this.meshGeometry != null) {
getAttachmentNode().detachChild(this.meshGeometry);
}
this.jme3mMesh = newMesh;
// Updates the mesh if applicable.
if (this.jme3mMesh != null) {
if (getTopologyNode().getNodeId() != null) {
this.meshGeometry = new Geometry(getTopologyNode().getNodeId(), this.jme3mMesh);
} else {
this.meshGeometry = new Geometry("CartesianTriangularMesh", this.jme3mMesh);
}
this.meshGeometry.setMaterial(createMaterial());
this.meshGeometry.setShadowMode(ShadowMode.CastAndReceive);
getAttachmentNode().attachChild(this.meshGeometry);
}
this.busy = false;
}
} catch (Throwable t) {
Logger.error(t.getMessage(), t);
}
}
private Material createMaterial() {
Material mat = null;
if (this.useShading) {
mat = new Material(this.assetManager, "Common/MatDefs/Light/Lighting.j3md");
if (this.meshColor != null) {
mat.setColor("Diffuse", this.meshColor);
mat.setColor("Ambient", this.meshColor);
mat.setColor("Specular", this.meshColor);
}
mat.setFloat("Shininess", 64f);
mat.setBoolean("VertexLighting", true);
mat.setBoolean("UseVertexColor", true);
} else {
mat = new Material(this.assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
if (this.meshColor != null) {
mat.setColor("Color", this.meshColor);
}
mat.setBoolean("VertexColor", true);
}
return mat;
}
private ColorRGBA getDefaultMeshColor() {
ColorRGBA rgba = null;
IPreferenceStore store = org.eclipse.apogy.common.geometry.data3d.ui.Activator.getDefault()
.getPreferenceStore();
// Change color.
RGB rgb = PreferenceConverter.getColor(store, MRTData3DUIPreferencesConstants.DEFAULT_TRIANGULAR_MESH_COLOR_ID);
if (rgb != null) {
rgba = JME3Utilities.convertToColorRGBA(rgb);
} else {
rgba = new ColorRGBA(1.0f, 0f, 0.0f, 1.0f);
}
return rgba;
}
private Adapter getPointsAdapter() {
if (this.pointsAdapter == null) {
this.pointsAdapter = new AdapterImpl() {
@Override
public void notifyChanged(Notification msg) {
int featureId = msg.getFeatureID(CartesianTriangularMesh.class);
if (featureId == ApogyCommonGeometryData3DPackage.CARTESIAN_TRIANGULAR_MESH__POINTS) {
if (msg.getEventType() == Notification.ADD_MANY
|| msg.getEventType() == Notification.REMOVE_MANY) {
requestUpdate();
} else if (msg.getEventType() == Notification.ADD
|| msg.getEventType() == Notification.REMOVE) {
requestUpdate();
}
}
}
};
}
return this.pointsAdapter;
}
private Adapter getPolygonsAdapter() {
if (this.polygonsAdapter == null) {
this.polygonsAdapter = new AdapterImpl() {
@Override
public void notifyChanged(Notification msg) {
int featureId = msg.getFeatureID(CartesianTriangularMesh.class);
if (featureId == ApogyCommonGeometryData3DPackage.CARTESIAN_TRIANGULAR_MESH__POLYGONS) {
if (msg.getEventType() == Notification.ADD_MANY
|| msg.getEventType() == Notification.REMOVE_MANY) {
requestUpdate();
} else if (msg.getEventType() == Notification.ADD
|| msg.getEventType() == Notification.REMOVE) {
requestUpdate();
}
}
}
};
}
return this.polygonsAdapter;
}
private Adapter getContentAdapter() {
if (this.contentAdapter == null) {
this.contentAdapter = new AdapterImpl() {
@Override
public void notifyChanged(Notification msg) {
int featureId = msg.getFeatureID(ContentNode.class);
if (featureId == ApogyCommonTopologyPackage.CONTENT_NODE__CONTENT) {
try {
// Remove adapters from old mesh
ColoredCartesianTriangularMeshJM3SceneObject.this.mesh.eAdapters()
.remove(getPointsAdapter());
ColoredCartesianTriangularMeshJM3SceneObject.this.mesh.eAdapters()
.remove(getPolygonsAdapter());
// Updates the mesh
ColoredCartesianTriangularMeshJM3SceneObject.this.mesh = (CartesianTriangularMesh) msg
.getNewValue();
if (ColoredCartesianTriangularMeshJM3SceneObject.this.mesh != null) {
// Register listeners to new mesh.
ColoredCartesianTriangularMeshJM3SceneObject.this.mesh.eAdapters()
.add(getPointsAdapter());
ColoredCartesianTriangularMeshJM3SceneObject.this.mesh.eAdapters()
.add(getPolygonsAdapter());
if (!ColoredCartesianTriangularMeshJM3SceneObject.this.busy) {
requestUpdate();
} else {
Logger.warn("ColoredCartesianTriangularMeshJM3SceneObject is busy.");
}
} else {
Logger.error("The mesh is Null.");
}
} catch (Exception e) {
Logger.error("Failed to update content of ColoredCartesianTriangularMesh.", e);
}
}
}
};
}
return this.contentAdapter;
}
}