From 063f6070af852a68b15e0640060d4f32739cdf46 Mon Sep 17 00:00:00 2001 From: Ryan Hickman Date: Mon, 6 Feb 2017 11:42:59 -0700 Subject: [PATCH 01/18] Apply color palette on render. --- Source/Renderer/UniformState.js | 12 + Source/Scene/CustomTemplateImageryProvider.js | 1002 +++++++++++++++++ Source/Scene/FrameState.js | 10 +- Source/Scene/GlobeSurfaceShaderSet.js | 29 +- Source/Scene/GlobeSurfaceTileProvider.js | 13 +- Source/Scene/ImageryLayer.js | 31 + Source/Scene/ImageryProvider.js | 9 + Source/Shaders/GlobeFS.glsl | 94 ++ 8 files changed, 1192 insertions(+), 8 deletions(-) create mode 100644 Source/Scene/CustomTemplateImageryProvider.js diff --git a/Source/Renderer/UniformState.js b/Source/Renderer/UniformState.js index 759659750639..41da0ddb1265 100644 --- a/Source/Renderer/UniformState.js +++ b/Source/Renderer/UniformState.js @@ -150,6 +150,7 @@ define([ this._fogDensity = undefined; + this._imageryColorPalette = 1.0; this._imagerySplitPosition = 0.0; this._pixelSizePerMeter = undefined; this._geometricToleranceOverMeter = undefined; @@ -800,6 +801,16 @@ define([ get : function() { return this._imagerySplitPosition; } + }, + + /** + * @memberof UniformState.prototype + * @type {Array} + */ + imageryColorPalette : { + get : function() { + return this._imageryColorPalette; + } } }); @@ -962,6 +973,7 @@ define([ this._temeToPseudoFixed = Transforms.computeTemeToPseudoFixedMatrix(frameState.time, this._temeToPseudoFixed); this._imagerySplitPosition = frameState.imagerySplitPosition; + this._imageryColorPalette = frameState.imageryColorPalette; var fov = camera.frustum.fov; var viewport = this._viewport; var pixelSizePerMeter; diff --git a/Source/Scene/CustomTemplateImageryProvider.js b/Source/Scene/CustomTemplateImageryProvider.js new file mode 100644 index 000000000000..1658261ae8f1 --- /dev/null +++ b/Source/Scene/CustomTemplateImageryProvider.js @@ -0,0 +1,1002 @@ +/*global define*/ +define([ + '../Core/Cartesian2', + '../Core/Cartesian3', + '../Core/Cartographic', + '../Core/combine', + '../Core/Credit', + '../Core/defaultValue', + '../Core/defined', + '../Core/defineProperties', + '../Core/DeveloperError', + '../Core/Event', + '../Core/freezeObject', + '../Core/GeographicTilingScheme', + '../Core/isArray', + '../Core/loadJson', + '../Core/loadText', + '../Core/loadWithXhr', + '../Core/loadXML', + '../Core/Math', + '../Core/Rectangle', + '../Core/TileProviderError', + '../Core/WebMercatorTilingScheme', + '../ThirdParty/when', + './ImageryProvider' + ], function( + Cartesian2, + Cartesian3, + Cartographic, + combine, + Credit, + defaultValue, + defined, + defineProperties, + DeveloperError, + Event, + freezeObject, + GeographicTilingScheme, + isArray, + loadJson, + loadText, + loadWithXhr, + loadXML, + CesiumMath, + Rectangle, + TileProviderError, + WebMercatorTilingScheme, + when, + ImageryProvider + ) { + 'use strict'; + + /** + * Provides imagery by requesting tiles using a specified URL template. + * + * @alias CustomTemplateImageryProvider + * @constructor + * + * @param {Promise.|Object} [options] Object with the following properties: + * @param {String} options.url The URL template to use to request tiles. It has the following keywords: + * + * @param {String} [options.pickFeaturesUrl] The URL template to use to pick features. If this property is not specified, + * {@link CustomTemplateImageryProvider#pickFeatures} will immediately returned undefined, indicating no + * features picked. The URL template supports all of the keywords supported by the url + * parameter, plus the following: + * + * @param {Object} [options.urlSchemeZeroPadding] Gets the URL scheme zero padding for each tile coordinate. The format is '000' where + * each coordinate will be padded on the left with zeros to match the width of the passed string of zeros. e.g. Setting: + * urlSchemeZeroPadding : { '{x}' : '0000'} + * will cause an 'x' value of 12 to return the string '0012' for {x} in the generated URL. + * It the passed object has the following keywords: + * + * @param {String|String[]} [options.subdomains='abc'] The subdomains to use for the {s} placeholder in the URL template. + * If this parameter is a single string, each character in the string is a subdomain. If it is + * an array, each element in the array is a subdomain. + * @param {Object} [options.proxy] A proxy to use for requests. This object is expected to have a getURL function which returns the proxied URL. + * @param {Credit|String} [options.credit=''] A credit for the data source, which is displayed on the canvas. + * @param {Number} [options.minimumLevel=0] The minimum level-of-detail supported by the imagery provider. Take care when specifying + * this that the number of tiles at the minimum level is small, such as four or less. A larger number is likely + * to result in rendering problems. + * @param {Number} [options.maximumLevel] The maximum level-of-detail supported by the imagery provider, or undefined if there is no limit. + * @param {Rectangle} [options.rectangle=Rectangle.MAX_VALUE] The rectangle, in radians, covered by the image. + * @param {TilingScheme} [options.tilingScheme=WebMercatorTilingScheme] The tiling scheme specifying how the ellipsoidal + * surface is broken into tiles. If this parameter is not provided, a {@link WebMercatorTilingScheme} + * is used. + * @param {Ellipsoid} [options.ellipsoid] The ellipsoid. If the tilingScheme is specified, + * this parameter is ignored and the tiling scheme's ellipsoid is used instead. If neither + * parameter is specified, the WGS84 ellipsoid is used. + * @param {Number} [options.tileWidth=256] Pixel width of image tiles. + * @param {Number} [options.tileHeight=256] Pixel height of image tiles. + * @param {Boolean} [options.hasAlphaChannel=true] true if the images provided by this imagery provider + * include an alpha channel; otherwise, false. If this property is false, an alpha channel, if + * present, will be ignored. If this property is true, any images without an alpha channel will + * be treated as if their alpha is 1.0 everywhere. When this property is false, memory usage + * and texture upload time are potentially reduced. + * @param {GetFeatureInfoFormat[]} [options.getFeatureInfoFormats] The formats in which to get feature information at a + * specific location when {@link CustomTemplateImageryProvider#pickFeatures} is invoked. If this + * parameter is not specified, feature picking is disabled. + * @param {Boolean} [options.enablePickFeatures=true] If true, {@link CustomTemplateImageryProvider#pickFeatures} will + * request the options.pickFeaturesUrl and attempt to interpret the features included in the response. If false, + * {@link CustomTemplateImageryProvider#pickFeatures} will immediately return undefined (indicating no pickable + * features) without communicating with the server. Set this property to false if you know your data + * source does not support picking features or if you don't want this provider's features to be pickable. Note + * that this can be dynamically overridden by modifying the {@link UriTemplateImageryProvider#enablePickFeatures} + * property. + * + * + * @example + * // Access Natural Earth II imagery, which uses a TMS tiling scheme and Geographic (EPSG:4326) project + * var tms = new Cesium.CustomTemplateImageryProvider({ + * url : 'https://cesiumjs.org/tilesets/imagery/naturalearthii/{z}/{x}/{reverseY}.jpg', + * credit : '© Analytical Graphics, Inc.', + * tilingScheme : new Cesium.GeographicTilingScheme(), + * maximumLevel : 5 + * }); + * // Access the CartoDB Positron basemap, which uses an OpenStreetMap-like tiling scheme. + * var positron = new Cesium.CustomTemplateImageryProvider({ + * url : 'http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png', + * credit : 'Map tiles by CartoDB, under CC BY 3.0. Data by OpenStreetMap, under ODbL.' + * }); + * // Access a Web Map Service (WMS) server. + * var wms = new Cesium.CustomTemplateImageryProvider({ + * url : 'https://programs.communications.gov.au/geoserver/ows?tiled=true&' + + * 'transparent=true&format=image%2Fpng&exceptions=application%2Fvnd.ogc.se_xml&' + + * 'styles=&service=WMS&version=1.1.1&request=GetMap&' + + * 'layers=public%3AMyBroadband_Availability&srs=EPSG%3A3857&' + + * 'bbox={westProjected}%2C{southProjected}%2C{eastProjected}%2C{northProjected}&' + + * 'width=256&height=256', + * rectangle : Cesium.Rectangle.fromDegrees(96.799393, -43.598214999057824, 153.63925700000001, -9.2159219997013) + * }); + * + * @see ArcGisMapServerImageryProvider + * @see BingMapsImageryProvider + * @see GoogleEarthImageryProvider + * @see createOpenStreetMapImageryProvider + * @see SingleTileImageryProvider + * @see createTileMapServiceImageryProvider + * @see WebMapServiceImageryProvider + * @see WebMapTileServiceImageryProvider + */ + function CustomTemplateImageryProvider(options) { + //>>includeStart('debug', pragmas.debug); + if (!defined(options)) { + throw new DeveloperError('options is required.'); + } + if (!when.isPromise(options) && !defined(options.url)) { + throw new DeveloperError('options is required.'); + } + //>>includeEnd('debug'); + + this._errorEvent = new Event(); + + this._url = undefined; + this._urlSchemeZeroPadding = undefined; + this._pickFeaturesUrl = undefined; + this._proxy = undefined; + this._tileWidth = undefined; + this._tileHeight = undefined; + this._maximumLevel = undefined; + this._minimumLevel = undefined; + this._tilingScheme = undefined; + this._rectangle = undefined; + this._tileDiscardPolicy = undefined; + this._credit = undefined; + this._hasAlphaChannel = undefined; + this._readyPromise = undefined; + this._palette = undefined; + this._min = undefined; + this._max = undefined; + + /** + * Gets or sets a value indicating whether feature picking is enabled. If true, {@link CustomTemplateImageryProvider#pickFeatures} will + * request the options.pickFeaturesUrl and attempt to interpret the features included in the response. If false, + * {@link CustomTemplateImageryProvider#pickFeatures} will immediately return undefined (indicating no pickable + * features) without communicating with the server. Set this property to false if you know your data + * source does not support picking features or if you don't want this provider's features to be pickable. + * @type {Boolean} + * @default true + */ + this.enablePickFeatures = true; + + this.reinitialize(options); + } + + defineProperties(CustomTemplateImageryProvider.prototype, { + /** + * Gets the URL template to use to request tiles. It has the following keywords: + * + * @memberof CustomTemplateImageryProvider.prototype + * @type {String} + * @readonly + */ + url : { + get : function() { + return this._url; + } + }, + + /** + * Gets the URL scheme zero padding for each tile coordinate. The format is '000' where each coordinate will be padded on + * the left with zeros to match the width of the passed string of zeros. e.g. Setting: + * urlSchemeZeroPadding : { '{x}' : '0000'} + * will cause an 'x' value of 12 to return the string '0012' for {x} in the generated URL. + * It has the following keywords: + * + * @memberof CustomTemplateImageryProvider.prototype + * @type {Object} + * @readonly + */ + urlSchemeZeroPadding : { + get : function() { + return this._urlSchemeZeroPadding; + } + }, + + + /** + * Gets the URL template to use to use to pick features. If this property is not specified, + * {@link CustomTemplateImageryProvider#pickFeatures} will immediately returned undefined, indicating no + * features picked. The URL template supports all of the keywords supported by the + * {@link CustomTemplateImageryProvider#url} property, plus the following: + * + * @type {String} + * @readonly + */ + pickFeaturesUrl : { + get : function() { + return this._pickFeaturesUrl; + } + }, + + /** + * Gets the proxy used by this provider. + * @memberof CustomTemplateImageryProvider.prototype + * @type {Proxy} + * @readonly + * @default undefined + */ + proxy : { + get : function() { + return this._proxy; + } + }, + + /** + * Gets the width of each tile, in pixels. This function should + * not be called before {@link CustomTemplateImageryProvider#ready} returns true. + * @memberof CustomTemplateImageryProvider.prototype + * @type {Number} + * @readonly + * @default 256 + */ + tileWidth : { + get : function() { + //>>includeStart('debug', pragmas.debug); + if (!this.ready) { + throw new DeveloperError('tileWidth must not be called before the imagery provider is ready.'); + } + //>>includeEnd('debug'); + return this._tileWidth; + } + }, + + /** + * Gets the height of each tile, in pixels. This function should + * not be called before {@link CustomTemplateImageryProvider#ready} returns true. + * @memberof CustomTemplateImageryProvider.prototype + * @type {Number} + * @readonly + * @default 256 + */ + tileHeight: { + get : function() { + //>>includeStart('debug', pragmas.debug); + if (!this.ready) { + throw new DeveloperError('tileHeight must not be called before the imagery provider is ready.'); + } + //>>includeEnd('debug'); + return this._tileHeight; + } + }, + + /** + * Gets the maximum level-of-detail that can be requested, or undefined if there is no limit. + * This function should not be called before {@link CustomTemplateImageryProvider#ready} returns true. + * @memberof CustomTemplateImageryProvider.prototype + * @type {Number} + * @readonly + * @default undefined + */ + maximumLevel : { + get : function() { + //>>includeStart('debug', pragmas.debug); + if (!this.ready) { + throw new DeveloperError('maximumLevel must not be called before the imagery provider is ready.'); + } + //>>includeEnd('debug'); + return this._maximumLevel; + } + }, + + /** + * Gets the minimum level-of-detail that can be requested. This function should + * not be called before {@link CustomTemplateImageryProvider#ready} returns true. + * @memberof CustomTemplateImageryProvider.prototype + * @type {Number} + * @readonly + * @default 0 + */ + minimumLevel : { + get : function() { + //>>includeStart('debug', pragmas.debug); + if (!this.ready) { + throw new DeveloperError('minimumLevel must not be called before the imagery provider is ready.'); + } + //>>includeEnd('debug'); + return this._minimumLevel; + } + }, + + /** + * Gets the tiling scheme used by this provider. This function should + * not be called before {@link CustomTemplateImageryProvider#ready} returns true. + * @memberof CustomTemplateImageryProvider.prototype + * @type {TilingScheme} + * @readonly + * @default new WebMercatorTilingScheme() + */ + tilingScheme : { + get : function() { + //>>includeStart('debug', pragmas.debug); + if (!this.ready) { + throw new DeveloperError('tilingScheme must not be called before the imagery provider is ready.'); + } + //>>includeEnd('debug'); + return this._tilingScheme; + } + }, + + /** + * Gets the rectangle, in radians, of the imagery provided by this instance. This function should + * not be called before {@link CustomTemplateImageryProvider#ready} returns true. + * @memberof CustomTemplateImageryProvider.prototype + * @type {Rectangle} + * @readonly + * @default tilingScheme.rectangle + */ + rectangle : { + get : function() { + //>>includeStart('debug', pragmas.debug); + if (!this.ready) { + throw new DeveloperError('rectangle must not be called before the imagery provider is ready.'); + } + //>>includeEnd('debug'); + return this._rectangle; + } + }, + + /** + * Gets the tile discard policy. If not undefined, the discard policy is responsible + * for filtering out "missing" tiles via its shouldDiscardImage function. If this function + * returns undefined, no tiles are filtered. This function should + * not be called before {@link CustomTemplateImageryProvider#ready} returns true. + * @memberof CustomTemplateImageryProvider.prototype + * @type {TileDiscardPolicy} + * @readonly + * @default undefined + */ + tileDiscardPolicy : { + get : function() { + //>>includeStart('debug', pragmas.debug); + if (!this.ready) { + throw new DeveloperError('tileDiscardPolicy must not be called before the imagery provider is ready.'); + } + //>>includeEnd('debug'); + return this._tileDiscardPolicy; + } + }, + + /** + * Gets an event that is raised when the imagery provider encounters an asynchronous error. By subscribing + * to the event, you will be notified of the error and can potentially recover from it. Event listeners + * are passed an instance of {@link TileProviderError}. + * @memberof CustomTemplateImageryProvider.prototype + * @type {Event} + * @readonly + */ + errorEvent : { + get : function() { + return this._errorEvent; + } + }, + + /** + * Gets a value indicating whether or not the provider is ready for use. + * @memberof CustomTemplateImageryProvider.prototype + * @type {Boolean} + * @readonly + */ + ready : { + get : function() { + return defined(this._urlParts); + } + }, + + /** + * Gets a promise that resolves to true when the provider is ready for use. + * @memberof CustomTemplateImageryProvider.prototype + * @type {Promise.} + * @readonly + */ + readyPromise : { + get : function() { + return this._readyPromise; + } + }, + + /** + * Gets the credit to display when this imagery provider is active. Typically this is used to credit + * the source of the imagery. This function should not be called before {@link CustomTemplateImageryProvider#ready} returns true. + * @memberof CustomTemplateImageryProvider.prototype + * @type {Credit} + * @readonly + * @default undefined + */ + credit : { + get : function() { + //>>includeStart('debug', pragmas.debug); + if (!this.ready) { + throw new DeveloperError('credit must not be called before the imagery provider is ready.'); + } + //>>includeEnd('debug'); + return this._credit; + } + }, + + /** + * Gets a value indicating whether or not the images provided by this imagery provider + * include an alpha channel. If this property is false, an alpha channel, if present, will + * be ignored. If this property is true, any images without an alpha channel will be treated + * as if their alpha is 1.0 everywhere. When this property is false, memory usage + * and texture upload time are reduced. This function should + * not be called before {@link ImageryProvider#ready} returns true. + * @memberof CustomTemplateImageryProvider.prototype + * @type {Boolean} + * @readonly + * @default true + */ + hasAlphaChannel : { + get : function() { + //>>includeStart('debug', pragmas.debug); + if (!this.ready) { + throw new DeveloperError('hasAlphaChannel must not be called before the imagery provider is ready.'); + } + //>>includeEnd('debug'); + return this._hasAlphaChannel; + } + } + }); + + /** + * Reinitializes this instance. Reinitializing an instance already in use is supported, but it is not + * recommended because existing tiles provided by the imagery provider will not be updated. + * + * @param {Promise.|Object} options Any of the options that may be passed to the {@link CustomTemplateImageryProvider} constructor. + */ + CustomTemplateImageryProvider.prototype.reinitialize = function(options) { + var that = this; + that._readyPromise = when(options).then(function(properties) { + //>>includeStart('debug', pragmas.debug); + if (!defined(properties)) { + throw new DeveloperError('options is required.'); + } + if (!defined(properties.url)) { + throw new DeveloperError('options.url is required.'); + } + //>>includeEnd('debug'); + that.enablePickFeatures = defaultValue(properties.enablePickFeatures, that.enablePickFeatures); + that._url = properties.url; + that._urlSchemeZeroPadding = defaultValue(properties.urlSchemeZeroPadding, that.urlSchemeZeroPadding); + that._pickFeaturesUrl = properties.pickFeaturesUrl; + that._proxy = properties.proxy; + that._tileDiscardPolicy = properties.tileDiscardPolicy; + that._getFeatureInfoFormats = properties.getFeatureInfoFormats; + + that._subdomains = properties.subdomains; + if (isArray(that._subdomains)) { + that._subdomains = that._subdomains.slice(); + } else if (defined(that._subdomains) && that._subdomains.length > 0) { + that._subdomains = that._subdomains.split(''); + } else { + that._subdomains = ['a', 'b', 'c']; + } + + that._tileWidth = defaultValue(properties.tileWidth, 256); + that._tileHeight = defaultValue(properties.tileHeight, 256); + that._minimumLevel = defaultValue(properties.minimumLevel, 0); + that._maximumLevel = properties.maximumLevel; + that._tilingScheme = defaultValue(properties.tilingScheme, new WebMercatorTilingScheme({ ellipsoid : properties.ellipsoid })); + that._rectangle = defaultValue(properties.rectangle, that._tilingScheme.rectangle); + that._rectangle = Rectangle.intersection(that._rectangle, that._tilingScheme.rectangle); + that._hasAlphaChannel = defaultValue(properties.hasAlphaChannel, true); + + that._colorPalette = defaultValue(properties.colorPalette); + that._min = defaultValue(properties.min, 0); + that._max = defaultValue(properties.max, 100); + + var credit = properties.credit; + if (typeof credit === 'string') { + credit = new Credit(credit); + } + that._credit = credit; + + that._urlParts = urlTemplateToParts(that._url, tags); + that._pickFeaturesUrlParts = urlTemplateToParts(that._pickFeaturesUrl, pickFeaturesTags); + return true; + }); + }; + + /** + * Gets the credits to be displayed when a given tile is displayed. + * + * @param {Number} x The tile X coordinate. + * @param {Number} y The tile Y coordinate. + * @param {Number} level The tile level; + * @returns {Credit[]} The credits to be displayed when the tile is displayed. + * + * @exception {DeveloperError} getTileCredits must not be called before the imagery provider is ready. + */ + CustomTemplateImageryProvider.prototype.getTileCredits = function(x, y, level) { + //>>includeStart('debug', pragmas.debug); + if (!this.ready) { + throw new DeveloperError('getTileCredits must not be called before the imagery provider is ready.'); + } + //>>includeEnd('debug'); + return undefined; + }; + + /** + * Requests the image for a given tile. This function should + * not be called before {@link CustomTemplateImageryProvider#ready} returns true. + * + * @param {Number} x The tile X coordinate. + * @param {Number} y The tile Y coordinate. + * @param {Number} level The tile level. + * @returns {Promise.|undefined} A promise for the image that will resolve when the image is available, or + * undefined if there are too many active requests to the server, and the request + * should be retried later. The resolved image may be either an + * Image or a Canvas DOM object. + */ + CustomTemplateImageryProvider.prototype.requestImage = function(x, y, level) { + //>>includeStart('debug', pragmas.debug); + if (!this.ready) { + throw new DeveloperError('requestImage must not be called before the imagery provider is ready.'); + } + //>>includeEnd('debug'); + var url = buildImageUrl(this, x, y, level); + var imagePromise = ImageryProvider.loadImage(this, url); + if(!defined(imagePromise)) { + return imagePromise; + } + + var that = this; + return when(imagePromise, function(image) { + return image; + }); + }; + + /** + * Asynchronously determines what features, if any, are located at a given longitude and latitude within + * a tile. This function should not be called before {@link ImageryProvider#ready} returns true. + * + * @param {Number} x The tile X coordinate. + * @param {Number} y The tile Y coordinate. + * @param {Number} level The tile level. + * @param {Number} longitude The longitude at which to pick features. + * @param {Number} latitude The latitude at which to pick features. + * @return {Promise.|undefined} A promise for the picked features that will resolve when the asynchronous + * picking completes. The resolved value is an array of {@link ImageryLayerFeatureInfo} + * instances. The array may be empty if no features are found at the given location. + * It may also be undefined if picking is not supported. + */ + CustomTemplateImageryProvider.prototype.pickFeatures = function(x, y, level, longitude, latitude) { + //>>includeStart('debug', pragmas.debug); + if (!this.ready) { + throw new DeveloperError('pickFeatures must not be called before the imagery provider is ready.'); + } + //>>includeEnd('debug'); + + if (!this.enablePickFeatures) { + return undefined; + } + + var format = this._getFeatureInfoFormats[0]; + + return format.callback(x, y, level, longitude, latitude); + }; + + function buildImageUrl(imageryProvider, x, y, level) { + degreesScratchComputed = false; + projectedScratchComputed = false; + + return buildUrl(imageryProvider, imageryProvider._urlParts, function(partFunction) { + return partFunction(imageryProvider, x, y, level); + }); + } + + function buildPickFeaturesUrl(imageryProvider, x, y, level, longitude, latitude, format) { + degreesScratchComputed = false; + projectedScratchComputed = false; + ijScratchComputed = false; + longitudeLatitudeProjectedScratchComputed = false; + + return buildUrl(imageryProvider, imageryProvider._pickFeaturesUrlParts, function(partFunction) { + return partFunction(imageryProvider, x, y, level, longitude, latitude, format); + }); + } + + function buildUrl(imageryProvider, parts, partFunctionInvoker) { + var url = ''; + + for (var i = 0; i < parts.length; ++i) { + var part = parts[i]; + if (typeof part === 'string') { + url += part; + } else { + url += encodeURIComponent(partFunctionInvoker(part)); + } + } + + var proxy = imageryProvider._proxy; + if (defined(proxy)) { + url = proxy.getURL(url); + } + + return url; + } + + function urlTemplateToParts(url, tags) { + if (!defined(url)) { + return undefined; + } + + var parts = []; + var nextIndex = 0; + var minIndex; + var minTag; + var tagList = Object.keys(tags); + + while (nextIndex < url.length) { + minIndex = Number.MAX_VALUE; + minTag = undefined; + + for (var i = 0; i < tagList.length; ++i) { + var thisIndex = url.indexOf(tagList[i], nextIndex); + if (thisIndex >= 0 && thisIndex < minIndex) { + minIndex = thisIndex; + minTag = tagList[i]; + } + } + + if (!defined(minTag)) { + parts.push(url.substring(nextIndex)); + nextIndex = url.length; + } else { + if (nextIndex < minIndex) { + parts.push(url.substring(nextIndex, minIndex)); + } + parts.push(tags[minTag]); + nextIndex = minIndex + minTag.length; + } + } + + return parts; + } + + function padWithZerosIfNecessary(imageryProvider, key, value) { + if (imageryProvider && + imageryProvider.urlSchemeZeroPadding && + imageryProvider.urlSchemeZeroPadding.hasOwnProperty(key) ) + { + var paddingTemplate = imageryProvider.urlSchemeZeroPadding[key]; + if (typeof paddingTemplate === 'string') { + var paddingTemplateWidth = paddingTemplate.length; + if (paddingTemplateWidth > 1) { + value = (value.length >= paddingTemplateWidth) ? value : new Array(paddingTemplateWidth - value.toString().length + 1).join('0') + value; + } + } + } + return value; + } + + function xTag(imageryProvider, x, y, level) { + return padWithZerosIfNecessary(imageryProvider, '{x}', x); + } + + function reverseXTag(imageryProvider, x, y, level) { + var reverseX = imageryProvider.tilingScheme.getNumberOfXTilesAtLevel(level) - x - 1; + return padWithZerosIfNecessary(imageryProvider, '{reverseX}', reverseX); + } + + function yTag(imageryProvider, x, y, level) { + return padWithZerosIfNecessary(imageryProvider, '{y}', y); + } + + function reverseYTag(imageryProvider, x, y, level) { + var reverseY = imageryProvider.tilingScheme.getNumberOfYTilesAtLevel(level) - y - 1; + return padWithZerosIfNecessary(imageryProvider, '{reverseY}', reverseY); + } + + function reverseZTag(imageryProvider, x, y, level) { + var maximumLevel = imageryProvider.maximumLevel; + var reverseZ = defined(maximumLevel) && level < maximumLevel ? maximumLevel - level - 1 : level; + return padWithZerosIfNecessary(imageryProvider, '{reverseZ}', reverseZ); + } + + function zTag(imageryProvider, x, y, level) { + return padWithZerosIfNecessary(imageryProvider, '{z}', level); + } + + function sTag(imageryProvider, x, y, level) { + var index = (x + y + level) % imageryProvider._subdomains.length; + return imageryProvider._subdomains[index]; + } + + function minValTag(imageryProvider, x, y, level) { + return padWithZerosIfNecessary(imageryProvider, '{min}', imageryProvider._min); + } + + function maxValTag(imageryProvider, x, y, level) { + return padWithZerosIfNecessary(imageryProvider, '{max}', imageryProvider._max); + } + + var degreesScratchComputed = false; + var degreesScratch = new Rectangle(); + + function computeDegrees(imageryProvider, x, y, level) { + if (degreesScratchComputed) { + return; + } + + imageryProvider.tilingScheme.tileXYToRectangle(x, y, level, degreesScratch); + degreesScratch.west = CesiumMath.toDegrees(degreesScratch.west); + degreesScratch.south = CesiumMath.toDegrees(degreesScratch.south); + degreesScratch.east = CesiumMath.toDegrees(degreesScratch.east); + degreesScratch.north = CesiumMath.toDegrees(degreesScratch.north); + + degreesScratchComputed = true; + } + + function westDegreesTag(imageryProvider, x, y, level) { + computeDegrees(imageryProvider, x, y, level); + return degreesScratch.west; + } + + function southDegreesTag(imageryProvider, x, y, level) { + computeDegrees(imageryProvider, x, y, level); + return degreesScratch.south; + } + + function eastDegreesTag(imageryProvider, x, y, level) { + computeDegrees(imageryProvider, x, y, level); + return degreesScratch.east; + } + + function northDegreesTag(imageryProvider, x, y, level) { + computeDegrees(imageryProvider, x, y, level); + return degreesScratch.north; + } + + var projectedScratchComputed = false; + var projectedScratch = new Rectangle(); + + function computeProjected(imageryProvider, x, y, level) { + if (projectedScratchComputed) { + return; + } + + imageryProvider.tilingScheme.tileXYToNativeRectangle(x, y, level, projectedScratch); + + projectedScratchComputed = true; + } + + function westProjectedTag(imageryProvider, x, y, level) { + computeProjected(imageryProvider, x, y, level); + return projectedScratch.west; + } + + function southProjectedTag(imageryProvider, x, y, level) { + computeProjected(imageryProvider, x, y, level); + return projectedScratch.south; + } + + function eastProjectedTag(imageryProvider, x, y, level) { + computeProjected(imageryProvider, x, y, level); + return projectedScratch.east; + } + + function northProjectedTag(imageryProvider, x, y, level) { + computeProjected(imageryProvider, x, y, level); + return projectedScratch.north; + } + + function widthTag(imageryProvider, x, y, level) { + return imageryProvider.tileWidth; + } + + function heightTag(imageryProvider, x, y, level) { + return imageryProvider.tileHeight; + } + + var ijScratchComputed = false; + var ijScratch = new Cartesian2(); + + function iTag(imageryProvider, x, y, level, longitude, latitude, format) { + computeIJ(imageryProvider, x, y, level, longitude, latitude); + return ijScratch.x; + } + + function jTag(imageryProvider, x, y, level, longitude, latitude, format) { + computeIJ(imageryProvider, x, y, level, longitude, latitude); + return ijScratch.y; + } + + function reverseITag(imageryProvider, x, y, level, longitude, latitude, format) { + computeIJ(imageryProvider, x, y, level, longitude, latitude); + return imageryProvider.tileWidth - ijScratch.x - 1; + } + + function reverseJTag(imageryProvider, x, y, level, longitude, latitude, format) { + computeIJ(imageryProvider, x, y, level, longitude, latitude); + return imageryProvider.tileHeight - ijScratch.y - 1; + } + + var rectangleScratch = new Rectangle(); + + function computeIJ(imageryProvider, x, y, level, longitude, latitude, format) { + if (ijScratchComputed) { + return; + } + + computeLongitudeLatitudeProjected(imageryProvider, x, y, level, longitude, latitude); + var projected = longitudeLatitudeProjectedScratch; + + var rectangle = imageryProvider.tilingScheme.tileXYToNativeRectangle(x, y, level, rectangleScratch); + ijScratch.x = (imageryProvider.tileWidth * (projected.x - rectangle.west) / rectangle.width) | 0; + ijScratch.y = (imageryProvider.tileHeight * (rectangle.north - projected.y) / rectangle.height) | 0; + ijScratchComputed = true; + } + + function longitudeDegreesTag(imageryProvider, x, y, level, longitude, latitude, format) { + return CesiumMath.toDegrees(longitude); + } + + function latitudeDegreesTag(imageryProvider, x, y, level, longitude, latitude, format) { + return CesiumMath.toDegrees(latitude); + } + + var longitudeLatitudeProjectedScratchComputed = false; + var longitudeLatitudeProjectedScratch = new Cartesian3(); + + function longitudeProjectedTag(imageryProvider, x, y, level, longitude, latitude, format) { + computeLongitudeLatitudeProjected(imageryProvider, x, y, level, longitude, latitude); + return longitudeLatitudeProjectedScratch.x; + } + + function latitudeProjectedTag(imageryProvider, x, y, level, longitude, latitude, format) { + computeLongitudeLatitudeProjected(imageryProvider, x, y, level, longitude, latitude); + return longitudeLatitudeProjectedScratch.y; + } + + var cartographicScratch = new Cartographic(); + + function computeLongitudeLatitudeProjected(imageryProvider, x, y, level, longitude, latitude, format) { + if (longitudeLatitudeProjectedScratchComputed) { + return; + } + + var projected; + if (imageryProvider.tilingScheme instanceof GeographicTilingScheme) { + longitudeLatitudeProjectedScratch.x = CesiumMath.toDegrees(longitude); + longitudeLatitudeProjectedScratch.y = CesiumMath.toDegrees(latitude); + } else { + var cartographic = cartographicScratch; + cartographic.longitude = longitude; + cartographic.latitude = latitude; + projected = imageryProvider.tilingScheme.projection.project(cartographic, longitudeLatitudeProjectedScratch); + } + + longitudeLatitudeProjectedScratchComputed = true; + } + + function formatTag(imageryProvider, x, y, level, longitude, latitude, format) { + return format; + } + + var tags = { + '{x}': xTag, + '{y}': yTag, + '{z}': zTag, + '{s}': sTag, + '{reverseX}': reverseXTag, + '{reverseY}': reverseYTag, + '{reverseZ}': reverseZTag, + '{westDegrees}': westDegreesTag, + '{southDegrees}': southDegreesTag, + '{eastDegrees}': eastDegreesTag, + '{northDegrees}': northDegreesTag, + '{westProjected}': westProjectedTag, + '{southProjected}': southProjectedTag, + '{eastProjected}': eastProjectedTag, + '{northProjected}': northProjectedTag, + '{width}': widthTag, + '{height}': heightTag, + '{min}': minValTag, + '{max}': maxValTag + }; + + var pickFeaturesTags = combine(tags, { + '{i}' : iTag, + '{j}' : jTag, + '{reverseI}' : reverseITag, + '{reverseJ}' : reverseJTag, + '{longitudeDegrees}' : longitudeDegreesTag, + '{latitudeDegrees}' : latitudeDegreesTag, + '{longitudeProjected}' : longitudeProjectedTag, + '{latitudeProjected}' : latitudeProjectedTag, + '{format}' : formatTag + }); + + return CustomTemplateImageryProvider; +}); diff --git a/Source/Scene/FrameState.js b/Source/Scene/FrameState.js index f28094fd9c7b..cc959e691e51 100644 --- a/Source/Scene/FrameState.js +++ b/Source/Scene/FrameState.js @@ -237,11 +237,11 @@ define([ this.imagerySplitPosition = 0.0; /** - * Distances to the near and far planes of the camera frustums - * @type {Number[]} - * @default [] - */ - this.frustumSplits = []; + * The color palette to use when rendering imagery layers. + * @type {Array} + * @default undefined + */ + this.imageryColorPalette = 0.0; } /** diff --git a/Source/Scene/GlobeSurfaceShaderSet.js b/Source/Scene/GlobeSurfaceShaderSet.js index 7ed5d9a3496d..5a6aba4af476 100644 --- a/Source/Scene/GlobeSurfaceShaderSet.js +++ b/Source/Scene/GlobeSurfaceShaderSet.js @@ -62,7 +62,7 @@ define([ return useWebMercatorProjection ? get2DYPositionFractionMercatorProjection : get2DYPositionFractionGeographicProjection; } - GlobeSurfaceShaderSet.prototype.getShaderProgram = function(frameState, surfaceTile, numberOfDayTextures, applyBrightness, applyContrast, applyHue, applySaturation, applyGamma, applyAlpha, applySplit, showReflectiveOcean, showOceanWaves, enableLighting, hasVertexNormals, useWebMercatorProjection, enableFog) { + GlobeSurfaceShaderSet.prototype.getShaderProgram = function(frameState, surfaceTile, numberOfDayTextures, applyBrightness, applyContrast, applyHue, applySaturation, applyGamma, applyAlpha, applySplit, colorPaletteKeys, showReflectiveOcean, showOceanWaves, enableLighting, hasVertexNormals, useWebMercatorProjection, enableFog) { var quantization = 0; var quantizationDefine = ''; @@ -88,7 +88,8 @@ define([ (useWebMercatorProjection << 12) | (enableFog << 13) | (quantization << 14) | - (applySplit << 15); + (applySplit << 15) | + (colorPaletteKeys << 16); var surfaceShader = surfaceTile.surfaceShader; if (defined(surfaceShader) && @@ -157,6 +158,10 @@ define([ fs.defines.push('FOG'); } + if (colorPaletteKeys.length > 0) { + fs.defines.push('APPLY_COLOR_PALETTE'); + } + if (applySplit) { fs.defines.push('APPLY_SPLIT'); } @@ -167,6 +172,25 @@ define([ vec4 color = initialColor;\n'; for (var i = 0; i < numberOfDayTextures; ++i) { + if(colorPaletteKeys[i] == 1) { + computeDayColor += '\ + color = sampleBlendAndPalette(\n\ + color,\n\ + u_dayTextures[' + i + '],\n\ + u_dayTextureUseWebMercatorT[' + i + '] ? textureCoordinates.xz : textureCoordinates.xy,\n\ + u_dayTextureTexCoordsRectangle[' + i + '],\n\ + u_dayTextureTranslationAndScale[' + i + '],\n\ + ' + (applyAlpha ? 'u_dayTextureAlpha[' + i + ']' : '1.0') + ',\n\ + ' + (applyBrightness ? 'u_dayTextureBrightness[' + i + ']' : '0.0') + ',\n\ + ' + (applyContrast ? 'u_dayTextureContrast[' + i + ']' : '0.0') + ',\n\ + ' + (applyHue ? 'u_dayTextureHue[' + i + ']' : '0.0') + ',\n\ + ' + (applySaturation ? 'u_dayTextureSaturation[' + i + ']' : '0.0') + ',\n\ + ' + (applyGamma ? 'u_dayTextureOneOverGamma[' + i + ']' : '0.0') + ',\n\ + ' + (applySplit ? 'u_dayTextureSplit[' + i + ']' : '0.0') + ',\n\ + u_dayTextureColorPalette[' + i + ']\n\ + );\n'; +} else { + computeDayColor += '\ color = sampleAndBlend(\n\ color,\n\ @@ -182,6 +206,7 @@ define([ ' + (applyGamma ? 'u_dayTextureOneOverGamma[' + i + ']' : '0.0') + ',\n\ ' + (applySplit ? 'u_dayTextureSplit[' + i + ']' : '0.0') + '\n\ );\n'; +} } computeDayColor += '\ diff --git a/Source/Scene/GlobeSurfaceTileProvider.js b/Source/Scene/GlobeSurfaceTileProvider.js index 7bec9532d203..a39577fde20f 100644 --- a/Source/Scene/GlobeSurfaceTileProvider.js +++ b/Source/Scene/GlobeSurfaceTileProvider.js @@ -755,6 +755,9 @@ define([ u_dayTextureSplit : function() { return this.properties.dayTextureSplit; }, + u_dayTextureColorPalette : function() { + return this.properties.dayTextureColorPalette; + }, // make a separate object so that changes to the properties are seen on // derived commands that combine another uniform map with this one. @@ -780,6 +783,7 @@ define([ dayTextureSaturation : [], dayTextureOneOverGamma : [], dayTextureSplit : [], + dayTextureColorPalette : [], dayIntensity : 0.0, southAndNorthLatitude : new Cartesian2(), @@ -1075,6 +1079,7 @@ define([ var applyGamma = false; var applyAlpha = false; var applySplit = false; + var colorPaletteKeys = []; while (numberOfDayTextures < maxTextures && imageryIndex < imageryLen) { var tileImagery = tileImageryCollection[imageryIndex]; @@ -1135,6 +1140,11 @@ define([ uniformMapProperties.dayTextureSplit[numberOfDayTextures] = imageryLayer.splitDirection; applySplit = applySplit || uniformMapProperties.dayTextureSplit[numberOfDayTextures] !== 0.0; + uniformMapProperties.dayTextureColorPalette[numberOfDayTextures] = imageryLayer.colorPalette; + if(uniformMapProperties.dayTextureColorPalette[numberOfDayTextures] !== ImageryLayer.DEFAULT_COLOR_PALETTE) { + colorPaletteKeys[numberOfDayTextures] = 1; + } + if (defined(imagery.credits)) { var creditDisplay = frameState.creditDisplay; var credits = imagery.credits; @@ -1156,7 +1166,8 @@ define([ uniformMapProperties.minMaxHeight.y = encoding.maximumHeight; Matrix4.clone(encoding.matrix, uniformMapProperties.scaleAndBias); - command.shaderProgram = tileProvider._surfaceShaderSet.getShaderProgram(frameState, surfaceTile, numberOfDayTextures, applyBrightness, applyContrast, applyHue, applySaturation, applyGamma, applyAlpha, applySplit, showReflectiveOcean, showOceanWaves, tileProvider.enableLighting, hasVertexNormals, useWebMercatorProjection, applyFog); + + command.shaderProgram = tileProvider._surfaceShaderSet.getShaderProgram(frameState, surfaceTile, numberOfDayTextures, applyBrightness, applyContrast, applyHue, applySaturation, applyGamma, applyAlpha, applySplit, colorPaletteKeys, showReflectiveOcean, showOceanWaves, tileProvider.enableLighting, hasVertexNormals, useWebMercatorProjection, applyFog); command.castShadows = castShadows; command.receiveShadows = receiveShadows; command.renderState = renderState; diff --git a/Source/Scene/ImageryLayer.js b/Source/Scene/ImageryLayer.js index 9fef8eeac772..9e767112a8cc 100644 --- a/Source/Scene/ImageryLayer.js +++ b/Source/Scene/ImageryLayer.js @@ -206,6 +206,14 @@ define([ */ this.splitDirection = defaultValue(options.splitDirection, defaultValue(imageryProvider.defaultSplit, ImageryLayer.DEFAULT_SPLIT)); + /** + * The color palette to apply to this layer. + * + * @type {Array} + * @default false + */ + this.colorPalette = defaultValue(options.colorPalette, defaultValue(imageryProvider.defaultColorPalette, ImageryLayer.DEFAULT_COLOR_PALETTE)); + /** * Determines if this layer is shown. * @@ -311,6 +319,13 @@ define([ */ ImageryLayer.DEFAULT_SPLIT = ImagerySplitDirection.NONE; + /** + * This value is used as the default color palette for the imagery layer if one is not provided during construction + * or by the imagery provider. + * @type {Array} + * @default undefined + */ + ImageryLayer.DEFAULT_COLOR_PALETTE = 1.0; /** * Gets a value indicating whether this layer is the base layer in the * {@link ImageryLayerCollection}. The base layer is the one that underlies all @@ -741,6 +756,22 @@ define([ } } + if(defined(imagery.imageryLayer.colorPalette) && + imagery.imageryLayer.colorPalette != ImageryLayer.DEFAULT_COLOR_PALETTE && + !(imagery.imageryLayer.colorPalette instanceof Texture) + ) { + imagery.imageryLayer.colorPalette = new Texture({ + context : context, + flipY : false, + source : { + arrayBufferView : imagery.imageryLayer.colorPalette + }, + width : 1, + height : 1024, + pixelFormat : PixelFormat.RGBA + }); + } + // Imagery does not need to be discarded, so upload it to WebGL. var texture; if (defined(image.internalFormat)) { diff --git a/Source/Scene/ImageryProvider.js b/Source/Scene/ImageryProvider.js index 2a0500a0f7b7..bbd5ef89180c 100644 --- a/Source/Scene/ImageryProvider.js +++ b/Source/Scene/ImageryProvider.js @@ -91,6 +91,15 @@ define([ */ this.defaultGamma = undefined; + /** + * The default color palette to apply to this provider. 1.0 uses the unmodified imagery color palette. + * + * @type {Array} + * @default undefined + */ + this.defaultColorPalette = undefined; + + DeveloperError.throwInstantiationError(); } diff --git a/Source/Shaders/GlobeFS.glsl b/Source/Shaders/GlobeFS.glsl index da6c49e2a9d4..abfbf84d73e8 100644 --- a/Source/Shaders/GlobeFS.glsl +++ b/Source/Shaders/GlobeFS.glsl @@ -38,6 +38,10 @@ uniform float u_dayTextureOneOverGamma[TEXTURE_UNITS]; uniform vec4 u_dayTextureTexCoordsRectangle[TEXTURE_UNITS]; #endif +#ifdef APPLY_COLOR_PALETTE +uniform sampler2D u_dayTextureColorPalette[TEXTURE_UNITS]; +#endif + #ifdef SHOW_REFLECTIVE_OCEAN uniform sampler2D u_waterMask; uniform vec4 u_waterMaskTranslationAndScale; @@ -64,6 +68,96 @@ varying vec3 v_rayleighColor; varying vec3 v_mieColor; #endif +vec4 sampleBlendAndPalette( + vec4 previousColor, + sampler2D texture, + vec2 tileTextureCoordinates, + vec4 textureCoordinateRectangle, + vec4 textureCoordinateTranslationAndScale, + float textureAlpha, + float textureBrightness, + float textureContrast, + float textureHue, + float textureSaturation, + float textureOneOverGamma, + float split, + sampler2D textureColorPalette) +{ + // This crazy step stuff sets the alpha to 0.0 if this following condition is true: + // tileTextureCoordinates.s < textureCoordinateRectangle.s || + // tileTextureCoordinates.s > textureCoordinateRectangle.p || + // tileTextureCoordinates.t < textureCoordinateRectangle.t || + // tileTextureCoordinates.t > textureCoordinateRectangle.q + // In other words, the alpha is zero if the fragment is outside the rectangle + // covered by this texture. Would an actual 'if' yield better performance? + vec2 alphaMultiplier = step(textureCoordinateRectangle.st, tileTextureCoordinates); + textureAlpha = textureAlpha * alphaMultiplier.x * alphaMultiplier.y; + + alphaMultiplier = step(vec2(0.0), textureCoordinateRectangle.pq - tileTextureCoordinates); + textureAlpha = textureAlpha * alphaMultiplier.x * alphaMultiplier.y; + + vec2 translation = textureCoordinateTranslationAndScale.xy; + vec2 scale = textureCoordinateTranslationAndScale.zw; + vec2 textureCoordinates = tileTextureCoordinates * scale + translation; + vec4 value = texture2D(texture, textureCoordinates); + vec3 color = value.rgb; + float alpha = value.a; + +#ifdef APPLY_SPLIT + float splitPosition = czm_imagerySplitPosition * czm_viewport.z; + // Split to the left + if (split < 0.0 && gl_FragCoord.x > splitPosition) { + alpha = 0.0; + } + // Split to the right + else if (split > 0.0 && gl_FragCoord.x < splitPosition) { + alpha = 0.0; + } +#endif + + float step = 1.0/1024.0; + float a1 = texture2D(texture, textureCoordinates).r; + float a2 = texture2D(texture, textureCoordinates + vec2(step, 0.0)).r; + float a3 = texture2D(texture, textureCoordinates + vec2(0.0, step)).r; + float a4 = texture2D(texture, textureCoordinates + vec2(step, step)).r; + if ((a1 != 0.0 && (a2 == 0.0 || a3 == 0.0 || a4 == 0.0)) || a1 == 0.0) { + } else { + vec2 f = fract(textureCoordinates * vec2(1024.0, 1024.0)); + float tA = mix(a1, a2, f.x); + float tB = mix(a3, a4, f.x); + a1 = mix(tA, tB, f.y); + } + + vec4 pixColor = texture2D(textureColorPalette, vec2(0.0, a1)); + color = pixColor.rgb; + alpha = pixColor.a; + +#ifdef APPLY_BRIGHTNESS + color = mix(vec3(0.0), color, textureBrightness); +#endif + +#ifdef APPLY_CONTRAST + color = mix(vec3(0.5), color, textureContrast); +#endif + +#ifdef APPLY_HUE + color = czm_hue(color, textureHue); +#endif + +#ifdef APPLY_SATURATION + color = czm_saturation(color, textureSaturation); +#endif + +#ifdef APPLY_GAMMA + color = pow(color, vec3(textureOneOverGamma)); +#endif + + float sourceAlpha = alpha * textureAlpha; + float outAlpha = mix(previousColor.a, 1.0, sourceAlpha); + vec3 outColor = mix(previousColor.rgb * previousColor.a, color, sourceAlpha) / outAlpha; + return vec4(outColor, outAlpha); +} + vec4 sampleAndBlend( vec4 previousColor, sampler2D texture, From 86294b7d18292421e06d29fc95973ebf116b85e6 Mon Sep 17 00:00:00 2001 From: Ryan Hickman Date: Wed, 8 Feb 2017 13:05:24 -0700 Subject: [PATCH 02/18] Restore accidental frustumSplits[] removal. --- Source/Scene/FrameState.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Source/Scene/FrameState.js b/Source/Scene/FrameState.js index cc959e691e51..b88e0490568f 100644 --- a/Source/Scene/FrameState.js +++ b/Source/Scene/FrameState.js @@ -237,7 +237,13 @@ define([ this.imagerySplitPosition = 0.0; /** - * The color palette to use when rendering imagery layers. + * Distances to the near and far planes of the camera frustums + * @type {Number[]} + * @default [] + */ + this.frustumSplits = []; + + /* The color palette to use when rendering imagery layers. * @type {Array} * @default undefined */ From 8714fe90947a11d47a56489df515df9a994bb16b Mon Sep 17 00:00:00 2001 From: Ryan Hickman Date: Wed, 8 Feb 2017 13:05:44 -0700 Subject: [PATCH 03/18] Make imageryColorPalette set match default. --- Source/Scene/FrameState.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Scene/FrameState.js b/Source/Scene/FrameState.js index b88e0490568f..9afae4f822a4 100644 --- a/Source/Scene/FrameState.js +++ b/Source/Scene/FrameState.js @@ -247,7 +247,7 @@ define([ * @type {Array} * @default undefined */ - this.imageryColorPalette = 0.0; + this.imageryColorPalette = 1.0; } /** From 92ce03c33784e0202f5e433f91fa9b83407f42ce Mon Sep 17 00:00:00 2001 From: Ryan Hickman Date: Wed, 8 Feb 2017 13:06:42 -0700 Subject: [PATCH 04/18] Initial color palette sandcastle example. --- .../gallery/Imagery Layers Palette.html | 199 ++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 Apps/Sandcastle/gallery/Imagery Layers Palette.html diff --git a/Apps/Sandcastle/gallery/Imagery Layers Palette.html b/Apps/Sandcastle/gallery/Imagery Layers Palette.html new file mode 100644 index 000000000000..e279bfcc23cb --- /dev/null +++ b/Apps/Sandcastle/gallery/Imagery Layers Palette.html @@ -0,0 +1,199 @@ + + + + + + + + + Cesium Demo + + + + + + + + +
+

Loading...

+
+ + + + + From 3ffa7052851065099f9f3cda07d9d36ccbf74779 Mon Sep 17 00:00:00 2001 From: Ryan Hickman Date: Wed, 8 Feb 2017 13:15:06 -0700 Subject: [PATCH 05/18] Move palette GLSL into sampleAndBlend * Removes unique sampleBlendAndPalette() function which was mostly duplicated. * Adds a second boolean argument to tell the function whether or not to palette the imagery. --- Source/Scene/GlobeSurfaceShaderSet.js | 24 +----- Source/Shaders/GlobeFS.glsl | 111 +++++--------------------- 2 files changed, 23 insertions(+), 112 deletions(-) diff --git a/Source/Scene/GlobeSurfaceShaderSet.js b/Source/Scene/GlobeSurfaceShaderSet.js index 5a6aba4af476..8789a09b15e9 100644 --- a/Source/Scene/GlobeSurfaceShaderSet.js +++ b/Source/Scene/GlobeSurfaceShaderSet.js @@ -172,29 +172,11 @@ define([ vec4 color = initialColor;\n'; for (var i = 0; i < numberOfDayTextures; ++i) { - if(colorPaletteKeys[i] == 1) { - computeDayColor += '\ - color = sampleBlendAndPalette(\n\ - color,\n\ - u_dayTextures[' + i + '],\n\ - u_dayTextureUseWebMercatorT[' + i + '] ? textureCoordinates.xz : textureCoordinates.xy,\n\ - u_dayTextureTexCoordsRectangle[' + i + '],\n\ - u_dayTextureTranslationAndScale[' + i + '],\n\ - ' + (applyAlpha ? 'u_dayTextureAlpha[' + i + ']' : '1.0') + ',\n\ - ' + (applyBrightness ? 'u_dayTextureBrightness[' + i + ']' : '0.0') + ',\n\ - ' + (applyContrast ? 'u_dayTextureContrast[' + i + ']' : '0.0') + ',\n\ - ' + (applyHue ? 'u_dayTextureHue[' + i + ']' : '0.0') + ',\n\ - ' + (applySaturation ? 'u_dayTextureSaturation[' + i + ']' : '0.0') + ',\n\ - ' + (applyGamma ? 'u_dayTextureOneOverGamma[' + i + ']' : '0.0') + ',\n\ - ' + (applySplit ? 'u_dayTextureSplit[' + i + ']' : '0.0') + ',\n\ - u_dayTextureColorPalette[' + i + ']\n\ - );\n'; -} else { - computeDayColor += '\ color = sampleAndBlend(\n\ color,\n\ u_dayTextures[' + i + '],\n\ + ' + (colorPaletteKeys[i] ? 'u_dayTextureColorPalette[' + i + ']' : 'u_dayTextures[' + i + ']') + ',\n\ u_dayTextureUseWebMercatorT[' + i + '] ? textureCoordinates.xz : textureCoordinates.xy,\n\ u_dayTextureTexCoordsRectangle[' + i + '],\n\ u_dayTextureTranslationAndScale[' + i + '],\n\ @@ -204,9 +186,9 @@ define([ ' + (applyHue ? 'u_dayTextureHue[' + i + ']' : '0.0') + ',\n\ ' + (applySaturation ? 'u_dayTextureSaturation[' + i + ']' : '0.0') + ',\n\ ' + (applyGamma ? 'u_dayTextureOneOverGamma[' + i + ']' : '0.0') + ',\n\ - ' + (applySplit ? 'u_dayTextureSplit[' + i + ']' : '0.0') + '\n\ + ' + (applySplit ? 'u_dayTextureSplit[' + i + ']' : '0.0') + ',\n\ + ' + (colorPaletteKeys[i] ? '1.0' : '0.0') + '\n\ );\n'; -} } computeDayColor += '\ diff --git a/Source/Shaders/GlobeFS.glsl b/Source/Shaders/GlobeFS.glsl index abfbf84d73e8..fd44731a0ea7 100644 --- a/Source/Shaders/GlobeFS.glsl +++ b/Source/Shaders/GlobeFS.glsl @@ -38,9 +38,7 @@ uniform float u_dayTextureOneOverGamma[TEXTURE_UNITS]; uniform vec4 u_dayTextureTexCoordsRectangle[TEXTURE_UNITS]; #endif -#ifdef APPLY_COLOR_PALETTE uniform sampler2D u_dayTextureColorPalette[TEXTURE_UNITS]; -#endif #ifdef SHOW_REFLECTIVE_OCEAN uniform sampler2D u_waterMask; @@ -68,9 +66,10 @@ varying vec3 v_rayleighColor; varying vec3 v_mieColor; #endif -vec4 sampleBlendAndPalette( +vec4 sampleAndBlend( vec4 previousColor, sampler2D texture, + sampler2D textureColorPalette, vec2 tileTextureCoordinates, vec4 textureCoordinateRectangle, vec4 textureCoordinateTranslationAndScale, @@ -81,7 +80,7 @@ vec4 sampleBlendAndPalette( float textureSaturation, float textureOneOverGamma, float split, - sampler2D textureColorPalette) + float applyTextureColorPalette) { // This crazy step stuff sets the alpha to 0.0 if this following condition is true: // tileTextureCoordinates.s < textureCoordinateRectangle.s || @@ -115,94 +114,24 @@ vec4 sampleBlendAndPalette( } #endif - float step = 1.0/1024.0; - float a1 = texture2D(texture, textureCoordinates).r; - float a2 = texture2D(texture, textureCoordinates + vec2(step, 0.0)).r; - float a3 = texture2D(texture, textureCoordinates + vec2(0.0, step)).r; - float a4 = texture2D(texture, textureCoordinates + vec2(step, step)).r; - if ((a1 != 0.0 && (a2 == 0.0 || a3 == 0.0 || a4 == 0.0)) || a1 == 0.0) { - } else { - vec2 f = fract(textureCoordinates * vec2(1024.0, 1024.0)); - float tA = mix(a1, a2, f.x); - float tB = mix(a3, a4, f.x); - a1 = mix(tA, tB, f.y); - } - - vec4 pixColor = texture2D(textureColorPalette, vec2(0.0, a1)); - color = pixColor.rgb; - alpha = pixColor.a; - -#ifdef APPLY_BRIGHTNESS - color = mix(vec3(0.0), color, textureBrightness); -#endif - -#ifdef APPLY_CONTRAST - color = mix(vec3(0.5), color, textureContrast); -#endif - -#ifdef APPLY_HUE - color = czm_hue(color, textureHue); -#endif - -#ifdef APPLY_SATURATION - color = czm_saturation(color, textureSaturation); -#endif - -#ifdef APPLY_GAMMA - color = pow(color, vec3(textureOneOverGamma)); -#endif - - float sourceAlpha = alpha * textureAlpha; - float outAlpha = mix(previousColor.a, 1.0, sourceAlpha); - vec3 outColor = mix(previousColor.rgb * previousColor.a, color, sourceAlpha) / outAlpha; - return vec4(outColor, outAlpha); -} - -vec4 sampleAndBlend( - vec4 previousColor, - sampler2D texture, - vec2 tileTextureCoordinates, - vec4 textureCoordinateRectangle, - vec4 textureCoordinateTranslationAndScale, - float textureAlpha, - float textureBrightness, - float textureContrast, - float textureHue, - float textureSaturation, - float textureOneOverGamma, - float split) -{ - // This crazy step stuff sets the alpha to 0.0 if this following condition is true: - // tileTextureCoordinates.s < textureCoordinateRectangle.s || - // tileTextureCoordinates.s > textureCoordinateRectangle.p || - // tileTextureCoordinates.t < textureCoordinateRectangle.t || - // tileTextureCoordinates.t > textureCoordinateRectangle.q - // In other words, the alpha is zero if the fragment is outside the rectangle - // covered by this texture. Would an actual 'if' yield better performance? - vec2 alphaMultiplier = step(textureCoordinateRectangle.st, tileTextureCoordinates); - textureAlpha = textureAlpha * alphaMultiplier.x * alphaMultiplier.y; - - alphaMultiplier = step(vec2(0.0), textureCoordinateRectangle.pq - tileTextureCoordinates); - textureAlpha = textureAlpha * alphaMultiplier.x * alphaMultiplier.y; - - vec2 translation = textureCoordinateTranslationAndScale.xy; - vec2 scale = textureCoordinateTranslationAndScale.zw; - vec2 textureCoordinates = tileTextureCoordinates * scale + translation; - vec4 value = texture2D(texture, textureCoordinates); - vec3 color = value.rgb; - float alpha = value.a; - -#ifdef APPLY_SPLIT - float splitPosition = czm_imagerySplitPosition * czm_viewport.z; - // Split to the left - if (split < 0.0 && gl_FragCoord.x > splitPosition) { - alpha = 0.0; + if(applyTextureColorPalette > 0.0) { + float step = 1.0/1024.0; + float a1 = texture2D(texture, textureCoordinates).r; + float a2 = texture2D(texture, textureCoordinates + vec2(step, 0.0)).r; + float a3 = texture2D(texture, textureCoordinates + vec2(0.0, step)).r; + float a4 = texture2D(texture, textureCoordinates + vec2(step, step)).r; + if ((a1 != 0.0 && (a2 == 0.0 || a3 == 0.0 || a4 == 0.0)) || a1 == 0.0) { + } else { + vec2 f = fract(textureCoordinates * vec2(1024.0, 1024.0)); + float tA = mix(a1, a2, f.x); + float tB = mix(a3, a4, f.x); + a1 = mix(tA, tB, f.y); + } + + vec4 pixColor = texture2D(textureColorPalette, vec2(0.0, a1)); + color = pixColor.rgb; + alpha = pixColor.a; } - // Split to the right - else if (split > 0.0 && gl_FragCoord.x < splitPosition) { - alpha = 0.0; - } -#endif #ifdef APPLY_BRIGHTNESS color = mix(vec3(0.0), color, textureBrightness); From 59a1aaef3a18e24711f7b1a9c9d775f1a4e2937a Mon Sep 17 00:00:00 2001 From: Ryan Hickman Date: Wed, 8 Feb 2017 13:24:02 -0700 Subject: [PATCH 06/18] Apply color palette after load. Fix URL. --- Apps/Sandcastle/gallery/Imagery Layers Palette.html | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Apps/Sandcastle/gallery/Imagery Layers Palette.html b/Apps/Sandcastle/gallery/Imagery Layers Palette.html index e279bfcc23cb..9b36e924964a 100644 --- a/Apps/Sandcastle/gallery/Imagery Layers Palette.html +++ b/Apps/Sandcastle/gallery/Imagery Layers Palette.html @@ -89,7 +89,7 @@ var options = { tileWidth: 512, tileHeight: 512, - url: 'http://cache.allisonhouse.com/maps/raw.php?model=rtma&run=201702081600&hour=1486569600000&layers=tmp_2m_0', + url: 'http://cache.allisonhouse.com/maps/raw.php?model=rtma&run=201702081600&hour=1486569600000&layers=tmp_2m_0&x={x}&y={y}&z={z}&min={min}&max={max}', palette: sortedColors, min: sortedColors[0][0], max: sortedColors[sortedColors.length-1][0] @@ -183,7 +183,10 @@ options.colorPalette = colorTableData; - layers.addImageryProvider(new Cesium.CustomTemplateImageryProvider(options)); + var newLayer = new Cesium.CustomTemplateImageryProvider(options); + + var layer = layers.addImageryProvider(newLayer); + layer.colorPalette = (Cesium.defined(newLayer._colorPalette) ? newLayer._colorPalette : []); //Sandcastle_End Sandcastle.finishedLoading(); From 82c0721c2e6a164bc40a70154e90f9faf52bf9a4 Mon Sep 17 00:00:00 2001 From: Ryan Hickman Date: Wed, 8 Feb 2017 13:27:58 -0700 Subject: [PATCH 07/18] Save a uniform bind if no Imagery with palette --- Source/Shaders/GlobeFS.glsl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/Shaders/GlobeFS.glsl b/Source/Shaders/GlobeFS.glsl index fd44731a0ea7..16f51cf1dbba 100644 --- a/Source/Shaders/GlobeFS.glsl +++ b/Source/Shaders/GlobeFS.glsl @@ -38,7 +38,9 @@ uniform float u_dayTextureOneOverGamma[TEXTURE_UNITS]; uniform vec4 u_dayTextureTexCoordsRectangle[TEXTURE_UNITS]; #endif +#ifdef APPLY_COLOR_PALETTE uniform sampler2D u_dayTextureColorPalette[TEXTURE_UNITS]; +#endif #ifdef SHOW_REFLECTIVE_OCEAN uniform sampler2D u_waterMask; From 94194cbc4de0353800387d6799fd3e7653c43c2f Mon Sep 17 00:00:00 2001 From: Ryan Hickman Date: Wed, 8 Feb 2017 15:20:13 -0700 Subject: [PATCH 08/18] Create PALETTE_UNITS constant. Fix bindTexture error. * Creates a `PALETTE_UNITS` constant to fix `bindTexture` errors. * Passes a boolean to sampleAndBlend to tell it whether or not to palette the dayTexture. --- Source/Scene/GlobeSurfaceShaderSet.js | 9 +++++---- Source/Scene/GlobeSurfaceTileProvider.js | 10 ++++++---- Source/Shaders/GlobeFS.glsl | 8 +++++--- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/Source/Scene/GlobeSurfaceShaderSet.js b/Source/Scene/GlobeSurfaceShaderSet.js index 8789a09b15e9..a9c2fe5da6ef 100644 --- a/Source/Scene/GlobeSurfaceShaderSet.js +++ b/Source/Scene/GlobeSurfaceShaderSet.js @@ -62,7 +62,7 @@ define([ return useWebMercatorProjection ? get2DYPositionFractionMercatorProjection : get2DYPositionFractionGeographicProjection; } - GlobeSurfaceShaderSet.prototype.getShaderProgram = function(frameState, surfaceTile, numberOfDayTextures, applyBrightness, applyContrast, applyHue, applySaturation, applyGamma, applyAlpha, applySplit, colorPaletteKeys, showReflectiveOcean, showOceanWaves, enableLighting, hasVertexNormals, useWebMercatorProjection, enableFog) { + GlobeSurfaceShaderSet.prototype.getShaderProgram = function(frameState, surfaceTile, numberOfDayTextures, numberOfPaletteTextures, applyBrightness, applyContrast, applyHue, applySaturation, applyGamma, applyAlpha, applySplit, colorPaletteKeys, showReflectiveOcean, showOceanWaves, enableLighting, hasVertexNormals, useWebMercatorProjection, enableFog) { var quantization = 0; var quantizationDefine = ''; @@ -113,6 +113,7 @@ define([ vs.defines.push(quantizationDefine); fs.defines.push('TEXTURE_UNITS ' + numberOfDayTextures); + fs.defines.push('PALETTE_UNITS ' + numberOfPaletteTextures); if (applyBrightness) { fs.defines.push('APPLY_BRIGHTNESS'); @@ -158,7 +159,7 @@ define([ fs.defines.push('FOG'); } - if (colorPaletteKeys.length > 0) { + if (numberOfPaletteTextures > 0) { fs.defines.push('APPLY_COLOR_PALETTE'); } @@ -176,7 +177,7 @@ define([ color = sampleAndBlend(\n\ color,\n\ u_dayTextures[' + i + '],\n\ - ' + (colorPaletteKeys[i] ? 'u_dayTextureColorPalette[' + i + ']' : 'u_dayTextures[' + i + ']') + ',\n\ + ' + (typeof(colorPaletteKeys[i]) !== 'undefined' ? 'u_dayTextureColorPalette[' + colorPaletteKeys[i] + ']' : 'u_dayTextures[' + i + ']') + ',\n\ u_dayTextureUseWebMercatorT[' + i + '] ? textureCoordinates.xz : textureCoordinates.xy,\n\ u_dayTextureTexCoordsRectangle[' + i + '],\n\ u_dayTextureTranslationAndScale[' + i + '],\n\ @@ -187,7 +188,7 @@ define([ ' + (applySaturation ? 'u_dayTextureSaturation[' + i + ']' : '0.0') + ',\n\ ' + (applyGamma ? 'u_dayTextureOneOverGamma[' + i + ']' : '0.0') + ',\n\ ' + (applySplit ? 'u_dayTextureSplit[' + i + ']' : '0.0') + ',\n\ - ' + (colorPaletteKeys[i] ? '1.0' : '0.0') + '\n\ + ' + (typeof(colorPaletteKeys[i]) !== 'undefined' ? '1' : '0') + '\n\ );\n'; } diff --git a/Source/Scene/GlobeSurfaceTileProvider.js b/Source/Scene/GlobeSurfaceTileProvider.js index a39577fde20f..f3efb810c6b9 100644 --- a/Source/Scene/GlobeSurfaceTileProvider.js +++ b/Source/Scene/GlobeSurfaceTileProvider.js @@ -1018,6 +1018,7 @@ define([ do { var numberOfDayTextures = 0; + var numberOfPaletteTextures = 0; var command; var uniformMap; @@ -1140,9 +1141,10 @@ define([ uniformMapProperties.dayTextureSplit[numberOfDayTextures] = imageryLayer.splitDirection; applySplit = applySplit || uniformMapProperties.dayTextureSplit[numberOfDayTextures] !== 0.0; - uniformMapProperties.dayTextureColorPalette[numberOfDayTextures] = imageryLayer.colorPalette; - if(uniformMapProperties.dayTextureColorPalette[numberOfDayTextures] !== ImageryLayer.DEFAULT_COLOR_PALETTE) { - colorPaletteKeys[numberOfDayTextures] = 1; + if(imageryLayer.colorPalette !== ImageryLayer.DEFAULT_COLOR_PALETTE) { + uniformMapProperties.dayTextureColorPalette[numberOfPaletteTextures] = imageryLayer.colorPalette; + colorPaletteKeys[numberOfDayTextures] = numberOfPaletteTextures; + numberOfPaletteTextures++; } if (defined(imagery.credits)) { @@ -1167,7 +1169,7 @@ define([ Matrix4.clone(encoding.matrix, uniformMapProperties.scaleAndBias); - command.shaderProgram = tileProvider._surfaceShaderSet.getShaderProgram(frameState, surfaceTile, numberOfDayTextures, applyBrightness, applyContrast, applyHue, applySaturation, applyGamma, applyAlpha, applySplit, colorPaletteKeys, showReflectiveOcean, showOceanWaves, tileProvider.enableLighting, hasVertexNormals, useWebMercatorProjection, applyFog); + command.shaderProgram = tileProvider._surfaceShaderSet.getShaderProgram(frameState, surfaceTile, numberOfDayTextures, numberOfPaletteTextures, applyBrightness, applyContrast, applyHue, applySaturation, applyGamma, applyAlpha, applySplit, colorPaletteKeys, showReflectiveOcean, showOceanWaves, tileProvider.enableLighting, hasVertexNormals, useWebMercatorProjection, applyFog); command.castShadows = castShadows; command.receiveShadows = receiveShadows; command.renderState = renderState; diff --git a/Source/Shaders/GlobeFS.glsl b/Source/Shaders/GlobeFS.glsl index 16f51cf1dbba..3c5c336fb007 100644 --- a/Source/Shaders/GlobeFS.glsl +++ b/Source/Shaders/GlobeFS.glsl @@ -39,7 +39,7 @@ uniform vec4 u_dayTextureTexCoordsRectangle[TEXTURE_UNITS]; #endif #ifdef APPLY_COLOR_PALETTE -uniform sampler2D u_dayTextureColorPalette[TEXTURE_UNITS]; +uniform sampler2D u_dayTextureColorPalette[PALETTE_UNITS]; #endif #ifdef SHOW_REFLECTIVE_OCEAN @@ -82,7 +82,7 @@ vec4 sampleAndBlend( float textureSaturation, float textureOneOverGamma, float split, - float applyTextureColorPalette) + int applyTextureColorPalette) { // This crazy step stuff sets the alpha to 0.0 if this following condition is true: // tileTextureCoordinates.s < textureCoordinateRectangle.s || @@ -116,7 +116,8 @@ vec4 sampleAndBlend( } #endif - if(applyTextureColorPalette > 0.0) { +#ifdef APPLY_COLOR_PALETTE + if(applyTextureColorPalette == 1) { float step = 1.0/1024.0; float a1 = texture2D(texture, textureCoordinates).r; float a2 = texture2D(texture, textureCoordinates + vec2(step, 0.0)).r; @@ -134,6 +135,7 @@ vec4 sampleAndBlend( color = pixColor.rgb; alpha = pixColor.a; } +#endif #ifdef APPLY_BRIGHTNESS color = mix(vec3(0.0), color, textureBrightness); From 437f2b3e079d96dc71cc8858a37f9be92079a70e Mon Sep 17 00:00:00 2001 From: Ryan Hickman Date: Wed, 8 Feb 2017 16:36:14 -0700 Subject: [PATCH 09/18] Get rid of APPLY_COLOR_PALETTE for PALETTE_UNITS --- Source/Scene/GlobeSurfaceShaderSet.js | 4 ---- Source/Shaders/GlobeFS.glsl | 4 ++-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/Source/Scene/GlobeSurfaceShaderSet.js b/Source/Scene/GlobeSurfaceShaderSet.js index a9c2fe5da6ef..83dfd327aeea 100644 --- a/Source/Scene/GlobeSurfaceShaderSet.js +++ b/Source/Scene/GlobeSurfaceShaderSet.js @@ -159,10 +159,6 @@ define([ fs.defines.push('FOG'); } - if (numberOfPaletteTextures > 0) { - fs.defines.push('APPLY_COLOR_PALETTE'); - } - if (applySplit) { fs.defines.push('APPLY_SPLIT'); } diff --git a/Source/Shaders/GlobeFS.glsl b/Source/Shaders/GlobeFS.glsl index 3c5c336fb007..925b956f4f76 100644 --- a/Source/Shaders/GlobeFS.glsl +++ b/Source/Shaders/GlobeFS.glsl @@ -38,7 +38,7 @@ uniform float u_dayTextureOneOverGamma[TEXTURE_UNITS]; uniform vec4 u_dayTextureTexCoordsRectangle[TEXTURE_UNITS]; #endif -#ifdef APPLY_COLOR_PALETTE +#if PALETTE_UNITS > 0 uniform sampler2D u_dayTextureColorPalette[PALETTE_UNITS]; #endif @@ -116,7 +116,7 @@ vec4 sampleAndBlend( } #endif -#ifdef APPLY_COLOR_PALETTE +#if PALETTE_UNITS > 0 if(applyTextureColorPalette == 1) { float step = 1.0/1024.0; float a1 = texture2D(texture, textureCoordinates).r; From 544bfbdac2f9be157f8d29cd7ca662aacf10b82d Mon Sep 17 00:00:00 2001 From: Ryan Hickman Date: Wed, 8 Feb 2017 16:36:39 -0700 Subject: [PATCH 10/18] Use same ++ as Cesium had for numberOfDayTextures --- Source/Scene/GlobeSurfaceTileProvider.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Scene/GlobeSurfaceTileProvider.js b/Source/Scene/GlobeSurfaceTileProvider.js index f3efb810c6b9..c6203737fb7c 100644 --- a/Source/Scene/GlobeSurfaceTileProvider.js +++ b/Source/Scene/GlobeSurfaceTileProvider.js @@ -1144,7 +1144,7 @@ define([ if(imageryLayer.colorPalette !== ImageryLayer.DEFAULT_COLOR_PALETTE) { uniformMapProperties.dayTextureColorPalette[numberOfPaletteTextures] = imageryLayer.colorPalette; colorPaletteKeys[numberOfDayTextures] = numberOfPaletteTextures; - numberOfPaletteTextures++; + ++numberOfPaletteTextures; } if (defined(imagery.credits)) { From c00a7b491049f4b9d83338c5474ff8732d85b38b Mon Sep 17 00:00:00 2001 From: Ryan Hickman Date: Wed, 8 Feb 2017 16:47:39 -0700 Subject: [PATCH 11/18] Fix URL to use other data. Old data was tainted. --- Apps/Sandcastle/gallery/Imagery Layers Palette.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Apps/Sandcastle/gallery/Imagery Layers Palette.html b/Apps/Sandcastle/gallery/Imagery Layers Palette.html index 9b36e924964a..0d9efbfd4951 100644 --- a/Apps/Sandcastle/gallery/Imagery Layers Palette.html +++ b/Apps/Sandcastle/gallery/Imagery Layers Palette.html @@ -89,7 +89,7 @@ var options = { tileWidth: 512, tileHeight: 512, - url: 'http://cache.allisonhouse.com/maps/raw.php?model=rtma&run=201702081600&hour=1486569600000&layers=tmp_2m_0&x={x}&y={y}&z={z}&min={min}&max={max}', + url: 'http://cache.allisonhouse.com/maps/raw.php?model=rtma&run=201702082200&hour=1486591200000&layers=tmp_2m_0&x={x}&y={y}&z={z}&min={min}&max={max}', palette: sortedColors, min: sortedColors[0][0], max: sortedColors[sortedColors.length-1][0] From 947bd3b374daa7bf56370c0ea655d0a5e169d515 Mon Sep 17 00:00:00 2001 From: Ryan Hickman Date: Thu, 9 Feb 2017 12:01:00 -0700 Subject: [PATCH 12/18] `that` was defined but never used. --- Source/Scene/CustomTemplateImageryProvider.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Source/Scene/CustomTemplateImageryProvider.js b/Source/Scene/CustomTemplateImageryProvider.js index 1658261ae8f1..33353b0976c1 100644 --- a/Source/Scene/CustomTemplateImageryProvider.js +++ b/Source/Scene/CustomTemplateImageryProvider.js @@ -629,8 +629,7 @@ define([ if(!defined(imagePromise)) { return imagePromise; } - - var that = this; + return when(imagePromise, function(image) { return image; }); From 08797ff7a22cbc86427e0dd97478f9cc279fcffa Mon Sep 17 00:00:00 2001 From: Ryan Hickman Date: Thu, 9 Feb 2017 12:01:48 -0700 Subject: [PATCH 13/18] `buildPickFeaturesUrl` was defined but never used --- Source/Scene/CustomTemplateImageryProvider.js | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/Source/Scene/CustomTemplateImageryProvider.js b/Source/Scene/CustomTemplateImageryProvider.js index 33353b0976c1..b9e5c9dfb24f 100644 --- a/Source/Scene/CustomTemplateImageryProvider.js +++ b/Source/Scene/CustomTemplateImageryProvider.js @@ -674,17 +674,6 @@ define([ }); } - function buildPickFeaturesUrl(imageryProvider, x, y, level, longitude, latitude, format) { - degreesScratchComputed = false; - projectedScratchComputed = false; - ijScratchComputed = false; - longitudeLatitudeProjectedScratchComputed = false; - - return buildUrl(imageryProvider, imageryProvider._pickFeaturesUrlParts, function(partFunction) { - return partFunction(imageryProvider, x, y, level, longitude, latitude, format); - }); - } - function buildUrl(imageryProvider, parts, partFunctionInvoker) { var url = ''; From 0bbfecc1fa96d185f60c24fda0ac057edbb06879 Mon Sep 17 00:00:00 2001 From: Ryan Hickman Date: Thu, 9 Feb 2017 12:03:20 -0700 Subject: [PATCH 14/18] Use !== instead of != --- Source/Scene/ImageryLayer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Scene/ImageryLayer.js b/Source/Scene/ImageryLayer.js index 9e767112a8cc..727b902c45cd 100644 --- a/Source/Scene/ImageryLayer.js +++ b/Source/Scene/ImageryLayer.js @@ -757,7 +757,7 @@ define([ } if(defined(imagery.imageryLayer.colorPalette) && - imagery.imageryLayer.colorPalette != ImageryLayer.DEFAULT_COLOR_PALETTE && + imagery.imageryLayer.colorPalette !== ImageryLayer.DEFAULT_COLOR_PALETTE && !(imagery.imageryLayer.colorPalette instanceof Texture) ) { imagery.imageryLayer.colorPalette = new Texture({ From 640f0c92533f26dd107fcbd4297eba3192169ffb Mon Sep 17 00:00:00 2001 From: Ryan Hickman Date: Thu, 9 Feb 2017 12:04:04 -0700 Subject: [PATCH 15/18] Get rid of template literal. Fix !==. Avoid global --- .../gallery/Imagery Layers Palette.html | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/Apps/Sandcastle/gallery/Imagery Layers Palette.html b/Apps/Sandcastle/gallery/Imagery Layers Palette.html index 0d9efbfd4951..1df4ca2701c7 100644 --- a/Apps/Sandcastle/gallery/Imagery Layers Palette.html +++ b/Apps/Sandcastle/gallery/Imagery Layers Palette.html @@ -41,27 +41,27 @@ var layers = viewer.imageryLayers; - var rawPalette = `-60 0 0 0 0 --50 45 0 45 --50 53 0 53 --40 46 0 91 --30 68 0 136 --20 163 70 255 --10 213 170 255 -0 255 255 255 -10 255 10 190 -20 72 0 83 -32 0 253 253 -35 88 177 164 -40 0 95 0 -50 0 197 5 -60 180 255 0 -65 255 250 78 -70 255 194 14 -80 255 126 10 -90 237 28 36 -100 107 0 0 -120 97 3 38`; + var rawPalette = '-60 0 0 0 0\n\ +-50 45 0 4\n\ +-50 53 0 53\n\ +-40 46 0 91\n\ +-30 68 0 136\n\ +-20 163 70 255\n\ +-10 213 170 255\n\ +0 255 255 255\n\ +10 255 10 190\n\ +20 72 0 83\n\ +32 0 253 253\n\ +35 88 177 164\n\ +40 0 95 0\n\ +50 0 197 5\n\ +60 180 255 0\n\ +65 255 250 78\n\ +70 255 194 14\n\ +80 255 126 10\n\ +90 237 28 36\n\ +100 107 0 0\n\ +120 97 3 38'; var lines = rawPalette.split('\n'); var unsortedColors = {}; @@ -73,13 +73,13 @@ unsortedColors[key][0] = parseInt(values[1]); unsortedColors[key][1] = parseInt(values[2]); unsortedColors[key][2] = parseInt(values[3]); - unsortedColors[key][3] = (typeof(values[4]) !== 'undefined' && values[4] != '' ? parseInt(values[4]) : 255); + unsortedColors[key][3] = (typeof(values[4]) !== 'undefined' && values[4] !== '' ? parseInt(values[4]) : 255); return true; } }); var sortedColors = []; - for (i in unsortedColors) { + for (var i in unsortedColors) { sortedColors.push([i, unsortedColors[i]]); } sortedColors.sort(function(a, b) { From c75fdb35703b2ada4d641758397f969c41c5a180 Mon Sep 17 00:00:00 2001 From: Ryan Hickman Date: Thu, 9 Feb 2017 12:06:28 -0700 Subject: [PATCH 16/18] =?UTF-8?q?Fix=20=E2=80=9Cbetter=20written=20in=20do?= =?UTF-8?q?t=20notation=E2=80=9D=20errors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gallery/Imagery Layers Palette.html | 62 +++++++++---------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/Apps/Sandcastle/gallery/Imagery Layers Palette.html b/Apps/Sandcastle/gallery/Imagery Layers Palette.html index 1df4ca2701c7..dd0111154e0f 100644 --- a/Apps/Sandcastle/gallery/Imagery Layers Palette.html +++ b/Apps/Sandcastle/gallery/Imagery Layers Palette.html @@ -113,20 +113,20 @@ var i = palette.length; palette[i] = []; - palette[i]['takeoff'] = []; - palette[i]['approach'] = []; - palette[i]['value'] = parseFloat(index); + palette[i].takeoff = []; + palette[i].approach = []; + palette[i].value = parseFloat(index); - palette[i]['takeoff']['red'] = r; - palette[i]['takeoff']['green'] = g; - palette[i]['takeoff']['blue'] = b; - palette[i]['takeoff']['alpha'] = a; + palette[i].takeoff.red = r; + palette[i].takeoff.green = g; + palette[i].takeoff.blue = b; + palette[i].takeoff.alpha = a; if(i > 0) { - palette[i]['approach']['red'] = r; - palette[i]['approach']['green'] = g; - palette[i]['approach']['blue'] = b; - palette[i]['approach']['alpha'] = a; + palette[i].approach.red = r; + palette[i].approach.green = g; + palette[i].approach.blue = b; + palette[i].approach.alpha = a; } if(index < min || min === null) { @@ -148,31 +148,31 @@ var stepSize = diff / 1024; for(var i = 16; i < 4096; i += 4) { - while (currentVal >= palette[currentValI]['value'] && (currentValI+1) < palette.length) { - prevColor[0] = palette[currentValI]['takeoff']['red']; - prevColor[1] = palette[currentValI]['takeoff']['green']; - prevColor[2] = palette[currentValI]['takeoff']['blue']; - prevColor[3] = palette[currentValI]['takeoff']['alpha']; - prevVal = palette[currentValI]['value']; + while (currentVal >= palette[currentValI].value && (currentValI+1) < palette.length) { + prevColor[0] = palette[currentValI].takeoff.red; + prevColor[1] = palette[currentValI].takeoff.green; + prevColor[2] = palette[currentValI].takeoff.blue; + prevColor[3] = palette[currentValI].takeoff.alpha; + prevVal = palette[currentValI].value; currentValI++; - diffVal = palette[currentValI]['value'] - prevVal; - nextColor[0] = palette[currentValI]['approach']['red']; - nextColor[1] = palette[currentValI]['approach']['green']; - nextColor[2] = palette[currentValI]['approach']['blue']; - nextColor[3] = palette[currentValI]['approach']['alpha']; + diffVal = palette[currentValI].value - prevVal; + nextColor[0] = palette[currentValI].approach.red; + nextColor[1] = palette[currentValI].approach.green; + nextColor[2] = palette[currentValI].approach.blue; + nextColor[3] = palette[currentValI].approach.alpha; } - if (currentVal >= palette[currentValI]['value'] && (currentValI+1) >= palette.length) { - prevColor[0] = palette[currentValI]['approach']['red']; - prevColor[1] = palette[currentValI]['approach']['green']; - prevColor[2] = palette[currentValI]['approach']['blue']; - prevColor[3] = palette[currentValI]['approach']['alpha']; + if (currentVal >= palette[currentValI].value && (currentValI+1) >= palette.length) { + prevColor[0] = palette[currentValI].approach.red; + prevColor[1] = palette[currentValI].approach.green; + prevColor[2] = palette[currentValI].approach.blue; + prevColor[3] = palette[currentValI].approach.alpha; prevVal = max; currentVal = max; diffVal = 1.0; - nextColor[0] = palette[currentValI]['approach']['red']; - nextColor[1] = palette[currentValI]['approach']['green']; - nextColor[2] = palette[currentValI]['approach']['blue']; - nextColor[3] = palette[currentValI]['approach']['alpha']; + nextColor[0] = palette[currentValI].approach.red; + nextColor[1] = palette[currentValI].approach.green; + nextColor[2] = palette[currentValI].approach.blue; + nextColor[3] = palette[currentValI].approach.alpha; } colorTableData[i] = parseFloat(currentVal-prevVal) * (parseFloat(nextColor[0] - prevColor[0]) / diffVal) + prevColor[0]; colorTableData[i+1] = parseFloat(currentVal-prevVal) * parseFloat(nextColor[1] - prevColor[1]) / diffVal + prevColor[1]; From de0ad6be069c44b1f8572cce6bc054c612bdc9d2 Mon Sep 17 00:00:00 2001 From: Ryan Hickman Date: Thu, 9 Feb 2017 12:23:15 -0700 Subject: [PATCH 17/18] =?UTF-8?q?Hoist=20variable=20to=20avoid=20=E2=80=98?= =?UTF-8?q?already=20defined=E2=80=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Apps/Sandcastle/gallery/Imagery Layers Palette.html | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Apps/Sandcastle/gallery/Imagery Layers Palette.html b/Apps/Sandcastle/gallery/Imagery Layers Palette.html index dd0111154e0f..4a28b8117fb9 100644 --- a/Apps/Sandcastle/gallery/Imagery Layers Palette.html +++ b/Apps/Sandcastle/gallery/Imagery Layers Palette.html @@ -79,8 +79,11 @@ }); var sortedColors = []; - for (var i in unsortedColors) { - sortedColors.push([i, unsortedColors[i]]); + var i; + for (i in unsortedColors) { + if(sortedColors.hasOwnProperty(i)) { + sortedColors.push([i, unsortedColors[i]]); + } } sortedColors.sort(function(a, b) { return a[0] - b[0]; @@ -138,7 +141,7 @@ } } - for(var i = 0; i < sortedColors.length; i++) { + for(i = 0; i < sortedColors.length; i++) { setPalette(sortedColors[i][0], sortedColors[i][1][0], sortedColors[i][1][1], sortedColors[i][1][2], sortedColors[i][1][3]); } @@ -147,7 +150,7 @@ prevVal = min; var stepSize = diff / 1024; - for(var i = 16; i < 4096; i += 4) { + for(i = 16; i < 4096; i += 4) { while (currentVal >= palette[currentValI].value && (currentValI+1) < palette.length) { prevColor[0] = palette[currentValI].takeoff.red; prevColor[1] = palette[currentValI].takeoff.green; From 538474ba01917f484250a65262a25c22393f1e1d Mon Sep 17 00:00:00 2001 From: Ryan Hickman Date: Thu, 9 Feb 2017 12:24:54 -0700 Subject: [PATCH 18/18] Fix for wrapped in if `hasOwnProperty` --- Apps/Sandcastle/gallery/Imagery Layers Palette.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Apps/Sandcastle/gallery/Imagery Layers Palette.html b/Apps/Sandcastle/gallery/Imagery Layers Palette.html index 4a28b8117fb9..658292cbfcbb 100644 --- a/Apps/Sandcastle/gallery/Imagery Layers Palette.html +++ b/Apps/Sandcastle/gallery/Imagery Layers Palette.html @@ -81,7 +81,7 @@ var sortedColors = []; var i; for (i in unsortedColors) { - if(sortedColors.hasOwnProperty(i)) { + if(unsortedColors.hasOwnProperty(i)) { sortedColors.push([i, unsortedColors[i]]); } }