/*******************************************************************************
* Copyright 2014 Geoscience Australia
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package au.gov.ga.earthsci.worldwind.common.view.target;
import gov.nasa.worldwind.View;
import gov.nasa.worldwind.avlist.AVKey;
import gov.nasa.worldwind.geom.Angle;
import gov.nasa.worldwind.geom.Matrix;
import gov.nasa.worldwind.geom.Position;
import gov.nasa.worldwind.geom.Vec4;
import gov.nasa.worldwind.render.DrawContext;
import gov.nasa.worldwind.render.Renderable;
import gov.nasa.worldwind.util.OGLStackHandler;
import java.awt.Rectangle;
import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import au.gov.ga.earthsci.worldwind.common.view.delegate.IDelegateView;
/**
* {@link Renderable} that displays a red/green/blue axis marker at the view's
* center of rotation point. The red axis lies east-west, the green axis lies
* north-south, and the blue axis points to the center of the globe. Heading
* changes always rotate around the blue axis.
*
* @author Michael de Hoog (michael.dehoog@ga.gov.au)
*/
public class AxisRenderable implements Renderable
{
protected final static double NANO = 1e-9;
protected double fadeInTime = 0.2;
protected double fadeOutTime = 0.2;
protected double onTime = 0.1;
protected double size = 0.02;
protected double opacity = 0.7;
protected double triggerTime = 0;
protected double fade = 0;
/**
* @return Fade in time
*/
public double getFadeInTime()
{
return fadeInTime;
}
/**
* Set the length of time it takes for the axis marker to fade in.
*
* @param fadeInTime
*/
public void setFadeInTime(double fadeInTime)
{
this.fadeInTime = Math.max(0, fadeInTime);
}
/**
* @return Fade out time
*/
public double getFadeOutTime()
{
return fadeOutTime;
}
/**
* Set the length of time it takes for the axis marker to fade out.
*
* @param fadeOutTime
*/
public void setFadeOutTime(double fadeOutTime)
{
this.fadeOutTime = Math.max(0, fadeOutTime);
}
/**
* @return Length of time the axis marker stays on for before fading out
*/
public double getOnTime()
{
return onTime;
}
/**
* Set the length of time the axis marker stays on for before fading out.
*
* @param onTime
*/
public void setOnTime(double onTime)
{
this.onTime = Math.max(0, onTime);
}
/**
* @return Marker size
*/
public double getSize()
{
return size;
}
/**
* Set the size of the axis marker. This is defined as a percentage of the
* distance between the view center and the eye point.
*
* @param size
*/
public void setSize(double size)
{
this.size = size;
}
/**
* @return Marker opacity
*/
public double getOpacity()
{
return opacity;
}
/**
* Set the opacity of the axis marker.
*
* @param opacity
*/
public void setOpacity(double opacity)
{
this.opacity = opacity;
}
/**
* Trigger the axis marker visibility. It will stay visible for
* <code>fadeInTime + onTime + fadeOutTime</code>
*/
public void trigger()
{
triggerTime = System.nanoTime() * NANO - fade * fadeInTime;
}
@Override
public void render(DrawContext dc)
{
double currentTime = System.nanoTime() * NANO;
double time = currentTime - triggerTime;
if (time <= 0 || time >= fadeInTime + onTime + fadeOutTime)
{
fade = 0;
}
else if (time < fadeInTime)
{
fade = time / fadeInTime;
}
else if (time < fadeInTime + onTime)
{
fade = 1;
}
else
{
fade = 1 - (time - fadeInTime - onTime) / fadeOutTime;
}
if (fade <= 0)
{
return;
}
renderAxis(dc, fade * opacity);
//make sure it renders again for fading:
dc.getView().firePropertyChange(AVKey.VIEW, null, dc.getView());
}
/**
* Render the axis marker.
*
* @param dc
*/
protected void renderAxis(DrawContext dc, double opacity)
{
View view = dc.getView();
Vec4 centerPoint = view.getCenterPoint();
Vec4 eyePoint = view.getEyePoint();
if (centerPoint == null || eyePoint == null)
{
return;
}
GL2 gl = dc.getGL().getGL2();
OGLStackHandler oglsh = new OGLStackHandler();
try
{
oglsh.pushProjection(gl);
oglsh.pushModelview(gl);
oglsh.pushAttrib(gl, GL.GL_DEPTH_BUFFER_BIT | GL.GL_COLOR_BUFFER_BIT | GL2.GL_LINE_BIT | GL2.GL_CURRENT_BIT);
double distance = eyePoint.distanceTo3(centerPoint);
double length = distance * size;
Rectangle viewport = view.getViewport();
Matrix projection;
if (dc.getView() instanceof IDelegateView)
{
projection = ((IDelegateView) dc.getView()).computeProjection(distance - length, distance + length);
}
else
{
projection = Matrix.fromPerspective(view.getFieldOfView(), viewport.width, viewport.height,
distance - length, distance + length);
}
Position centerPosition = dc.getGlobe().computePositionFromPoint(centerPoint);
Matrix rotation = Matrix.fromRotationXYZ(Angle.ZERO, centerPosition.longitude, Angle.ZERO).multiply(
Matrix.fromRotationXYZ(centerPosition.latitude.multiply(-1), Angle.ZERO, Angle.ZERO));
Matrix modelview = Matrix.fromTranslation(centerPoint).multiply(rotation);
double[] matrixArray = new double[16];
gl.glMatrixMode(GL2.GL_PROJECTION);
projection.toArray(matrixArray, 0, false);
gl.glLoadMatrixd(matrixArray, 0);
gl.glMatrixMode(GL2.GL_MODELVIEW);
modelview.toArray(matrixArray, 0, false);
gl.glMultMatrixd(matrixArray, 0);
gl.glDisable(GL.GL_DEPTH_TEST);
gl.glEnable(GL2.GL_BLEND);
gl.glBlendFunc(GL2.GL_SRC_ALPHA, GL2.GL_ONE_MINUS_SRC_ALPHA);
gl.glLineWidth(2f);
gl.glBegin(GL.GL_LINES);
{
gl.glColor4d(1, 0, 0, opacity);
gl.glVertex3d(0, 0, 0);
gl.glVertex3d(length, 0, 0);
gl.glColor4d(0, 1, 0, opacity);
gl.glVertex3d(0, 0, 0);
gl.glVertex3d(0, length, 0);
gl.glColor4d(0, 0, 1, opacity);
gl.glVertex3d(0, 0, 0);
gl.glVertex3d(0, 0, length);
}
gl.glEnd();
gl.glLineStipple(4, (short) 0xaaaa);
gl.glEnable(GL2.GL_LINE_STIPPLE);
gl.glBegin(GL.GL_LINES);
{
gl.glColor4d(1, 0, 0, opacity);
gl.glVertex3d(0, 0, 0);
gl.glVertex3d(-length, 0, 0);
gl.glColor4d(0, 1, 0, opacity);
gl.glVertex3d(0, 0, 0);
gl.glVertex3d(0, -length, 0);
gl.glColor4d(0, 0, 1, opacity);
gl.glVertex3d(0, 0, 0);
gl.glVertex3d(0, 0, -length);
}
gl.glEnd();
gl.glDisable(GL2.GL_LINE_STIPPLE);
}
finally
{
oglsh.pop(gl);
}
}
}