123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748 |
- /*global define*/
- define([
- '../Core/BoundingSphere',
- '../Core/Cartesian3',
- '../Core/Cartesian4',
- '../Core/Cartographic',
- '../Core/defaultValue',
- '../Core/defined',
- '../Core/defineProperties',
- '../Core/IntersectionTests',
- '../Core/PixelFormat',
- '../Core/Rectangle',
- '../Renderer/PixelDatatype',
- '../Renderer/TextureMagnificationFilter',
- '../Renderer/TextureMinificationFilter',
- '../Renderer/TextureWrap',
- './ImageryState',
- './QuadtreeTileLoadState',
- './SceneMode',
- './TerrainState',
- './TileTerrain'
- ], function(
- BoundingSphere,
- Cartesian3,
- Cartesian4,
- Cartographic,
- defaultValue,
- defined,
- defineProperties,
- IntersectionTests,
- PixelFormat,
- Rectangle,
- PixelDatatype,
- TextureMagnificationFilter,
- TextureMinificationFilter,
- TextureWrap,
- ImageryState,
- QuadtreeTileLoadState,
- SceneMode,
- TerrainState,
- TileTerrain) {
- "use strict";
- /**
- * Contains additional information about a {@link QuadtreeTile} of the globe's surface, and
- * encapsulates state transition logic for loading tiles.
- *
- * @constructor
- * @alias GlobeSurfaceTile
- * @private
- */
- var GlobeSurfaceTile = function() {
- /**
- * The {@link TileImagery} attached to this tile.
- * @type {TileImagery[]}
- * @default []
- */
- this.imagery = [];
- /**
- * The world coordinates of the southwest corner of the tile's rectangle.
- *
- * @type {Cartesian3}
- * @default Cartesian3()
- */
- this.southwestCornerCartesian = new Cartesian3();
- /**
- * The world coordinates of the northeast corner of the tile's rectangle.
- *
- * @type {Cartesian3}
- * @default Cartesian3()
- */
- this.northeastCornerCartesian = new Cartesian3();
- /**
- * A normal that, along with southwestCornerCartesian, defines a plane at the western edge of
- * the tile. Any position above (in the direction of the normal) this plane is outside the tile.
- *
- * @type {Cartesian3}
- * @default Cartesian3()
- */
- this.westNormal = new Cartesian3();
- /**
- * A normal that, along with southwestCornerCartesian, defines a plane at the southern edge of
- * the tile. Any position above (in the direction of the normal) this plane is outside the tile.
- * Because points of constant latitude do not necessary lie in a plane, positions below this
- * plane are not necessarily inside the tile, but they are close.
- *
- * @type {Cartesian3}
- * @default Cartesian3()
- */
- this.southNormal = new Cartesian3();
- /**
- * A normal that, along with northeastCornerCartesian, defines a plane at the eastern edge of
- * the tile. Any position above (in the direction of the normal) this plane is outside the tile.
- *
- * @type {Cartesian3}
- * @default Cartesian3()
- */
- this.eastNormal = new Cartesian3();
- /**
- * A normal that, along with northeastCornerCartesian, defines a plane at the eastern edge of
- * the tile. Any position above (in the direction of the normal) this plane is outside the tile.
- * Because points of constant latitude do not necessary lie in a plane, positions below this
- * plane are not necessarily inside the tile, but they are close.
- *
- * @type {Cartesian3}
- * @default Cartesian3()
- */
- this.northNormal = new Cartesian3();
- this.waterMaskTexture = undefined;
- this.waterMaskTranslationAndScale = new Cartesian4(0.0, 0.0, 1.0, 1.0);
- this.terrainData = undefined;
- this.center = new Cartesian3();
- this.vertexArray = undefined;
- this.minimumHeight = 0.0;
- this.maximumHeight = 0.0;
- this.boundingSphere3D = new BoundingSphere();
- this.boundingSphere2D = new BoundingSphere();
- this.occludeePointInScaledSpace = new Cartesian3();
- this.loadedTerrain = undefined;
- this.upsampledTerrain = undefined;
- this.pickBoundingSphere = new BoundingSphere();
- this.pickTerrain = undefined;
- this.surfaceShader = undefined;
- };
- defineProperties(GlobeSurfaceTile.prototype, {
- /**
- * Gets a value indicating whether or not this tile is eligible to be unloaded.
- * Typically, a tile is ineligible to be unloaded while an asynchronous operation,
- * such as a request for data, is in progress on it. A tile will never be
- * unloaded while it is needed for rendering, regardless of the value of this
- * property.
- * @memberof GlobeSurfaceTile.prototype
- * @type {Boolean}
- */
- eligibleForUnloading : {
- get : function() {
- // Do not remove tiles that are transitioning or that have
- // imagery that is transitioning.
- var loadedTerrain = this.loadedTerrain;
- var loadingIsTransitioning = defined(loadedTerrain) &&
- (loadedTerrain.state === TerrainState.RECEIVING || loadedTerrain.state === TerrainState.TRANSFORMING);
- var upsampledTerrain = this.upsampledTerrain;
- var upsamplingIsTransitioning = defined(upsampledTerrain) &&
- (upsampledTerrain.state === TerrainState.RECEIVING || upsampledTerrain.state === TerrainState.TRANSFORMING);
- var shouldRemoveTile = !loadingIsTransitioning && !upsamplingIsTransitioning;
- var imagery = this.imagery;
- for (var i = 0, len = imagery.length; shouldRemoveTile && i < len; ++i) {
- var tileImagery = imagery[i];
- shouldRemoveTile = !defined(tileImagery.loadingImagery) || tileImagery.loadingImagery.state !== ImageryState.TRANSITIONING;
- }
- return shouldRemoveTile;
- }
- }
- });
- function getPosition(tile, scene, vertices, stride, index, result) {
- Cartesian3.unpack(vertices, index * stride, result);
- Cartesian3.add(tile.center, result, result);
- if (defined(scene) && scene.mode !== SceneMode.SCENE3D) {
- var projection = scene.mapProjection;
- var ellipsoid = projection.ellipsoid;
- var positionCart = ellipsoid.cartesianToCartographic(result);
- projection.project(positionCart, result);
- Cartesian3.fromElements(result.z, result.x, result.y, result);
- }
- return result;
- }
- var scratchV0 = new Cartesian3();
- var scratchV1 = new Cartesian3();
- var scratchV2 = new Cartesian3();
- var scratchResult = new Cartesian3();
- GlobeSurfaceTile.prototype.pick = function(ray, scene, cullBackFaces, result) {
- var terrain = this.pickTerrain;
- if (!defined(terrain)) {
- return undefined;
- }
- var mesh = terrain.mesh;
- if (!defined(mesh)) {
- return undefined;
- }
- var vertices = mesh.vertices;
- var stride = mesh.stride;
- var indices = mesh.indices;
- var length = indices.length;
- for (var i = 0; i < length; i += 3) {
- var i0 = indices[i];
- var i1 = indices[i + 1];
- var i2 = indices[i + 2];
- var v0 = getPosition(this, scene, vertices, stride, i0, scratchV0);
- var v1 = getPosition(this, scene, vertices, stride, i1, scratchV1);
- var v2 = getPosition(this, scene, vertices, stride, i2, scratchV2);
- var intersection = IntersectionTests.rayTriangle(ray, v0, v1, v2, cullBackFaces, scratchResult);
- if (defined(intersection)) {
- return Cartesian3.clone(intersection, result);
- }
- }
- return undefined;
- };
- GlobeSurfaceTile.prototype.freeResources = function() {
- if (defined(this.waterMaskTexture)) {
- --this.waterMaskTexture.referenceCount;
- if (this.waterMaskTexture.referenceCount === 0) {
- this.waterMaskTexture.destroy();
- }
- this.waterMaskTexture = undefined;
- }
- this.terrainData = undefined;
- if (defined(this.loadedTerrain)) {
- this.loadedTerrain.freeResources();
- this.loadedTerrain = undefined;
- }
- if (defined(this.upsampledTerrain)) {
- this.upsampledTerrain.freeResources();
- this.upsampledTerrain = undefined;
- }
- if (defined(this.pickTerrain)) {
- this.pickTerrain.freeResources();
- this.pickTerrain = undefined;
- }
- var i, len;
- var imageryList = this.imagery;
- for (i = 0, len = imageryList.length; i < len; ++i) {
- imageryList[i].freeResources();
- }
- this.imagery.length = 0;
- this.freeVertexArray();
- };
- GlobeSurfaceTile.prototype.freeVertexArray = function() {
- var indexBuffer;
- if (defined(this.vertexArray)) {
- indexBuffer = this.vertexArray.indexBuffer;
- this.vertexArray = this.vertexArray.destroy();
- if (!indexBuffer.isDestroyed() && defined(indexBuffer.referenceCount)) {
- --indexBuffer.referenceCount;
- if (indexBuffer.referenceCount === 0) {
- indexBuffer.destroy();
- }
- }
- }
- if (defined(this.wireframeVertexArray)) {
- indexBuffer = this.wireframeVertexArray.indexBuffer;
- this.wireframeVertexArray = this.wireframeVertexArray.destroy();
- if (!indexBuffer.isDestroyed() && defined(indexBuffer.referenceCount)) {
- --indexBuffer.referenceCount;
- if (indexBuffer.referenceCount === 0) {
- indexBuffer.destroy();
- }
- }
- }
- };
- GlobeSurfaceTile.processStateMachine = function(tile, context, terrainProvider, imageryLayerCollection) {
- var surfaceTile = tile.data;
- if (!defined(surfaceTile)) {
- surfaceTile = tile.data = new GlobeSurfaceTile();
- }
- if (tile.state === QuadtreeTileLoadState.START) {
- prepareNewTile(tile, terrainProvider, imageryLayerCollection);
- tile.state = QuadtreeTileLoadState.LOADING;
- }
- if (tile.state === QuadtreeTileLoadState.LOADING) {
- processTerrainStateMachine(tile, context, terrainProvider);
- }
- // The terrain is renderable as soon as we have a valid vertex array.
- var isRenderable = defined(surfaceTile.vertexArray);
- // But it's not done loading until our two state machines are terminated.
- var isDoneLoading = !defined(surfaceTile.loadedTerrain) && !defined(surfaceTile.upsampledTerrain);
- // If this tile's terrain and imagery are just upsampled from its parent, mark the tile as
- // upsampled only. We won't refine a tile if its four children are upsampled only.
- var isUpsampledOnly = defined(surfaceTile.terrainData) && surfaceTile.terrainData.wasCreatedByUpsampling();
- // Transition imagery states
- var tileImageryCollection = surfaceTile.imagery;
- for (var i = 0, len = tileImageryCollection.length; i < len; ++i) {
- var tileImagery = tileImageryCollection[i];
- if (!defined(tileImagery.loadingImagery)) {
- isUpsampledOnly = false;
- continue;
- }
- if (tileImagery.loadingImagery.state === ImageryState.PLACEHOLDER) {
- var imageryLayer = tileImagery.loadingImagery.imageryLayer;
- if (imageryLayer.imageryProvider.ready) {
- // Remove the placeholder and add the actual skeletons (if any)
- // at the same position. Then continue the loop at the same index.
- tileImagery.freeResources();
- tileImageryCollection.splice(i, 1);
- imageryLayer._createTileImagerySkeletons(tile, terrainProvider, i);
- --i;
- len = tileImageryCollection.length;
- continue;
- } else {
- isUpsampledOnly = false;
- }
- }
- var thisTileDoneLoading = tileImagery.processStateMachine(tile, context);
- isDoneLoading = isDoneLoading && thisTileDoneLoading;
- // The imagery is renderable as soon as we have any renderable imagery for this region.
- isRenderable = isRenderable && (thisTileDoneLoading || defined(tileImagery.readyImagery));
- isUpsampledOnly = isUpsampledOnly && defined(tileImagery.loadingImagery) &&
- (tileImagery.loadingImagery.state === ImageryState.FAILED || tileImagery.loadingImagery.state === ImageryState.INVALID);
- }
- tile.upsampledFromParent = isUpsampledOnly;
- // The tile becomes renderable when the terrain and all imagery data are loaded.
- if (i === len) {
- if (isRenderable) {
- tile.renderable = true;
- }
- if (isDoneLoading) {
- tile.state = QuadtreeTileLoadState.DONE;
- }
- }
- };
- var cartesian3Scratch = new Cartesian3();
- var cartesian3Scratch2 = new Cartesian3();
- var westernMidpointScratch = new Cartesian3();
- var easternMidpointScratch = new Cartesian3();
- var cartographicScratch = new Cartographic();
- function prepareNewTile(tile, terrainProvider, imageryLayerCollection) {
- var surfaceTile = tile.data;
- var upsampleTileDetails = getUpsampleTileDetails(tile);
- if (defined(upsampleTileDetails)) {
- surfaceTile.upsampledTerrain = new TileTerrain(upsampleTileDetails);
- }
- if (isDataAvailable(tile, terrainProvider)) {
- surfaceTile.loadedTerrain = new TileTerrain();
- }
- // Map imagery tiles to this terrain tile
- for (var i = 0, len = imageryLayerCollection.length; i < len; ++i) {
- var layer = imageryLayerCollection.get(i);
- if (layer.show) {
- layer._createTileImagerySkeletons(tile, terrainProvider);
- }
- }
- var ellipsoid = tile.tilingScheme.ellipsoid;
- // Compute tile rectangle boundaries for estimating the distance to the tile.
- var rectangle = tile.rectangle;
- ellipsoid.cartographicToCartesian(Rectangle.southwest(rectangle), surfaceTile.southwestCornerCartesian);
- ellipsoid.cartographicToCartesian(Rectangle.northeast(rectangle), surfaceTile.northeastCornerCartesian);
- // The middle latitude on the western edge.
- cartographicScratch.longitude = rectangle.west;
- cartographicScratch.latitude = (rectangle.south + rectangle.north) * 0.5;
- cartographicScratch.height = 0.0;
- var westernMidpointCartesian = ellipsoid.cartographicToCartesian(cartographicScratch, westernMidpointScratch);
- // Compute the normal of the plane on the western edge of the tile.
- var westNormal = Cartesian3.cross(westernMidpointCartesian, Cartesian3.UNIT_Z, cartesian3Scratch);
- Cartesian3.normalize(westNormal, surfaceTile.westNormal);
- // The middle latitude on the eastern edge.
- cartographicScratch.longitude = rectangle.east;
- var easternMidpointCartesian = ellipsoid.cartographicToCartesian(cartographicScratch, easternMidpointScratch);
- // Compute the normal of the plane on the eastern edge of the tile.
- var eastNormal = Cartesian3.cross(Cartesian3.UNIT_Z, easternMidpointCartesian, cartesian3Scratch);
- Cartesian3.normalize(eastNormal, surfaceTile.eastNormal);
- // Compute the normal of the plane bounding the southern edge of the tile.
- var southeastCornerNormal = ellipsoid.geodeticSurfaceNormalCartographic(Rectangle.southeast(rectangle), cartesian3Scratch2);
- var westVector = Cartesian3.subtract(westernMidpointCartesian, easternMidpointCartesian, cartesian3Scratch);
- var southNormal = Cartesian3.cross(southeastCornerNormal, westVector, cartesian3Scratch2);
- Cartesian3.normalize(southNormal, surfaceTile.southNormal);
- // Compute the normal of the plane bounding the northern edge of the tile.
- var northwestCornerNormal = ellipsoid.geodeticSurfaceNormalCartographic(Rectangle.northwest(rectangle), cartesian3Scratch2);
- var northNormal = Cartesian3.cross(westVector, northwestCornerNormal, cartesian3Scratch2);
- Cartesian3.normalize(northNormal, surfaceTile.northNormal);
- }
- function processTerrainStateMachine(tile, context, terrainProvider) {
- var surfaceTile = tile.data;
- var loaded = surfaceTile.loadedTerrain;
- var upsampled = surfaceTile.upsampledTerrain;
- var suspendUpsampling = false;
- if (defined(loaded)) {
- loaded.processLoadStateMachine(context, terrainProvider, tile.x, tile.y, tile.level);
- // Publish the terrain data on the tile as soon as it is available.
- // We'll potentially need it to upsample child tiles.
- if (loaded.state >= TerrainState.RECEIVED) {
- if (surfaceTile.terrainData !== loaded.data) {
- surfaceTile.terrainData = loaded.data;
- // If there's a water mask included in the terrain data, create a
- // texture for it.
- createWaterMaskTextureIfNeeded(context, surfaceTile);
- propagateNewLoadedDataToChildren(tile);
- }
- suspendUpsampling = true;
- }
- if (loaded.state === TerrainState.READY) {
- loaded.publishToTile(tile);
- // No further loading or upsampling is necessary.
- surfaceTile.pickTerrain = defaultValue(surfaceTile.loadedTerrain, surfaceTile.upsampledTerrain);
- surfaceTile.loadedTerrain = undefined;
- surfaceTile.upsampledTerrain = undefined;
- } else if (loaded.state === TerrainState.FAILED) {
- // Loading failed for some reason, or data is simply not available,
- // so no need to continue trying to load. Any retrying will happen before we
- // reach this point.
- surfaceTile.loadedTerrain = undefined;
- }
- }
- if (!suspendUpsampling && defined(upsampled)) {
- upsampled.processUpsampleStateMachine(context, terrainProvider, tile.x, tile.y, tile.level);
- // Publish the terrain data on the tile as soon as it is available.
- // We'll potentially need it to upsample child tiles.
- // It's safe to overwrite terrainData because we won't get here after
- // loaded terrain data has been received.
- if (upsampled.state >= TerrainState.RECEIVED) {
- if (surfaceTile.terrainData !== upsampled.data) {
- surfaceTile.terrainData = upsampled.data;
- // If the terrain provider has a water mask, "upsample" that as well
- // by computing texture translation and scale.
- if (terrainProvider.hasWaterMask) {
- upsampleWaterMask(tile);
- }
- propagateNewUpsampledDataToChildren(tile);
- }
- }
- if (upsampled.state === TerrainState.READY) {
- upsampled.publishToTile(tile);
- // No further upsampling is necessary. We need to continue loading, though.
- surfaceTile.pickTerrain = surfaceTile.upsampledTerrain;
- surfaceTile.upsampledTerrain = undefined;
- } else if (upsampled.state === TerrainState.FAILED) {
- // Upsampling failed for some reason. This is pretty much a catastrophic failure,
- // but maybe we'll be saved by loading.
- surfaceTile.upsampledTerrain = undefined;
- }
- }
- }
- function getUpsampleTileDetails(tile) {
- // Find the nearest ancestor with loaded terrain.
- var sourceTile = tile.parent;
- while (defined(sourceTile) && defined(sourceTile.data) && !defined(sourceTile.data.terrainData)) {
- sourceTile = sourceTile.parent;
- }
- if (!defined(sourceTile) || !defined(sourceTile.data)) {
- // No ancestors have loaded terrain - try again later.
- return undefined;
- }
- return {
- data : sourceTile.data.terrainData,
- x : sourceTile.x,
- y : sourceTile.y,
- level : sourceTile.level
- };
- }
- function propagateNewUpsampledDataToChildren(tile) {
- var surfaceTile = tile.data;
- // Now that there's new data for this tile:
- // - child tiles that were previously upsampled need to be re-upsampled based on the new data.
- // Generally this is only necessary when a child tile is upsampled, and then one
- // of its ancestors receives new (better) data and we want to re-upsample from the
- // new data.
- if (defined(tile._children)) {
- for (var childIndex = 0; childIndex < 4; ++childIndex) {
- var childTile = tile._children[childIndex];
- if (childTile.state !== QuadtreeTileLoadState.START) {
- var childSurfaceTile = childTile.data;
- if (defined(childSurfaceTile.terrainData) && !childSurfaceTile.terrainData.wasCreatedByUpsampling()) {
- // Data for the child tile has already been loaded.
- continue;
- }
- // Restart the upsampling process, no matter its current state.
- // We create a new instance rather than just restarting the existing one
- // because there could be an asynchronous operation pending on the existing one.
- if (defined(childSurfaceTile.upsampledTerrain)) {
- childSurfaceTile.upsampledTerrain.freeResources();
- }
- childSurfaceTile.upsampledTerrain = new TileTerrain({
- data : surfaceTile.terrainData,
- x : tile.x,
- y : tile.y,
- level : tile.level
- });
- childTile.state = QuadtreeTileLoadState.LOADING;
- }
- }
- }
- }
- function propagateNewLoadedDataToChildren(tile) {
- var surfaceTile = tile.data;
- // Now that there's new data for this tile:
- // - child tiles that were previously upsampled need to be re-upsampled based on the new data.
- // - child tiles that were previously deemed unavailable may now be available.
- if (defined(tile.children)) {
- for (var childIndex = 0; childIndex < 4; ++childIndex) {
- var childTile = tile.children[childIndex];
- if (childTile.state !== QuadtreeTileLoadState.START) {
- var childSurfaceTile = childTile.data;
- if (defined(childSurfaceTile.terrainData) && !childSurfaceTile.terrainData.wasCreatedByUpsampling()) {
- // Data for the child tile has already been loaded.
- continue;
- }
- // Restart the upsampling process, no matter its current state.
- // We create a new instance rather than just restarting the existing one
- // because there could be an asynchronous operation pending on the existing one.
- if (defined(childSurfaceTile.upsampledTerrain)) {
- childSurfaceTile.upsampledTerrain.freeResources();
- }
- childSurfaceTile.upsampledTerrain = new TileTerrain({
- data : surfaceTile.terrainData,
- x : tile.x,
- y : tile.y,
- level : tile.level
- });
- if (surfaceTile.terrainData.isChildAvailable(tile.x, tile.y, childTile.x, childTile.y)) {
- // Data is available for the child now. It might have been before, too.
- if (!defined(childSurfaceTile.loadedTerrain)) {
- // No load process is in progress, so start one.
- childSurfaceTile.loadedTerrain = new TileTerrain();
- }
- }
- childTile.state = QuadtreeTileLoadState.LOADING;
- }
- }
- }
- }
- function isDataAvailable(tile, terrainProvider) {
- var tileDataAvailable = terrainProvider.getTileDataAvailable(tile.x, tile.y, tile.level);
- if (defined(tileDataAvailable)) {
- return tileDataAvailable;
- }
- var parent = tile.parent;
- if (!defined(parent)) {
- // Data is assumed to be available for root tiles.
- return true;
- }
- if (!defined(parent.data) || !defined(parent.data.terrainData)) {
- // Parent tile data is not yet received or upsampled, so assume (for now) that this
- // child tile is not available.
- return false;
- }
- return parent.data.terrainData.isChildAvailable(parent.x, parent.y, tile.x, tile.y);
- }
- function getContextWaterMaskData(context) {
- var data = context.cache.tile_waterMaskData;
- if (!defined(data)) {
- var allWaterTexture = context.createTexture2D({
- pixelFormat : PixelFormat.LUMINANCE,
- pixelDatatype : PixelDatatype.UNSIGNED_BYTE,
- source : {
- arrayBufferView : new Uint8Array([255]),
- width : 1,
- height : 1
- }
- });
- allWaterTexture.referenceCount = 1;
- var sampler = context.createSampler({
- wrapS : TextureWrap.CLAMP_TO_EDGE,
- wrapT : TextureWrap.CLAMP_TO_EDGE,
- minificationFilter : TextureMinificationFilter.LINEAR,
- magnificationFilter : TextureMagnificationFilter.LINEAR
- });
- data = {
- allWaterTexture : allWaterTexture,
- sampler : sampler,
- destroy : function() {
- this.allWaterTexture.destroy();
- }
- };
- context.cache.tile_waterMaskData = data;
- }
- return data;
- }
- function createWaterMaskTextureIfNeeded(context, surfaceTile) {
- var previousTexture = surfaceTile.waterMaskTexture;
- if (defined(previousTexture)) {
- --previousTexture.referenceCount;
- if (previousTexture.referenceCount === 0) {
- previousTexture.destroy();
- }
- surfaceTile.waterMaskTexture = undefined;
- }
- var waterMask = surfaceTile.terrainData.waterMask;
- if (!defined(waterMask)) {
- return;
- }
- var waterMaskData = getContextWaterMaskData(context);
- var texture;
- var waterMaskLength = waterMask.length;
- if (waterMaskLength === 1) {
- // Length 1 means the tile is entirely land or entirely water.
- // A value of 0 indicates entirely land, a value of 1 indicates entirely water.
- if (waterMask[0] !== 0) {
- texture = waterMaskData.allWaterTexture;
- } else {
- // Leave the texture undefined if the tile is entirely land.
- return;
- }
- } else {
- var textureSize = Math.sqrt(waterMaskLength);
- texture = context.createTexture2D({
- pixelFormat : PixelFormat.LUMINANCE,
- pixelDatatype : PixelDatatype.UNSIGNED_BYTE,
- source : {
- width : textureSize,
- height : textureSize,
- arrayBufferView : waterMask
- }
- });
- texture.referenceCount = 0;
- texture.sampler = waterMaskData.sampler;
- }
- ++texture.referenceCount;
- surfaceTile.waterMaskTexture = texture;
- Cartesian4.fromElements(0.0, 0.0, 1.0, 1.0, surfaceTile.waterMaskTranslationAndScale);
- }
- function upsampleWaterMask(tile) {
- var surfaceTile = tile.data;
- // Find the nearest ancestor with loaded terrain.
- var sourceTile = tile.parent;
- while (defined(sourceTile) && !defined(sourceTile.data.terrainData) || sourceTile.data.terrainData.wasCreatedByUpsampling()) {
- sourceTile = sourceTile.parent;
- }
- if (!defined(sourceTile) || !defined(sourceTile.data.waterMaskTexture)) {
- // No ancestors have a water mask texture - try again later.
- return;
- }
- surfaceTile.waterMaskTexture = sourceTile.data.waterMaskTexture;
- ++surfaceTile.waterMaskTexture.referenceCount;
- // Compute the water mask translation and scale
- var sourceTileRectangle = sourceTile.rectangle;
- var tileRectangle = tile.rectangle;
- var tileWidth = tileRectangle.width;
- var tileHeight = tileRectangle.height;
- var scaleX = tileWidth / sourceTileRectangle.width;
- var scaleY = tileHeight / sourceTileRectangle.height;
- surfaceTile.waterMaskTranslationAndScale.x = scaleX * (tileRectangle.west - sourceTileRectangle.west) / tileWidth;
- surfaceTile.waterMaskTranslationAndScale.y = scaleY * (tileRectangle.south - sourceTileRectangle.south) / tileHeight;
- surfaceTile.waterMaskTranslationAndScale.z = scaleX;
- surfaceTile.waterMaskTranslationAndScale.w = scaleY;
- }
- return GlobeSurfaceTile;
- });
|