@kitware/vtk.js 33.0.0-beta.2 → 33.0.0-beta.3

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 (61) hide show
  1. package/Common/Core/DataArray.d.ts +4 -0
  2. package/Common/Core/DataArray.js +3 -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/Glyph3DMapper.d.ts +45 -29
  41. package/Rendering/Core/ImageCPRMapper.js +1 -1
  42. package/Rendering/Core/ImageProperty.d.ts +22 -0
  43. package/Rendering/Core/PointPicker.js +10 -1
  44. package/Rendering/Core/Prop3D.js +1 -1
  45. package/Rendering/Core/RenderWindowInteractor.d.ts +1 -1
  46. package/Rendering/Core/RenderWindowInteractor.js +1 -1
  47. package/Rendering/Misc/CanvasView.js +4 -2
  48. package/Rendering/Misc/RemoteView.d.ts +9 -3
  49. package/Rendering/Misc/RemoteView.js +7 -3
  50. package/Rendering/Misc/SynchronizableRenderWindow/ObjectManager.d.ts +1 -1
  51. package/Rendering/OpenGL/ImageMapper.js +14 -7
  52. package/Rendering/OpenGL/Texture/supportsNorm16Linear.js +97 -0
  53. package/Rendering/OpenGL/Texture.js +18 -11
  54. package/Widgets/Widgets3D/AngleWidget/behavior.js +2 -0
  55. package/Widgets/Widgets3D/InteractiveOrientationWidget.js +1 -1
  56. package/Widgets/Widgets3D/ResliceCursorWidget/behavior.js +17 -0
  57. package/Widgets/Widgets3D/ResliceCursorWidget/helpers.js +1 -0
  58. package/Widgets/Widgets3D/ShapeWidget/behavior.js +3 -0
  59. package/_virtual/rollup-plugin-worker-loader__module_Sources/IO/Geometry/GLTFImporter/ORMTexture.worker.js +296 -0
  60. package/index.d.ts +5 -0
  61. package/package.json +12 -10
