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
.*;
11 import javax
.media
.opengl
.*;
12 import javax
.media
.opengl
.glu
.*;
14 import java
.awt
.geom
.*;
16 import java
.util
.logging
.Level
;
20 * @version $Id: PlaceNameRenderer.java 1994 2007-06-11 16:33:33Z dcollins $
22 public class PlaceNameRenderer
implements Disposable
24 private static final Font defaultFont
= Font
.decode("Arial-12-PLAIN");
25 private static final Color defaultColor
= Color
.white
;
26 private final Map
<Font
, TextRenderer
> textRenderers
= new HashMap
<Font
, TextRenderer
>();
27 private TextRenderer lastTextRenderer
= null;
28 private final GLU glu
= new GLU();
30 public PlaceNameRenderer()
36 for (TextRenderer textRenderer
: textRenderers
.values())
38 if (textRenderer
!= null)
39 textRenderer
.dispose();
43 public void render(DrawContext dc
, Iterator
<PlaceName
> placeNames
, boolean enableDepthTest
)
45 this.drawMany(dc
, placeNames
, enableDepthTest
);
48 public void render(DrawContext dc
, PlaceName placeName
, Vec4 placeNamePoint
, boolean enableDepthTest
)
50 if (!isNameValid(placeName
, false))
53 this.drawOne(dc
, placeName
, placeNamePoint
, enableDepthTest
);
56 private void drawMany(DrawContext dc
, Iterator
<PlaceName
> placeNames
, boolean enableDepthTest
)
60 String msg
= WorldWind
.retrieveErrMsg("nullValue.DrawContextIsNull");
61 WorldWind
.logger().log(Level
.FINE
, msg
);
62 throw new IllegalArgumentException(msg
);
65 if (dc
.getVisibleSector() == null)
68 SectorGeometryList geos
= dc
.getSurfaceGeometry();
72 if (placeNames
== null)
74 String msg
= WorldWind
.retrieveErrMsg("nullValue.Iterator");
75 WorldWind
.logger().log(Level
.FINE
, msg
);
76 throw new IllegalArgumentException(msg
);
79 if (!placeNames
.hasNext())
82 Frustum frustumInModelCoords
= dc
.getView().getFrustumInModelCoordinates();
83 double horizon
= dc
.getView().computeHorizonDistance();
85 this.beginDrawNames(dc
, enableDepthTest
);
87 while (placeNames
.hasNext())
89 PlaceName placeName
= placeNames
.next();
90 if (!isNameValid(placeName
, true))
93 if (!placeName
.isVisible())
96 Angle lat
= placeName
.getPosition().getLatitude();
97 Angle lon
= placeName
.getPosition().getLongitude();
99 if (!dc
.getVisibleSector().contains(lat
, lon
))
102 Vec4 namePoint
= geos
.getSurfacePoint(lat
, lon
, placeName
.getPosition().getElevation());
103 if (namePoint
== null)
106 double eyeDistance
= dc
.getView().getEyePoint().distanceTo3(namePoint
);
107 if (eyeDistance
> horizon
)
110 if (!frustumInModelCoords
.contains(namePoint
))
113 this.drawName(dc
, placeName
, namePoint
, enableDepthTest
);
116 this.endDrawNames(dc
);
119 private void drawOne(DrawContext dc
, PlaceName placeName
, Vec4 namePoint
, boolean enableDepthTest
)
123 String msg
= WorldWind
.retrieveErrMsg("nullValue.DrawContextIsNull");
124 WorldWind
.logger().log(Level
.FINE
, msg
);
125 throw new IllegalArgumentException(msg
);
127 if (dc
.getView() == null)
129 String msg
= WorldWind
.retrieveErrMsg("nullValue.ViewIsNull");
130 WorldWind
.logger().log(Level
.FINE
, msg
);
131 throw new IllegalArgumentException(msg
);
134 if (dc
.getVisibleSector() == null)
137 SectorGeometryList geos
= dc
.getSurfaceGeometry();
141 if (!placeName
.isVisible())
144 if (namePoint
== null)
146 if (placeName
.getPosition() == null)
149 Angle lat
= placeName
.getPosition().getLatitude();
150 Angle lon
= placeName
.getPosition().getLongitude();
152 if (!dc
.getVisibleSector().contains(lat
, lon
))
155 namePoint
= geos
.getSurfacePoint(lat
, lon
, placeName
.getPosition().getElevation());
156 if (namePoint
== null)
160 double horizon
= dc
.getView().computeHorizonDistance();
161 double eyeDistance
= dc
.getView().getEyePoint().distanceTo3(namePoint
);
162 if (eyeDistance
> horizon
)
165 if (!dc
.getView().getFrustumInModelCoordinates().contains(namePoint
))
168 this.beginDrawNames(dc
, enableDepthTest
);
169 this.drawName(dc
, placeName
, namePoint
, enableDepthTest
);
170 this.endDrawNames(dc
);
173 private static boolean isNameValid(PlaceName placeName
, boolean checkPosition
)
175 if (placeName
== null || placeName
.getText() == null)
178 //noinspection RedundantIfStatement
179 if (checkPosition
&& placeName
.getPosition() == null)
185 private final int[] viewportArray
= new int[4];
187 private void beginDrawNames(DrawContext dc
, boolean enableDepthTest
)
192 | GL
.GL_COLOR_BUFFER_BIT
// for alpha test func and ref, and blend
193 | GL
.GL_CURRENT_BIT
// for current color
194 | GL
.GL_TRANSFORM_BIT
// for modelview and perspective
195 | (enableDepthTest ? GL
.GL_VIEWPORT_BIT
| GL
.GL_DEPTH_BUFFER_BIT
: 0); // for depth func, depth range
196 gl
.glPushAttrib(attribBits
);
198 gl
.glGetIntegerv(GL
.GL_VIEWPORT
, viewportArray
, 0);
199 gl
.glMatrixMode(GL
.GL_PROJECTION
);
202 glu
.gluOrtho2D(0, viewportArray
[2], 0, viewportArray
[3]);
203 gl
.glMatrixMode(GL
.GL_MODELVIEW
);
206 gl
.glMatrixMode(GL
.GL_TEXTURE
);
210 // Enable the depth test but don't write to the depth buffer.
213 gl
.glEnable(GL
.GL_DEPTH_TEST
);
214 gl
.glDepthFunc(GL
.GL_LESS
);
215 gl
.glDepthMask(false);
219 gl
.glDisable(GL
.GL_DEPTH_TEST
);
221 // Suppress polygon culling.
222 gl
.glDisable(GL
.GL_CULL_FACE
);
223 // Suppress any fully transparent image pixels
224 final float ALPHA_EPSILON
= 0.001f
;
225 gl
.glEnable(GL
.GL_ALPHA_TEST
);
226 gl
.glAlphaFunc(GL
.GL_GREATER
, ALPHA_EPSILON
);
229 private void endDrawNames(DrawContext dc
)
231 if (this.lastTextRenderer
!= null)
233 this.lastTextRenderer
.end3DRendering();
234 this.lastTextRenderer
= null;
239 gl
.glMatrixMode(GL
.GL_PROJECTION
);
241 gl
.glMatrixMode(GL
.GL_MODELVIEW
);
243 gl
.glMatrixMode(GL
.GL_TEXTURE
);
249 private Vec4
drawName(DrawContext dc
, PlaceName name
, Vec4 namePoint
, boolean enableDepthTest
)
251 if (namePoint
== null)
253 String msg
= WorldWind
.retrieveErrMsg("nullValue.PointIsNull");
254 WorldWind
.logger().log(Level
.FINE
, msg
);
258 final String text
= name
.getText();
262 final Vec4 screenPoint
= dc
.getView().project(namePoint
);
263 if (screenPoint
== null)
267 this.setDepthFunc(dc
, screenPoint
);
269 Font font
= name
.getFont();
273 TextRenderer textRenderer
= this.textRenderers
.get(font
);
274 if (textRenderer
== null)
275 textRenderer
= this.initializeTextRenderer(font
);
276 if (textRenderer
!= this.lastTextRenderer
)
278 if (this.lastTextRenderer
!= null)
279 this.lastTextRenderer
.end3DRendering();
280 textRenderer
.begin3DRendering();
281 this.lastTextRenderer
= textRenderer
;
284 Rectangle2D nameBound
= textRenderer
.getBounds(text
);
285 int x
= (int) (screenPoint
.x
- nameBound
.getWidth() / 2d
);
286 int y
= (int) screenPoint
.y
;
288 Color color
= name
.getColor();
290 color
= defaultColor
;
292 this.setBackgroundColor(textRenderer
, color
);
293 textRenderer
.draw(text
, x
+ 1, y
- 1);
294 textRenderer
.setColor(color
);
295 textRenderer
.draw(text
, x
, y
);
300 private void setDepthFunc(DrawContext dc
, Vec4 screenPoint
)
302 double depth
= screenPoint
.z
- (8d
* 0.00048875809d
);
303 depth
= (depth
< 0) ?
0 : ((depth
> 1) ?
1 : depth
);
304 dc
.getGL().glDepthRange(depth
, depth
);
307 private final float[] compArray
= new float[4];
309 private void setBackgroundColor(TextRenderer textRenderer
, Color color
)
311 Color
.RGBtoHSB(color
.getRed(), color
.getGreen(), color
.getBlue(), compArray
);
312 if (compArray
[2] > 0.5)
313 textRenderer
.setColor(0, 0, 0, 0.7f
);
315 textRenderer
.setColor(1, 1, 1, 0.7f
);
318 private TextRenderer
initializeTextRenderer(Font font
)
320 TextRenderer textRenderer
= new TextRenderer(font
, true, true);
321 TextRenderer oldTextRenderer
;
322 oldTextRenderer
= this.textRenderers
.put(font
, textRenderer
);
323 if (oldTextRenderer
!= null)
324 oldTextRenderer
.dispose();
328 public String
toString()
330 return WorldWind
.retrieveErrMsg("layers.PlaceNameLayer.Name");