@shapediver/viewer.data-engine.geometry-engine 3.3.3 → 3.3.6

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,100 +0,0 @@
1
- import { AttributeData } from '@shapediver/viewer.shared.types'
2
- import {
3
- ACCESSORCOMPONENTTYPE_V2 as ACCESSOR_COMPONENTTYPE,
4
- ACCESSORTYPE_V2 as ACCESSORTYPE,
5
- IGLTF_v2
6
- } from '@shapediver/viewer.data-engine.shared-types'
7
- import { Logger } from '@shapediver/viewer.shared.services'
8
-
9
- import { BufferViewLoader } from './BufferViewLoader'
10
-
11
- export class AccessorLoader {
12
- // #region Properties (2)
13
-
14
- private readonly _logger: Logger = Logger.instance;
15
-
16
- private _loaded: {
17
- [key: string]: AttributeData | null
18
- } = {};
19
-
20
- // #endregion Properties (2)
21
-
22
- // #region Constructors (1)
23
-
24
- constructor(private readonly _content: IGLTF_v2, private readonly _bufferViewLoader: BufferViewLoader) { }
25
-
26
- // #endregion Constructors (1)
27
-
28
- // #region Public Methods (2)
29
-
30
- public getAccessor(accessorId: number): AttributeData | null {
31
- if (!this._content.accessors) throw new Error('AccessorLoader.getAccessor: Accessors not available.')
32
- if (!this._content.accessors[accessorId]) throw new Error('AccessorLoader.getAccessor: Accessor not available.')
33
- if (!this._loaded[accessorId]) throw new Error('AccessorLoader.getAccessor: Accessor not loaded.')
34
- return this._loaded[accessorId];
35
- }
36
-
37
- public load(): void {
38
- if (!this._content.accessors) return;
39
- for (let i = 0; i < this._content.accessors.length; i++) {
40
- const accessorId = i;
41
- if (!this._content.accessors[accessorId]) throw new Error('AccessorLoader.load: BufferView not available.')
42
- const accessor = this._content.accessors[accessorId];
43
-
44
- if (accessor.bufferView === undefined) {
45
- // Ignore empty accessors, which may be used to declare runtime
46
- // information about attributes coming from another source (e.g. Draco
47
- // compression extension).
48
- this._loaded[accessorId] = null;
49
- continue;
50
- }
51
-
52
- const arrayBuffer = this._bufferViewLoader.getBufferView(accessor.bufferView!);
53
-
54
- const itemSize = ACCESSORTYPE[<keyof typeof ACCESSORTYPE>accessor.type];
55
- if (accessor.componentType === 5124) this._logger.warn('GLTFLoader.loadAccessor: The componentType for this accessor is 5124, which is not allowed. Trying to load it anyway.');
56
- const ArrayType = ACCESSOR_COMPONENTTYPE[<keyof typeof ACCESSOR_COMPONENTTYPE>accessor.componentType];
57
-
58
- const elementBytes = ArrayType.BYTES_PER_ELEMENT;
59
- const itemBytes = elementBytes * itemSize;
60
- const byteOffset = accessor.byteOffset || 0;
61
- const byteStride = accessor.bufferView !== undefined ? this._content.bufferViews ? this._content.bufferViews[accessor.bufferView].byteStride : undefined : undefined;
62
- const normalized = accessor.normalized === true;
63
- const target = this._content.bufferViews ? this._content.bufferViews[accessor.bufferView].target : undefined;
64
- let array;
65
-
66
- if (byteStride && byteStride !== itemBytes) {
67
- // Each "slice" of the buffer, as defined by 'count' elements of 'byteStride' bytes, gets its own InterleavedBuffer
68
- // This makes sure that IBA.count reflects accessor.count properly
69
- const ibSlice = Math.floor(byteOffset / byteStride);
70
- array = new ArrayType(arrayBuffer, ibSlice * byteStride, accessor.count * byteStride / elementBytes);
71
- } else {
72
- if (arrayBuffer === null) {
73
- array = new ArrayType(accessor.count * itemSize);
74
- } else {
75
- array = new ArrayType(arrayBuffer, byteOffset, accessor.count * itemSize);
76
- }
77
- }
78
-
79
- if (accessor.sparse !== undefined) {
80
- const itemSizeIndices = ACCESSORTYPE.SCALAR;
81
- const IndicesArrayType = ACCESSOR_COMPONENTTYPE[<keyof typeof ACCESSOR_COMPONENTTYPE>accessor.sparse.indices.componentType];
82
-
83
- const byteOffsetIndices = accessor.sparse.indices.byteOffset || 0;
84
- const byteOffsetValues = accessor.sparse.values.byteOffset || 0;
85
-
86
- if (!accessor.sparse.indices.bufferView || !accessor.sparse.values.bufferView) throw new Error('Sparse Mesh not properly defined.')
87
-
88
- const sparseIndices = new IndicesArrayType(this._bufferViewLoader.getBufferView(accessor.sparse.indices.bufferView!), byteOffsetIndices, accessor.sparse.count * itemSizeIndices);
89
- const sparseValues = new ArrayType(this._bufferViewLoader.getBufferView(accessor.sparse.values.bufferView!), byteOffsetValues, accessor.sparse.count * itemSize);
90
-
91
- this._loaded[accessorId] = new AttributeData(array, itemSize, itemBytes, byteOffset, elementBytes, normalized, accessor.count, accessor.min, accessor.max, byteStride, target, true, sparseIndices, sparseValues);
92
- continue;
93
- }
94
-
95
- this._loaded[accessorId] = new AttributeData(array, itemSize, itemBytes, byteOffset, elementBytes, normalized, accessor.count, accessor.min, accessor.max, byteStride, target);
96
- }
97
- }
98
-
99
- // #endregion Public Methods (2)
100
- }
@@ -1,76 +0,0 @@
1
- import { IGLTF_v2 } from '@shapediver/viewer.data-engine.shared-types';
2
- import { HttpClient, HttpResponse, atobCustom } from '@shapediver/viewer.shared.services';
3
-
4
- export class BufferLoader {
5
- // #region Properties (2)
6
-
7
- private readonly _httpClient: HttpClient = HttpClient.instance;
8
-
9
- private _loaded: {
10
- [key: string]: ArrayBuffer
11
- } = {};
12
-
13
- // #endregion Properties (2)
14
-
15
- // #region Constructors (1)
16
-
17
- constructor(private readonly _content: IGLTF_v2, private _body?: ArrayBuffer, private _baseUri?: string) { }
18
-
19
- // #endregion Constructors (1)
20
-
21
- // #region Public Methods (2)
22
-
23
- public getBuffer(bufferId: number): ArrayBuffer {
24
- if (!this._content.buffers) throw new Error('BufferLoader.getBuffer: Buffers not available.');
25
- if (!this._content.buffers[bufferId]) throw new Error('BufferLoader.getBuffer: Buffer not available.');
26
- if (!this._loaded[bufferId]) throw new Error('BufferLoader.getBuffer: Buffer not loaded.');
27
- return this._loaded[bufferId];
28
- }
29
-
30
- public async load(): Promise<void> {
31
- if (!this._content.buffers) return;
32
-
33
- const promises: Promise<void>[] = [];
34
-
35
- for (let i = 0; i < this._content.buffers.length; i++) {
36
- const bufferId = i;
37
- const buffer = this._content.buffers[bufferId];
38
-
39
- if (buffer.type && buffer.type !== 'arraybuffer') {
40
- throw new Error(`BufferLoader.load: ${buffer.type} is not supported.`);
41
- }
42
-
43
- // If present, GLB container is required to be the first buffer.
44
- if (buffer.uri === undefined && bufferId === 0) {
45
- if (!this._body) throw new Error('BufferLoader.load: Buffer not available.');
46
- this._loaded[bufferId] = this._body;
47
- return;
48
- }
49
-
50
- const dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/;
51
- const dataUriRegexResult = buffer.uri!.match(dataUriRegex);
52
-
53
- // Safari can not handle Data URIs through XMLHttpRequest so process manually
54
- if (dataUriRegexResult) {
55
- const isBase64 = !!dataUriRegexResult[2];
56
- let data = dataUriRegexResult[3];
57
- data = decodeURIComponent(data);
58
- if (isBase64) data = atobCustom(data);
59
-
60
- const view = new Uint8Array(data.length);
61
- for (let i = 0; i < data.length; i++) {
62
- view[i] = data.charCodeAt(i);
63
- }
64
- this._loaded[bufferId] = view.buffer;
65
- } else {
66
- const httpResultPromise = (this._httpClient.get(this._baseUri + '/' + buffer.uri!, {
67
- responseType: 'arraybuffer'
68
- }) as Promise<HttpResponse<ArrayBuffer>>).then(response => { this._loaded[bufferId] = response.data; });
69
- promises.push(httpResultPromise);
70
- }
71
- }
72
- await Promise.all(promises);
73
- }
74
-
75
- // #endregion Public Methods (2)
76
- }
@@ -1,48 +0,0 @@
1
- import { IGLTF_v2 } from '@shapediver/viewer.data-engine.shared-types'
2
-
3
- import { BufferLoader } from './BufferLoader'
4
-
5
- export class BufferViewLoader {
6
- // #region Properties (1)
7
-
8
- private _loaded: {
9
- [key: string]: ArrayBuffer
10
- } = {};
11
-
12
- // #endregion Properties (1)
13
-
14
- // #region Constructors (1)
15
-
16
- constructor(private readonly _content: IGLTF_v2, private readonly _bufferLoader: BufferLoader) { }
17
-
18
- // #endregion Constructors (1)
19
-
20
- // #region Public Methods (2)
21
-
22
- public getBufferView(bufferViewId: number): ArrayBuffer {
23
- if (!this._content.bufferViews) throw new Error('BufferViewLoader.load: BufferViews not available.')
24
- if (!this._content.bufferViews[bufferViewId]) throw new Error('BufferViewLoader.load: BufferView not available.')
25
- if (!this._loaded[bufferViewId]) throw new Error('BufferViewLoader.load: BufferView not loaded.')
26
- return this._loaded[bufferViewId];
27
- }
28
-
29
- public load(): void {
30
- if (!this._content.bufferViews) return;
31
- for (let i = 0; i < this._content.bufferViews.length; i++) {
32
- const bufferViewId = i;
33
- if (!this._content.bufferViews[bufferViewId]) throw new Error('BufferViewLoader.load: BufferView not available.')
34
- const bufferView = this._content.bufferViews[bufferViewId];
35
-
36
- const byteLength = bufferView.byteLength || 0;
37
- const byteOffset = bufferView.byteOffset || 0;
38
-
39
- if (bufferView.buffer === undefined) throw new Error('BufferViewLoader.load: BufferView has no buffer defined.')
40
- const buffer = this._bufferLoader.getBuffer(bufferView.buffer!);
41
- const result = buffer.slice(byteOffset, byteOffset + byteLength);
42
-
43
- this._loaded[bufferViewId] = result;
44
- }
45
- }
46
-
47
- // #endregion Public Methods (2)
48
- }
@@ -1,220 +0,0 @@
1
- import { IGLTF_v2, IGLTF_v2_Primitive } from '@shapediver/viewer.data-engine.shared-types'
2
- import { ITreeNode, TreeNode } from '@shapediver/viewer.shared.node-tree'
3
- import { AttributeData, GeometryData, MaterialVariantsData, PrimitiveData } from '@shapediver/viewer.shared.types'
4
-
5
- import { GLTF_EXTENSIONS } from '../GLTFLoader'
6
- import { AccessorLoader } from './AccessorLoader'
7
- import { BufferViewLoader } from './BufferViewLoader'
8
- import { MaterialLoader } from './MaterialLoader'
9
-
10
- export class GeometryLoader {
11
- // #region Properties (1)
12
-
13
- private _materialVariantsData = new MaterialVariantsData();
14
- private _loaded: {
15
- [key: string]: GeometryData
16
- } = {};
17
-
18
- // #endregion Properties (1)
19
-
20
- // #region Constructors (1)
21
-
22
- constructor(
23
- private readonly _content: IGLTF_v2,
24
- private readonly _accessorLoader: AccessorLoader,
25
- private readonly _bufferViewLoader: BufferViewLoader,
26
- private readonly _materialLoader: MaterialLoader,
27
- private readonly _dracoModule: any
28
- ) { }
29
-
30
- // #endregion Constructors (1)
31
-
32
- // #region Public Accessors (1)
33
-
34
- public get materialVariantsData(): MaterialVariantsData {
35
- return this._materialVariantsData;
36
- }
37
-
38
- // #endregion Public Accessors (1)
39
-
40
- // #region Public Methods (1)
41
-
42
- public loadMesh(meshId: number, weights?: number[]): ITreeNode {
43
- if (!this._content.meshes) throw new Error('GeometryLoader.loadMesh: Meshes not available.')
44
- if (!this._content.meshes[meshId]) throw new Error('GeometryLoader.loadMesh: Mesh not available.')
45
-
46
- const mesh = this._content.meshes[meshId];
47
- const meshNode = new TreeNode(mesh.name || 'mesh_' + meshId);
48
- meshNode.originalName = mesh.name;
49
-
50
- if (mesh.primitives)
51
- for (let i = 0, len = mesh.primitives.length; i < len; i++)
52
- meshNode.addChild(this.loadPrimitive(meshId, mesh.primitives, i, mesh.weights || weights));
53
-
54
- return meshNode;
55
- }
56
-
57
- // #endregion Public Methods (1)
58
-
59
- // #region Private Methods (1)
60
-
61
- private loadPrimitive(meshId: number, primitives: IGLTF_v2_Primitive[], index: number, weights: number[] = []): ITreeNode {
62
- const primitive = primitives[index];
63
- const primitiveNode = new TreeNode('primitive_' + index);
64
-
65
- if (this._loaded['mesh_' + meshId + '_primitive_' + index]) {
66
- primitiveNode.data.push(this._loaded['mesh_' + meshId + '_primitive_' + index].clone());
67
- return primitiveNode;
68
- }
69
-
70
- const attributes: {
71
- [key: string]: AttributeData
72
- } = {};
73
-
74
- let indices = null;
75
- const convertedNames: { [key: string]: string } = {}
76
-
77
- if (primitive.extensions && primitive.extensions[GLTF_EXTENSIONS.KHR_DRACO_MESH_COMPRESSION]) {
78
- const dracoDef = primitive.extensions[GLTF_EXTENSIONS.KHR_DRACO_MESH_COMPRESSION];
79
- const arrayBuffer = this._bufferViewLoader.getBufferView(dracoDef.bufferView!);
80
-
81
- const decoder = new this._dracoModule.Decoder();
82
- const array = new Int8Array(arrayBuffer);
83
- const geometryType = decoder.GetEncodedGeometryType(array);
84
-
85
- let dracoGeometry;
86
- if (geometryType === this._dracoModule.TRIANGULAR_MESH) {
87
- dracoGeometry = new this._dracoModule.Mesh();
88
- decoder.DecodeArrayToMesh(array, array.byteLength, dracoGeometry);
89
- } else if (geometryType === this._dracoModule.POINT_CLOUD) {
90
- dracoGeometry = new this._dracoModule.PointCloud();
91
- decoder.DecodeArrayToPointCloud(array, array.byteLength, dracoGeometry);
92
- }
93
-
94
- if (dracoDef.attributes['POSITION'] === undefined) {
95
- const errorMsg = "No position attribute found in the mesh.";
96
- this._dracoModule.destroy(decoder);
97
- this._dracoModule.destroy(dracoGeometry);
98
- throw new Error(errorMsg);
99
- }
100
-
101
- for (let a in dracoDef.attributes) {
102
- const attribute = decoder.GetAttributeByUniqueId(dracoGeometry, dracoDef.attributes[a])
103
- const attributeData = new this._dracoModule.DracoFloat32Array();
104
- decoder.GetAttributeFloatForAllPoints(dracoGeometry, attribute, attributeData);
105
-
106
- const byteOffset = attribute.byte_offset();
107
- const normalized = attribute.normalized();
108
- const numComponents = attribute.num_components();
109
-
110
- const numPoints = dracoGeometry.num_points();
111
- const numValues = numPoints * numComponents;
112
- const byteLength = numValues * Float32Array.BYTES_PER_ELEMENT;
113
-
114
- const ptr = this._dracoModule._malloc(byteLength);
115
- decoder.GetAttributeDataArrayForAllPoints(dracoGeometry, attribute, this._dracoModule.DT_FLOAT32, byteLength, ptr);
116
- const array = new Float32Array(this._dracoModule.HEAPF32.buffer, ptr, numValues).slice();
117
- this._dracoModule._free(ptr);
118
-
119
- if(a.includes("COLOR")) array.forEach((n, i) => array[i] = Math.max(0, Math.min(1, n)));
120
-
121
- attributes[a] = new AttributeData(
122
- array,
123
- numComponents, // itemSize
124
- array.BYTES_PER_ELEMENT * numComponents, // itemBytes = elementBytes * itemSize
125
- byteOffset, // byteOffset
126
- array.BYTES_PER_ELEMENT, // elementBytes
127
- normalized, // normalized
128
- array.length / numComponents
129
- );
130
- }
131
-
132
- if (geometryType == this._dracoModule.TRIANGULAR_MESH) {
133
-
134
- const numFaces = dracoGeometry.num_faces();
135
- const numIndices = numFaces * 3;
136
- const byteLength = numIndices * 4;
137
-
138
- const ptr = this._dracoModule._malloc(byteLength);
139
- decoder.GetTrianglesUInt32Array(dracoGeometry, byteLength, ptr);
140
- const indexArray = new Uint32Array(this._dracoModule.HEAPF32.buffer, ptr, numIndices).slice();
141
- this._dracoModule._free(ptr);
142
-
143
- indices = new AttributeData(
144
- indexArray,
145
- 1, // itemSize
146
- indexArray.BYTES_PER_ELEMENT * 1, // itemBytes = elementBytes * itemSize
147
- 0, // byteOffset
148
- indexArray.BYTES_PER_ELEMENT, // elementBytes
149
- false, // normalized
150
- indexArray.length // count
151
- );
152
- }
153
-
154
- this._dracoModule.destroy(decoder);
155
- this._dracoModule.destroy(dracoGeometry);
156
- }
157
-
158
- for (let attribute in primitive.attributes) {
159
- if (attributes[attribute]) {
160
- convertedNames[attribute] = attribute;
161
- continue;
162
- }
163
-
164
-
165
- let attributeName = attribute;
166
- // attribute name conversion to be consistent with gltf
167
- if (/\d/.test(attributeName) && !attributeName.includes('_')) {
168
- const index = attributeName.search(/\d/)
169
- attributeName = attributeName.substring(0, index) + '_' + attributeName.substring(index, attributeName.length);
170
- } else if (attributeName === 'TEXCOORD' || attributeName === 'COLOR' || attributeName === 'JOINTS' || attributeName === 'WEIGHTS') {
171
- attributeName += '_0';
172
- } else if (attributeName === 'UV') {
173
- attributeName = 'TEXCOORD_0';
174
- }
175
-
176
- convertedNames[attribute] = attributeName;
177
- attributes[attributeName] = (this._accessorLoader.getAccessor(primitive.attributes[attribute]))!;
178
- }
179
-
180
- if ((primitive.indices || primitive.indices === 0) && !indices)
181
- indices = this._accessorLoader.getAccessor(primitive.indices);
182
-
183
- // reading and assigning morph targets
184
- if (primitive.targets) {
185
- for (let i = 0; i < primitive.targets.length; i++) {
186
- for (let target in primitive.targets[i]) {
187
- if (!attributes[target]) continue;
188
- attributes[convertedNames[target]].morphAttributeData.push((this._accessorLoader.getAccessor(primitive.targets[i][target]))!);
189
- }
190
- }
191
- }
192
-
193
- let material = null;
194
- if (primitive.material || primitive.material === 0)
195
- material = this._materialLoader.getMaterial(primitive.material);
196
-
197
- const primitiveData = new PrimitiveData(attributes, indices);
198
- const geometryData = new GeometryData(primitiveData, primitive.mode, material);
199
-
200
- if (primitive.extensions && primitive.extensions[GLTF_EXTENSIONS.KHR_MATERIALS_VARIANTS]) {
201
- this._materialVariantsData.geometryData.push(geometryData);
202
- const variantsExtension = primitive.extensions[GLTF_EXTENSIONS.KHR_MATERIALS_VARIANTS];
203
-
204
- for (let i = 0; i < variantsExtension.mappings.length; i++) {
205
- const mapping = variantsExtension.mappings[i];
206
- const material = this._materialLoader.getMaterial(mapping.material);
207
- for (let j = 0; j < mapping.variants.length; j++)
208
- geometryData.materialVariants.push({ variant: mapping.variants[j], material });
209
- }
210
- }
211
-
212
- geometryData.morphWeights = weights;
213
- this._loaded['mesh_' + meshId + '_primitive_' + index] = geometryData;
214
-
215
- primitiveNode.data.push(geometryData);
216
- return primitiveNode;
217
- }
218
-
219
- // #endregion Private Methods (1)
220
- }