2 Copyright (C) 2001, 2006 United States Government as represented by
3 the Administrator of the National Aeronautics and Space Administration.
6 package gov
.nasa
.worldwind
;
8 import com
.sun
.opengl
.util
.j2d
.*;
9 import gov
.nasa
.worldwind
.geom
.*;
10 import gov
.nasa
.worldwind
.geom
.Point
;
12 import javax
.media
.opengl
.*;
13 import javax
.media
.opengl
.glu
.*;
15 import java
.awt
.geom
.*;
17 import java
.util
.logging
.Level
;
21 * @version $Id: PlaceNameRenderer.java 1774 2007-05-08 01:03:37Z dcollins $
23 public class PlaceNameRenderer
implements Disposable
25 private static final Font defaultFont
= Font
.decode("Arial-12-PLAIN");
26 private static final Color defaultColor
= Color
.white
;
27 private final Map
<Font
, TextRenderer
> textRenderers
= new HashMap
<Font
, TextRenderer
>();
28 private TextRenderer lastTextRenderer
= null;
29 private final GLU glu
= new GLU();
31 public PlaceNameRenderer()
37 for (TextRenderer textRenderer
: textRenderers
.values())
39 if (textRenderer
!= null)
40 textRenderer
.dispose();
44 public void render(DrawContext dc
, Iterator
<PlaceName
> placeNames
, boolean enableDepthTest
)
46 this.drawMany(dc
, placeNames
, enableDepthTest
);
49 public void render(DrawContext dc
, PlaceName placeName
, Point placeNamePoint
, boolean enableDepthTest
)
51 if (!isNameValid(placeName
, false))
54 this.drawOne(dc
, placeName
, placeNamePoint
, enableDepthTest
);
57 private void drawMany(DrawContext dc
, Iterator
<PlaceName
> placeNames
, boolean enableDepthTest
)
61 String msg
= WorldWind
.retrieveErrMsg("nullValue.DrawContextIsNull");
62 WorldWind
.logger().log(Level
.FINE
, msg
);
63 throw new IllegalArgumentException(msg
);
66 if (dc
.getVisibleSector() == null)
69 SectorGeometryList geos
= dc
.getSurfaceGeometry();
73 if (placeNames
== null)
75 String msg
= WorldWind
.retrieveErrMsg("nullValue.Iterator");
76 WorldWind
.logger().log(Level
.FINE
, msg
);
77 throw new IllegalArgumentException(msg
);
80 if (!placeNames
.hasNext())
83 Frustum frustumInModelCoords
= dc
.getView().getFrustumInModelCoordinates();
84 double horizon
= dc
.getView().computeHorizonDistance();
86 this.beginDrawNames(dc
, enableDepthTest
);
88 while (placeNames
.hasNext())
90 PlaceName placeName
= placeNames
.next();
91 if (!isNameValid(placeName
, true))
94 if (!placeName
.isVisible())
97 Angle lat
= placeName
.getPosition().getLatitude();
98 Angle lon
= placeName
.getPosition().getLongitude();
100 if (!dc
.getVisibleSector().contains(lat
, lon
))
103 Point namePoint
= geos
.getSurfacePoint(lat
, lon
, placeName
.getPosition().getElevation());
104 if (namePoint
== null)
107 double eyeDistance
= dc
.getView().getEyePoint().distanceTo(namePoint
);
108 if (eyeDistance
> horizon
)
111 if (!frustumInModelCoords
.contains(namePoint
))
114 this.drawName(dc
, placeName
, namePoint
, enableDepthTest
);
117 this.endDrawNames(dc
);
120 private void drawOne(DrawContext dc
, PlaceName placeName
, Point namePoint
, boolean enableDepthTest
)
124 String msg
= WorldWind
.retrieveErrMsg("nullValue.DrawContextIsNull");
125 WorldWind
.logger().log(Level
.FINE
, msg
);
126 throw new IllegalArgumentException(msg
);
128 if (dc
.getView() == null)
130 String msg
= WorldWind
.retrieveErrMsg("nullValue.ViewIsNull");
131 WorldWind
.logger().log(Level
.FINE
, msg
);
132 throw new IllegalArgumentException(msg
);
135 if (dc
.getVisibleSector() == null)
138 SectorGeometryList geos
= dc
.getSurfaceGeometry();
142 if (!placeName
.isVisible())
145 if (namePoint
== null)
147 if (placeName
.getPosition() == null)
150 Angle lat
= placeName
.getPosition().getLatitude();
151 Angle lon
= placeName
.getPosition().getLongitude();
153 if (!dc
.getVisibleSector().contains(lat
, lon
))
156 namePoint
= geos
.getSurfacePoint(lat
, lon
, placeName
.getPosition().getElevation());
157 if (namePoint
== null)
161 double horizon
= dc
.getView().computeHorizonDistance();
162 double eyeDistance
= dc
.getView().getEyePoint().distanceTo(namePoint
);
163 if (eyeDistance
> horizon
)
166 if (!dc
.getView().getFrustumInModelCoordinates().contains(namePoint
))
169 this.beginDrawNames(dc
, enableDepthTest
);
170 this.drawName(dc
, placeName
, namePoint
, enableDepthTest
);
171 this.endDrawNames(dc
);
174 private static boolean isNameValid(PlaceName placeName
, boolean checkPosition
)
176 if (placeName
== null || placeName
.getText() == null)
179 //noinspection RedundantIfStatement
180 if (checkPosition
&& placeName
.getPosition() == null)
186 private final int[] viewportArray
= new int[4];
188 private void beginDrawNames(DrawContext dc
, boolean enableDepthTest
)
193 | GL
.GL_COLOR_BUFFER_BIT
// for alpha test func and ref, and blend
194 | GL
.GL_CURRENT_BIT
// for current color
195 | GL
.GL_TRANSFORM_BIT
// for modelview and perspective
196 | (enableDepthTest ? GL
.GL_VIEWPORT_BIT
| GL
.GL_DEPTH_BUFFER_BIT
: 0); // for depth func, depth range
197 gl
.glPushAttrib(attribBits
);
199 gl
.glGetIntegerv(GL
.GL_VIEWPORT
, viewportArray
, 0);
200 gl
.glMatrixMode(GL
.GL_PROJECTION
);
203 glu
.gluOrtho2D(0, viewportArray
[2], 0, viewportArray
[3]);
204 gl
.glMatrixMode(GL
.GL_MODELVIEW
);
207 gl
.glMatrixMode(GL
.GL_TEXTURE
);
211 // Enable the depth test but don't write to the depth buffer.
214 gl
.glEnable(GL
.GL_DEPTH_TEST
);
215 gl
.glDepthFunc(GL
.GL_LESS
);
216 gl
.glDepthMask(false);
220 gl
.glDisable(GL
.GL_DEPTH_TEST
);
222 // Suppress polygon culling.
223 gl
.glDisable(GL
.GL_CULL_FACE
);
224 // Suppress any fully transparent image pixels
225 final float ALPHA_EPSILON
= 0.001f
;
226 gl
.glEnable(GL
.GL_ALPHA_TEST
);
227 gl
.glAlphaFunc(GL
.GL_GREATER
, ALPHA_EPSILON
);
230 private void endDrawNames(DrawContext dc
)
232 if (this.lastTextRenderer
!= null)
234 this.lastTextRenderer
.end3DRendering();
235 this.lastTextRenderer
= null;
240 gl
.glMatrixMode(GL
.GL_PROJECTION
);
242 gl
.glMatrixMode(GL
.GL_MODELVIEW
);
244 gl
.glMatrixMode(GL
.GL_TEXTURE
);
250 private Point
drawName(DrawContext dc
, PlaceName name
, Point namePoint
, boolean enableDepthTest
)
252 if (namePoint
== null)
254 String msg
= WorldWind
.retrieveErrMsg("nullValue.PointIsNull");
255 WorldWind
.logger().log(Level
.FINE
, msg
);
259 final String text
= name
.getText();
263 final Point screenPoint
= dc
.getView().project(namePoint
);
264 if (screenPoint
== null)
268 this.setDepthFunc(dc
, screenPoint
);
270 Font font
= name
.getFont();
274 TextRenderer textRenderer
= this.textRenderers
.get(font
);
275 if (textRenderer
== null)
276 textRenderer
= this.initializeTextRenderer(font
);
277 if (textRenderer
!= this.lastTextRenderer
)
279 if (this.lastTextRenderer
!= null)
280 this.lastTextRenderer
.end3DRendering();
281 textRenderer
.begin3DRendering();
282 this.lastTextRenderer
= textRenderer
;
285 Rectangle2D nameBound
= textRenderer
.getBounds(text
);
286 int x
= (int) (screenPoint
.x() - nameBound
.getWidth() / 2d
);
287 int y
= (int) screenPoint
.y();
289 Color color
= name
.getColor();
291 color
= defaultColor
;
293 this.setBackgroundColor(textRenderer
, color
);
294 textRenderer
.draw(text
, x
+ 1, y
- 1);
295 textRenderer
.setColor(color
);
296 textRenderer
.draw(text
, x
, y
);
301 private void setDepthFunc(DrawContext dc
, Point screenPoint
)
303 double depth
= screenPoint
.z() - 8d
* 0.00048875809d
;
304 depth
= (depth
< 0) ?
0 : ((depth
> 1) ?
1 : depth
);
305 dc
.getGL().glDepthRange(depth
, depth
);
308 private final float[] compArray
= new float[4];
310 private void setBackgroundColor(TextRenderer textRenderer
, Color color
)
312 Color
.RGBtoHSB(color
.getRed(), color
.getGreen(), color
.getBlue(), compArray
);
313 if (compArray
[2] > 0.5)
314 textRenderer
.setColor(0, 0, 0, 0.7f
);
316 textRenderer
.setColor(1, 1, 1, 0.7f
);
319 private TextRenderer
initializeTextRenderer(Font font
)
321 TextRenderer textRenderer
= new TextRenderer(font
, true, true);
322 TextRenderer oldTextRenderer
;
323 oldTextRenderer
= this.textRenderers
.put(font
, textRenderer
);
324 if (oldTextRenderer
!= null)
325 oldTextRenderer
.dispose();
329 public String
toString()
331 return WorldWind
.retrieveErrMsg("layers.PlaceNameLayer.Name");