Skip to content

Instantly share code, notes, and snippets.

@strikerM
Created February 8, 2017 09:01
Show Gist options
  • Save strikerM/2aa6748c2e28a95c7365072d69e7e6d4 to your computer and use it in GitHub Desktop.
Save strikerM/2aa6748c2e28a95c7365072d69e7e6d4 to your computer and use it in GitHub Desktop.
SurfaceShapeTile - update previousShapes after the texture has been created
/*
* Copyright (C) 2014 United States Government as represented by the Administrator of the
* National Aeronautics and Space Administration. All Rights Reserved.
*/
/**
* @exports SurfaceShapeTile
* @version $Id: SurfaceShapeTile.js 3048 2015-04-23 23:26:47Z danm $
*/
define([
'../geom/Angle',
'../error/ArgumentError',
'../util/Level',
'../util/Logger',
'../geom/Sector',
'../render/Texture',
'../render/TextureTile'
],
function (Angle,
ArgumentError,
Level,
Logger,
Sector,
Texture,
TextureTile) {
"use strict";
/**
* Constructs a surface shape tile.
* @alias SurfaceShapeTile
* @constructor
* @classdesc Represents a texture map containing renditions of surface shapes applied to a portion of a globe's terrain.
* @param {Sector} sector The sector this tile covers.
* @param {Level} level The level this tile is associated with.
* @param {number} row This tile's row in the associated level.
* @param {number} column This tile's column in the associated level.
* @throws {ArgumentError} If the specified sector or level is null or undefined, the row or column arguments
* are less than zero, or the specified image path is null, undefined or empty.
*
*/
var SurfaceShapeTile = function(sector, level, row, column) {
TextureTile.call(this, sector, level, row, column); // args are checked in the superclass' constructor
/**
* The surface shapes that affect this tile.
* @type {SurfaceShape[]}
*/
this.surfaceShapes = [];
/**
* The sector that bounds this tile.
* @type {Sector}
*/
this.sector = sector;
/**
* A string to use as a cache key.
* @type {string}
*/
this.cacheKey = null;
/**
* Internal use only. Intentionally not documented.
* @type {number}
*/
this.pickSequence = 0;
// Internal use only. Intentionally not documented.
this.surfaceShapeStateKeys = [];
// Internal use only. Intentionally not documented.
this.prevSurfaceShapes = [];
this.createCtx2D();
};
SurfaceShapeTile.prototype = Object.create(TextureTile.prototype);
/**
* Clear all collected surface shapes.
*/
SurfaceShapeTile.prototype.clearShapes = function() {
this.surfaceShapes = [];
};
/**
* Called from this.needsUpdate when previous is different than current.
*/
SurfaceShapeTile.prototype.setPrevious = function() {
this.prevSurfaceShapes = this.surfaceShapes;
};
/**
* Query whether any surface shapes have been collected.
* @returns {boolean} Returns true if there are collected surface shapes.
*/
SurfaceShapeTile.prototype.hasShapes = function() {
return this.surfaceShapes.length > 0;
};
/**
* Get all shapes that this tile references.
* @returns {SurfaceShape[]} The collection of surface shapes referenced by this tile.
*/
SurfaceShapeTile.prototype.getShapes = function() {
return this.surfaceShapes;
};
/**
* Set the shapes this tile should reference.
* @param {SurfaceShape[]} surfaceShapes The collection of surface shapes to be referenced by this tile.
*/
SurfaceShapeTile.prototype.setShapes = function(surfaceShapes) {
this.surfaceShapes = surfaceShapes;
};
/**
* The sector that bounds this tile.
* @returns {Sector}
*/
SurfaceShapeTile.prototype.getSector = function() {
return this.sector;
};
/**
* Add a surface shape to this tile's collection of surface shapes.
* @param {SurfaceShape} surfaceShape The surface shape to add.
*/
SurfaceShapeTile.prototype.addSurfaceShape = function(surfaceShape) {
this.surfaceShapes.push(surfaceShape);
this.surfaceShapeStateKeys.push(surfaceShape.stateKey);
};
/**
* Add multiple surface shapes to this tile's collection.
* @param {SurfaceShape[]} shapes A collection of surface shapes to add to the collection of this tile.
*/
SurfaceShapeTile.prototype.addAllSurfaceShapes = function(shapes) {
for (var idx = 0, len = shapes.length; idx < len; idx += 1) {
var shape = shapes[idx];
this.addAllSurfaceShapes(shape);
}
};
// Internal use only. Intentionally not documented.
SurfaceShapeTile.prototype.needsUpdate = function(dc) {
var idx, len, surfaceShape, surfaceShapeStateKey;
// If the number of shapes have changed, ... (cheap test)
if (this.prevSurfaceShapes.length != this.surfaceShapes.length) {
return true;
}
// If shapes have been removed since the previous iteration, ...
for (idx = 0, len = this.prevSurfaceShapes.length; idx < len; idx += 1) {
surfaceShape = this.prevSurfaceShapes[idx];
if (this.surfaceShapes.indexOf(surfaceShape) < 0) {
return true;
}
}
// If shapes added since the previous iteration, ...
for (idx = 0, len = this.surfaceShapes.length; idx < len; idx += 1) {
surfaceShape = this.surfaceShapes[idx];
if (this.prevSurfaceShapes.indexOf(surfaceShape) < 0) {
return true;
}
}
// If the state key of the shape is different than the saved state key for that shape, ...
for (idx = 0, len = this.surfaceShapes.length; idx < len; idx += 1) {
surfaceShape = this.surfaceShapes[idx];
surfaceShapeStateKey = this.surfaceShapeStateKeys[idx];
if (surfaceShapeStateKey != surfaceShape.stateKey) {
return true;
}
}
// If a texture does not already exist, ...
if (!this.hasTexture(dc)) {
return true;
}
// If you get here, the texture can be reused.
return false;
};
/**
* Determine whether the surface shape tile has a valid texture.
* @param {DrawContext} dc The draw context.
* @returns {boolean} True if the surface shape tile has a valid texture, else false.
*/
SurfaceShapeTile.prototype.hasTexture = function(dc) {
if (dc.pickingMode) {
return false;
}
var gpuResourceCache = dc.gpuResourceCache;
if (!this.gpuCacheKey) {
this.gpuCacheKey = this.getCacheKey();
}
var texture = gpuResourceCache.resourceForKey(this.gpuCacheKey);
return !!texture;
};
/**
* Redraw all of the surface shapes onto the texture for this tile.
* @param {DrawContext} dc
* @returns {Texture}
*/
SurfaceShapeTile.prototype.updateTexture = function(dc) {
var gl = dc.currentGlContext,
canvas = SurfaceShapeTile.canvas;
canvas.width = this.tileWidth;
canvas.height = this.tileHeight;
var ctx2D = SurfaceShapeTile.ctx2D;
// Mapping from lat/lon to x/y:
// lon = minlon => x = 0
// lon = maxLon => x = 256
// lat = minLat => y = 256
// lat = maxLat => y = 0
// (assuming texture size is 256)
// So:
// x = 256 / sector.dlon * (lon - minLon)
// y = -256 / sector.dlat * (lat - maxLat)
var xScale = this.tileWidth / this.sector.deltaLongitude(),
yScale = -this.tileHeight / this.sector.deltaLatitude(),
xOffset = -this.sector.minLongitude * xScale,
yOffset = -this.sector.maxLatitude * yScale;
for (var idx = 0, len = this.surfaceShapes.length; idx < len; idx += 1) {
var shape = this.surfaceShapes[idx];
this.surfaceShapeStateKeys[idx] = shape.stateKey;
shape.renderToTexture(dc, ctx2D, xScale, yScale, xOffset, yOffset);
}
this.setPrevious();
var texture = new Texture(gl, canvas);
var gpuResourceCache = dc.gpuResourceCache;
this.gpuCacheKey = this.getCacheKey();
gpuResourceCache.putResource(this.gpuCacheKey, texture, texture.size);
return texture;
};
/**
* Get a key suitable for cache look-ups.
* @returns {string}
*/
SurfaceShapeTile.prototype.getCacheKey = function() {
if (!this.cacheKey) {
this.cacheKey = "SurfaceShapeTile:" +
this.tileKey + "," +
this.pickSequence.toString();
}
return this.cacheKey;
};
/**
* Create a new canvas and its 2D context on demand.
*/
SurfaceShapeTile.prototype.createCtx2D = function() {
// If the context was previously created, ...
if (!SurfaceShapeTile.ctx2D) {
SurfaceShapeTile.canvas = document.createElement("canvas");
SurfaceShapeTile.ctx2D = SurfaceShapeTile.canvas.getContext("2d");
}
};
/*
* For internal use only.
* 2D canvas and context, which is created lazily on demand.
*/
SurfaceShapeTile.canvas = null;
SurfaceShapeTile.ctx2D = null;
return SurfaceShapeTile;
}
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment