zincjs 2.4.1-beta.3 → 2.4.1-beta.5

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.
@@ -63,6 +63,7 @@ const Glyph = function (geometry, materialIn, idIn, glyphsetIn) {
63
63
  * @param {String} text - Label to be set for this instance
64
64
  */
65
65
  this.setLabel = text => {
66
+ parent?.requestRender?.();
66
67
  if (text && (typeof text === 'string' || text instanceof String)) {
67
68
  labelString = text;
68
69
  if (this.morph)
@@ -78,6 +79,7 @@ const Glyph = function (geometry, materialIn, idIn, glyphsetIn) {
78
79
  * getColour()) - e.g. genuinely no colour data at all for this glyphset.
79
80
  */
80
81
  this.showLabel = (colour) => {
82
+ parent?.requestRender?.();
81
83
  if (label) {
82
84
  _position = label.getPosition();
83
85
  this.group.remove(label.getSprite());
@@ -88,7 +90,8 @@ const Glyph = function (geometry, materialIn, idIn, glyphsetIn) {
88
90
  label = new Label(labelString, _colour || colour);
89
91
  label.setPosition(_position[0], _position[1], _position[2]);
90
92
  const sprite = label.getSprite();
91
- sprite.material.alphaTest = 0.5;
93
+ //Only discard fully transparent pixels to keep the smooth edges
94
+ sprite.material.alphaTest = 0.05;
92
95
  sprite.material.transparent = true;
93
96
  sprite.material.depthWrite = false;
94
97
  this.group.add(label.getSprite());
@@ -99,6 +102,7 @@ const Glyph = function (geometry, materialIn, idIn, glyphsetIn) {
99
102
  * Hide label with the choosen colour.
100
103
  */
101
104
  this.hideLabel = () => {
105
+ parent?.requestRender?.();
102
106
  if (label) {
103
107
  _position = label.getPosition();
104
108
  this.group.remove(label.getSprite());
@@ -135,6 +139,7 @@ const Glyph = function (geometry, materialIn, idIn, glyphsetIn) {
135
139
  * transformation.
136
140
  */
137
141
  this.setTransformation = (position, axis1, axis2, axis3) => {
142
+ parent?.requestRender?.();
138
143
  if (this.morph) {
139
144
  this.morph.matrix.elements[0] = axis1[0];
140
145
  this.morph.matrix.elements[1] = axis1[1];
@@ -170,6 +175,7 @@ const Glyph = function (geometry, materialIn, idIn, glyphsetIn) {
170
175
  * @param {THREE.Color} color - Colour to be set.
171
176
  */
172
177
  this.setColour = (color) => {
178
+ parent?.requestRender?.();
173
179
  _colour = color ? color.clone() : undefined;
174
180
  if (label)
175
181
  label.setColour(color);
@@ -190,6 +196,10 @@ const Glyph = function (geometry, materialIn, idIn, glyphsetIn) {
190
196
  * Clear and free its memory.
191
197
  */
192
198
  this.dispose = () => {
199
+ if (label) {
200
+ label.dispose();
201
+ label = undefined;
202
+ }
193
203
  if (this.material)
194
204
  this.material.dispose();
195
205
  this.morph = undefined;
@@ -1,6 +1,7 @@
1
1
  import * as THREE from 'three/webgpu';
2
2
  import { Glyph } from './glyph';
3
3
  import { ZincObject } from './zincObject';
4
+ import { updateWorldMatrixFromAncestors } from '../utilities';
4
5
  import { JSONLoader } from '../loaders/JSONLoader';
5
6
  import { createGlyphTransformCompute, dispatchAndReadbackGlyphTransform, readbackGlyphTransform } from '../tsl/glyphTransform';
6
7
  import { createGlyphInstancedMaterial } from '../tsl/glyphRenderMaterial';
@@ -22,6 +23,8 @@ const Glyphset = function () {
22
23
  let axis2s = undefined;
23
24
  let axis3s = undefined;
24
25
  let positions = undefined;
26
+ //Glyph geometry loaded after dispose is discarded
27
+ let disposed = false;
25
28
  let scales = undefined;
26
29
  let colors = undefined;
27
30
  let labels = undefined;
@@ -69,6 +72,9 @@ const Glyphset = function () {
69
72
  // for ACCURATE_RESYNC_DEBOUNCE_MS of quiet.
70
73
  let accurateResyncTimer = undefined;
71
74
  const ACCURATE_RESYNC_DEBOUNCE_MS = 500;
75
+ //Set to false when the static (non morphing) transformation needs to be
76
+ //re-applied, e.g. after a scale change.
77
+ let staticTransformationApplied = false;
72
78
  for (let i = 0; i < 8; i++) {
73
79
  _points[i] = new THREE.Vector3();
74
80
  }
@@ -149,6 +155,7 @@ const Glyphset = function () {
149
155
  * geometry is loaded.
150
156
  */
151
157
  this.load = (glyphsetData, glyphURL, finishCallback, isInline, displayLabels) => {
158
+ disposed = false;
152
159
  axis1s = glyphsetData.axis1;
153
160
  axis2s = glyphsetData.axis2;
154
161
  axis3s = glyphsetData.axis3;
@@ -440,6 +447,7 @@ const Glyphset = function () {
440
447
  * completely unchanged downstream.
441
448
  */
442
449
  const applyGlyphComputeResult = (result) => {
450
+ this.requestRender();
443
451
  const matrixArray = this.morph.instanceMatrix.array;
444
452
  const updateLabels = this.canShowLabel();
445
453
  for (let i = 0; i < numberOfVertices; i++) {
@@ -540,6 +548,7 @@ const Glyphset = function () {
540
548
  * all, bouding box will not be updated.
541
549
  */
542
550
  const dispatchGlyphComputeFast = (bottom_frame, top_frame, proportion) => {
551
+ this.requestRender();
543
552
  const renderer = this.region?.getScene?.()?.getRenderer?.();
544
553
  if (!renderer) return false;
545
554
  glyphCompute.uniforms.bottomFrame.value = bottom_frame;
@@ -663,8 +672,13 @@ const Glyphset = function () {
663
672
  current_axis3s = axis3s["0"];
664
673
  current_scales = scales["0"];
665
674
  }
666
- updateGlyphsetTransformation(current_positions, current_axis1s, current_axis2s, current_axis3s,
667
- current_scales);
675
+ //Colour only morphing does not change the transformation, skip it
676
+ //unless it is out of date.
677
+ if (morphVertices || !staticTransformationApplied) {
678
+ updateGlyphsetTransformation(current_positions, current_axis1s, current_axis2s, current_axis3s,
679
+ current_scales);
680
+ staticTransformationApplied = !morphVertices;
681
+ }
668
682
  if (colors != undefined) {
669
683
  if (morphColours) {
670
684
  const bottom_colors = colors[bottom_frame.toString()];
@@ -710,6 +724,7 @@ const Glyphset = function () {
710
724
  * Display the label of the glyphs in the glyphset.
711
725
  */
712
726
  this.showLabel = () => {
727
+ this.requestRender();
713
728
  if (glyphList?.length) {
714
729
  labelsOn = true;
715
730
  for (let i = 0; i < glyphList.length; i++) {
@@ -722,6 +737,7 @@ const Glyphset = function () {
722
737
  * Hide label with the choosen colour.
723
738
  */
724
739
  this.hideLabel = () => {
740
+ this.requestRender();
725
741
  for (let i = 0; i < glyphList.length; i++) {
726
742
  glyphList[i].hideLabel();
727
743
  }
@@ -801,6 +817,7 @@ const Glyphset = function () {
801
817
  //Update the transformation of the glyphs.
802
818
  updateGlyphsetTransformation(positions["0"], axis1s["0"],
803
819
  axis2s["0"], axis3s["0"], scales["0"]);
820
+ staticTransformationApplied = true;
804
821
  if (colors != undefined) {
805
822
  updateGlyphsetHexColors(colors["0"], !!(glyphCompute && glyphCompute.outputs.color));
806
823
  }
@@ -816,6 +833,7 @@ const Glyphset = function () {
816
833
  * @param {Glyph} Glyph to be added.
817
834
  */
818
835
  this.addCustomGlyph = glyph => {
836
+ this.requestRender();
819
837
  if (glyph.isGlyph)
820
838
  glyphList.push(glyph);
821
839
  this.ready = true;
@@ -829,6 +847,7 @@ const Glyphset = function () {
829
847
  * @param {Number} id of the mesh.
830
848
  */
831
849
  this.addMeshAsGlyph = (mesh, id) => {
850
+ this.requestRender();
832
851
  if (mesh.isMesh) {
833
852
  const glyph = new Glyph(undefined, undefined, id, this);
834
853
  glyph.fromMesh(mesh);
@@ -856,6 +875,10 @@ const Glyphset = function () {
856
875
 
857
876
  var meshloader = (finishCallback, displayLabels) => {
858
877
  return (geometry, materials) => {
878
+ if (disposed) {
879
+ geometry.dispose();
880
+ return;
881
+ }
859
882
  this.geometry.copy(geometry);
860
883
  this.geometry.computeBoundingSphere();
861
884
  this.geometry.computeBoundingBox();
@@ -937,8 +960,7 @@ const Glyphset = function () {
937
960
  if (this.morph && this.ready && this.morph.visible) {
938
961
  if (glyphCompute && !boundsAreExact && allFramesBoundingBox) {
939
962
  this.cachedBoundingBox.copy(allFramesBoundingBox);
940
- this.morph.updateWorldMatrix(true, true);
941
- this.cachedBoundingBox.applyMatrix4(this.morph.matrixWorld);
963
+ this.cachedBoundingBox.applyMatrix4(updateWorldMatrixFromAncestors(this.morph));
942
964
  return this.cachedBoundingBox;
943
965
  }
944
966
  if (this.boundingBoxUpdateRequired) {
@@ -955,8 +977,7 @@ const Glyphset = function () {
955
977
  }
956
978
  if (_boundingBox3) {
957
979
  this.cachedBoundingBox.copy(_boundingBox3);
958
- this.morph.updateWorldMatrix(true, true);
959
- this.cachedBoundingBox.applyMatrix4(this.morph.matrixWorld);
980
+ this.cachedBoundingBox.applyMatrix4(updateWorldMatrixFromAncestors(this.morph));
960
981
  this.boundingBoxUpdateRequired = false;
961
982
  } else
962
983
  return undefined;
@@ -972,6 +993,7 @@ const Glyphset = function () {
972
993
  * @param {Number} time - Can be any value between 0 to duration.
973
994
  */
974
995
  this.setMorphTime = time => {
996
+ this.requestRender();
975
997
  if (time > this.duration)
976
998
  this.inbuildTime = this.duration;
977
999
  else if (0 > time)
@@ -1055,7 +1077,9 @@ const Glyphset = function () {
1055
1077
  * @return {THREE.Box3}.
1056
1078
  */
1057
1079
  this.setScaleAll = function(scale) {
1080
+ this.requestRender();
1058
1081
  this.globalScale = scale;
1082
+ staticTransformationApplied = false;
1059
1083
  updateMorphGlyphsets(false);
1060
1084
  }
1061
1085
 
@@ -1063,6 +1087,7 @@ const Glyphset = function () {
1063
1087
  * Clear this glyphset and its list of glyphs which will release them from the memory.
1064
1088
  */
1065
1089
  this.dispose = () => {
1090
+ disposed = true;
1066
1091
  for (let i = glyphList.length - 1; i >= 0; i--) {
1067
1092
  glyphList[i].dispose();
1068
1093
  }
@@ -1090,12 +1115,13 @@ const Glyphset = function () {
1090
1115
  /**
1091
1116
  * Update the glyphsets if required the render.
1092
1117
  */
1093
- this.render = (delta, playAnimation, options) => {
1118
+ this.render = (delta, playAnimation, cameraControls, options) => {
1094
1119
  if (glyphCompute && !renderBuffersInitialized) {
1095
1120
  const renderer = this.region?.getScene?.()?.getRenderer?.();
1096
1121
  if (renderer) {
1097
1122
  renderer.compute(glyphCompute.compute);
1098
1123
  renderBuffersInitialized = true;
1124
+ this.requestRender();
1099
1125
  }
1100
1126
  }
1101
1127
  if (playAnimation == true) {
@@ -1,6 +1,9 @@
1
- import * as THREE from 'three/webgpu';
2
- import SpriteTextModule from 'three-spritetext';
3
- const SpriteText = SpriteTextModule.default || SpriteTextModule;
1
+ import {
2
+ applyTextSpriteTextureSettings,
3
+ createTextSprite,
4
+ releaseTextSprite,
5
+ setTextSpriteHeight,
6
+ } from '../textSprite';
4
7
 
5
8
  /**
6
9
  * Bitmap labels, this is used with {@link Glyph} to
@@ -21,25 +24,16 @@ const Label = function (textIn, colourIn) {
21
24
  let size = 1.0;
22
25
  let fontWeight = 500;
23
26
  const textHeight = 0.012;
24
- if (colourIn)
25
- sprite = new SpriteText(text, textHeight, colourIn.getStyle());
26
- else
27
- sprite = new SpriteText(text, textHeight);
28
- sprite.fontFace = "Asap";
29
- sprite.fontSize = 90;
30
- sprite.fontWeight = fontWeight;
31
- const canvasTexture = sprite.material.map; // Snag the canvas texture generated by the library
32
- sprite.material = new THREE.SpriteNodeMaterial({
33
- map: canvasTexture,
34
- });
35
- sprite.material.map.generateMipmaps = true;
36
- sprite.material.map.anisotropy = 4;
37
- sprite.material.minFilter = THREE.LinearMipmapLinearFilter; // Smooth downscaling
38
- sprite.material.magFilter = THREE.LinearFilter;
39
- sprite.material.sizeAttenuation = false;
27
+ //The canvas resolution is chosen from the size of the text on screen
28
+ sprite = createTextSprite(text, textHeight,
29
+ colourIn ? colourIn.getStyle() : undefined, "Asap", fontWeight);
40
30
  sprite.center.x = -0.05;
41
31
  sprite.center.y = 0;
42
-
32
+ //SpriteText replaces the texture whenever the text, colour or size
33
+ //changes, the settings need to be re-applied to the new texture.
34
+ const applyTextureSettings = () => {
35
+ applyTextSpriteTextureSettings(sprite);
36
+ }
43
37
 
44
38
 
45
39
  /**
@@ -78,7 +72,13 @@ const Label = function (textIn, colourIn) {
78
72
  */
79
73
  this.setColour = colourIn => {
80
74
  if (colourIn) {
81
- sprite.color = colourIn.getStyle();
75
+ //Changing the colour redraws the canvas and creates a new texture,
76
+ //only do it when the colour has changed.
77
+ const style = colourIn.getStyle();
78
+ if (style !== sprite.color) {
79
+ sprite.color = style;
80
+ applyTextureSettings();
81
+ }
82
82
  colour = colourIn;
83
83
  }
84
84
  }
@@ -111,7 +111,8 @@ const Label = function (textIn, colourIn) {
111
111
  */
112
112
  this.setSize = sizeIn => {
113
113
  if (sizeIn > 0.0) {
114
- sprite.textHeight = textHeight * sizeIn;
114
+ //Redraw at the resolution matching the new size
115
+ setTextSpriteHeight(sprite, textHeight * sizeIn);
115
116
  size = sizeIn;
116
117
  }
117
118
  }
@@ -124,6 +125,7 @@ const Label = function (textIn, colourIn) {
124
125
  this.setFontWeight = fontWeightIn => {
125
126
  if (fontWeightIn && fontWeightIn !== fontWeight) {
126
127
  sprite.fontWeight = fontWeightIn;
128
+ applyTextureSettings();
127
129
  fontWeight = fontWeightIn;
128
130
  }
129
131
  }
@@ -149,9 +151,10 @@ const Label = function (textIn, colourIn) {
149
151
  sprite._canvas.height = 1;
150
152
  }
151
153
  sprite.text = textIn;
152
- sprite.textHeight = textHeight * size;
154
+ setTextSpriteHeight(sprite, textHeight * size);
153
155
  text = textIn;
154
156
  if (sprite.material && sprite.material.map) {
157
+ applyTextureSettings();
155
158
  sprite.material.map.needsUpdate = true;
156
159
  }
157
160
  }
@@ -170,7 +173,19 @@ const Label = function (textIn, colourIn) {
170
173
  * Free up the memory
171
174
  */
172
175
  this.dispose = () => {
173
- //sprite.dispose();
176
+ if (sprite) {
177
+ releaseTextSprite(sprite);
178
+ sprite.removeFromParent();
179
+ if (sprite.material) {
180
+ sprite.material.map?.dispose();
181
+ sprite.material.dispose();
182
+ }
183
+ //Release the canvas memory
184
+ if (sprite._canvas) {
185
+ sprite._canvas.width = 0;
186
+ sprite._canvas.height = 0;
187
+ }
188
+ }
174
189
  }
175
190
 
176
191
  /**
@@ -53,6 +53,7 @@ const Lines = function () {
53
53
  * @param {Number} width - Width of the lines.
54
54
  */
55
55
  this.setWidth = width => {
56
+ this.requestRender();
56
57
  if (this.morph && this.morph.material) {
57
58
  this.morph.material.linewidth = width;
58
59
  this.morph.material.needsUpdate = true;
@@ -67,6 +68,7 @@ const Lines = function () {
67
68
  * @param {Number} colour - A hex value of the colour for the points
68
69
  */
69
70
  this.addLines = (coords, colour) => {
71
+ this.requestRender();
70
72
  if (coords && coords.length > 0) {
71
73
  const geometry = this.addVertices(coords);
72
74
  let mesh = this.getMorph();
@@ -16,7 +16,70 @@ import { LineSegmentsGeometry } from '../three/line/LineSegmentsGeometry';
16
16
  const Lines2 = function () {
17
17
  Lines.call(this);
18
18
  this.isLines2 = true;
19
- let positions = new Array(300);
19
+ //Shared with the GPU buffer of the mesh, edits are made in place
20
+ let positions = new Float32Array(300);
21
+
22
+ //Grow the positions array if required, returns true if it has
23
+ //been reallocated.
24
+ const ensureCapacity = (length) => {
25
+ if (length > positions.length) {
26
+ //Each segment has two vertices, six values
27
+ const capacity = Math.ceil(Math.max(positions.length * 2, length) / 6) * 6;
28
+ const newPositions = new Float32Array(capacity);
29
+ newPositions.set(positions);
30
+ positions = newPositions;
31
+ return true;
32
+ }
33
+ return false;
34
+ }
35
+
36
+ //Fill the unused part of the array with degenerate segments at coord
37
+ const fillUnused = (start, coord) => {
38
+ for (let index = start; index + 2 < positions.length; index += 3) {
39
+ positions[index] = coord[0];
40
+ positions[index + 1] = coord[1];
41
+ positions[index + 2] = coord[2];
42
+ }
43
+ }
44
+
45
+ //Update the line distances without allocating new buffers
46
+ const updateLineDistances = (mesh) => {
47
+ const geometry = mesh.geometry;
48
+ const distanceStart = geometry.attributes.instanceDistanceStart;
49
+ const instanceStart = geometry.attributes.instanceStart;
50
+ if (!distanceStart || distanceStart.data.array.length !== instanceStart.count * 2) {
51
+ mesh.computeLineDistances();
52
+ return;
53
+ }
54
+ const distances = distanceStart.data.array;
55
+ let total = 0;
56
+ for (let i = 0; i < instanceStart.count; i++) {
57
+ const offset = i * 6;
58
+ const dx = positions[offset + 3] - positions[offset];
59
+ const dy = positions[offset + 4] - positions[offset + 1];
60
+ const dz = positions[offset + 5] - positions[offset + 2];
61
+ distances[i * 2] = total;
62
+ total += Math.sqrt(dx * dx + dy * dy + dz * dz);
63
+ distances[i * 2 + 1] = total;
64
+ }
65
+ distanceStart.data.needsUpdate = true;
66
+ }
67
+
68
+ //Upload the positions after they have been changed
69
+ const updatePositions = (mesh, reallocated) => {
70
+ const instanceStart = mesh.geometry.getAttribute('instanceStart');
71
+ if (reallocated || !instanceStart || instanceStart.data.array !== positions) {
72
+ //Only happens when the capacity has been increased
73
+ mesh.geometry.setPositions(positions);
74
+ mesh.computeLineDistances();
75
+ } else {
76
+ instanceStart.data.needsUpdate = true;
77
+ updateLineDistances(mesh);
78
+ mesh.geometry.computeBoundingBox();
79
+ mesh.geometry.computeBoundingSphere();
80
+ }
81
+ this.boundingBoxUpdateRequired = true;
82
+ }
20
83
 
21
84
  /**
22
85
  * Create the line segements using geometry and material.
@@ -47,6 +110,7 @@ const Lines2 = function () {
47
110
  * @param {Number} width - Width of the lines.
48
111
  */
49
112
  this.setWidth = width => {
113
+ this.requestRender();
50
114
  if (this.morph && this.morph.material) {
51
115
  this.morph.material.linewidth = width;
52
116
  this.morph.material.needsUpdate = true;
@@ -57,12 +121,14 @@ const Lines2 = function () {
57
121
  * Add new vertices into the array
58
122
  */
59
123
  this.addVertices = function(coords) {
124
+ this.requestRender();
60
125
  if (coords && coords.length) {
61
126
  let mesh = this.getMorph();
62
127
  if (!mesh) {
63
128
  this.drawRange = 0;
64
129
  }
65
130
  let index = this.drawRange * 3;
131
+ const reallocated = ensureCapacity(index + coords.length * 3);
66
132
  coords.forEach(coord => {
67
133
  positions[index++] = coord[0];
68
134
  positions[index++] = coord[1];
@@ -71,19 +137,12 @@ const Lines2 = function () {
71
137
  });
72
138
  //fill the rest of the array.
73
139
  if (!mesh) {
74
- while (index < 300) {
75
- positions[index++] = coords[0][0];
76
- positions[index++] = coords[0][1];
77
- positions[index++] = coords[0][2];
140
+ fillUnused(index, coords[0]);
141
+ } else {
142
+ if (reallocated) {
143
+ fillUnused(index, coords[0]);
78
144
  }
79
- }
80
-
81
- if (mesh) {
82
- mesh.geometry.setPositions(positions);
83
- mesh.computeLineDistances();
84
- mesh.geometry.computeBoundingBox();
85
- mesh.geometry.computeBoundingSphere();
86
- this.boundingBoxUpdateRequired = true;
145
+ updatePositions(mesh, reallocated);
87
146
  }
88
147
  }
89
148
  return positions;
@@ -117,6 +176,7 @@ const Lines2 = function () {
117
176
  * Edit Vertice in index.
118
177
  */
119
178
  this.editVertices = function(coords, i) {
179
+ this.requestRender();
120
180
  if (coords && coords.length) {
121
181
  let mesh = this.getMorph();
122
182
  const maxIndex = i + coords.length - 1;
@@ -130,17 +190,8 @@ const Lines2 = function () {
130
190
  positions[index++] = coord[1];
131
191
  positions[index++] = coord[2];
132
192
  });
133
- index = this.drawRange * 3;
134
- while (index < 300) {
135
- positions[index++] = coords[0][0];
136
- positions[index++] = coords[0][1];
137
- positions[index++] = coords[0][2];
138
- }
139
- mesh.geometry.setPositions(positions);
140
- mesh.computeLineDistances();
141
- mesh.geometry.computeBoundingBox();
142
- mesh.geometry.computeBoundingSphere();
143
- this.boundingBoxUpdateRequired = true;
193
+ fillUnused(this.drawRange * 3, coords[0]);
194
+ updatePositions(mesh, false);
144
195
  }
145
196
  }
146
197
  return positions;
@@ -154,6 +205,7 @@ const Lines2 = function () {
154
205
  * @param {Number} colour - A hex value of the colour for the points
155
206
  */
156
207
  this.addLines = (coords, colour) => {
208
+ this.requestRender();
157
209
  if (coords && coords.length > 0) {
158
210
  this.addVertices(coords);
159
211
  let mesh = this.getMorph();
@@ -1,5 +1,5 @@
1
1
  import * as THREE from 'three/webgpu';
2
- import { toBufferGeometry, updateMorphColorAttribute } from '../utilities';
2
+ import { keepIndexType, toBufferGeometry, updateMorphColorAttribute } from '../utilities';
3
3
  import { LineSegments } from '../three/line/LineSegments';
4
4
 
5
5
  /**
@@ -26,12 +26,15 @@ const LOD = function (parent) {
26
26
  this._loader = undefined;
27
27
  //The owning Zinc Object
28
28
  this._parent = parent;
29
+ //Levels loaded after dispose are discarded
30
+ this._disposed = false;
29
31
 
30
32
  /*
31
33
  * Add a level of LOD at the specified distance
32
34
  */
33
35
  this.addLevel = (object, distanceIn) => {
34
36
  if (object) {
37
+ keepIndexType(object.geometry);
35
38
  const distance = Math.abs(distanceIn);
36
39
  let l;
37
40
  for (l = 0; l < this.levels.length; l++) {
@@ -57,6 +60,7 @@ const LOD = function (parent) {
57
60
  */
58
61
  this.levelLoaded = (object, distanceIn) => {
59
62
  if (object) {
63
+ keepIndexType(object.geometry);
60
64
  const distance = Math.abs(distanceIn);
61
65
  for (let l = 0; l < this.levels.length; l++) {
62
66
  if (distance === this.levels[l].distance) {
@@ -68,6 +72,7 @@ const LOD = function (parent) {
68
72
  }
69
73
  }
70
74
  this.checkTransparentMesh();
75
+ this._parent?.requestRender?.();
71
76
  }
72
77
  }
73
78
 
@@ -182,6 +187,7 @@ const LOD = function (parent) {
182
187
  }
183
188
 
184
189
  this.dispose = () => {
190
+ this._disposed = true;
185
191
  this.levels.forEach((level) => {
186
192
  if (level.morph && level.morph.geometry) {
187
193
  level.morph.geometry.dispose();
@@ -212,6 +218,10 @@ const LOD = function (parent) {
212
218
  */
213
219
  this.lodLoader = function (distance) {
214
220
  return (geometryIn) => {
221
+ if (this._disposed) {
222
+ geometryIn.dispose();
223
+ return;
224
+ }
215
225
  const material = this._material;
216
226
  const options = {
217
227
  localTimeEnabled: this._parent.timeEnabled,
@@ -281,10 +291,13 @@ const LOD = function (parent) {
281
291
  this._material = material;
282
292
  if (this._secondaryMaterial) {
283
293
  this._secondaryMaterial.dispose();
294
+ this._secondaryMaterial = undefined;
295
+ }
296
+ if (material.transparent || this.levels.some((level) => level.secondaryMesh)) {
297
+ this._secondaryMaterial = material.clone()
298
+ this._secondaryMaterial.side = THREE.FrontSide;
299
+ this._secondaryMaterial.transparent = true;
284
300
  }
285
- this._secondaryMaterial = material.clone()
286
- this._secondaryMaterial.side = THREE.FrontSide;
287
- this._secondaryMaterial.transparent = true;
288
301
  this.levels.forEach((level) => {
289
302
  if (level.morph) {
290
303
  level.morph.material = this._material;
@@ -377,6 +390,7 @@ const LOD = function (parent) {
377
390
  if (this._currentLevel != visibleIndex) {
378
391
  this._currentLevel = visibleIndex;
379
392
  this.checkTransparentMesh();
393
+ this._parent?.requestRender?.();
380
394
  }
381
395
  }
382
396
  }
@@ -2,9 +2,11 @@ import * as THREE from 'three/webgpu';
2
2
  import myImage from '../assets/mapMarker.svg';
3
3
  import { createNewSpriteText } from '../utilities';
4
4
  import { ZincObject } from './zincObject';
5
+ import { requestRenderAll } from '../renderRequests';
6
+ import { releaseTextSprite } from '../textSprite';
5
7
 
6
8
  const textureLoader = new THREE.TextureLoader();
7
- const texture = textureLoader.load(myImage);
9
+ const texture = textureLoader.load(myImage, requestRenderAll);
8
10
  texture.colorSpace = THREE.SRGBColorSpace;
9
11
  const size = [0.02, 0.03, 1];
10
12
  const spriteMaterial = new THREE.SpriteMaterial({
@@ -153,6 +155,7 @@ const Marker = function(zincObject) {
153
155
  userImage.crossOrigin = "anonymous"
154
156
  userImage.onload = () => {
155
157
  this.setImageForUserSprite(userImage, size);
158
+ this.parent?.requestRender?.();
156
159
  };
157
160
  userImage.src = url;
158
161
  } else {
@@ -173,6 +176,7 @@ const Marker = function(zincObject) {
173
176
  sprite = undefined;
174
177
  }
175
178
  if (label) {
179
+ releaseTextSprite(label);
176
180
  label.material.map.dispose();
177
181
  label.material.dispose();
178
182
  label = undefined;
@@ -188,6 +192,7 @@ const Marker = function(zincObject) {
188
192
  //remove label
189
193
  if (label) {
190
194
  this.morph.remove(label);
195
+ releaseTextSprite(label);
191
196
  label.material.map.dispose();
192
197
  label.material.dispose();
193
198
  label = undefined;
@@ -1,10 +1,12 @@
1
1
  import * as THREE from 'three/webgpu';
2
2
  import { ZincObject } from './zincObject';
3
+ import { requestRenderAll } from '../renderRequests';
4
+ import { releaseTextSprite } from '../textSprite';
3
5
  import mapMarkerOrange from '../assets/mapMarkerOrange.svg';
4
6
  import { createNewSpriteText } from '../utilities';
5
7
 
6
8
  const textureLoader = new THREE.TextureLoader();
7
- const texture = textureLoader.load(mapMarkerOrange);
9
+ const texture = textureLoader.load(mapMarkerOrange, requestRenderAll);
8
10
  texture.colorSpace = THREE.SRGBColorSpace;
9
11
  const size = [0.02, 0.03, 1];
10
12
  const spriteMaterial = new THREE.SpriteMaterial({
@@ -96,6 +98,7 @@ const MarkerCluster = function(sceneIn) {
96
98
  if (sprite.label === undefined || (number !== sprite.number)) {
97
99
  if (sprite.label) {
98
100
  sprite.group.remove(sprite.label);
101
+ releaseTextSprite(sprite.label);
99
102
  sprite.label.material.map.dispose();
100
103
  sprite.label.material.dispose();
101
104
  }
@@ -178,6 +181,7 @@ const MarkerCluster = function(sceneIn) {
178
181
  let clusters = [];
179
182
  getCluster({...this.markers}, clusters);
180
183
  drawClusters(clusters);
184
+ scene?.invalidate?.();
181
185
  start = Date.now();
182
186
  this.markerUpdateRequired = false;
183
187
  }