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