Update to Worldwind release 0.4.1
[worldwind-tracker.git] / gov / nasa / worldwind / layers / TextureTile.java
blobe2ef8a496e5a5141480869817e4b789a5c39e836
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.globes.EllipsoidalGlobe;
15 import gov.nasa.worldwind.render.*;
16 import gov.nasa.worldwind.util.*;
18 import javax.media.opengl.*;
20 /**
21 * @author tag
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)
35 super(sector);
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 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)
150 if (dc == null)
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();
163 return this.extent;
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);
191 if (subTile != null)
192 subTiles[0] = subTile;
193 else
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);
198 if (subTile != null)
199 subTiles[1] = subTile;
200 else
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);
205 if (subTile != null)
206 subTiles[2] = subTile;
207 else
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);
212 if (subTile != null)
213 subTiles[3] = subTile;
214 else
215 subTiles[3] = new TextureTile(new Sector(p1, p2, t1, t2), nextLevel, 2 * row + 1, 2 * col + 1);
217 return subTiles;
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)
233 if (dc == null)
235 String message = Logging.getMessage("nullValue.DrawContextIsNull");
236 Logging.logger().severe(message);
237 throw new IllegalStateException(message);
240 Texture t = this.getTexture(dc.getTextureCache());
241 if (t != null)
242 return t;
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());
255 catch (Exception e)
257 Logging.logger().log(
258 java.util.logging.Level.SEVERE, "layers.TextureLayer.ExceptionAttemptingToReadTextureFile", e);
259 return null;
262 this.setTexture(dc.getTextureCache(), t);
263 t.bind();
265 GL gl = dc.getGL();
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);
271 return t;
274 public boolean bind(DrawContext dc)
276 if (dc == null)
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);
287 if (t != null)
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());
295 if (t == null)
297 t = resourceTile.initializeTexture(dc);
298 if (t != null)
299 return true; // texture was bound during initialization.
303 if (t != null)
304 t.bind();
306 return t != null;
309 public void applyInternalTransform(DrawContext dc)
311 if (dc == null)
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);
323 if (t != null)
325 if (t.getMustFlipVertically())
327 GL gl = GLContext.getCurrent().getGL();
328 gl.glMatrixMode(GL.GL_TEXTURE);
329 gl.glLoadIdentity();
330 gl.glScaled(1, -1, 1);
331 gl.glTranslated(0, -1, 0);
333 return;
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
339 return;
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
346 return;
348 // Apply necessary transforms to the fallback texture.
349 GL gl = GLContext.getCurrent().getGL();
350 gl.glMatrixMode(GL.GL_TEXTURE);
351 gl.glLoadIdentity();
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)
364 if (dc == null)
366 String message = Logging.getMessage("nullValue.DrawContextIsNull");
367 Logging.logger().severe(message);
368 throw new IllegalStateException(message);
371 if (this.getLevel() == null)
372 return;
374 int levelDelta = this.getLevelNumber() - this.getFallbackTile().getLevelNumber();
375 if (levelDelta <= 0)
376 return;
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);
388 @Override
389 public boolean equals(Object o)
391 if (this == o)
392 return true;
393 if (o == null || getClass() != o.getClass())
394 return false;
396 final TextureTile tile = (TextureTile) o;
398 return !(this.getTileKey() != null ? !this.getTileKey().equals(tile.getTileKey()) : tile.getTileKey() != null);
401 @Override
402 public int hashCode()
404 return (this.getTileKey() != null ? this.getTileKey().hashCode() : 0);
407 @Override
408 public String toString()
410 return this.getSector().toString();