/*******************************************************************************
* Copyright 2012 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.layers.geometry.types.airspace;
import gov.nasa.worldwind.geom.LatLon;
import gov.nasa.worldwind.geom.Vec4;
import gov.nasa.worldwind.render.DrawContext;
import gov.nasa.worldwind.render.airspaces.AirspaceAttributes;
import gov.nasa.worldwind.render.airspaces.Curtain;
import gov.nasa.worldwind.render.airspaces.Geometry;
import gov.nasa.worldwind.util.OGLStackHandler;
import javax.media.opengl.GL2;
/**
* An extension of the {@link Curtain} airspace that can render the generating
* shape as a line at the upper and lower elevations.
*
* @author James Navin (james.navin@ga.gov.au)
*/
public class ShapeOutlineCurtain extends Curtain implements ShapeOutlineAirspace
{
private static final int GEOMETRY_TYPE_ELEMENT = 1;
private static final int GEOMETRY_TYPE_VERTEX = 2;
boolean drawCurtain = true;
boolean drawUpperShapeOutline = false;
boolean drawLowerShapeOutline = false;
public ShapeOutlineCurtain()
{
super();
}
public ShapeOutlineCurtain(AirspaceAttributes attributes)
{
super(attributes);
}
public ShapeOutlineCurtain(Iterable<? extends LatLon> locations)
{
super(locations);
}
@Override
protected void doRenderGeometry(DrawContext dc, String drawStyle)
{
setExpiryTime(0);
if (drawCurtain)
{
super.doRenderGeometry(dc, drawStyle);
}
if (drawUpperShapeOutline)
{
renderUpperShapeOutline(dc);
}
if (drawLowerShapeOutline)
{
renderLowerShapeOutline(dc);
}
}
private void renderUpperShapeOutline(DrawContext dc)
{
Vec4 refCenter = computeReferenceCenter(dc);
Geometry vertexGeometry = getCurtainGeometry(dc, refCenter).getVertexGeometry();
int count = vertexGeometry.getCount(GEOMETRY_TYPE_VERTEX) - 2;
int[] shapeIndices = new int[count];
int i = 0;
while (i < count)
{
shapeIndices[i] = i + 1;
shapeIndices[i + 1] = i + 3;
i += 2;
}
Geometry shapeOutlineElementGeometry = new Geometry();
shapeOutlineElementGeometry.setElementData(GL2.GL_LINES, count, shapeIndices);
drawShapeOutline(dc, refCenter, vertexGeometry, shapeOutlineElementGeometry);
}
private void renderLowerShapeOutline(DrawContext dc)
{
Vec4 refCenter = computeReferenceCenter(dc);
Geometry vertexGeometry = getCurtainGeometry(dc, refCenter).getVertexGeometry();
int count = vertexGeometry.getCount(GEOMETRY_TYPE_VERTEX) - 2;
int[] shapeIndices = new int[count];
int i = 0;
while (i < count)
{
shapeIndices[i] = i;
shapeIndices[i + 1] = i + 2;
i += 2;
}
Geometry shapeOutlineElementGeometry = new Geometry();
shapeOutlineElementGeometry.setElementData(GL2.GL_LINES, count, shapeIndices);
drawShapeOutline(dc, refCenter, vertexGeometry, shapeOutlineElementGeometry);
}
private void drawShapeOutline(DrawContext dc, Vec4 refCenter, Geometry vertexGeometry,
Geometry shapeOutlineElementGeometry)
{
dc.getView().pushReferenceCenter(dc, refCenter);
GL2 gl = dc.getGL().getGL2();
OGLStackHandler stack = new OGLStackHandler();
stack.pushAttrib(gl, GL2.GL_CURRENT_BIT | GL2.GL_HINT_BIT | GL2.GL_ENABLE_BIT | GL2.GL_DEPTH_BUFFER_BIT
| GL2.GL_POINT_BIT | GL2.GL_COLOR_BUFFER_BIT | GL2.GL_LIGHTING_BIT | GL2.GL_POINT_BIT);
stack.pushClientAttrib(gl, GL2.GL_CLIENT_VERTEX_ARRAY_BIT);
try
{
// Points are drawn over the line to prevent gaps forming when
// antialiasing and smoothing is applied to the line
setupDrawParams(dc, gl);
gl.glDepthMask(false);
drawShapeOutlineAsLines(dc, shapeOutlineElementGeometry, vertexGeometry);
drawShapeOutlineAsPoints(dc, shapeOutlineElementGeometry, vertexGeometry);
gl.glDepthMask(true);
drawShapeOutlineAsLines(dc, shapeOutlineElementGeometry, vertexGeometry);
}
finally
{
dc.getView().popReferenceCenter(dc);
stack.pop(gl);
}
}
private void setupDrawParams(DrawContext dc, GL2 gl)
{
gl.glShadeModel(GL2.GL_SMOOTH);
gl.glEnable(GL2.GL_LINE_SMOOTH);
gl.glEnable(GL2.GL_POINT_SMOOTH);
gl.glEnable(GL2.GL_BLEND);
gl.glBlendFunc(GL2.GL_SRC_ALPHA, GL2.GL_ONE_MINUS_SRC_ALPHA);
gl.glHint(GL2.GL_LINE_SMOOTH_HINT, GL2.GL_NICEST);
gl.glHint(GL2.GL_POINT_SMOOTH_HINT, GL2.GL_NICEST);
getAttributes().applyOutline(dc, false);
gl.glPointSize((float) getAttributes().getOutlineWidth());
}
private void drawShapeOutlineAsLines(DrawContext dc, Geometry shapeOutlineElementGeometry, Geometry vertexGeometry)
{
getRenderer().drawGeometry(dc, shapeOutlineElementGeometry, vertexGeometry);
}
private void drawShapeOutlineAsPoints(DrawContext dc, Geometry shapeOutlineElementGeometry, Geometry vertexGeometry)
{
getRenderer().drawGeometry(dc, GL2.GL_POINTS, shapeOutlineElementGeometry.getCount(GEOMETRY_TYPE_ELEMENT),
shapeOutlineElementGeometry.getGLType(GEOMETRY_TYPE_ELEMENT),
shapeOutlineElementGeometry.getBuffer(GEOMETRY_TYPE_ELEMENT), vertexGeometry);
}
private CurtainGeometry getCurtainGeometry(DrawContext dc, Vec4 refCenter)
{
return getCurtainGeometry(dc, locations.size(), locations.toArray(new LatLon[locations.size()]), pathType,
splitThreshold, getAltitudes(), isTerrainConforming(), refCenter);
}
public void setDrawCurtain(boolean drawCurtain)
{
this.drawCurtain = drawCurtain;
}
@Override
public void setDrawUpperShapeOutline(boolean drawUpperShapeOutline)
{
this.drawUpperShapeOutline = drawUpperShapeOutline;
}
@Override
public void setDrawLowerShapeOutline(boolean drawLowerShapeOutline)
{
this.drawLowerShapeOutline = drawLowerShapeOutline;
}
}