@cesium/engine 13.1.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 (183) hide show
  1. package/Build/Workers/{chunk-APCS5YJI.js → chunk-25TOENEE.js} +7 -7
  2. package/Build/Workers/{chunk-FNCXBBCF.js → chunk-2AVIUB5H.js} +2 -2
  3. package/Build/Workers/{chunk-OZTFRHA2.js → chunk-3JZGPJMZ.js} +6 -6
  4. package/Build/Workers/{chunk-5JY4LYO3.js → chunk-3LHBH4TC.js} +7 -7
  5. package/Build/Workers/{chunk-MGABCOOH.js → chunk-3LZF23RY.js} +6 -6
  6. package/Build/Workers/{chunk-AXYZUG4N.js → chunk-5S2B46UQ.js} +1 -1
  7. package/Build/Workers/{chunk-2SRHVCFD.js → chunk-67ONR44K.js} +6 -6
  8. package/Build/Workers/{chunk-PBJQFLKS.js → chunk-6EDBC234.js} +11 -11
  9. package/Build/Workers/{chunk-GSLKQJM2.js → chunk-6EV4VOET.js} +10 -10
  10. package/Build/Workers/{chunk-OGRXNUR2.js → chunk-7ITUZTFH.js} +1 -1
  11. package/Build/Workers/{chunk-IP7F2MVW.js → chunk-ARVZCY6X.js} +7 -7
  12. package/Build/Workers/{chunk-EYZFEJX3.js → chunk-B2UQN3DH.js} +6 -6
  13. package/Build/Workers/{chunk-WE4KF4AM.js → chunk-B2Y4ZS6X.js} +9 -9
  14. package/Build/Workers/{chunk-DWIKWWEE.js → chunk-BD2TPFGC.js} +5 -5
  15. package/Build/Workers/{chunk-5ICYLS6B.js → chunk-CHX2K5AC.js} +10 -10
  16. package/Build/Workers/{chunk-NQDKNE7V.js → chunk-CJGVEABL.js} +13 -13
  17. package/Build/Workers/{chunk-B34JXFHF.js → chunk-DYJHEP3B.js} +5 -5
  18. package/Build/Workers/{chunk-J7BMSSY7.js → chunk-E3H7AVMK.js} +13 -13
  19. package/Build/Workers/{chunk-TOHDFUJM.js → chunk-EZNAJPP5.js} +4 -4
  20. package/Build/Workers/{chunk-K62EHZFT.js → chunk-F7ZI463G.js} +15 -15
  21. package/Build/Workers/{chunk-EJ5DT5BP.js → chunk-FMZ5CX6V.js} +1 -1
  22. package/Build/Workers/{chunk-OARMSJUU.js → chunk-FRAWHNSR.js} +2 -2
  23. package/Build/Workers/{chunk-S3UM4OKP.js → chunk-GGV2XJHE.js} +7 -7
  24. package/Build/Workers/{chunk-SAKQO5NX.js → chunk-GK4QU6QI.js} +2 -2
  25. package/Build/Workers/{chunk-LFUFGHL3.js → chunk-HYPB7FAV.js} +10 -10
  26. package/Build/Workers/{chunk-3SCCWLZS.js → chunk-I4HO2ED2.js} +9 -9
  27. package/Build/Workers/{chunk-K6SQV4IS.js → chunk-IGINOLDX.js} +6 -6
  28. package/Build/Workers/{chunk-IXNXKVOB.js → chunk-ISQSYLZY.js} +4 -4
  29. package/Build/Workers/{chunk-PM76TX2X.js → chunk-JZAMRL5I.js} +6 -6
  30. package/Build/Workers/{chunk-CBE4HRBH.js → chunk-K5G2WELR.js} +7 -7
  31. package/Build/Workers/{chunk-EHGQQA7C.js → chunk-L5SO4Y5V.js} +1 -1
  32. package/Build/Workers/{chunk-M2AA2ARJ.js → chunk-LCMJQVIF.js} +11 -11
  33. package/Build/Workers/{chunk-HI73PIPQ.js → chunk-MWJW37I7.js} +2 -2
  34. package/Build/Workers/{chunk-WAJNX74N.js → chunk-NAGMYRDW.js} +27 -20
  35. package/Build/Workers/{chunk-WUIDEXAN.js → chunk-OYO6TKMU.js} +7 -7
  36. package/Build/Workers/{chunk-YVGU235V.js → chunk-PUTA3AE2.js} +4 -4
  37. package/Build/Workers/{chunk-ZWSWJYJP.js → chunk-Q5BHMNKU.js} +13 -13
  38. package/Build/Workers/{chunk-LQT2ZK7D.js → chunk-QTEX3Y4V.js} +17 -17
  39. package/Build/Workers/{chunk-UBAHTE4Q.js → chunk-QZKN2RXM.js} +1 -1
  40. package/Build/Workers/{chunk-T34EOLFR.js → chunk-RO2Z3LCR.js} +14 -14
  41. package/Build/Workers/{chunk-PTFIVVLX.js → chunk-RRN6LRDX.js} +12 -12
  42. package/Build/Workers/{chunk-B6IJY6AN.js → chunk-SLIA3GQP.js} +7 -7
  43. package/Build/Workers/{chunk-GIOZHX7U.js → chunk-TFCOEX3W.js} +2 -2
  44. package/Build/Workers/{chunk-KRVALCCI.js → chunk-TU6ZXHVU.js} +5 -5
  45. package/Build/Workers/{chunk-54I6VSRP.js → chunk-VJ2PDF64.js} +6 -6
  46. package/Build/Workers/{chunk-BMFWWTD7.js → chunk-VMVPONIV.js} +5 -5
  47. package/Build/Workers/{chunk-CNPP6TQ2.js → chunk-WPXU45PH.js} +4 -4
  48. package/Build/Workers/{chunk-2ONAV62A.js → chunk-XDHM4G3P.js} +7 -7
  49. package/Build/Workers/{chunk-KO232FLP.js → chunk-XED3RXKO.js} +2 -2
  50. package/Build/Workers/{chunk-5I3LPAS7.js → chunk-YNYCGTQH.js} +5 -5
  51. package/Build/Workers/{chunk-THDHWSEJ.js → chunk-Z4SI54EB.js} +4 -4
  52. package/Build/Workers/{chunk-R2KGFZBA.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 +15 -14
  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/Color.js +3 -3
  102. package/Source/Core/Credit.js +3 -3
  103. package/Source/Core/DistanceDisplayCondition.js +3 -3
  104. package/Source/Core/EllipsoidRhumbLine.js +1 -1
  105. package/Source/Core/Ion.js +1 -1
  106. package/Source/Core/OrientedBoundingBox.js +2 -2
  107. package/Source/Core/PolygonGeometryLibrary.js +26 -4
  108. package/Source/Core/Spherical.js +3 -3
  109. package/Source/Core/TexturePacker.js +166 -0
  110. package/Source/Core/writeTextToCanvas.js +0 -1
  111. package/Source/DataSources/BillboardVisualizer.js +3 -3
  112. package/Source/DataSources/BoundingSphereState.js +3 -3
  113. package/Source/DataSources/DataSourceClock.js +1 -1
  114. package/Source/DataSources/DataSourceDisplay.js +5 -2
  115. package/Source/DataSources/EntityCluster.js +44 -19
  116. package/Source/Renderer/AutomaticUniforms.js +2 -2
  117. package/Source/Renderer/Context.js +0 -4
  118. package/Source/Renderer/Texture.js +6 -5
  119. package/Source/Renderer/TextureAtlas.js +802 -0
  120. package/Source/Scene/ArcGisMapService.js +1 -1
  121. package/Source/Scene/Billboard.js +87 -142
  122. package/Source/Scene/BillboardCollection.js +132 -202
  123. package/Source/Scene/BillboardLoadState.js +44 -0
  124. package/Source/Scene/BillboardTexture.js +348 -0
  125. package/Source/Scene/Camera.js +2 -2
  126. package/Source/Scene/Cesium3DTile.js +56 -28
  127. package/Source/Scene/Cesium3DTilesVoxelProvider.js +403 -132
  128. package/Source/Scene/Cesium3DTilesetStatistics.js +0 -1
  129. package/Source/Scene/ClippingPolygon.js +2 -2
  130. package/Source/Scene/Expression.js +1 -0
  131. package/Source/Scene/GltfDracoLoader.js +45 -0
  132. package/Source/Scene/GltfIndexBufferLoader.js +5 -0
  133. package/Source/Scene/GltfLoader.js +22 -9
  134. package/Source/Scene/GltfVertexBufferLoader.js +13 -0
  135. package/Source/Scene/ITwinData.js +47 -1
  136. package/Source/Scene/ImageryLayer.js +1 -1
  137. package/Source/Scene/ImplicitSubtree.js +2 -0
  138. package/Source/Scene/KeyframeNode.js +16 -2
  139. package/Source/Scene/Label.js +1 -1
  140. package/Source/Scene/LabelCollection.js +212 -193
  141. package/Source/Scene/Megatexture.js +145 -81
  142. package/Source/Scene/Model/CustomShader.js +0 -2
  143. package/Source/Scene/Model/Model.js +1 -1
  144. package/Source/Scene/Model/ModelUtility.js +5 -1
  145. package/Source/Scene/Multiple3DTileContent.js +21 -8
  146. package/Source/Scene/PointPrimitive.js +1 -1
  147. package/Source/Scene/ResourceCache.js +17 -1
  148. package/Source/Scene/Scene.js +39 -15
  149. package/Source/Scene/ScreenSpaceCameraController.js +0 -8
  150. package/Source/Scene/SpatialNode.js +4 -11
  151. package/Source/Scene/Vector3DTilePoints.js +2 -5
  152. package/Source/Scene/VoxelBoxShape.js +12 -5
  153. package/Source/Scene/VoxelCell.js +6 -5
  154. package/Source/Scene/VoxelContent.js +171 -107
  155. package/Source/Scene/VoxelCylinderShape.js +65 -58
  156. package/Source/Scene/VoxelEllipsoidShape.js +15 -5
  157. package/Source/Scene/VoxelMetadataOrder.js +12 -0
  158. package/Source/Scene/VoxelPrimitive.js +245 -53
  159. package/Source/Scene/VoxelProvider.js +44 -29
  160. package/Source/Scene/VoxelRenderResources.js +30 -7
  161. package/Source/Scene/VoxelShape.js +10 -3
  162. package/Source/Scene/VoxelTraversal.js +326 -166
  163. package/Source/Scene/WebMapTileServiceImageryProvider.js +2 -2
  164. package/Source/Scene/createGooglePhotorealistic3DTileset.js +5 -8
  165. package/Source/Scene/processVoxelProperties.js +3 -0
  166. package/Source/Shaders/GlobeFS.glsl +10 -1
  167. package/Source/Shaders/GlobeFS.js +10 -1
  168. package/Source/Shaders/PolylineCommon.glsl +1 -1
  169. package/Source/Shaders/PolylineCommon.js +1 -1
  170. package/Source/Shaders/Voxels/Megatexture.glsl +4 -16
  171. package/Source/Shaders/Voxels/Megatexture.js +4 -16
  172. package/Source/Shaders/Voxels/Octree.glsl +44 -7
  173. package/Source/Shaders/Voxels/Octree.js +44 -7
  174. package/Source/Shaders/Voxels/VoxelFS.glsl +9 -15
  175. package/Source/Shaders/Voxels/VoxelFS.js +9 -15
  176. package/Source/Shaders/Voxels/convertUvToCylinder.glsl +15 -15
  177. package/Source/Shaders/Voxels/convertUvToCylinder.js +15 -15
  178. package/Source/Widget/CesiumWidget.js +16 -10
  179. package/Source/Workers/decodeDraco.js +4 -4
  180. package/index.d.ts +321 -110
  181. package/index.js +209 -205
  182. package/package.json +2 -2
  183. package/Source/Scene/TextureAtlas.js +0 -558
@@ -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
@@ -68,7 +97,6 @@ function createGlyphCanvas(
68
97
  outlineColor,
69
98
  outlineWidth,
70
99
  style,
71
- verticalOrigin,
72
100
  ) {
73
101
  writeTextToCanvasParameters.font = font;
74
102
  writeTextToCanvasParameters.fillColor = fillColor;
@@ -77,15 +105,6 @@ function createGlyphCanvas(
77
105
  // Setting the padding to something bigger is necessary to get enough space for the outlining.
78
106
  writeTextToCanvasParameters.padding = SDFSettings.PADDING;
79
107
 
80
- if (verticalOrigin === VerticalOrigin.CENTER) {
81
- writeTextToCanvasParameters.textBaseline = "middle";
82
- } else if (verticalOrigin === VerticalOrigin.TOP) {
83
- writeTextToCanvasParameters.textBaseline = "top";
84
- } else {
85
- // VerticalOrigin.BOTTOM and VerticalOrigin.BASELINE
86
- writeTextToCanvasParameters.textBaseline = "bottom";
87
- }
88
-
89
108
  writeTextToCanvasParameters.fill =
90
109
  style === LabelStyle.FILL || style === LabelStyle.FILL_AND_OUTLINE;
91
110
  writeTextToCanvasParameters.stroke =
@@ -95,14 +114,10 @@ function createGlyphCanvas(
95
114
  return writeTextToCanvas(character, writeTextToCanvasParameters);
96
115
  }
97
116
 
98
- function unbindGlyph(labelCollection, glyph) {
99
- glyph.textureInfo = undefined;
100
- glyph.dimensions = undefined;
101
-
117
+ function unbindGlyphBillboard(labelCollection, glyph) {
102
118
  const billboard = glyph.billboard;
103
119
  if (defined(billboard)) {
104
120
  billboard.show = false;
105
- billboard.image = undefined;
106
121
  if (defined(billboard._removeCallbackFunc)) {
107
122
  billboard._removeCallbackFunc();
108
123
  billboard._removeCallbackFunc = undefined;
@@ -112,11 +127,8 @@ function unbindGlyph(labelCollection, glyph) {
112
127
  }
113
128
  }
114
129
 
115
- function addGlyphToTextureAtlas(textureAtlas, id, canvas, glyphTextureInfo) {
116
- glyphTextureInfo.index = textureAtlas.addImageSync(id, canvas);
117
- }
118
-
119
130
  const splitter = new GraphemeSplitter();
131
+ const whitespaceRegex = /\s/;
120
132
 
121
133
  function rebindAllGlyphs(labelCollection, label) {
122
134
  const text = label._renderedText;
@@ -125,17 +137,13 @@ function rebindAllGlyphs(labelCollection, label) {
125
137
  const glyphs = label._glyphs;
126
138
  const glyphsLength = glyphs.length;
127
139
 
128
- let glyph;
129
- let glyphIndex;
130
- let textIndex;
131
-
132
140
  // Compute a font size scale relative to the sdf font generated size.
133
141
  label._relativeSize = label._fontSize / SDFSettings.FONT_SIZE;
134
142
 
135
143
  // if we have more glyphs than needed, unbind the extras.
136
144
  if (textLength < glyphsLength) {
137
- for (glyphIndex = textLength; glyphIndex < glyphsLength; ++glyphIndex) {
138
- unbindGlyph(labelCollection, glyphs[glyphIndex]);
145
+ for (let glyphIndex = textLength; glyphIndex < glyphsLength; ++glyphIndex) {
146
+ unbindGlyphBillboard(labelCollection, glyphs[glyphIndex]);
139
147
  }
140
148
  }
141
149
 
@@ -154,11 +162,10 @@ function rebindAllGlyphs(labelCollection, label) {
154
162
  }
155
163
  } else {
156
164
  if (!defined(backgroundBillboard)) {
157
- backgroundBillboard = backgroundBillboardCollection.add({
158
- collection: labelCollection,
159
- image: whitePixelCanvasId,
160
- imageSubRegion: whitePixelBoundingRegion,
161
- });
165
+ backgroundBillboard = getWhitePixelBillboard(
166
+ backgroundBillboardCollection,
167
+ labelCollection,
168
+ );
162
169
  label._backgroundBillboard = backgroundBillboard;
163
170
  }
164
171
 
@@ -184,11 +191,13 @@ function rebindAllGlyphs(labelCollection, label) {
184
191
  backgroundBillboard.clusterShow = label.clusterShow;
185
192
  }
186
193
 
187
- const glyphTextureCache = labelCollection._glyphTextureCache;
194
+ const glyphBillboardCollection = labelCollection._glyphBillboardCollection;
195
+ const glyphTextureCache = glyphBillboardCollection.billboardTextureCache;
196
+ const textDimensionsCache = labelCollection._textDimensionsCache;
188
197
 
189
198
  // walk the text looking for new characters (creating new glyphs for each)
190
199
  // or changed characters (rebinding existing glyphs)
191
- for (textIndex = 0; textIndex < textLength; ++textIndex) {
200
+ for (let textIndex = 0; textIndex < textLength; ++textIndex) {
192
201
  const character = graphemes[textIndex];
193
202
  const verticalOrigin = label._verticalOrigin;
194
203
 
@@ -200,8 +209,12 @@ function rebindAllGlyphs(labelCollection, label) {
200
209
  +verticalOrigin,
201
210
  ]);
202
211
 
203
- let glyphTextureInfo = glyphTextureCache[id];
204
- 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
+
205
218
  const glyphFont = `${label._fontStyle} ${label._fontWeight} ${SDFSettings.FONT_SIZE}px ${label._fontFamily}`;
206
219
 
207
220
  const canvas = createGlyphCanvas(
@@ -211,17 +224,16 @@ function rebindAllGlyphs(labelCollection, label) {
211
224
  Color.WHITE,
212
225
  0.0,
213
226
  LabelStyle.FILL,
214
- verticalOrigin,
215
227
  );
216
228
 
217
- glyphTextureInfo = new GlyphTextureInfo(
218
- labelCollection,
219
- -1,
220
- canvas.dimensions,
221
- );
222
- glyphTextureCache[id] = glyphTextureInfo;
229
+ dimensions = canvas.dimensions;
230
+ textDimensionsCache[id] = dimensions;
223
231
 
224
- if (canvas.width > 0 && canvas.height > 0) {
232
+ if (
233
+ canvas.width > 0 &&
234
+ canvas.height > 0 &&
235
+ !whitespaceRegex.test(character)
236
+ ) {
225
237
  const sdfValues = bitmapSDF(canvas, {
226
238
  cutoff: SDFSettings.CUTOFF,
227
239
  radius: SDFSettings.RADIUS,
@@ -244,84 +256,76 @@ function rebindAllGlyphs(labelCollection, label) {
244
256
  }
245
257
  }
246
258
  ctx.putImageData(imgData, 0, 0);
247
- if (character !== " ") {
248
- addGlyphToTextureAtlas(
249
- labelCollection._textureAtlas,
250
- id,
251
- canvas,
252
- glyphTextureInfo,
253
- );
254
- }
259
+ glyphBillboardTexture.loadImage(id, canvas);
255
260
  }
256
261
  }
257
262
 
258
- glyph = glyphs[textIndex];
259
-
260
- if (defined(glyph)) {
261
- // clean up leftover information from the previous glyph
262
- if (glyphTextureInfo.index === -1) {
263
- // no texture, and therefore no billboard, for this glyph.
264
- // so, completely unbind glyph.
265
- unbindGlyph(labelCollection, glyph);
266
- } else if (defined(glyph.textureInfo)) {
267
- // we have a texture and billboard. If we had one before, release
268
- // our reference to that texture info, but reuse the billboard.
269
- glyph.textureInfo = undefined;
270
- }
271
- } else {
272
- // create a glyph object
263
+ let glyph = glyphs[textIndex];
264
+ if (!defined(glyph)) {
273
265
  glyph = new Glyph();
266
+ glyph.dimensions = dimensions;
267
+ glyph.billboardTexture = glyphBillboardTexture;
274
268
  glyphs[textIndex] = glyph;
275
269
  }
276
270
 
277
- glyph.textureInfo = glyphTextureInfo;
278
- glyph.dimensions = glyphTextureInfo.dimensions;
279
-
280
- // if we have a texture, configure the existing billboard, or obtain one
281
- if (glyphTextureInfo.index !== -1) {
282
- let billboard = glyph.billboard;
283
- const spareBillboards = labelCollection._spareBillboards;
284
- if (!defined(billboard)) {
285
- if (spareBillboards.length > 0) {
286
- billboard = spareBillboards.pop();
287
- } else {
288
- billboard = labelCollection._billboardCollection.add({
289
- collection: labelCollection,
290
- });
291
- billboard._labelDimensions = new Cartesian2();
292
- billboard._labelTranslate = new Cartesian2();
293
- }
294
- glyph.billboard = billboard;
295
- }
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
+ }
296
277
 
297
- billboard.show = label._show;
298
- billboard.position = label._position;
299
- billboard.eyeOffset = label._eyeOffset;
300
- billboard.pixelOffset = label._pixelOffset;
301
- billboard.horizontalOrigin = HorizontalOrigin.LEFT;
302
- billboard.verticalOrigin = label._verticalOrigin;
303
- billboard.heightReference = label._heightReference;
304
- billboard.scale = label.totalScale;
305
- billboard.pickPrimitive = label;
306
- billboard.id = label._id;
307
- billboard.image = id;
308
- billboard.translucencyByDistance = label._translucencyByDistance;
309
- billboard.pixelOffsetScaleByDistance = label._pixelOffsetScaleByDistance;
310
- billboard.scaleByDistance = label._scaleByDistance;
311
- billboard.distanceDisplayCondition = label._distanceDisplayCondition;
312
- billboard.disableDepthTestDistance = label._disableDepthTestDistance;
313
- billboard._batchIndex = label._batchIndex;
314
- billboard.outlineColor = label.outlineColor;
315
- if (label.style === LabelStyle.FILL_AND_OUTLINE) {
316
- billboard.color = label._fillColor;
317
- billboard.outlineWidth = label.outlineWidth;
318
- } else if (label.style === LabelStyle.FILL) {
319
- billboard.color = label._fillColor;
320
- billboard.outlineWidth = 0.0;
321
- } else if (label.style === LabelStyle.OUTLINE) {
322
- billboard.color = Color.TRANSPARENT;
323
- billboard.outlineWidth = label.outlineWidth;
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
+ }
284
+
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();
324
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;
325
329
  }
326
330
  }
327
331
 
@@ -346,15 +350,12 @@ const scratchBackgroundPadding = new Cartesian2();
346
350
  function repositionAllGlyphs(label) {
347
351
  const glyphs = label._glyphs;
348
352
  const text = label._renderedText;
349
- let glyph;
350
- let dimensions;
351
353
  let lastLineWidth = 0;
352
354
  let maxLineWidth = 0;
353
355
  const lineWidths = [];
354
356
  let maxGlyphDescent = Number.NEGATIVE_INFINITY;
355
357
  let maxGlyphY = 0;
356
358
  let numberOfLines = 1;
357
- let glyphIndex;
358
359
  const glyphLength = glyphs.length;
359
360
 
360
361
  const backgroundBillboard = label._backgroundBillboard;
@@ -367,18 +368,21 @@ function repositionAllGlyphs(label) {
367
368
  backgroundPadding.x /= label._relativeSize;
368
369
  backgroundPadding.y /= label._relativeSize;
369
370
 
370
- for (glyphIndex = 0; glyphIndex < glyphLength; ++glyphIndex) {
371
+ for (let glyphIndex = 0; glyphIndex < glyphLength; ++glyphIndex) {
371
372
  if (text.charAt(glyphIndex) === "\n") {
372
373
  lineWidths.push(lastLineWidth);
373
374
  ++numberOfLines;
374
375
  lastLineWidth = 0;
375
- } else {
376
- glyph = glyphs[glyphIndex];
377
- dimensions = glyph.dimensions;
376
+ continue;
377
+ }
378
+
379
+ const glyph = glyphs[glyphIndex];
380
+ const dimensions = glyph.dimensions;
381
+ if (defined(dimensions)) {
378
382
  maxGlyphY = Math.max(maxGlyphY, dimensions.height - dimensions.descent);
379
383
  maxGlyphDescent = Math.max(maxGlyphDescent, dimensions.descent);
380
384
 
381
- //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.
382
386
  lastLineWidth += dimensions.width - dimensions.minx;
383
387
  if (glyphIndex < glyphLength - 1) {
384
388
  lastLineWidth += glyphs[glyphIndex + 1].dimensions.minx;
@@ -419,7 +423,7 @@ function repositionAllGlyphs(label) {
419
423
  let firstCharOfLine = true;
420
424
 
421
425
  let lineOffsetY = 0;
422
- for (glyphIndex = 0; glyphIndex < glyphLength; ++glyphIndex) {
426
+ for (let glyphIndex = 0; glyphIndex < glyphLength; ++glyphIndex) {
423
427
  if (text.charAt(glyphIndex) === "\n") {
424
428
  ++lineIndex;
425
429
  lineOffsetY += lineSpacing;
@@ -431,10 +435,12 @@ function repositionAllGlyphs(label) {
431
435
  );
432
436
  glyphPixelOffset.x = widthOffset * scale;
433
437
  firstCharOfLine = true;
434
- } else {
435
- glyph = glyphs[glyphIndex];
436
- dimensions = glyph.dimensions;
438
+ continue;
439
+ }
437
440
 
441
+ const glyph = glyphs[glyphIndex];
442
+ const dimensions = glyph.dimensions;
443
+ if (defined(dimensions)) {
438
444
  if (verticalOrigin === VerticalOrigin.TOP) {
439
445
  glyphPixelOffset.y =
440
446
  dimensions.height - maxGlyphY - backgroundPadding.y;
@@ -511,8 +517,8 @@ function repositionAllGlyphs(label) {
511
517
  }
512
518
 
513
519
  if (isHeightReferenceClamp(label.heightReference)) {
514
- for (glyphIndex = 0; glyphIndex < glyphLength; ++glyphIndex) {
515
- glyph = glyphs[glyphIndex];
520
+ for (let glyphIndex = 0; glyphIndex < glyphLength; ++glyphIndex) {
521
+ const glyph = glyphs[glyphIndex];
516
522
  const billboard = glyph.billboard;
517
523
  if (defined(billboard)) {
518
524
  billboard._labelTranslate = Cartesian2.clone(
@@ -527,7 +533,7 @@ function repositionAllGlyphs(label) {
527
533
  function destroyLabel(labelCollection, label) {
528
534
  const glyphs = label._glyphs;
529
535
  for (let i = 0, len = glyphs.length; i < len; ++i) {
530
- unbindGlyph(labelCollection, glyphs[i]);
536
+ unbindGlyphBillboard(labelCollection, glyphs[i]);
531
537
  }
532
538
  if (defined(label._backgroundBillboard)) {
533
539
  labelCollection._backgroundBillboardCollection.remove(
@@ -598,23 +604,25 @@ function LabelCollection(options) {
598
604
  this._scene = options.scene;
599
605
  this._batchTable = options.batchTable;
600
606
 
601
- this._textureAtlas = undefined;
602
- this._backgroundTextureAtlas = undefined;
603
-
604
- this._backgroundBillboardCollection = new BillboardCollection({
607
+ const backgroundBillboardCollection = new BillboardCollection({
605
608
  scene: this._scene,
609
+ textureAtlas: new TextureAtlas({
610
+ initialSize: whitePixelSize,
611
+ }),
606
612
  });
607
- this._backgroundBillboardCollection.destroyTextureAtlas = false;
613
+ this._backgroundBillboardCollection = backgroundBillboardCollection;
614
+ this._backgroundBillboardTexture = new BillboardTexture(
615
+ backgroundBillboardCollection,
616
+ );
608
617
 
609
- this._billboardCollection = new BillboardCollection({
618
+ this._glyphBillboardCollection = new BillboardCollection({
610
619
  scene: this._scene,
611
620
  batchTable: this._batchTable,
612
621
  });
613
- this._billboardCollection.destroyTextureAtlas = false;
614
- this._billboardCollection._sdf = true;
622
+ this._glyphBillboardCollection._sdf = true;
615
623
 
616
624
  this._spareBillboards = [];
617
- this._glyphTextureCache = {};
625
+ this._textDimensionsCache = {};
618
626
  this._labels = [];
619
627
  this._labelsToUpdate = [];
620
628
  this._totalGlyphCount = 0;
@@ -698,12 +706,47 @@ Object.defineProperties(LabelCollection.prototype, {
698
706
  * in the collection.
699
707
  * @memberof LabelCollection.prototype
700
708
  * @type {number}
709
+ * @readonly
701
710
  */
702
711
  length: {
703
712
  get: function () {
704
713
  return this._labels.length;
705
714
  },
706
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
+ },
707
750
  });
708
751
 
709
752
  /**
@@ -720,7 +763,6 @@ Object.defineProperties(LabelCollection.prototype, {
720
763
  *
721
764
  * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
722
765
  *
723
- *
724
766
  * @example
725
767
  * // Example 1: Add a label, specifying all the default values.
726
768
  * const l = labels.add({
@@ -883,42 +925,22 @@ LabelCollection.prototype.get = function (index) {
883
925
 
884
926
  /**
885
927
  * @private
886
- *
887
928
  */
888
929
  LabelCollection.prototype.update = function (frameState) {
889
930
  if (!this.show) {
890
931
  return;
891
932
  }
892
933
 
893
- const billboardCollection = this._billboardCollection;
934
+ const glyphBillboardCollection = this._glyphBillboardCollection;
894
935
  const backgroundBillboardCollection = this._backgroundBillboardCollection;
895
936
 
896
- billboardCollection.modelMatrix = this.modelMatrix;
897
- billboardCollection.debugShowBoundingVolume = this.debugShowBoundingVolume;
937
+ glyphBillboardCollection.modelMatrix = this.modelMatrix;
938
+ glyphBillboardCollection.debugShowBoundingVolume =
939
+ this.debugShowBoundingVolume;
898
940
  backgroundBillboardCollection.modelMatrix = this.modelMatrix;
899
941
  backgroundBillboardCollection.debugShowBoundingVolume =
900
942
  this.debugShowBoundingVolume;
901
943
 
902
- const context = frameState.context;
903
-
904
- if (!defined(this._textureAtlas)) {
905
- this._textureAtlas = new TextureAtlas({
906
- context: context,
907
- });
908
- billboardCollection.textureAtlas = this._textureAtlas;
909
- }
910
-
911
- if (!defined(this._backgroundTextureAtlas)) {
912
- this._backgroundTextureAtlas = new TextureAtlas({
913
- context: context,
914
- initialSize: whitePixelSize,
915
- });
916
- backgroundBillboardCollection.textureAtlas = this._backgroundTextureAtlas;
917
-
918
- // Request a new render in request render mode after the next frame renders
919
- addWhitePixelCanvas(this._backgroundTextureAtlas);
920
- }
921
-
922
944
  const len = this._labelsToUpdate.length;
923
945
  for (let i = 0; i < len; ++i) {
924
946
  const label = this._labelsToUpdate[i];
@@ -946,15 +968,15 @@ LabelCollection.prototype.update = function (frameState) {
946
968
  backgroundBillboardCollection.length > 0
947
969
  ? BlendOption.TRANSLUCENT
948
970
  : this.blendOption;
949
- billboardCollection.blendOption = blendOption;
971
+ glyphBillboardCollection.blendOption = blendOption;
950
972
  backgroundBillboardCollection.blendOption = blendOption;
951
973
 
952
- billboardCollection._highlightColor = this._highlightColor;
974
+ glyphBillboardCollection._highlightColor = this._highlightColor;
953
975
  backgroundBillboardCollection._highlightColor = this._highlightColor;
954
976
 
955
977
  this._labelsToUpdate.length = 0;
956
978
  backgroundBillboardCollection.update(frameState);
957
- billboardCollection.update(frameState);
979
+ glyphBillboardCollection.update(frameState);
958
980
  };
959
981
 
960
982
  /**
@@ -989,12 +1011,9 @@ LabelCollection.prototype.isDestroyed = function () {
989
1011
  */
990
1012
  LabelCollection.prototype.destroy = function () {
991
1013
  this.removeAll();
992
- this._billboardCollection = this._billboardCollection.destroy();
993
- this._textureAtlas = this._textureAtlas && this._textureAtlas.destroy();
1014
+ this._glyphBillboardCollection = this._glyphBillboardCollection.destroy();
994
1015
  this._backgroundBillboardCollection =
995
1016
  this._backgroundBillboardCollection.destroy();
996
- this._backgroundTextureAtlas =
997
- this._backgroundTextureAtlas && this._backgroundTextureAtlas.destroy();
998
1017
 
999
1018
  return destroyObject(this);
1000
1019
  };