@kitware/vtk.js 34.0.0-beta.2 → 34.0.0

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.
@@ -1,65 +1,79 @@
1
1
  import BinaryHelper from '../../Core/BinaryHelper.js';
2
- import { BINARY_HEADER_MAGIC, BINARY_CHUNK_TYPES, BINARY_CHUNK_HEADER_INTS, BINARY_HEADER_LENGTH, BINARY_HEADER_INTS } from './Constants.js';
2
+ import { BINARY_HEADER_LENGTH, BINARY_HEADER_MAGIC, BINARY_CHUNK_TYPES, BINARY_CHUNK_HEADER_INTS, BINARY_HEADER_INTS } from './Constants.js';
3
3
 
4
4
  function getChunkInfo(headerStart, data) {
5
+ // Cache array view
5
6
  const header = new Uint32Array(data, headerStart, BINARY_CHUNK_HEADER_INTS);
6
7
  const chunkStart = headerStart + BINARY_CHUNK_HEADER_INTS * 4;
7
- const chunkLength = header[0];
8
- const chunkType = header[1];
9
8
  return {
10
9
  start: chunkStart,
11
- length: chunkLength,
12
- type: chunkType
10
+ length: header[0],
11
+ type: header[1]
13
12
  };
14
13
  }
15
14
  function getAllChunkInfos(data) {
16
- const infos = [];
15
+ // Pre-calculate array size
16
+ const maxChunks = Math.floor((data.byteLength - BINARY_HEADER_LENGTH) / 8);
17
+ const infos = new Array(maxChunks);
17
18
  let chunkStart = BINARY_HEADER_INTS * 4;
19
+ let chunkCount = 0;
18
20
  while (chunkStart < data.byteLength) {
19
21
  const chunkInfo = getChunkInfo(chunkStart, data);
20
- infos.push(chunkInfo);
22
+ infos[chunkCount++] = chunkInfo;
21
23
  chunkStart += chunkInfo.length + BINARY_CHUNK_HEADER_INTS * 4;
22
24
  }
23
- return infos;
25
+
26
+ // Trim array to actual size
27
+ return infos.slice(0, chunkCount);
24
28
  }
25
29
  function getJsonFromChunk(chunkInfo, data) {
26
- const chunkLength = chunkInfo.length;
27
30
  const jsonStart = (BINARY_HEADER_INTS + BINARY_CHUNK_HEADER_INTS) * 4;
28
- const jsonSlice = new Uint8Array(data, jsonStart, chunkLength);
29
- const stringBuffer = BinaryHelper.arrayBufferToString(jsonSlice);
30
- return JSON.parse(stringBuffer);
31
+ const jsonView = new Uint8Array(data, jsonStart, chunkInfo.length);
32
+ const decoder = new TextDecoder('utf-8');
33
+ const jsonString = decoder.decode(jsonView);
34
+ return JSON.parse(jsonString);
31
35
  }
32
36
  function getBufferFromChunk(chunkInfo, data) {
33
37
  return data.slice(chunkInfo.start, chunkInfo.start + chunkInfo.length);
34
38
  }
