@mapwhit/tilerenderer 0.48.0 → 0.50.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 (42) hide show
  1. package/build/min/package.json +1 -1
  2. package/build/min/src/shaders/fill_extrusion.fragment.glsl.txt +1 -9
  3. package/build/min/src/shaders/fill_extrusion.vertex.glsl.txt +4 -4
  4. package/package.json +3 -2
  5. package/src/data/array_types.js +169 -0
  6. package/src/data/bucket/symbol_attributes.js +18 -0
  7. package/src/data/bucket/symbol_bucket.js +108 -78
  8. package/src/geo/transform.js +13 -5
  9. package/src/render/glyph_atlas.js +3 -6
  10. package/src/render/image_atlas.js +3 -6
  11. package/src/render/image_manager.js +41 -41
  12. package/src/shaders/fill_extrusion.fragment.glsl +0 -7
  13. package/src/shaders/fill_extrusion.vertex.glsl +4 -4
  14. package/src/style/style_layer/symbol_style_layer_properties.js +6 -0
  15. package/src/style-spec/expression/definitions/assertion.js +52 -5
  16. package/src/style-spec/expression/definitions/coalesce.js +1 -3
  17. package/src/style-spec/expression/definitions/coercion.js +32 -21
  18. package/src/style-spec/expression/definitions/collator.js +1 -23
  19. package/src/style-spec/expression/definitions/{formatted.js → format.js} +3 -29
  20. package/src/style-spec/expression/definitions/index.js +8 -26
  21. package/src/style-spec/expression/definitions/let.js +1 -1
  22. package/src/style-spec/expression/definitions/literal.js +1 -1
  23. package/src/style-spec/expression/evaluation_context.js +3 -0
  24. package/src/style-spec/expression/index.js +18 -17
  25. package/src/style-spec/expression/parsing_context.js +28 -24
  26. package/src/style-spec/expression/types/collator.js +24 -0
  27. package/src/style-spec/expression/types/formatted.js +39 -0
  28. package/src/style-spec/expression/types.js +1 -1
  29. package/src/style-spec/expression/values.js +24 -1
  30. package/src/style-spec/feature_filter/convert.js +197 -0
  31. package/src/style-spec/feature_filter/index.js +4 -1
  32. package/src/style-spec/function/convert.js +86 -102
  33. package/src/style-spec/function/index.js +4 -0
  34. package/src/style-spec/reference/v8.json +43 -6
  35. package/src/symbol/collision_index.js +0 -1
  36. package/src/symbol/cross_tile_symbol_index.js +12 -7
  37. package/src/symbol/mergelines.js +2 -2
  38. package/src/symbol/placement.js +71 -54
  39. package/src/symbol/shaping.js +9 -18
  40. package/src/symbol/symbol_layout.js +33 -33
  41. package/src/symbol/transform_text.js +5 -8
  42. package/src/style-spec/expression/definitions/array.js +0 -82
@@ -1,3 +1,3 @@
1
1
  {
2
- "version": "0.47.2"
2
+ "version": "0.49.0"
3
3
  }
