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.
@@ -2,7 +2,7 @@ import * as THREE from 'three/webgpu';
2
2
  import { Label } from './label';
3
3
  import { InstancedPoints } from '../three/InstancedPoints';
4
4
  import { ZincObject } from './zincObject';
5
- import { getCircularTexture, toBufferGeometry } from '../utilities';
5
+ import { getCircularTexture, toBufferGeometry, updateWorldMatrixFromAncestors } from '../utilities';
6
6
  import { createInstancedPointsMaterial } from '../tsl/pointsMaterial';
7
7
 
8
8
  //Maximum number of points a programmatically built (addPoints) Pointset can
@@ -124,27 +124,26 @@ const Pointset = function () {
124
124
  if (morphVertices) {
125
125
  const bottomPositions = positionFrames[bottomFrame];
126
126
  const topPositions = positionFrames[topFrame];
127
+ //pointPositions shares its array with instancePosition
127
128
  const positions = mesh.pointPositions;
128
129
  const length = activeCount * 3;
129
130
  for (let i = 0; i < length; i++) {
130
131
  positions[i] = proportion * bottomPositions[i] + (1 - proportion) * topPositions[i];
131
132
  }
132
- const instancePosition = mesh.geometry.getAttribute('instancePosition');
133
- instancePosition.array.set(positions.subarray(0, length));
134
- instancePosition.needsUpdate = true;
133
+ mesh.geometry.getAttribute('instancePosition').needsUpdate = true;
135
134
  this.boundingBoxUpdateRequired = true;
136
135
  }
137
136
  if (morphColours && colorFrames) {
138
137
  const bottomColors = colorFrames[Math.min(bottomFrame, colorFrames.length - 1)];
139
138
  const topColors = colorFrames[Math.min(topFrame, colorFrames.length - 1)];
140
- for (let i = 0; i < activeCount; i++) {
141
- const index = i * 3;
142
- _tempColor.setRGB(
143
- proportion * bottomColors[index] + (1 - proportion) * topColors[index],
144
- proportion * bottomColors[index + 1] + (1 - proportion) * topColors[index + 1],
145
- proportion * bottomColors[index + 2] + (1 - proportion) * topColors[index + 2],
146
- );
147
- mesh.setColorAt(i, _tempColor);
139
+ if (!mesh.instanceColor) {
140
+ mesh.setColorAt(0, _tempColor);
141
+ }
142
+ //Write the blended colours straight into the instance colours
143
+ const colors = mesh.instanceColor.array;
144
+ const length = activeCount * 3;
145
+ for (let i = 0; i < length; i++) {
146
+ colors[i] = proportion * bottomColors[i] + (1 - proportion) * topColors[i];
148
147
  }
149
148
  mesh.instanceColor.needsUpdate = true;
150
149
  }
@@ -188,14 +187,13 @@ const Pointset = function () {
188
187
 
189
188
  const mesh = new InstancedPoints(quadGeometry, material, numberOfPoints);
190
189
  mesh.count = numberOfPoints;
191
- mesh.pointPositions = new Float32Array(numberOfPoints * 3);
192
- mesh.pointPositions.set(positionFrames[0]);
193
- mesh.userData = this;
194
- this.drawRange = numberOfPoints;
195
-
196
190
  const instancePosition = quadGeometry.getAttribute('instancePosition');
197
191
  instancePosition.array.set(positionFrames[0]);
198
192
  instancePosition.needsUpdate = true;
193
+ //Share the array to avoid keeping and updating two copies
194
+ mesh.pointPositions = instancePosition.array;
195
+ mesh.userData = this;
196
+ this.drawRange = numberOfPoints;
199
197
 
200
198
  const initialColorFrame = colorFrames ? colorFrames[0] : extractStaticColorFrame(geometry);
201
199
  if (initialColorFrame) {
@@ -230,7 +228,8 @@ const Pointset = function () {
230
228
  label.setPosition(coord[0], coord[1], coord[2]);
231
229
  const sprite = label.getSprite();
232
230
  sprite.material.sizeAttenuation = false;
233
- sprite.material.alphaTest = 0.5;
231
+ //Only discard fully transparent pixels to keep the smooth edges
232
+ sprite.material.alphaTest = 0.05;
234
233
  sprite.material.transparent = true;
235
234
  sprite.material.depthWrite = false;
236
235
  sprite.material.depthTest = labelDepthTest;
@@ -261,6 +260,7 @@ const Pointset = function () {
261
260
  * @param {Number} colour - A hex value of the colour for the points
262
261
  */
263
262
  this.addPoints = (coords, labels, colour) => {
263
+ this.requestRender();
264
264
  if (coords && coords.length > 0) {
265
265
  let mesh = this.getMorph();
266
266
  let current = this.drawRange;
@@ -272,7 +272,7 @@ const Pointset = function () {
272
272
  material.color.set(colour);
273
273
  material.alphaTest = 0.5;
274
274
  mesh = new InstancedPoints(quadGeometry, material, DEFAULT_CAPACITY);
275
- mesh.pointPositions = new Float32Array(DEFAULT_CAPACITY * 3);
275
+ mesh.pointPositions = quadGeometry.getAttribute('instancePosition').array;
276
276
  mesh.count = 0;
277
277
  mesh.userData = this;
278
278
  this.setMorph(mesh);
@@ -281,9 +281,6 @@ const Pointset = function () {
281
281
  coords.forEach(coord => {
282
282
  if (this.drawRange < DEFAULT_CAPACITY) {
283
283
  instancePosition.setXYZ(this.drawRange, coord[0], coord[1], coord[2]);
284
- mesh.pointPositions[this.drawRange * 3] = coord[0];
285
- mesh.pointPositions[this.drawRange * 3 + 1] = coord[1];
286
- mesh.pointPositions[this.drawRange * 3 + 2] = coord[2];
287
284
  this.drawRange++;
288
285
  }
289
286
  });
@@ -311,6 +308,7 @@ const Pointset = function () {
311
308
  * @param {Number} hex - hex value of color to be set
312
309
  */
313
310
  this.setColourHex = function(hex) {
311
+ this.requestRender();
314
312
  this._lod._material.color.setHex(hex);
315
313
  if (this._lod._secondaryMaterial) {
316
314
  this._lod._secondaryMaterial.color.setHex(hex);
@@ -328,6 +326,7 @@ const Pointset = function () {
328
326
  * @param {THREE.Color} colour - colour to be set
329
327
  */
330
328
  this.setColour = (colour) => {
329
+ this.requestRender();
331
330
  this._lod.setColour(colour);
332
331
  for (let i = 0; i < labelSets.length; i++) {
333
332
  if (labelSets[i]) {
@@ -343,6 +342,7 @@ const Pointset = function () {
343
342
  * should be on or off.
344
343
  */
345
344
  this.setLabelDepthTest = (flag) => {
345
+ this.requestRender();
346
346
  labelDepthTest = flag;
347
347
  for (let i = 0; i < labelSets.length; i++) {
348
348
  if (labelSets[i]) {
@@ -357,6 +357,7 @@ const Pointset = function () {
357
357
  * @param {Number} fontWeightIn - Default value is 700
358
358
  */
359
359
  this.setLabelFontWeight = (fontWeightIn) => {
360
+ this.requestRender();
360
361
  fontWeight = fontWeightIn;
361
362
  for (let i = 0; i < labelSets.length; i++) {
362
363
  if (labelSets[i]) {
@@ -372,6 +373,7 @@ const Pointset = function () {
372
373
  * value is 1.
373
374
  */
374
375
  this.setLabelSize = (size) => {
376
+ this.requestRender();
375
377
  labelSize = size;
376
378
  for (let i = 0; i < labelSets.length; i++) {
377
379
  if (labelSets[i]) {
@@ -386,6 +388,7 @@ const Pointset = function () {
386
388
  * @param {boolean} flag - default value is true
387
389
  */
388
390
  this.displayLabels = (flag) => {
391
+ this.requestRender();
389
392
  labelVisibility = flag;
390
393
  for (let i = 0; i < labelSets.length; i++) {
391
394
  if (labelSets[i]) {
@@ -399,6 +402,7 @@ const Pointset = function () {
399
402
  * @param {Number} size - size to be set.
400
403
  */
401
404
  this.setSize = size => {
405
+ this.requestRender();
402
406
  if (this.morph && this.morph.material) {
403
407
  this.morph.material.size = size;
404
408
  this.morph.material.userData.uniforms.pointSize.value = size;
@@ -413,6 +417,7 @@ const Pointset = function () {
413
417
  * should be on or off.
414
418
  */
415
419
  this.setSizeAttenuation = flag => {
420
+ this.requestRender();
416
421
  if (this.morph && this.morph.material) {
417
422
  this.morph.material.sizeAttenuation = flag;
418
423
  this.morph.material.userData.uniforms.sizeAttenuation.value = flag ? 1 : 0;
@@ -438,6 +443,7 @@ const Pointset = function () {
438
443
  * Edit Vertice in index.
439
444
  */
440
445
  this.editVertices = function(coords, i) {
446
+ this.requestRender();
441
447
  if (coords && coords.length) {
442
448
  const mesh = this.getMorph();
443
449
  const maxIndex = i + coords.length - 1;
@@ -452,9 +458,6 @@ const Pointset = function () {
452
458
  label.setPosition(coord[0], coord[1], coord[2]);
453
459
  }
454
460
  instancePosition.setXYZ(index, coord[0], coord[1], coord[2]);
455
- mesh.pointPositions[index * 3] = coord[0];
456
- mesh.pointPositions[index * 3 + 1] = coord[1];
457
- mesh.pointPositions[index * 3 + 2] = coord[2];
458
461
  //Keep the base frame consistent for any pointset that also
459
462
  //happens to be time varying.
460
463
  if (positionFrames[0]) {
@@ -474,6 +477,7 @@ const Pointset = function () {
474
477
  * Delete a vertex in index.
475
478
  */
476
479
  this.deleteVertices = function(index) {
480
+ this.requestRender();
477
481
  const mesh = this.getMorph();
478
482
  if (!mesh || 0 > index || index >= this.drawRange) {
479
483
  return this.drawRange;
@@ -481,7 +485,8 @@ const Pointset = function () {
481
485
  const instancePosition = mesh.geometry.getAttribute('instancePosition');
482
486
  const end = this.drawRange - 1;
483
487
  instancePosition.array.copyWithin(index * 3, (index + 1) * 3, this.drawRange * 3);
484
- mesh.pointPositions.copyWithin(index * 3, (index + 1) * 3, this.drawRange * 3);
488
+ if (mesh.pointPositions !== instancePosition.array)
489
+ mesh.pointPositions.copyWithin(index * 3, (index + 1) * 3, this.drawRange * 3);
485
490
  if (mesh.instanceColor) {
486
491
  mesh.instanceColor.array.copyWithin(index * 3, (index + 1) * 3, this.drawRange * 3);
487
492
  mesh.instanceColor.needsUpdate = true;
@@ -560,8 +565,7 @@ const Pointset = function () {
560
565
  if (this.boundingBoxUpdateRequired) {
561
566
  this._b1.setFromArray(mesh.pointPositions.subarray(0, this.drawRange * 3));
562
567
  this.cachedBoundingBox.copy(this._b1);
563
- mesh.updateWorldMatrix(true, true);
564
- this.cachedBoundingBox.applyMatrix4(mesh.matrixWorld);
568
+ this.cachedBoundingBox.applyMatrix4(updateWorldMatrixFromAncestors(mesh));
565
569
  this.cachedBoundingBox.getCenter(this.center);
566
570
  this.radius = this.center.distanceTo(this.cachedBoundingBox.max);
567
571
  this.boundingBoxUpdateRequired = false;
@@ -586,6 +590,7 @@ const Pointset = function () {
586
590
  * @param {Number} time - Can be any value between 0 to duration.
587
591
  */
588
592
  this.setMorphTime = time => {
593
+ this.requestRender();
589
594
  if (time > this.duration) {
590
595
  this.inbuildTime = this.duration;
591
596
  } else if (0 > time) {
@@ -70,4 +70,16 @@ const TexturePrimitive = function (textureIn) {
70
70
 
71
71
  TexturePrimitive.prototype = Object.create(ZincObject.prototype);
72
72
  TexturePrimitive.prototype.constructor = TexturePrimitive;
73
+
74
+ /**
75
+ * Free the textures and the other allocated memory.
76
+ */
77
+ TexturePrimitive.prototype.dispose = function() {
78
+ const textures = new Set(this.textureList);
79
+ if (this.texture) textures.add(this.texture);
80
+ textures.forEach(texture => texture.dispose());
81
+ this.texture = undefined;
82
+ this.textureList = [];
83
+ ZincObject.prototype.dispose.call(this);
84
+ }
73
85
  export { TexturePrimitive };
@@ -2,6 +2,7 @@ import * as THREE from 'three/webgpu';
2
2
  //import * as shader from '../shaders/textureSlide.js';
3
3
  import { createWebGPUMaterial } from '../tsl/textureSlides.js';
4
4
  import { TexturePrimitive } from './texturePrimitive';
5
+ import { updateWorldMatrixFromAncestors } from '../utilities';
5
6
 
6
7
 
7
8
  const cloneData3DTexture = (sourceTex) => {
@@ -73,6 +74,7 @@ const TextureSlides = function (textureIn) {
73
74
  * @param {SLIDE_SETTINGS} slideSettings - An array to each slide settings.
74
75
  */
75
76
  this.createSlides = slideSettings => {
77
+ this.requestRender();
76
78
  slideSettings.forEach(slide => this.createSlide(slide));
77
79
  }
78
80
 
@@ -123,6 +125,7 @@ const TextureSlides = function (textureIn) {
123
125
  * @param {SLIDE_SETTINGS} settings - s.
124
126
  */
125
127
  this.modifySlideSettings = (settings) => {
128
+ this.requestRender();
126
129
  if (settings && settings.id &&
127
130
  settings.id in idTextureMap &&
128
131
  idTextureMap[settings.id]) {
@@ -139,6 +142,7 @@ const TextureSlides = function (textureIn) {
139
142
  * created mesh's id.
140
143
  */
141
144
  this.createSlide = settings => {
145
+ this.requestRender();
142
146
  if (this.texture && this.texture.isTextureArray && this.texture.isReady()) {
143
147
  if (settings && settings.direction && settings.value !== undefined) {
144
148
  const geometry = new THREE.PlaneGeometry(1, 1);
@@ -238,6 +242,7 @@ const TextureSlides = function (textureIn) {
238
242
  * @param {Slide} slide - Slide to be remvoed
239
243
  */
240
244
  this.removeSlide = slide => {
245
+ this.requestRender();
241
246
  if (slide) {
242
247
  this.removeSlideWithId(slide.id);
243
248
  }
@@ -249,6 +254,7 @@ const TextureSlides = function (textureIn) {
249
254
  * @param {Number} id - id of slide to be remvoed
250
255
  */
251
256
  this.removeSlideWithId = id => {
257
+ this.requestRender();
252
258
  if (this.morph && id in idTextureMap && idTextureMap[id]) {
253
259
  if (this.morph.getObjectById(id)) {
254
260
  const slide = idTextureMap[id];
@@ -277,6 +283,11 @@ const TextureSlides = function (textureIn) {
277
283
  if (slide.material)
278
284
  slide.material.dispose();
279
285
  });
286
+ if (maskTexture) {
287
+ maskTexture.dispose();
288
+ maskTexture = undefined;
289
+ maskEnabled = false;
290
+ }
280
291
  TexturePrimitive.prototype.dispose.call(this);
281
292
  this.boundingBoxUpdateRequired = true;
282
293
  }
@@ -328,14 +339,14 @@ const TextureSlides = function (textureIn) {
328
339
  expandBoxWithSettings(this.cachedBoundingBox, slide.material.userData.uniforms,
329
340
  vector);
330
341
  });
331
- this.morph.updateMatrixWorld (true, true);
332
- this.cachedBoundingBox.applyMatrix4(this.morph.matrixWorld);
342
+ this.cachedBoundingBox.applyMatrix4(updateWorldMatrixFromAncestors(this.morph));
333
343
  this.boundingBoxUpdateRequired = false;
334
344
  }
335
345
  return this.cachedBoundingBox;
336
346
  }
337
347
 
338
348
  this.applyTransformation = (rotation, position, scale) => {
349
+ this.requestRender();
339
350
  const matrix = new THREE.Matrix4();
340
351
  matrix.set(
341
352
  rotation[0],
@@ -364,6 +375,7 @@ const TextureSlides = function (textureIn) {
364
375
  }
365
376
 
366
377
  this.setRenderOrder = (order) => {
378
+ this.requestRender();
367
379
  //multiilayers
368
380
  this.morph.renderOrder = order;
369
381
  }
@@ -389,6 +401,7 @@ const TextureSlides = function (textureIn) {
389
401
  }
390
402
 
391
403
  this.showEdges = (color) => {
404
+ this.requestRender();
392
405
  if (!edgesLine) {
393
406
  const geometry = new THREE.BoxGeometry( 1, 1, 1 );
394
407
  geometry.translate(0.5, 0.5, 0.5);
@@ -403,6 +416,7 @@ const TextureSlides = function (textureIn) {
403
416
 
404
417
 
405
418
  this.setUniformsValue = (name, val) => {
419
+ this.requestRender();
406
420
  this.morph.children.forEach((mesh) => {
407
421
  const material = mesh.material;
408
422
  if (material.userData.uniforms) {
@@ -417,6 +431,7 @@ const TextureSlides = function (textureIn) {
417
431
  }
418
432
 
419
433
  this.discardAlphaPixel = (flag) => {
434
+ this.requestRender();
420
435
  discardAlpha = flag;
421
436
  this.setUniformsValue("discardAlpha", discardAlpha);
422
437
  }
@@ -426,6 +441,7 @@ const TextureSlides = function (textureIn) {
426
441
  }
427
442
 
428
443
  this.setBrightness = (brightnessIn) => {
444
+ this.requestRender();
429
445
  brightness = brightnessIn;
430
446
  this.setUniformsValue("brightness", brightness);
431
447
  }
@@ -435,6 +451,7 @@ const TextureSlides = function (textureIn) {
435
451
  }
436
452
 
437
453
  this.setContrast = (contrastIn) => {
454
+ this.requestRender();
438
455
  if (contrast >= 0 ) {
439
456
  contrast = contrastIn;
440
457
  this.setUniformsValue("contrast", contrast);
@@ -446,6 +463,7 @@ const TextureSlides = function (textureIn) {
446
463
  }
447
464
 
448
465
  this.setNumberOfChannels = (numbersIn) => {
466
+ this.requestRender();
449
467
  nChannels = numbersIn;
450
468
  this.setUniformsValue("nChannels", nChannels);
451
469
  }
@@ -455,6 +473,7 @@ const TextureSlides = function (textureIn) {
455
473
  }
456
474
 
457
475
  this.setMask = (maskTextureIn) => {
476
+ this.requestRender();
458
477
  maskTexture = maskTextureIn;
459
478
  maskEnabled = maskTexture ? true : false;
460
479
  this.morph.children.forEach((mesh) => {
@@ -470,6 +489,7 @@ const TextureSlides = function (textureIn) {
470
489
  }
471
490
 
472
491
  this.hideEdges = () => {
492
+ this.requestRender();
473
493
  if (edgesLine) {
474
494
  edgesLine.visible = false;
475
495
  }
@@ -508,6 +528,7 @@ const TextureSlides = function (textureIn) {
508
528
  * Update the glyphsets if required the render.
509
529
  */
510
530
  this.setMorphTime = (time) => {
531
+ this.requestRender();
511
532
  let newTime = time;
512
533
  if (time > this.duration)
513
534
  newTime = this.duration;
@@ -524,7 +545,7 @@ const TextureSlides = function (textureIn) {
524
545
  /**
525
546
  * Update the glyphsets if required the render.
526
547
  */
527
- this.render = (delta, playAnimation, options) => {
548
+ this.render = (delta, playAnimation, cameraControls, options) => {
528
549
  //console.log("render", delta, playAnimation, this.textureList)
529
550
  if (playAnimation == true && this.timeEnabled &&
530
551
  this.textureList.length > 1) {
@@ -17,6 +17,8 @@ const TextureSlides = function (textureIn) {
17
17
  TexturePrimitive.call(this, textureIn);
18
18
  this.isTextureVolume = true;
19
19
  const textureSettings = [];
20
+ //Map of mesh id to slide mesh
21
+ const idTextureMap = {};
20
22
  this.morph = new THREE.Group();
21
23
  this.group = this.morph;
22
24
  this.morph.userData = this;
@@ -44,6 +44,7 @@ const TubeLines = function () {
44
44
  * @param {Number} width - Width of the lines.
45
45
  */
46
46
  this.setWidth = width => {
47
+ this.requestRender();
47
48
  if (this.morph && this.morph.material) {
48
49
  this.morph.material.linewidth = width;
49
50
  this.morph.material.needsUpdate = true;
@@ -58,6 +59,7 @@ const TubeLines = function () {
58
59
  * can be any value between from 0 to 1.0.
59
60
  */
60
61
  this.setAlpha = function (alpha) {
62
+ this.requestRender();
61
63
  let mesh = this.getMorph();
62
64
  mesh.material.opacity = alpha;
63
65
  mesh.material.transparent = alpha < 1.0;
@@ -69,6 +71,7 @@ const TubeLines = function () {
69
71
  * @param {Boolean} wireframe
70
72
  */
71
73
  this.setWireframe = (wireframe) => {
74
+ this.requestRender();
72
75
  let mesh = this.getMorph();
73
76
  mesh.material.wireframe = wireframe;
74
77
  }
@@ -80,6 +83,7 @@ const TubeLines = function () {
80
83
  * @param {Integer} radialSegments The number of segments that make up the cross-section.
81
84
  */
82
85
  this.setTubeLines = (radius, radialSegments) => {
86
+ this.requestRender();
83
87
  if (radius && radialSegments) {
84
88
  const { geometryIn } = dataIn;
85
89
  let mesh = this.getMorph();