35
39
  function parseGLB(data) {
36
- let json;
37
- const buffers = [];
40
+ if (data.byteLength < BINARY_HEADER_LENGTH) {
41
+ throw new Error('Invalid GLB: File too small');
42
+ }
43
+
44
+ // Cache DataView
38
45
  const headerView = new DataView(data, 0, BINARY_HEADER_LENGTH);
46
+ const magic = new Uint8Array(data, 0, 4);
39
47
  const header = {
40
- magic: BinaryHelper.arrayBufferToString(new Uint8Array(data, 0, 4)),
48
+ magic: BinaryHelper.arrayBufferToString(magic),
41
49
  version: headerView.getUint32(4, true),
42
50
  length: headerView.getUint32(8, true)
43
51
  };
44
52
  if (header.magic !== BINARY_HEADER_MAGIC) {
45
53
  throw new Error('Unsupported glTF-Binary header.');
46
- } else if (header.version < 2.0) {
54
+ }
55
+ if (header.version < 2.0) {
47
56
  throw new Error('Unsupported legacy binary file detected.');
48
57
  }
58
+ if (header.length > data.byteLength) {
59
+ throw new Error('Invalid GLB: Declared length exceeds file size');
60
+ }
49
61
  const chunkInfos = getAllChunkInfos(data);
50
- chunkInfos.forEach(chunkInfo => {
62
+ let json = null;
63
+ const buffers = [];
64
+
65
+ // Process chunks sequentially
66
+ for (let i = 0; i < chunkInfos.length; i++) {
67
+ const chunkInfo = chunkInfos[i];
51
68
  if (chunkInfo.type === BINARY_CHUNK_TYPES.JSON && !json) {
52
69
  json = getJsonFromChunk(chunkInfo, data);
53
70
  } else if (chunkInfo.type === BINARY_CHUNK_TYPES.BIN) {
54
71
  buffers.push(getBufferFromChunk(chunkInfo, data));
55
72
  }
56
- });
73
+ }
57
74
  if (!json) {
58
75
  throw new Error('glTF-Binary: JSON content not found.');
59
76
  }
60
- if (!buffers) {
61
- throw new Error('glTF-Binary: Binary chunk not found.');
62
- }
63
77
  return {
64
78
  json,
65
79
  buffers
@@ -210,15 +210,24 @@ class GLTFParser {
210
210
  if (accessor.bufferView) {
211
211
  const buffer = accessor.bufferView.buffer;
212
212
  const {
213
- ArrayType,
214
- byteLength
213
+ ArrayType
215
214
  } = getAccessorArrayTypeAndLength(accessor, accessor.bufferView);
216
- const byteOffset = (accessor.bufferView.byteOffset || 0) + (accessor.byteOffset || 0) + buffer.byteOffset;
217
- let slicedBufffer = buffer.arrayBuffer.slice(byteOffset, byteOffset + byteLength);
215
+ const baseByteOffset = (accessor.bufferView.byteOffset || 0) + buffer.byteOffset;
216
+ const byteOffset = baseByteOffset + (accessor.byteOffset || 0);
217
+ let arrayBufferView;
218
218
  if (accessor.bufferView.byteStride) {
219
- slicedBufffer = this.getValueFromInterleavedBuffer(buffer, byteOffset, accessor.bufferView.byteStride, accessor.bytesPerElement, accessor.count);
219
+ // Only extract if stride is not equal to element size
220
+ if (accessor.bufferView.byteStride === accessor.bytesPerElement) {
221
+ arrayBufferView = new ArrayType(buffer.arrayBuffer, byteOffset, accessor.count * accessor.components);
222
+ } else {
223
+ // Interleaved buffer, extract only needed bytes
224
+ const interleavedBuffer = this.getValueFromInterleavedBuffer(buffer, byteOffset, accessor.bufferView.byteStride, accessor.bytesPerElement, accessor.count);
225
+ arrayBufferView = new ArrayType(interleavedBuffer);
226
+ }
227
+ } else {
228
+ arrayBufferView = new ArrayType(buffer.arrayBuffer, byteOffset, accessor.count * accessor.components);
220
229
  }
221
- accessor.value = new ArrayType(slicedBufffer);
230
+ accessor.value = arrayBufferView;
222
231
  }
223
232
  return accessor;
224
233
  }
@@ -149,6 +149,7 @@ async function createPolyDataFromGLTFMesh(primitive) {
149
149
  polyData.setStrips(cells);
150
150
  break;
151
151
  default:
152
+ cells.delete();
152
153
  vtkWarningMacro('Invalid primitive draw mode. Ignoring connectivity.');
153
154
  }
154
155
  return polyData;
@@ -198,15 +199,7 @@ async function createPropertyFromGLTFMaterial(model, material, actor) {
198
199
  const sampler = tex.sampler;
199
200
  const image = await loadImage(tex.source);
200
201
  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
- }
202
+ property.setDiffuseTexture(diffuseTex);
210
203
  }
211
204
 
212
205
  // Handle metallic-roughness texture (metallicRoughnessTexture)
@@ -224,7 +217,7 @@ async function createPropertyFromGLTFMaterial(model, material, actor) {
224
217
  material.occlusionTexture.extensions;
225
218
  const tex = material.occlusionTexture.texture;
226
219
  const sampler = tex.sampler;
227
- const aoImage = await loadImage(tex.source, 'r');
220
+ const aoImage = await loadImage(tex.source);
228
221
  const aoTex = createVTKTextureFromGLTFTexture(aoImage, sampler);
229
222
  property.setAmbientOcclusionTexture(aoTex);
230
223
  }
@@ -299,6 +292,8 @@ function handlePrimitiveExtensions(nodeId, extensions, model) {
299
292
  case 'KHR_materials_variants':
300
293
  model.variantMappings.set(nodeId, extension.mappings);
301
294
  break;
295
+ case 'KHR_draco_mesh_compression':
296
+ break;
302
297
  default:
303
298
  vtkWarningMacro(`Unhandled extension: ${extensionName}`);
304
299
  }
@@ -314,6 +309,7 @@ async function createActorFromGTLFNode(worldMatrix) {
314
309
  const actor = vtkActor.newInstance();
315
310
  const mapper = vtkMapper.newInstance();
316
311
  mapper.setColorModeToDirectScalars();
312
+ mapper.setInterpolateScalarsBeforeMapping(true);
317
313
  actor.setMapper(mapper);
318
314
  actor.setUserMatrix(worldMatrix);
319
315
  const polydata = vtkPolyData.newInstance();
@@ -330,6 +326,7 @@ async function createActorFromGTLFPrimitive(model, primitive, worldMatrix) {
330
326
  const actor = vtkActor.newInstance();
331
327
  const mapper = vtkMapper.newInstance();
332
328
  mapper.setColorModeToDirectScalars();
329
+ mapper.setInterpolateScalarsBeforeMapping(true);
333
330
  actor.setMapper(mapper);
334
331
  actor.setUserMatrix(worldMatrix);
335
332
  const polydata = await createPolyDataFromGLTFMesh(primitive);
@@ -1,7 +1,5 @@
1
- import WebworkerPromise from 'webworker-promise';
2
1
  import { m as macro } from '../../../macros2.js';
3
2
  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
3
  import { ARRAY_TYPES, COMPONENTS, BYTES, GL_SAMPLER } from './Constants.js';
6
4
 
7
5
  const {
@@ -83,33 +81,18 @@ function resolveUrl(url, originalPath) {
83
81
  /**
84
82
  * Loads image from buffer or URI
85
83
  * @param {*} image
86
- * @param {*} channel
87
84
  * @returns
88
85
  */
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());
86
+ async function loadImage(image) {
101
87
  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();
88
+ const blob = new Blob([image.bufferView.data], {
89
+ type: image.mimeType
90
+ });
91
+ const bitmap = await createImageBitmap(blob, {
92
+ colorSpaceConversion: 'none',
93
+ imageOrientation: 'flipY'
112
94
  });
95
+ return bitmap;
113
96
  }
114
97
  if (image.uri) {
115
98
  vtkWarningMacro('Falling back to image uri', image.uri);
@@ -117,7 +100,6 @@ async function loadImage(image, channel) {
117
100
  const img = new Image();
118
101
  img.crossOrigin = 'Anonymous';
119
102
  img.onload = () => {
120
- image.cache[channel] = img; // Cache the loaded image based on the channel
121
103
  resolve(img);
122
104
  };
123
105
  img.onerror = reject;
@@ -158,7 +140,7 @@ function createVTKTextureFromGLTFTexture(image, sampler, extensions) {
158
140
  texture.setEdgeClamp(true);
159
141
  }
160
142
  }
161
- texture.setJsImageData(image);
143
+ texture.setImageBitmap(image);
162
144
  return texture;
163
145
  }
164
146
 
@@ -629,12 +629,12 @@ function vtkWebGPUCellArrayMapper(publicAPI, model) {
629
629
  } else {
630
630
  if (roughnessTexture?.getImageLoaded()) {
631
631
  if (checkDims(roughnessTexture)) {
632
- usedTextures.push('_roughnessMap = textureSample(RoughnessTexture, RoughnessTextureSampler, input.tcoordVS);');
632
+ usedTextures.push('_roughnessMap = textureSample(RoughnessTexture, RoughnessTextureSampler, input.tcoordVS).ggga;');
633
633
  }
634
634
  }
635
635
  if (metallicTexture?.getImageLoaded()) {
636
636
  if (checkDims(metallicTexture)) {
637
- usedTextures.push('_metallicMap = textureSample(MetallicTexture, MetallicTextureSampler, input.tcoordVS);');
637
+ usedTextures.push('_metallicMap = textureSample(MetallicTexture, MetallicTextureSampler, input.tcoordVS).bbba;');
638
638
  }
639
639
  }
640
640
  if (ambientOcclusionTexture?.getImageLoaded()) {
@@ -847,11 +847,11 @@ function vtkWebGPUCellArrayMapper(publicAPI, model) {
847
847
  }
848
848
  if (idata) {
849
849
  model.colorTexture.setInputData(idata);
850
- newTextures.push(['Diffuse', model.colorTexture]);
850
+ newTextures.push(['DiffuseTexture', model.colorTexture]);
851
851
  }
852
852
  const actor = model.WebGPUActor.getRenderable();
853
853
  const renderer = model.WebGPURenderer.getRenderable();
854
- const textures = [['Diffuse', actor.getProperty().getDiffuseTexture?.()], ['Diffuse', actor.getTextures()[0]], ['Diffuse', model.colorTexture], ['ORM', actor.getProperty().getORMTexture?.()], ['RM', actor.getProperty().getRMTexture?.()], ['Roughness', actor.getProperty().getRoughnessTexture?.()], ['Metallic', actor.getProperty().getMetallicTexture?.()], ['Normal', actor.getProperty().getNormalTexture?.()], ['AmbientOcclusion', actor.getProperty().getAmbientOcclusionTexture?.()], ['Emission', actor.getProperty().getEmissionTexture?.()], ['Environment', renderer.getEnvironmentTexture?.()]];
854
+ const textures = [['DiffuseTexture', actor.getProperty().getDiffuseTexture?.()], ['DiffuseTexture', actor.getTextures()[0]], ['DiffuseTexture', model.colorTexture], ['ORMTexture', actor.getProperty().getORMTexture?.()], ['RMTexture', actor.getProperty().getRMTexture?.()], ['RoughnessTexture', actor.getProperty().getRoughnessTexture?.()], ['MetallicTexture', actor.getProperty().getMetallicTexture?.()], ['NormalTexture', actor.getProperty().getNormalTexture?.()], ['AmbientOcclusionTexture', actor.getProperty().getAmbientOcclusionTexture?.()], ['EmissionTexture', actor.getProperty().getEmissionTexture?.()], ['EnvironmentTexture', renderer.getEnvironmentTexture?.()]];
855
855
  textures.forEach(_ref => {
856
856
  let [name, tex] = _ref;
857
857
  if (!tex) return;
@@ -866,7 +866,7 @@ function vtkWebGPUCellArrayMapper(publicAPI, model) {
866
866
  // Add textures to manager only if not present
867
867
  newTextures.forEach(_ref2 => {
868
868
  let [textureName, srcTexture] = _ref2;
869
- const newTex = model.device.getTextureManager().getTextureForVTKTexture(srcTexture);
869
+ const newTex = model.device.getTextureManager().getTextureForVTKTexture(srcTexture, textureName);
870
870
  if (!newTex.getReady()) return;
871
871
  let found = false;
872
872
  for (let t = 0; t < model.textures.length; ++t) {
@@ -878,7 +878,7 @@ function vtkWebGPUCellArrayMapper(publicAPI, model) {
878
878
  }
879
879
  if (!found) {
880
880
  usedTextures[model.textures.length] = true;
881
- const tview = newTex.createView(`${textureName}Texture`);
881
+ const tview = newTex.createView(textureName);
882
882
  model.textures.push(newTex);
883
883
  model.textureViews.push(tview);
884
884
 
@@ -888,24 +888,24 @@ function vtkWebGPUCellArrayMapper(publicAPI, model) {
888
888
  if (srcTexture.getEdgeClamp() && srcTexture.getRepeat()) addressMode = 'mirror-repeat';else if (srcTexture.getEdgeClamp()) addressMode = 'clamp-to-edge';else if (srcTexture.getRepeat()) addressMode = 'repeat';
889
889
 
890
890
  // Handle environment texture separately
891
- if (textureName !== 'Environment') {
892
- tview.addSampler(model.device, {
893
- addressModeU: addressMode,
894
- addressModeV: addressMode,
895
- addressModeW: addressMode,
896
- minFilter: interpolate,
897
- magFilter: interpolate
898
- });
899
- } else {
900
- tview.addSampler(model.device, {
891
+ let options = {
892
+ addressModeU: addressMode,
893
+ addressModeV: addressMode,
894
+ addressModeW: addressMode,
895
+ minFilter: interpolate,
896
+ magFilter: interpolate
897
+ };
898
+ if (textureName === 'EnvironmentTexture') {
899
+ options = {
901
900
  addressModeU: 'repeat',
902
901
  addressModeV: 'clamp-to-edge',
903
902
  addressModeW: 'repeat',
904
903
  minFilter: interpolate,
905
904
  magFilter: interpolate,
906
905
  mipmapFilter: 'linear'
907
- });
906
+ };
908
907
  }
908
+ tview.addSampler(model.device, options);
909
909
  }
910
910
  });
911
911
 
@@ -38,7 +38,8 @@ function vtkWebGPUPolyDataMapper(publicAPI, model) {
38
38
  // and they handle the rendering of that cell array
39
39
  const cellMappers = [];
40
40
  let cellOffset = 0;
41
- for (let i = PrimitiveTypes.Points; i <= PrimitiveTypes.Triangles; i++) {
41
+ // Handle all primitive types including strips
42
+ for (let i = PrimitiveTypes.Points; i <= PrimitiveTypes.TriangleStrips; i++) {
42
43
  if (prims[i].getNumberOfValues() > 0) {
43
44
  if (!model.primitives[i]) {
44
45
  model.primitives[i] = publicAPI.createCellArrayMapper();
@@ -55,22 +56,41 @@ function vtkWebGPUPolyDataMapper(publicAPI, model) {
55
56
  model.primitives[i] = null;
56
57
  }
57
58
  }
59
+
60
+ // Handle edge visibility for both triangles and triangle strips
58
61
  if (model.WebGPUActor.getRenderable().getProperty().getEdgeVisibility()) {
59
- for (let i = PrimitiveTypes.TriangleEdges; i <= PrimitiveTypes.TriangleStripEdges; i++) {
60
- if (prims[i - 2].getNumberOfValues() > 0) {
61
- if (!model.primitives[i]) {
62
- model.primitives[i] = publicAPI.createCellArrayMapper();
63
- }
64
- const cellMapper = model.primitives[i];
65
- cellMapper.setCellArray(prims[i - 2]);
66
- cellMapper.setCurrentInput(poly);
67
- cellMapper.setCellOffset(model.primitives[i - 2].getCellOffset());
68
- cellMapper.setPrimitiveType(i);
69
- cellMapper.setRenderable(model.renderable);
70
- cellMappers.push(cellMapper);
71
- } else {
72
- model.primitives[i] = null;
62
+ // Handle triangle edges
63
+ if (prims[PrimitiveTypes.Triangles].getNumberOfValues() > 0) {
64
+ const i = PrimitiveTypes.TriangleEdges;
65
+ if (!model.primitives[i]) {
66
+ model.primitives[i] = publicAPI.createCellArrayMapper();
67
+ }
68
+ const cellMapper = model.primitives[i];
69
+ cellMapper.setCellArray(prims[PrimitiveTypes.Triangles]);
70
+ cellMapper.setCurrentInput(poly);
71
+ cellMapper.setCellOffset(model.primitives[PrimitiveTypes.Triangles].getCellOffset());
72
+ cellMapper.setPrimitiveType(i);
73
+ cellMapper.setRenderable(model.renderable);
74
+ cellMappers.push(cellMapper);
75
+ } else {
76
+ model.primitives[PrimitiveTypes.TriangleEdges] = null;
77
+ }
78
+
79
+ // Handle triangle strip edges
80
+ if (prims[PrimitiveTypes.TriangleStrips].getNumberOfValues() > 0) {
81
+ const i = PrimitiveTypes.TriangleStripEdges;
82
+ if (!model.primitives[i]) {
83
+ model.primitives[i] = publicAPI.createCellArrayMapper();
73
84
  }
85
+ const cellMapper = model.primitives[i];
86
+ cellMapper.setCellArray(prims[PrimitiveTypes.TriangleStrips]);
87
+ cellMapper.setCurrentInput(poly);
88
+ cellMapper.setCellOffset(model.primitives[PrimitiveTypes.TriangleStrips].getCellOffset());
89
+ cellMapper.setPrimitiveType(i);
90
+ cellMapper.setRenderable(model.renderable);
91
+ cellMappers.push(cellMapper);
92
+ } else {
93
+ model.primitives[PrimitiveTypes.TriangleStripEdges] = null;
74
94
  }
75
95
  }
76
96
  publicAPI.prepareNodes();
@@ -315,7 +315,7 @@ function vtkWebGPURenderer(publicAPI, model) {
315
315
  ubo.addEntry('FSQMatrix', 'mat4x4<f32>');
316
316
  ubo.addEntry('BackgroundColor', 'vec4<f32>');
317
317
  model.clearFSQ.setUBO(ubo);
318
- const environmentTextureHash = device.getTextureManager().getTextureForVTKTexture(model.backgroundTex);
318
+ const environmentTextureHash = device.getTextureManager().getTextureForVTKTexture(model.backgroundTex, 'EnvironmentTexture');
319
319
  if (environmentTextureHash.getReady()) {
320
320
  const tview = environmentTextureHash.createView(`EnvironmentTexture`);
321
321
  model.clearFSQ.setTextureViews([tview]);
@@ -84,17 +84,27 @@ function vtkWebGPUTexture(publicAPI, model) {
84
84
  req.height = req.imageBitmap.height;
85
85
  req.depth = 1;
86
86
  req.format = 'rgba8unorm';
87
- req.flip = false;
87
+ req.flip = true;
88
88
  _copyImageToTexture(req.imageBitmap);
89
89
  return;
90
90
  }
91
- if (req.jsImageData && !req.nativeArray) {
91
+ if (req.jsImageData) {
92
92
  req.width = req.jsImageData.width;
93
93
  req.height = req.jsImageData.height;
94
94
  req.depth = 1;
95
95
  req.format = 'rgba8unorm';
96
96
  req.flip = true;
97
- req.nativeArray = req.jsImageData.data;
97
+ _copyImageToTexture(req.jsImageData);
98
+ return;
99
+ }
100
+ if (req.image) {
101
+ req.width = req.image.width;
102
+ req.height = req.image.height;
103
+ req.depth = 1;
104
+ req.format = 'rgba8unorm';
105
+ req.flip = true;
106
+ _copyImageToTexture(req.image);
107
+ return;
98
108
  }
99
109
  const tDetails = vtkWebGPUTypes.getDetailsFromTextureFormat(model.format);
100
110
  let bufferBytesPerRow = model.width * tDetails.stride;
@@ -154,15 +164,6 @@ function vtkWebGPUTexture(publicAPI, model) {
154
164
  if (req.nativeArray) {
155
165
  nativeArray = req.nativeArray;
156
166
  }
157
- if (req.image) {
158
- const canvas = new OffscreenCanvas(req.image.width, req.image.height);
159
- const ctx = canvas.getContext('2d');
160
- ctx.translate(0, canvas.height);
161
- ctx.scale(1, -1);
162
- ctx.drawImage(req.image, 0, 0, req.image.width, req.image.height, 0, 0, canvas.width, canvas.height);
163
- const imageData = ctx.getImageData(0, 0, req.image.width, req.image.height);
164
- nativeArray = imageData.data;
165
- }
166
167
  const is3D = publicAPI.getDimensionality() === 3;
167
168
  const alignedTextureData = alignTextureData(nativeArray, model.height, is3D ? model.depth : 1);
168
169
  bufferBytesPerRow = alignedTextureData[1];
@@ -69,9 +69,10 @@ function vtkWebGPUTextureManager(publicAPI, model) {
69
69
  req.height = req.image.height;
70
70
  req.depth = 1;
71
71
  req.format = 'rgba8unorm';
72
+ req.flip = true;
72
73
  /* eslint-disable no-undef */
73
74
  /* eslint-disable no-bitwise */
74
- req.usage = GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.TEXTURE_BINDING;
75
+ req.usage = GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT;
75
76
  /* eslint-enable no-undef */
76
77
  /* eslint-enable no-bitwise */
77
78
  }
@@ -86,7 +87,7 @@ function vtkWebGPUTextureManager(publicAPI, model) {
86
87
  req.nativeArray = req.jsImageData.data;
87
88
  /* eslint-disable no-undef */
88
89
  /* eslint-disable no-bitwise */
89
- req.usage = GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.TEXTURE_BINDING;
90
+ req.usage = GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT;
90
91
  /* eslint-enable no-undef */
91
92
  /* eslint-enable no-bitwise */
92
93
  }
@@ -99,7 +100,7 @@ function vtkWebGPUTextureManager(publicAPI, model) {
99
100
  req.flip = true;
100
101
  /* eslint-disable no-undef */
101
102
  /* eslint-disable no-bitwise */
102
- req.usage = GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT;
103
+ req.usage = GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT;
103
104
  /* eslint-enable no-undef */
104
105
  /* eslint-enable no-bitwise */
105
106
  }
@@ -112,7 +113,7 @@ function vtkWebGPUTextureManager(publicAPI, model) {
112
113
  req.flip = true;
113
114
  /* eslint-disable no-undef */
114
115
  /* eslint-disable no-bitwise */
115
- req.usage = GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT;
116
+ req.usage = GPUTextureUsage.STORAGE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT;
116
117
  /* eslint-enable no-undef */
117
118
  /* eslint-enable no-bitwise */
118
119
  }
@@ -120,7 +121,9 @@ function vtkWebGPUTextureManager(publicAPI, model) {
120
121
 
121
122
  // create a texture (used by getTexture)
122
123
  function _createTexture(req) {
123
- const newTex = vtkWebGPUTexture.newInstance();
124
+ const newTex = vtkWebGPUTexture.newInstance({
125
+ label: req.label
126
+ });
124
127
  newTex.create(model.device, {
125
128
  width: req.width,
126
129
  height: req.height,
@@ -157,9 +160,11 @@ function vtkWebGPUTextureManager(publicAPI, model) {
157
160
  treq.hash = treq.time + treq.format + treq.mipLevel;
158
161
  return model.device.getTextureManager().getTexture(treq);
159
162
  };
160
- publicAPI.getTextureForVTKTexture = srcTexture => {
163
+ publicAPI.getTextureForVTKTexture = function (srcTexture) {
164
+ let label = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;
161
165
  const treq = {
162
- time: srcTexture.getMTime()
166
+ time: srcTexture.getMTime(),
167
+ label
163
168
  };
164
169
  if (srcTexture.getInputData()) {
165
170
  treq.imageData = srcTexture.getInputData();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kitware/vtk.js",
3
- "version": "34.0.0-beta.2",
3
+ "version": "34.0.0",
4
4
  "description": "Visualization Toolkit for the Web",
5
5
  "keywords": [
6
6
  "3d",
@@ -1,42 +0,0 @@
1
- import registerWebworker from 'webworker-promise/lib/register';
2
-
3
- /**
4
- *
5
- * @param {ArrayBuffer} imageBuffer
6
- * @param {string} mimeType
7
- * @param {string} channel
8
- * @returns {Promise<ImageData>}
9
- */
10
- registerWebworker(async _ref => {
11
- let {
12
- imageBuffer,
13
- mimeType,
14
- channel
15
- } = _ref;
16
- const channelsMap = {
17
- r: 0,
18
- g: 1,
19
- b: 2
20
- };
21
- const blob = new Blob([imageBuffer], {
22
- type: mimeType
23
- });
24
- const img = await createImageBitmap(blob);
25
- const canvas = new OffscreenCanvas(img.width, img.height);
26
- const ctx = canvas.getContext('2d');
27
- ctx.drawImage(img, 0, 0, img.width, img.height);
28
- const bitmap = ctx.getImageData(0, 0, img.width, img.height);
29
- if (channel) {
30
- const idx = channelsMap[channel];
31
- for (let i = 0; i < bitmap.data.length; i += 4) {
32
- const channelValue = bitmap.data[i + idx];
33
- bitmap.data[i] = channelValue; // red channel
34
- bitmap.data[i + 1] = channelValue; // green channel
35
- bitmap.data[i + 2] = channelValue; // blue channel
36
- }
37
- }
38
-
39
- return {
40
- bitmap
41
- };
42
- });
@@ -1,296 +0,0 @@
1
- import { c as createInlineWorkerFactory } from '../../../../rollup-plugin-web-worker-loader__helper__browser__createInlineWorkerFactory.js';
2
-
3
- var WorkerFactory = createInlineWorkerFactory(/* rollup-plugin-web-worker-loader */function () {
4
- (function () {
5
- '__worker_loader_strict__';
6
-
7
- var register = {exports: {}};
8
-
9
- var _createClass$1 = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
10
-
11
- function _classCallCheck$1(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
12
-
13
- var TinyEmitter$1 = function () {
14
- function TinyEmitter() {
15
- _classCallCheck$1(this, TinyEmitter);
16
-
17
- Object.defineProperty(this, '__listeners', {
18
- value: {},
19
- enumerable: false,
20
- writable: false
21
- });
22
- }
23
-
24
- _createClass$1(TinyEmitter, [{
25
- key: 'emit',
26
- value: function emit(eventName) {
27
- if (!this.__listeners[eventName]) return this;
28
-
29
- for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
30
- args[_key - 1] = arguments[_key];
31
- }
32
-
33
- var _iteratorNormalCompletion = true;
34
- var _didIteratorError = false;
35
- var _iteratorError = undefined;
36
-
37
- try {
38
- for (var _iterator = this.__listeners[eventName][Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
39
- var handler = _step.value;
40
-
41
- handler.apply(undefined, args);
42
- }
43
- } catch (err) {
44
- _didIteratorError = true;
45
- _iteratorError = err;
46
- } finally {
47
- try {
48
- if (!_iteratorNormalCompletion && _iterator.return) {
49
- _iterator.return();
50
- }
51
- } finally {
52
- if (_didIteratorError) {
53
- throw _iteratorError;
54
- }
55
- }
56
- }
57
-
58
- return this;
59
- }
60
- }, {
61
- key: 'once',
62
- value: function once(eventName, handler) {
63
- var _this = this;
64
-
65
- var once = function once() {
66
- _this.off(eventName, once);
67
- handler.apply(undefined, arguments);
68
- };
69
-
70
- return this.on(eventName, once);
71
- }
72
- }, {
73
- key: 'on',
74
- value: function on(eventName, handler) {
75
- if (!this.__listeners[eventName]) this.__listeners[eventName] = [];
76
-
77
- this.__listeners[eventName].push(handler);
78
-
79
- return this;
80
- }
81
- }, {
82
- key: 'off',
83
- value: function off(eventName, handler) {
84
- if (handler) this.__listeners[eventName] = this.__listeners[eventName].filter(function (h) {
85
- return h !== handler;
86
- });else this.__listeners[eventName] = [];
87
-
88
- return this;
89
- }
90
- }]);
91
-
92
- return TinyEmitter;
93
- }();
94
-
95
- var tinyEmitter = TinyEmitter$1;
96
-
97
- var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
98
-
99
- var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };
100
-
101
- var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
102
-
103
- function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
104
-
105
- function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
106
-
107
- function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
108
-
109
- function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
110
-
111
- function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
112
-
113
- var TinyEmitter = tinyEmitter;
114
-
115
- var MESSAGE_RESULT = 0;
116
- var MESSAGE_EVENT = 1;
117
-
118
- var RESULT_ERROR = 0;
119
- var RESULT_SUCCESS = 1;
120
-
121
- var DEFAULT_HANDLER = 'main';
122
-
123
- var isPromise = function isPromise(o) {
124
- return (typeof o === 'undefined' ? 'undefined' : _typeof(o)) === 'object' && o !== null && typeof o.then === 'function' && typeof o.catch === 'function';
125
- };
126
-
127
- function RegisterPromise(fn) {
128
- var handlers = _defineProperty({}, DEFAULT_HANDLER, fn);
129
- var sendPostMessage = self.postMessage.bind(self);
130
-
131
- var server = new (function (_TinyEmitter) {
132
- _inherits(WorkerRegister, _TinyEmitter);
133
-
134
- function WorkerRegister() {
135
- _classCallCheck(this, WorkerRegister);
136
-
137
- return _possibleConstructorReturn(this, (WorkerRegister.__proto__ || Object.getPrototypeOf(WorkerRegister)).apply(this, arguments));
138
- }
139
-
140
- _createClass(WorkerRegister, [{
141
- key: 'emit',
142
- value: function emit(eventName) {
143
- for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
144
- args[_key - 1] = arguments[_key];
145
- }
146
-
147
- if (args.length == 1 && args[0] instanceof TransferableResponse) {
148
- sendPostMessage({ eventName: eventName, args: args }, args[0].transferable);
149
- } else {
150
- sendPostMessage({ eventName: eventName, args: args });
151
- }
152
- return this;
153
- }
154
- }, {
155
- key: 'emitLocally',
156
- value: function emitLocally(eventName) {
157
- var _get2;
158
-
159
- for (var _len2 = arguments.length, args = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
160
- args[_key2 - 1] = arguments[_key2];
161
- }
162
-
163
- (_get2 = _get(WorkerRegister.prototype.__proto__ || Object.getPrototypeOf(WorkerRegister.prototype), 'emit', this)).call.apply(_get2, [this, eventName].concat(args));
164
- }
165
- }, {
166
- key: 'operation',
167
- value: function operation(name, handler) {
168
- handlers[name] = handler;
169
- return this;
170
- }
171
- }]);
172
-
173
- return WorkerRegister;
174
- }(TinyEmitter))();
175
-
176
- var run = function run(messageId, payload, handlerName) {
177
-
178
- var onSuccess = function onSuccess(result) {
179
- if (result && result instanceof TransferableResponse) {
180
- sendResult(messageId, RESULT_SUCCESS, result.payload, result.transferable);
181
- } else {
182
- sendResult(messageId, RESULT_SUCCESS, result);
183
- }
184
- };
185
-
186
- var onError = function onError(e) {
187
- sendResult(messageId, RESULT_ERROR, {
188
- message: e.message,
189
- stack: e.stack
190
- });
191
- };
192
-
193
- try {
194
- var result = runFn(messageId, payload, handlerName);
195
- if (isPromise(result)) {
196
- result.then(onSuccess).catch(onError);
197
- } else {
198
- onSuccess(result);
199
- }
200
- } catch (e) {
201
- onError(e);
202
- }
203
- };
204
-
205
- var runFn = function runFn(messageId, payload, handlerName) {
206
- var handler = handlers[handlerName || DEFAULT_HANDLER];
207
- if (!handler) throw new Error('Not found handler for this request');
208
-
209
- return handler(payload, sendEvent.bind(null, messageId));
210
- };
211
-
212
- var sendResult = function sendResult(messageId, success, payload) {
213
- var transferable = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [];
214
-
215
- sendPostMessage([MESSAGE_RESULT, messageId, success, payload], transferable);
216
- };
217
-
218
- var sendEvent = function sendEvent(messageId, eventName, payload) {
219
- if (!eventName) throw new Error('eventName is required');
220
-
221
- if (typeof eventName !== 'string') throw new Error('eventName should be string');
222
-
223
- sendPostMessage([MESSAGE_EVENT, messageId, eventName, payload]);
224
- };
225
-
226
- self.addEventListener('message', function (_ref) {
227
- var data = _ref.data;
228
-
229
- if (Array.isArray(data)) {
230
- run.apply(undefined, _toConsumableArray(data));
231
- } else if (data && data.eventName) {
232
- server.emitLocally.apply(server, [data.eventName].concat(_toConsumableArray(data.args)));
233
- }
234
- });
235
-
236
- return server;
237
- }
238
-
239
- var TransferableResponse = function TransferableResponse(payload, transferable) {
240
- _classCallCheck(this, TransferableResponse);
241
-
242
- this.payload = payload;
243
- this.transferable = transferable;
244
- };
245
-
246
- register.exports = RegisterPromise;
247
- register.exports.TransferableResponse = TransferableResponse;
248
-
249
- var registerWebworker = register.exports;
250
-
251
- /**
252
- *
253
- * @param {ArrayBuffer} imageBuffer
254
- * @param {string} mimeType
255
- * @param {string} channel
256
- * @returns {Promise<ImageData>}
257
- */
258
- registerWebworker(async _ref => {
259
- let {
260
- imageBuffer,
261
- mimeType,
262
- channel
263
- } = _ref;
264
- const channelsMap = {
265
- r: 0,
266
- g: 1,
267
- b: 2
268
- };
269
- const blob = new Blob([imageBuffer], {
270
- type: mimeType
271
- });
272
- const img = await createImageBitmap(blob);
273
- const canvas = new OffscreenCanvas(img.width, img.height);
274
- const ctx = canvas.getContext('2d');
275
- ctx.drawImage(img, 0, 0, img.width, img.height);
276
- const bitmap = ctx.getImageData(0, 0, img.width, img.height);
277
- if (channel) {
278
- const idx = channelsMap[channel];
279
- for (let i = 0; i < bitmap.data.length; i += 4) {
280
- const channelValue = bitmap.data[i + idx];
281
- bitmap.data[i] = channelValue; // red channel
282
- bitmap.data[i + 1] = channelValue; // green channel
283
- bitmap.data[i + 2] = channelValue; // blue channel
284
- }
285
- }
286
-
287
- return {
288
- bitmap
289
- };
290
- });
291
-
292
- })();
293
- }, null);
294
- /* eslint-enable */
295
-
296
- export { WorkerFactory as W };