@@ -1,12 +1,4 @@
1
- varying vec4 v_color;
2
- #pragma mapbox: define lowp float base
3
- #pragma mapbox: define lowp float height
4
- #pragma mapbox: define highp vec4 color
5
- void main(){
6
- #pragma mapbox: initialize lowp float base
7
- #pragma mapbox: initialize lowp float height
8
- #pragma mapbox: initialize highp vec4 color
9
- gl_FragColor=v_color;
1
+ varying vec4 v_color;void main(){gl_FragColor=v_color;
10
2
  #ifdef OVERDRAW_INSPECTOR
11
3
  gl_FragColor=vec4(1.);
12
4
  #endif
@@ -1,9 +1,9 @@
1
1
  uniform mat4 u_matrix;uniform vec3 u_lightcolor;uniform lowp vec3 u_lightpos;uniform lowp float u_lightintensity;uniform float u_vertical_gradient;uniform lowp float u_opacity;attribute vec2 a_pos;attribute vec4 a_normal_ed;varying vec4 v_color;
2
- #pragma mapbox: define lowp float base
3
- #pragma mapbox: define lowp float height
2
+ #pragma mapbox: define highp float base
3
+ #pragma mapbox: define highp float height
4
4
  #pragma mapbox: define highp vec4 color
5
5
  void main(){
6
- #pragma mapbox: initialize lowp float base
7
- #pragma mapbox: initialize lowp float height
6
+ #pragma mapbox: initialize highp float base
7
+ #pragma mapbox: initialize highp float height
8
8
  #pragma mapbox: initialize highp vec4 color
9
9
  vec3 normal=a_normal_ed.xyz;base=max(0.,base);height=max(0.,height);float t=mod(normal.x,2.);gl_Position=u_matrix*vec4(a_pos,t>0.?height:base,1);float colorvalue=color.r*0.2126+color.g*0.7152+color.b*0.0722;v_color=vec4(0.,0.,0.,1.);vec4 ambientlight=vec4(0.03,0.03,0.03,1.);color+=ambientlight;float directional=clamp(dot(normal/16384.,u_lightpos),0.,1.);directional=mix((1.-u_lightintensity),max((1.-colorvalue+u_lightintensity),1.),directional);if(normal.y!=0.){directional*=((1.-u_vertical_gradient)+(u_vertical_gradient*clamp((t+base)*pow(height/150.,0.5),mix(0.7,0.98,1.-u_lightintensity),1.)));}v_color.r+=clamp(color.r*directional*u_lightcolor.r,mix(0.,0.3,1.-u_lightcolor.r),1.);v_color.g+=clamp(color.g*directional*u_lightcolor.g,mix(0.,0.3,1.-u_lightcolor.g),1.);v_color.b+=clamp(color.b*directional*u_lightcolor.b,mix(0.,0.3,1.-u_lightcolor.b),1.);v_color*=u_opacity;}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mapwhit/tilerenderer",
3
3
  "description": "A WebGL interactive maps library",
4
- "version": "0.48.0",
4
+ "version": "0.50.0",
5
5
  "main": "src/index.js",
6
6
  "license": "BSD-3-Clause",
7
7
  "repository": {
@@ -11,7 +11,6 @@
11
11
  "dependencies": {
12
12
  "@mapbox/gl-matrix": "^0.0.1",
13
13
  "@mapbox/point-geometry": "^0.1.0",
14
- "@mapbox/shelf-pack": "^3.0.0",
15
14
  "@mapbox/tiny-sdf": "^1.1.0",
16
15
  "@mapbox/unitbezier": "^0.0.0",
17
16
  "@mapbox/vector-tile": "^1.3.1",
@@ -24,6 +23,8 @@
24
23
  "earcut": "^2.0.3",
25
24
  "geojson-vt": "^3.1.2",
26
25
  "grid-index": "^1.1.0",
26
+ "murmurhash-js": "^1.0.0",
27
+ "potpack": "^1.0.1",
27
28
  "quickselect": "^2.0.0",
28
29
  "supercluster": "^2.0.1",
29
30
  "tinyqueue": "^1.1.0"
@@ -513,6 +513,68 @@ class StructArrayLayout2i2ui3ul3ui2f2ub40 extends StructArray {
513
513
  StructArrayLayout2i2ui3ul3ui2f2ub40.prototype.bytesPerElement = 40;
514
514
  register('StructArrayLayout2i2ui3ul3ui2f2ub40', StructArrayLayout2i2ui3ul3ui2f2ub40);
515
515
 
516
+ /**
517
+ * Implementation of the StructArray layout:
518
+ * [0]: Int16[4]
519
+ * [8]: Uint16[9]
520
+ * [28]: Uint32[1]
521
+ *
522
+ * @private
523
+ */
524
+ class StructArrayLayout4i9ui1ul32 extends StructArray {
525
+ _refreshViews() {
526
+ this.uint8 = new Uint8Array(this.arrayBuffer);
527
+ this.int16 = new Int16Array(this.arrayBuffer);
528
+ this.uint16 = new Uint16Array(this.arrayBuffer);
529
+ this.uint32 = new Uint32Array(this.arrayBuffer);
530
+ }
531
+
532
+ emplaceBack(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) {
533
+ const i = this.length;
534
+ this.resize(i + 1);
535
+ const o2 = i * 16;
536
+ const o4 = i * 8;
537
+ this.int16[o2 + 0] = v0;
538
+ this.int16[o2 + 1] = v1;
539
+ this.int16[o2 + 2] = v2;
540
+ this.int16[o2 + 3] = v3;
541
+ this.uint16[o2 + 4] = v4;
542
+ this.uint16[o2 + 5] = v5;
543
+ this.uint16[o2 + 6] = v6;
544
+ this.uint16[o2 + 7] = v7;
545
+ this.uint16[o2 + 8] = v8;
546
+ this.uint16[o2 + 9] = v9;
547
+ this.uint16[o2 + 10] = v10;
548
+ this.uint16[o2 + 11] = v11;
549
+ this.uint16[o2 + 12] = v12;
550
+ this.uint32[o4 + 7] = v13;
551
+ return i;
552
+ }
553
+
554
+ emplace(i, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) {
555
+ const o2 = i * 16;
556
+ const o4 = i * 8;
557
+ this.int16[o2 + 0] = v0;
558
+ this.int16[o2 + 1] = v1;
559
+ this.int16[o2 + 2] = v2;
560
+ this.int16[o2 + 3] = v3;
561
+ this.uint16[o2 + 4] = v4;
562
+ this.uint16[o2 + 5] = v5;
563
+ this.uint16[o2 + 6] = v6;
564
+ this.uint16[o2 + 7] = v7;
565
+ this.uint16[o2 + 8] = v8;
566
+ this.uint16[o2 + 9] = v9;
567
+ this.uint16[o2 + 10] = v10;
568
+ this.uint16[o2 + 11] = v11;
569
+ this.uint16[o2 + 12] = v12;
570
+ this.uint32[o4 + 7] = v13;
571
+ return i;
572
+ }
573
+ }
574
+
575
+ StructArrayLayout4i9ui1ul32.prototype.bytesPerElement = 32;
576
+ register('StructArrayLayout4i9ui1ul32', StructArrayLayout4i9ui1ul32);
577
+
516
578
  /**
517
579
  * Implementation of the StructArray layout:
518
580
  * [0]: Float32[1]
@@ -974,6 +1036,111 @@ class PlacedSymbolArray extends StructArrayLayout2i2ui3ul3ui2f2ub40 {
974
1036
 
975
1037
  register('PlacedSymbolArray', PlacedSymbolArray);
976
1038
 
1039
+ class SymbolInstanceStruct extends Struct {
1040
+ get anchorX() {
1041
+ return this._structArray.int16[this._pos2 + 0];
1042
+ }
1043
+ set anchorX(x) {
1044
+ this._structArray.int16[this._pos2 + 0] = x;
1045
+ }
1046
+ get anchorY() {
1047
+ return this._structArray.int16[this._pos2 + 1];
1048
+ }
1049
+ set anchorY(x) {
1050
+ this._structArray.int16[this._pos2 + 1] = x;
1051
+ }
1052
+ get horizontalPlacedTextSymbolIndex() {
1053
+ return this._structArray.int16[this._pos2 + 2];
1054
+ }
1055
+ set horizontalPlacedTextSymbolIndex(x) {
1056
+ this._structArray.int16[this._pos2 + 2] = x;
1057
+ }
1058
+ get verticalPlacedTextSymbolIndex() {
1059
+ return this._structArray.int16[this._pos2 + 3];
1060
+ }
1061
+ set verticalPlacedTextSymbolIndex(x) {
1062
+ this._structArray.int16[this._pos2 + 3] = x;
1063
+ }
1064
+ get key() {
1065
+ return this._structArray.uint16[this._pos2 + 4];
1066
+ }
1067
+ set key(x) {
1068
+ this._structArray.uint16[this._pos2 + 4] = x;
1069
+ }
1070
+ get textBoxStartIndex() {
1071
+ return this._structArray.uint16[this._pos2 + 5];
1072
+ }
1073
+ set textBoxStartIndex(x) {
1074
+ this._structArray.uint16[this._pos2 + 5] = x;
1075
+ }
1076
+ get textBoxEndIndex() {
1077
+ return this._structArray.uint16[this._pos2 + 6];
1078
+ }
1079
+ set textBoxEndIndex(x) {
1080
+ this._structArray.uint16[this._pos2 + 6] = x;
1081
+ }
1082
+ get iconBoxStartIndex() {
1083
+ return this._structArray.uint16[this._pos2 + 7];
1084
+ }
1085
+ set iconBoxStartIndex(x) {
1086
+ this._structArray.uint16[this._pos2 + 7] = x;
1087
+ }
1088
+ get iconBoxEndIndex() {
1089
+ return this._structArray.uint16[this._pos2 + 8];
1090
+ }
1091
+ set iconBoxEndIndex(x) {
1092
+ this._structArray.uint16[this._pos2 + 8] = x;
1093
+ }
1094
+ get featureIndex() {
1095
+ return this._structArray.uint16[this._pos2 + 9];
1096
+ }
1097
+ set featureIndex(x) {
1098
+ this._structArray.uint16[this._pos2 + 9] = x;
1099
+ }
1100
+ get numGlyphVertices() {
1101
+ return this._structArray.uint16[this._pos2 + 10];
1102
+ }
1103
+ set numGlyphVertices(x) {
1104
+ this._structArray.uint16[this._pos2 + 10] = x;
1105
+ }
1106
+ get numVerticalGlyphVertices() {
1107
+ return this._structArray.uint16[this._pos2 + 11];
1108
+ }
1109
+ set numVerticalGlyphVertices(x) {
1110
+ this._structArray.uint16[this._pos2 + 11] = x;
1111
+ }
1112
+ get numIconVertices() {
1113
+ return this._structArray.uint16[this._pos2 + 12];
1114
+ }
1115
+ set numIconVertices(x) {
1116
+ this._structArray.uint16[this._pos2 + 12] = x;
1117
+ }
1118
+ get crossTileID() {
1119
+ return this._structArray.uint32[this._pos4 + 7];
1120
+ }
1121
+ set crossTileID(x) {
1122
+ this._structArray.uint32[this._pos4 + 7] = x;
1123
+ }
1124
+ }
1125
+
1126
+ SymbolInstanceStruct.prototype.size = 32;
1127
+
1128
+ /**
1129
+ * @private
1130
+ */
1131
+ class SymbolInstanceArray extends StructArrayLayout4i9ui1ul32 {
1132
+ /**
1133
+ * Return the SymbolInstanceStruct at the given location in the array.
1134
+ * @param {number} index The index of the element.
1135
+ */
1136
+ get(index) {
1137
+ assert(!this.isTransferred);
1138
+ return new SymbolInstanceStruct(this, index);
1139
+ }
1140
+ }
1141
+
1142
+ register('SymbolInstanceArray', SymbolInstanceArray);
1143
+
977
1144
  class GlyphOffsetStruct extends Struct {
978
1145
  get offsetX() {
979
1146
  return this._structArray.float32[this._pos4 + 0];
@@ -1104,6 +1271,7 @@ module.exports = {
1104
1271
  StructArrayLayout2i2i2i12,
1105
1272
  StructArrayLayout2ub4,
1106
1273
  StructArrayLayout2i2ui3ul3ui2f2ub40,
1274
+ StructArrayLayout4i9ui1ul32,
1107
1275
  StructArrayLayout1f4,
1108
1276
  StructArrayLayout3i6,
1109
1277
  StructArrayLayout1ul2ui8,
@@ -1134,5 +1302,6 @@ module.exports = {
1134
1302
  FeatureIndexArray,
1135
1303
  GlyphOffsetArray,
1136
1304
  PlacedSymbolArray,
1305
+ SymbolInstanceArray,
1137
1306
  SymbolLineVertexArray
1138
1307
  };
@@ -73,6 +73,23 @@ const placement = createLayout([
73
73
  { type: 'Uint8', name: 'hidden' }
74
74
  ]);
75
75
 
76
+ const symbolInstance = createLayout([
77
+ { type: 'Int16', name: 'anchorX' },
78
+ { type: 'Int16', name: 'anchorY' },
79
+ { type: 'Int16', name: 'horizontalPlacedTextSymbolIndex' },
80
+ { type: 'Int16', name: 'verticalPlacedTextSymbolIndex' },
81
+ { type: 'Uint16', name: 'key' },
82
+ { type: 'Uint16', name: 'textBoxStartIndex' },
83
+ { type: 'Uint16', name: 'textBoxEndIndex' },
84
+ { type: 'Uint16', name: 'iconBoxStartIndex' },
85
+ { type: 'Uint16', name: 'iconBoxEndIndex' },
86
+ { type: 'Uint16', name: 'featureIndex' },
87
+ { type: 'Uint16', name: 'numGlyphVertices' },
88
+ { type: 'Uint16', name: 'numVerticalGlyphVertices' },
89
+ { type: 'Uint16', name: 'numIconVertices' },
90
+ { type: 'Uint32', name: 'crossTileID' }
91
+ ]);
92
+
76
93
  const glyphOffset = createLayout([{ type: 'Float32', name: 'offsetX' }]);
77
94
 
78
95
  const lineVertex = createLayout([
@@ -90,6 +107,7 @@ module.exports = {
90
107
  collisionBoxLayout,
91
108
  collisionCircleLayout,
92
109
  placement,
110
+ symbolInstance,
93
111
  glyphOffset,
94
112
  lineVertex
95
113
  };
@@ -14,6 +14,7 @@ const {
14
14
  CollisionCircleLayoutArray,
15
15
  CollisionVertexArray,
16
16
  PlacedSymbolArray,
17
+ SymbolInstanceArray,
17
18
  GlyphOffsetArray,
18
19
  SymbolLineVertexArray
19
20
  } = require('../array_types');
@@ -31,7 +32,7 @@ const { verticalizedCharacterMap } = require('../../util/verticalize_punctuation
31
32
  const { getSizeData } = require('../../symbol/symbol_size');
32
33
  const { register } = require('../../util/transfer_registry');
33
34
  const EvaluationParameters = require('../../style/evaluation_parameters');
34
- const { Formatted } = require('../../style-spec/expression/definitions/formatted');
35
+ const { Formatted } = require('../../style-spec/expression/types/formatted');
35
36
 
36
37
  // Opacity arrays are frequently updated but don't contain a lot of information, so we pack them
37
38
  // tight. Each Uint32 is actually four duplicate Uint8s for the four corners of a glyph
@@ -190,11 +191,13 @@ class SymbolBucket {
190
191
  this.iconSizeData = getSizeData(this.zoom, unevaluatedLayoutValues['icon-size']);
191
192
 
192
193
  const layout = this.layers[0].layout;
194
+ const zOrderByViewportY = layout.get('symbol-z-order') === 'viewport-y';
193
195
  this.sortFeaturesByY =
194
- layout.get('text-allow-overlap') ||
195
- layout.get('icon-allow-overlap') ||
196
- layout.get('text-ignore-placement') ||
197
- layout.get('icon-ignore-placement');
196
+ zOrderByViewportY &&
197
+ (layout.get('text-allow-overlap') ||
198
+ layout.get('icon-allow-overlap') ||
199
+ layout.get('text-ignore-placement') ||
200
+ layout.get('icon-ignore-placement'));
198
201
 
199
202
  this.sourceID = options.sourceID;
200
203
  }
@@ -220,6 +223,7 @@ class SymbolBucket {
220
223
 
221
224
  this.glyphOffsetArray = new GlyphOffsetArray();
222
225
  this.lineVertexArray = new SymbolLineVertexArray();
226
+ this.symbolInstances = new SymbolInstanceArray();
223
227
  }
224
228
 
225
229
  calculateGlyphDependencies(text, stack, textAlongLine, doesAllowVerticalWritingMode) {
@@ -263,8 +267,15 @@ class SymbolBucket {
263
267
 
264
268
  let text;
265
269
  if (hasText) {
266
- text = layer.getValueAndResolveTokens('text-field', feature);
267
- text = transformText(text, layer, feature);
270
+ // Expression evaluation will automatically coerce to Formatted
271
+ // but plain string token evaluation skips that pathway so do the
272
+ // conversion here.
273
+ const resolvedTokens = layer.getValueAndResolveTokens('text-field', feature);
274
+ text = transformText(
275
+ resolvedTokens instanceof Formatted ? resolvedTokens : Formatted.fromString(resolvedTokens),
276
+ layer,
277
+ feature
278
+ );
268
279
  }
269
280
 
270
281
  let icon;
@@ -296,19 +307,13 @@ class SymbolBucket {
296
307
 
297
308
  if (text) {
298
309
  const fontStack = textFont.evaluate(feature, {}).join(',');
299
- const stack = (stacks[fontStack] = stacks[fontStack] || {});
300
310
  const textAlongLine =
301
311
  layout.get('text-rotation-alignment') === 'map' && layout.get('symbol-placement') !== 'point';
302
- if (text instanceof Formatted) {
303
- for (const section of text.sections) {
304
- const doesAllowVerticalWritingMode = allowsVerticalWritingMode(text.toString());
305
- const sectionFont = section.fontStack || fontStack;
306
- const sectionStack = (stacks[sectionFont] = stacks[sectionFont] || {});
307
- this.calculateGlyphDependencies(section.text, sectionStack, textAlongLine, doesAllowVerticalWritingMode);
308
- }
309
- } else {
310
- const doesAllowVerticalWritingMode = allowsVerticalWritingMode(text);
311
- this.calculateGlyphDependencies(text, stack, textAlongLine, doesAllowVerticalWritingMode);
312
+ for (const section of text.sections) {
313
+ const doesAllowVerticalWritingMode = allowsVerticalWritingMode(text.toString());
314
+ const sectionFont = section.fontStack || fontStack;
315
+ const sectionStack = (stacks[sectionFont] = stacks[sectionFont] || {});
316
+ this.calculateGlyphDependencies(section.text, sectionStack, textAlongLine, doesAllowVerticalWritingMode);
312
317
  }
313
318
  }
314
319
  }
@@ -455,15 +460,15 @@ class SymbolBucket {
455
460
  arrays.programConfigurations.populatePaintArrays(arrays.layoutVertexArray.length, feature, feature.index, {});
456
461
  }
457
462
 
458
- _addCollisionDebugVertex(layoutVertexArray, collisionVertexArray, point, anchor, extrude) {
463
+ _addCollisionDebugVertex(layoutVertexArray, collisionVertexArray, point, anchorX, anchorY, extrude) {
459
464
  collisionVertexArray.emplaceBack(0, 0);
460
465
  return layoutVertexArray.emplaceBack(
461
466
  // pos
462
467
  point.x,
463
468
  point.y,
464
469
  // a_anchor_pos
465
- anchor.x,
466
- anchor.y,
470
+ anchorX,
471
+ anchorY,
467
472
  // extrude
468
473
  Math.round(extrude.x),
469
474
  Math.round(extrude.y)
@@ -477,32 +482,39 @@ class SymbolBucket {
477
482
  const layoutVertexArray = arrays.layoutVertexArray;
478
483
  const collisionVertexArray = arrays.collisionVertexArray;
479
484
 
485
+ const anchorX = symbolInstance.anchorX;
486
+ const anchorY = symbolInstance.anchorY;
487
+
480
488
  this._addCollisionDebugVertex(
481
489
  layoutVertexArray,
482
490
  collisionVertexArray,
483
491
  boxAnchorPoint,
484
- symbolInstance.anchor,
492
+ anchorX,
493
+ anchorY,
485
494
  new Point(x1, y1)
486
495
  );
487
496
  this._addCollisionDebugVertex(
488
497
  layoutVertexArray,
489
498
  collisionVertexArray,
490
499
  boxAnchorPoint,
491
- symbolInstance.anchor,
500
+ anchorX,
501
+ anchorY,
492
502
  new Point(x2, y1)
493
503
  );
494
504
  this._addCollisionDebugVertex(
495
505
  layoutVertexArray,
496
506
  collisionVertexArray,
497
507
  boxAnchorPoint,
498
- symbolInstance.anchor,
508
+ anchorX,
509
+ anchorY,
499
510
  new Point(x2, y2)
500
511
  );
501
512
  this._addCollisionDebugVertex(
502
513
  layoutVertexArray,
503
514
  collisionVertexArray,
504
515
  boxAnchorPoint,
505
- symbolInstance.anchor,
516
+ anchorX,
517
+ anchorY,
506
518
  new Point(x1, y2)
507
519
  );
508
520
 
@@ -524,49 +536,41 @@ class SymbolBucket {
524
536
  }
525
537
  }
526
538
 
527
- generateCollisionDebugBuffers() {
528
- for (const symbolInstance of this.symbolInstances) {
529
- symbolInstance.textCollisionFeature = {
530
- boxStartIndex: symbolInstance.textBoxStartIndex,
531
- boxEndIndex: symbolInstance.textBoxEndIndex
532
- };
533
- symbolInstance.iconCollisionFeature = {
534
- boxStartIndex: symbolInstance.iconBoxStartIndex,
535
- boxEndIndex: symbolInstance.iconBoxEndIndex
536
- };
539
+ addDebugCollisionBoxes(startIndex, endIndex, symbolInstance) {
540
+ for (let b = startIndex; b < endIndex; b++) {
541
+ const box = this.collisionBoxArray.get(b);
542
+ const x1 = box.x1;
543
+ const y1 = box.y1;
544
+ const x2 = box.x2;
545
+ const y2 = box.y2;
546
+
547
+ // If the radius > 0, this collision box is actually a circle
548
+ // The data we add to the buffers is exactly the same, but we'll render with a different shader.
549
+ const isCircle = box.radius > 0;
550
+ this.addCollisionDebugVertices(
551
+ x1,
552
+ y1,
553
+ x2,
554
+ y2,
555
+ isCircle ? this.collisionCircle : this.collisionBox,
556
+ box.anchorPoint,
557
+ symbolInstance,
558
+ isCircle
559
+ );
560
+ }
561
+ }
537
562
 
538
- for (let i = 0; i < 2; i++) {
539
- const feature = symbolInstance[i === 0 ? 'textCollisionFeature' : 'iconCollisionFeature'];
540
- if (!feature) continue;
541
-
542
- for (let b = feature.boxStartIndex; b < feature.boxEndIndex; b++) {
543
- const box = this.collisionBoxArray.get(b);
544
- const x1 = box.x1;
545
- const y1 = box.y1;
546
- const x2 = box.x2;
547
- const y2 = box.y2;
548
-
549
- // If the radius > 0, this collision box is actually a circle
550
- // The data we add to the buffers is exactly the same, but we'll render with a different shader.
551
- const isCircle = box.radius > 0;
552
- this.addCollisionDebugVertices(
553
- x1,
554
- y1,
555
- x2,
556
- y2,
557
- isCircle ? this.collisionCircle : this.collisionBox,
558
- box.anchorPoint,
559
- symbolInstance,
560
- isCircle
561
- );
562
- }
563
- }
563
+ generateCollisionDebugBuffers() {
564
+ for (let i = 0; i < this.symbolInstances.length; i++) {
565
+ const symbolInstance = this.symbolInstances.get(i);
566
+ this.addDebugCollisionBoxes(symbolInstance.textBoxStartIndex, symbolInstance.textBoxEndIndex, symbolInstance);
567
+ this.addDebugCollisionBoxes(symbolInstance.iconBoxStartIndex, symbolInstance.iconBoxEndIndex, symbolInstance);
564
568
  }
565
569
  }
566
570
 
567
571
  // These flat arrays are meant to be quicker to iterate over than the source
568
572
  // CollisionBoxArray
569
- deserializeCollisionBoxes(collisionBoxArray, textStartIndex, textEndIndex, iconStartIndex, iconEndIndex) {
573
+ _deserializeCollisionBoxesForSymbol(collisionBoxArray, textStartIndex, textEndIndex, iconStartIndex, iconEndIndex) {
570
574
  const collisionArrays = {};
571
575
  for (let k = textStartIndex; k < textEndIndex; k++) {
572
576
  const box = collisionBoxArray.get(k);
@@ -614,6 +618,22 @@ class SymbolBucket {
614
618
  return collisionArrays;
615
619
  }
616
620
 
621
+ deserializeCollisionBoxes(collisionBoxArray) {
622
+ this.collisionArrays = [];
623
+ for (let i = 0; i < this.symbolInstances.length; i++) {
624
+ const symbolInstance = this.symbolInstances.get(i);
625
+ this.collisionArrays.push(
626
+ this._deserializeCollisionBoxesForSymbol(
627
+ collisionBoxArray,
628
+ symbolInstance.textBoxStartIndex,
629
+ symbolInstance.textBoxEndIndex,
630
+ symbolInstance.iconBoxStartIndex,
631
+ symbolInstance.iconBoxEndIndex
632
+ )
633
+ );
634
+ }
635
+ }
636
+
617
637
  hasTextData() {
618
638
  return this.text.segments.get().length > 0;
619
639
  }
@@ -630,6 +650,16 @@ class SymbolBucket {
630
650
  return this.collisionCircle.segments.get().length > 0;
631
651
  }
632
652
 
653
+ addIndicesForPlacedTextSymbol(placedTextSymbolIndex) {
654
+ const placedSymbol = this.text.placedSymbolArray.get(placedTextSymbolIndex);
655
+
656
+ const endIndex = placedSymbol.vertexStartIndex + placedSymbol.numGlyphs * 4;
657
+ for (let vertexIndex = placedSymbol.vertexStartIndex; vertexIndex < endIndex; vertexIndex += 4) {
658
+ this.text.indexArray.emplaceBack(vertexIndex, vertexIndex + 1, vertexIndex + 2);
659
+ this.text.indexArray.emplaceBack(vertexIndex + 1, vertexIndex + 2, vertexIndex + 3);
660
+ }
661
+ }
662
+
633
663
  sortFeatures(angle) {
634
664
  if (!this.sortFeaturesByY) return;
635
665
 
@@ -653,12 +683,16 @@ class SymbolBucket {
653
683
  const sin = Math.sin(angle);
654
684
  const cos = Math.cos(angle);
655
685
 
686
+ const rotatedYs = [];
687
+ const featureIndexes = [];
688
+ for (let i = 0; i < this.symbolInstances.length; i++) {
689
+ const symbolInstance = this.symbolInstances.get(i);
690
+ rotatedYs.push(Math.round(sin * symbolInstance.anchorX + cos * symbolInstance.anchorY) | 0);
691
+ featureIndexes.push(symbolInstance.featureIndex);
692
+ }
693
+
656
694
  symbolInstanceIndexes.sort((aIndex, bIndex) => {
657
- const a = this.symbolInstances[aIndex];
658
- const b = this.symbolInstances[bIndex];
659
- const aRotated = Math.round(sin * a.anchor.x + cos * a.anchor.y) | 0;
660
- const bRotated = Math.round(sin * b.anchor.x + cos * b.anchor.y) | 0;
661
- return aRotated - bRotated || b.featureIndex - a.featureIndex;
695
+ return rotatedYs[aIndex] - rotatedYs[bIndex] || featureIndexes[bIndex] - featureIndexes[aIndex];
662
696
  });
663
697
 
664
698
  this.text.indexArray.clear();
@@ -667,17 +701,14 @@ class SymbolBucket {
667
701
  this.featureSortOrder = [];
668
702
 
669
703
  for (const i of symbolInstanceIndexes) {
670
- const symbolInstance = this.symbolInstances[i];
704
+ const symbolInstance = this.symbolInstances.get(i);
671
705
  this.featureSortOrder.push(symbolInstance.featureIndex);
672
706
 
673
- for (const placedTextSymbolIndex of symbolInstance.placedTextSymbolIndices) {
674
- const placedSymbol = this.text.placedSymbolArray.get(placedTextSymbolIndex);
675
-
676
- const endIndex = placedSymbol.vertexStartIndex + placedSymbol.numGlyphs * 4;
677
- for (let vertexIndex = placedSymbol.vertexStartIndex; vertexIndex < endIndex; vertexIndex += 4) {
678
- this.text.indexArray.emplaceBack(vertexIndex, vertexIndex + 1, vertexIndex + 2);
679
- this.text.indexArray.emplaceBack(vertexIndex + 1, vertexIndex + 2, vertexIndex + 3);
680
- }
707
+ if (symbolInstance.horizontalPlacedTextSymbolIndex >= 0) {
708
+ this.addIndicesForPlacedTextSymbol(symbolInstance.horizontalPlacedTextSymbolIndex);
709
+ }
710
+ if (symbolInstance.verticalPlacedTextSymbolIndex >= 0) {
711
+ this.addIndicesForPlacedTextSymbol(symbolInstance.verticalPlacedTextSymbolIndex);
681
712
  }
682
713
 
683
714
  const placedIcon = this.icon.placedSymbolArray.get(i);
@@ -694,8 +725,7 @@ class SymbolBucket {
694
725
  }
695
726
 
696
727
  register('SymbolBucket', SymbolBucket, {
697
- omit: ['layers', 'collisionBoxArray', 'features', 'compareText'],
698
- shallow: ['symbolInstances']
728
+ omit: ['layers', 'collisionBoxArray', 'features', 'compareText']
699
729
  });
700
730
 
701
731
  // this constant is based on the size of StructArray indexes used in a symbol
@@ -177,13 +177,21 @@ class Transform {
177
177
  * @private
178
178
  */
179
179
  getVisibleUnwrappedCoordinates(tileID) {
180
- const ul = this.pointCoordinate(new Point(0, 0), 0);
181
- const ur = this.pointCoordinate(new Point(this.width, 0), 0);
182
- const w0 = Math.floor(ul.column);
183
- const w1 = Math.floor(ur.column);
184
180
  const result = [new UnwrappedTileID(0, tileID)];
185
181
  if (this._renderWorldCopies) {
186
- for (let w = w0; w <= w1; w++) {
182
+ const utl = this.pointCoordinate(new Point(0, 0), 0);
183
+ const utr = this.pointCoordinate(new Point(this.width, 0), 0);
184
+ const ubl = this.pointCoordinate(new Point(this.width, this.height), 0);
185
+ const ubr = this.pointCoordinate(new Point(0, this.height), 0);
186
+ const w0 = Math.floor(Math.min(utl.column, utr.column, ubl.column, ubr.column));
187
+ const w1 = Math.floor(Math.max(utl.column, utr.column, ubl.column, ubr.column));
188
+
189
+ // Add an extra copy of the world on each side to properly render ImageSources and CanvasSources.
190
+ // Both sources draw outside the tile boundaries of the tile that "contains them" so we need
191
+ // to add extra copies on both sides in case offscreen tiles need to draw into on-screen ones.
192
+ const extraWorldCopy = 1;
193
+
194
+ for (let w = w0 - extraWorldCopy; w <= w1 + extraWorldCopy; w++) {
187
195
  if (w === 0) continue;
188
196
  result.push(new UnwrappedTileID(w, tileID));
189
197
  }
@@ -1,14 +1,12 @@
1
- const ShelfPack = require('@mapbox/shelf-pack');
2
-
3
1
  const { AlphaImage } = require('../util/image');
4
2
  const { register } = require('../util/transfer_registry');
3
+ const potpack = require('potpack');
5
4
 
6
5
  const padding = 1;
7
6
 
8
7
  class GlyphAtlas {
9
8
  constructor(stacks) {
10
9
  const positions = {};
11
- const pack = new ShelfPack(0, 0, { autoResize: true });
12
10
  const bins = [];
13
11
 
14
12
  for (const stack in stacks) {
@@ -30,9 +28,8 @@ class GlyphAtlas {
30
28
  }
31
29
  }
32
30
 
33
- pack.pack(bins, { inPlace: true });
34
-
35
- const image = new AlphaImage({ width: pack.w, height: pack.h });
31
+ const { w, h } = potpack(bins);
32
+ const image = new AlphaImage({ width: w ?? 1, height: h ?? 1 });
36
33
 
37
34
  for (const stack in stacks) {
38
35
  const glyphs = stacks[stack];