blob: a813278933d8240116e5e8fc007639cbcd6f09f8 [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.core.ui.jme3.scene_objects;
import java.awt.Color;
import java.awt.Font;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import org.eclipse.apogy.common.images.AbstractEImage;
import org.eclipse.apogy.common.images.EImagesUtilities;
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.AbstractTransformationJME3SceneObject;
import org.eclipse.apogy.core.PositionedResult;
import org.eclipse.apogy.core.ResultNode;
import org.eclipse.apogy.core.invocator.OperationCallResult;
import org.eclipse.apogy.core.ui.ResultNodeSceneObject;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.jme3.asset.AssetManager;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.Node;
import com.jme3.scene.control.BillboardControl;
import com.jme3.util.BufferUtils;
public class ResultNodeJME3Object extends AbstractTransformationJME3SceneObject<ResultNode>
implements ResultNodeSceneObject {
private static final Logger Logger = LoggerFactory.getLogger(ResultNodeJME3Object.class);
public static final float DEFAULT_FLAG_POLE_HEIGHT = 1.0f;
public static final float FLAG_SIZE_PER_PIXEL = 0.005f;
public static final ColorRGBA FLAG_POLE_COLOR = ColorRGBA.Yellow;
public static final ColorRGBA FLAG_BACKGROUND_COLOR = ColorRGBA.Black;
public static final ColorRGBA FLAG_TEXT_COLOR = ColorRGBA.Yellow;
private boolean flagVisible = false;
private float flagPoleHeight = DEFAULT_FLAG_POLE_HEIGHT;
private AssetManager assetManager;
private Node pole = null;
private Geometry poleGeometry = null;
private Node flag = null;
private Geometry flagGeometry = null;
private BillboardControl billboardControl;
public ResultNodeJME3Object(ResultNode node, JME3RenderEngineDelegate jme3RenderEngineDelegate) {
super(node, jme3RenderEngineDelegate);
this.assetManager = this.jme3Application.getAssetManager();
Job job = new Job("ResultNodeJME3Object : Updating Geometry") {
@Override
protected IStatus run(IProgressMonitor monitor) {
updateGeometry();
return Status.OK_STATUS;
}
};
job.schedule();
}
@Override
public List<Geometry> getGeometries() {
List<Geometry> geometries = new ArrayList<Geometry>();
if (this.poleGeometry != null)
geometries.add(this.poleGeometry);
if (this.flagGeometry != null)
geometries.add(this.flagGeometry);
geometries.addAll(super.getGeometries());
return geometries;
}
@Override
public void dispose() {
if (this.billboardControl != null) {
this.billboardControl.setEnabled(false);
this.billboardControl.setSpatial(null);
}
if (this.pole != null) {
this.pole.detachAllChildren();
if (this.pole.getParent() != null) {
this.pole.getParent().detachChild(this.pole);
}
}
super.dispose();
}
@Override
public void setFlagPoleHeight(float poleHeight) {
Logger.info("Setting Flag Pole Height to <" + poleHeight + ">.");
if (poleHeight > 0) {
this.flagPoleHeight = poleHeight;
updateGeometry();
}
}
@Override
public float getFlagPoleHeight() {
return this.flagPoleHeight;
}
@Override
public void setFlagVisible(final boolean visible) {
Logger.info("Setting Flag Visible to <" + visible + ">.");
this.flagVisible = visible;
this.jme3Application.enqueue(new Callable<Object>() {
@Override
public Object call() throws Exception {
if (ResultNodeJME3Object.this.flagVisible) {
if (ResultNodeJME3Object.this.pole != null) {
if (!getAttachmentNode().getChildren().contains(ResultNodeJME3Object.this.pole)) {
getAttachmentNode().attachChild(ResultNodeJME3Object.this.pole);
}
}
} else {
if (ResultNodeJME3Object.this.pole != null)
getAttachmentNode().detachChild(ResultNodeJME3Object.this.pole);
}
return null;
}
});
}
@Override
public boolean isFlagVisible() {
return this.flagVisible;
}
private void updateGeometry() {
this.jme3Application.enqueue(new Callable<Object>() {
@Override
public Object call() throws Exception {
if (ResultNodeJME3Object.this.pole != null)
getAttachmentNode().detachChild(ResultNodeJME3Object.this.pole);
if (ResultNodeJME3Object.this.flag != null)
getAttachmentNode().detachChild(ResultNodeJME3Object.this.flag);
getBillboardControl().setSpatial(null);
// Creates the pole.
ResultNodeJME3Object.this.pole = createPole(ResultNodeJME3Object.this.flagPoleHeight);
if (ResultNodeJME3Object.this.flagVisible) {
getAttachmentNode().attachChild(ResultNodeJME3Object.this.pole);
}
// Creates the flag
ResultNodeJME3Object.this.flag = createFlag(getFlagText(), 16);
ResultNodeJME3Object.this.pole.attachChild(ResultNodeJME3Object.this.flag);
return null;
}
});
}
private Node createPole(float poleHeight) {
List<Vector3f> verticesList = new ArrayList<Vector3f>();
List<Integer> indexesList = new ArrayList<Integer>();
Vector3f p0 = new Vector3f(0, 0, 0);
Vector3f p1 = new Vector3f(0, 0, poleHeight);
verticesList.add(p0);
verticesList.add(p1);
indexesList.add(verticesList.indexOf(p0));
indexesList.add(verticesList.indexOf(p1));
Mesh mesh = new Mesh();
mesh.setMode(Mesh.Mode.Lines);
mesh.setBuffer(com.jme3.scene.VertexBuffer.Type.Position, 3,
BufferUtils.createFloatBuffer(JME3Utilities.convertToFloatArray(verticesList)));
mesh.setBuffer(com.jme3.scene.VertexBuffer.Type.Index, 2,
BufferUtils.createIntBuffer(JME3Utilities.convertToIntArray(indexesList)));
mesh.updateBound();
mesh.updateCounts();
this.poleGeometry = new Geometry("Pole", mesh);
Material mat = new Material(this.assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.setColor("Color", FLAG_POLE_COLOR.clone());
this.poleGeometry.setMaterial(mat);
Node node = new Node("Pole.");
node.setShadowMode(ShadowMode.Off);
node.attachChild(this.poleGeometry);
return node;
}
private String getFlagText() {
String text = "?";
if (getTopologyNode() != null) {
if (getTopologyNode().getDescription() != null) {
text = getTopologyNode().getDescription();
} else if (getTopologyNode().getResult() != null) {
if (getTopologyNode().getResult().getTime() != null) {
text = getTopologyNode().getResult().getTime().toString();
}
}
}
return text;
}
private Node createFlag(String text, int fontSize) {
Node node = new Node("Flag");
node.setShadowMode(ShadowMode.Off);
Node flagAttachmentPoint = new Node("Flag Attachment Point");
flagAttachmentPoint.setLocalTranslation(0, 0, this.flagPoleHeight);
node.attachChild(flagAttachmentPoint);
// First, create the image that will hold the text.
Font font = new Font("Serif", Font.BOLD, fontSize);
BufferedImage bufferedImage = createTextImage(text, font, 2);
// Based on the image size, create the flag geometry.
float flagWidth = FLAG_SIZE_PER_PIXEL * bufferedImage.getWidth();
float flagHeight = FLAG_SIZE_PER_PIXEL * bufferedImage.getHeight();
Mesh flagMesh = createFlagMesh(flagWidth, flagHeight);
this.flagGeometry = new Geometry("Flag Geometry", flagMesh);
Material mat = JME3Utilities.createMaterial(bufferedImage, this.assetManager);
this.flagGeometry.setMaterial(mat);
flagAttachmentPoint.addControl(getBillboardControl());
flagAttachmentPoint.attachChild(this.flagGeometry);
return node;
}
private Mesh createFlagMesh(float flagWidth, float flagHeight) {
Vector3f[] vertices = new Vector3f[4];
vertices[0] = new Vector3f(0, 0, 0);
vertices[1] = new Vector3f(flagWidth, 0, 0);
vertices[2] = new Vector3f(0, flagHeight, 0);
vertices[3] = new Vector3f(flagWidth, flagHeight, 0);
int[] indexes = { 2, 0, 1, 1, 3, 2 };
Vector2f[] texCoord = new Vector2f[4];
texCoord[0] = new Vector2f(0, 0);
texCoord[1] = new Vector2f(1, 0);
texCoord[2] = new Vector2f(0, 1);
texCoord[3] = new Vector2f(1, 1);
Mesh mesh = new Mesh();
mesh.setBuffer(com.jme3.scene.VertexBuffer.Type.Position, 3, BufferUtils.createFloatBuffer(vertices));
mesh.setBuffer(com.jme3.scene.VertexBuffer.Type.TexCoord, 2, BufferUtils.createFloatBuffer(texCoord));
mesh.setBuffer(com.jme3.scene.VertexBuffer.Type.Index, 3, BufferUtils.createIntBuffer(indexes));
mesh.updateBound();
mesh.updateCounts();
return mesh;
}
private BillboardControl getBillboardControl() {
if (this.billboardControl == null) {
this.billboardControl = new BillboardControl();
this.billboardControl.setAlignment(BillboardControl.Alignment.Screen);
}
return this.billboardControl;
}
private boolean isResultHasError() {
if (getTopologyNode() != null && getTopologyNode().getResult() instanceof PositionedResult) {
PositionedResult positionedResult = getTopologyNode().getResult();
if (positionedResult instanceof OperationCallResult) {
OperationCallResult operationCallResult = (OperationCallResult) positionedResult;
if (operationCallResult.getExceptionContainer() != null) {
if (operationCallResult.getExceptionContainer().getException() != null) {
return true;
}
}
}
}
return false;
}
private ColorRGBA getFlagBackgroundColor() {
if (isResultHasError()) {
return ColorRGBA.Red;
} else {
return ColorRGBA.Black;
}
}
private ColorRGBA getTextColor() {
if (isResultHasError()) {
return ColorRGBA.Black;
} else {
return ColorRGBA.Green;
}
}
private BufferedImage createTextImage(String text, Font font, int borderWidth) {
Color textColor = JME3Utilities.convertToAWTColor(getTextColor());
Color backgroundColor = JME3Utilities.convertToAWTColor(getFlagBackgroundColor());
AbstractEImage original = EImagesUtilities.INSTANCE.createTextImage(text, font, textColor, backgroundColor,
borderWidth);
int[] borderColor = JME3Utilities.convertToColorIntRGBA(FLAG_POLE_COLOR);
AbstractEImage imageWithBorder = EImagesUtilities.INSTANCE.addBorder(original, borderWidth, borderColor[0],
borderColor[1], borderColor[2]);
return imageWithBorder.asBufferedImage();
}
}