@kitware/vtk.js 33.0.0-beta.2 → 33.0.0-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.
Files changed (87) hide show
  1. package/Common/Core/DataArray.d.ts +21 -0
  2. package/Common/Core/DataArray.js +39 -0
  3. package/Common/Core/Math/index.js +1 -1
  4. package/Common/Core/Math.js +1 -1
  5. package/Common/Core/URLExtract.js +2 -6
  6. package/Common/DataModel/Line.js +1 -0
  7. package/Common/DataModel/PolyLine.js +4 -0
  8. package/Filters/Core/ThresholdPoints.d.ts +72 -0
  9. package/Filters/Core/ThresholdPoints.js +219 -0
  10. package/Filters/General/ContourTriangulator/helper.js +1 -1
  11. package/IO/Core/DataAccessHelper/JSZipDataAccessHelper.js +1 -1
  12. package/IO/Geometry/DracoReader.d.ts +4 -4
  13. package/IO/Geometry/DracoReader.js +154 -105
  14. package/IO/Geometry/GLTFImporter/Animations.js +239 -0
  15. package/IO/Geometry/GLTFImporter/Constants.js +87 -0
  16. package/IO/Geometry/GLTFImporter/Decoder.js +69 -0
  17. package/IO/Geometry/GLTFImporter/Extensions.js +110 -0
  18. package/IO/Geometry/GLTFImporter/ORMTexture.worker.js +42 -0
  19. package/IO/Geometry/GLTFImporter/Parser.js +359 -0
  20. package/IO/Geometry/GLTFImporter/Reader.js +518 -0
  21. package/IO/Geometry/GLTFImporter/Utils.js +165 -0
  22. package/IO/Geometry/GLTFImporter.d.ts +266 -0
  23. package/IO/Geometry/GLTFImporter.js +245 -0
  24. package/IO/Geometry/IFCImporter.d.ts +163 -0
  25. package/IO/Geometry/IFCImporter.js +270 -0
  26. package/IO/Geometry/STLReader.d.ts +14 -0
  27. package/IO/Geometry/STLReader.js +57 -1
  28. package/IO/Geometry.js +5 -1
  29. package/IO/Image/HDRReader/Utils.js +1 -1
  30. package/IO/Image/HDRReader.js +1 -1
  31. package/IO/Image/TGAReader/Constants.js +28 -0
  32. package/IO/Image/TGAReader.d.ts +121 -0
  33. package/IO/Image/TGAReader.js +418 -0
  34. package/IO/Image/TIFFReader.d.ts +133 -0
  35. package/IO/Image/TIFFReader.js +144 -0
  36. package/IO/Image.js +5 -1
  37. package/IO/XML/XMLPolyDataWriter.js +1 -0
  38. package/Interaction/Manipulators/MouseCameraTrackballRollManipulator.js +1 -1
  39. package/Interaction/Style/InteractorStyleTrackballCamera.js +1 -1
  40. package/Rendering/Core/AbstractImageMapper.d.ts +81 -0
  41. package/Rendering/Core/AbstractImageMapper.js +5 -2
  42. package/Rendering/Core/AbstractPicker.d.ts +13 -13
  43. package/Rendering/Core/AbstractPicker.js +1 -1
  44. package/Rendering/Core/Actor2D.d.ts +22 -0
  45. package/Rendering/Core/Actor2D.js +1 -1
  46. package/Rendering/Core/CellPicker.js +4 -1
  47. package/Rendering/Core/Glyph3DMapper.d.ts +45 -29
  48. package/Rendering/Core/ImageCPRMapper.js +6 -5
  49. package/Rendering/Core/ImageProperty.d.ts +42 -1
  50. package/Rendering/Core/ImageProperty.js +7 -5
  51. package/Rendering/Core/ImageResliceMapper.d.ts +1 -2
  52. package/Rendering/Core/ImageResliceMapper.js +5 -4
  53. package/Rendering/Core/PointPicker.js +10 -1
  54. package/Rendering/Core/Prop3D.js +1 -1
  55. package/Rendering/Core/RenderWindowInteractor.d.ts +1 -1
  56. package/Rendering/Core/RenderWindowInteractor.js +1 -1
  57. package/Rendering/Core/Viewport.js +13 -3
  58. package/Rendering/Core/VolumeMapper.d.ts +70 -0
  59. package/Rendering/Core/VolumeMapper.js +10 -5
  60. package/Rendering/Core/VolumeProperty.d.ts +20 -1
  61. package/Rendering/Core/VolumeProperty.js +7 -5
  62. package/Rendering/Misc/CanvasView.js +4 -2
  63. package/Rendering/Misc/RemoteView.d.ts +9 -3
  64. package/Rendering/Misc/RemoteView.js +7 -3
  65. package/Rendering/Misc/SynchronizableRenderWindow/BehaviorManager/CameraSynchronizer.js +2 -2
  66. package/Rendering/Misc/SynchronizableRenderWindow/ObjectManager.d.ts +1 -1
  67. package/Rendering/OpenGL/ImageCPRMapper.js +18 -2
  68. package/Rendering/OpenGL/ImageMapper.js +42 -11
  69. package/Rendering/OpenGL/ImageResliceMapper.js +20 -4
  70. package/Rendering/OpenGL/Renderer.js +1 -1
  71. package/Rendering/OpenGL/Texture/supportsNorm16Linear.js +97 -0
  72. package/Rendering/OpenGL/Texture.d.ts +29 -8
  73. package/Rendering/OpenGL/Texture.js +172 -34
  74. package/Rendering/OpenGL/VolumeMapper.js +22 -4
  75. package/Rendering/SceneGraph/ViewNode.js +12 -2
  76. package/Rendering/WebXR/RenderWindowHelper.js +9 -0
  77. package/Widgets/Core/WidgetManager.d.ts +12 -1
  78. package/Widgets/Representations/WidgetRepresentation.d.ts +1 -7
  79. package/Widgets/Widgets3D/AngleWidget/behavior.js +2 -0
  80. package/Widgets/Widgets3D/InteractiveOrientationWidget.js +1 -1
  81. package/Widgets/Widgets3D/ResliceCursorWidget/behavior.js +17 -0
  82. package/Widgets/Widgets3D/ResliceCursorWidget/helpers.js +1 -0
  83. package/Widgets/Widgets3D/ResliceCursorWidget.d.ts +1 -8
  84. package/Widgets/Widgets3D/ShapeWidget/behavior.js +3 -0
  85. package/_virtual/rollup-plugin-worker-loader__module_Sources/IO/Geometry/GLTFImporter/ORMTexture.worker.js +296 -0
  86. package/index.d.ts +5 -0
  87. package/package.json +19 -17
