@cesium/engine 14.0.0 → 15.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. package/Build/Workers/{chunk-EWDGNOJE.js → chunk-25TOENEE.js} +7 -7
  2. package/Build/Workers/{chunk-OMXHEJTK.js → chunk-2AVIUB5H.js} +2 -2
  3. package/Build/Workers/{chunk-LJBJM6VI.js → chunk-3JZGPJMZ.js} +6 -6
  4. package/Build/Workers/{chunk-DT5NFR5C.js → chunk-3LHBH4TC.js} +7 -7
  5. package/Build/Workers/{chunk-3QLSKXKF.js → chunk-3LZF23RY.js} +6 -6
  6. package/Build/Workers/{chunk-ED6GLQTK.js → chunk-5S2B46UQ.js} +1 -1
  7. package/Build/Workers/{chunk-B4GSRXE3.js → chunk-67ONR44K.js} +6 -6
  8. package/Build/Workers/{chunk-LOZ4NKY3.js → chunk-6EDBC234.js} +11 -11
  9. package/Build/Workers/{chunk-7ZB2RVIQ.js → chunk-6EV4VOET.js} +10 -10
  10. package/Build/Workers/{chunk-KHWLAQVA.js → chunk-7ITUZTFH.js} +1 -1
  11. package/Build/Workers/{chunk-JHBPC4LK.js → chunk-ARVZCY6X.js} +7 -7
  12. package/Build/Workers/{chunk-FFBJDW4A.js → chunk-B2UQN3DH.js} +6 -6
  13. package/Build/Workers/{chunk-VCNOFQYH.js → chunk-B2Y4ZS6X.js} +9 -9
  14. package/Build/Workers/{chunk-Q4ZVWJXX.js → chunk-BD2TPFGC.js} +5 -5
  15. package/Build/Workers/{chunk-K4AH3TDT.js → chunk-CHX2K5AC.js} +10 -10
  16. package/Build/Workers/{chunk-3LYROPON.js → chunk-CJGVEABL.js} +13 -13
  17. package/Build/Workers/{chunk-KSYBJA4M.js → chunk-DYJHEP3B.js} +5 -5
  18. package/Build/Workers/{chunk-CI2HEJFC.js → chunk-E3H7AVMK.js} +13 -13
  19. package/Build/Workers/{chunk-F4CUH4MR.js → chunk-EZNAJPP5.js} +4 -4
  20. package/Build/Workers/{chunk-YJX7X577.js → chunk-F7ZI463G.js} +15 -15
  21. package/Build/Workers/{chunk-HEZHXDYB.js → chunk-FMZ5CX6V.js} +1 -1
  22. package/Build/Workers/{chunk-G3BVMPWG.js → chunk-FRAWHNSR.js} +2 -2
  23. package/Build/Workers/{chunk-J7IH4EYI.js → chunk-GGV2XJHE.js} +7 -7
  24. package/Build/Workers/{chunk-5KWRW7YL.js → chunk-GK4QU6QI.js} +2 -2
  25. package/Build/Workers/{chunk-77XPS7ZA.js → chunk-HYPB7FAV.js} +10 -10
  26. package/Build/Workers/{chunk-MVM4JV5U.js → chunk-I4HO2ED2.js} +9 -9
  27. package/Build/Workers/{chunk-FX4R4MTH.js → chunk-IGINOLDX.js} +6 -6
  28. package/Build/Workers/{chunk-PWF4EY5P.js → chunk-ISQSYLZY.js} +4 -4
  29. package/Build/Workers/{chunk-7UHKH6M3.js → chunk-JZAMRL5I.js} +6 -6
  30. package/Build/Workers/{chunk-HUFQVUMY.js → chunk-K5G2WELR.js} +7 -7
  31. package/Build/Workers/{chunk-5S5OOA6U.js → chunk-L5SO4Y5V.js} +1 -1
  32. package/Build/Workers/{chunk-LNSWJ43X.js → chunk-LCMJQVIF.js} +11 -11
  33. package/Build/Workers/{chunk-WVNLSTOF.js → chunk-MWJW37I7.js} +2 -2
  34. package/Build/Workers/{chunk-ZGFIT57T.js → chunk-NAGMYRDW.js} +27 -20
  35. package/Build/Workers/{chunk-SDIDRZDG.js → chunk-OYO6TKMU.js} +7 -7
  36. package/Build/Workers/{chunk-HKHQ3EDR.js → chunk-PUTA3AE2.js} +4 -4
  37. package/Build/Workers/{chunk-JPDKYBLF.js → chunk-Q5BHMNKU.js} +13 -13
  38. package/Build/Workers/{chunk-XK4OP6VA.js → chunk-QTEX3Y4V.js} +17 -17
  39. package/Build/Workers/{chunk-TVL3F7IU.js → chunk-QZKN2RXM.js} +1 -1
  40. package/Build/Workers/{chunk-Z3QWTHI7.js → chunk-RO2Z3LCR.js} +14 -14
  41. package/Build/Workers/{chunk-N2XAJBC6.js → chunk-RRN6LRDX.js} +12 -12
  42. package/Build/Workers/{chunk-FYGLNDKG.js → chunk-SLIA3GQP.js} +7 -7
  43. package/Build/Workers/{chunk-7EO56M5R.js → chunk-TFCOEX3W.js} +2 -2
  44. package/Build/Workers/{chunk-KM6MITPF.js → chunk-TU6ZXHVU.js} +5 -5
  45. package/Build/Workers/{chunk-LS3KVHYY.js → chunk-VJ2PDF64.js} +6 -6
  46. package/Build/Workers/{chunk-D7ZBZPHV.js → chunk-VMVPONIV.js} +5 -5
  47. package/Build/Workers/{chunk-3PIZQT3I.js → chunk-WPXU45PH.js} +4 -4
  48. package/Build/Workers/{chunk-WEHZP4SE.js → chunk-XDHM4G3P.js} +7 -7
  49. package/Build/Workers/{chunk-TY4DKOWR.js → chunk-XED3RXKO.js} +2 -2
  50. package/Build/Workers/{chunk-ZMNLEL6W.js → chunk-YNYCGTQH.js} +5 -5
  51. package/Build/Workers/{chunk-4CHMVQTQ.js → chunk-Z4SI54EB.js} +4 -4
  52. package/Build/Workers/{chunk-3JBEPBPL.js → chunk-ZVDLC3T4.js} +13 -13
  53. package/Build/Workers/combineGeometry.js +22 -22
  54. package/Build/Workers/createBoxGeometry.js +16 -16
  55. package/Build/Workers/createBoxOutlineGeometry.js +14 -14
  56. package/Build/Workers/createCircleGeometry.js +24 -24
  57. package/Build/Workers/createCircleOutlineGeometry.js +17 -17
  58. package/Build/Workers/createCoplanarPolygonGeometry.js +31 -31
  59. package/Build/Workers/createCoplanarPolygonOutlineGeometry.js +29 -29
  60. package/Build/Workers/createCorridorGeometry.js +27 -27
  61. package/Build/Workers/createCorridorOutlineGeometry.js +26 -26
  62. package/Build/Workers/createCylinderGeometry.js +18 -18
  63. package/Build/Workers/createCylinderOutlineGeometry.js +16 -16
  64. package/Build/Workers/createEllipseGeometry.js +24 -24
  65. package/Build/Workers/createEllipseOutlineGeometry.js +17 -17
  66. package/Build/Workers/createEllipsoidGeometry.js +17 -17
  67. package/Build/Workers/createEllipsoidOutlineGeometry.js +16 -16
  68. package/Build/Workers/createFrustumGeometry.js +16 -16
  69. package/Build/Workers/createFrustumOutlineGeometry.js +16 -16
  70. package/Build/Workers/createGeometry.js +22 -22
  71. package/Build/Workers/createGroundPolylineGeometry.js +20 -20
  72. package/Build/Workers/createPlaneGeometry.js +14 -14
  73. package/Build/Workers/createPlaneOutlineGeometry.js +13 -13
  74. package/Build/Workers/createPolygonGeometry.js +30 -30
  75. package/Build/Workers/createPolygonOutlineGeometry.js +28 -28
  76. package/Build/Workers/createPolylineGeometry.js +23 -23
  77. package/Build/Workers/createPolylineVolumeGeometry.js +29 -29
  78. package/Build/Workers/createPolylineVolumeOutlineGeometry.js +25 -25
  79. package/Build/Workers/createRectangleGeometry.js +25 -25
  80. package/Build/Workers/createRectangleOutlineGeometry.js +18 -18
  81. package/Build/Workers/createSimplePolylineGeometry.js +21 -21
  82. package/Build/Workers/createSphereGeometry.js +17 -17
  83. package/Build/Workers/createSphereOutlineGeometry.js +16 -16
  84. package/Build/Workers/createTaskProcessorWorker.js +3 -3
  85. package/Build/Workers/createVectorTileClampedPolylines.js +13 -13
  86. package/Build/Workers/createVectorTileGeometries.js +22 -22
  87. package/Build/Workers/createVectorTilePoints.js +12 -12
  88. package/Build/Workers/createVectorTilePolygons.js +20 -20
  89. package/Build/Workers/createVectorTilePolylines.js +13 -13
  90. package/Build/Workers/createVerticesFromGoogleEarthEnterpriseBuffer.js +20 -20
  91. package/Build/Workers/createVerticesFromHeightmap.js +20 -20
  92. package/Build/Workers/createVerticesFromQuantizedTerrainMesh.js +17 -17
  93. package/Build/Workers/createWallGeometry.js +22 -22
  94. package/Build/Workers/createWallOutlineGeometry.js +21 -21
  95. package/Build/Workers/decodeDraco.js +11 -11
  96. package/Build/Workers/decodeGoogleEarthEnterprisePacket.js +5 -5
  97. package/Build/Workers/decodeI3S.js +10 -10
  98. package/Build/Workers/transcodeKTX2.js +50 -43
  99. package/Build/Workers/transferTypedArrayTest.js +1 -1
  100. package/Build/Workers/upsampleQuantizedTerrainMesh.js +20 -20
  101. package/Source/Core/EllipsoidRhumbLine.js +1 -1
  102. package/Source/Core/Ion.js +1 -1
  103. package/Source/Core/PolygonGeometryLibrary.js +26 -4
  104. package/Source/Core/TexturePacker.js +166 -0
  105. package/Source/DataSources/BillboardVisualizer.js +3 -3
  106. package/Source/DataSources/EntityCluster.js +44 -19
  107. package/Source/Renderer/Context.js +0 -4
  108. package/Source/Renderer/Texture.js +6 -5
  109. package/Source/Renderer/TextureAtlas.js +802 -0
  110. package/Source/Scene/ArcGisMapService.js +1 -1
  111. package/Source/Scene/Billboard.js +86 -141
  112. package/Source/Scene/BillboardCollection.js +132 -202
  113. package/Source/Scene/BillboardLoadState.js +44 -0
  114. package/Source/Scene/BillboardTexture.js +348 -0
  115. package/Source/Scene/Camera.js +2 -2
  116. package/Source/Scene/Cesium3DTilesVoxelProvider.js +380 -126
  117. package/Source/Scene/Cesium3DTilesetStatistics.js +0 -1
  118. package/Source/Scene/Expression.js +1 -0
  119. package/Source/Scene/GltfLoader.js +5 -7
  120. package/Source/Scene/ImplicitSubtree.js +2 -0
  121. package/Source/Scene/KeyframeNode.js +16 -2
  122. package/Source/Scene/LabelCollection.js +212 -182
  123. package/Source/Scene/Megatexture.js +145 -81
  124. package/Source/Scene/Model/CustomShader.js +0 -2
  125. package/Source/Scene/Model/Model.js +1 -1
  126. package/Source/Scene/Model/ModelUtility.js +5 -1
  127. package/Source/Scene/Scene.js +39 -15
  128. package/Source/Scene/ScreenSpaceCameraController.js +0 -8
  129. package/Source/Scene/SpatialNode.js +4 -11
  130. package/Source/Scene/Vector3DTilePoints.js +2 -5
  131. package/Source/Scene/VoxelBoxShape.js +12 -5
  132. package/Source/Scene/VoxelCell.js +6 -5
  133. package/Source/Scene/VoxelContent.js +171 -107
  134. package/Source/Scene/VoxelCylinderShape.js +65 -58
  135. package/Source/Scene/VoxelEllipsoidShape.js +15 -5
  136. package/Source/Scene/VoxelMetadataOrder.js +12 -0
  137. package/Source/Scene/VoxelPrimitive.js +122 -54
  138. package/Source/Scene/VoxelProvider.js +34 -29
  139. package/Source/Scene/VoxelRenderResources.js +30 -7
  140. package/Source/Scene/VoxelShape.js +10 -3
  141. package/Source/Scene/VoxelTraversal.js +264 -180
  142. package/Source/Scene/processVoxelProperties.js +3 -0
  143. package/Source/Shaders/GlobeFS.glsl +10 -1
  144. package/Source/Shaders/GlobeFS.js +10 -1
  145. package/Source/Shaders/Voxels/Megatexture.glsl +4 -16
  146. package/Source/Shaders/Voxels/Megatexture.js +4 -16
  147. package/Source/Shaders/Voxels/Octree.glsl +44 -7
  148. package/Source/Shaders/Voxels/Octree.js +44 -7
  149. package/Source/Shaders/Voxels/VoxelFS.glsl +9 -15
  150. package/Source/Shaders/Voxels/VoxelFS.js +9 -15
  151. package/Source/Shaders/Voxels/convertUvToCylinder.glsl +15 -15
  152. package/Source/Shaders/Voxels/convertUvToCylinder.js +15 -15
  153. package/index.d.ts +176 -79
  154. package/index.js +413 -409
  155. package/package.json +2 -2
  156. package/Source/Scene/TextureAtlas.js +0 -558
