blob: 29531c5b3f3ad0f83219ad6b0d4f6a5cf907e067 [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:
<<<<<<< HEAD
* Pierre Allard - initial API and implementation
*
=======
* Pierre Allard - initial API and implementation
*
>>>>>>> refs/heads/eclipse_pa
* SPDX-License-Identifier: EPL-1.0
*******************************************************************************/
package org.eclipse.apogy.core.environment.earth.surface.ui.jme3;
import java.awt.image.BufferedImage;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.media.j3d.LineAttributes;
import javax.media.j3d.Transform3D;
import javax.vecmath.Matrix4d;
import javax.vecmath.Vector3d;
import org.eclipse.apogy.common.ApogyCommonOSGiUtilities;
import org.eclipse.apogy.common.EclipseUtils;
import org.eclipse.apogy.common.images.AbstractEImage;
import org.eclipse.apogy.common.images.ApogyCommonImagesFactory;
import org.eclipse.apogy.common.images.EImage;
import org.eclipse.apogy.common.images.EImagesUtilities;
import org.eclipse.apogy.common.images.URLEImage;
import org.eclipse.apogy.common.topology.ui.jme3.JME3Utilities;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.jme3.asset.AssetManager;
import com.jme3.asset.plugins.FileLocator;
import com.jme3.bounding.BoundingSphere;
import com.jme3.font.BitmapFont;
import com.jme3.font.BitmapText;
import com.jme3.font.Rectangle;
import com.jme3.material.Material;
import com.jme3.math.Matrix3f;
import com.jme3.math.Vector3f;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.renderer.queue.RenderQueue.Bucket;
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.Spatial;
import com.jme3.scene.shape.Sphere;
import com.jme3.texture.Image;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture2D;
import com.jme3.texture.TextureCubeMap;
import com.jme3.texture.plugins.AWTLoader;
import com.jme3.util.BufferUtils;
public class EnvironmentUIJME3Utilities {
private static final Logger Logger = LoggerFactory.getLogger(EnvironmentUIJME3Utilities.class);
private static DecimalFormat decimalFormat = new DecimalFormat("0.0");
private static Map<Double, String> labelMap;
/**
* Creates a Mesh representing a grid in the XY plane.
*
* @param gridSize The size of the grid squares.
* @param planeSize The overall size of the grid.
* @return The Mesh.
*/
public static Mesh createGrid(float gridSize, float planeSize) {
float planeHalfSize = planeSize / 2.0f;
List<Vector3f> verticesList = new ArrayList<Vector3f>();
List<Integer> indexesList = new ArrayList<Integer>();
// Lines in the Y direction
float x = 0;
while (x <= planeHalfSize) {
Vector3f p1 = new Vector3f(x, -planeHalfSize, 0);
Vector3f p2 = new Vector3f(x, planeHalfSize, 0);
verticesList.add(p1);
verticesList.add(p2);
indexesList.add(verticesList.indexOf(p1));
indexesList.add(verticesList.indexOf(p2));
x += gridSize;
}
x = 0.0f;
while (x >= -planeHalfSize) {
Vector3f p1 = new Vector3f(x, -planeHalfSize, 0);
Vector3f p2 = new Vector3f(x, planeHalfSize, 0);
verticesList.add(p1);
verticesList.add(p2);
indexesList.add(verticesList.indexOf(p1));
indexesList.add(verticesList.indexOf(p2));
x -= gridSize;
}
// Lines in the X direction
float y = 0;
while (y <= planeHalfSize) {
Vector3f p1 = new Vector3f(-planeHalfSize, y, 0);
Vector3f p2 = new Vector3f(planeHalfSize, y, 0);
verticesList.add(p1);
verticesList.add(p2);
indexesList.add(verticesList.indexOf(p1));
indexesList.add(verticesList.indexOf(p2));
y += gridSize;
}
y = 0;
while (y >= -planeHalfSize) {
Vector3f p1 = new Vector3f(-planeHalfSize, y, 0);
Vector3f p2 = new Vector3f(planeHalfSize, y, 0);
verticesList.add(p1);
verticesList.add(p2);
indexesList.add(verticesList.indexOf(p1));
indexesList.add(verticesList.indexOf(p2));
y -= gridSize;
}
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();
return mesh;
}
/**
* Creates a square plane in the XY plane centered at the origin.
*
* @param planeSize The overall size of the plane.
* @return The plane mesh.
*/
public static Mesh createPlane(float planeSize) {
float planeHalfSize = planeSize / 2.0f;
List<Vector3f> verticesList = new ArrayList<Vector3f>();
List<Integer> indexesList = new ArrayList<Integer>();
Vector3f p0 = new Vector3f(-planeHalfSize, -planeHalfSize, 0);
Vector3f p1 = new Vector3f(planeHalfSize, -planeHalfSize, 0);
Vector3f p2 = new Vector3f(planeHalfSize, planeHalfSize, 0);
Vector3f p3 = new Vector3f(-planeHalfSize, planeHalfSize, 0);
verticesList.add(p0);
verticesList.add(p1);
verticesList.add(p2);
verticesList.add(p3);
indexesList.add(new Integer(0));
indexesList.add(new Integer(1));
indexesList.add(new Integer(2));
indexesList.add(new Integer(0));
indexesList.add(new Integer(2));
indexesList.add(new Integer(3));
Mesh mesh = new Mesh();
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();
return mesh;
}
/**
* Creates a node that displays the azimuth
*
* @return
*/
public static Node createAzimuthDisplay(final AssetManager assetManager) {
Node node = new Node("Worksite Azimuth Display.");
List<Vector3f> verticesList = new ArrayList<Vector3f>();
List<Integer> indexesList = new ArrayList<Integer>();
// Create the major ticks.
float angle = 0.0f;
while (angle < 360) {
float x = (float) (EarthSurfaceEnvironmentJMEConstants.AZIMUTH_DISPLAY_RADIUS
* Math.cos(Math.toRadians(angle)));
float y = (float) (EarthSurfaceEnvironmentJMEConstants.AZIMUTH_DISPLAY_RADIUS
* Math.sin(Math.toRadians(angle)));
float z0 = 0;
float z1 = EarthSurfaceEnvironmentJMEConstants.AZIMUTH_MAJOR_TICKS_HEIGHT;
Vector3f p0 = new Vector3f(x, y, z0);
Vector3f p1 = new Vector3f(x, y, z1);
// Adds line
verticesList.add(p0);
verticesList.add(p1);
indexesList.add(verticesList.indexOf(p0));
indexesList.add(verticesList.indexOf(p1));
// Adds text.
node.attachChild(createLabel(assetManager, getAzimuthLabelText(360 - angle), x, y, z1 * 1.1f,
Math.toRadians(angle), 0, EarthSurfaceEnvironmentJMEConstants.MAJOR_TICKS_FONT_SIZE));
angle += EarthSurfaceEnvironmentJMEConstants.AZIMUTH_MAJOR_TICK_ANGLE_INTERVAL_IN_DEG;
}
// Create the mid ticks.
angle = 45;
while (angle < 360) {
if (Math.IEEEremainder(angle,
EarthSurfaceEnvironmentJMEConstants.AZIMUTH_MAJOR_TICK_ANGLE_INTERVAL_IN_DEG) != 0) {
float x = (float) (EarthSurfaceEnvironmentJMEConstants.AZIMUTH_DISPLAY_RADIUS
* Math.cos(Math.toRadians(angle)));
float y = (float) (EarthSurfaceEnvironmentJMEConstants.AZIMUTH_DISPLAY_RADIUS
* Math.sin(Math.toRadians(angle)));
float z0 = 0;
float z1 = EarthSurfaceEnvironmentJMEConstants.AZIMUTH_MIDDLE_TICKS_HEIGHT;
Vector3f p0 = new Vector3f(x, y, z0);
Vector3f p1 = new Vector3f(x, y, z1);
// Adds line
verticesList.add(p0);
verticesList.add(p1);
indexesList.add(verticesList.indexOf(p0));
indexesList.add(verticesList.indexOf(p1));
// Adds text.
node.attachChild(createLabel(assetManager, getAzimuthLabelText(360 - angle), x, y, z1 * 3f,
Math.toRadians(angle), 0, EarthSurfaceEnvironmentJMEConstants.MIDDLE_TICKS_FONT_SIZE));
}
angle += EarthSurfaceEnvironmentJMEConstants.AZIMUTH_MAJOR_TICK_ANGLE_INTERVAL_IN_DEG;
}
// Create the minor ticks.
angle = 0;
while (angle < 360) {
if ((Math.IEEEremainder(angle,
EarthSurfaceEnvironmentJMEConstants.AZIMUTH_MAJOR_TICK_ANGLE_INTERVAL_IN_DEG) != 0)
&& (Math.IEEEremainder(angle,
EarthSurfaceEnvironmentJMEConstants.AZIMUTH_MID_TICK_ANGLE_INTERVAL_IN_DEG) != 0)) {
float x = (float) (EarthSurfaceEnvironmentJMEConstants.AZIMUTH_DISPLAY_RADIUS
* Math.cos(Math.toRadians(angle)));
float y = (float) (EarthSurfaceEnvironmentJMEConstants.AZIMUTH_DISPLAY_RADIUS
* Math.sin(Math.toRadians(angle)));
float z0 = 0;
float z1 = (EarthSurfaceEnvironmentJMEConstants.AZIMUTH_MINOR_TICKS_HEIGHT);
Vector3f p0 = new Vector3f(x, y, z0);
Vector3f p1 = new Vector3f(x, y, z1);
// Adds line
verticesList.add(p0);
verticesList.add(p1);
indexesList.add(verticesList.indexOf(p0));
indexesList.add(verticesList.indexOf(p1));
// Adds text.
node.attachChild(createLabel(assetManager, getAzimuthLabelText(360 - angle), x, y, z1 * 3f,
Math.toRadians(angle), 0, EarthSurfaceEnvironmentJMEConstants.MINOR_TICKS_FONT_SIZE));
}
angle += EarthSurfaceEnvironmentJMEConstants.AZIMUTH_MINOR_TICK_ANGLE_INTERVAL_IN_DEG;
}
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();
Geometry azimuthGeometry = new Geometry("Azimuth lines", mesh);
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.setColor("Color", EarthSurfaceEnvironmentJMEConstants.DEFAULT_AZIMUTH_LINES_COLOR.clone());
azimuthGeometry.setMaterial(mat);
azimuthGeometry.setShadowMode(ShadowMode.Off);
node.attachChild(azimuthGeometry);
return node;
}
/**
* Creates the elevation circles display.
*
* @return The transformGroup containing the geometries.
*/
public static Node createElevationCirclesDisplay(final AssetManager assetManager) {
Node node = new Node("Elevation Circles Display.");
// Adds the cross at the zenith
Node zenithCross = createZenithCross(assetManager, 1.0f);
node.attachChild(zenithCross);
// Creates the elevation lines.
double elevationAngleInDeg = EarthSurfaceEnvironmentJMEConstants.ELEVATION_LINES_ANGLE_INTERVAL_IN_DEG;
while (elevationAngleInDeg < 90) {
Node elevationCircle = createElevationCircle(assetManager, elevationAngleInDeg,
EarthSurfaceEnvironmentJMEConstants.ELEVATION_AZIMUTH_INTERVAL_IN_DEG,
EarthSurfaceEnvironmentJMEConstants.ELEVATION_LABEL_AZIMUTH_INTERVAL_IN_DEG, 0.5f,
LineAttributes.PATTERN_DASH);
elevationAngleInDeg += EarthSurfaceEnvironmentJMEConstants.ELEVATION_LINES_ANGLE_INTERVAL_IN_DEG;
node.attachChild(elevationCircle);
}
return node;
}
/**
* Generate a line approximating a circle for a specified elevation angle.
*
* @param elevationAngleInDeg The elevation angle (above horizon), in
* degrees.
* @param azimuthAngleIncrementInDeg The azimuth increment to be used to sweep a
* circle, in degrees.
* @param labelAzimuthIntervalInDeg The azimuth interval of the elevation
* labels.
* @param lineWidth The line width.
* @param linePattern The line pattern to use. See
* LineAttributes.
* @return The line.
*/
public static Node createElevationCircle(final AssetManager assetManager, final double elevationAngleInDeg,
final double azimuthAngleIncrementInDeg, final double labelAzimuthIntervalInDeg, final float lineWidth,
int linePattern) {
Node node = new Node("Elevation Circle");
List<Vector3f> verticesList = new ArrayList<Vector3f>();
List<Integer> indexesList = new ArrayList<Integer>();
// Increment the azimuth angle an generate points along the swept circle.
double azimuthAngleInDeg = 0.0;
while (azimuthAngleInDeg < 360) {
float d = (float) (EarthSurfaceEnvironmentJMEConstants.ELEVATION_DISPLAY_RADIUS
* Math.cos(Math.toRadians(elevationAngleInDeg)));
float x0 = (float) (d * Math.cos(Math.toRadians(azimuthAngleInDeg)));
float x1 = (float) (d * Math.cos(Math.toRadians(
azimuthAngleInDeg + EarthSurfaceEnvironmentJMEConstants.ELEVATION_AZIMUTH_INTERVAL_IN_DEG)));
float y0 = (float) (d * Math.sin(Math.toRadians(azimuthAngleInDeg)));
float y1 = (float) (d * Math.sin(Math.toRadians(
azimuthAngleInDeg + EarthSurfaceEnvironmentJMEConstants.ELEVATION_AZIMUTH_INTERVAL_IN_DEG)));
float z = (float) (EarthSurfaceEnvironmentJMEConstants.ELEVATION_DISPLAY_RADIUS
* Math.sin(Math.toRadians(elevationAngleInDeg)));
// Generate a line between the two points.
Vector3f p0 = new Vector3f(x0, y0, z);
Vector3f p1 = new Vector3f(x1, y1, z);
verticesList.add(p0);
verticesList.add(p1);
indexesList.add(verticesList.indexOf(p0));
indexesList.add(verticesList.indexOf(p1));
azimuthAngleInDeg += azimuthAngleIncrementInDeg;
}
// Adds the elevation labels offseted in azimuth relative to azimuth circles.
float labelAzimuthAngleInDeg = EarthSurfaceEnvironmentJMEConstants.AZIMUTH_LINES_ANGLE_INTERVAL_IN_DEG / 2.0f;
String labelText = getElevationLabelText(elevationAngleInDeg);
while (labelAzimuthAngleInDeg < 360) {
float d = (float) (EarthSurfaceEnvironmentJMEConstants.ELEVATION_DISPLAY_RADIUS
* Math.cos(Math.toRadians(elevationAngleInDeg)));
float x = (float) (d * Math.cos(Math.toRadians(labelAzimuthAngleInDeg)));
float y = (float) (d * Math.sin(Math.toRadians(labelAzimuthAngleInDeg)));
float z = (float) (EarthSurfaceEnvironmentJMEConstants.ELEVATION_DISPLAY_RADIUS
* Math.sin(Math.toRadians(elevationAngleInDeg)));
// Add Text
node.attachChild(createLabel(assetManager, labelText, x, y, z, Math.toRadians(labelAzimuthAngleInDeg),
Math.toRadians(elevationAngleInDeg), EarthSurfaceEnvironmentJMEConstants.MINOR_TICKS_FONT_SIZE));
labelAzimuthAngleInDeg += labelAzimuthIntervalInDeg;
}
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();
Geometry azimuthGeometry = new Geometry("Elevation Circle", mesh);
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.setColor("Color", EarthSurfaceEnvironmentJMEConstants.DEFAULT_AZIMUTH_LINES_COLOR.clone());
azimuthGeometry.setMaterial(mat);
node.attachChild(azimuthGeometry);
return node;
}
public static Node createAzimuthCirclesDisplay(final AssetManager assetManager) {
Node node = new Node("Azimuth Display Circles");
// Adds the cross at the zenith
Node zenithCross = createZenithCross(assetManager, 1.0f);
node.attachChild(zenithCross);
// Creates the elevation lines.
double azimuthAngleInDeg = EarthSurfaceEnvironmentJMEConstants.AZIMUTH_LINES_ANGLE_INTERVAL_IN_DEG;
while (azimuthAngleInDeg <= 360) {
Node azimuthCircle = createAzimuthCircle(assetManager, azimuthAngleInDeg,
EarthSurfaceEnvironmentJMEConstants.AZIMUTH_ELEVATION_INTERVAL_IN_DEG,
EarthSurfaceEnvironmentJMEConstants.AZIMUTH_MIN_ELEVATION_ANGLE_IN_DEG,
EarthSurfaceEnvironmentJMEConstants.AZIMUTH_MAX_ELEVATION_ANGLE_IN_DEG,
EarthSurfaceEnvironmentJMEConstants.AZIMUTH_LABEL_AZIMUTH_INTERVAL_IN_DEG, 0.5f,
LineAttributes.PATTERN_DASH);
azimuthAngleInDeg += EarthSurfaceEnvironmentJMEConstants.AZIMUTH_LINES_ANGLE_INTERVAL_IN_DEG;
node.attachChild(azimuthCircle);
}
return node;
}
public static Node createAzimuthCircle(final AssetManager assetManager, final double azimuthAngleInDeg,
final double elevationAngleIncrementInDeg, final double minimumElevationAngleInDeg,
final double maximumElevationAngleInDeg, final double labelElevationIntervalInDeg, final float lineWidth,
int linePattern) {
Node node = new Node("Azimuth Circle");
List<Vector3f> verticesList = new ArrayList<Vector3f>();
List<Integer> indexesList = new ArrayList<Integer>();
// Increment the elevation angle an generate points along the swept circle.
double elevationAngleInDeg = minimumElevationAngleInDeg;
while (elevationAngleInDeg < maximumElevationAngleInDeg) {
double elevationAngleInDegHigh = elevationAngleInDeg + elevationAngleIncrementInDeg;
if (elevationAngleInDegHigh > maximumElevationAngleInDeg) {
elevationAngleInDegHigh = maximumElevationAngleInDeg;
}
float d0 = (float) (EarthSurfaceEnvironmentJMEConstants.ELEVATION_DISPLAY_RADIUS
* Math.cos(Math.toRadians(elevationAngleInDeg)));
float d1 = (float) (EarthSurfaceEnvironmentJMEConstants.ELEVATION_DISPLAY_RADIUS
* Math.cos(Math.toRadians(elevationAngleInDegHigh)));
float x0 = (float) (d0 * Math.cos(Math.toRadians(azimuthAngleInDeg)));
float x1 = (float) (d1 * Math.cos(Math.toRadians(azimuthAngleInDeg)));
float y0 = (float) (d0 * Math.sin(Math.toRadians(azimuthAngleInDeg)));
float y1 = (float) (d1 * Math.sin(Math.toRadians(azimuthAngleInDeg)));
float z0 = (float) (EarthSurfaceEnvironmentJMEConstants.ELEVATION_DISPLAY_RADIUS
* Math.sin(Math.toRadians(elevationAngleInDeg)));
float z1 = (float) (EarthSurfaceEnvironmentJMEConstants.ELEVATION_DISPLAY_RADIUS
* Math.sin(Math.toRadians(elevationAngleInDegHigh)));
// Generate a line between the two points.
Vector3f p0 = new Vector3f(x0, y0, z0);
Vector3f p1 = new Vector3f(x1, y1, z1);
verticesList.add(p0);
verticesList.add(p1);
indexesList.add(verticesList.indexOf(p0));
indexesList.add(verticesList.indexOf(p1));
elevationAngleInDeg += elevationAngleIncrementInDeg;
}
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();
Geometry azimuthGeometry = new Geometry("Azimuth lines", mesh);
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.setColor("Color", EarthSurfaceEnvironmentJMEConstants.DEFAULT_AZIMUTH_LINES_COLOR.clone());
azimuthGeometry.setMaterial(mat);
azimuthGeometry.setShadowMode(ShadowMode.Off);
node.attachChild(azimuthGeometry);
return node;
}
/**
* Creates a Sky Box using six images found in a specified location.
*
* @param assetManager The AssetManager to use.
* @param texturesLocation The location of the textures. The location should
* containg the following files : west.png, east.png,
* north.png, south.png, up.png, down.png.
* @return The Spatial that represents the Sky.
* @throws Exception If the spatial cannot be initialized.
*/
public static Spatial createSky(AssetManager assetManager, String texturesLocation) throws Exception {
Logger.info("Creating Sky Box using images found in location <" + texturesLocation + ">.");
// TODO : Verifies this will work on Windows.
String urlString = "platform:plugin/" + ApogyCommonOSGiUtilities.INSTANCE.getBundleSymbolicName(EnvironmentUIJME3Utilities.class) + "/assets";
URL url = org.eclipse.core.runtime.FileLocator.toFileURL(new URL(urlString));
assetManager.registerLocator(url.getPath(), FileLocator.class);
// Ensures the texturesLocation ends with a forward slash.
String assetLocation = texturesLocation;
if (!assetLocation.endsWith("/")) {
assetLocation += "/";
}
// Loads the texture for each sides of the box.
Texture west = assetManager.loadTexture(assetLocation + "west.png");
Texture east = assetManager.loadTexture(assetLocation + "east.png");
Texture north = assetManager.loadTexture(assetLocation + "north.png");
Texture south = assetManager.loadTexture(assetLocation + "south.png");
Texture up = assetManager.loadTexture(assetLocation + "up.png");
Texture down = assetManager.loadTexture(assetLocation + "down.png");
// Creates the sky box.
return createSky(assetManager, west, east, north, south, up, down);
}
/**
* Creates a Sky Box using six images used for each side of the box.
*
* @param assetManager The AssetManager to use.
* @param west Texture used for the west side of the box.
* @param east Texture used for the east side of the box.
* @param north Texture used for the north side of the box.
* @param south Texture used for the south side of the box.
* @param up Texture used for the up side of the box.
* @param down Texture used for the down side of the box.
* @return The Spatial that represents the Sky.
* @throws If the spatial cannot be initialized.
*/
public static Spatial createSky(AssetManager assetManager, Texture west, Texture east, Texture north, Texture south,
Texture up, Texture down) throws Exception {
Image westImg = west.getImage();
Image eastImg = east.getImage();
Image northImg = north.getImage();
Image southImg = south.getImage();
Image upImg = up.getImage();
Image downImg = down.getImage();
Image cubeImage = new Image(westImg.getFormat(), westImg.getWidth(), westImg.getHeight(), null);
cubeImage.addData(westImg.getData(0));
cubeImage.addData(eastImg.getData(0));
cubeImage.addData(downImg.getData(0));
cubeImage.addData(upImg.getData(0));
cubeImage.addData(southImg.getData(0));
cubeImage.addData(northImg.getData(0));
TextureCubeMap cubeMap = new TextureCubeMap(cubeImage);
try {
// TODO : Verifies this will work on Windows.
// FIXME: Implement in ApogyCommonOSGiUtilities.
String urlString = "platform:plugin/" + ApogyCommonOSGiUtilities.INSTANCE.getBundleSymbolicName(EnvironmentUIJME3Utilities.class) + "/assets";
URL url = org.eclipse.core.runtime.FileLocator.toFileURL(new URL(urlString));
assetManager.registerLocator(url.getPath(), FileLocator.class);
} catch (Exception e) {
Logger.error(e.getMessage(), e);
}
final Sphere sphereMesh = new Sphere(10, 10, 10, false, true);
Geometry sky = new Geometry("Sky", sphereMesh);
sky.setQueueBucket(Bucket.Sky);
sky.setCullHint(Spatial.CullHint.Never);
sky.setModelBound(new BoundingSphere(Float.POSITIVE_INFINITY, Vector3f.ZERO));
Material skyMat = new Material(assetManager, "MatDefs/EarthSky.j3md");
skyMat.setVector3("NormalScale", Vector3f.UNIT_XYZ);
skyMat.setVector3("SunPosition", new Vector3f());
skyMat.setFloat("Alpha", 1.0f);
skyMat.setTransparent(true);
// FIXME Implement in ApogyCommonOSGi platformURL.
String urlString = "platform:plugin/" + ApogyCommonOSGiUtilities.INSTANCE.getBundleSymbolicName(EnvironmentUIJME3Utilities.class) + "/assets/Textures/sunglow.png";
URL url = EclipseUtils.resolveURL(ApogyCommonOSGiUtilities.INSTANCE.getBundle(EnvironmentUIJME3Utilities.class), urlString);
skyMat.setTexture("SunGlowTexture", EnvironmentUIJME3Utilities.createTexture2D(url, 1.0f));
cubeMap.setMagFilter(Texture.MagFilter.Bilinear);
cubeMap.setMinFilter(Texture.MinFilter.BilinearNoMipMaps);
cubeMap.setAnisotropicFilter(0);
cubeMap.setWrap(Texture.WrapMode.EdgeClamp);
skyMat.setTexture("Texture", cubeMap);
skyMat.setTransparent(true);
sky.setMaterial(skyMat);
// Rotate sky to align with worksite.
Matrix3f skyRot = new Matrix3f();
skyRot.fromAngleAxis((float) Math.toRadians(-90), new Vector3f(1, 0, 0));
sky.setLocalRotation(skyRot);
return sky;
}
/**
* Creates a Texture2D by loading an image from a specified URL.
*
* @param url The URL to the image.
* @param alpha The alpha to apply to the image (0.0 = fully transparent, 1.0
* fully opaque).
* @return The Texture2D.
* @throws An exception if the image could not be loaded.
*/
public static Texture2D createTexture2D(URL url, float alpha) throws Exception {
Texture2D texture2D = null;
URLEImage tmp = ApogyCommonImagesFactory.eINSTANCE.createURLEImage();
tmp.setUrl(url.toString());
BufferedImage image = tmp.asBufferedImage();
AWTLoader awtLoader = new AWTLoader();
if (alpha != 1.0) {
EImage originalImage = ApogyCommonImagesFactory.eINSTANCE.createEImage();
originalImage.setImageContent(image);
AbstractEImage alphaImage = EImagesUtilities.INSTANCE.applyAlpha(originalImage, alpha);
texture2D = new Texture2D(awtLoader.load(alphaImage.asBufferedImage(), false));
} else {
texture2D = new Texture2D(awtLoader.load(image, false));
}
return texture2D;
}
/**
* Creates a Texture2D by loading an image from a specified URL.
*
* @param url The URL to the image.
* @param alpha The alpha to apply to the image (0.0 = fully transparent, 1.0
* fully opaque).
* @return The Texture2D.
* @throws An exception if the image could not be loaded.
*/
public static TextureCubeMap createTextureCubeMap(URL url, float alpha) throws Exception {
TextureCubeMap texture2D = null;
URLEImage tmp = ApogyCommonImagesFactory.eINSTANCE.createURLEImage();
tmp.setUrl(url.toString());
BufferedImage image = tmp.asBufferedImage();
AWTLoader awtLoader = new AWTLoader();
if (alpha != 1.0) {
EImage originalImage = ApogyCommonImagesFactory.eINSTANCE.createEImage();
originalImage.setImageContent(image);
AbstractEImage alphaImage = EImagesUtilities.INSTANCE.applyAlpha(originalImage, alpha);
texture2D = new TextureCubeMap(awtLoader.load(alphaImage.asBufferedImage(), false));
} else {
texture2D = new TextureCubeMap(awtLoader.load(image, false));
}
return texture2D;
}
/**
* Creates a cross at the zenith.
*
* @param crossAngularSpanInDeg The angular span of the cross members, in
* degrees.
* @return The line array representing the cross.
*/
private static Node createZenithCross(final AssetManager assetManager, float crossAngularSpanInDeg) {
Node node = new Node("Zenith Cross.");
List<Vector3f> verticesList = new ArrayList<Vector3f>();
List<Integer> indexesList = new ArrayList<Integer>();
float elevation = (float) (Math.toRadians(90 - (crossAngularSpanInDeg / 2.0f)));
float delta = (float) (EarthSurfaceEnvironmentJMEConstants.ELEVATION_DISPLAY_RADIUS * Math.cos(elevation));
float z = (float) (EarthSurfaceEnvironmentJMEConstants.ELEVATION_DISPLAY_RADIUS * Math.sin(elevation));
Vector3f p0 = new Vector3f(delta, 0, z);
Vector3f p1 = new Vector3f(-delta, 0, z);
verticesList.add(p0);
verticesList.add(p1);
indexesList.add(verticesList.indexOf(p0));
indexesList.add(verticesList.indexOf(p1));
Vector3f p2 = new Vector3f(0, delta, z);
Vector3f p3 = new Vector3f(0, -delta, z);
verticesList.add(p2);
verticesList.add(p3);
indexesList.add(verticesList.indexOf(p2));
indexesList.add(verticesList.indexOf(p3));
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();
Geometry zenithCrossGeometry = new Geometry("Zenith Cross", mesh);
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.setColor("Color", EarthSurfaceEnvironmentJMEConstants.DEFAULT_AZIMUTH_LINES_COLOR.clone());
zenithCrossGeometry.setMaterial(mat);
zenithCrossGeometry.setShadowMode(ShadowMode.Off);
node.attachChild(zenithCrossGeometry);
return node;
}
private static String getAzimuthLabelText(double angle) {
String label = getLabelMap().get(new Double(angle));
if (label == null) {
label = new String(decimalFormat.format(angle) + EarthSurfaceEnvironmentJMEConstants.DEGREE_STRING);
}
return label;
}
private static String getElevationLabelText(double angle) {
return new String(decimalFormat.format(angle) + EarthSurfaceEnvironmentJMEConstants.DEGREE_STRING);
}
private static Map<Double, String> getLabelMap() {
if (labelMap == null) {
labelMap = new HashMap<Double, String>();
labelMap.put(new Double(0), "N");
labelMap.put(new Double(360), "N");
labelMap.put(new Double(45), "NE");
labelMap.put(new Double(90), "E");
labelMap.put(new Double(135), "SE");
labelMap.put(new Double(180), "S");
labelMap.put(new Double(225), "SW");
labelMap.put(new Double(270), "W");
labelMap.put(new Double(315), "NW");
}
return labelMap;
}
private static Node createLabel(final AssetManager assetManager, String text, double x, double y, double z,
double azimuthAngle, double elevationAngle, int fontSize) {
Node root = new Node();
float textWidth = text.length() * fontSize * 0.45f;
// Adds the text.
BitmapFont bitmapFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
BitmapText bitmapText = bitmapFont.createLabel(text);
bitmapText.setSize(fontSize);
bitmapText.setText(text); // crosshairs
bitmapText.setColor(EarthSurfaceEnvironmentJMEConstants.DEFAULT_AZIMUTH_LINES_COLOR.clone());
bitmapText.setBox(new Rectangle(-textWidth / 2.0f, 0, textWidth, 100));
bitmapText.setQueueBucket(RenderQueue.Bucket.Transparent);
// TODO : Make text background transparent.
// bitmapText.setMaterial(arg0);
// Translate the text to the required position
Transform3D translation = new Transform3D();
translation.setTranslation(new Vector3d(x, y, z));
// Rotates the text to make it vertical.
Transform3D t1 = new Transform3D();
t1.rotX(Math.toRadians(90));
// Rotate the text in azimuth.
Transform3D t2 = new Transform3D();
t2.rotY(azimuthAngle - Math.toRadians(90));
// Rotate the text in elevation.
Transform3D t3 = new Transform3D();
t3.rotX(elevationAngle);
// Stacks the transforms
Transform3D t = new Transform3D();
t.mul(translation, t1);
t.mul(t2);
t.mul(t3);
Matrix4d transformMatrix = new Matrix4d();
t.get(transformMatrix);
root.setLocalTransform(JME3Utilities.createTransform(transformMatrix));
root.attachChild(bitmapText);
return root;
}
}