Updated to worldwind release 20070817
[worldwind-tracker.git] / gov / nasa / worldwind / layers / TextureTile.java
blobc9c749e54f122d35c26241f3f396314ebd778b23
1 /*
2 Copyright (C) 2001, 2006 United States Government
3 as represented by the Administrator of the
4 National Aeronautics and Space Administration.
5 All Rights Reserved.
6 */
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.render.*;
15 import gov.nasa.worldwind.util.*;
17 import javax.media.opengl.*;
19 /**
20 * @author tag
21 * @version $Id: TextureTile.java 2533 2007-08-13 05:59:08Z tgaskins $
23 public class TextureTile extends Tile implements SurfaceTile
25 private volatile TextureData textureData;
26 private TextureTile fallbackTile = null; // holds texture to use if own texture not available
27 private Vec4 centroid; // Cartesian coordinate of lat/lon center
28 private Vec4[] corners; // Cartesian coordinate of lat/lon corners
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, TileKey tileKey)
35 super(sector, tileKey);
38 public TextureTile(Sector sector, Level level, int row, int col)
40 super(sector, level, row, col);
43 @Override
44 public final long getSizeInBytes()
46 long size = super.getSizeInBytes();
48 if (this.textureData != null)
49 size += this.textureData.getEstimatedMemorySize();
51 return size;
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)
76 if (tc == null)
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)
88 if (tc == null)
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)
100 if (tc == null)
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)
116 if (globe == null)
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 Vec4[] getCornerPoints(Globe globe)
134 if (globe == null)
136 String msg = Logging.getMessage("nullValue.GlobeIsNull");
137 Logging.logger().severe(msg);
138 throw new IllegalArgumentException(msg);
141 if (this.corners == null)
143 Sector s = this.getSector();
144 this.corners = new Vec4[4];
145 this.corners[0] = globe.computePointFromPosition(s.getMinLatitude(), s.getMinLongitude(), 0); // sw
146 this.corners[1] = globe.computePointFromPosition(s.getMinLatitude(), s.getMaxLongitude(), 0); // se
147 this.corners[2] = globe.computePointFromPosition(s.getMaxLatitude(), s.getMaxLongitude(), 0); // nw
148 this.corners[3] = globe.computePointFromPosition(s.getMaxLatitude(), s.getMinLongitude(), 0); // ne
151 return this.corners;
154 public double getWidth()
156 double sLow = this.corners[0].distanceTo3(this.corners[1]);
157 double sHigh = this.corners[2].distanceTo3(this.corners[3]);
159 return sLow > sHigh ? sLow : sHigh;
162 public double getHeight()
164 double tLow = this.corners[0].distanceTo3(this.corners[2]);
165 double tHigh = this.corners[1].distanceTo3(this.corners[3]);
167 return tLow > tHigh ? tLow : tHigh;
170 public double getMinDistanceToEye()
172 return this.minDistanceToEye;
175 public void setMinDistanceToEye(double minDistanceToEye)
177 if (minDistanceToEye < 0)
179 String msg = Logging.getMessage("layers.TextureTile.MinDistanceToEyeNegative");
180 Logging.logger().severe(msg);
181 throw new IllegalArgumentException(msg);
183 this.minDistanceToEye = minDistanceToEye;
186 public Extent getExtent(DrawContext dc)
188 if (dc == null)
190 String msg = Logging.getMessage("nullValue.DrawContextIsNull");
191 Logging.logger().severe(msg);
192 throw new IllegalArgumentException(msg);
195 if (this.extent == null || this.extentVerticalExaggertion != dc.getVerticalExaggeration())
197 this.extent = Sector.computeBoundingCylinder(dc.getGlobe(), dc.getVerticalExaggeration(), this.getSector());
198 this.extentVerticalExaggertion = dc.getVerticalExaggeration();
201 return this.extent;
204 public TextureTile[] createSubTiles(Level nextLevel)
206 if (nextLevel == null)
208 String msg = Logging.getMessage("nullValue.LevelIsNull");
209 Logging.logger().severe(msg);
210 throw new IllegalArgumentException(msg);
212 Angle p0 = this.getSector().getMinLatitude();
213 Angle p2 = this.getSector().getMaxLatitude();
214 Angle p1 = Angle.midAngle(p0, p2);
216 Angle t0 = this.getSector().getMinLongitude();
217 Angle t2 = this.getSector().getMaxLongitude();
218 Angle t1 = Angle.midAngle(t0, t2);
220 String nextLevelCacheName = nextLevel.getCacheName();
221 int nextLevelNum = nextLevel.getLevelNumber();
222 int row = this.getRow();
223 int col = this.getColumn();
225 TextureTile[] subTiles = new TextureTile[4];
227 TileKey key = new TileKey(nextLevelNum, 2 * row, 2 * col, nextLevelCacheName);
228 TextureTile subTile = this.getTileFromMemoryCache(key);
229 if (subTile != null)
230 subTiles[0] = subTile;
231 else
232 subTiles[0] = new TextureTile(new Sector(p0, p1, t0, t1), nextLevel, 2 * row, 2 * col);
234 key = new TileKey(nextLevelNum, 2 * row, 2 * col + 1, nextLevelCacheName);
235 subTile = this.getTileFromMemoryCache(key);
236 if (subTile != null)
237 subTiles[1] = subTile;
238 else
239 subTiles[1] = new TextureTile(new Sector(p0, p1, t1, t2), nextLevel, 2 * row, 2 * col + 1);
241 key = new TileKey(nextLevelNum, 2 * row + 1, 2 * col, nextLevelCacheName);
242 subTile = this.getTileFromMemoryCache(key);
243 if (subTile != null)
244 subTiles[2] = subTile;
245 else
246 subTiles[2] = new TextureTile(new Sector(p1, p2, t0, t1), nextLevel, 2 * row + 1, 2 * col);
248 key = new TileKey(nextLevelNum, 2 * row + 1, 2 * col + 1, nextLevelCacheName);
249 subTile = this.getTileFromMemoryCache(key);
250 if (subTile != null)
251 subTiles[3] = subTile;
252 else
253 subTiles[3] = new TextureTile(new Sector(p1, p2, t1, t2), nextLevel, 2 * row + 1, 2 * col + 1);
255 return subTiles;
258 private TextureTile getTileFromMemoryCache(TileKey tileKey)
260 return (TextureTile) WorldWind.getMemoryCache(TextureTile.class.getName()).getObject(tileKey);
263 private void updateMemoryCache()
265 if (this.getTileFromMemoryCache(this.getTileKey()) != null)
266 WorldWind.getMemoryCache(TextureTile.class.getName()).add(this.getTileKey(), this);
269 public Texture initializeTexture(DrawContext dc)
271 if (dc == null)
273 String message = Logging.getMessage("nullValue.DrawContextIsNull");
274 Logging.logger().severe(message);
275 throw new IllegalStateException(message);
278 Texture t = this.getTexture(dc.getTextureCache());
279 if (t != null)
280 return t;
282 if (this.getTextureData() == null)
284 String msg = Logging.getMessage("nullValue.TextureDataIsNull");
285 Logging.logger().severe(msg);
286 throw new IllegalStateException(msg);
291 t = TextureIO.newTexture(this.getTextureData());
293 catch (Exception e)
295 Logging.logger().log(
296 java.util.logging.Level.SEVERE, "layers.TextureLayer.ExceptionAttemptingToReadTextureFile", e);
297 return null;
300 this.setTexture(dc.getTextureCache(), t);
301 t.bind();
303 GL gl = dc.getGL();
304 gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
305 gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
306 gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE);
307 gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE);
309 return t;
312 public boolean bind(DrawContext dc)
314 if (dc == null)
316 String message = Logging.getMessage("nullValue.DrawContextIsNull");
317 Logging.logger().severe(message);
318 throw new IllegalStateException(message);
321 Texture t = this.getTexture(dc.getTextureCache());
322 if (t == null && this.getTextureData() != null)
324 t = this.initializeTexture(dc);
325 if (t != null)
326 return true; // texture was bound during initialization.
329 if (t == null && this.getFallbackTile() != null)
331 TextureTile resourceTile = this.getFallbackTile();
332 t = resourceTile.getTexture(dc.getTextureCache());
333 if (t == null)
335 t = resourceTile.initializeTexture(dc);
336 if (t != null)
337 return true; // texture was bound during initialization.
341 if (t != null)
342 t.bind();
344 return t != null;
347 public void applyInternalTransform(DrawContext dc)
349 if (dc == null)
351 String message = Logging.getMessage("nullValue.DrawContextIsNull");
352 Logging.logger().severe(message);
353 throw new IllegalStateException(message);
356 // Use the tile's texture if available.
357 Texture t = this.getTexture(dc.getTextureCache());
358 if (t == null && this.getTextureData() != null)
359 t = this.initializeTexture(dc);
361 if (t != null)
363 if (t.getMustFlipVertically())
365 GL gl = GLContext.getCurrent().getGL();
366 gl.glMatrixMode(GL.GL_TEXTURE);
367 gl.glLoadIdentity();
368 gl.glScaled(1, -1, 1);
369 gl.glTranslated(0, -1, 0);
371 return;
374 // Use the tile's fallback texture if its primary texture is not available.
375 TextureTile resourceTile = this.getFallbackTile();
376 if (resourceTile == null) // no fallback specified
377 return;
379 t = resourceTile.getTexture(dc.getTextureCache());
380 if (t == null && resourceTile.getTextureData() != null)
381 t = resourceTile.initializeTexture(dc);
383 if (t == null) // was not able to initialize the fallback texture
384 return;
386 // Apply necessary transforms to the fallback texture.
387 GL gl = GLContext.getCurrent().getGL();
388 gl.glMatrixMode(GL.GL_TEXTURE);
389 gl.glLoadIdentity();
391 if (t.getMustFlipVertically())
393 gl.glScaled(1, -1, 1);
394 gl.glTranslated(0, -1, 0);
397 this.applyResourceTextureTransform(dc);
400 private void applyResourceTextureTransform(DrawContext dc)
402 if (dc == null)
404 String message = Logging.getMessage("nullValue.DrawContextIsNull");
405 Logging.logger().severe(message);
406 throw new IllegalStateException(message);
409 if (this.getLevel() == null)
410 return;
412 int levelDelta = this.getLevelNumber() - this.getFallbackTile().getLevelNumber();
413 if (levelDelta <= 0)
414 return;
416 double twoToTheN = Math.pow(2, levelDelta);
417 double oneOverTwoToTheN = 1 / twoToTheN;
419 double sShift = oneOverTwoToTheN * (this.getColumn() % twoToTheN);
420 double tShift = oneOverTwoToTheN * (this.getRow() % twoToTheN);
422 dc.getGL().glTranslated(sShift, tShift, 0);
423 dc.getGL().glScaled(oneOverTwoToTheN, oneOverTwoToTheN, 1);
426 @Override
427 public boolean equals(Object o)
429 if (this == o)
430 return true;
431 if (o == null || getClass() != o.getClass())
432 return false;
434 final TextureTile tile = (TextureTile) o;
436 return !(this.getTileKey() != null ? !this.getTileKey().equals(tile.getTileKey()) : tile.getTileKey() != null);
439 @Override
440 public int hashCode()
442 return (this.getTileKey() != null ? this.getTileKey().hashCode() : 0);
445 @Override
446 public String toString()
448 return this.getSector().toString();