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
.render
;
9 import com
.sun
.opengl
.util
.BufferUtil
;
10 import com
.sun
.opengl
.util
.texture
.*;
11 import gov
.nasa
.worldwind
.Disposable
;
12 import gov
.nasa
.worldwind
.globes
.SectorGeometry
;
13 import gov
.nasa
.worldwind
.util
.Logging
;
15 import javax
.media
.opengl
.GL
;
16 import java
.nio
.ByteBuffer
;
17 import java
.util
.ArrayList
;
18 import java
.util
.logging
.Level
;
22 * @version $Id: SurfaceTileRenderer.java 3685 2007-12-03 19:51:05Z tgaskins $
24 public abstract class SurfaceTileRenderer
implements Disposable
26 private static final int DEFAULT_ALPHA_TEXTURE_SIZE
= 2;
28 private Texture alphaTexture
;
29 private Texture outlineTexture
;
30 private boolean showImageTileOutlines
= false;
32 public void dispose() // TODO: but waiting to implement a global texture disposal system
36 public boolean isShowImageTileOutlines()
38 return showImageTileOutlines
;
41 public void setShowImageTileOutlines(boolean showImageTileOutlines
)
43 this.showImageTileOutlines
= showImageTileOutlines
;
46 public void renderTile(DrawContext dc
, SurfaceTile tile
)
50 String message
= Logging
.getMessage("nullValue.TileIsNull");
51 Logging
.logger().severe(message
);
52 throw new IllegalStateException(message
);
55 ArrayList
<SurfaceTile
> al
= new ArrayList
<SurfaceTile
>(1);
57 this.renderTiles(dc
, al
);
61 protected static class Transform
69 abstract protected void preComputeTransform(DrawContext dc
, SectorGeometry sg
);
70 abstract protected void computeTransform(DrawContext dc
, SurfaceTile tile
, Transform t
);
71 abstract protected Iterable
<SurfaceTile
> getIntersectingTiles(DrawContext dc
, SectorGeometry sg
,
72 Iterable
<?
extends SurfaceTile
> tiles
);
74 public void renderTiles(DrawContext dc
, Iterable
<?
extends SurfaceTile
> tiles
)
78 String message
= Logging
.getMessage("nullValue.TileIterableIsNull");
79 Logging
.logger().severe(message
);
80 throw new IllegalStateException(message
);
85 String message
= Logging
.getMessage("nullValue.DrawContextIsNull");
86 Logging
.logger().severe(message
);
87 throw new IllegalStateException(message
);
92 gl
.glPushAttrib(GL
.GL_COLOR_BUFFER_BIT
// for alpha func
95 | GL
.GL_DEPTH_BUFFER_BIT
// for depth func
96 | GL
.GL_TEXTURE_BIT
// for texture env
97 | GL
.GL_TRANSFORM_BIT
);
101 this.alphaTexture
= dc
.getTextureCache().get(this);
102 if (this.alphaTexture
== null)
104 this.initAlphaTexture(DEFAULT_ALPHA_TEXTURE_SIZE
); // TODO: choose size to match incoming tile sizes?
105 dc
.getTextureCache().put(this, this.alphaTexture
);
108 boolean showOutlines
= this.showImageTileOutlines
&& dc
.getNumTextureUnits() > 2;
109 if (showOutlines
&& this.outlineTexture
== null)
110 this.initOutlineTexture(128);
112 gl
.glEnable(GL
.GL_DEPTH_TEST
);
113 gl
.glDepthFunc(GL
.GL_LEQUAL
);
115 gl
.glEnable(GL
.GL_ALPHA_TEST
);
116 gl
.glAlphaFunc(GL
.GL_GREATER
, 0.01f
);
118 gl
.glActiveTexture(GL
.GL_TEXTURE0
);
119 gl
.glEnable(GL
.GL_TEXTURE_2D
);
120 gl
.glMatrixMode(GL
.GL_TEXTURE
);
122 if (!dc
.isPickingMode())
124 gl
.glTexEnvi(GL
.GL_TEXTURE_ENV
, GL
.GL_TEXTURE_ENV_MODE
, GL
.GL_MODULATE
);
128 gl
.glTexEnvf(GL
.GL_TEXTURE_ENV
, GL
.GL_TEXTURE_ENV_MODE
, GL
.GL_COMBINE
);
129 gl
.glTexEnvf(GL
.GL_TEXTURE_ENV
, GL
.GL_SRC0_RGB
, GL
.GL_PREVIOUS
);
130 gl
.glTexEnvf(GL
.GL_TEXTURE_ENV
, GL
.GL_COMBINE_RGB
, GL
.GL_REPLACE
);
133 int numTexUnitsUsed
= 2;
134 int alphaTextureUnit
= GL
.GL_TEXTURE1
;
138 alphaTextureUnit
= GL
.GL_TEXTURE2
;
139 gl
.glActiveTexture(GL
.GL_TEXTURE1
);
140 gl
.glEnable(GL
.GL_TEXTURE_2D
);
141 gl
.glMatrixMode(GL
.GL_TEXTURE
);
143 gl
.glTexEnvi(GL
.GL_TEXTURE_ENV
, GL
.GL_TEXTURE_ENV_MODE
, GL
.GL_ADD
);
146 gl
.glActiveTexture(alphaTextureUnit
);
147 gl
.glEnable(GL
.GL_TEXTURE_2D
);
148 gl
.glMatrixMode(GL
.GL_TEXTURE
);
150 gl
.glTexEnvi(GL
.GL_TEXTURE_ENV
, GL
.GL_TEXTURE_ENV_MODE
, GL
.GL_MODULATE
);
152 // For each current geometry tile, find the intersecting image tiles and render the geometry
153 // tile once for each intersecting image tile.
154 Transform transform
= new Transform();
155 for (SectorGeometry sg
: dc
.getSurfaceGeometry())
157 Iterable
<SurfaceTile
> tilesToRender
= this.getIntersectingTiles(dc
, sg
, tiles
);
158 if (tilesToRender
== null)
161 // Pre-load info to compute the texture transform
162 this.preComputeTransform(dc
, sg
);
164 // For each interesecting tile, establish the texture transform necessary to map the image tile
165 // into the geometry tile's texture space. Use an alpha texture as a mask to prevent changing the
166 // frame buffer where the image tile does not overlap the geometry tile. Render both the image and
167 // alpha textures via multi-texture rendering.
168 // TODO: Figure out how to apply multi-texture to more than one tile at a time, most likely via a
170 for (SurfaceTile tile
: tilesToRender
)
172 gl
.glActiveTexture(GL
.GL_TEXTURE0
);
176 gl
.glMatrixMode(GL
.GL_TEXTURE
);
178 tile
.applyInternalTransform(dc
);
180 // Determine and apply texture transform to map image tile into geometry tile's texture space
181 this.computeTransform(dc
, tile
, transform
);
182 gl
.glScaled(transform
.HScale
, transform
.VScale
, 1d
);
183 gl
.glTranslated(transform
.HShift
, transform
.VShift
, 0d
);
187 gl
.glActiveTexture(GL
.GL_TEXTURE1
);
188 this.outlineTexture
.bind();
190 // Apply the same texture transform to the outline texture. The outline textures uses a
191 // different texture unit than the tile, so the transform made above does not carry over.
192 gl
.glMatrixMode(GL
.GL_TEXTURE
);
194 gl
.glScaled(transform
.HScale
, transform
.VScale
, 1d
);
195 gl
.glTranslated(transform
.HShift
, transform
.VShift
, 0d
);
198 // Prepare the alpha texture to be used as a mask where texture coords are outside [0,1]
199 gl
.glActiveTexture(alphaTextureUnit
);
200 this.alphaTexture
.bind();
202 // Apply the same texture transform to the alpha texture. The alpha texture uses a
203 // different texture unit than the tile, so the transform made above does not carry over.
204 gl
.glMatrixMode(GL
.GL_TEXTURE
);
206 gl
.glScaled(transform
.HScale
, transform
.VScale
, 1d
);
207 gl
.glTranslated(transform
.HShift
, transform
.VShift
, 0d
);
209 // Render the geometry tile
210 sg
.renderMultiTexture(dc
, numTexUnitsUsed
);
215 gl
.glActiveTexture(alphaTextureUnit
);
216 gl
.glMatrixMode(GL
.GL_TEXTURE
);
218 gl
.glDisable(GL
.GL_TEXTURE_2D
);
220 gl
.glActiveTexture(GL
.GL_TEXTURE0
);
221 gl
.glMatrixMode(GL
.GL_TEXTURE
);
223 gl
.glDisable(GL
.GL_TEXTURE_2D
);
227 gl
.glActiveTexture(GL
.GL_TEXTURE1
);
228 gl
.glMatrixMode(GL
.GL_TEXTURE
);
230 gl
.glDisable(GL
.GL_TEXTURE_2D
);
235 Logging
.logger().log(Level
.SEVERE
,
236 Logging
.getMessage("generic.ExceptionWhileRenderingLayer", this.getClass().getName()), e
);
240 // TODO: pop matrix stack too
245 private static void fillByteBuffer(ByteBuffer buffer
, byte value
)
247 for (int i
= 0; i
< buffer
.capacity(); i
++)
253 private void initAlphaTexture(int size
)
255 ByteBuffer textureBytes
= BufferUtil
.newByteBuffer(size
* size
);
256 fillByteBuffer(textureBytes
, (byte) 0xff);
257 TextureData textureData
= new TextureData(GL
.GL_ALPHA
, size
, size
, 0, GL
.GL_ALPHA
,
258 GL
.GL_UNSIGNED_BYTE
, false, false, false, textureBytes
.rewind(), null);
259 this.alphaTexture
= TextureIO
.newTexture(textureData
);
261 this.alphaTexture
.bind();
262 this.alphaTexture
.setTexParameteri(GL
.GL_TEXTURE_MAG_FILTER
, GL
.GL_NEAREST
);
263 this.alphaTexture
.setTexParameteri(GL
.GL_TEXTURE_MIN_FILTER
, GL
.GL_NEAREST
);
264 this.alphaTexture
.setTexParameteri(GL
.GL_TEXTURE_WRAP_S
, GL
.GL_CLAMP_TO_BORDER
);
265 this.alphaTexture
.setTexParameteri(GL
.GL_TEXTURE_WRAP_T
, GL
.GL_CLAMP_TO_BORDER
);
266 // Assume the default border color of (0, 0, 0, 0).
269 private void initOutlineTexture(int size
)
271 ByteBuffer textureBytes
= BufferUtil
.newByteBuffer(size
* size
);
272 for (int row
= 0; row
< size
; row
++)
274 for (int col
= 0; col
< size
; col
++)
277 if (row
== 0 || col
== 0 || row
== size
- 1 || col
== size
- 1)
281 textureBytes
.put(row
* size
+ col
, p
);
285 TextureData textureData
= new TextureData(GL
.GL_LUMINANCE
, size
, size
, 0, GL
.GL_LUMINANCE
,
286 GL
.GL_UNSIGNED_BYTE
, false, false, false, textureBytes
.rewind(), null);
287 this.outlineTexture
= TextureIO
.newTexture(textureData
);
289 this.outlineTexture
.bind();
290 this.outlineTexture
.setTexParameteri(GL
.GL_TEXTURE_MAG_FILTER
, GL
.GL_NEAREST
);
291 this.outlineTexture
.setTexParameteri(GL
.GL_TEXTURE_MIN_FILTER
, GL
.GL_NEAREST
);
292 this.outlineTexture
.setTexParameteri(GL
.GL_TEXTURE_WRAP_S
, GL
.GL_CLAMP_TO_EDGE
);
293 this.outlineTexture
.setTexParameteri(GL
.GL_TEXTURE_WRAP_T
, GL
.GL_CLAMP_TO_EDGE
);