@@ -183,6 +183,7 @@ ImplicitSubtree.prototype.tileIsAvailableAtIndex = function (index) {
183
183
 
184
184
  /**
185
185
  * Check if a specific tile is available at an implicit tile coordinate
186
+ * NOTE: only used for voxels.
186
187
  *
187
188
  * @param {ImplicitTileCoordinates} implicitCoordinates The global coordinates of a tile
188
189
  * @returns {boolean} The value of the i-th bit
@@ -249,6 +250,7 @@ ImplicitSubtree.prototype.childSubtreeIsAvailableAtIndex = function (index) {
249
250
 
250
251
  /**
251
252
  * Check if a specific child subtree is available at an implicit tile coordinate
253
+ * NOTE: only used for voxels.
252
254
  *
253
255
  * @param {ImplicitTileCoordinates} implicitCoordinates The global coordinates of a child subtree
254
256
  * @returns {boolean} The value of the i-th bit
@@ -1,7 +1,7 @@
1
1
  const LoadState = Object.freeze({
2
2
  UNLOADED: 0, // Has no data and is in dormant state
3
3
  RECEIVING: 1, // Is waiting on data from the provider
4
- RECEIVED: 2, // Received data from the provider
4
+ PROCESSING: 2, // Data received. Contents are being processed for rendering. Depending on the content, it might make its own requests for external data.
5
5
  LOADED: 3, // Processed data from provider
6
6
  FAILED: 4, // Failed to receive data from the provider
7
7
  UNAVAILABLE: 5, // No data available for this tile
@@ -20,12 +20,26 @@ function KeyframeNode(spatialNode, keyframe) {
20
20
  this.spatialNode = spatialNode;
21
21
  this.keyframe = keyframe;
22
22
  this.state = LoadState.UNLOADED;
23
- this.metadata = [];
23
+ this.content = undefined;
24
24
  this.megatextureIndex = -1;
25
25
  this.priority = -Number.MAX_VALUE;
26
26
  this.highPriorityFrameNumber = -1;
27
27
  }
28
28
 
29
+ /**
30
+ * Frees the resources used by this object.
31
+ * @private
32
+ */
33
+ KeyframeNode.prototype.unload = function () {
34
+ this.content = this.content && this.content.destroy();
35
+
36
+ this.spatialNode = undefined;
37
+ this.state = LoadState.UNLOADED;
38
+ this.megatextureIndex = -1;
39
+ this.priority = -Number.MAX_VALUE;
40
+ this.highPriorityFrameNumber = -1;
41
+ };
42
+
29
43
  /**
30
44
  * @param {KeyframeNode} a
31
45
  * @param {KeyframeNode} b
@@ -9,34 +9,43 @@ import Matrix4 from "../Core/Matrix4.js";
9
9
  import writeTextToCanvas from "../Core/writeTextToCanvas.js";
10
10
  import bitmapSDF from "bitmap-sdf";
11
11
  import BillboardCollection from "./BillboardCollection.js";
12
+ import BillboardTexture from "./BillboardTexture.js";
12
13
  import BlendOption from "./BlendOption.js";
13
14
  import { isHeightReferenceClamp } from "./HeightReference.js";
14
15
  import HorizontalOrigin from "./HorizontalOrigin.js";
15
16
  import Label from "./Label.js";
16
17
  import LabelStyle from "./LabelStyle.js";
17
18
  import SDFSettings from "./SDFSettings.js";
18
- import TextureAtlas from "./TextureAtlas.js";
19
+ import TextureAtlas from "../Renderer/TextureAtlas.js";
19
20
  import VerticalOrigin from "./VerticalOrigin.js";
20
21
  import GraphemeSplitter from "grapheme-splitter";
21
22
 
22
- // A glyph represents a single character in a particular label. It may or may
23
- // not have a billboard, depending on whether the texture info has an index into
24
- // the the label collection's texture atlas. Invisible characters have no texture, and
25
- // no billboard. However, it always has a valid dimensions object.
23
+ /**
24
+ * A glyph represents a single character in label.
25
+ * @private
26
+ */
26
27
  function Glyph() {
27
- this.textureInfo = undefined;
28
+ /**
29
+ * Object containing dimensions of the character as rendered to a canvas.
30
+ * @see {writeTextToCanvas}
31
+ * @type {object}
32
+ * @private
33
+ */
28
34
  this.dimensions = undefined;
29
- this.billboard = undefined;
30
- }
31
35
 
32
- // GlyphTextureInfo represents a single character, drawn in a particular style,
33
- // shared and reference counted across all labels. It may or may not have an
34
- // index into the label collection's texture atlas, depending on whether the character
35
- // has both width and height, but it always has a valid dimensions object.
36
- function GlyphTextureInfo(labelCollection, index, dimensions) {
37
- this.labelCollection = labelCollection;
38
- this.index = index;
39
- this.dimensions = dimensions;
36
+ /**
37
+ * Reference to loaded image data for a single character, drawn in a particular style, shared and referenced across all labels.
38
+ * @type {BillboardTexture}
39
+ * @private
40
+ */
41
+ this.billboardTexture = undefined;
42
+
43
+ /**
44
+ * The individual billboard used to render the glyph. This may be <code>undefined</code> if the associated character is whitespace.
45
+ * @type {Billboard|undefined}
46
+ * @private
47
+ */
48
+ this.billboard = undefined;
40
49
  }
41
50
 
42
51
  // Traditionally, leading is %20 of the font size.
@@ -45,18 +54,38 @@ const whitePixelCanvasId = "ID_WHITE_PIXEL";
45
54
  const whitePixelSize = new Cartesian2(4, 4);
46
55
  const whitePixelBoundingRegion = new BoundingRectangle(1, 1, 1, 1);
47
56
 
48
- function addWhitePixelCanvas(textureAtlas) {
49
- const canvas = document.createElement("canvas");
50
- canvas.width = whitePixelSize.x;
51
- canvas.height = whitePixelSize.y;
57
+ /**
58
+ * Create the background image and start loading it into a texture
59
+ * @private
60
+ * @param {BillboardCollection} billboardCollection
61
+ * @param {LabelCollection} labelCollection
62
+ * @returns {Billboard}
63
+ */
64
+ function getWhitePixelBillboard(billboardCollection, labelCollection) {
65
+ const billboardTexture = labelCollection._backgroundBillboardTexture;
66
+ if (!billboardTexture.hasImage) {
67
+ const canvas = document.createElement("canvas");
68
+ canvas.width = whitePixelSize.x;
69
+ canvas.height = whitePixelSize.y;
70
+
71
+ const context2D = canvas.getContext("2d");
72
+ context2D.fillStyle = "#fff";
73
+ context2D.fillRect(0, 0, canvas.width, canvas.height);
74
+
75
+ billboardTexture.loadImage(whitePixelCanvasId, canvas);
76
+ billboardTexture.addImageSubRegion(
77
+ whitePixelCanvasId,
78
+ whitePixelBoundingRegion,
79
+ );
80
+ }
81
+
82
+ const billboard = billboardCollection.add({
83
+ collection: labelCollection,
84
+ });
52
85
 
53
- const context2D = canvas.getContext("2d");
54
- context2D.fillStyle = "#fff";
55
- context2D.fillRect(0, 0, canvas.width, canvas.height);
86
+ billboard.setImageTexture(billboardTexture);
56
87
 
57
- // Canvas operations take a frame to draw. Use the asynchronous add function which resolves a promise and allows the draw to complete,
58
- // but there's no need to wait on the promise before operation can continue
59
- return textureAtlas.addImage(whitePixelCanvasId, canvas);
88
+ return billboard;
60
89
  }
61
90
 
62
91
  // reusable object for calling writeTextToCanvas
@@ -85,14 +114,10 @@ function createGlyphCanvas(
85
114
  return writeTextToCanvas(character, writeTextToCanvasParameters);
86
115
  }
87
116
 
88
- function unbindGlyph(labelCollection, glyph) {
89
- glyph.textureInfo = undefined;
90
- glyph.dimensions = undefined;
91
-
117
+ function unbindGlyphBillboard(labelCollection, glyph) {
92
118
  const billboard = glyph.billboard;
93
119
  if (defined(billboard)) {
94
120
  billboard.show = false;
95
- billboard.image = undefined;
96
121
  if (defined(billboard._removeCallbackFunc)) {
97
122
  billboard._removeCallbackFunc();
98
123
  billboard._removeCallbackFunc = undefined;
@@ -102,11 +127,8 @@ function unbindGlyph(labelCollection, glyph) {
102
127
  }
103
128
  }
104
129
 
105
- function addGlyphToTextureAtlas(textureAtlas, id, canvas, glyphTextureInfo) {
106
- glyphTextureInfo.index = textureAtlas.addImageSync(id, canvas);
107
- }
108
-
109
130
  const splitter = new GraphemeSplitter();
131
+ const whitespaceRegex = /\s/;
110
132
 
111
133
  function rebindAllGlyphs(labelCollection, label) {
112
134
  const text = label._renderedText;
@@ -115,17 +137,13 @@ function rebindAllGlyphs(labelCollection, label) {
115
137
  const glyphs = label._glyphs;
116
138
  const glyphsLength = glyphs.length;
117
139
 
118
- let glyph;
119
- let glyphIndex;
120
- let textIndex;
121
-
122
140
  // Compute a font size scale relative to the sdf font generated size.
123
141
  label._relativeSize = label._fontSize / SDFSettings.FONT_SIZE;
124
142
 
125
143
  // if we have more glyphs than needed, unbind the extras.
126
144
  if (textLength < glyphsLength) {
127
- for (glyphIndex = textLength; glyphIndex < glyphsLength; ++glyphIndex) {
128
- unbindGlyph(labelCollection, glyphs[glyphIndex]);
145
+ for (let glyphIndex = textLength; glyphIndex < glyphsLength; ++glyphIndex) {
146
+ unbindGlyphBillboard(labelCollection, glyphs[glyphIndex]);
129
147
  }
130
148
  }
131
149
 
@@ -144,11 +162,10 @@ function rebindAllGlyphs(labelCollection, label) {
144
162
  }
145
163
  } else {
146
164
  if (!defined(backgroundBillboard)) {
147
- backgroundBillboard = backgroundBillboardCollection.add({
148
- collection: labelCollection,
149
- image: whitePixelCanvasId,
150
- imageSubRegion: whitePixelBoundingRegion,
151
- });
165
+ backgroundBillboard = getWhitePixelBillboard(
166
+ backgroundBillboardCollection,
167
+ labelCollection,
168
+ );
152
169
  label._backgroundBillboard = backgroundBillboard;
153
170
  }
154
171
 
@@ -174,11 +191,13 @@ function rebindAllGlyphs(labelCollection, label) {
174
191
  backgroundBillboard.clusterShow = label.clusterShow;
175
192
  }
176
193
 
177
- const glyphTextureCache = labelCollection._glyphTextureCache;
194
+ const glyphBillboardCollection = labelCollection._glyphBillboardCollection;
195
+ const glyphTextureCache = glyphBillboardCollection.billboardTextureCache;
196
+ const textDimensionsCache = labelCollection._textDimensionsCache;
178
197
 
179
198
  // walk the text looking for new characters (creating new glyphs for each)
180
199
  // or changed characters (rebinding existing glyphs)
181
- for (textIndex = 0; textIndex < textLength; ++textIndex) {
200
+ for (let textIndex = 0; textIndex < textLength; ++textIndex) {
182
201
  const character = graphemes[textIndex];
183
202
  const verticalOrigin = label._verticalOrigin;
184
203
 
@@ -190,8 +209,12 @@ function rebindAllGlyphs(labelCollection, label) {
190
209
  +verticalOrigin,
191
210
  ]);
192
211
 
193
- let glyphTextureInfo = glyphTextureCache[id];
194
- if (!defined(glyphTextureInfo)) {
212
+ let dimensions = textDimensionsCache[id];
213
+ let glyphBillboardTexture = glyphTextureCache.get(id);
214
+ if (!defined(glyphBillboardTexture) || !defined(dimensions)) {
215
+ glyphBillboardTexture = new BillboardTexture(glyphBillboardCollection);
216
+ glyphTextureCache.set(id, glyphBillboardTexture);
217
+
195
218
  const glyphFont = `${label._fontStyle} ${label._fontWeight} ${SDFSettings.FONT_SIZE}px ${label._fontFamily}`;
196
219
 
197
220
  const canvas = createGlyphCanvas(
@@ -203,14 +226,14 @@ function rebindAllGlyphs(labelCollection, label) {
203
226
  LabelStyle.FILL,
204
227
  );
205
228
 
206
- glyphTextureInfo = new GlyphTextureInfo(
207
- labelCollection,
208
- -1,
209
- canvas.dimensions,
210
- );
211
- glyphTextureCache[id] = glyphTextureInfo;
229
+ dimensions = canvas.dimensions;
230
+ textDimensionsCache[id] = dimensions;
212
231
 
213
- if (canvas.width > 0 && canvas.height > 0) {
232
+ if (
233
+ canvas.width > 0 &&
234
+ canvas.height > 0 &&
235
+ !whitespaceRegex.test(character)
236
+ ) {
214
237
  const sdfValues = bitmapSDF(canvas, {
215
238
  cutoff: SDFSettings.CUTOFF,
216
239
  radius: SDFSettings.RADIUS,
@@ -233,84 +256,76 @@ function rebindAllGlyphs(labelCollection, label) {
233
256
  }
234
257
  }
235
258
  ctx.putImageData(imgData, 0, 0);
236
- if (character !== " ") {
237
- addGlyphToTextureAtlas(
238
- labelCollection._textureAtlas,
239
- id,
240
- canvas,
241
- glyphTextureInfo,
242
- );
243
- }
259
+ glyphBillboardTexture.loadImage(id, canvas);
244
260
  }
245
261
  }
246
262
 
247
- glyph = glyphs[textIndex];
248
-
249
- if (defined(glyph)) {
250
- // clean up leftover information from the previous glyph
251
- if (glyphTextureInfo.index === -1) {
252
- // no texture, and therefore no billboard, for this glyph.
253
- // so, completely unbind glyph.
254
- unbindGlyph(labelCollection, glyph);
255
- } else if (defined(glyph.textureInfo)) {
256
- // we have a texture and billboard. If we had one before, release
257
- // our reference to that texture info, but reuse the billboard.
258
- glyph.textureInfo = undefined;
259
- }
260
- } else {
261
- // create a glyph object
263
+ let glyph = glyphs[textIndex];
264
+ if (!defined(glyph)) {
262
265
  glyph = new Glyph();
266
+ glyph.dimensions = dimensions;
267
+ glyph.billboardTexture = glyphBillboardTexture;
263
268
  glyphs[textIndex] = glyph;
264
269
  }
265
270
 
266
- glyph.textureInfo = glyphTextureInfo;
267
- glyph.dimensions = glyphTextureInfo.dimensions;
268
-
269
- // if we have a texture, configure the existing billboard, or obtain one
270
- if (glyphTextureInfo.index !== -1) {
271
- let billboard = glyph.billboard;
272
- const spareBillboards = labelCollection._spareBillboards;
273
- if (!defined(billboard)) {
274
- if (spareBillboards.length > 0) {
275
- billboard = spareBillboards.pop();
276
- } else {
277
- billboard = labelCollection._billboardCollection.add({
278
- collection: labelCollection,
279
- });
280
- billboard._labelDimensions = new Cartesian2();
281
- billboard._labelTranslate = new Cartesian2();
282
- }
283
- glyph.billboard = billboard;
284
- }
271
+ if (glyph.billboardTexture.id !== id) {
272
+ // This glyph has been mapped to a new texture. If we had one before, release
273
+ // our reference to that texture and dimensions, but reuse the billboard.
274
+ glyph.billboardTexture = glyphBillboardTexture;
275
+ glyph.dimensions = dimensions;
276
+ }
277
+
278
+ if (!glyphBillboardTexture.hasImage) {
279
+ // No texture, and therefore no billboard, for this glyph.
280
+ // so, completely unbind glyph to free up the billboard for others
281
+ unbindGlyphBillboard(labelCollection, glyph);
282
+ continue;
283
+ }
285
284
 
286
- billboard.show = label._show;
287
- billboard.position = label._position;
288
- billboard.eyeOffset = label._eyeOffset;
289
- billboard.pixelOffset = label._pixelOffset;
290
- billboard.horizontalOrigin = HorizontalOrigin.LEFT;
291
- billboard.verticalOrigin = label._verticalOrigin;
292
- billboard.heightReference = label._heightReference;
293
- billboard.scale = label.totalScale;
294
- billboard.pickPrimitive = label;
295
- billboard.id = label._id;
296
- billboard.image = id;
297
- billboard.translucencyByDistance = label._translucencyByDistance;
298
- billboard.pixelOffsetScaleByDistance = label._pixelOffsetScaleByDistance;
299
- billboard.scaleByDistance = label._scaleByDistance;
300
- billboard.distanceDisplayCondition = label._distanceDisplayCondition;
301
- billboard.disableDepthTestDistance = label._disableDepthTestDistance;
302
- billboard._batchIndex = label._batchIndex;
303
- billboard.outlineColor = label.outlineColor;
304
- if (label.style === LabelStyle.FILL_AND_OUTLINE) {
305
- billboard.color = label._fillColor;
306
- billboard.outlineWidth = label.outlineWidth;
307
- } else if (label.style === LabelStyle.FILL) {
308
- billboard.color = label._fillColor;
309
- billboard.outlineWidth = 0.0;
310
- } else if (label.style === LabelStyle.OUTLINE) {
311
- billboard.color = Color.TRANSPARENT;
312
- billboard.outlineWidth = label.outlineWidth;
285
+ // If we have a texture, configure the existing billboard, or obtain one
286
+ let billboard = glyph.billboard;
287
+ const spareBillboards = labelCollection._spareBillboards;
288
+ if (!defined(billboard)) {
289
+ if (spareBillboards.length > 0) {
290
+ billboard = spareBillboards.pop();
291
+ } else {
292
+ billboard = glyphBillboardCollection.add({
293
+ collection: labelCollection,
294
+ });
295
+ billboard._labelDimensions = new Cartesian2();
296
+ billboard._labelTranslate = new Cartesian2();
313
297
  }
298
+ glyph.billboard = billboard;
299
+ }
300
+
301
+ billboard.setImageTexture(glyphBillboardTexture);
302
+
303
+ billboard.show = label._show;
304
+ billboard.position = label._position;
305
+ billboard.eyeOffset = label._eyeOffset;
306
+ billboard.pixelOffset = label._pixelOffset;
307
+ billboard.horizontalOrigin = HorizontalOrigin.LEFT;
308
+ billboard.verticalOrigin = label._verticalOrigin;
309
+ billboard.heightReference = label._heightReference;
310
+ billboard.scale = label.totalScale;
311
+ billboard.pickPrimitive = label;
312
+ billboard.id = label._id;
313
+ billboard.translucencyByDistance = label._translucencyByDistance;
314
+ billboard.pixelOffsetScaleByDistance = label._pixelOffsetScaleByDistance;
315
+ billboard.scaleByDistance = label._scaleByDistance;
316
+ billboard.distanceDisplayCondition = label._distanceDisplayCondition;
317
+ billboard.disableDepthTestDistance = label._disableDepthTestDistance;
318
+ billboard._batchIndex = label._batchIndex;
319
+ billboard.outlineColor = label.outlineColor;
320
+ if (label.style === LabelStyle.FILL_AND_OUTLINE) {
321
+ billboard.color = label._fillColor;
322
+ billboard.outlineWidth = label.outlineWidth;
323
+ } else if (label.style === LabelStyle.FILL) {
324
+ billboard.color = label._fillColor;
325
+ billboard.outlineWidth = 0.0;
326
+ } else if (label.style === LabelStyle.OUTLINE) {
327
+ billboard.color = Color.TRANSPARENT;
328
+ billboard.outlineWidth = label.outlineWidth;
314
329
  }
315
330
  }
316
331
 
@@ -335,15 +350,12 @@ const scratchBackgroundPadding = new Cartesian2();
335
350
  function repositionAllGlyphs(label) {
336
351
  const glyphs = label._glyphs;
337
352
  const text = label._renderedText;
338
- let glyph;
339
- let dimensions;
340
353
  let lastLineWidth = 0;
341
354
  let maxLineWidth = 0;
342
355
  const lineWidths = [];
343
356
  let maxGlyphDescent = Number.NEGATIVE_INFINITY;
344
357
  let maxGlyphY = 0;
345
358
  let numberOfLines = 1;
346
- let glyphIndex;
347
359
  const glyphLength = glyphs.length;
348
360
 
349
361
  const backgroundBillboard = label._backgroundBillboard;
@@ -356,18 +368,21 @@ function repositionAllGlyphs(label) {
356
368
  backgroundPadding.x /= label._relativeSize;
357
369
  backgroundPadding.y /= label._relativeSize;
358
370
 
359
- for (glyphIndex = 0; glyphIndex < glyphLength; ++glyphIndex) {
371
+ for (let glyphIndex = 0; glyphIndex < glyphLength; ++glyphIndex) {
360
372
  if (text.charAt(glyphIndex) === "\n") {
361
373
  lineWidths.push(lastLineWidth);
362
374
  ++numberOfLines;
363
375
  lastLineWidth = 0;
364
- } else {
365
- glyph = glyphs[glyphIndex];
366
- dimensions = glyph.dimensions;
376
+ continue;
377
+ }
378
+
379
+ const glyph = glyphs[glyphIndex];
380
+ const dimensions = glyph.dimensions;
381
+ if (defined(dimensions)) {
367
382
  maxGlyphY = Math.max(maxGlyphY, dimensions.height - dimensions.descent);
368
383
  maxGlyphDescent = Math.max(maxGlyphDescent, dimensions.descent);
369
384
 
370
- //Computing the line width must also account for the kerning that occurs between letters.
385
+ // Computing the line width must also account for the kerning that occurs between letters.
371
386
  lastLineWidth += dimensions.width - dimensions.minx;
372
387
  if (glyphIndex < glyphLength - 1) {
373
388
  lastLineWidth += glyphs[glyphIndex + 1].dimensions.minx;
@@ -408,7 +423,7 @@ function repositionAllGlyphs(label) {
408
423
  let firstCharOfLine = true;
409
424
 
410
425
  let lineOffsetY = 0;
411
- for (glyphIndex = 0; glyphIndex < glyphLength; ++glyphIndex) {
426
+ for (let glyphIndex = 0; glyphIndex < glyphLength; ++glyphIndex) {
412
427
  if (text.charAt(glyphIndex) === "\n") {
413
428
  ++lineIndex;
414
429
  lineOffsetY += lineSpacing;
@@ -420,10 +435,12 @@ function repositionAllGlyphs(label) {
420
435
  );
421
436
  glyphPixelOffset.x = widthOffset * scale;
422
437
  firstCharOfLine = true;
423
- } else {
424
- glyph = glyphs[glyphIndex];
425
- dimensions = glyph.dimensions;
438
+ continue;
439
+ }
426
440
 
441
+ const glyph = glyphs[glyphIndex];
442
+ const dimensions = glyph.dimensions;
443
+ if (defined(dimensions)) {
427
444
  if (verticalOrigin === VerticalOrigin.TOP) {
428
445
  glyphPixelOffset.y =
429
446
  dimensions.height - maxGlyphY - backgroundPadding.y;
@@ -500,8 +517,8 @@ function repositionAllGlyphs(label) {
500
517
  }
501
518
 
502
519
  if (isHeightReferenceClamp(label.heightReference)) {
503
- for (glyphIndex = 0; glyphIndex < glyphLength; ++glyphIndex) {
504
- glyph = glyphs[glyphIndex];
520
+ for (let glyphIndex = 0; glyphIndex < glyphLength; ++glyphIndex) {
521
+ const glyph = glyphs[glyphIndex];
505
522
  const billboard = glyph.billboard;
506
523
  if (defined(billboard)) {
507
524
  billboard._labelTranslate = Cartesian2.clone(
@@ -516,7 +533,7 @@ function repositionAllGlyphs(label) {
516
533
  function destroyLabel(labelCollection, label) {
517
534
  const glyphs = label._glyphs;
518
535
  for (let i = 0, len = glyphs.length; i < len; ++i) {
519
- unbindGlyph(labelCollection, glyphs[i]);
536
+ unbindGlyphBillboard(labelCollection, glyphs[i]);
520
537
  }
521
538
  if (defined(label._backgroundBillboard)) {
522
539
  labelCollection._backgroundBillboardCollection.remove(
@@ -587,23 +604,25 @@ function LabelCollection(options) {
587
604
  this._scene = options.scene;
588
605
  this._batchTable = options.batchTable;
589
606
 
590
- this._textureAtlas = undefined;
591
- this._backgroundTextureAtlas = undefined;
592
-
593
- this._backgroundBillboardCollection = new BillboardCollection({
607
+ const backgroundBillboardCollection = new BillboardCollection({
594
608
  scene: this._scene,
609
+ textureAtlas: new TextureAtlas({
610
+ initialSize: whitePixelSize,
611
+ }),
595
612
  });
596
- this._backgroundBillboardCollection.destroyTextureAtlas = false;
613
+ this._backgroundBillboardCollection = backgroundBillboardCollection;
614
+ this._backgroundBillboardTexture = new BillboardTexture(
615
+ backgroundBillboardCollection,
616
+ );
597
617
 
598
- this._billboardCollection = new BillboardCollection({
618
+ this._glyphBillboardCollection = new BillboardCollection({
599
619
  scene: this._scene,
600
620
  batchTable: this._batchTable,
601
621
  });
602
- this._billboardCollection.destroyTextureAtlas = false;
603
- this._billboardCollection._sdf = true;
622
+ this._glyphBillboardCollection._sdf = true;
604
623
 
605
624
  this._spareBillboards = [];
606
- this._glyphTextureCache = {};
625
+ this._textDimensionsCache = {};
607
626
  this._labels = [];
608
627
  this._labelsToUpdate = [];
609
628
  this._totalGlyphCount = 0;
@@ -687,12 +706,47 @@ Object.defineProperties(LabelCollection.prototype, {
687
706
  * in the collection.
688
707
  * @memberof LabelCollection.prototype
689
708
  * @type {number}
709
+ * @readonly
690
710
  */
691
711
  length: {
692
712
  get: function () {
693
713
  return this._labels.length;
694
714
  },
695
715
  },
716
+
717
+ /**
718
+ * Returns the size in bytes of the WebGL texture resources.
719
+ * @private
720
+ * @memberof LabelCollection.prototype
721
+ * @type {number}
722
+ * @readonly
723
+ */
724
+ sizeInBytes: {
725
+ get: function () {
726
+ return (
727
+ this._glyphBillboardCollection.sizeInBytes +
728
+ this._backgroundBillboardCollection.sizeInBytes
729
+ );
730
+ },
731
+ },
732
+
733
+ /**
734
+ * True when all labels currently in the collection are ready for rendering.
735
+ * @private
736
+ * @memberof LabelCollection.prototype
737
+ * @type {boolean}
738
+ * @readonly
739
+ */
740
+ ready: {
741
+ get: function () {
742
+ const backgroundBillboard = this._backgroundBillboardCollection.get(0);
743
+ if (defined(backgroundBillboard) && !backgroundBillboard.ready) {
744
+ return false;
745
+ }
746
+
747
+ return this._glyphBillboardCollection.ready;
748
+ },
749
+ },
696
750
  });
697
751
 
698
752
  /**
@@ -709,7 +763,6 @@ Object.defineProperties(LabelCollection.prototype, {
709
763
  *
710
764
  * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
711
765
  *
712
- *
713
766
  * @example
714
767
  * // Example 1: Add a label, specifying all the default values.
715
768
  * const l = labels.add({
@@ -872,42 +925,22 @@ LabelCollection.prototype.get = function (index) {
872
925
 
873
926
  /**
874
927
  * @private
875
- *
876
928
  */
877
929
  LabelCollection.prototype.update = function (frameState) {
878
930
  if (!this.show) {
879
931
  return;
880
932
  }
881
933
 
882
- const billboardCollection = this._billboardCollection;
934
+ const glyphBillboardCollection = this._glyphBillboardCollection;
883
935
  const backgroundBillboardCollection = this._backgroundBillboardCollection;
884
936
 
885
- billboardCollection.modelMatrix = this.modelMatrix;
886
- billboardCollection.debugShowBoundingVolume = this.debugShowBoundingVolume;
937
+ glyphBillboardCollection.modelMatrix = this.modelMatrix;
938
+ glyphBillboardCollection.debugShowBoundingVolume =
939
+ this.debugShowBoundingVolume;
887
940
  backgroundBillboardCollection.modelMatrix = this.modelMatrix;
888
941
  backgroundBillboardCollection.debugShowBoundingVolume =
889
942
  this.debugShowBoundingVolume;
890
943
 
891
- const context = frameState.context;
892
-
893
- if (!defined(this._textureAtlas)) {
894
- this._textureAtlas = new TextureAtlas({
895
- context: context,
896
- });
897
- billboardCollection.textureAtlas = this._textureAtlas;
898
- }
899
-
900
- if (!defined(this._backgroundTextureAtlas)) {
901
- this._backgroundTextureAtlas = new TextureAtlas({
902
- context: context,
903
- initialSize: whitePixelSize,
904
- });
905
- backgroundBillboardCollection.textureAtlas = this._backgroundTextureAtlas;
906
-
907
- // Request a new render in request render mode after the next frame renders
908
- addWhitePixelCanvas(this._backgroundTextureAtlas);
909
- }
910
-
911
944
  const len = this._labelsToUpdate.length;
912
945
  for (let i = 0; i < len; ++i) {
913
946
  const label = this._labelsToUpdate[i];
@@ -935,15 +968,15 @@ LabelCollection.prototype.update = function (frameState) {
935
968
  backgroundBillboardCollection.length > 0
936
969
  ? BlendOption.TRANSLUCENT
937
970
  : this.blendOption;
938
- billboardCollection.blendOption = blendOption;
971
+ glyphBillboardCollection.blendOption = blendOption;
939
972
  backgroundBillboardCollection.blendOption = blendOption;
940
973
 
941
- billboardCollection._highlightColor = this._highlightColor;
974
+ glyphBillboardCollection._highlightColor = this._highlightColor;
942
975
  backgroundBillboardCollection._highlightColor = this._highlightColor;
943
976
 
944
977
  this._labelsToUpdate.length = 0;
945
978
  backgroundBillboardCollection.update(frameState);
946
- billboardCollection.update(frameState);
979
+ glyphBillboardCollection.update(frameState);
947
980
  };
948
981
 
949
982
  /**
@@ -978,12 +1011,9 @@ LabelCollection.prototype.isDestroyed = function () {
978
1011
  */
979
1012
  LabelCollection.prototype.destroy = function () {
980
1013
  this.removeAll();
981
- this._billboardCollection = this._billboardCollection.destroy();
982
- this._textureAtlas = this._textureAtlas && this._textureAtlas.destroy();
1014
+ this._glyphBillboardCollection = this._glyphBillboardCollection.destroy();
983
1015
  this._backgroundBillboardCollection =
984
1016
  this._backgroundBillboardCollection.destroy();
985
- this._backgroundTextureAtlas =
986
- this._backgroundTextureAtlas && this._backgroundTextureAtlas.destroy();
987
1017
 
988
1018
  return destroyObject(this);
989
1019
  };