@@ -0,0 +1,518 @@
1
+ import { m as macro } from '../../../macros2.js';
2
+ import { A as degreesFromRadians } from '../../../Common/Core/Math/index.js';
3
+ import vtkActor from '../../../Rendering/Core/Actor.js';
4
+ import vtkCamera from '../../../Rendering/Core/Camera.js';
5
+ import vtkDataArray from '../../../Common/Core/DataArray.js';
6
+ import vtkPolyData from '../../../Common/DataModel/PolyData.js';
7
+ import vtkMapper from '../../../Rendering/Core/Mapper.js';
8
+ import vtkCellArray from '../../../Common/Core/CellArray.js';
9
+ import vtkTransform from '../../../Common/Transform/Transform.js';
10
+ import GLTFParser from './Parser.js';
11
+ import { ALPHA_MODE, SEMANTIC_ATTRIBUTE_MAP, MODES } from './Constants.js';
12
+ import { loadImage, createVTKTextureFromGLTFTexture } from './Utils.js';
13
+ import { handleKHRMaterialsSpecular, handleKHRMaterialsIor, handleKHRMaterialsUnlit, handleKHRMaterialsVariants, handleKHRLightsPunctual, handleKHRDracoMeshCompression } from './Extensions.js';
14
+ import { mat4, vec3, quat } from 'gl-matrix';
15
+
16
+ const {
17
+ vtkWarningMacro,
18
+ vtkDebugMacro
19
+ } = macro;
20
+
21
+ /**
22
+ * Parses a GLTF objects
23
+ * @param {Object} gltf - The GLTF object to parse
24
+ * @returns {glTF} The parsed GLTF object
25
+ */
26
+ async function parseGLTF(gltf, options) {
27
+ const parser = new GLTFParser(gltf, options);
28
+ const tree = await parser.parse();
29
+ return tree;
30
+ }
31
+
32
+ /**
33
+ * Creates VTK polydata from a GLTF mesh primitive
34
+ * @param {GLTFPrimitive} primitive - The GLTF mesh primitive
35
+ * @returns {vtkPolyData} The created VTK polydata
36
+ */
37
+ async function createPolyDataFromGLTFMesh(primitive) {
38
+ if (!primitive || !primitive.attributes) {
39
+ vtkWarningMacro('Primitive has no position data, skipping');
40
+ return null;
41
+ }
42
+ if (primitive.extensions?.KHR_draco_mesh_compression) {
43
+ return handleKHRDracoMeshCompression(primitive.extensions.KHR_draco_mesh_compression);
44
+ }
45
+ const polyData = vtkPolyData.newInstance();
46
+ const cells = vtkCellArray.newInstance();
47
+ const pointData = polyData.getPointData();
48
+ const attrs = Object.entries(primitive.attributes);
49
+ attrs.forEach(async _ref => {
50
+ let [attributeName, accessor] = _ref;
51
+ switch (attributeName) {
52
+ case SEMANTIC_ATTRIBUTE_MAP.POSITION:
53
+ {
54
+ const position = primitive.attributes.position.value;
55
+ polyData.getPoints().setData(position, primitive.attributes.position.component);
56
+ break;
57
+ }
58
+ case SEMANTIC_ATTRIBUTE_MAP.NORMAL:
59
+ {
60
+ const normals = primitive.attributes.normal.value;
61
+ pointData.setNormals(vtkDataArray.newInstance({
62
+ name: 'Normals',
63
+ values: normals,
64
+ numberOfComponents: primitive.attributes.normal.components
65
+ }));
66
+ break;
67
+ }
68
+ case SEMANTIC_ATTRIBUTE_MAP.COLOR_0:
69
+ {
70
+ const color = primitive.attributes.color.value;
71
+ pointData.setScalars(vtkDataArray.newInstance({
72
+ name: 'Scalars',
73
+ values: color,
74
+ numberOfComponents: primitive.attributes.color.components
75
+ }));
76
+ break;
77
+ }
78
+ case SEMANTIC_ATTRIBUTE_MAP.TEXCOORD_0:
79
+ {
80
+ const tcoords0 = primitive.attributes.texcoord0.value;
81
+ const da = vtkDataArray.newInstance({
82
+ name: 'TEXCOORD_0',
83
+ values: tcoords0,
84
+ numberOfComponents: primitive.attributes.texcoord0.components
85
+ });
86
+ pointData.addArray(da);
87
+ pointData.setActiveTCoords(da.getName());
88
+ break;
89
+ }
90
+ case SEMANTIC_ATTRIBUTE_MAP.TEXCOORD_1:
91
+ {
92
+ const tcoords = primitive.attributes.texcoord1.value;
93
+ const dac = vtkDataArray.newInstance({
94
+ name: 'TEXCOORD_1',
95
+ values: tcoords,
96
+ numberOfComponents: primitive.attributes.texcoord1.components
97
+ });
98
+ pointData.addArray(dac);
99
+ break;
100
+ }
101
+ case SEMANTIC_ATTRIBUTE_MAP.TANGENT:
102
+ {
103
+ const tangent = primitive.attributes.tangent.value;
104
+ const dat = vtkDataArray.newInstance({
105
+ name: 'Tangents',
106
+ values: tangent,
107
+ numberOfComponents: primitive.attributes.tangent.components
108
+ });
109
+ pointData.addArray(dat);
110
+ break;
111
+ }
112
+ default:
113
+ vtkWarningMacro(`Unhandled attribute: ${attributeName}`);
114
+ }
115
+ });
116
+
117
+ // Handle indices if available
118
+ if (primitive.indices != null) {
119
+ const indices = primitive.indices.value;
120
+ const nCells = indices.length - 2;
121
+ switch (primitive.mode) {
122
+ case MODES.GL_LINE_STRIP:
123
+ case MODES.GL_TRIANGLE_STRIP:
124
+ case MODES.GL_LINE_LOOP:
125
+ vtkWarningMacro('GL_LINE_LOOP not implemented');
126
+ break;
127
+ default:
128
+ cells.resize(4 * indices.length / 3);
129
+ for (let cellId = 0; cellId < nCells; cellId += 3) {
130
+ const cell = indices.slice(cellId, cellId + 3);
131
+ cells.insertNextCell(cell);
132
+ }
133
+ }
134
+ }
135
+ switch (primitive.mode) {
136
+ case MODES.GL_TRIANGLES:
137
+ case MODES.GL_TRIANGLE_FAN:
138
+ polyData.setPolys(cells);
139
+ break;
140
+ case MODES.GL_LINES:
141
+ case MODES.GL_LINE_STRIP:
142
+ case MODES.GL_LINE_LOOP:
143
+ polyData.setLines(cells);
144
+ break;
145
+ case MODES.GL_POINTS:
146
+ polyData.setVerts(cells);
147
+ break;
148
+ case MODES.GL_TRIANGLE_STRIP:
149
+ polyData.setStrips(cells);
150
+ break;
151
+ default:
152
+ vtkWarningMacro('Invalid primitive draw mode. Ignoring connectivity.');
153
+ }
154
+ return polyData;
155
+ }
156
+
157
+ /**
158
+ * Creates a VTK property from a GLTF material
159
+ * @param {object} model - The vtk model object
160
+ * @param {GLTFMaterial} material - The GLTF material
161
+ * @param {vtkActor} actor - The VTK actor
162
+ */
163
+ async function createPropertyFromGLTFMaterial(model, material, actor) {
164
+ let metallicFactor = 1.0;
165
+ let roughnessFactor = 1.0;
166
+ const emissiveFactor = material.emissiveFactor;
167
+ const property = actor.getProperty();
168
+ const pbr = material.pbrMetallicRoughness;
169
+ if (pbr != null) {
170
+ if (!pbr?.metallicFactor || pbr?.metallicFactor <= 0 || pbr?.metallicFactor >= 1) {
171
+ vtkDebugMacro('Invalid material.pbrMetallicRoughness.metallicFactor value. Using default value instead.');
172
+ } else metallicFactor = pbr.metallicFactor;
173
+ if (!pbr?.roughnessFactor || pbr?.roughnessFactor <= 0 || pbr?.roughnessFactor >= 1) {
174
+ vtkDebugMacro('Invalid material.pbrMetallicRoughness.roughnessFactor value. Using default value instead.');
175
+ } else roughnessFactor = pbr.roughnessFactor;
176
+ const color = pbr.baseColorFactor;
177
+ if (color != null) {
178
+ property.setDiffuseColor(color[0], color[1], color[2]);
179
+ property.setOpacity(color[3]);
180
+ }
181
+ property.setMetallic(metallicFactor);
182
+ property.setRoughness(roughnessFactor);
183
+ property.setEmission(emissiveFactor);
184
+ if (pbr.baseColorTexture) {
185
+ pbr.baseColorTexture.extensions;
186
+ const tex = pbr.baseColorTexture.texture;
187
+ if (tex.extensions != null) {
188
+ const extensionsNames = Object.keys(tex.extensions);
189
+ extensionsNames.forEach(extensionName => {
190
+ // TODO: Handle KHR_texture_basisu extension
191
+ // const extension = tex.extensions[extensionName];
192
+ switch (extensionName) {
193
+ default:
194
+ vtkWarningMacro(`Unhandled extension: ${extensionName}`);
195
+ }
196
+ });
197
+ }
198
+ const sampler = tex.sampler;
199
+ const image = await loadImage(tex.source);
200
+ const diffuseTex = createVTKTextureFromGLTFTexture(image, sampler);
201
+
202
+ // FIXME: Workaround for textures not showing up in WebGL
203
+ const viewAPI = model.renderer.getRenderWindow();
204
+ const isWebGL = viewAPI.getViews()[0].isA('vtkOpenGLRenderWindow');
205
+ if (isWebGL) {
206
+ actor.addTexture(diffuseTex);
207
+ } else {
208
+ property.setDiffuseTexture(diffuseTex);
209
+ }
210
+ }
211
+ if (pbr.metallicRoughnessTexture) {
212
+ pbr.metallicRoughnessTexture.extensions;
213
+ const tex = pbr.metallicRoughnessTexture.texture;
214
+ const sampler = tex.sampler;
215
+ const metallicImage = await loadImage(tex.source, 'b');
216
+ const metallicTex = createVTKTextureFromGLTFTexture(metallicImage, sampler);
217
+ property.setMetallicTexture(metallicTex);
218
+ const roughnessImage = await loadImage(tex.source, 'g');
219
+ const roughnessTex = createVTKTextureFromGLTFTexture(roughnessImage, sampler);
220
+ property.setRoughnessTexture(roughnessTex);
221
+ }
222
+
223
+ // Handle ambient occlusion texture (occlusionTexture)
224
+ if (material.occlusionTexture) {
225
+ material.occlusionTexture.extensions;
226
+ const tex = material.occlusionTexture.texture;
227
+ const sampler = tex.sampler;
228
+ const aoImage = await loadImage(tex.source, 'r');
229
+ const aoTex = createVTKTextureFromGLTFTexture(aoImage, sampler);
230
+ property.setAmbientOcclusionTexture(aoTex);
231
+ }
232
+
233
+ // Handle emissive texture (emissiveTexture)
234
+ if (material.emissiveTexture) {
235
+ material.emissiveTexture.extensions;
236
+ const tex = material.emissiveTexture.texture;
237
+ const sampler = tex.sampler;
238
+ const emissiveImage = await loadImage(tex.source);
239
+ const emissiveTex = createVTKTextureFromGLTFTexture(emissiveImage, sampler);
240
+ property.setEmissionTexture(emissiveTex);
241
+
242
+ // Handle mutiple Uvs
243
+ if (material.emissiveTexture.texCoord != null) {
244
+ const pd = actor.getMapper().getInputData().getPointData();
245
+ pd.setActiveTCoords(`TEXCOORD_${material.emissiveTexture.texCoord}`);
246
+ }
247
+ }
248
+
249
+ // Handle normal texture (normalTexture)
250
+ if (material.normalTexture) {
251
+ material.normalTexture.extensions;
252
+ const tex = material.normalTexture.texture;
253
+ const sampler = tex.sampler;
254
+ const normalImage = await loadImage(tex.source);
255
+ const normalTex = createVTKTextureFromGLTFTexture(normalImage, sampler);
256
+ property.setNormalTexture(normalTex);
257
+ if (material.normalTexture.scale != null) {
258
+ property.setNormalStrength(material.normalTexture.scale);
259
+ }
260
+ }
261
+ }
262
+
263
+ // Material extensions
264
+ if (material.extensions != null) {
265
+ const extensionsNames = Object.keys(material.extensions);
266
+ extensionsNames.forEach(extensionName => {
267
+ const extension = material.extensions[extensionName];
268
+ switch (extensionName) {
269
+ case 'KHR_materials_unlit':
270
+ handleKHRMaterialsUnlit(extension, property);
271
+ break;
272
+ case 'KHR_materials_ior':
273
+ handleKHRMaterialsIor(extension, property);
274
+ break;
275
+ case 'KHR_materials_specular':
276
+ handleKHRMaterialsSpecular(extension, property);
277
+ break;
278
+ default:
279
+ vtkWarningMacro(`Unhandled extension: ${extensionName}`);
280
+ }
281
+ });
282
+ }
283
+ if (material.alphaMode !== ALPHA_MODE.OPAQUE) {
284
+ actor.setForceTranslucent(true);
285
+ }
286
+ property.setBackfaceCulling(!material.doubleSided);
287
+ }
288
+
289
+ /**
290
+ * Handles primitive extensions
291
+ * @param {string} nodeId The GLTF node id
292
+ * @param {*} extensions The extensions object
293
+ * @param {*} model The vtk model object
294
+ */
295
+ function handlePrimitiveExtensions(nodeId, extensions, model) {
296
+ const extensionsNames = Object.keys(extensions);
297
+ extensionsNames.forEach(extensionName => {
298
+ const extension = extensions[extensionName];
299
+ switch (extensionName) {
300
+ case 'KHR_materials_variants':
301
+ model.variantMappings.set(nodeId, extension.mappings);
302
+ break;
303
+ default:
304
+ vtkWarningMacro(`Unhandled extension: ${extensionName}`);
305
+ }
306
+ });
307
+ }
308
+
309
+ /**
310
+ * Creates a VTK actor from a GLTF mesh
311
+ * @param {GLTFMesh} mesh - The GLTF mesh
312
+ * @returns {vtkActor} The created VTK actor
313
+ */
314
+ async function createActorFromGTLFNode(worldMatrix) {
315
+ const actor = vtkActor.newInstance();
316
+ const mapper = vtkMapper.newInstance();
317
+ mapper.setColorModeToDirectScalars();
318
+ actor.setMapper(mapper);
319
+ actor.setUserMatrix(worldMatrix);
320
+ const polydata = vtkPolyData.newInstance();
321
+ mapper.setInputData(polydata);
322
+ return actor;
323
+ }
324
+
325
+ /**
326
+ * Creates a VTK actor from a GLTF mesh
327
+ * @param {GLTFMesh} mesh - The GLTF mesh
328
+ * @returns {vtkActor} The created VTK actor
329
+ */
330
+ async function createActorFromGTLFPrimitive(model, primitive, worldMatrix) {
331
+ const actor = vtkActor.newInstance();
332
+ const mapper = vtkMapper.newInstance();
333
+ mapper.setColorModeToDirectScalars();
334
+ actor.setMapper(mapper);
335
+ actor.setUserMatrix(worldMatrix);
336
+ const polydata = await createPolyDataFromGLTFMesh(primitive);
337
+ mapper.setInputData(polydata);
338
+
339
+ // Support for materials
340
+ if (primitive.material != null) {
341
+ await createPropertyFromGLTFMaterial(model, primitive.material, actor);
342
+ }
343
+ if (primitive.extensions != null) {
344
+ handlePrimitiveExtensions(`${primitive.name}`, primitive.extensions, model);
345
+ }
346
+ return actor;
347
+ }
348
+
349
+ /**
350
+ * Creates a GLTF animation object
351
+ * @param {GLTFAnimation} animation
352
+ * @returns
353
+ */
354
+ function createGLTFAnimation(animation) {
355
+ vtkDebugMacro('Creating animation:', animation);
356
+ return {
357
+ name: animation.name,
358
+ channels: animation.channels,
359
+ samplers: animation.samplers,
360
+ getChannelByTargetNode(nodeIndex) {
361
+ return this.channels.filter(channel => channel.target.node === nodeIndex);
362
+ }
363
+ };
364
+ }
365
+
366
+ /**
367
+ * Gets the transformation matrix for a GLTF node
368
+ * @param {GLTFNode} node - The GLTF node
369
+ * @returns {mat4} The transformation matrix
370
+ */
371
+ function getTransformationMatrix(node) {
372
+ // TRS
373
+ const translation = node.translation ?? vec3.create();
374
+ const rotation = node.rotation ?? quat.create();
375
+ const scale = node.scale ?? vec3.fromValues(1.0, 1.0, 1.0);
376
+ const matrix = node.matrix != null ? mat4.clone(node.matrix) : mat4.fromRotationTranslationScale(mat4.create(), rotation, translation, scale);
377
+ return matrix;
378
+ }
379
+
380
+ /**
381
+ * Processes a GLTF node
382
+ * @param {GLTFnode} node - The GLTF node
383
+ * @param {object} model The model object
384
+ * @param {vtkActor} parentActor The parent actor
385
+ * @param {mat4} parentMatrix The parent matrix
386
+ */
387
+ async function processNode(node, model) {
388
+ let parentActor = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
389
+ let parentMatrix = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : mat4.create();
390
+ node.transform = getTransformationMatrix(node);
391
+ const worldMatrix = mat4.multiply(mat4.create(), parentMatrix, node.transform);
392
+
393
+ // Create actor for the current node
394
+ if (node.mesh != null) {
395
+ const nodeActor = await createActorFromGTLFNode(worldMatrix);
396
+ if (parentActor) {
397
+ nodeActor.setParentProp(parentActor);
398
+ }
399
+ model.actors.set(`${node.id}`, nodeActor);
400
+ await Promise.all(node.mesh.primitives.map(async (primitive, i) => {
401
+ const actor = await createActorFromGTLFPrimitive(model, primitive, worldMatrix);
402
+ actor.setParentProp(nodeActor);
403
+ model.actors.set(`${node.id}_${primitive.name}`, actor);
404
+ }));
405
+ }
406
+
407
+ // Handle KHRLightsPunctual extension
408
+ if (node.extensions?.KHR_lights_punctual) {
409
+ handleKHRLightsPunctual(node.extensions.KHR_lights_punctual, node.transform, model);
410
+ }
411
+ if (node.children && Array.isArray(node.children) && node.children.length > 0) {
412
+ await Promise.all(node.children.map(async child => {
413
+ const parent = model.actors.get(node.id);
414
+ await processNode(child, model, parent, worldMatrix);
415
+ }));
416
+ }
417
+ }
418
+
419
+ /**
420
+ * Creates VTK actors from a GLTF object
421
+ * @param {glTF} glTF - The GLTF object
422
+ * @param {number} sceneId - The scene index to create actors for
423
+ * @returns {vtkActor[]} The created VTK actors
424
+ */
425
+ async function createVTKObjects(model) {
426
+ model.animations = model.glTFTree.animations?.map(createGLTFAnimation);
427
+ const extensionsNames = Object.keys(model.glTFTree?.extensions || []);
428
+ extensionsNames.forEach(extensionName => {
429
+ const extension = model.glTFTree.extensions[extensionName];
430
+ switch (extensionName) {
431
+ case 'KHR_materials_variants':
432
+ handleKHRMaterialsVariants(extension, model);
433
+ break;
434
+ case 'KHR_draco_mesh_compression':
435
+ break;
436
+ default:
437
+ vtkWarningMacro(`Unhandled extension: ${extensionName}`);
438
+ }
439
+ });
440
+
441
+ // Get the sceneId to process
442
+ const sceneId = model.sceneId ?? model.glTFTree.scene;
443
+ if (model.glTFTree.scenes?.length && model.glTFTree.scenes[sceneId]?.nodes) {
444
+ await Promise.all(model.glTFTree.scenes[sceneId].nodes.map(async node => {
445
+ if (node) {
446
+ await processNode(node, model);
447
+ } else {
448
+ vtkWarningMacro(`Node not found in glTF.nodes`);
449
+ }
450
+ }));
451
+ } else {
452
+ vtkWarningMacro('No valid scenes found in the glTF data');
453
+ }
454
+ }
455
+
456
+ /**
457
+ * Sets up the camera for a vtk renderer based on the bounds of the given actors.
458
+ *
459
+ * @param {GLTCamera} camera - The GLTF camera object
460
+ */
461
+ function GLTFCameraToVTKCamera(glTFCamera) {
462
+ const camera = vtkCamera.newInstance();
463
+ if (glTFCamera.type === 'perspective') {
464
+ const {
465
+ yfov,
466
+ znear,
467
+ zfar
468
+ } = glTFCamera.perspective;
469
+ camera.setClippingRange(znear, zfar);
470
+ camera.setParallelProjection(false);
471
+ camera.setViewAngle(degreesFromRadians(yfov));
472
+ } else if (glTFCamera.type === 'orthographic') {
473
+ const {
474
+ ymag,
475
+ znear,
476
+ zfar
477
+ } = glTFCamera.orthographic;
478
+ camera.setClippingRange(znear, zfar);
479
+ camera.setParallelProjection(true);
480
+ camera.setParallelScale(ymag);
481
+ } else {
482
+ throw new Error('Unsupported camera type');
483
+ }
484
+ return camera;
485
+ }
486
+
487
+ /**
488
+ *
489
+ * @param {vtkCamera} camera
490
+ * @param {*} transformMatrix
491
+ */
492
+ function applyTransformToCamera(camera, transformMatrix) {
493
+ if (!camera || !transformMatrix) {
494
+ return;
495
+ }
496
+
497
+ // At identity, camera position is origin, +y up, -z view direction
498
+ const position = [0, 0, 0];
499
+ const viewUp = [0, 1, 0];
500
+ const focus = [0, 0, -1];
501
+ const t = vtkTransform.newInstance();
502
+ t.setMatrix(transformMatrix);
503
+
504
+ // Transform position
505
+ t.transformPoint(position, position);
506
+ t.transformPoints(viewUp, viewUp);
507
+ t.transformPoints(focus, focus);
508
+ focus[0] += position[0];
509
+ focus[1] += position[1];
510
+ focus[2] += position[2];
511
+
512
+ // Apply the transformed values to the camera
513
+ camera.setPosition(position);
514
+ camera.setFocalPoint(focus);
515
+ camera.setViewUp(viewUp);
516
+ }
517
+
518
+ export { GLTFCameraToVTKCamera, applyTransformToCamera, createPropertyFromGLTFMaterial, createVTKObjects, parseGLTF };
@@ -0,0 +1,165 @@
1
+ import WebworkerPromise from 'webworker-promise';
2
+ import { m as macro } from '../../../macros2.js';
3
+ import vtkTexture from '../../../Rendering/Core/Texture.js';
4
+ import { W as WorkerFactory } from '../../../_virtual/rollup-plugin-worker-loader__module_Sources/IO/Geometry/GLTFImporter/ORMTexture.worker.js';
5
+ import { ARRAY_TYPES, COMPONENTS, BYTES, GL_SAMPLER } from './Constants.js';
6
+
7
+ const {
8
+ vtkWarningMacro,
9
+ vtkErrorMacro
10
+ } = macro;
11
+
12
+ /**
13
+ * Get GL enum from sampler parameter
14
+ * @param {*} parameter The sampler parameter
15
+ * @returns The GL enum
16
+ */
17
+ function getGLEnumFromSamplerParameter(parameter) {
18
+ const GL_TEXTURE_MAG_FILTER = 0x2800;
19
+ const GL_TEXTURE_MIN_FILTER = 0x2801;
20
+ const GL_TEXTURE_WRAP_S = 0x2802;
21
+ const GL_TEXTURE_WRAP_T = 0x2803;
22
+ const Mapping = {
23
+ magFilter: GL_TEXTURE_MAG_FILTER,
24
+ minFilter: GL_TEXTURE_MIN_FILTER,
25
+ wrapS: GL_TEXTURE_WRAP_S,
26
+ wrapT: GL_TEXTURE_WRAP_T
27
+ };
28
+ return Mapping[parameter];
29
+ }
30
+ function getAccessorArrayTypeAndLength(accessor, bufferView) {
31
+ const ArrayType = ARRAY_TYPES[accessor.componentType];
32
+ const components = COMPONENTS[accessor.type];
33
+ const bytesPerComponent = BYTES[accessor.componentType];
34
+ const length = accessor.count * components;
35
+ const byteLength = accessor.count * components * bytesPerComponent;
36
+ return {
37
+ ArrayType,
38
+ length,
39
+ byteLength
40
+ };
41
+ }
42
+
43
+ /**
44
+ * Resolves a URL based on the original path
45
+ * @param {*} url The URL to resolve
46
+ * @param {*} originalPath The original path to resolve the URL against
47
+ * @returns The resolved URL or an empty string if the URL is invalid
48
+ */
49
+ function resolveUrl(url, originalPath) {
50
+ // Invalid URL
51
+ if (typeof url !== 'string' || url === '') return '';
52
+ try {
53
+ // Data URI
54
+ if (url.startsWith('data:')) return url;
55
+
56
+ // Blob URL
57
+ if (url.startsWith('blob:')) return url;
58
+
59
+ // Create URL object from the original path
60
+ const baseUrl = new URL(originalPath);
61
+ if (!baseUrl.pathname.includes('.') && !baseUrl.pathname.endsWith('/')) {
62
+ baseUrl.pathname += '/';
63
+ }
64
+
65
+ // Absolute URL (http://, https://, //)
66
+ if (url.startsWith('http:') || url.startsWith('https:') || url.startsWith('//')) {
67
+ return new URL(url, baseUrl).href;
68
+ }
69
+
70
+ // Host Relative URL
71
+ if (url.startsWith('/')) {
72
+ return new URL(url, baseUrl).href;
73
+ }
74
+
75
+ // Relative URL
76
+ return new URL(url, baseUrl).href;
77
+ } catch (error) {
78
+ vtkErrorMacro('Error resolving URL:', error);
79
+ return '';
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Loads image from buffer or URI
85
+ * @param {*} image
86
+ * @param {*} channel
87
+ * @returns
88
+ */
89
+ async function loadImage(image, channel) {
90
+ let forceReLoad = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
91
+ // Initialize cache if it doesn't exist
92
+ if (!image.cache) {
93
+ image.cache = {};
94
+ }
95
+
96
+ // Return cached result for the channel if available and not forced to reload
97
+ if (!forceReLoad && image.cache[channel]) {
98
+ return image.cache[channel];
99
+ }
100
+ const worker = new WebworkerPromise(new WorkerFactory());
101
+ if (image.bufferView) {
102
+ return worker.postMessage({
103
+ imageBuffer: image.bufferView.data,
104
+ mimeType: image.mimeType,
105
+ channel
106
+ }).then(result => {
107
+ // Cache the bitmap based on the channel
108
+ image.cache[channel] = result.bitmap;
109
+ return result.bitmap;
110
+ }).finally(() => {
111
+ worker.terminate();
112
+ });
113
+ }
114
+ if (image.uri) {
115
+ vtkWarningMacro('Falling back to image uri', image.uri);
116
+ return new Promise((resolve, reject) => {
117
+ const img = new Image();
118
+ img.crossOrigin = 'Anonymous';
119
+ img.onload = () => {
120
+ image.cache[channel] = img; // Cache the loaded image based on the channel
121
+ resolve(img);
122
+ };
123
+ img.onerror = reject;
124
+ img.src = image.uri;
125
+ });
126
+ }
127
+ return null;
128
+ }
129
+
130
+ /**
131
+ *
132
+ * @param {*} image
133
+ * @param {*} sampler
134
+ * @param {*} extensions
135
+ * @returns
136
+ */
137
+ function createVTKTextureFromGLTFTexture(image, sampler, extensions) {
138
+ const texture = vtkTexture.newInstance();
139
+ // Apply sampler settings
140
+ if (sampler) {
141
+ if ('wrapS' in sampler && 'wrapT' in sampler || 'minFilter' in sampler && 'magFilter' in sampler) {
142
+ if (sampler.wrapS === GL_SAMPLER.CLAMP_TO_EDGE || sampler.wrapT === GL_SAMPLER.CLAMP_TO_EDGE) {
143
+ texture.setRepeat(false);
144
+ texture.setEdgeClamp(true);
145
+ } else if (sampler.wrapS === GL_SAMPLER.REPEAT || sampler.wrapT === GL_SAMPLER.REPEAT) {
146
+ texture.setRepeat(true);
147
+ texture.setEdgeClamp(false);
148
+ } else {
149
+ vtkWarningMacro('Mirrored texture wrapping is not supported!');
150
+ }
151
+ const linearFilters = [GL_SAMPLER.LINEAR, GL_SAMPLER.LINEAR_MIPMAP_NEAREST, GL_SAMPLER.NEAREST_MIPMAP_LINEAR, GL_SAMPLER.LINEAR_MIPMAP_LINEAR];
152
+ if (linearFilters.includes(sampler.minFilter) || linearFilters.includes(sampler.magFilter)) {
153
+ texture.setInterpolate(true);
154
+ }
155
+ } else {
156
+ texture.setMipLevel(8);
157
+ texture.setInterpolate(true);
158
+ texture.setEdgeClamp(true);
159
+ }
160
+ }
161
+ texture.setJsImageData(image);
162
+ return texture;
163
+ }
164
+
165
+ export { createVTKTextureFromGLTFTexture, getAccessorArrayTypeAndLength, getGLEnumFromSamplerParameter, loadImage, resolveUrl };