@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.
- package/Common/Core/DataArray.d.ts +21 -0
- package/Common/Core/DataArray.js +39 -0
- package/Common/Core/Math/index.js +1 -1
- package/Common/Core/Math.js +1 -1
- package/Common/Core/URLExtract.js +2 -6
- package/Common/DataModel/Line.js +1 -0
- package/Common/DataModel/PolyLine.js +4 -0
- package/Filters/Core/ThresholdPoints.d.ts +72 -0
- package/Filters/Core/ThresholdPoints.js +219 -0
- package/Filters/General/ContourTriangulator/helper.js +1 -1
- package/IO/Core/DataAccessHelper/JSZipDataAccessHelper.js +1 -1
- package/IO/Geometry/DracoReader.d.ts +4 -4
- package/IO/Geometry/DracoReader.js +154 -105
- package/IO/Geometry/GLTFImporter/Animations.js +239 -0
- package/IO/Geometry/GLTFImporter/Constants.js +87 -0
- package/IO/Geometry/GLTFImporter/Decoder.js +69 -0
- package/IO/Geometry/GLTFImporter/Extensions.js +110 -0
- package/IO/Geometry/GLTFImporter/ORMTexture.worker.js +42 -0
- package/IO/Geometry/GLTFImporter/Parser.js +359 -0
- package/IO/Geometry/GLTFImporter/Reader.js +518 -0
- package/IO/Geometry/GLTFImporter/Utils.js +165 -0
- package/IO/Geometry/GLTFImporter.d.ts +266 -0
- package/IO/Geometry/GLTFImporter.js +245 -0
- package/IO/Geometry/IFCImporter.d.ts +163 -0
- package/IO/Geometry/IFCImporter.js +270 -0
- package/IO/Geometry/STLReader.d.ts +14 -0
- package/IO/Geometry/STLReader.js +57 -1
- package/IO/Geometry.js +5 -1
- package/IO/Image/HDRReader/Utils.js +1 -1
- package/IO/Image/HDRReader.js +1 -1
- package/IO/Image/TGAReader/Constants.js +28 -0
- package/IO/Image/TGAReader.d.ts +121 -0
- package/IO/Image/TGAReader.js +418 -0
- package/IO/Image/TIFFReader.d.ts +133 -0
- package/IO/Image/TIFFReader.js +144 -0
- package/IO/Image.js +5 -1
- package/IO/XML/XMLPolyDataWriter.js +1 -0
- package/Interaction/Manipulators/MouseCameraTrackballRollManipulator.js +1 -1
- package/Interaction/Style/InteractorStyleTrackballCamera.js +1 -1
- package/Rendering/Core/AbstractImageMapper.d.ts +81 -0
- package/Rendering/Core/AbstractImageMapper.js +5 -2
- package/Rendering/Core/AbstractPicker.d.ts +13 -13
- package/Rendering/Core/AbstractPicker.js +1 -1
- package/Rendering/Core/Actor2D.d.ts +22 -0
- package/Rendering/Core/Actor2D.js +1 -1
- package/Rendering/Core/CellPicker.js +4 -1
- package/Rendering/Core/Glyph3DMapper.d.ts +45 -29
- package/Rendering/Core/ImageCPRMapper.js +6 -5
- package/Rendering/Core/ImageProperty.d.ts +42 -1
- package/Rendering/Core/ImageProperty.js +7 -5
- package/Rendering/Core/ImageResliceMapper.d.ts +1 -2
- package/Rendering/Core/ImageResliceMapper.js +5 -4
- package/Rendering/Core/PointPicker.js +10 -1
- package/Rendering/Core/Prop3D.js +1 -1
- package/Rendering/Core/RenderWindowInteractor.d.ts +1 -1
- package/Rendering/Core/RenderWindowInteractor.js +1 -1
- package/Rendering/Core/Viewport.js +13 -3
- package/Rendering/Core/VolumeMapper.d.ts +70 -0
- package/Rendering/Core/VolumeMapper.js +10 -5
- package/Rendering/Core/VolumeProperty.d.ts +20 -1
- package/Rendering/Core/VolumeProperty.js +7 -5
- package/Rendering/Misc/CanvasView.js +4 -2
- package/Rendering/Misc/RemoteView.d.ts +9 -3
- package/Rendering/Misc/RemoteView.js +7 -3
- package/Rendering/Misc/SynchronizableRenderWindow/BehaviorManager/CameraSynchronizer.js +2 -2
- package/Rendering/Misc/SynchronizableRenderWindow/ObjectManager.d.ts +1 -1
- package/Rendering/OpenGL/ImageCPRMapper.js +18 -2
- package/Rendering/OpenGL/ImageMapper.js +42 -11
- package/Rendering/OpenGL/ImageResliceMapper.js +20 -4
- package/Rendering/OpenGL/Renderer.js +1 -1
- package/Rendering/OpenGL/Texture/supportsNorm16Linear.js +97 -0
- package/Rendering/OpenGL/Texture.d.ts +29 -8
- package/Rendering/OpenGL/Texture.js +172 -34
- package/Rendering/OpenGL/VolumeMapper.js +22 -4
- package/Rendering/SceneGraph/ViewNode.js +12 -2
- package/Rendering/WebXR/RenderWindowHelper.js +9 -0
- package/Widgets/Core/WidgetManager.d.ts +12 -1
- package/Widgets/Representations/WidgetRepresentation.d.ts +1 -7
- package/Widgets/Widgets3D/AngleWidget/behavior.js +2 -0
- package/Widgets/Widgets3D/InteractiveOrientationWidget.js +1 -1
- package/Widgets/Widgets3D/ResliceCursorWidget/behavior.js +17 -0
- package/Widgets/Widgets3D/ResliceCursorWidget/helpers.js +1 -0
- package/Widgets/Widgets3D/ResliceCursorWidget.d.ts +1 -8
- package/Widgets/Widgets3D/ShapeWidget/behavior.js +3 -0
- package/_virtual/rollup-plugin-worker-loader__module_Sources/IO/Geometry/GLTFImporter/ORMTexture.worker.js +296 -0
- package/index.d.ts +5 -0
- package/package.json +19 -17
|
@@ -0,0 +1,69 @@
|
|
|
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';
|
|
3
|
+
|
|
4
|
+
function getChunkInfo(headerStart, data) {
|
|
5
|
+
const header = new Uint32Array(data, headerStart, BINARY_CHUNK_HEADER_INTS);
|
|
6
|
+
const chunkStart = headerStart + BINARY_CHUNK_HEADER_INTS * 4;
|
|
7
|
+
const chunkLength = header[0];
|
|
8
|
+
const chunkType = header[1];
|
|
9
|
+
return {
|
|
10
|
+
start: chunkStart,
|
|
11
|
+
length: chunkLength,
|
|
12
|
+
type: chunkType
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
function getAllChunkInfos(data) {
|
|
16
|
+
const infos = [];
|
|
17
|
+
let chunkStart = BINARY_HEADER_INTS * 4;
|
|
18
|
+
while (chunkStart < data.byteLength) {
|
|
19
|
+
const chunkInfo = getChunkInfo(chunkStart, data);
|
|
20
|
+
infos.push(chunkInfo);
|
|
21
|
+
chunkStart += chunkInfo.length + BINARY_CHUNK_HEADER_INTS * 4;
|
|
22
|
+
}
|
|
23
|
+
return infos;
|
|
24
|
+
}
|
|
25
|
+
function getJsonFromChunk(chunkInfo, data) {
|
|
26
|
+
const chunkLength = chunkInfo.length;
|
|
27
|
+
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
|
+
}
|
|
32
|
+
function getBufferFromChunk(chunkInfo, data) {
|
|
33
|
+
return data.slice(chunkInfo.start, chunkInfo.start + chunkInfo.length);
|
|
34
|
+
}
|
|
35
|
+
function parseGLB(data) {
|
|
36
|
+
let json;
|
|
37
|
+
const buffers = [];
|
|
38
|
+
const headerView = new DataView(data, 0, BINARY_HEADER_LENGTH);
|
|
39
|
+
const header = {
|
|
40
|
+
magic: BinaryHelper.arrayBufferToString(new Uint8Array(data, 0, 4)),
|
|
41
|
+
version: headerView.getUint32(4, true),
|
|
42
|
+
length: headerView.getUint32(8, true)
|
|
43
|
+
};
|
|
44
|
+
if (header.magic !== BINARY_HEADER_MAGIC) {
|
|
45
|
+
throw new Error('Unsupported glTF-Binary header.');
|
|
46
|
+
} else if (header.version < 2.0) {
|
|
47
|
+
throw new Error('Unsupported legacy binary file detected.');
|
|
48
|
+
}
|
|
49
|
+
const chunkInfos = getAllChunkInfos(data);
|
|
50
|
+
chunkInfos.forEach(chunkInfo => {
|
|
51
|
+
if (chunkInfo.type === BINARY_CHUNK_TYPES.JSON && !json) {
|
|
52
|
+
json = getJsonFromChunk(chunkInfo, data);
|
|
53
|
+
} else if (chunkInfo.type === BINARY_CHUNK_TYPES.BIN) {
|
|
54
|
+
buffers.push(getBufferFromChunk(chunkInfo, data));
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
if (!json) {
|
|
58
|
+
throw new Error('glTF-Binary: JSON content not found.');
|
|
59
|
+
}
|
|
60
|
+
if (!buffers) {
|
|
61
|
+
throw new Error('glTF-Binary: Binary chunk not found.');
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
json,
|
|
65
|
+
buffers
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export { parseGLB as default };
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { m as macro } from '../../../macros2.js';
|
|
2
|
+
import { r as radiansFromDegrees } from '../../../Common/Core/Math/index.js';
|
|
3
|
+
import vtkDracoReader from '../DracoReader.js';
|
|
4
|
+
import vtkLight from '../../../Rendering/Core/Light.js';
|
|
5
|
+
import { MIN_LIGHT_ATTENUATION } from './Constants.js';
|
|
6
|
+
|
|
7
|
+
const {
|
|
8
|
+
vtkWarningMacro
|
|
9
|
+
} = macro;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Handles the KHR_materials_unlit extension.
|
|
13
|
+
*
|
|
14
|
+
* @param {object} extension - The KHR_materials_unlit extension object.
|
|
15
|
+
* @param {vtkProperty} property - The vtkProperty instance to update.
|
|
16
|
+
*/
|
|
17
|
+
function handleKHRMaterialsUnlit(extension, property) {
|
|
18
|
+
property.setLighting(true);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Handles the KHR_materials_ior extension.
|
|
23
|
+
*
|
|
24
|
+
* @param {object} extension - The KHR_materials_unlit extension object.
|
|
25
|
+
* @param {vtkProperty} property - The vtkProperty instance to update.
|
|
26
|
+
*/
|
|
27
|
+
function handleKHRMaterialsIor(extension, property) {
|
|
28
|
+
property.setBaseIOR(extension.ior);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Handles the KHR_materials_specular extension.
|
|
33
|
+
* @param {object} extension - The KHR_materials_specular extension object.
|
|
34
|
+
* @param {vtkProperty} property - The vtkProperty instance to update.
|
|
35
|
+
*/
|
|
36
|
+
function handleKHRMaterialsSpecular(extension, property) {
|
|
37
|
+
property.setSpecular(extension.specularFactor);
|
|
38
|
+
property.setSpecularColor(extension.specularColorFactor);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Handles the KHR_lights_punctual extension.
|
|
43
|
+
*
|
|
44
|
+
* @param {object} extension - The KHR_lights_punctual extension object.
|
|
45
|
+
* @param {vtkRenderer} renderer - The vtkRenderer instance to add the light to.
|
|
46
|
+
*/
|
|
47
|
+
function handleKHRLightsPunctual(extension, transformMatrix, model) {
|
|
48
|
+
const {
|
|
49
|
+
light
|
|
50
|
+
} = extension;
|
|
51
|
+
const {
|
|
52
|
+
color,
|
|
53
|
+
intensity,
|
|
54
|
+
range,
|
|
55
|
+
spot,
|
|
56
|
+
type
|
|
57
|
+
} = light;
|
|
58
|
+
const l = vtkLight.newInstance({
|
|
59
|
+
color: color || [1, 1, 1],
|
|
60
|
+
intensity: intensity || 1.0
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Apply the global transform to the light
|
|
64
|
+
l.setTransformMatrix(transformMatrix);
|
|
65
|
+
|
|
66
|
+
// Handle range
|
|
67
|
+
if (range > 0) {
|
|
68
|
+
// Set quadratic values to get attenuation(range) ~= MIN_LIGHT_ATTENUATION
|
|
69
|
+
l.setAttenuationValues(1, 0, 1.0 / (range * range * MIN_LIGHT_ATTENUATION));
|
|
70
|
+
}
|
|
71
|
+
switch (type) {
|
|
72
|
+
case 'directional':
|
|
73
|
+
l.setPositional(false);
|
|
74
|
+
break;
|
|
75
|
+
case 'point':
|
|
76
|
+
l.setPositional(true);
|
|
77
|
+
l.setConeAngle(90);
|
|
78
|
+
break;
|
|
79
|
+
case 'spot':
|
|
80
|
+
l.setPositional(true);
|
|
81
|
+
l.setConeAngle(radiansFromDegrees(spot.outerConeAngle));
|
|
82
|
+
break;
|
|
83
|
+
default:
|
|
84
|
+
vtkWarningMacro(`Unsupported light type: ${type}`);
|
|
85
|
+
}
|
|
86
|
+
model.lights.set(light.name, l);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Handles the KHR_draco_mesh_compression extension.
|
|
91
|
+
*
|
|
92
|
+
* @param {object} extension - The KHR_draco_mesh_compression extension object.
|
|
93
|
+
*/
|
|
94
|
+
function handleKHRDracoMeshCompression(extension) {
|
|
95
|
+
const reader = vtkDracoReader.newInstance();
|
|
96
|
+
reader.parse(extension.bufferView);
|
|
97
|
+
return reader.getOutputData();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Handles the KHR_materials_variants extension.
|
|
102
|
+
*
|
|
103
|
+
* @param {object} extension - The KHR_materials_variants extension object.
|
|
104
|
+
* @param {object} model - The model object to update with variant information.
|
|
105
|
+
*/
|
|
106
|
+
function handleKHRMaterialsVariants(extension, model) {
|
|
107
|
+
model.variants = extension.variants.map(v => v.name);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export { handleKHRDracoMeshCompression, handleKHRLightsPunctual, handleKHRMaterialsIor, handleKHRMaterialsSpecular, handleKHRMaterialsUnlit, handleKHRMaterialsVariants };
|
|
@@ -0,0 +1,42 @@
|
|
|
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
|
+
});
|
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
import { m as macro } from '../../../macros2.js';
|
|
2
|
+
import { SEMANTIC_ATTRIBUTE_MAP, MODES, ALPHA_MODE, BYTES, COMPONENTS, DEFAULT_SAMPLER, GL_SAMPLER } from './Constants.js';
|
|
3
|
+
import { getAccessorArrayTypeAndLength, resolveUrl, getGLEnumFromSamplerParameter } from './Utils.js';
|
|
4
|
+
|
|
5
|
+
/* eslint-disable guard-for-in */
|
|
6
|
+
const {
|
|
7
|
+
vtkDebugMacro,
|
|
8
|
+
vtkWarningMacro
|
|
9
|
+
} = macro;
|
|
10
|
+
class GLTFParser {
|
|
11
|
+
constructor(glTF) {
|
|
12
|
+
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
13
|
+
const {
|
|
14
|
+
json,
|
|
15
|
+
baseUri = ''
|
|
16
|
+
} = glTF;
|
|
17
|
+
this.glTF = glTF;
|
|
18
|
+
this.options = options;
|
|
19
|
+
this.baseUri = baseUri;
|
|
20
|
+
this.json = json;
|
|
21
|
+
this.extensions = json.extensions || {};
|
|
22
|
+
this.extensionsUsed = json.extensionsUsed || [];
|
|
23
|
+
}
|
|
24
|
+
async parse() {
|
|
25
|
+
const buffers = this.json.buffers || [];
|
|
26
|
+
this.buffers = new Array(buffers.length).fill(null);
|
|
27
|
+
const images = this.json.images || [];
|
|
28
|
+
this.images = new Array(images.length).fill({});
|
|
29
|
+
await this.loadBuffers();
|
|
30
|
+
await this.loadImages();
|
|
31
|
+
this.resolveTree();
|
|
32
|
+
return this.glTF.json;
|
|
33
|
+
}
|
|
34
|
+
resolveTree() {
|
|
35
|
+
this.json.scenes = this.json.scenes?.map((scene, idx) => this.resolveScene(scene, idx));
|
|
36
|
+
this.json.cameras = this.json.cameras?.map((camera, idx) => this.resolveCamera(camera, idx));
|
|
37
|
+
this.json.bufferViews = this.json.bufferViews?.map((bufView, idx) => this.resolveBufferView(bufView, idx));
|
|
38
|
+
this.json.images = this.json.images?.map((image, idx) => this.resolveImage(image, idx));
|
|
39
|
+
this.json.samplers = this.json.samplers?.map((sampler, idx) => this.resolveSampler(sampler, idx));
|
|
40
|
+
this.json.textures = this.json.textures?.map((texture, idx) => this.resolveTexture(texture, idx));
|
|
41
|
+
this.json.accessors = this.json.accessors?.map((accessor, idx) => this.resolveAccessor(accessor, idx));
|
|
42
|
+
this.json.materials = this.json.materials?.map((material, idx) => this.resolveMaterial(material, idx));
|
|
43
|
+
this.json.meshes = this.json.meshes?.map((mesh, idx) => this.resolveMesh(mesh, idx));
|
|
44
|
+
this.json.nodes = this.json.nodes?.map((node, idx) => this.resolveNode(node, idx));
|
|
45
|
+
this.json.skins = this.json.skins?.map((skin, idx) => this.resolveSkin(skin, idx));
|
|
46
|
+
this.json.animations = this.json.animations?.map((animation, idx) => this.resolveAnimation(animation, idx));
|
|
47
|
+
}
|
|
48
|
+
get(array, index) {
|
|
49
|
+
// check if already resolved
|
|
50
|
+
if (typeof index === 'object') {
|
|
51
|
+
return index;
|
|
52
|
+
}
|
|
53
|
+
const object = this.json[array] && this.json[array][index];
|
|
54
|
+
if (!object) {
|
|
55
|
+
vtkWarningMacro(`glTF file error: Could not find ${array}[${index}]`);
|
|
56
|
+
}
|
|
57
|
+
return object;
|
|
58
|
+
}
|
|
59
|
+
resolveScene(scene, index) {
|
|
60
|
+
scene.id = scene.id || `scene-${index}`;
|
|
61
|
+
scene.nodes = (scene.nodes || []).map(node => this.get('nodes', node));
|
|
62
|
+
return scene;
|
|
63
|
+
}
|
|
64
|
+
resolveNode(node, index) {
|
|
65
|
+
node.id = node.id || `node-${index}`;
|
|
66
|
+
if (node.children) {
|
|
67
|
+
node.children = node.children.map(child => this.get('nodes', child));
|
|
68
|
+
}
|
|
69
|
+
if (node.mesh !== undefined) {
|
|
70
|
+
node.mesh = this.get('meshes', node.mesh);
|
|
71
|
+
} else if (node.meshes !== undefined && node.meshes.length) {
|
|
72
|
+
node.mesh = node.meshes.reduce((accum, meshIndex) => {
|
|
73
|
+
const mesh = this.get('meshes', meshIndex);
|
|
74
|
+
accum.id = mesh.id;
|
|
75
|
+
accum.primitives = accum.primitives.concat(mesh.primitives);
|
|
76
|
+
return accum;
|
|
77
|
+
}, {
|
|
78
|
+
primitives: []
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
if (node.camera !== undefined) {
|
|
82
|
+
node.camera = this.get('cameras', node.camera);
|
|
83
|
+
}
|
|
84
|
+
if (node.skin !== undefined) {
|
|
85
|
+
node.skin = this.get('skins', node.skin);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Fill punctual lights objects
|
|
89
|
+
if (node.extensions?.KHR_lights_punctual) {
|
|
90
|
+
node.extensions.KHR_lights_punctual.light = this.extensions?.KHR_lights_punctual.lights[node.extensions.KHR_lights_punctual.light];
|
|
91
|
+
}
|
|
92
|
+
return node;
|
|
93
|
+
}
|
|
94
|
+
resolveSkin(skin, index) {
|
|
95
|
+
skin.id = skin.id || `skin-${index}`;
|
|
96
|
+
skin.inverseBindMatrices = this.get('accessors', skin.inverseBindMatrices);
|
|
97
|
+
return skin;
|
|
98
|
+
}
|
|
99
|
+
resolveMesh(mesh, index) {
|
|
100
|
+
mesh.id = mesh.id || `mesh-${index}`;
|
|
101
|
+
if (mesh.primitives) {
|
|
102
|
+
mesh.primitives = mesh.primitives.map((primitive, idx) => {
|
|
103
|
+
const attributes = primitive.attributes;
|
|
104
|
+
primitive.name = `primitive-${idx}`;
|
|
105
|
+
primitive.attributes = {};
|
|
106
|
+
for (const attribute in attributes) {
|
|
107
|
+
const attr = SEMANTIC_ATTRIBUTE_MAP[attribute];
|
|
108
|
+
primitive.attributes[attr] = this.get('accessors', attributes[attribute]);
|
|
109
|
+
}
|
|
110
|
+
if (primitive.indices !== undefined) {
|
|
111
|
+
primitive.indices = this.get('accessors', primitive.indices);
|
|
112
|
+
}
|
|
113
|
+
if (primitive.material !== undefined) {
|
|
114
|
+
primitive.material = this.get('materials', primitive.material);
|
|
115
|
+
}
|
|
116
|
+
if (primitive.mode === undefined) {
|
|
117
|
+
primitive.mode = MODES.GL_TRIANGLES; // Default one
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (primitive.extensions?.KHR_draco_mesh_compression) {
|
|
121
|
+
vtkDebugMacro('Using Draco mesh compression');
|
|
122
|
+
const bufferView = this.get('bufferViews', primitive.extensions.KHR_draco_mesh_compression.bufferView);
|
|
123
|
+
primitive.extensions.KHR_draco_mesh_compression.bufferView = bufferView.data;
|
|
124
|
+
}
|
|
125
|
+
return primitive;
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
return mesh;
|
|
129
|
+
}
|
|
130
|
+
resolveMaterial(material, index) {
|
|
131
|
+
material.id = material.id || `material-${index}`;
|
|
132
|
+
if (material.alphaMode === undefined) material.alphaMode = ALPHA_MODE.OPAQUE;
|
|
133
|
+
if (material.doubleSided === undefined) material.doubleSided = false;
|
|
134
|
+
if (material.alphaCutoff === undefined) material.alphaCutoff = 0.5;
|
|
135
|
+
if (material.normalTexture) {
|
|
136
|
+
material.normalTexture = {
|
|
137
|
+
...material.normalTexture
|
|
138
|
+
};
|
|
139
|
+
material.normalTexture.texture = this.get('textures', material.normalTexture.index);
|
|
140
|
+
}
|
|
141
|
+
if (material.occlusionTexture) {
|
|
142
|
+
material.occlusionTexture = {
|
|
143
|
+
...material.occlusionTexture
|
|
144
|
+
};
|
|
145
|
+
material.occlusionTexture.texture = this.get('textures', material.occlusionTexture.index);
|
|
146
|
+
}
|
|
147
|
+
if (material.emissiveTexture) {
|
|
148
|
+
material.emissiveTexture = {
|
|
149
|
+
...material.emissiveTexture
|
|
150
|
+
};
|
|
151
|
+
material.emissiveTexture.texture = this.get('textures', material.emissiveTexture.index);
|
|
152
|
+
}
|
|
153
|
+
if (!material.emissiveFactor) {
|
|
154
|
+
material.emissiveFactor = material.emissiveTexture ? 1 : 0;
|
|
155
|
+
} else material.emissiveFactor = material.emissiveFactor[0];
|
|
156
|
+
if (material.pbrMetallicRoughness) {
|
|
157
|
+
material.pbrMetallicRoughness = {
|
|
158
|
+
...material.pbrMetallicRoughness
|
|
159
|
+
};
|
|
160
|
+
const mr = material.pbrMetallicRoughness;
|
|
161
|
+
if (mr.baseColorTexture) {
|
|
162
|
+
mr.baseColorTexture = {
|
|
163
|
+
...mr.baseColorTexture
|
|
164
|
+
};
|
|
165
|
+
mr.baseColorTexture.texture = this.get('textures', mr.baseColorTexture.index);
|
|
166
|
+
}
|
|
167
|
+
if (mr.metallicRoughnessTexture) {
|
|
168
|
+
mr.metallicRoughnessTexture = {
|
|
169
|
+
...mr.metallicRoughnessTexture
|
|
170
|
+
};
|
|
171
|
+
mr.metallicRoughnessTexture.texture = this.get('textures', mr.metallicRoughnessTexture.index);
|
|
172
|
+
}
|
|
173
|
+
} else {
|
|
174
|
+
material.pbrMetallicRoughness = {
|
|
175
|
+
baseColorFactor: [1, 1, 1, 1],
|
|
176
|
+
metallicFactor: 1.0,
|
|
177
|
+
roughnessFactor: 1.0
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
return material;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Take values of particular accessor from interleaved buffer various parts of
|
|
185
|
+
* the buffer
|
|
186
|
+
*/
|
|
187
|
+
getValueFromInterleavedBuffer(buffer, byteOffset, byteStride, bytesPerElement, count) {
|
|
188
|
+
const result = new Uint8Array(count * bytesPerElement);
|
|
189
|
+
for (let i = 0; i < count; i++) {
|
|
190
|
+
const elementOffset = byteOffset + i * byteStride;
|
|
191
|
+
result.set(new Uint8Array(buffer.arrayBuffer.slice(elementOffset, elementOffset + bytesPerElement)), i * bytesPerElement);
|
|
192
|
+
}
|
|
193
|
+
return result.buffer;
|
|
194
|
+
}
|
|
195
|
+
resolveAccessor(accessor, index) {
|
|
196
|
+
accessor.id = accessor.id || `accessor-${index}`;
|
|
197
|
+
if (accessor.bufferView !== undefined) {
|
|
198
|
+
// Draco encoded meshes don't have bufferView
|
|
199
|
+
accessor.bufferView = this.get('bufferViews', accessor.bufferView);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Look up enums
|
|
203
|
+
accessor.bytesPerComponent = BYTES[accessor.componentType];
|
|
204
|
+
accessor.components = COMPONENTS[accessor.type];
|
|
205
|
+
accessor.bytesPerElement = accessor.bytesPerComponent * accessor.components;
|
|
206
|
+
|
|
207
|
+
// Create TypedArray for the accessor
|
|
208
|
+
// Note: The canonical way to instantiate is to ignore this array and create
|
|
209
|
+
// WebGLBuffer's using the bufferViews.
|
|
210
|
+
if (accessor.bufferView) {
|
|
211
|
+
const buffer = accessor.bufferView.buffer;
|
|
212
|
+
const {
|
|
213
|
+
ArrayType,
|
|
214
|
+
byteLength
|
|
215
|
+
} = 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);
|
|
218
|
+
if (accessor.bufferView.byteStride) {
|
|
219
|
+
slicedBufffer = this.getValueFromInterleavedBuffer(buffer, byteOffset, accessor.bufferView.byteStride, accessor.bytesPerElement, accessor.count);
|
|
220
|
+
}
|
|
221
|
+
accessor.value = new ArrayType(slicedBufffer);
|
|
222
|
+
}
|
|
223
|
+
return accessor;
|
|
224
|
+
}
|
|
225
|
+
resolveTexture(texture, index) {
|
|
226
|
+
texture.id = texture.id || `texture-${index}`;
|
|
227
|
+
texture.sampler = 'sampler' in texture ? this.get('samplers', texture.sampler) : DEFAULT_SAMPLER;
|
|
228
|
+
texture.source = this.get('images', texture.source);
|
|
229
|
+
|
|
230
|
+
// Handle texture extensions sources
|
|
231
|
+
if (texture.extensions !== undefined) {
|
|
232
|
+
const extensionsNames = Object.keys(texture.extensions);
|
|
233
|
+
extensionsNames.forEach(extensionName => {
|
|
234
|
+
const extension = texture.extensions[extensionName];
|
|
235
|
+
switch (extensionName) {
|
|
236
|
+
case 'KHR_texture_basisu':
|
|
237
|
+
case 'EXT_texture_webp':
|
|
238
|
+
case 'EXT_texture_avif':
|
|
239
|
+
texture.source = this.get('images', extension.source);
|
|
240
|
+
break;
|
|
241
|
+
default:
|
|
242
|
+
vtkWarningMacro(`Unhandled extension: ${extensionName}`);
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
return texture;
|
|
247
|
+
}
|
|
248
|
+
resolveSampler(sampler, index) {
|
|
249
|
+
sampler.id = sampler.id || `sampler-${index}`;
|
|
250
|
+
if (!Object.hasOwn(sampler, 'wrapS')) sampler.wrapS = GL_SAMPLER.REPEAT;
|
|
251
|
+
if (!Object.hasOwn(sampler, 'wrapT')) sampler.wrapT = GL_SAMPLER.REPEAT;
|
|
252
|
+
if (!Object.hasOwn(sampler, 'minFilter')) sampler.minFilter = GL_SAMPLER.LINEAR_MIPMAP_LINEAR;
|
|
253
|
+
if (!Object.hasOwn(sampler, 'magFilter')) sampler.magFilter = GL_SAMPLER.NEAREST;
|
|
254
|
+
|
|
255
|
+
// Map textual parameters to GL parameter values
|
|
256
|
+
sampler.parameters = {};
|
|
257
|
+
for (const key in sampler) {
|
|
258
|
+
const glEnum = getGLEnumFromSamplerParameter(key);
|
|
259
|
+
if (glEnum !== undefined) {
|
|
260
|
+
sampler.parameters[glEnum] = sampler[key];
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return sampler;
|
|
264
|
+
}
|
|
265
|
+
resolveImage(image, index) {
|
|
266
|
+
image.id = image.id || `image-${index}`;
|
|
267
|
+
if (image.bufferView !== undefined) {
|
|
268
|
+
image.bufferView = this.get('bufferViews', image.bufferView);
|
|
269
|
+
}
|
|
270
|
+
return image;
|
|
271
|
+
}
|
|
272
|
+
resolveBufferView(bufferView, index) {
|
|
273
|
+
bufferView.id = bufferView.id || `bufferView-${index}`;
|
|
274
|
+
const bufferIndex = bufferView.buffer;
|
|
275
|
+
bufferView.buffer = this.buffers[bufferIndex];
|
|
276
|
+
const arrayBuffer = this.buffers[bufferIndex].arrayBuffer;
|
|
277
|
+
let byteOffset = this.buffers[bufferIndex].byteOffset || 0;
|
|
278
|
+
if ('byteOffset' in bufferView) {
|
|
279
|
+
byteOffset += bufferView.byteOffset;
|
|
280
|
+
}
|
|
281
|
+
bufferView.data = new Uint8Array(arrayBuffer, byteOffset, bufferView.byteLength);
|
|
282
|
+
return bufferView;
|
|
283
|
+
}
|
|
284
|
+
resolveCamera(camera, index) {
|
|
285
|
+
camera.id = camera.id || `camera-${index}`;
|
|
286
|
+
return camera;
|
|
287
|
+
}
|
|
288
|
+
resolveAnimation(animation, index) {
|
|
289
|
+
animation.id = animation.id || `animation-${index}`;
|
|
290
|
+
animation.samplers.map(sampler => {
|
|
291
|
+
sampler.input = this.get('accessors', sampler.input).value;
|
|
292
|
+
sampler.output = this.get('accessors', sampler.output).value;
|
|
293
|
+
return sampler;
|
|
294
|
+
});
|
|
295
|
+
return animation;
|
|
296
|
+
}
|
|
297
|
+
loadBuffers() {
|
|
298
|
+
const promises = this.json.buffers.map((buffer, idx) => this.loadBuffer(buffer, idx).then(() => {
|
|
299
|
+
delete buffer.uri;
|
|
300
|
+
}));
|
|
301
|
+
return Promise.all(promises);
|
|
302
|
+
}
|
|
303
|
+
async loadBuffer(buffer, index) {
|
|
304
|
+
let arrayBuffer = buffer;
|
|
305
|
+
if (buffer.uri) {
|
|
306
|
+
vtkDebugMacro('Loading uri', buffer.uri);
|
|
307
|
+
const uri = resolveUrl(buffer.uri, this.options.baseUri);
|
|
308
|
+
const response = await fetch(uri);
|
|
309
|
+
arrayBuffer = await response.arrayBuffer();
|
|
310
|
+
} else if (this.glTF.glbBuffers) {
|
|
311
|
+
arrayBuffer = this.glTF.glbBuffers[index];
|
|
312
|
+
}
|
|
313
|
+
this.buffers[index] = {
|
|
314
|
+
arrayBuffer,
|
|
315
|
+
byteOffset: 0,
|
|
316
|
+
byteLength: arrayBuffer.byteLength
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
loadImages() {
|
|
320
|
+
const images = this.json.images || [];
|
|
321
|
+
const promises = [];
|
|
322
|
+
return new Promise((resolve, reject) => {
|
|
323
|
+
for (let i = 0; i < images.length; ++i) {
|
|
324
|
+
promises.push(Promise.resolve(this.loadImage(images[i], i).then(() => {
|
|
325
|
+
vtkDebugMacro('Texture loaded ', images[i]);
|
|
326
|
+
})));
|
|
327
|
+
}
|
|
328
|
+
Promise.all(promises).then(() => resolve(this.images));
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
async loadImage(image, index) {
|
|
332
|
+
let arrayBuffer;
|
|
333
|
+
let buffer;
|
|
334
|
+
if (image.uri) {
|
|
335
|
+
vtkDebugMacro('Loading texture', image.uri);
|
|
336
|
+
const uri = resolveUrl(image.uri, this.options.baseUri);
|
|
337
|
+
const response = await fetch(uri);
|
|
338
|
+
arrayBuffer = await response.arrayBuffer();
|
|
339
|
+
image.uri = uri;
|
|
340
|
+
image.bufferView = {
|
|
341
|
+
data: arrayBuffer
|
|
342
|
+
};
|
|
343
|
+
} else if (image.bufferView) {
|
|
344
|
+
const bufferView = this.get('bufferViews', image.bufferView);
|
|
345
|
+
buffer = this.get('buffers', bufferView.buffer);
|
|
346
|
+
|
|
347
|
+
// GLB buffer
|
|
348
|
+
if (this.glTF.glbBuffers) {
|
|
349
|
+
buffer = this.glTF.glbBuffers[bufferView.buffer];
|
|
350
|
+
arrayBuffer = buffer.slice(bufferView.byteOffset, bufferView.byteOffset + bufferView.byteLength);
|
|
351
|
+
}
|
|
352
|
+
image.bufferView = {
|
|
353
|
+
data: arrayBuffer
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
export { GLTFParser as default };
|