zincjs 2.4.1-beta.2 → 2.4.1-beta.4

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zincjs",
3
- "version": "2.4.1-beta.2",
3
+ "version": "2.4.1-beta.4",
4
4
  "description": "ZincJS (Web-based-Zinc-Visualisation)",
5
5
  "type": "module",
6
6
  "main": "build/zinc.js",
@@ -1,13 +1,63 @@
1
- import * as THREE from 'three/webgpu';
2
1
  import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
3
2
  import { Geometry } from '../primitives/geometry';
4
3
  import { Lines } from '../primitives/lines';
5
4
  import { Pointset } from '../primitives/pointset';
5
+ import { applyMorphColorNode } from '../tsl/morphColorMaterial';
6
6
 
7
7
  const GLTFToZincJSLoader = function () {
8
8
 
9
9
  const _this = this;
10
10
 
11
+ /*
12
+ * glTF stores morph targets as offsets from the base attribute and
13
+ * GLTFLoader keeps them that way (morphTargetsRelative), but zinc expects
14
+ * absolute morph targets. GLTFLoader also only keeps the target names in
15
+ * morphTargetDictionary, while zinc builds its animation clip from the
16
+ * attribute names, so copy the names back onto the attributes.
17
+ */
18
+ const convertMorphTargets = (object) => {
19
+ const geometry = object.geometry;
20
+ if (!geometry || !geometry.morphAttributes) return;
21
+ const names = [];
22
+ if (object.morphTargetDictionary) {
23
+ for (const key in object.morphTargetDictionary) {
24
+ names[object.morphTargetDictionary[key]] = key;
25
+ }
26
+ }
27
+ for (const attributeName in geometry.morphAttributes) {
28
+ const base = geometry.attributes[attributeName];
29
+ geometry.morphAttributes[attributeName].forEach((attribute, i) => {
30
+ if (geometry.morphTargetsRelative && base) {
31
+ const array = attribute.array;
32
+ const baseArray = base.array;
33
+ const length = Math.min(array.length, baseArray.length);
34
+ for (let j = 0; j < length; j++) {
35
+ array[j] += baseArray[j];
36
+ }
37
+ attribute.needsUpdate = true;
38
+ }
39
+ if (names[i] !== undefined) attribute.name = names[i];
40
+ });
41
+ }
42
+ geometry.morphTargetsRelative = false;
43
+ }
44
+
45
+ /*
46
+ * Zinc renders colour morphs with its own colorNode (see geometry.js and
47
+ * lines.js), so swap it into the materials GLTFLoader created. Without it
48
+ * the colours stay at the first frame.
49
+ */
50
+ const applyMorphColourMaterial = (object) => {
51
+ const setup = (material) => {
52
+ //Same as geometry.js - vertexColors would multiply the blend by the
53
+ //static colour attribute.
54
+ material.vertexColors = false;
55
+ return applyMorphColorNode(material);
56
+ };
57
+ object.material = Array.isArray(object.material) ?
58
+ object.material.map(setup) : setup(object.material);
59
+ }
60
+
11
61
  this.parseGLTFObjects = (object, region, depth, finishCallback) => {
12
62
  let childRegion = region;
13
63
  if (depth !== 0) {
@@ -36,10 +86,14 @@ const GLTFToZincJSLoader = function () {
36
86
  let localTimeEnabled = false;
37
87
  let localMorphColour = false;
38
88
  if (object.geometry && object.geometry.morphAttributes) {
89
+ convertMorphTargets(object);
39
90
  localTimeEnabled = object.geometry.morphAttributes.position ? true : false;
40
91
  localMorphColour = object.geometry.morphAttributes.color ? true : false;
41
92
  }
42
- zincGeometry.setMesh(object.clone(), localTimeEnabled, localMorphColour);
93
+ const mesh = object.clone();
94
+ if (localMorphColour && !zincGeometry.isPointset)
95
+ applyMorphColourMaterial(mesh);
96
+ zincGeometry.setMesh(mesh, localTimeEnabled, localMorphColour);
43
97
  const morph = zincGeometry.getMorph();
44
98
  zincGeometry.groupName = morph.name;
45
99
  morph.matrixAutoUpdate = true;
@@ -69,13 +123,16 @@ const GLTFToZincJSLoader = function () {
69
123
  * @param {String} url - URL to the GLTF file
70
124
  * @param {Function} finishCallback - Callback function which will be called
71
125
  * once the glyphset is succssfully load in.
126
+ * @param {Function} isCancelled - Optional function returning true if this
127
+ * load has been cancelled, the loaded content will be discarded.
72
128
  */
73
- this.load = (scene, region, url, finishCallback, allCompletedCallback, options) => {
129
+ this.load = (scene, region, url, finishCallback, allCompletedCallback, options, isCancelled) => {
74
130
  const path = url.substring(0, url.lastIndexOf("/") + 1);
75
131
  const filename = url.substring(url.lastIndexOf("/") + 1, url.length);
76
132
  const loader = new GLTFLoader().setPath(path);
77
133
 
78
134
  loader.load( filename, function ( gltf ) {
135
+ if (isCancelled && isCancelled()) return;
79
136
  console.log(gltf)
80
137
  _this.parseGLTFObjects(gltf.scene, region, 0, finishCallback);
81
138
  _this.setCamera(scene);
@@ -302,7 +302,7 @@ Object.assign( JSONLoader.prototype, {
302
302
 
303
303
  }
304
304
 
305
- const attribute = new Float32BufferAttribute( array, 3 );
305
+ const attribute = new BufferAttribute( array, 3 );
306
306
  attribute.name = json.morphTargets[ i ].name;
307
307
  morphPositions.push( attribute );
308
308
 
@@ -321,7 +321,7 @@ Object.assign( JSONLoader.prototype, {
321
321
  const srcNormals = json.morphNormals[ i ].normals;
322
322
  const array = Float32Array.from( srcNormals );
323
323
 
324
- const attribute = new Float32BufferAttribute( array, 3 );
324
+ const attribute = new BufferAttribute( array, 3 );
325
325
  attribute.name = morphPositions[ i ].name;
326
326
  morphNormals[ i ] = attribute;
327
327
 
@@ -234,7 +234,7 @@ function createDataTexture(data, width, height, depth, isRGB) {
234
234
  if (!isRGB) {
235
235
  dataTexture.format = THREE.RedFormat;
236
236
  }
237
- dataTexture.colorSpace = THREE.SRGBColorSpace;
237
+ dataTexture.colorSpace = THREE.NoColorSpace;
238
238
  dataTexture.minFilter = THREE.NearestFilter;
239
239
  dataTexture.magFilter = THREE.NearestFilter;
240
240
  dataTexture.needsUpdate = true;
@@ -244,7 +244,7 @@ function createDataTexture(data, width, height, depth, isRGB) {
244
244
  function createTextureArray(sources) {
245
245
  if (sources?.data) {
246
246
  const tArray = new TextureArray();
247
- const dataTexutre = new createDataTexture(
247
+ const dataTexutre = createDataTexture(
248
248
  sources.data, sources.width, sources.height, sources.depth);
249
249
  tArray.setDataTexture(dataTexutre);
250
250
  tArray.size = {
@@ -124,7 +124,7 @@ const IndexedSourcesHandler = function(urlIn, crossOrigin, onDownloadedCallback)
124
124
  if (data) {
125
125
  processItemDownloaded(item);
126
126
  } else {
127
- processItemError(error);
127
+ processItemError(item);
128
128
  }
129
129
  } else if (downloading) {
130
130
  //quene it up
@@ -1,6 +1,6 @@
1
1
  import * as THREE from 'three/webgpu';
2
2
  import { toBufferGeometry } from '../utilities';
3
- import { applyMorphColorNode } from '../tls/morphColorMaterial';
3
+ import { applyMorphColorNode } from '../tsl/morphColorMaterial';
4
4
  import { ZincObject} from './zincObject';
5
5
 
6
6
  const createMeshForGeometry = (geometryIn, materialIn, options) => {
@@ -27,6 +27,7 @@ const Glyph = function (geometry, materialIn, idIn, glyphsetIn) {
27
27
  let labelString = undefined;
28
28
  this.isGlyph = true;
29
29
  let _position = [0, 0, 0];
30
+ let _colour = undefined;
30
31
 
31
32
  /**
32
33
  * Create a glyph using mesh
@@ -72,7 +73,9 @@ const Glyph = function (geometry, materialIn, idIn, glyphsetIn) {
72
73
  /**
73
74
  * Display label with the choosen colour. It will replace the current
74
75
  * label.
75
- * @param {THREE.Color} colour - Colour for the label.
76
+ * @param {THREE.Color} colour - Colour to fall back to for the label if
77
+ * this glyph doesn't already have its own colour (see setColour()/
78
+ * getColour()) - e.g. genuinely no colour data at all for this glyphset.
76
79
  */
77
80
  this.showLabel = (colour) => {
78
81
  if (label) {
@@ -82,7 +85,7 @@ const Glyph = function (geometry, materialIn, idIn, glyphsetIn) {
82
85
  label = undefined;
83
86
  }
84
87
  if (labelString && (typeof labelString === 'string' || labelString instanceof String)) {
85
- label = new Label(labelString, colour);
88
+ label = new Label(labelString, _colour || colour);
86
89
  label.setPosition(_position[0], _position[1], _position[2]);
87
90
  const sprite = label.getSprite();
88
91
  sprite.material.alphaTest = 0.5;
@@ -158,20 +161,31 @@ const Glyph = function (geometry, materialIn, idIn, glyphsetIn) {
158
161
  }
159
162
 
160
163
  /**
161
- * Set the color of the glyph and its label.
164
+ * Set the color of the glyph and its label. Remembered (see showLabel())
165
+ * so a label created/recreated later - e.g. by Glyphset.showLabel(),
166
+ * which otherwise only has a single shared material colour to fall back
167
+ * on - starts out with this glyph's own correct colour rather than that
168
+ * shared one.
162
169
  *
163
170
  * @param {THREE.Color} color - Colour to be set.
164
171
  */
165
172
  this.setColour = (color) => {
173
+ _colour = color ? color.clone() : undefined;
166
174
  if (label)
167
175
  label.setColour(color);
168
176
  if (this.secondaryMesh && this.secondaryMesh.material)
169
- this.secondaryMesh.material.color = colour;
177
+ this.secondaryMesh.material.color = color;
170
178
  if (this.geometry) {
171
179
  this.geometry.colorsNeedUpdate = true;
172
180
  }
173
181
  }
174
182
 
183
+ /**
184
+ * Get the last colour set via setColour(), if any.
185
+ * @return {THREE.Color|undefined}
186
+ */
187
+ this.getColour = () => _colour;
188
+
175
189
  /**
176
190
  * Clear and free its memory.
177
191
  */