@shapediver/viewer.data-engine.geometry-engine 3.3.4 → 3.3.7
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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shapediver/viewer.data-engine.geometry-engine",
|
|
3
|
-
"version": "3.3.
|
|
3
|
+
"version": "3.3.7",
|
|
4
4
|
"description": "",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"author": "Michael Oppitz <michael@shapediver.com>",
|
|
@@ -10,11 +10,10 @@
|
|
|
10
10
|
"test": "__tests__"
|
|
11
11
|
},
|
|
12
12
|
"files": [
|
|
13
|
-
"dist",
|
|
14
|
-
"src",
|
|
15
13
|
"package.json",
|
|
14
|
+
"dist/",
|
|
16
15
|
"README.md",
|
|
17
|
-
"
|
|
16
|
+
"LICENSE"
|
|
18
17
|
],
|
|
19
18
|
"publishConfig": {
|
|
20
19
|
"access": "public"
|
|
@@ -40,14 +39,14 @@
|
|
|
40
39
|
},
|
|
41
40
|
"dependencies": {
|
|
42
41
|
"@shapediver/sdk.geometry-api-sdk-v2": "1.11.0",
|
|
43
|
-
"@shapediver/viewer.data-engine.material-engine": "3.3.
|
|
44
|
-
"@shapediver/viewer.data-engine.shared-types": "3.3.
|
|
45
|
-
"@shapediver/viewer.rendering-engine.camera-engine": "3.3.
|
|
46
|
-
"@shapediver/viewer.rendering-engine.light-engine": "3.3.
|
|
47
|
-
"@shapediver/viewer.shared.build-data": "3.3.
|
|
48
|
-
"@shapediver/viewer.shared.node-tree": "3.3.
|
|
49
|
-
"@shapediver/viewer.shared.services": "3.3.
|
|
50
|
-
"@shapediver/viewer.shared.types": "3.3.
|
|
42
|
+
"@shapediver/viewer.data-engine.material-engine": "3.3.7",
|
|
43
|
+
"@shapediver/viewer.data-engine.shared-types": "3.3.7",
|
|
44
|
+
"@shapediver/viewer.rendering-engine.camera-engine": "3.3.7",
|
|
45
|
+
"@shapediver/viewer.rendering-engine.light-engine": "3.3.7",
|
|
46
|
+
"@shapediver/viewer.shared.build-data": "3.3.7",
|
|
47
|
+
"@shapediver/viewer.shared.node-tree": "3.3.7",
|
|
48
|
+
"@shapediver/viewer.shared.services": "3.3.7",
|
|
49
|
+
"@shapediver/viewer.shared.types": "3.3.7",
|
|
51
50
|
"axios": "^1.2.6",
|
|
52
51
|
"gl-matrix": "3.3.0"
|
|
53
52
|
},
|
|
@@ -56,5 +55,5 @@
|
|
|
56
55
|
"path": false,
|
|
57
56
|
"os": false
|
|
58
57
|
},
|
|
59
|
-
"gitHead": "
|
|
58
|
+
"gitHead": "112787d5c5226cca5e89d08102d0b1a3dd4a1d71"
|
|
60
59
|
}
|
package/src/GeometryEngine.ts
DELETED
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
import { ITreeNode } from '@shapediver/viewer.shared.node-tree';
|
|
2
|
-
import { HttpClient, HttpResponse, Logger, PerformanceEvaluator, ShapeDiverViewerDataProcessingError } from '@shapediver/viewer.shared.services';
|
|
3
|
-
|
|
4
|
-
import { GLTFLoader as GLTF_v1Loader } from './gltfv1/GLTFLoader';
|
|
5
|
-
import { GLTFLoader as GLTF_v2Loader } from './gltfv2/GLTFLoader';
|
|
6
|
-
import { ShapeDiverResponseOutputContent } from '@shapediver/sdk.geometry-api-sdk-v2';
|
|
7
|
-
|
|
8
|
-
export class GeometryEngine {
|
|
9
|
-
// #region Properties (7)
|
|
10
|
-
|
|
11
|
-
private readonly BINARY_EXTENSION_HEADER_LENGTH = 20;
|
|
12
|
-
private readonly _httpClient: HttpClient = HttpClient.instance;
|
|
13
|
-
private readonly _loadingQueue: Promise<ITreeNode>[] = [];
|
|
14
|
-
private readonly _logger: Logger = Logger.instance;
|
|
15
|
-
private readonly _performanceEvaluator = PerformanceEvaluator.instance;
|
|
16
|
-
|
|
17
|
-
private static _instance: GeometryEngine;
|
|
18
|
-
|
|
19
|
-
private _loadingQueueLength = Infinity;
|
|
20
|
-
|
|
21
|
-
// #endregion Properties (7)
|
|
22
|
-
|
|
23
|
-
// #region Public Static Accessors (1)
|
|
24
|
-
|
|
25
|
-
public static get instance() {
|
|
26
|
-
return this._instance || (this._instance = new this());
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// #endregion Public Static Accessors (1)
|
|
30
|
-
|
|
31
|
-
// #region Public Accessors (2)
|
|
32
|
-
|
|
33
|
-
public get parallelGlTFProcessing(): number {
|
|
34
|
-
return this._loadingQueueLength;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
public set parallelGlTFProcessing(value: number) {
|
|
38
|
-
this._loadingQueueLength = value;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// #endregion Public Accessors (2)
|
|
42
|
-
|
|
43
|
-
// #region Public Methods (1)
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Load the geometry content into a scene graph node.
|
|
47
|
-
*
|
|
48
|
-
* @param content the geometry content
|
|
49
|
-
* @returns the scene graph node
|
|
50
|
-
*/
|
|
51
|
-
public async loadContent(content: ShapeDiverResponseOutputContent, taskEventId: string): Promise<ITreeNode> {
|
|
52
|
-
if (!content || (content && !content.href))
|
|
53
|
-
throw new ShapeDiverViewerDataProcessingError('GeometryEngine cannot load content.');
|
|
54
|
-
|
|
55
|
-
while (this._loadingQueueLength <= this._loadingQueue.length)
|
|
56
|
-
await new Promise(resolve => setTimeout(resolve, 10));
|
|
57
|
-
|
|
58
|
-
const url = content.href!;
|
|
59
|
-
// eslint-disable-next-line no-async-promise-executor
|
|
60
|
-
const loadingPromise = new Promise<ITreeNode>(async (resolve, reject) => {
|
|
61
|
-
let gltfContent, gltfBinary, gltfBaseUrl, gltfHeader;
|
|
62
|
-
let version = '2.0';
|
|
63
|
-
|
|
64
|
-
if (content.format === 'glb' || content.format === 'gltf') {
|
|
65
|
-
this._performanceEvaluator.startSection('gltfProcessing.' + url);
|
|
66
|
-
|
|
67
|
-
this._performanceEvaluator.startSection('loadGltf.' + url);
|
|
68
|
-
const axiosResponse = await this._httpClient.get(url!, {
|
|
69
|
-
responseType: 'arraybuffer'
|
|
70
|
-
}) as HttpResponse<ArrayBuffer>;
|
|
71
|
-
this._performanceEvaluator.endSection('loadGltf.' + url);
|
|
72
|
-
|
|
73
|
-
const magic = new TextDecoder().decode(new Uint8Array(axiosResponse.data, 0, 4));
|
|
74
|
-
const isBinary = magic === 'glTF';
|
|
75
|
-
|
|
76
|
-
if (isBinary) {
|
|
77
|
-
gltfBinary = axiosResponse.data;
|
|
78
|
-
// create header data
|
|
79
|
-
const headerDataView = new DataView(gltfBinary, 0, this.BINARY_EXTENSION_HEADER_LENGTH);
|
|
80
|
-
gltfHeader = {
|
|
81
|
-
magic: magic,
|
|
82
|
-
version: headerDataView.getUint32(4, true),
|
|
83
|
-
length: headerDataView.getUint32(8, true),
|
|
84
|
-
contentLength: headerDataView.getUint32(12, true),
|
|
85
|
-
contentFormat: headerDataView.getUint32(16, true)
|
|
86
|
-
};
|
|
87
|
-
if (gltfHeader.magic != 'glTF')
|
|
88
|
-
throw new ShapeDiverViewerDataProcessingError('Invalid data: glTF magic wrong.');
|
|
89
|
-
|
|
90
|
-
// create content
|
|
91
|
-
const contentDataView = new DataView(gltfBinary, this.BINARY_EXTENSION_HEADER_LENGTH, gltfHeader.contentLength);
|
|
92
|
-
const contentDecoded = new TextDecoder().decode(contentDataView);
|
|
93
|
-
gltfContent = JSON.parse(contentDecoded);
|
|
94
|
-
|
|
95
|
-
if (gltfContent && gltfContent.asset && gltfContent.asset.version) {
|
|
96
|
-
const assetVersion = (gltfContent.asset.version + '').endsWith('.0') ? gltfContent.asset.version : gltfContent.asset.version + '.0';
|
|
97
|
-
if (gltfHeader.version + '.0' === assetVersion) {
|
|
98
|
-
version = gltfHeader.version + '.0';
|
|
99
|
-
} else {
|
|
100
|
-
throw new ShapeDiverViewerDataProcessingError('GeometryEngine.loadContent: glTF header version (' + gltfHeader.version + ') is not the same as asset version (' + assetVersion + ').');
|
|
101
|
-
}
|
|
102
|
-
} else {
|
|
103
|
-
version = gltfHeader.version + '.0';
|
|
104
|
-
}
|
|
105
|
-
} else {
|
|
106
|
-
gltfContent = JSON.parse(new TextDecoder().decode(axiosResponse.data));
|
|
107
|
-
|
|
108
|
-
if (gltfContent && gltfContent.asset && gltfContent.asset.version) {
|
|
109
|
-
if (gltfContent.asset.version !== '2.0')
|
|
110
|
-
throw new ShapeDiverViewerDataProcessingError('GeometryEngine.loadContent: Only gltf v2 is supported in a non-binary format.');
|
|
111
|
-
} else {
|
|
112
|
-
this._logger.warn('GeometryEngine.loadContent: No version specified in asset, trying to load as v2.');
|
|
113
|
-
version = '2.0';
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const removeLastDirectoryPartOf = (the_url: string): string => {
|
|
117
|
-
const dir_char = the_url.includes('/') ? '/' : '\\';
|
|
118
|
-
const the_arr = the_url.split(dir_char);
|
|
119
|
-
the_arr.pop();
|
|
120
|
-
return the_arr.join(dir_char);
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
gltfBaseUrl = removeLastDirectoryPartOf(url!);
|
|
124
|
-
if (!gltfBaseUrl && window && window.location && window.location.href)
|
|
125
|
-
gltfBaseUrl = removeLastDirectoryPartOf(window.location.href);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
let promise: Promise<ITreeNode>;
|
|
130
|
-
if (version === '1.0') {
|
|
131
|
-
promise = new GLTF_v1Loader().load(gltfContent, gltfBinary, gltfHeader, gltfBaseUrl, taskEventId);
|
|
132
|
-
} else {
|
|
133
|
-
promise = new GLTF_v2Loader().load(gltfContent, gltfBinary, gltfHeader, gltfBaseUrl, taskEventId);
|
|
134
|
-
}
|
|
135
|
-
promise.catch(e => { reject(e); });
|
|
136
|
-
resolve(promise);
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
this._loadingQueue.push(loadingPromise);
|
|
140
|
-
const node = await loadingPromise;
|
|
141
|
-
this._loadingQueue.splice(this._loadingQueue.indexOf(loadingPromise), 1);
|
|
142
|
-
|
|
143
|
-
this._performanceEvaluator.endSection('gltfProcessing.' + url);
|
|
144
|
-
|
|
145
|
-
return node;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// #endregion Public Methods (1)
|
|
149
|
-
}
|
package/src/gltfv1/GLTFLoader.ts
DELETED
|
@@ -1,356 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-prototype-builtins */
|
|
2
|
-
import { ITreeNode, TreeNode } from '@shapediver/viewer.shared.node-tree';
|
|
3
|
-
import { HttpClient, PerformanceEvaluator, UuidGenerator, Logger, ShapeDiverViewerDataProcessingError, EventEngine, EVENTTYPE, HttpResponse } from '@shapediver/viewer.shared.services';
|
|
4
|
-
import {
|
|
5
|
-
ACCESSORCOMPONENTTYPE_V1 as ACCESSOR_COMPONENTTYPE,
|
|
6
|
-
ACCESSORTYPE_V1 as ACCESSORTYPE,
|
|
7
|
-
IGLTF_v1,
|
|
8
|
-
IGLTF_v1_Material,
|
|
9
|
-
} from '@shapediver/viewer.data-engine.shared-types';
|
|
10
|
-
import { mat4, vec3, vec4 } from 'gl-matrix';
|
|
11
|
-
import {
|
|
12
|
-
AttributeData,
|
|
13
|
-
GeometryData,
|
|
14
|
-
MATERIAL_SIDE,
|
|
15
|
-
MaterialStandardData,
|
|
16
|
-
PrimitiveData,
|
|
17
|
-
ITaskEvent,
|
|
18
|
-
TASK_TYPE,
|
|
19
|
-
PRIMITIVE_MODE,
|
|
20
|
-
} from '@shapediver/viewer.shared.types';
|
|
21
|
-
|
|
22
|
-
import { SDGTFLoader } from './SDGTFLoader';
|
|
23
|
-
|
|
24
|
-
export class GLTFLoader {
|
|
25
|
-
// #region Properties (5)
|
|
26
|
-
|
|
27
|
-
private readonly BINARY_EXTENSION_HEADER_LENGTH = 20;
|
|
28
|
-
private readonly _httpClient: HttpClient = HttpClient.instance;
|
|
29
|
-
private readonly _uuidGenerator: UuidGenerator = UuidGenerator.instance;
|
|
30
|
-
private readonly _logger: Logger = Logger.instance;
|
|
31
|
-
private readonly _implementedExtensions = ['KHR_materials_common'];
|
|
32
|
-
private readonly _globalTransformation = mat4.fromValues(1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1);
|
|
33
|
-
private readonly _eventEngine: EventEngine = EventEngine.instance;
|
|
34
|
-
private readonly _performanceEvaluator = PerformanceEvaluator.instance;
|
|
35
|
-
private readonly _progressUpdateLimit = 500;
|
|
36
|
-
|
|
37
|
-
private _baseUri: string | undefined;
|
|
38
|
-
private _body: ArrayBuffer | undefined;
|
|
39
|
-
private _content!: IGLTF_v1;
|
|
40
|
-
private _eventId: string = '';
|
|
41
|
-
private _numberOfNodes = 0;
|
|
42
|
-
private _numberOfConvertedNodes = 0;
|
|
43
|
-
private _progressTimer = 0;
|
|
44
|
-
|
|
45
|
-
// #endregion Properties (5)
|
|
46
|
-
|
|
47
|
-
// #region Public Methods (1)
|
|
48
|
-
|
|
49
|
-
public async load(content: IGLTF_v1, gltfBinary?: ArrayBuffer, gltfHeader?: { magic: string, version: number, length: number, contentLength: number, contentFormat: number }, baseUri?: string, taskEventId?: string): Promise<ITreeNode> {
|
|
50
|
-
this._eventId = taskEventId || this._uuidGenerator.create();
|
|
51
|
-
const eventStart: ITaskEvent = { type: TASK_TYPE.GLTF_CONTENT_LOADING, id: this._eventId, progress: 0, status: 'Starting glTF 1.0 loading.' };
|
|
52
|
-
this._eventEngine.emitEvent(EVENTTYPE.TASK.TASK_START, eventStart);
|
|
53
|
-
|
|
54
|
-
this._numberOfConvertedNodes = 0;
|
|
55
|
-
this._numberOfNodes = content.nodes ? Object.values(content.nodes).length : 0;
|
|
56
|
-
this._progressTimer = performance.now();
|
|
57
|
-
|
|
58
|
-
this._baseUri = baseUri;
|
|
59
|
-
if(gltfBinary && gltfHeader)
|
|
60
|
-
this._body = gltfBinary.slice(this.BINARY_EXTENSION_HEADER_LENGTH + gltfHeader.contentLength, gltfHeader.length);
|
|
61
|
-
this._content = content;
|
|
62
|
-
|
|
63
|
-
let sdgtfNode;
|
|
64
|
-
if(gltfBinary && gltfHeader)
|
|
65
|
-
sdgtfNode = await new SDGTFLoader().load(gltfBinary, gltfHeader.length);
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const eventProgressSDgTF: ITaskEvent = { type: TASK_TYPE.GLTF_CONTENT_LOADING, id: this._eventId, progress: 0.25, status: 'Loaded SDgTF content.' };
|
|
69
|
-
this._eventEngine.emitEvent(EVENTTYPE.TASK.TASK_PROCESS, eventProgressSDgTF);
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
this.validateVersionAndExtensions();
|
|
73
|
-
const node = await this.loadScene();
|
|
74
|
-
if(sdgtfNode) node.addChild(sdgtfNode);
|
|
75
|
-
|
|
76
|
-
const eventEnd: ITaskEvent = { type: TASK_TYPE.GLTF_CONTENT_LOADING, id: this._eventId, progress: 1, status: 'GlTF loading complete.' };
|
|
77
|
-
this._eventEngine.emitEvent(EVENTTYPE.TASK.TASK_END, eventEnd);
|
|
78
|
-
|
|
79
|
-
return node;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
public async loadWithUrl(url?: string | undefined): Promise<ITreeNode> {
|
|
83
|
-
this._performanceEvaluator.startSection('gltfProcessing.' + url);
|
|
84
|
-
|
|
85
|
-
this._performanceEvaluator.startSection('loadGltf.' + url);
|
|
86
|
-
const binaryGeometry = (await this._httpClient.get(url!, {
|
|
87
|
-
responseType: 'arraybuffer'
|
|
88
|
-
}) as HttpResponse<ArrayBuffer>).data;
|
|
89
|
-
this._performanceEvaluator.endSection('loadGltf.' + url);
|
|
90
|
-
|
|
91
|
-
// create header data
|
|
92
|
-
const headerDataView = new DataView(binaryGeometry, 0, this.BINARY_EXTENSION_HEADER_LENGTH);
|
|
93
|
-
const header = {
|
|
94
|
-
magic: String.fromCharCode(headerDataView.getUint8(0)) + String.fromCharCode(headerDataView.getUint8(1)) + String.fromCharCode(headerDataView.getUint8(2)) + String.fromCharCode(headerDataView.getUint8(3)),
|
|
95
|
-
version: headerDataView.getUint32(4, true),
|
|
96
|
-
length: headerDataView.getUint32(8, true),
|
|
97
|
-
contentLength: headerDataView.getUint32(12, true),
|
|
98
|
-
contentFormat: headerDataView.getUint32(16, true)
|
|
99
|
-
};
|
|
100
|
-
if (header.magic != 'glTF')
|
|
101
|
-
throw new ShapeDiverViewerDataProcessingError('GLTFLoader.load: Invalid data: glTF magic wrong.');
|
|
102
|
-
|
|
103
|
-
// create content
|
|
104
|
-
const contentDataView = new DataView(binaryGeometry, this.BINARY_EXTENSION_HEADER_LENGTH, header.contentLength);
|
|
105
|
-
const contentDecoded = new TextDecoder().decode(contentDataView);
|
|
106
|
-
this._content = JSON.parse(contentDecoded);
|
|
107
|
-
|
|
108
|
-
// create body
|
|
109
|
-
this._body = binaryGeometry.slice(this.BINARY_EXTENSION_HEADER_LENGTH + header.contentLength, header.length);
|
|
110
|
-
|
|
111
|
-
const sdgtfNode = await new SDGTFLoader().load(binaryGeometry, header.length);
|
|
112
|
-
|
|
113
|
-
this.validateVersionAndExtensions();
|
|
114
|
-
const node = await this.loadScene();
|
|
115
|
-
node.addChild(sdgtfNode);
|
|
116
|
-
this._performanceEvaluator.endSection('gltfProcessing.' + url);
|
|
117
|
-
return node;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// #endregion Public Methods (1)
|
|
121
|
-
|
|
122
|
-
// #region Private Methods (6)
|
|
123
|
-
|
|
124
|
-
private validateVersionAndExtensions(): void {
|
|
125
|
-
if(this._content.extensionsUsed) {
|
|
126
|
-
const notSupported = [];
|
|
127
|
-
for(let i = 0; i < this._content.extensionsUsed.length; i++) {
|
|
128
|
-
if(!this._implementedExtensions.includes(this._content.extensionsUsed[i]))
|
|
129
|
-
notSupported.push(this._content.extensionsUsed[i]);
|
|
130
|
-
}
|
|
131
|
-
if(notSupported.length > 0) {
|
|
132
|
-
let message = 'Extension' + (notSupported.length === 1 ? ' ' : 's ');
|
|
133
|
-
notSupported.forEach((element, index) => {
|
|
134
|
-
message += '"' + element + '"' + (index === notSupported.length-1 ? '' : index === notSupported.length-2 ? ' and ' : ', ');
|
|
135
|
-
});
|
|
136
|
-
message += (notSupported.length === 1 ? ' is' : ' are') + ' not supported, but used. Loading glTF regardless.';
|
|
137
|
-
this._logger.info('GLTFLoader.validateVersionAndExtensions: ' + message);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
private async loadAccessor(accessorName: string): Promise<AttributeData> {
|
|
143
|
-
if (!this._content.accessors![accessorName]) throw new Error('Accessor not available.');
|
|
144
|
-
const accessor = this._content.accessors![accessorName];
|
|
145
|
-
const bufferView = await this.loadBufferView(accessor.bufferView!);
|
|
146
|
-
|
|
147
|
-
const itemSize = ACCESSORTYPE[<keyof typeof ACCESSORTYPE>accessor.type];
|
|
148
|
-
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.');
|
|
149
|
-
const ArrayType = ACCESSOR_COMPONENTTYPE[<keyof typeof ACCESSOR_COMPONENTTYPE>accessor.componentType];
|
|
150
|
-
const elementBytes = ArrayType.BYTES_PER_ELEMENT;
|
|
151
|
-
const itemBytes = elementBytes * itemSize;
|
|
152
|
-
|
|
153
|
-
const byteOffset = accessor.byteOffset || 0;
|
|
154
|
-
const byteStride = accessor.byteStride;
|
|
155
|
-
const normalized = false;
|
|
156
|
-
const target = this._content.bufferViews![accessor.bufferView] ? this._content.bufferViews![accessor.bufferView].target : undefined;
|
|
157
|
-
|
|
158
|
-
const min = this._content.asset && this._content.asset?.generator === 'ShapeDiverGltfV1Writer' ? accessor.min || [] : [];
|
|
159
|
-
const max = this._content.asset && this._content.asset?.generator === 'ShapeDiverGltfV1Writer' ? accessor.max || [] : [];
|
|
160
|
-
|
|
161
|
-
// The buffer is not interleaved if the stride is the item size in bytes.
|
|
162
|
-
return new AttributeData(new ArrayType(bufferView), itemSize, itemBytes, byteOffset, elementBytes, normalized, accessor.count, min, max, byteStride, target);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
private async loadBuffer(bufferName: string): Promise<ArrayBuffer> {
|
|
166
|
-
if (!this._content.buffers![bufferName]) throw new Error('Buffer not available.');
|
|
167
|
-
const buffer = this._content.buffers![bufferName];
|
|
168
|
-
|
|
169
|
-
if (bufferName === 'binary_glTF')
|
|
170
|
-
return this._body!;
|
|
171
|
-
|
|
172
|
-
if (buffer.type === 'arraybuffer') {
|
|
173
|
-
const binaryGeometry: ArrayBuffer = (await this._httpClient.get(buffer.uri!, {
|
|
174
|
-
responseType: 'arraybuffer'
|
|
175
|
-
}) as HttpResponse<ArrayBuffer>).data;
|
|
176
|
-
return binaryGeometry;
|
|
177
|
-
}
|
|
178
|
-
if(!this._body) throw new Error('Buffer not available.');
|
|
179
|
-
return this._body;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
private async loadBufferView(bufferViewName: string): Promise<ArrayBuffer> {
|
|
183
|
-
if (!this._content.bufferViews![bufferViewName]) throw new Error('Buffer View not available.');
|
|
184
|
-
const bufferView = this._content.bufferViews![bufferViewName];
|
|
185
|
-
const buffer: ArrayBuffer = await this.loadBuffer(bufferView.buffer!);
|
|
186
|
-
const byteLength = bufferView.byteLength !== undefined ? bufferView.byteLength : 0;
|
|
187
|
-
|
|
188
|
-
return buffer.slice(bufferView.byteOffset!, bufferView.byteOffset! + byteLength);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
private async loadMaterial(materialName: string): Promise<MaterialStandardData> {
|
|
193
|
-
if(!this._content.materials![materialName]) throw new Error('Material not available.');
|
|
194
|
-
const material: IGLTF_v1_Material = this._content.materials![materialName];
|
|
195
|
-
const materialData = new MaterialStandardData();
|
|
196
|
-
if(material.name !== undefined) materialData.name = material.name;
|
|
197
|
-
|
|
198
|
-
if(material.extensions && material.extensions.KHR_materials_common) {
|
|
199
|
-
const technique = material.extensions.KHR_materials_common.technique;
|
|
200
|
-
if(technique && technique !== 'BLINN') this._logger.warn('The technique ' + technique + ' is not supported. Trying to load the material either way.');
|
|
201
|
-
const values = material.extensions.KHR_materials_common.values;
|
|
202
|
-
|
|
203
|
-
if (values.hasOwnProperty('doubleSided'))
|
|
204
|
-
materialData.side = values.doubleSided ? MATERIAL_SIDE.DOUBLE : MATERIAL_SIDE.FRONT;
|
|
205
|
-
|
|
206
|
-
materialData.color = '#d3d3d3';
|
|
207
|
-
if (values.hasOwnProperty('diffuse') && Array.isArray(values.diffuse)) {
|
|
208
|
-
const diffuseScaled = (<number[]>values.diffuse).map(element => element *= 255.0);
|
|
209
|
-
materialData.color = diffuseScaled;
|
|
210
|
-
materialData.opacity = Math.max(0.0, Math.min(values.diffuse[3], 1.0));
|
|
211
|
-
} else if(values.hasOwnProperty('diffuse')) {
|
|
212
|
-
this._logger.warn('GLTFLoader.loadMaterial: The value diffuse was set for a material, but is not supported in that type.');
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
if (!values.hasOwnProperty('diffuse') && values.hasOwnProperty('ambient')) {
|
|
216
|
-
const ambientScaled = (<number[]>values.ambient).map(element => element *= 255.0);
|
|
217
|
-
materialData.color = ambientScaled;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
if (values.hasOwnProperty('emission') && Array.isArray(values.emission)) {
|
|
221
|
-
materialData.emissiveness = values.emission;
|
|
222
|
-
} else if (values.hasOwnProperty('emission')) {
|
|
223
|
-
this._logger.warn('GLTFLoader.loadMaterial: The value emission was set for a material, but is not supported in that type.');
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
if (values.hasOwnProperty('shininess')) {
|
|
227
|
-
materialData.metalness = Math.min(1, values.shininess);
|
|
228
|
-
materialData.roughness = 1 - Math.min(1, values.shininess);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
if (values.hasOwnProperty('transparency'))
|
|
232
|
-
materialData.opacity = Math.max(0.0, Math.min(values.transparency, 1.0));
|
|
233
|
-
|
|
234
|
-
if (!values.hasOwnProperty('transparency') && values.hasOwnProperty('transparent') && (values.transparency === 'true' || values.transparency === true))
|
|
235
|
-
materialData.opacity = 0;
|
|
236
|
-
|
|
237
|
-
if (values.hasOwnProperty('_roughness'))
|
|
238
|
-
materialData.roughness = Math.min(1, Math.max(0, values.roughness));
|
|
239
|
-
|
|
240
|
-
if (values.hasOwnProperty('_metalness'))
|
|
241
|
-
materialData.metalness = Math.min(1, Math.max(0, values.metalness));
|
|
242
|
-
}
|
|
243
|
-
return materialData;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
private async loadMesh(meshName: string): Promise<ITreeNode> {
|
|
247
|
-
if (!this._content.meshes![meshName]) throw new Error('Mesh not available.');
|
|
248
|
-
const mesh = this._content.meshes![meshName];
|
|
249
|
-
const meshNode = new TreeNode(meshName);
|
|
250
|
-
|
|
251
|
-
if(!mesh.primitives) return new TreeNode('primitive');
|
|
252
|
-
for (let i = 0, len = mesh.primitives!.length; i < len; i++) {
|
|
253
|
-
const primitiveNode = new TreeNode('primitive_' + i);
|
|
254
|
-
meshNode.addChild(primitiveNode);
|
|
255
|
-
|
|
256
|
-
const primitive = mesh.primitives![i];
|
|
257
|
-
const attributes: {
|
|
258
|
-
[key: string]: AttributeData
|
|
259
|
-
} = {};
|
|
260
|
-
|
|
261
|
-
for (const attribute in primitive.attributes) {
|
|
262
|
-
// attribute name conversion to be consistent witg gltf
|
|
263
|
-
let attributeName = attribute;
|
|
264
|
-
if(/\d/.test(attributeName) && !attributeName.includes('_')) {
|
|
265
|
-
const index = attributeName.search(/\d/);
|
|
266
|
-
attributeName = attributeName.substring(0, index) + '_' + attributeName.substring(index, attributeName.length);
|
|
267
|
-
} else if(attributeName === 'TEXCOORD' || attributeName === 'COLOR' || attributeName === 'JOINTS' || attributeName === 'WEIGHTS') {
|
|
268
|
-
attributeName += '_0';
|
|
269
|
-
} else if (attributeName === 'UV') {
|
|
270
|
-
attributeName = 'TEXCOORD_0';
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
attributes[attributeName] = await this.loadAccessor(primitive.attributes[attribute]);
|
|
274
|
-
if(attributeName.startsWith('COLOR'))
|
|
275
|
-
attributes[attributeName] = new AttributeData(attributes[attributeName].array, attributes[attributeName].itemSize, attributes[attributeName].itemBytes, attributes[attributeName].byteOffset, attributes[attributeName].elementBytes, true, attributes[attributeName].count, [], [], attributes[attributeName].byteStride, attributes[attributeName].target);
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
let material: MaterialStandardData | undefined;
|
|
279
|
-
if(primitive.material)
|
|
280
|
-
material = await this.loadMaterial(primitive.material);
|
|
281
|
-
|
|
282
|
-
const geometry = new GeometryData(new PrimitiveData(attributes, await this.loadAccessor(primitive.indices!)), PRIMITIVE_MODE.TRIANGLES, material);
|
|
283
|
-
primitiveNode.data.push(geometry);
|
|
284
|
-
}
|
|
285
|
-
return meshNode;
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
private async loadNode(nodeName: string): Promise<ITreeNode> {
|
|
289
|
-
if (!this._content.nodes![nodeName]) throw new Error('Node not available.');
|
|
290
|
-
const node = this._content.nodes![nodeName];
|
|
291
|
-
const nodeDef = new TreeNode(nodeName);
|
|
292
|
-
|
|
293
|
-
if (node.matrix) {
|
|
294
|
-
nodeDef.addTransformation({
|
|
295
|
-
id: this._uuidGenerator.create(),
|
|
296
|
-
matrix: mat4.fromValues(node.matrix[0], node.matrix[1], node.matrix[2], node.matrix[3],
|
|
297
|
-
node.matrix[4], node.matrix[5], node.matrix[6], node.matrix[7],
|
|
298
|
-
node.matrix[8], node.matrix[9], node.matrix[10], node.matrix[11],
|
|
299
|
-
node.matrix[12], node.matrix[13], node.matrix[14], node.matrix[15])
|
|
300
|
-
});
|
|
301
|
-
} else if (node.translation || node.scale || node.rotation) {
|
|
302
|
-
const matT = node.translation ? mat4.fromTranslation(mat4.create(), vec3.fromValues(node.translation[0], node.translation[1], node.translation[2])) : mat4.create();
|
|
303
|
-
const matS = node.scale ? mat4.fromScaling(mat4.create(), vec3.fromValues(node.scale[0], node.scale[1], node.scale[2])) : mat4.create();
|
|
304
|
-
const matR = node.rotation ? mat4.fromQuat(mat4.create(), vec4.fromValues(node.rotation[0], node.rotation[1], node.rotation[2], node.rotation[3])) : mat4.create();
|
|
305
|
-
const matrix = mat4.mul(mat4.create(), mat4.mul(mat4.create(), matT, matS), matR);
|
|
306
|
-
nodeDef.addTransformation({
|
|
307
|
-
id: this._uuidGenerator.create(),
|
|
308
|
-
matrix: matrix
|
|
309
|
-
});
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
if(node.meshes) {
|
|
313
|
-
for (let i = 0, len = node.meshes!.length; i < len; i++) {
|
|
314
|
-
// we create a child node as we one want to have one mesh as in the GLTF2 def
|
|
315
|
-
nodeDef.addChild(await this.loadMesh(node.meshes![i]));
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
if (node.children) {
|
|
320
|
-
for (let i = 0, len = node.children!.length; i < len; i++) {
|
|
321
|
-
// got through all children
|
|
322
|
-
nodeDef.addChild(await this.loadNode(node.children![i]));
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
this._numberOfConvertedNodes++;
|
|
328
|
-
|
|
329
|
-
if(performance.now() - this._progressTimer > this._progressUpdateLimit) {
|
|
330
|
-
this._progressTimer = performance.now();
|
|
331
|
-
const eventProgress: ITaskEvent = { type: TASK_TYPE.GLTF_CONTENT_LOADING, id: this._eventId, progress: (this._numberOfConvertedNodes / this._numberOfNodes) / 2 + 0.25, status: `GlTF conversion progress: ${this._numberOfConvertedNodes}/${this._numberOfNodes} nodes.` };
|
|
332
|
-
this._eventEngine.emitEvent(EVENTTYPE.TASK.TASK_PROCESS, eventProgress);
|
|
333
|
-
await new Promise(resolve => setTimeout(resolve, 0));
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
return nodeDef;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
private async loadScene(): Promise<ITreeNode> {
|
|
340
|
-
if (!this._content.scene) throw new Error('No scene.');
|
|
341
|
-
if (!this._content.scenes![this._content.scene!]) throw new Error('Scene not available.');
|
|
342
|
-
const scene = this._content.scenes![this._content.scene!];
|
|
343
|
-
const sceneDef = new TreeNode(this._content.scene!);
|
|
344
|
-
if(this._content.asset && this._content.asset?.generator !== 'ShapeDiverGltfWriter' && this._content.asset?.generator !== 'ShapeDiverGltfV1Writer') {
|
|
345
|
-
sceneDef.addTransformation({
|
|
346
|
-
id: this._uuidGenerator.create(),
|
|
347
|
-
matrix: this._globalTransformation
|
|
348
|
-
});
|
|
349
|
-
}
|
|
350
|
-
if(scene.nodes)
|
|
351
|
-
for (let i = 0, len = scene.nodes!.length; i < len; i++)
|
|
352
|
-
sceneDef.addChild(await this.loadNode(scene.nodes![i]));
|
|
353
|
-
return sceneDef;
|
|
354
|
-
}
|
|
355
|
-
// #endregion Private Methods (6)
|
|
356
|
-
}
|