GlobeSurfaceTile.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858
  1. import BoundingSphere from "../Core/BoundingSphere.js";
  2. import Cartesian3 from "../Core/Cartesian3.js";
  3. import Cartesian4 from "../Core/Cartesian4.js";
  4. import defined from "../Core/defined.js";
  5. import IndexDatatype from "../Core/IndexDatatype.js";
  6. import IntersectionTests from "../Core/IntersectionTests.js";
  7. import OrientedBoundingBox from "../Core/OrientedBoundingBox.js";
  8. import PixelFormat from "../Core/PixelFormat.js";
  9. import Ray from "../Core/Ray.js";
  10. import Request from "../Core/Request.js";
  11. import RequestState from "../Core/RequestState.js";
  12. import RequestType from "../Core/RequestType.js";
  13. import TileProviderError from "../Core/TileProviderError.js";
  14. import Buffer from "../Renderer/Buffer.js";
  15. import BufferUsage from "../Renderer/BufferUsage.js";
  16. import PixelDatatype from "../Renderer/PixelDatatype.js";
  17. import Sampler from "../Renderer/Sampler.js";
  18. import Texture from "../Renderer/Texture.js";
  19. import TextureMagnificationFilter from "../Renderer/TextureMagnificationFilter.js";
  20. import TextureMinificationFilter from "../Renderer/TextureMinificationFilter.js";
  21. import TextureWrap from "../Renderer/TextureWrap.js";
  22. import VertexArray from "../Renderer/VertexArray.js";
  23. import when from "../ThirdParty/when.js";
  24. import ImageryState from "./ImageryState.js";
  25. import QuadtreeTileLoadState from "./QuadtreeTileLoadState.js";
  26. import SceneMode from "./SceneMode.js";
  27. import TerrainState from "./TerrainState.js";
  28. /**
  29. * Contains additional information about a {@link QuadtreeTile} of the globe's surface, and
  30. * encapsulates state transition logic for loading tiles.
  31. *
  32. * @constructor
  33. * @alias GlobeSurfaceTile
  34. * @private
  35. */
  36. function GlobeSurfaceTile() {
  37. /**
  38. * The {@link TileImagery} attached to this tile.
  39. * @type {TileImagery[]}
  40. * @default []
  41. */
  42. this.imagery = [];
  43. this.waterMaskTexture = undefined;
  44. this.waterMaskTranslationAndScale = new Cartesian4(0.0, 0.0, 1.0, 1.0);
  45. this.terrainData = undefined;
  46. this.vertexArray = undefined;
  47. this.orientedBoundingBox = undefined;
  48. this.boundingVolumeSourceTile = undefined;
  49. /**
  50. * A bounding region used to estimate distance to the tile. The horizontal bounds are always tight-fitting,
  51. * but the `minimumHeight` and `maximumHeight` properties may be derived from the min/max of an ancestor tile
  52. * and be quite loose-fitting and thus very poor for estimating distance. The {@link TileBoundingRegion#boundingVolume}
  53. * and {@link TileBoundingRegion#boundingSphere} will always be undefined; tiles store these separately.
  54. * @type {TileBoundingRegion}
  55. */
  56. this.tileBoundingRegion = undefined;
  57. this.occludeePointInScaledSpace = new Cartesian3();
  58. this.terrainState = TerrainState.UNLOADED;
  59. this.mesh = undefined;
  60. this.fill = undefined;
  61. this.pickBoundingSphere = new BoundingSphere();
  62. this.surfaceShader = undefined;
  63. this.isClipped = true;
  64. this.clippedByBoundaries = false;
  65. }
  66. Object.defineProperties(GlobeSurfaceTile.prototype, {
  67. /**
  68. * Gets a value indicating whether or not this tile is eligible to be unloaded.
  69. * Typically, a tile is ineligible to be unloaded while an asynchronous operation,
  70. * such as a request for data, is in progress on it. A tile will never be
  71. * unloaded while it is needed for rendering, regardless of the value of this
  72. * property.
  73. * @memberof GlobeSurfaceTile.prototype
  74. * @type {Boolean}
  75. */
  76. eligibleForUnloading: {
  77. get: function () {
  78. // Do not remove tiles that are transitioning or that have
  79. // imagery that is transitioning.
  80. var terrainState = this.terrainState;
  81. var loadingIsTransitioning =
  82. terrainState === TerrainState.RECEIVING ||
  83. terrainState === TerrainState.TRANSFORMING;
  84. var shouldRemoveTile = !loadingIsTransitioning;
  85. var imagery = this.imagery;
  86. for (var i = 0, len = imagery.length; shouldRemoveTile && i < len; ++i) {
  87. var tileImagery = imagery[i];
  88. shouldRemoveTile =
  89. !defined(tileImagery.loadingImagery) ||
  90. tileImagery.loadingImagery.state !== ImageryState.TRANSITIONING;
  91. }
  92. return shouldRemoveTile;
  93. },
  94. },
  95. /**
  96. * Gets the {@link TerrainMesh} that is used for rendering this tile, if any.
  97. * Returns the value of the {@link GlobeSurfaceTile#mesh} property if
  98. * {@link GlobeSurfaceTile#vertexArray} is defined. Otherwise, It returns the
  99. * {@link TerrainFillMesh#mesh} property of the {@link GlobeSurfaceTile#fill}.
  100. * If there is no fill, it returns undefined.
  101. *
  102. * @memberof GlobeSurfaceTile.prototype
  103. * @type {TerrainMesh}
  104. */
  105. renderedMesh: {
  106. get: function () {
  107. if (defined(this.vertexArray)) {
  108. return this.mesh;
  109. } else if (defined(this.fill)) {
  110. return this.fill.mesh;
  111. }
  112. return undefined;
  113. },
  114. },
  115. });
  116. function getPosition(encoding, mode, projection, vertices, index, result) {
  117. encoding.decodePosition(vertices, index, result);
  118. if (defined(mode) && mode !== SceneMode.SCENE3D) {
  119. var ellipsoid = projection.ellipsoid;
  120. var positionCart = ellipsoid.cartesianToCartographic(result);
  121. projection.project(positionCart, result);
  122. Cartesian3.fromElements(result.z, result.x, result.y, result);
  123. }
  124. return result;
  125. }
  126. var scratchV0 = new Cartesian3();
  127. var scratchV1 = new Cartesian3();
  128. var scratchV2 = new Cartesian3();
  129. GlobeSurfaceTile.prototype.pick = function (
  130. ray,
  131. mode,
  132. projection,
  133. cullBackFaces,
  134. result
  135. ) {
  136. var mesh = this.renderedMesh;
  137. if (!defined(mesh)) {
  138. return undefined;
  139. }
  140. var vertices = mesh.vertices;
  141. var indices = mesh.indices;
  142. var encoding = mesh.encoding;
  143. var indicesLength = indices.length;
  144. var minT = Number.MAX_VALUE;
  145. for (var i = 0; i < indicesLength; i += 3) {
  146. var i0 = indices[i];
  147. var i1 = indices[i + 1];
  148. var i2 = indices[i + 2];
  149. var v0 = getPosition(encoding, mode, projection, vertices, i0, scratchV0);
  150. var v1 = getPosition(encoding, mode, projection, vertices, i1, scratchV1);
  151. var v2 = getPosition(encoding, mode, projection, vertices, i2, scratchV2);
  152. var t = IntersectionTests.rayTriangleParametric(
  153. ray,
  154. v0,
  155. v1,
  156. v2,
  157. cullBackFaces
  158. );
  159. if (defined(t) && t < minT && t >= 0.0) {
  160. minT = t;
  161. }
  162. }
  163. return minT !== Number.MAX_VALUE
  164. ? Ray.getPoint(ray, minT, result)
  165. : undefined;
  166. };
  167. GlobeSurfaceTile.prototype.freeResources = function () {
  168. if (defined(this.waterMaskTexture)) {
  169. --this.waterMaskTexture.referenceCount;
  170. if (this.waterMaskTexture.referenceCount === 0) {
  171. this.waterMaskTexture.destroy();
  172. }
  173. this.waterMaskTexture = undefined;
  174. }
  175. this.terrainData = undefined;
  176. this.terrainState = TerrainState.UNLOADED;
  177. this.mesh = undefined;
  178. this.fill = this.fill && this.fill.destroy();
  179. var imageryList = this.imagery;
  180. for (var i = 0, len = imageryList.length; i < len; ++i) {
  181. imageryList[i].freeResources();
  182. }
  183. this.imagery.length = 0;
  184. this.freeVertexArray();
  185. };
  186. GlobeSurfaceTile.prototype.freeVertexArray = function () {
  187. GlobeSurfaceTile._freeVertexArray(this.vertexArray);
  188. this.vertexArray = undefined;
  189. GlobeSurfaceTile._freeVertexArray(this.wireframeVertexArray);
  190. this.wireframeVertexArray = undefined;
  191. };
  192. GlobeSurfaceTile.initialize = function (
  193. tile,
  194. terrainProvider,
  195. imageryLayerCollection
  196. ) {
  197. var surfaceTile = tile.data;
  198. if (!defined(surfaceTile)) {
  199. surfaceTile = tile.data = new GlobeSurfaceTile();
  200. }
  201. if (tile.state === QuadtreeTileLoadState.START) {
  202. prepareNewTile(tile, terrainProvider, imageryLayerCollection);
  203. tile.state = QuadtreeTileLoadState.LOADING;
  204. }
  205. };
  206. GlobeSurfaceTile.processStateMachine = function (
  207. tile,
  208. frameState,
  209. terrainProvider,
  210. imageryLayerCollection,
  211. vertexArraysToDestroy,
  212. terrainOnly
  213. ) {
  214. GlobeSurfaceTile.initialize(tile, terrainProvider, imageryLayerCollection);
  215. var surfaceTile = tile.data;
  216. if (tile.state === QuadtreeTileLoadState.LOADING) {
  217. processTerrainStateMachine(
  218. tile,
  219. frameState,
  220. terrainProvider,
  221. imageryLayerCollection,
  222. vertexArraysToDestroy
  223. );
  224. }
  225. // From here down we're loading imagery, not terrain. We don't want to load imagery until
  226. // we're certain that the terrain tiles are actually visible, though. We'll load terrainOnly
  227. // in these scenarios:
  228. // * our bounding volume isn't accurate so we're not certain this tile is really visible (see GlobeSurfaceTileProvider#loadTile).
  229. // * we want to upsample from this tile but don't plan to render it (see processTerrainStateMachine).
  230. if (terrainOnly) {
  231. return;
  232. }
  233. var wasAlreadyRenderable = tile.renderable;
  234. // The terrain is renderable as soon as we have a valid vertex array.
  235. tile.renderable = defined(surfaceTile.vertexArray);
  236. // But it's not done loading until it's in the READY state.
  237. var isTerrainDoneLoading = surfaceTile.terrainState === TerrainState.READY;
  238. // If this tile's terrain and imagery are just upsampled from its parent, mark the tile as
  239. // upsampled only. We won't refine a tile if its four children are upsampled only.
  240. tile.upsampledFromParent =
  241. defined(surfaceTile.terrainData) &&
  242. surfaceTile.terrainData.wasCreatedByUpsampling();
  243. var isImageryDoneLoading = surfaceTile.processImagery(
  244. tile,
  245. terrainProvider,
  246. frameState
  247. );
  248. if (isTerrainDoneLoading && isImageryDoneLoading) {
  249. var callbacks = tile._loadedCallbacks;
  250. var newCallbacks = {};
  251. for (var layerId in callbacks) {
  252. if (callbacks.hasOwnProperty(layerId)) {
  253. if (!callbacks[layerId](tile)) {
  254. newCallbacks[layerId] = callbacks[layerId];
  255. }
  256. }
  257. }
  258. tile._loadedCallbacks = newCallbacks;
  259. tile.state = QuadtreeTileLoadState.DONE;
  260. }
  261. // Once a tile is renderable, it stays renderable, because doing otherwise would
  262. // cause detail (or maybe even the entire globe) to vanish when adding a new
  263. // imagery layer. `GlobeSurfaceTileProvider._onLayerAdded` sets renderable to
  264. // false for all affected tiles that are not currently being rendered.
  265. if (wasAlreadyRenderable) {
  266. tile.renderable = true;
  267. }
  268. };
  269. GlobeSurfaceTile.prototype.processImagery = function (
  270. tile,
  271. terrainProvider,
  272. frameState,
  273. skipLoading
  274. ) {
  275. var surfaceTile = tile.data;
  276. var isUpsampledOnly = tile.upsampledFromParent;
  277. var isAnyTileLoaded = false;
  278. var isDoneLoading = true;
  279. // Transition imagery states
  280. var tileImageryCollection = surfaceTile.imagery;
  281. var i, len;
  282. for (i = 0, len = tileImageryCollection.length; i < len; ++i) {
  283. var tileImagery = tileImageryCollection[i];
  284. if (!defined(tileImagery.loadingImagery)) {
  285. isUpsampledOnly = false;
  286. continue;
  287. }
  288. if (tileImagery.loadingImagery.state === ImageryState.PLACEHOLDER) {
  289. var imageryLayer = tileImagery.loadingImagery.imageryLayer;
  290. if (imageryLayer.imageryProvider.ready) {
  291. // Remove the placeholder and add the actual skeletons (if any)
  292. // at the same position. Then continue the loop at the same index.
  293. tileImagery.freeResources();
  294. tileImageryCollection.splice(i, 1);
  295. imageryLayer._createTileImagerySkeletons(tile, terrainProvider, i);
  296. --i;
  297. len = tileImageryCollection.length;
  298. continue;
  299. } else {
  300. isUpsampledOnly = false;
  301. }
  302. }
  303. var thisTileDoneLoading = tileImagery.processStateMachine(
  304. tile,
  305. frameState,
  306. skipLoading
  307. );
  308. isDoneLoading = isDoneLoading && thisTileDoneLoading;
  309. // The imagery is renderable as soon as we have any renderable imagery for this region.
  310. isAnyTileLoaded =
  311. isAnyTileLoaded ||
  312. thisTileDoneLoading ||
  313. defined(tileImagery.readyImagery);
  314. isUpsampledOnly =
  315. isUpsampledOnly &&
  316. defined(tileImagery.loadingImagery) &&
  317. (tileImagery.loadingImagery.state === ImageryState.FAILED ||
  318. tileImagery.loadingImagery.state === ImageryState.INVALID);
  319. }
  320. tile.upsampledFromParent = isUpsampledOnly;
  321. // Allow rendering if any available layers are loaded
  322. tile.renderable = tile.renderable && (isAnyTileLoaded || isDoneLoading);
  323. return isDoneLoading;
  324. };
  325. function prepareNewTile(tile, terrainProvider, imageryLayerCollection) {
  326. var available = terrainProvider.getTileDataAvailable(
  327. tile.x,
  328. tile.y,
  329. tile.level
  330. );
  331. if (!defined(available) && defined(tile.parent)) {
  332. // Provider doesn't know if this tile is available. Does the parent tile know?
  333. var parent = tile.parent;
  334. var parentSurfaceTile = parent.data;
  335. if (defined(parentSurfaceTile) && defined(parentSurfaceTile.terrainData)) {
  336. available = parentSurfaceTile.terrainData.isChildAvailable(
  337. parent.x,
  338. parent.y,
  339. tile.x,
  340. tile.y
  341. );
  342. }
  343. }
  344. if (available === false) {
  345. // This tile is not available, so mark it failed so we start upsampling right away.
  346. tile.data.terrainState = TerrainState.FAILED;
  347. }
  348. // Map imagery tiles to this terrain tile
  349. for (var i = 0, len = imageryLayerCollection.length; i < len; ++i) {
  350. var layer = imageryLayerCollection.get(i);
  351. if (layer.show) {
  352. layer._createTileImagerySkeletons(tile, terrainProvider);
  353. }
  354. }
  355. }
  356. function processTerrainStateMachine(
  357. tile,
  358. frameState,
  359. terrainProvider,
  360. imageryLayerCollection,
  361. vertexArraysToDestroy
  362. ) {
  363. var surfaceTile = tile.data;
  364. // If this tile is FAILED, we'll need to upsample from the parent. If the parent isn't
  365. // ready for that, let's push it along.
  366. var parent = tile.parent;
  367. if (
  368. surfaceTile.terrainState === TerrainState.FAILED &&
  369. parent !== undefined
  370. ) {
  371. var parentReady =
  372. parent.data !== undefined &&
  373. parent.data.terrainData !== undefined &&
  374. parent.data.terrainData.canUpsample !== false;
  375. if (!parentReady) {
  376. GlobeSurfaceTile.processStateMachine(
  377. parent,
  378. frameState,
  379. terrainProvider,
  380. imageryLayerCollection,
  381. true
  382. );
  383. }
  384. }
  385. if (surfaceTile.terrainState === TerrainState.FAILED) {
  386. upsample(
  387. surfaceTile,
  388. tile,
  389. frameState,
  390. terrainProvider,
  391. tile.x,
  392. tile.y,
  393. tile.level
  394. );
  395. }
  396. if (surfaceTile.terrainState === TerrainState.UNLOADED) {
  397. requestTileGeometry(
  398. surfaceTile,
  399. terrainProvider,
  400. tile.x,
  401. tile.y,
  402. tile.level
  403. );
  404. }
  405. if (surfaceTile.terrainState === TerrainState.RECEIVED) {
  406. transform(
  407. surfaceTile,
  408. frameState,
  409. terrainProvider,
  410. tile.x,
  411. tile.y,
  412. tile.level
  413. );
  414. }
  415. if (surfaceTile.terrainState === TerrainState.TRANSFORMED) {
  416. createResources(
  417. surfaceTile,
  418. frameState.context,
  419. terrainProvider,
  420. tile.x,
  421. tile.y,
  422. tile.level,
  423. vertexArraysToDestroy
  424. );
  425. }
  426. if (
  427. surfaceTile.terrainState >= TerrainState.RECEIVED &&
  428. surfaceTile.waterMaskTexture === undefined &&
  429. terrainProvider.hasWaterMask
  430. ) {
  431. var terrainData = surfaceTile.terrainData;
  432. if (terrainData.waterMask !== undefined) {
  433. createWaterMaskTextureIfNeeded(frameState.context, surfaceTile);
  434. } else {
  435. var sourceTile = surfaceTile._findAncestorTileWithTerrainData(tile);
  436. if (defined(sourceTile) && defined(sourceTile.data.waterMaskTexture)) {
  437. surfaceTile.waterMaskTexture = sourceTile.data.waterMaskTexture;
  438. ++surfaceTile.waterMaskTexture.referenceCount;
  439. surfaceTile._computeWaterMaskTranslationAndScale(
  440. tile,
  441. sourceTile,
  442. surfaceTile.waterMaskTranslationAndScale
  443. );
  444. }
  445. }
  446. }
  447. }
  448. function upsample(surfaceTile, tile, frameState, terrainProvider, x, y, level) {
  449. var parent = tile.parent;
  450. if (!parent) {
  451. // Trying to upsample from a root tile. No can do. This tile is a failure.
  452. tile.state = QuadtreeTileLoadState.FAILED;
  453. return;
  454. }
  455. var sourceData = parent.data.terrainData;
  456. var sourceX = parent.x;
  457. var sourceY = parent.y;
  458. var sourceLevel = parent.level;
  459. if (!defined(sourceData)) {
  460. // Parent is not available, so we can't upsample this tile yet.
  461. return;
  462. }
  463. var terrainDataPromise = sourceData.upsample(
  464. terrainProvider.tilingScheme,
  465. sourceX,
  466. sourceY,
  467. sourceLevel,
  468. x,
  469. y,
  470. level
  471. );
  472. if (!defined(terrainDataPromise)) {
  473. // The upsample request has been deferred - try again later.
  474. return;
  475. }
  476. surfaceTile.terrainState = TerrainState.RECEIVING;
  477. when(
  478. terrainDataPromise,
  479. function (terrainData) {
  480. surfaceTile.terrainData = terrainData;
  481. surfaceTile.terrainState = TerrainState.RECEIVED;
  482. },
  483. function () {
  484. surfaceTile.terrainState = TerrainState.FAILED;
  485. }
  486. );
  487. }
  488. function requestTileGeometry(surfaceTile, terrainProvider, x, y, level) {
  489. function success(terrainData) {
  490. surfaceTile.terrainData = terrainData;
  491. surfaceTile.terrainState = TerrainState.RECEIVED;
  492. surfaceTile.request = undefined;
  493. }
  494. function failure() {
  495. if (surfaceTile.request.state === RequestState.CANCELLED) {
  496. // Cancelled due to low priority - try again later.
  497. surfaceTile.terrainData = undefined;
  498. surfaceTile.terrainState = TerrainState.UNLOADED;
  499. surfaceTile.request = undefined;
  500. return;
  501. }
  502. // Initially assume failure. handleError may retry, in which case the state will
  503. // change to RECEIVING or UNLOADED.
  504. surfaceTile.terrainState = TerrainState.FAILED;
  505. surfaceTile.request = undefined;
  506. var message =
  507. "Failed to obtain terrain tile X: " +
  508. x +
  509. " Y: " +
  510. y +
  511. " Level: " +
  512. level +
  513. ".";
  514. terrainProvider._requestError = TileProviderError.handleError(
  515. terrainProvider._requestError,
  516. terrainProvider,
  517. terrainProvider.errorEvent,
  518. message,
  519. x,
  520. y,
  521. level,
  522. doRequest
  523. );
  524. }
  525. function doRequest() {
  526. // Request the terrain from the terrain provider.
  527. var request = new Request({
  528. throttle: false,
  529. throttleByServer: true,
  530. type: RequestType.TERRAIN,
  531. });
  532. surfaceTile.request = request;
  533. var requestPromise = terrainProvider.requestTileGeometry(
  534. x,
  535. y,
  536. level,
  537. request
  538. );
  539. // If the request method returns undefined (instead of a promise), the request
  540. // has been deferred.
  541. if (defined(requestPromise)) {
  542. surfaceTile.terrainState = TerrainState.RECEIVING;
  543. when(requestPromise, success, failure);
  544. } else {
  545. // Deferred - try again later.
  546. surfaceTile.terrainState = TerrainState.UNLOADED;
  547. surfaceTile.request = undefined;
  548. }
  549. }
  550. doRequest();
  551. }
  552. function transform(surfaceTile, frameState, terrainProvider, x, y, level) {
  553. var tilingScheme = terrainProvider.tilingScheme;
  554. var terrainData = surfaceTile.terrainData;
  555. var meshPromise = terrainData.createMesh(
  556. tilingScheme,
  557. x,
  558. y,
  559. level,
  560. frameState.terrainExaggeration
  561. );
  562. if (!defined(meshPromise)) {
  563. // Postponed.
  564. return;
  565. }
  566. surfaceTile.terrainState = TerrainState.TRANSFORMING;
  567. when(
  568. meshPromise,
  569. function (mesh) {
  570. surfaceTile.mesh = mesh;
  571. surfaceTile.orientedBoundingBox = OrientedBoundingBox.clone(
  572. mesh.orientedBoundingBox,
  573. surfaceTile.orientedBoundingBox
  574. );
  575. surfaceTile.occludeePointInScaledSpace = Cartesian3.clone(
  576. mesh.occludeePointInScaledSpace,
  577. surfaceTile.occludeePointInScaledSpace
  578. );
  579. surfaceTile.terrainState = TerrainState.TRANSFORMED;
  580. },
  581. function () {
  582. surfaceTile.terrainState = TerrainState.FAILED;
  583. }
  584. );
  585. }
  586. GlobeSurfaceTile._createVertexArrayForMesh = function (context, mesh) {
  587. var typedArray = mesh.vertices;
  588. var buffer = Buffer.createVertexBuffer({
  589. context: context,
  590. typedArray: typedArray,
  591. usage: BufferUsage.STATIC_DRAW,
  592. });
  593. var attributes = mesh.encoding.getAttributes(buffer);
  594. var indexBuffers = mesh.indices.indexBuffers || {};
  595. var indexBuffer = indexBuffers[context.id];
  596. if (!defined(indexBuffer) || indexBuffer.isDestroyed()) {
  597. var indices = mesh.indices;
  598. indexBuffer = Buffer.createIndexBuffer({
  599. context: context,
  600. typedArray: indices,
  601. usage: BufferUsage.STATIC_DRAW,
  602. indexDatatype: IndexDatatype.fromSizeInBytes(indices.BYTES_PER_ELEMENT),
  603. });
  604. indexBuffer.vertexArrayDestroyable = false;
  605. indexBuffer.referenceCount = 1;
  606. indexBuffers[context.id] = indexBuffer;
  607. mesh.indices.indexBuffers = indexBuffers;
  608. } else {
  609. ++indexBuffer.referenceCount;
  610. }
  611. return new VertexArray({
  612. context: context,
  613. attributes: attributes,
  614. indexBuffer: indexBuffer,
  615. });
  616. };
  617. GlobeSurfaceTile._freeVertexArray = function (vertexArray) {
  618. if (defined(vertexArray)) {
  619. var indexBuffer = vertexArray.indexBuffer;
  620. vertexArray.destroy();
  621. if (
  622. defined(indexBuffer) &&
  623. !indexBuffer.isDestroyed() &&
  624. defined(indexBuffer.referenceCount)
  625. ) {
  626. --indexBuffer.referenceCount;
  627. if (indexBuffer.referenceCount === 0) {
  628. indexBuffer.destroy();
  629. }
  630. }
  631. }
  632. };
  633. function createResources(
  634. surfaceTile,
  635. context,
  636. terrainProvider,
  637. x,
  638. y,
  639. level,
  640. vertexArraysToDestroy
  641. ) {
  642. surfaceTile.vertexArray = GlobeSurfaceTile._createVertexArrayForMesh(
  643. context,
  644. surfaceTile.mesh
  645. );
  646. surfaceTile.terrainState = TerrainState.READY;
  647. surfaceTile.fill =
  648. surfaceTile.fill && surfaceTile.fill.destroy(vertexArraysToDestroy);
  649. }
  650. function getContextWaterMaskData(context) {
  651. var data = context.cache.tile_waterMaskData;
  652. if (!defined(data)) {
  653. var allWaterTexture = Texture.create({
  654. context: context,
  655. pixelFormat: PixelFormat.LUMINANCE,
  656. pixelDatatype: PixelDatatype.UNSIGNED_BYTE,
  657. source: {
  658. arrayBufferView: new Uint8Array([255]),
  659. width: 1,
  660. height: 1,
  661. },
  662. });
  663. allWaterTexture.referenceCount = 1;
  664. var sampler = new Sampler({
  665. wrapS: TextureWrap.CLAMP_TO_EDGE,
  666. wrapT: TextureWrap.CLAMP_TO_EDGE,
  667. minificationFilter: TextureMinificationFilter.LINEAR,
  668. magnificationFilter: TextureMagnificationFilter.LINEAR,
  669. });
  670. data = {
  671. allWaterTexture: allWaterTexture,
  672. sampler: sampler,
  673. destroy: function () {
  674. this.allWaterTexture.destroy();
  675. },
  676. };
  677. context.cache.tile_waterMaskData = data;
  678. }
  679. return data;
  680. }
  681. function createWaterMaskTextureIfNeeded(context, surfaceTile) {
  682. var waterMask = surfaceTile.terrainData.waterMask;
  683. var waterMaskData = getContextWaterMaskData(context);
  684. var texture;
  685. var waterMaskLength = waterMask.length;
  686. if (waterMaskLength === 1) {
  687. // Length 1 means the tile is entirely land or entirely water.
  688. // A value of 0 indicates entirely land, a value of 1 indicates entirely water.
  689. if (waterMask[0] !== 0) {
  690. texture = waterMaskData.allWaterTexture;
  691. } else {
  692. // Leave the texture undefined if the tile is entirely land.
  693. return;
  694. }
  695. } else {
  696. var textureSize = Math.sqrt(waterMaskLength);
  697. texture = Texture.create({
  698. context: context,
  699. pixelFormat: PixelFormat.LUMINANCE,
  700. pixelDatatype: PixelDatatype.UNSIGNED_BYTE,
  701. source: {
  702. width: textureSize,
  703. height: textureSize,
  704. arrayBufferView: waterMask,
  705. },
  706. sampler: waterMaskData.sampler,
  707. flipY: false,
  708. });
  709. texture.referenceCount = 0;
  710. }
  711. ++texture.referenceCount;
  712. surfaceTile.waterMaskTexture = texture;
  713. Cartesian4.fromElements(
  714. 0.0,
  715. 0.0,
  716. 1.0,
  717. 1.0,
  718. surfaceTile.waterMaskTranslationAndScale
  719. );
  720. }
  721. GlobeSurfaceTile.prototype._findAncestorTileWithTerrainData = function (tile) {
  722. var sourceTile = tile.parent;
  723. while (
  724. defined(sourceTile) &&
  725. (!defined(sourceTile.data) ||
  726. !defined(sourceTile.data.terrainData) ||
  727. sourceTile.data.terrainData.wasCreatedByUpsampling())
  728. ) {
  729. sourceTile = sourceTile.parent;
  730. }
  731. return sourceTile;
  732. };
  733. GlobeSurfaceTile.prototype._computeWaterMaskTranslationAndScale = function (
  734. tile,
  735. sourceTile,
  736. result
  737. ) {
  738. var sourceTileRectangle = sourceTile.rectangle;
  739. var tileRectangle = tile.rectangle;
  740. var tileWidth = tileRectangle.width;
  741. var tileHeight = tileRectangle.height;
  742. var scaleX = tileWidth / sourceTileRectangle.width;
  743. var scaleY = tileHeight / sourceTileRectangle.height;
  744. result.x =
  745. (scaleX * (tileRectangle.west - sourceTileRectangle.west)) / tileWidth;
  746. result.y =
  747. (scaleY * (tileRectangle.south - sourceTileRectangle.south)) / tileHeight;
  748. result.z = scaleX;
  749. result.w = scaleY;
  750. return result;
  751. };
  752. export default GlobeSurfaceTile;