@shapediver/viewer.data-engine.geometry-engine 3.3.4 → 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.
- package/package.json +12 -13
- package/src/GeometryEngine.ts +0 -149
- package/src/gltfv1/GLTFLoader.ts +0 -356
- package/src/gltfv1/SDGTFLoader.ts +0 -823
- package/src/gltfv2/GLTFLoader.ts +0 -527
- package/src/gltfv2/draco/draco_decoder.js +0 -36
- package/src/gltfv2/loaders/AccessorLoader.ts +0 -100
- package/src/gltfv2/loaders/BufferLoader.ts +0 -76
- package/src/gltfv2/loaders/BufferViewLoader.ts +0 -48
- package/src/gltfv2/loaders/GeometryLoader.ts +0 -220
- package/src/gltfv2/loaders/MaterialLoader.ts +0 -380
- package/src/gltfv2/loaders/TextureLoader.ts +0 -116
- package/src/index.ts +0 -5
- package/tsconfig.json +0 -19
|
@@ -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
|
-
}
|