@@ -1,8 +1,9 @@
1
- import DataAccessHelper from '../Core/DataAccessHelper.js';
2
1
  import { m as macro } from '../../macros2.js';
2
+ import DataAccessHelper from '../Core/DataAccessHelper.js';
3
3
  import vtkCellArray from '../../Common/Core/CellArray.js';
4
4
  import vtkDataArray from '../../Common/Core/DataArray.js';
5
5
  import vtkPolyData from '../../Common/DataModel/PolyData.js';
6
+ import vtkPolyDataNormals from '../../Filters/Core/PolyDataNormals.js';
6
7
  import '../Core/DataAccessHelper/LiteHttpDataAccessHelper.js';
7
8
 
8
9
  // import 'vtk.js/Sources/IO/Core/DataAccessHelper/HttpDataAccessHelper'; // HTTP + zip
@@ -12,8 +13,7 @@ import '../Core/DataAccessHelper/LiteHttpDataAccessHelper.js';
12
13
  const {
13
14
  vtkErrorMacro
14
15
  } = macro;
15
- let decoderModule = {};
16
-
16
+ let decoderModule = null;
17
17
  // ----------------------------------------------------------------------------
18
18
  // static methods
19
19
  // ----------------------------------------------------------------------------
@@ -46,8 +46,13 @@ function setWasmBinary(url, binaryName) {
46
46
  xhr.send(null);
47
47
  });
48
48
  }
