/*
Copyright (C) 2001, 2006 United States Government
as represented by the Administrator of the
National Aeronautics and Space Administration.
All Rights Reserved.
*/
package gov.nasa.worldwind.render;
import com.sun.opengl.util.texture.TextureCoords;
import gov.nasa.worldwind.*;
import gov.nasa.worldwind.cache.TextureCache;
import gov.nasa.worldwind.geom.*;
import gov.nasa.worldwind.globes.*;
import gov.nasa.worldwind.layers.LayerList;
import gov.nasa.worldwind.pick.*;
import gov.nasa.worldwind.util.*;
import gov.nasa.worldwind.View;
import javax.media.opengl.*;
import javax.media.opengl.glu.GLU;
import java.awt.*;
import java.util.*;
/**
* @author Tom Gaskins
* @version $Id: DrawContextImpl.java 5113 2008-04-21 23:46:50Z tgaskins $
*/
public class DrawContextImpl extends WWObjectImpl implements DrawContext
{
private GLContext glContext;
private GLU glu = new GLU();
private View view;
private Model model;
private Globe globe;
private double verticalExaggeration = 1d;
private Sector visibleSector;
private SectorGeometryList surfaceGeometry;
private PickedObjectList pickedObjects = new PickedObjectList();
private int uniquePickNumber = 0;
private Color clearColor = new Color(0, 0, 0, 0);
private boolean isPickingMode = false;
private Point pickPoint = null;
private Point viewportCenterScreenPoint = null;
private Position viewportCenterPosition = null;
private Vec4 viewportCenterSurfacePoint = null;
private Vec4 viewportCenterGlobePoint = null;
private int numTextureUnits = -1;
private SurfaceTileRenderer geographicSurfaceTileRenderer = new GeographicSurfaceTileRenderer();
private AnnotationRenderer annotationRenderer = new BasicAnnotationRenderer();
private TextureCache textureCache;
private TextRendererCache textRendererCache;
private Set<String> perFrameStatisticsKeys;
private Collection<PerformanceStatistic> perFrameStatistics;
PriorityQueue<OrderedRenderable> orderedRenderables =
new PriorityQueue<OrderedRenderable>(100, new Comparator<OrderedRenderable>()
{
public int compare(OrderedRenderable orA, OrderedRenderable orB)
{
double eA = orA.getDistanceFromEye();
double eB = orB.getDistanceFromEye();
return eA > eB ? -1 : eA == eB ? 0 : 1;
}
});
public void reinitialize()
{
if (this.geographicSurfaceTileRenderer != null)
this.geographicSurfaceTileRenderer.dispose();
this.geographicSurfaceTileRenderer = new GeographicSurfaceTileRenderer();
this.pickedObjects.clear();
this.perFrameStatistics.clear();
this.perFrameStatisticsKeys.clear();
this.annotationRenderer = new BasicAnnotationRenderer();
}
/**
* Free internal resources held by this draw context.
* A GL context must be current when this method is called.
*
* @throws javax.media.opengl.GLException - If an OpenGL context is not current when this method is called.
*/
public void dispose()
{
this.geographicSurfaceTileRenderer.dispose();
}
public final GL getGL()
{
return this.getGLContext().getGL();
}
public final GLU getGLU()
{
return this.glu;
}
public final GLContext getGLContext()
{
return this.glContext;
}
public final int getDrawableHeight()
{
return this.getGLDrawable().getHeight();
}
public final int getDrawableWidth()
{
return this.getGLDrawable().getWidth();
}
public final GLDrawable getGLDrawable()
{
return this.getGLContext().getGLDrawable();
}
public final void initialize(GLContext glContext)
{
if (glContext == null)
{
String message = Logging.getMessage("nullValue.GLContextIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
this.glContext = glContext;
this.visibleSector = null;
if (this.surfaceGeometry != null)
this.surfaceGeometry.clear();
this.surfaceGeometry = null;
this.pickedObjects.clear();
this.orderedRenderables.clear();
this.uniquePickNumber = 0;
if (this.numTextureUnits < 1)
this.numTextureUnits = queryMaxTextureUnits(glContext);
}
private static int queryMaxTextureUnits(GLContext glContext)
{
int[] mtu = new int[1];
glContext.getGL().glGetIntegerv(GL.GL_MAX_TEXTURE_UNITS, mtu, 0);
return mtu[0];
}
public final void setModel(Model model)
{
this.model = model;
if (this.model == null)
return;
Globe g = this.model.getGlobe();
if (g != null)
this.globe = g;
}
public final Model getModel()
{
return this.model;
}
public final LayerList getLayers()
{
return this.model.getLayers();
}
public final Sector getVisibleSector()
{
return this.visibleSector;
}
public final void setVisibleSector(Sector s)
{
// don't check for null - it is possible that no globe is active, no view is active, no sectors visible, etc.
this.visibleSector = s;
}
public void setSurfaceGeometry(SectorGeometryList surfaceGeometry)
{
this.surfaceGeometry = surfaceGeometry;
}
public SectorGeometryList getSurfaceGeometry()
{
return surfaceGeometry;
}
public final Globe getGlobe()
{
return this.globe != null ? this.globe : this.model.getGlobe();
}
public final void setView(View view)
{
this.view = view;
}
public final View getView()
{
return this.view;
}
public final void setGLContext(GLContext glContext)
{
if (glContext == null)
{
String message = Logging.getMessage("nullValue.GLContextIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
this.glContext = glContext;
}
public final double getVerticalExaggeration()
{
return verticalExaggeration;
}
public final void setVerticalExaggeration(double verticalExaggeration)
{
this.verticalExaggeration = verticalExaggeration;
}
public TextureCache getTextureCache()
{
return textureCache;
}
public void setTextureCache(TextureCache textureCache)
{
if (textureCache == null)
{
String msg = Logging.getMessage("nullValue.TextureCacheIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
this.textureCache = textureCache;
}
public TextRendererCache getTextRendererCache()
{
return textRendererCache;
}
public void setTextRendererCache(TextRendererCache textRendererCache)
{
if (textRendererCache == null)
{
String msg = Logging.getMessage("nullValue.TextRendererCacheIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
this.textRendererCache = textRendererCache;
}
public AnnotationRenderer getAnnotationRenderer()
{
return annotationRenderer;
}
public void setAnnotationRenderer(AnnotationRenderer ar)
{
if (ar == null)
{
String msg = Logging.getMessage("nullValue.AnnotationRendererIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
annotationRenderer = ar;
}
public Point getPickPoint()
{
return pickPoint;
}
public void setPickPoint(Point pickPoint)
{
this.pickPoint = pickPoint;
}
public Point getViewportCenterScreenPoint()
{
return viewportCenterScreenPoint;
}
public void setViewportCenterScreenPoint(Point viewportCenterScreenPoint)
{
this.viewportCenterScreenPoint = viewportCenterScreenPoint;
}
public Position getViewportCenterPosition()
{
return viewportCenterPosition;
}
public void setViewportCenterPosition(Position viewportCenterPosition)
{
this.viewportCenterPosition = viewportCenterPosition;
this.viewportCenterGlobePoint = null;
this.viewportCenterSurfacePoint = null;
if (viewportCenterPosition != null)
{
if (this.getGlobe() != null)
this.viewportCenterGlobePoint = this.getGlobe().computePointFromPosition(
this.viewportCenterPosition.getLatitude(), this.viewportCenterPosition.getLongitude(), 0d);
if (this.getSurfaceGeometry() != null)
this.viewportCenterSurfacePoint =
this.getSurfaceGeometry().getSurfacePoint(this.viewportCenterPosition);
}
}
public Vec4 getViewportCenterSurfacePoint()
{
return viewportCenterSurfacePoint;
}
public Vec4 getViewportCenterGlobePoint()
{
return viewportCenterGlobePoint;
}
/**
* Add picked objects to the current list of picked objects.
*
* @param pickedObjects the list of picked objects to add
* @throws IllegalArgumentException if <code>pickedObjects is null</code>
*/
public void addPickedObjects(PickedObjectList pickedObjects)
{
if (pickedObjects == null)
{
String msg = Logging.getMessage("nullValue.PickedObjectList");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
if (this.pickedObjects == null)
{
this.pickedObjects = pickedObjects;
return;
}
for (PickedObject po : pickedObjects)
{
this.pickedObjects.add(po);
}
}
/**
* Adds a single insatnce of the picked object to the current picked-object list
*
* @param pickedObject the object to add
* @throws IllegalArgumentException if <code>picked Object is null</code>
*/
public void addPickedObject(PickedObject pickedObject)
{
if (null == pickedObject)
{
String msg = Logging.getMessage("nullValue.PickedObject");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
if (null == this.pickedObjects)
this.pickedObjects = new PickedObjectList();
this.pickedObjects.add(pickedObject);
}
public PickedObjectList getPickedObjects()
{
return this.pickedObjects;
}
public Color getUniquePickColor()
{
this.uniquePickNumber++;
int clearColorCode = this.getClearColor().getRGB();
if (clearColorCode == this.uniquePickNumber)
this.uniquePickNumber++;
if (this.uniquePickNumber >= 0x00FFFFFF)
{
this.uniquePickNumber = 1; // no black, no white
if (clearColorCode == this.uniquePickNumber)
this.uniquePickNumber++;
}
return new Color(this.uniquePickNumber, true); // has alpha
}
public Color getClearColor()
{
return this.clearColor;
}
/**
* Returns true if the Picking mode is active, otherwise return false
*
* @return true for Picking mode, otherwise false
*/
public boolean isPickingMode()
{
return this.isPickingMode;
}
/**
* Enables color picking mode
*/
public void enablePickingMode()
{
this.isPickingMode = true;
}
/**
* Disables color picking mode
*/
public void disablePickingMode()
{
this.isPickingMode = false;
}
public void addOrderedRenderable(OrderedRenderable orderedRenderable)
{
if (null == orderedRenderable)
{
String msg = Logging.getMessage("nullValue.OrderedRenderable");
Logging.logger().warning(msg);
return; // benign event
}
this.orderedRenderables.add(orderedRenderable);
}
public java.util.Queue<OrderedRenderable> getOrderedRenderables()
{
return this.orderedRenderables;
}
public void drawUnitQuad()
{
GL gl = this.getGL();
gl.glBegin(GL.GL_QUADS); // TODO: use a vertex array or vertex buffer
gl.glVertex2d(0d, 0d);
gl.glVertex2d(1, 0d);
gl.glVertex2d(1, 1);
gl.glVertex2d(0d, 1);
gl.glEnd();
}
public void drawUnitQuad(TextureCoords texCoords)
{
GL gl = this.getGL();
gl.glBegin(GL.GL_QUADS); // TODO: use a vertex array or vertex buffer
gl.glTexCoord2d(texCoords.left(), texCoords.bottom());
gl.glVertex2d(0d, 0d);
gl.glTexCoord2d(texCoords.right(), texCoords.bottom());
gl.glVertex2d(1, 0d);
gl.glTexCoord2d(texCoords.right(), texCoords.top());
gl.glVertex2d(1, 1);
gl.glTexCoord2d(texCoords.left(), texCoords.top());
gl.glVertex2d(0d, 1);
gl.glEnd();
}
public int getNumTextureUnits()
{
return numTextureUnits;
}
public void setNumTextureUnits(int numTextureUnits)
{
// TODO: validate arg for >= 1
this.numTextureUnits = numTextureUnits;
}
public Vec4 getPointOnGlobe(Angle latitude, Angle longitude)
{
if (latitude == null || longitude == null)
{
String message = Logging.getMessage("nullValue.LatitudeOrLongitudeIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (this.getVisibleSector() == null)
return null;
if (!this.getVisibleSector().contains(latitude, longitude))
return null;
SectorGeometryList sectorGeometry = this.getSurfaceGeometry();
if (sectorGeometry != null)
{
Vec4 p = sectorGeometry.getSurfacePoint(latitude, longitude);
if (p != null)
return p;
}
return null;
}
public SurfaceTileRenderer getGeographicSurfaceTileRenderer()
{
return this.geographicSurfaceTileRenderer;
}
public Collection<PerformanceStatistic> getPerFrameStatistics()
{
return this.perFrameStatistics;
}
public void setPerFrameStatisticsKeys(Set<String> statKeys, Collection<PerformanceStatistic> stats)
{
this.perFrameStatisticsKeys = statKeys;
this.perFrameStatistics = stats;
}
public Set<String> getPerFrameStatisticsKeys()
{
return perFrameStatisticsKeys;
}
public void setPerFrameStatistic(String key, String displayName, Object value)
{
if (this.perFrameStatistics == null || this.perFrameStatisticsKeys == null)
return;
if (key == null)
{
String message = Logging.getMessage("nullValue.KeyIsNull=Key is null");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (displayName == null)
{
String message = Logging.getMessage("nullValue.DisplayNameIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (this.perFrameStatisticsKeys.contains(key) || this.perFrameStatisticsKeys.contains(PerformanceStatistic.ALL))
this.perFrameStatistics.add(new PerformanceStatistic(key, displayName, value));
}
public void setPerFrameStatistics(Collection<PerformanceStatistic> stats)
{
if (this.perFrameStatistics == null || this.perFrameStatisticsKeys == null)
return;
if (stats == null)
{
String message = Logging.getMessage("nullValue.KeyIsNull=Key is null"); // TODO
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
for (PerformanceStatistic stat : stats)
this.perFrameStatistics.add(stat);
}
}