/*******************************************************************************
* 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.render;
import gov.nasa.worldwind.geom.LatLon;
import gov.nasa.worldwind.geom.Sector;
import gov.nasa.worldwind.geom.Vec4;
import gov.nasa.worldwind.globes.Globe;
import gov.nasa.worldwind.render.DrawContext;
import gov.nasa.worldwind.render.GeographicSurfaceTileRenderer;
import gov.nasa.worldwind.render.SurfaceTile;
import gov.nasa.worldwind.render.SurfaceTileRenderer;
import gov.nasa.worldwind.terrain.SectorGeometry;
import javax.media.opengl.GL2;
/**
* {@link SurfaceTileRenderer} that supports rendering surface tiles at an
* elevation offset. Also supports rendering surface tiles on flat geometry (ie
* elevation model is ignored).
*
* @author Michael de Hoog (michael.dehoog@ga.gov.au)
*/
public class ExtendedSurfaceTileRenderer extends GeographicSurfaceTileRenderer
{
protected double elevationOffset = 0;
protected boolean ignoreElevation = false;
@Override
public synchronized void renderTiles(DrawContext dc, Iterable<? extends SurfaceTile> tiles)
{
ExtendedDrawContext.applyWireframePolygonMode(dc);
if (ignoreElevation && dc instanceof ExtendedDrawContext)
{
try
{
((ExtendedDrawContext) dc).switchToFlatSurfaceGeometry();
super.renderTiles(dc, tiles);
}
finally
{
((ExtendedDrawContext) dc).switchToStandardSurfaceGeometry();
}
}
else
{
super.renderTiles(dc, tiles);
}
}
@Override
protected void preComputeTextureTransform(DrawContext dc, SectorGeometry sg, SurfaceTileRenderer.Transform t)
{
super.preComputeTextureTransform(dc, sg, t);
//this is a bit dodgy to setup the ModelView matrix in this function, but the superclass calls the
//preComputeTextureTransform function at exactly the right time, which is why it's done here
double exaggeratedOffset = elevationOffset * dc.getVerticalExaggeration();
if (exaggeratedOffset != 0)
{
GL2 gl = dc.getGL().getGL2();
gl.glMatrixMode(GL2.GL_MODELVIEW);
Globe globe = dc.getGlobe();
Sector sector = sg.getSector();
LatLon centroid = sector.getCentroid();
Vec4 cn = globe.computePointFromLocation(centroid).normalize3();
Vec4 v1 = globe.computePointFromPosition(centroid.latitude, sector.getMinLongitude(), 0);
Vec4 v2 = globe.computePointFromPosition(centroid.latitude, sector.getMinLongitude(), exaggeratedOffset);
Vec4 v3 = globe.computePointFromPosition(centroid.latitude, sector.getMaxLongitude(), 0);
Vec4 v4 = globe.computePointFromPosition(centroid.latitude, sector.getMaxLongitude(), exaggeratedOffset);
//translate the tile by the elevation offset
double elevationDelta = v1.distanceTo3(v2);
elevationDelta *= exaggeratedOffset < 0 ? -1 : 1;
Vec4 translation = cn.multiply3(elevationDelta);
gl.glTranslated(translation.x, translation.y, translation.z);
//When translating the tile away from the center of the earth, gaps may appear
//in between tiles. To fix this, scale them too.
double longitudeScale = v2.distanceTo3(v4) / v1.distanceTo3(v3);
gl.glScaled(longitudeScale, longitudeScale, longitudeScale);
}
}
/**
* @return The elevation offset at which to render tiles. Uses the OpenGL
* ModelView matrix to offset tiles.
*/
public double getElevationOffset()
{
return elevationOffset;
}
/**
* Set the elevation offset at which to render tiles.
*
* @param elevationOffset
*/
public void setElevationOffset(double elevationOffset)
{
this.elevationOffset = elevationOffset;
}
/**
* @return Should the elevation model be ignored when rendering tiles? This
* has the effect of rendering surface tiles on a flat surface.
*/
public boolean isIgnoreElevation()
{
return ignoreElevation;
}
/**
* Set whether the elevation model should be ignored when rendering tiles.
*
* @param ignoreElevation
*/
public void setIgnoreElevation(boolean ignoreElevation)
{
this.ignoreElevation = ignoreElevation;
}
}