2 Copyright (C) 2001, 2006 United States Government
3 as represented by the Administrator of the
4 National Aeronautics and Space Administration.
7 package gov
.nasa
.worldwind
;
9 import gov
.nasa
.worldwind
.layers
.*;
10 import gov
.nasa
.worldwind
.geom
.*;
12 import javax
.media
.opengl
.*;
14 import com
.sun
.opengl
.util
.texture
.*;
21 * @version $Id: SurfaceTileRenderer.java 1884 2007-05-25 21:15:33Z dcollins $
23 public class SurfaceTileRenderer
implements Disposable
25 private static final int DEFAULT_ALPHA_TEXTURE_SIZE
= 2;
27 private Texture alphaTexture
;
28 private Texture outlineTexture
;
29 private boolean showImageTileOutlines
= false;
31 public void dispose() // TODO: but waiting to implement a global texture disposal system
35 public boolean isShowImageTileOutlines()
37 return showImageTileOutlines
;
40 public void setShowImageTileOutlines(boolean showImageTileOutlines
)
42 this.showImageTileOutlines
= showImageTileOutlines
;
45 public void renderTile(DrawContext dc
, TextureTile tile
)
49 String message
= WorldWind
.retrieveErrMsg("nullValue.TileIsNull");
50 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
51 throw new IllegalStateException(message
);
54 ArrayList
<TextureTile
> al
= new ArrayList
<TextureTile
>(1);
56 this.renderTiles(dc
, al
);
60 public void renderTiles(DrawContext dc
, Iterable
<?
extends TextureTile
> tiles
)
64 String message
= WorldWind
.retrieveErrMsg("nullValue.TileIterableIsNull");
65 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
66 throw new IllegalStateException(message
);
71 String message
= WorldWind
.retrieveErrMsg("nullValue.DrawContextIsNull");
72 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
73 throw new IllegalStateException(message
);
78 gl
.glPushAttrib(GL
.GL_COLOR_BUFFER_BIT
// for alpha func
81 | GL
.GL_DEPTH_BUFFER_BIT
// for depth func
82 | GL
.GL_TEXTURE_BIT
// for texture env
83 | GL
.GL_TRANSFORM_BIT
);
87 if (this.alphaTexture
== null)
88 this.initAlphaTexture(DEFAULT_ALPHA_TEXTURE_SIZE
); // TODO: choose size to match incoming tile sizes?
90 boolean showOutlines
= this.showImageTileOutlines
&& dc
.getNumTextureUnits() > 2;
91 if (showOutlines
&& this.outlineTexture
== null)
92 this.initOutlineTexture(128);
94 gl
.glEnable(GL
.GL_DEPTH_TEST
);
95 gl
.glDepthFunc(GL
.GL_LEQUAL
);
97 gl
.glEnable(GL
.GL_ALPHA_TEST
);
98 gl
.glAlphaFunc(GL
.GL_GREATER
, 0.01f
);
100 gl
.glActiveTexture(GL
.GL_TEXTURE0
);
101 gl
.glEnable(GL
.GL_TEXTURE_2D
);
102 gl
.glMatrixMode(GL
.GL_TEXTURE
);
104 if (!dc
.isPickingMode())
106 gl
.glTexEnvi(GL
.GL_TEXTURE_ENV
, GL
.GL_TEXTURE_ENV_MODE
, GL
.GL_REPLACE
);
110 gl
.glTexEnvf(GL
.GL_TEXTURE_ENV
, GL
.GL_TEXTURE_ENV_MODE
, GL
.GL_COMBINE
);
111 gl
.glTexEnvf(GL
.GL_TEXTURE_ENV
, GL
.GL_SRC0_RGB
, GL
.GL_PREVIOUS
);
112 gl
.glTexEnvf(GL
.GL_TEXTURE_ENV
, GL
.GL_COMBINE_RGB
, GL
.GL_REPLACE
);
115 int numTexUnitsUsed
= 2;
116 int alphaTextureUnit
= GL
.GL_TEXTURE1
;
120 alphaTextureUnit
= GL
.GL_TEXTURE2
;
121 gl
.glActiveTexture(GL
.GL_TEXTURE1
);
122 gl
.glEnable(GL
.GL_TEXTURE_2D
);
123 gl
.glMatrixMode(GL
.GL_TEXTURE
);
125 gl
.glTexEnvi(GL
.GL_TEXTURE_ENV
, GL
.GL_TEXTURE_ENV_MODE
, GL
.GL_ADD
);
128 gl
.glActiveTexture(alphaTextureUnit
);
129 gl
.glEnable(GL
.GL_TEXTURE_2D
);
130 gl
.glMatrixMode(GL
.GL_TEXTURE
);
132 gl
.glTexEnvi(GL
.GL_TEXTURE_ENV
, GL
.GL_TEXTURE_ENV_MODE
, GL
.GL_MODULATE
);
134 // For each current geometry tile, find the intersecting image tiles and render the geometry
135 // tile once for each intersecting image tile.
136 // System.out.printf("%d geo tiles\n", dc.getSurfaceGeometry().size());
137 for (SectorGeometry sg
: dc
.getSurfaceGeometry())
139 Iterable
<TextureTile
> tilesToRender
= this.getIntersectingTiles(sg
, tiles
);
140 if (tilesToRender
== null)
142 // System.out.printf("%d, ", tilesToRender.length);
144 // Pre-load info to compute the texture transform below
145 Sector st
= sg
.getSector();
146 double geoDeltaLat
= st
.getDeltaLatRadians();
147 double geoDeltaLon
= st
.getDeltaLonRadians();
148 double geoMinLat
= st
.getMinLatitude().radians
;
149 double geoMinLon
= st
.getMinLongitude().radians
;
151 // For each interesecting tile, establish the texture transform necessary to map the image tile
152 // into the geometry tile's texture space. Use an alpha texture as a mask to prevent changing the
153 // frame buffer where the image tile does not overlap the geometry tile. Render both the image and
154 // alpha textures via multi-texture rendering.
155 // TODO: Figure out how to apply multi-texture to more than one tile at a time, most likely via a
157 for (TextureTile tile
: tilesToRender
)
159 gl
.glActiveTexture(GL
.GL_TEXTURE0
);
161 if (tile
.bindTexture(dc
))
163 gl
.glMatrixMode(GL
.GL_TEXTURE
);
165 tile
.applyTextureTransform(dc
);
167 // Determine and apply texture transform to map image tile into geometry tile's texture space
168 Sector si
= tile
.getSector();
169 double latScale
= si
.getDeltaLatRadians() > 0 ? geoDeltaLat
/ si
.getDeltaLatRadians() : 1;
170 double lonScale
= si
.getDeltaLonRadians() > 0 ? geoDeltaLon
/ si
.getDeltaLonRadians() : 1;
171 gl
.glScaled(lonScale
, latScale
, 1d
);
173 double latShift
= -(si
.getMinLatitude().radians
- geoMinLat
) / geoDeltaLat
;
174 double lonShift
= -(si
.getMinLongitude().radians
- geoMinLon
) / geoDeltaLon
;
175 gl
.glTranslated(lonShift
, latShift
, 0d
);
179 gl
.glActiveTexture(GL
.GL_TEXTURE1
);
180 this.outlineTexture
.bind();
182 // Apply the same texture transform to the outline texture. The outline textures uses a
183 // different texture unit than the tile, so the transform made above does not carry over.
184 gl
.glMatrixMode(GL
.GL_TEXTURE
);
186 gl
.glScaled(lonScale
, latScale
, 1d
);
187 gl
.glTranslated(lonShift
, latShift
, 0d
);
190 // Prepare the alpha texture to be used as a mask where texture coords are outside [0,1]
191 gl
.glActiveTexture(alphaTextureUnit
);
192 this.alphaTexture
.bind();
194 // Apply the same texture transform to the alpha texture. The alpha texture uses a
195 // different texture unit than the tile, so the transform made above does not carry over.
196 gl
.glMatrixMode(GL
.GL_TEXTURE
);
198 gl
.glScaled(lonScale
, latScale
, 1d
);
199 gl
.glTranslated(lonShift
, latShift
, 0d
);
201 // Render the geometry tile
202 sg
.renderMultiTexture(dc
, numTexUnitsUsed
);
206 // System.out.println();
208 gl
.glActiveTexture(alphaTextureUnit
);
209 gl
.glMatrixMode(GL
.GL_TEXTURE
);
211 gl
.glDisable(GL
.GL_TEXTURE_2D
);
213 gl
.glActiveTexture(GL
.GL_TEXTURE0
);
214 gl
.glMatrixMode(GL
.GL_TEXTURE
);
216 gl
.glDisable(GL
.GL_TEXTURE_2D
);
220 gl
.glActiveTexture(GL
.GL_TEXTURE1
);
221 gl
.glMatrixMode(GL
.GL_TEXTURE
);
223 gl
.glDisable(GL
.GL_TEXTURE_2D
);
228 String message
= WorldWind
.retrieveErrMsg("generic.ExceptionWhileRenderingLayer");
229 message
+= this.getClass().getName();
230 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
, e
);
238 private Iterable
<TextureTile
> getIntersectingTiles(SectorGeometry sg
, Iterable
<?
extends TextureTile
> tiles
)
240 ArrayList
<TextureTile
> intersectingTiles
= null;
242 for (TextureTile tile
: tiles
)
244 if (!tile
.getSector().intersects(sg
.getSector()))
247 if (intersectingTiles
== null)
248 intersectingTiles
= new ArrayList
<TextureTile
>();
250 intersectingTiles
.add(tile
);
253 if (intersectingTiles
== null)
256 return intersectingTiles
;
259 private static void fillByteBuffer(ByteBuffer buffer
, byte value
)
261 for (int i
= 0; i
< buffer
.capacity(); i
++)
267 private void initAlphaTexture(int size
)
269 ByteBuffer textureBytes
= com
.sun
.opengl
.util
.BufferUtil
.newByteBuffer(size
* size
);
270 fillByteBuffer(textureBytes
, (byte) 0xff);
271 TextureData textureData
= new TextureData(GL
.GL_ALPHA
, size
, size
, 0, GL
.GL_ALPHA
,
272 GL
.GL_UNSIGNED_BYTE
, false, false, false, textureBytes
.rewind(), null);
273 this.alphaTexture
= TextureIO
.newTexture(textureData
);
275 this.alphaTexture
.bind();
276 this.alphaTexture
.setTexParameteri(GL
.GL_TEXTURE_MAG_FILTER
, GL
.GL_NEAREST
);
277 this.alphaTexture
.setTexParameteri(GL
.GL_TEXTURE_MIN_FILTER
, GL
.GL_NEAREST
);
278 this.alphaTexture
.setTexParameteri(GL
.GL_TEXTURE_WRAP_S
, GL
.GL_CLAMP_TO_BORDER
);
279 this.alphaTexture
.setTexParameteri(GL
.GL_TEXTURE_WRAP_T
, GL
.GL_CLAMP_TO_BORDER
);
280 // Assume the default border color of (0, 0, 0, 0).
283 private void initOutlineTexture(int size
)
285 ByteBuffer textureBytes
= com
.sun
.opengl
.util
.BufferUtil
.newByteBuffer(size
* size
);
286 for (int row
= 0; row
< size
; row
++)
288 for (int col
= 0; col
< size
; col
++)
291 if (row
== 0 || col
== 0 || row
== size
- 1 || col
== size
- 1)
295 textureBytes
.put(row
* size
+ col
, p
);
299 TextureData textureData
= new TextureData(GL
.GL_LUMINANCE
, size
, size
, 0, GL
.GL_LUMINANCE
,
300 GL
.GL_UNSIGNED_BYTE
, false, false, false, textureBytes
.rewind(), null);
301 this.outlineTexture
= TextureIO
.newTexture(textureData
);
303 this.outlineTexture
.bind();
304 this.outlineTexture
.setTexParameteri(GL
.GL_TEXTURE_MAG_FILTER
, GL
.GL_NEAREST
);
305 this.outlineTexture
.setTexParameteri(GL
.GL_TEXTURE_MIN_FILTER
, GL
.GL_NEAREST
);
306 this.outlineTexture
.setTexParameteri(GL
.GL_TEXTURE_WRAP_S
, GL
.GL_CLAMP_TO_EDGE
);
307 this.outlineTexture
.setTexParameteri(GL
.GL_TEXTURE_WRAP_T
, GL
.GL_CLAMP_TO_EDGE
);