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
.layers
;
9 import com
.sun
.opengl
.util
.texture
.*;
10 import gov
.nasa
.worldwind
.WorldWind
;
11 import gov
.nasa
.worldwind
.cache
.TextureCache
;
12 import gov
.nasa
.worldwind
.geom
.*;
13 import gov
.nasa
.worldwind
.globes
.Globe
;
14 import gov
.nasa
.worldwind
.globes
.EllipsoidalGlobe
;
15 import gov
.nasa
.worldwind
.render
.*;
16 import gov
.nasa
.worldwind
.util
.*;
18 import javax
.media
.opengl
.*;
22 * @version $Id: TextureTile.java 3307 2007-10-16 14:43:49Z patrickmurris $
24 public class TextureTile
extends Tile
implements SurfaceTile
26 private volatile TextureData textureData
;
27 private TextureTile fallbackTile
= null; // holds texture to use if own texture not available
28 private Vec4 centroid
; // Cartesian coordinate of lat/lon center
29 private Extent extent
= null; // bounding volume
30 private double extentVerticalExaggertion
= Double
.MIN_VALUE
; // VE used to calculate the extent
31 private double minDistanceToEye
= Double
.MAX_VALUE
;
33 public TextureTile(Sector sector
)
38 public TextureTile(Sector sector
, Level level
, int row
, int col
)
40 super(sector
, level
, row
, col
);
44 public final long getSizeInBytes()
46 long size
= super.getSizeInBytes();
48 if (this.textureData
!= null)
49 size
+= this.textureData
.getEstimatedMemorySize();
54 public TextureTile
getFallbackTile()
56 return this.fallbackTile
;
59 public void setFallbackTile(TextureTile fallbackTile
)
61 this.fallbackTile
= fallbackTile
;
64 public TextureData
getTextureData()
66 return this.textureData
;
69 public void setTextureData(TextureData textureData
)
71 this.textureData
= textureData
;
74 public Texture
getTexture(TextureCache tc
)
78 String message
= Logging
.getMessage("nullValue.TextureCacheIsNull");
79 Logging
.logger().severe(message
);
80 throw new IllegalStateException(message
);
83 return tc
.get(this.getTileKey());
86 public boolean isTextureInMemory(TextureCache tc
)
90 String message
= Logging
.getMessage("nullValue.TextureCacheIsNull");
91 Logging
.logger().severe(message
);
92 throw new IllegalStateException(message
);
95 return this.getTexture(tc
) != null || this.getTextureData() != null;
98 public void setTexture(TextureCache tc
, Texture texture
)
102 String message
= Logging
.getMessage("nullValue.TextureCacheIsNull");
103 Logging
.logger().severe(message
);
104 throw new IllegalStateException(message
);
107 tc
.put(this.getTileKey(), texture
);
109 // No more need for texture data; allow garbage collector and memory cache to reclaim it.
110 this.textureData
= null;
111 this.updateMemoryCache();
114 public Vec4
getCentroidPoint(Globe globe
)
118 String msg
= Logging
.getMessage("nullValue.GlobeIsNull");
119 Logging
.logger().severe(msg
);
120 throw new IllegalArgumentException(msg
);
123 if (this.centroid
== null)
125 LatLon c
= this.getSector().getCentroid();
126 this.centroid
= globe
.computePointFromPosition(c
.getLatitude(), c
.getLongitude(), 0);
129 return this.centroid
;
132 public double getMinDistanceToEye()
134 return this.minDistanceToEye
;
137 public void setMinDistanceToEye(double minDistanceToEye
)
139 if (minDistanceToEye
< 0)
141 String msg
= Logging
.getMessage("layers.TextureTile.MinDistanceToEyeNegative");
142 Logging
.logger().severe(msg
);
143 throw new IllegalArgumentException(msg
);
145 this.minDistanceToEye
= minDistanceToEye
;
148 public Extent
getExtent(DrawContext dc
)
152 String msg
= Logging
.getMessage("nullValue.DrawContextIsNull");
153 Logging
.logger().severe(msg
);
154 throw new IllegalArgumentException(msg
);
157 if (this.extent
== null || this.extentVerticalExaggertion
!= dc
.getVerticalExaggeration())
159 this.extent
= dc
.getGlobe().computeBoundingCylinder(dc
.getVerticalExaggeration(), this.getSector());
160 this.extentVerticalExaggertion
= dc
.getVerticalExaggeration();
166 public TextureTile
[] createSubTiles(Level nextLevel
)
168 if (nextLevel
== null)
170 String msg
= Logging
.getMessage("nullValue.LevelIsNull");
171 Logging
.logger().severe(msg
);
172 throw new IllegalArgumentException(msg
);
174 Angle p0
= this.getSector().getMinLatitude();
175 Angle p2
= this.getSector().getMaxLatitude();
176 Angle p1
= Angle
.midAngle(p0
, p2
);
178 Angle t0
= this.getSector().getMinLongitude();
179 Angle t2
= this.getSector().getMaxLongitude();
180 Angle t1
= Angle
.midAngle(t0
, t2
);
182 String nextLevelCacheName
= nextLevel
.getCacheName();
183 int nextLevelNum
= nextLevel
.getLevelNumber();
184 int row
= this.getRow();
185 int col
= this.getColumn();
187 TextureTile
[] subTiles
= new TextureTile
[4];
189 TileKey key
= new TileKey(nextLevelNum
, 2 * row
, 2 * col
, nextLevelCacheName
);
190 TextureTile subTile
= this.getTileFromMemoryCache(key
);
192 subTiles
[0] = subTile
;
194 subTiles
[0] = new TextureTile(new Sector(p0
, p1
, t0
, t1
), nextLevel
, 2 * row
, 2 * col
);
196 key
= new TileKey(nextLevelNum
, 2 * row
, 2 * col
+ 1, nextLevelCacheName
);
197 subTile
= this.getTileFromMemoryCache(key
);
199 subTiles
[1] = subTile
;
201 subTiles
[1] = new TextureTile(new Sector(p0
, p1
, t1
, t2
), nextLevel
, 2 * row
, 2 * col
+ 1);
203 key
= new TileKey(nextLevelNum
, 2 * row
+ 1, 2 * col
, nextLevelCacheName
);
204 subTile
= this.getTileFromMemoryCache(key
);
206 subTiles
[2] = subTile
;
208 subTiles
[2] = new TextureTile(new Sector(p1
, p2
, t0
, t1
), nextLevel
, 2 * row
+ 1, 2 * col
);
210 key
= new TileKey(nextLevelNum
, 2 * row
+ 1, 2 * col
+ 1, nextLevelCacheName
);
211 subTile
= this.getTileFromMemoryCache(key
);
213 subTiles
[3] = subTile
;
215 subTiles
[3] = new TextureTile(new Sector(p1
, p2
, t1
, t2
), nextLevel
, 2 * row
+ 1, 2 * col
+ 1);
220 private TextureTile
getTileFromMemoryCache(TileKey tileKey
)
222 return (TextureTile
) WorldWind
.getMemoryCache(TextureTile
.class.getName()).getObject(tileKey
);
225 private void updateMemoryCache()
227 if (this.getTileFromMemoryCache(this.getTileKey()) != null)
228 WorldWind
.getMemoryCache(TextureTile
.class.getName()).add(this.getTileKey(), this);
231 public Texture
initializeTexture(DrawContext dc
)
235 String message
= Logging
.getMessage("nullValue.DrawContextIsNull");
236 Logging
.logger().severe(message
);
237 throw new IllegalStateException(message
);
240 Texture t
= this.getTexture(dc
.getTextureCache());
244 if (this.getTextureData() == null)
246 String msg
= Logging
.getMessage("nullValue.TextureDataIsNull");
247 Logging
.logger().severe(msg
);
248 throw new IllegalStateException(msg
);
253 t
= TextureIO
.newTexture(this.getTextureData());
257 Logging
.logger().log(
258 java
.util
.logging
.Level
.SEVERE
, "layers.TextureLayer.ExceptionAttemptingToReadTextureFile", e
);
262 this.setTexture(dc
.getTextureCache(), t
);
266 gl
.glTexParameteri(GL
.GL_TEXTURE_2D
, GL
.GL_TEXTURE_MIN_FILTER
, GL
.GL_LINEAR
);
267 gl
.glTexParameteri(GL
.GL_TEXTURE_2D
, GL
.GL_TEXTURE_MAG_FILTER
, GL
.GL_LINEAR
);
268 gl
.glTexParameteri(GL
.GL_TEXTURE_2D
, GL
.GL_TEXTURE_WRAP_S
, GL
.GL_CLAMP_TO_EDGE
);
269 gl
.glTexParameteri(GL
.GL_TEXTURE_2D
, GL
.GL_TEXTURE_WRAP_T
, GL
.GL_CLAMP_TO_EDGE
);
274 public boolean bind(DrawContext dc
)
278 String message
= Logging
.getMessage("nullValue.DrawContextIsNull");
279 Logging
.logger().severe(message
);
280 throw new IllegalStateException(message
);
283 Texture t
= this.getTexture(dc
.getTextureCache());
284 if (t
== null && this.getTextureData() != null)
286 t
= this.initializeTexture(dc
);
288 return true; // texture was bound during initialization.
291 if (t
== null && this.getFallbackTile() != null)
293 TextureTile resourceTile
= this.getFallbackTile();
294 t
= resourceTile
.getTexture(dc
.getTextureCache());
297 t
= resourceTile
.initializeTexture(dc
);
299 return true; // texture was bound during initialization.
309 public void applyInternalTransform(DrawContext dc
)
313 String message
= Logging
.getMessage("nullValue.DrawContextIsNull");
314 Logging
.logger().severe(message
);
315 throw new IllegalStateException(message
);
318 // Use the tile's texture if available.
319 Texture t
= this.getTexture(dc
.getTextureCache());
320 if (t
== null && this.getTextureData() != null)
321 t
= this.initializeTexture(dc
);
325 if (t
.getMustFlipVertically())
327 GL gl
= GLContext
.getCurrent().getGL();
328 gl
.glMatrixMode(GL
.GL_TEXTURE
);
330 gl
.glScaled(1, -1, 1);
331 gl
.glTranslated(0, -1, 0);
336 // Use the tile's fallback texture if its primary texture is not available.
337 TextureTile resourceTile
= this.getFallbackTile();
338 if (resourceTile
== null) // no fallback specified
341 t
= resourceTile
.getTexture(dc
.getTextureCache());
342 if (t
== null && resourceTile
.getTextureData() != null)
343 t
= resourceTile
.initializeTexture(dc
);
345 if (t
== null) // was not able to initialize the fallback texture
348 // Apply necessary transforms to the fallback texture.
349 GL gl
= GLContext
.getCurrent().getGL();
350 gl
.glMatrixMode(GL
.GL_TEXTURE
);
353 if (t
.getMustFlipVertically())
355 gl
.glScaled(1, -1, 1);
356 gl
.glTranslated(0, -1, 0);
359 this.applyResourceTextureTransform(dc
);
362 private void applyResourceTextureTransform(DrawContext dc
)
366 String message
= Logging
.getMessage("nullValue.DrawContextIsNull");
367 Logging
.logger().severe(message
);
368 throw new IllegalStateException(message
);
371 if (this.getLevel() == null)
374 int levelDelta
= this.getLevelNumber() - this.getFallbackTile().getLevelNumber();
378 double twoToTheN
= Math
.pow(2, levelDelta
);
379 double oneOverTwoToTheN
= 1 / twoToTheN
;
381 double sShift
= oneOverTwoToTheN
* (this.getColumn() % twoToTheN
);
382 double tShift
= oneOverTwoToTheN
* (this.getRow() % twoToTheN
);
384 dc
.getGL().glTranslated(sShift
, tShift
, 0);
385 dc
.getGL().glScaled(oneOverTwoToTheN
, oneOverTwoToTheN
, 1);
389 public boolean equals(Object o
)
393 if (o
== null || getClass() != o
.getClass())
396 final TextureTile tile
= (TextureTile
) o
;
398 return !(this.getTileKey() != null ?
!this.getTileKey().equals(tile
.getTileKey()) : tile
.getTileKey() != null);
402 public int hashCode()
404 return (this.getTileKey() != null ?
this.getTileKey().hashCode() : 0);
408 public String
toString()
410 return this.getSector().toString();