49
- function setDracoDecoder(createDracoModule) {
50
- decoderModule = createDracoModule({});
49
+
50
+ /**
51
+ * Set the Draco decoder module
52
+ * @param {*} dracoDecoder
53
+ */
54
+ async function setDracoDecoder(dracoDecoder) {
55
+ decoderModule = await dracoDecoder({});
51
56
  }
52
57
  function getDracoDecoder() {
53
58
  return decoderModule;
@@ -56,115 +61,141 @@ function getDracoDecoder() {
56
61
  // ----------------------------------------------------------------------------
57
62
  // vtkDracoReader methods
58
63
  // ----------------------------------------------------------------------------
59
-
60
- function decodeBuffer(buffer) {
61
- const byteArray = new Int8Array(buffer);
62
- const decoder = new decoderModule.Decoder();
63
- const decoderBuffer = new decoderModule.DecoderBuffer();
64
- decoderBuffer.Init(byteArray, byteArray.length);
65
- const geometryType = decoder.GetEncodedGeometryType(decoderBuffer);
66
- let dracoGeometry;
67
- if (geometryType === decoderModule.TRIANGULAR_MESH) {
68
- dracoGeometry = new decoderModule.Mesh();
69
- const status = decoder.DecodeBufferToMesh(decoderBuffer, dracoGeometry);
70
- if (!status.ok()) {
71
- vtkErrorMacro(`Could not decode Draco file: ${status.error_msg()}`);
72
- }
73
- } else {
74
- vtkErrorMacro('Wrong geometry type, expected mesh, got point cloud.');
64
+ function getDracoDataType(attributeType) {
65
+ switch (attributeType) {
66
+ case Float32Array:
67
+ return decoderModule.DT_FLOAT32;
68
+ case Int8Array:
69
+ return decoderModule.DT_INT8;
70
+ case Int16Array:
71
+ return decoderModule.DT_INT16;
72
+ case Int32Array:
73
+ return decoderModule.DT_INT32;
74
+ case Uint8Array:
75
+ return decoderModule.DT_UINT8;
76
+ case Uint16Array:
77
+ return decoderModule.DT_UINT16;
78
+ case Uint32Array:
79
+ return decoderModule.DT_UINT32;
80
+ default:
81
+ return decoderModule.DT_FLOAT32;
75
82
  }
76
- decoderModule.destroy(decoderBuffer);
77
- decoderModule.destroy(decoder);
78
- return dracoGeometry;
79
83
  }
80
- function getDracoAttributeAsFloat32Array(dracoGeometry, attributeId) {
81
- const decoder = new decoderModule.Decoder();
82
- const attribute = decoder.GetAttribute(dracoGeometry, attributeId);
83
- const numberOfComponents = attribute.num_components();
84
- const numberOfPoints = dracoGeometry.num_points();
85
- const attributeData = new decoderModule.DracoFloat32Array();
86
- decoder.GetAttributeFloatForAllPoints(dracoGeometry, attribute, attributeData);
87
- let i = numberOfPoints * numberOfComponents;
88
- const attributeArray = new Float32Array(i);
89
- while (i--) {
90
- attributeArray[i] = attributeData.GetValue(i);
91
- }
92
- return attributeArray;
84
+
85
+ /**
86
+ * Decode a single attribute
87
+ * @param {*} decoder The Draco decoder
88
+ * @param {*} dracoGeometry The geometry to decode
89
+ * @param {*} attributeName The name of the attribute
90
+ * @param {*} attributeType The type of the attribute
91
+ * @param {*} attribute The attribute to decode
92
+ * @returns object with name, array, itemSize
93
+ */
94
+ function decodeAttribute(decoder, dracoGeometry, attributeName, attributeType, attribute) {
95
+ const numComponents = attribute.num_components();
96
+ const numPoints = dracoGeometry.num_points();
97
+ const numValues = numPoints * numComponents;
98
+ const byteLength = numValues * attributeType.BYTES_PER_ELEMENT;
99
+ const dataType = getDracoDataType(attributeType);
100
+ const ptr = decoderModule._malloc(byteLength);
101
+ decoder.GetAttributeDataArrayForAllPoints(dracoGeometry, attribute, dataType, byteLength, ptr);
102
+
103
+ // eslint-disable-next-line new-cap
104
+ const array = new attributeType(decoderModule.HEAPF32.buffer, ptr, numValues).slice();
105
+ decoderModule._free(ptr);
106
+ return {
107
+ name: attributeName,
108
+ array,
109
+ itemSize: numComponents
110
+ };
93
111
  }
94
- function getPolyDataFromDracoGeometry(dracoGeometry) {
95
- const decoder = new decoderModule.Decoder();
96
112
 
97
- // Get position attribute ID
98
- const positionAttributeId = decoder.GetAttributeId(dracoGeometry, decoderModule.POSITION);
99
- if (positionAttributeId === -1) {
100
- console.error('No position attribute found in the decoded model.');
101
- decoderModule.destroy(decoder);
102
- decoderModule.destroy(dracoGeometry);
103
- return null;
104
- }
105
- const positionArray = getDracoAttributeAsFloat32Array(dracoGeometry, positionAttributeId);
113
+ /**
114
+ * Decode the indices of the geometry
115
+ * @param {*} decoder The Draco decoder
116
+ * @param {*} dracoGeometry The geometry to decode
117
+ * @returns The indices array of the geometry
118
+ */
119
+ function decodeIndices(decoder, dracoGeometry) {
120
+ const numFaces = dracoGeometry.num_faces();
121
+ const numIndices = numFaces * 3;
122
+ const byteLength = numIndices * 4;
123
+ const ptr = decoderModule._malloc(byteLength);
124
+ decoder.GetTrianglesUInt32Array(dracoGeometry, byteLength, ptr);
125
+ const indices = new Uint32Array(decoderModule.HEAPF32.buffer, ptr, numIndices).slice();
126
+ decoderModule._free(ptr);
127
+ return indices;
128
+ }
106
129
 
107
- // Read indices
108
- let i = dracoGeometry.num_faces();
109
- const indices = new Uint32Array(i * 4);
110
- const indicesArray = new decoderModule.DracoInt32Array();
111
- while (i--) {
112
- decoder.GetFaceFromMesh(dracoGeometry, i, indicesArray);
113
- const index = i * 4;
114
- indices[index] = 3;
115
- indices[index + 1] = indicesArray.GetValue(0);
116
- indices[index + 2] = indicesArray.GetValue(1);
117
- indices[index + 3] = indicesArray.GetValue(2);
130
+ /**
131
+ * Get the polyData from the Draco geometry
132
+ * @param {*} decoder The Draco decoder
133
+ * @param {*} dracoGeometry The geometry to decode
134
+ * @returns {vtkPolyData} The polyData of the geometry
135
+ */
136
+ function getPolyDataFromDracoGeometry(decoder, dracoGeometry) {
137
+ const indices = decodeIndices(decoder, dracoGeometry);
138
+ const nCells = indices.length - 2;
139
+ const cells = vtkCellArray.newInstance();
140
+ cells.resize(4 * indices.length / 3);
141
+ for (let cellId = 0; cellId < nCells; cellId += 3) {
142
+ const cell = indices.slice(cellId, cellId + 3);
143
+ cells.insertNextCell(cell);
118
144
  }
119
-
120
- // Create polyData and add positions and indinces
121
- const cellArray = vtkCellArray.newInstance({
122
- values: indices
123
- });
124
145
  const polyData = vtkPolyData.newInstance({
125
- polys: cellArray
146
+ polys: cells
126
147
  });
127
- polyData.getPoints().setData(positionArray);
128
-
129
- // Look for other attributes
130
- const pointData = polyData.getPointData();
131
148
 
132
- // Normals
133
- const normalAttributeId = decoder.GetAttributeId(dracoGeometry, decoderModule.NORMAL);
134
- if (normalAttributeId !== -1) {
135
- const normalArray = getDracoAttributeAsFloat32Array(dracoGeometry, decoderModule.NORMAL);
136
- const normals = vtkDataArray.newInstance({
137
- numberOfComponents: 3,
138
- values: normalArray,
139
- name: 'Normals'
140
- });
141
- pointData.setNormals(normals);
142
- }
143
-
144
- // Texture coordinates
145
- const texCoordAttributeId = decoder.GetAttributeId(dracoGeometry, decoderModule.TEX_COORD);
146
- if (texCoordAttributeId !== -1) {
147
- const texCoordArray = getDracoAttributeAsFloat32Array(dracoGeometry, texCoordAttributeId);
148
- const texCoords = vtkDataArray.newInstance({
149
- numberOfComponents: 2,
150
- values: texCoordArray,
151
- name: 'TCoords'
152
- });
153
- pointData.setTCoords(texCoords);
154
- }
149
+ // Look for attributes
150
+ const attributeIDs = {
151
+ points: 'POSITION',
152
+ normals: 'NORMAL',
153
+ scalars: 'COLOR',
154
+ tcoords: 'TEX_COORD'
155
+ };
156
+ Object.keys(attributeIDs).forEach(attributeName => {
157
+ const attributeType = Float32Array;
158
+ const attributeID = decoder.GetAttributeId(dracoGeometry, decoderModule[attributeIDs[attributeName]]);
159
+ if (attributeID === -1) return;
160
+ const attribute = decoder.GetAttribute(dracoGeometry, attributeID);
161
+ const attributeResult = decodeAttribute(decoder, dracoGeometry, attributeName, attributeType, attribute);
162
+ const pointData = polyData.getPointData();
163
+ switch (attributeName) {
164
+ case 'points':
165
+ polyData.getPoints().setData(attributeResult.array, attributeResult.itemSize);
166
+ break;
167
+ case 'normals':
168
+ pointData.setNormals(vtkDataArray.newInstance({
169
+ numberOfComponents: attributeResult.itemSize,
170
+ values: attributeResult.array,
171
+ name: 'Normals'
172
+ }));
173
+ break;
174
+ case 'scalars':
175
+ pointData.setScalars(vtkDataArray.newInstance({
176
+ numberOfComponents: attributeResult.itemSize,
177
+ values: attributeResult.array,
178
+ name: 'Scalars'
179
+ }));
180
+ break;
181
+ case 'tcoords':
182
+ pointData.setTCoords(vtkDataArray.newInstance({
183
+ numberOfComponents: attributeResult.itemSize,
184
+ values: attributeResult.array,
185
+ name: 'TCoords'
186
+ }));
187
+ break;
188
+ }
189
+ });
155
190
 
156
- // Scalars
157
- const colorAttributeId = decoder.GetAttributeId(dracoGeometry, decoderModule.COLOR);
158
- if (colorAttributeId !== -1) {
159
- const colorArray = getDracoAttributeAsFloat32Array(dracoGeometry, colorAttributeId);
160
- const scalars = vtkDataArray.newInstance({
161
- numberOfComponents: 3,
162
- values: colorArray,
163
- name: 'Scalars'
164
- });
165
- pointData.setScalars(scalars);
191
+ // we will generate normals if they're missing
192
+ const hasNormals = polyData.getPointData().getNormals();
193
+ if (!hasNormals) {
194
+ const pdn = vtkPolyDataNormals.newInstance();
195
+ pdn.setInputData(polyData);
196
+ pdn.setComputePointNormals(true);
197
+ return pdn.getOutputData();
166
198
  }
167
- decoderModule.destroy(decoder);
168
199
  return polyData;
169
200
  }
170
201
  function vtkDracoReader(publicAPI, model) {
@@ -235,9 +266,27 @@ function vtkDracoReader(publicAPI, model) {
235
266
  return;
236
267
  }
237
268
  model.parseData = content;
238
- const dracoGeometry = decodeBuffer(content);
239
- const polyData = getPolyDataFromDracoGeometry(dracoGeometry);
269
+ const byteArray = new Int8Array(content);
270
+ const decoder = new decoderModule.Decoder();
271
+ const buffer = new decoderModule.DecoderBuffer();
272
+ buffer.Init(byteArray, byteArray.length);
273
+ const geometryType = decoder.GetEncodedGeometryType(buffer);
274
+ let dracoGeometry;
275
+ if (geometryType === decoderModule.TRIANGULAR_MESH) {
276
+ dracoGeometry = new decoderModule.Mesh();
277
+ const status = decoder.DecodeBufferToMesh(buffer, dracoGeometry);
278
+ if (!status.ok()) {
279
+ vtkErrorMacro(`Could not decode Draco file: ${status.error_msg()}`);
280
+ return;
281
+ }
282
+ } else {
283
+ vtkErrorMacro('Wrong geometry type, expected mesh, got point cloud.');
284
+ return;
285
+ }
286
+ const polyData = getPolyDataFromDracoGeometry(decoder, dracoGeometry);
240
287
  decoderModule.destroy(dracoGeometry);
288
+ decoderModule.destroy(buffer);
289
+ decoderModule.destroy(decoder);
241
290
  model.output[0] = polyData;
242
291
  };
243
292
  publicAPI.requestData = () => {
@@ -0,0 +1,239 @@
1
+ import { m as macro } from '../../../macros2.js';
2
+ import { A as degreesFromRadians } from '../../../Common/Core/Math/index.js';
3
+ import { quat, vec3 } from 'gl-matrix';
4
+
5
+ const {
6
+ vtkDebugMacro,
7
+ vtkWarningMacro
8
+ } = macro;
9
+
10
+ /**
11
+ * Create an animation channel
12
+ * @param {glTFChannel} glTFChannel
13
+ * @param {glTFChannel[]} glTFSamplers
14
+ * @returns
15
+ */
16
+ function createAnimationChannel(glTFChannel, glTFSamplers) {
17
+ const path = glTFChannel.target.path;
18
+ const node = glTFChannel.target.node;
19
+ function applyAnimation(value) {
20
+ let axisAngle;
21
+ let w;
22
+ let nq;
23
+ switch (path) {
24
+ case 'translation':
25
+ node.setPosition(value[0], value[1], value[2]);
26
+ break;
27
+ case 'rotation':
28
+ // Convert quaternion to axis-angle representation
29
+ nq = quat.normalize(quat.create(), value);
30
+ axisAngle = new Float64Array(3);
31
+ w = quat.getAxisAngle(axisAngle, nq);
32
+ // Apply rotation using rotateWXYZ
33
+ node.rotateWXYZ(degreesFromRadians(w), axisAngle[0], axisAngle[1], axisAngle[2]);
34
+ break;
35
+ case 'scale':
36
+ node.setScale(value[0], value[1], value[2]);
37
+ break;
38
+ default:
39
+ vtkWarningMacro(`Unsupported animation path: ${path}`);
40
+ }
41
+ }
42
+ function animate(currentTime) {
43
+ const sampler = glTFSamplers[glTFChannel.sampler];
44
+ const value = sampler.evaluate(currentTime, path);
45
+ applyAnimation(value);
46
+ }
47
+ return {
48
+ ...glTFChannel,
49
+ animate
50
+ };
51
+ }
52
+
53
+ /**
54
+ * Create an animation sampler
55
+ * @param {glTFSampler} glTFSampler
56
+ * @returns
57
+ */
58
+ function createAnimationSampler(glTFSampler) {
59
+ let lastKeyframeIndex = 0;
60
+ function findKeyframes(time) {
61
+ let i1 = lastKeyframeIndex;
62
+ while (i1 < glTFSampler.input.length - 1 && glTFSampler.input[i1] <= time) {
63
+ i1++;
64
+ }
65
+ const i0 = Math.max(0, i1 - 1);
66
+ lastKeyframeIndex = i0;
67
+ return [glTFSampler.input[i0], glTFSampler.input[i1], i0, i1];
68
+ }
69
+ function stepInterpolate(path, i0) {
70
+ const startIndex = i0 * 3;
71
+ const v0 = new Array(3);
72
+ for (let i = 0; i < 3; ++i) {
73
+ v0[i] = glTFSampler.output[startIndex + i];
74
+ }
75
+ return v0;
76
+ }
77
+ function linearInterpolate(path, t0, t1, i0, i1, t) {
78
+ const ratio = (t - t0) / (t1 - t0);
79
+ const startIndex = i0 * 4;
80
+ const endIndex = i1 * 4;
81
+ const v0 = new Array(4);
82
+ const v1 = new Array(4);
83
+ for (let i = 0; i < 4; ++i) {
84
+ v0[i] = glTFSampler.output[startIndex + i];
85
+ v1[i] = glTFSampler.output[endIndex + i];
86
+ }
87
+ switch (path) {
88
+ case 'translation':
89
+ case 'scale':
90
+ return vec3.lerp(vec3.create(), v0, v1, ratio);
91
+ case 'rotation':
92
+ return quat.slerp(quat.create(), v0, v1, ratio);
93
+ default:
94
+ vtkWarningMacro(`Unsupported animation path: ${path}`);
95
+ return null;
96
+ }
97
+ }
98
+ function cubicSplineInterpolate(path, t0, t1, i0, i1, time) {
99
+ const dt = t1 - t0;
100
+ const t = (time - t0) / dt;
101
+ const t2 = t * t;
102
+ const t3 = t2 * t;
103
+ const p0 = glTFSampler.output[i0 * 3 + 1];
104
+ const m0 = dt * glTFSampler.output[i0 * 3 + 2];
105
+ const p1 = glTFSampler.output[i1 * 3 + 1];
106
+ const m1 = dt * glTFSampler.output[i1 * 3];
107
+ if (Array.isArray(p0)) {
108
+ return p0.map((v, j) => {
109
+ const a = 2 * t3 - 3 * t2 + 1;
110
+ const b = t3 - 2 * t2 + t;
111
+ const c = -2 * t3 + 3 * t2;
112
+ const d = t3 - t2;
113
+ return a * v + b * m0[j] + c * p1[j] + d * m1[j];
114
+ });
115
+ }
116
+ const a = 2 * t3 - 3 * t2 + 1;
117
+ const b = t3 - 2 * t2 + t;
118
+ const c = -2 * t3 + 3 * t2;
119
+ const d = t3 - t2;
120
+ return a * p0 + b * m0 + c * p1 + d * m1;
121
+ }
122
+ function evaluate(time, path) {
123
+ const [t0, t1, i0, i1] = findKeyframes(time);
124
+ let result;
125
+ switch (glTFSampler.interpolation) {
126
+ case 'STEP':
127
+ result = stepInterpolate(path, i0);
128
+ break;
129
+ case 'LINEAR':
130
+ result = linearInterpolate(path, t0, t1, i0, i1, time);
131
+ break;
132
+ case 'CUBICSPLINE':
133
+ result = cubicSplineInterpolate(path, t0, t1, i0, i1, time);
134
+ break;
135
+ default:
136
+ vtkWarningMacro(`Unknown interpolation method: ${glTFSampler.interpolation}`);
137
+ }
138
+ return result;
139
+ }
140
+ return {
141
+ ...glTFSampler,
142
+ evaluate
143
+ };
144
+ }
145
+
146
+ /**
147
+ * Create an animation
148
+ * @param {glTFAnimation} glTFAnimation
149
+ * @param {Map} nodes
150
+ * @returns
151
+ */
152
+ function createAnimation(glTFAnimation, nodes) {
153
+ glTFAnimation.samplers = glTFAnimation.samplers.map(sampler => createAnimationSampler(sampler));
154
+ glTFAnimation.channels = glTFAnimation.channels.map(channel => {
155
+ channel.target.node = nodes.get(`node-${channel.target.node}`);
156
+ return createAnimationChannel(channel, glTFAnimation.samplers);
157
+ });
158
+ function update(currentTime) {
159
+ glTFAnimation.channels.forEach(channel => channel.animate(currentTime));
160
+ }
161
+ return {
162
+ ...glTFAnimation,
163
+ update
164
+ };
165
+ }
166
+
167
+ /**
168
+ * Create an animation mixer
169
+ * @param {Map} nodes
170
+ * @param {*} accessors
171
+ * @returns
172
+ */
173
+ function createAnimationMixer(nodes, accessors) {
174
+ const animations = new Map();
175
+ const activeAnimations = new Map();
176
+ function addAnimation(glTFAnimation) {
177
+ const annimation = createAnimation(glTFAnimation, nodes);
178
+ animations.set(glTFAnimation.id, annimation);
179
+ vtkDebugMacro(`Animation "${glTFAnimation.id}" added to mixer`);
180
+ }
181
+ function play(name) {
182
+ let weight = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
183
+ if (!animations.has(name)) {
184
+ vtkWarningMacro(`Animation "${name}" not found in mixer`);
185
+ return;
186
+ }
187
+ activeAnimations.set(name, {
188
+ animation: animations.get(name),
189
+ weight,
190
+ time: 0
191
+ });
192
+ vtkDebugMacro(`Playing animation "${name}" with weight ${weight}`);
193
+ }
194
+ function stop(name) {
195
+ if (activeAnimations.delete(name)) {
196
+ vtkWarningMacro(`Stopped animation "${name}"`);
197
+ } else {
198
+ vtkWarningMacro(`Animation "${name}" was not playing`);
199
+ }
200
+ }
201
+ function stopAll() {
202
+ activeAnimations.clear();
203
+ vtkWarningMacro('Stopped all animations');
204
+ }
205
+ function update(deltaTime) {
206
+ // Normalize weights
207
+ const totalWeight = Array.from(activeAnimations.values()).reduce((sum, _ref) => {
208
+ let {
209
+ weight
210
+ } = _ref;
211
+ return sum + weight;
212
+ }, 0);
213
+ activeAnimations.forEach((_ref2, name) => {
214
+ let {
215
+ animation,
216
+ weight,
217
+ time
218
+ } = _ref2;
219
+ const normalizedWeight = totalWeight > 0 ? weight / totalWeight : 0;
220
+ const newTime = time + deltaTime;
221
+ activeAnimations.set(name, {
222
+ animation,
223
+ weight,
224
+ time: newTime
225
+ });
226
+ vtkDebugMacro(`Updating animation "${name}" at time ${newTime.toFixed(3)} with normalized weight ${normalizedWeight.toFixed(3)}`);
227
+ animation.update(newTime, normalizedWeight);
228
+ });
229
+ }
230
+ return {
231
+ addAnimation,
232
+ play,
233
+ stop,
234
+ stopAll,
235
+ update
236
+ };
237
+ }
238
+
239
+ export { createAnimation, createAnimationChannel, createAnimationMixer, createAnimationSampler };
@@ -0,0 +1,87 @@
1
+ const BINARY_HEADER_MAGIC = 'glTF';
2
+ const BINARY_HEADER_LENGTH = 12;
3
+ const BINARY_CHUNK_TYPES = {
4
+ JSON: 0x4e4f534a,
5
+ BIN: 0x004e4942
6
+ };
7
+ const BINARY_HEADER_INTS = 3;
8
+ const BINARY_CHUNK_HEADER_INTS = 2;
9
+ const MIN_LIGHT_ATTENUATION = 0.01;
10
+ const COMPONENTS = {
11
+ SCALAR: 1,
12
+ VEC2: 2,
13
+ VEC3: 3,
14
+ VEC4: 4,
15
+ MAT2: 4,
16
+ MAT3: 9,
17
+ MAT4: 16
18
+ };
19
+ const BYTES = {
20
+ 5120: 1,
21
+ // BYTE
22
+ 5121: 1,
23
+ // UNSIGNED_BYTE
24
+ 5122: 2,
25
+ // SHORT
26
+ 5123: 2,
27
+ // UNSIGNED_SHORT
28
+ 5125: 4,
29
+ // UNSIGNED_INT
30
+ 5126: 4 // FLOAT
31
+ };
32
+
33
+ const MODES = {
34
+ GL_POINTS: 0,
35
+ GL_LINES: 1,
36
+ GL_LINE_LOOP: 2,
37
+ GL_LINE_STRIP: 3,
38
+ GL_TRIANGLES: 4,
39
+ GL_TRIANGLE_STRIP: 5,
40
+ GL_TRIANGLE_FAN: 6
41
+ };
42
+ const ARRAY_TYPES = {
43
+ 5120: Int8Array,
44
+ 5121: Uint8Array,
45
+ 5122: Int16Array,
46
+ 5123: Uint16Array,
47
+ 5125: Uint32Array,
48
+ 5126: Float32Array
49
+ };
50
+ const GL_SAMPLER = {
51
+ NEAREST: 9728,
52
+ LINEAR: 9729,
53
+ NEAREST_MIPMAP_NEAREST: 9984,
54
+ LINEAR_MIPMAP_NEAREST: 9985,
55
+ NEAREST_MIPMAP_LINEAR: 9986,
56
+ LINEAR_MIPMAP_LINEAR: 9987,
57
+ REPEAT: 10497,
58
+ CLAMP_TO_EDGE: 33071,
59
+ MIRRORED_REPEAT: 33648,
60
+ TEXTURE_MAG_FILTER: 10240,
61
+ TEXTURE_MIN_FILTER: 10241,
62
+ TEXTURE_WRAP_S: 10242,
63
+ TEXTURE_WRAP_T: 10243
64
+ };
65
+ const DEFAULT_SAMPLER = {
66
+ magFilter: GL_SAMPLER.NEAREST,
67
+ minFilter: GL_SAMPLER.LINEAR_MIPMAP_LINEAR,
68
+ wrapS: GL_SAMPLER.REPEAT,
69
+ wrapT: GL_SAMPLER.REPEAT
70
+ };
71
+ const SEMANTIC_ATTRIBUTE_MAP = {
72
+ NORMAL: 'normal',
73
+ POSITION: 'position',
74
+ TEXCOORD_0: 'texcoord0',
75
+ TEXCOORD_1: 'texcoord1',
76
+ WEIGHTS_0: 'weight',
77
+ JOINTS_0: 'joint',
78
+ COLOR_0: 'color',
79
+ TANGENT: 'tangent'
80
+ };
81
+ const ALPHA_MODE = {
82
+ OPAQUE: 'OPAQUE',
83
+ MASK: 'MASK',
84
+ BLEND: 'BLEND'
85
+ };
86
+
87
+ export { ALPHA_MODE, ARRAY_TYPES, BINARY_CHUNK_HEADER_INTS, BINARY_CHUNK_TYPES, BINARY_HEADER_INTS, BINARY_HEADER_LENGTH, BINARY_HEADER_MAGIC, BYTES, COMPONENTS, DEFAULT_SAMPLER, GL_SAMPLER, MIN_LIGHT_ATTENUATION, MODES, SEMANTIC_ATTRIBUTE_MAP };