@inweb/viewer-three 26.10.6 → 26.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -4
- package/dist/{plugins → extensions}/components/AxesHelperComponent.js +23 -1
- package/dist/extensions/components/AxesHelperComponent.js.map +1 -0
- package/dist/extensions/components/AxesHelperComponent.min.js +24 -0
- package/dist/{plugins → extensions}/components/AxesHelperComponent.module.js +24 -2
- package/dist/extensions/components/AxesHelperComponent.module.js.map +1 -0
- package/dist/{plugins → extensions}/components/ExtentsHelperComponent.js +18 -0
- package/dist/extensions/components/ExtentsHelperComponent.js.map +1 -0
- package/dist/{plugins/components/AxesHelperComponent.min.js → extensions/components/ExtentsHelperComponent.min.js} +1 -1
- package/dist/{plugins → extensions}/components/ExtentsHelperComponent.module.js +19 -1
- package/dist/extensions/components/ExtentsHelperComponent.module.js.map +1 -0
- package/dist/extensions/components/GridHelperComponent.js.map +1 -0
- package/dist/extensions/components/GridHelperComponent.module.js.map +1 -0
- package/dist/extensions/components/InfoPanelComponent.js +170 -0
- package/dist/extensions/components/InfoPanelComponent.js.map +1 -0
- package/dist/extensions/components/InfoPanelComponent.min.js +24 -0
- package/dist/extensions/components/InfoPanelComponent.module.js +164 -0
- package/dist/extensions/components/InfoPanelComponent.module.js.map +1 -0
- package/dist/extensions/components/LightHelperComponent.js.map +1 -0
- package/dist/extensions/components/LightHelperComponent.module.js.map +1 -0
- package/dist/extensions/components/RoomEnvironmentComponent.js.map +1 -0
- package/dist/extensions/components/RoomEnvironmentComponent.module.js.map +1 -0
- package/dist/{plugins → extensions}/components/StatsPanelComponent.js +9 -3
- package/dist/extensions/components/StatsPanelComponent.js.map +1 -0
- package/dist/extensions/components/StatsPanelComponent.min.js +24 -0
- package/dist/{plugins → extensions}/components/StatsPanelComponent.module.js +9 -3
- package/dist/extensions/components/StatsPanelComponent.module.js.map +1 -0
- package/dist/{plugins → extensions}/loaders/GLTFCloudLoader.js +2 -3
- package/dist/extensions/loaders/GLTFCloudLoader.js.map +1 -0
- package/dist/{plugins → extensions}/loaders/GLTFCloudLoader.min.js +1 -1
- package/dist/{plugins → extensions}/loaders/GLTFCloudLoader.module.js +2 -3
- package/dist/extensions/loaders/GLTFCloudLoader.module.js.map +1 -0
- package/dist/extensions/loaders/GLTFFileLoader.js +2499 -0
- package/dist/extensions/loaders/GLTFFileLoader.js.map +1 -0
- package/dist/extensions/loaders/GLTFFileLoader.min.js +24 -0
- package/dist/extensions/loaders/GLTFFileLoader.module.js +74 -0
- package/dist/extensions/loaders/GLTFFileLoader.module.js.map +1 -0
- package/dist/{plugins → extensions}/loaders/IFCXLoader.js +5 -7
- package/dist/extensions/loaders/IFCXLoader.js.map +1 -0
- package/dist/{plugins → extensions}/loaders/IFCXLoader.min.js +1 -1
- package/dist/{plugins → extensions}/loaders/IFCXLoader.module.js +5 -7
- package/dist/extensions/loaders/IFCXLoader.module.js.map +1 -0
- package/dist/{plugins → extensions}/loaders/PotreeLoader.js +56 -6
- package/dist/extensions/loaders/PotreeLoader.js.map +1 -0
- package/dist/extensions/loaders/PotreeLoader.min.js +24 -0
- package/dist/{plugins → extensions}/loaders/PotreeLoader.module.js +53 -2
- package/dist/extensions/loaders/PotreeLoader.module.js.map +1 -0
- package/dist/viewer-three.js +1416 -2930
- package/dist/viewer-three.js.map +1 -1
- package/dist/viewer-three.min.js +8 -3
- package/dist/viewer-three.module.js +1205 -363
- package/dist/viewer-three.module.js.map +1 -1
- package/{plugins → extensions}/components/AxesHelperComponent.ts +31 -2
- package/{plugins → extensions}/components/ExtentsHelperComponent.ts +25 -0
- package/extensions/components/InfoPanelComponent.ts +197 -0
- package/{plugins → extensions}/components/StatsPanelComponent.ts +10 -3
- package/{plugins → extensions}/loaders/GLTFCloudLoader.ts +2 -3
- package/{src/Viewer → extensions}/loaders/GLTFFileLoader.ts +21 -12
- package/{plugins → extensions}/loaders/IFCX/IFCXCloudLoader.ts +5 -5
- package/{plugins → extensions}/loaders/IFCX/IFCXFileLoader.ts +3 -4
- package/{plugins → extensions}/loaders/Potree/PotreeFileLoader.ts +3 -4
- package/extensions/loaders/Potree/PotreeModelImpl.ts +108 -0
- package/lib/Viewer/Viewer.d.ts +28 -20
- package/lib/Viewer/commands/GetSelected2.d.ts +2 -0
- package/lib/Viewer/commands/SelectModel.d.ts +1 -1
- package/lib/Viewer/commands/SetSelected2.d.ts +2 -0
- package/lib/Viewer/components/InfoComponent.d.ts +22 -0
- package/lib/Viewer/components/SelectionComponent.d.ts +1 -3
- package/lib/Viewer/components/index.d.ts +6 -6
- package/lib/Viewer/draggers/MeasureLineDragger.d.ts +7 -1
- package/lib/Viewer/loaders/DynamicGltfLoader/DynamicModelImpl.d.ts +2 -1
- package/lib/Viewer/loaders/GLTFBinaryExtension.d.ts +5 -0
- package/lib/Viewer/loaders/GLTFCloudDynamicLoader.d.ts +2 -2
- package/lib/Viewer/loaders/{GLTFFileLoader.d.ts → GLTFFileDynamicLoader.d.ts} +7 -1
- package/lib/Viewer/loaders/GLTFLoadingManager.d.ts +4 -3
- package/lib/Viewer/loaders/RangesLoader.d.ts +15 -0
- package/lib/Viewer/loaders/index.d.ts +22 -14
- package/lib/Viewer/measurement/Snapper.d.ts +15 -0
- package/lib/Viewer/measurement/UnitConverter.d.ts +63 -0
- package/lib/Viewer/measurement/UnitFormatter.d.ts +4 -0
- package/lib/Viewer/models/IModelImpl.d.ts +11 -8
- package/lib/Viewer/models/ModelImpl.d.ts +9 -5
- package/package.json +11 -11
- package/src/Viewer/Viewer.ts +127 -88
- package/src/Viewer/commands/ClearSelected.ts +3 -1
- package/src/Viewer/commands/GetModels.ts +1 -1
- package/src/Viewer/commands/GetSelected.ts +2 -2
- package/{plugins/loaders/Potree/PotreeModelImpl.ts → src/Viewer/commands/GetSelected2.ts} +7 -9
- package/src/Viewer/commands/HideSelected.ts +3 -1
- package/src/Viewer/commands/SelectModel.ts +5 -5
- package/src/Viewer/commands/SetSelected.ts +9 -10
- package/src/Viewer/commands/SetSelected2.ts +42 -0
- package/src/Viewer/commands/ZoomToObjects.ts +5 -6
- package/src/Viewer/commands/ZoomToSelected.ts +3 -1
- package/src/Viewer/commands/index.ts +4 -0
- package/src/Viewer/components/CameraComponent.ts +6 -1
- package/src/Viewer/components/ExtentsComponent.ts +4 -1
- package/src/Viewer/components/InfoComponent.ts +187 -0
- package/src/Viewer/components/SelectionComponent.ts +7 -30
- package/src/Viewer/components/index.ts +8 -6
- package/src/Viewer/draggers/MeasureLineDragger.ts +84 -226
- package/src/Viewer/loaders/DynamicGltfLoader/DynamicGltfLoader.js +276 -39
- package/src/Viewer/loaders/DynamicGltfLoader/DynamicModelImpl.ts +45 -10
- package/src/Viewer/loaders/DynamicGltfLoader/GltfStructure.js +71 -2
- package/src/Viewer/loaders/GLTFBinaryExtension.ts +91 -0
- package/src/Viewer/loaders/GLTFCloudDynamicLoader.ts +13 -19
- package/src/Viewer/loaders/GLTFFileDynamicLoader.ts +145 -0
- package/src/Viewer/loaders/GLTFLoadingManager.ts +5 -4
- package/src/Viewer/loaders/RangesLoader.ts +105 -0
- package/src/Viewer/loaders/index.ts +24 -16
- package/src/Viewer/measurement/Snapper.ts +208 -0
- package/src/Viewer/measurement/UnitConverter.ts +47 -0
- package/src/Viewer/measurement/UnitFormatter.ts +95 -0
- package/src/Viewer/models/IModelImpl.ts +17 -8
- package/src/Viewer/models/ModelImpl.ts +205 -16
- package/src/index-umd.ts +1 -1
- package/dist/plugins/components/AxesHelperComponent.js.map +0 -1
- package/dist/plugins/components/AxesHelperComponent.module.js.map +0 -1
- package/dist/plugins/components/ExtentsHelperComponent.js.map +0 -1
- package/dist/plugins/components/ExtentsHelperComponent.min.js +0 -24
- package/dist/plugins/components/ExtentsHelperComponent.module.js.map +0 -1
- package/dist/plugins/components/GridHelperComponent.js.map +0 -1
- package/dist/plugins/components/GridHelperComponent.module.js.map +0 -1
- package/dist/plugins/components/LightHelperComponent.js.map +0 -1
- package/dist/plugins/components/LightHelperComponent.module.js.map +0 -1
- package/dist/plugins/components/RoomEnvironmentComponent.js.map +0 -1
- package/dist/plugins/components/RoomEnvironmentComponent.module.js.map +0 -1
- package/dist/plugins/components/StatsPanelComponent.js.map +0 -1
- package/dist/plugins/components/StatsPanelComponent.min.js +0 -24
- package/dist/plugins/components/StatsPanelComponent.module.js.map +0 -1
- package/dist/plugins/loaders/GLTFCloudLoader.js.map +0 -1
- package/dist/plugins/loaders/GLTFCloudLoader.module.js.map +0 -1
- package/dist/plugins/loaders/IFCXLoader.js.map +0 -1
- package/dist/plugins/loaders/IFCXLoader.module.js.map +0 -1
- package/dist/plugins/loaders/PotreeLoader.js.map +0 -1
- package/dist/plugins/loaders/PotreeLoader.min.js +0 -24
- package/dist/plugins/loaders/PotreeLoader.module.js.map +0 -1
- /package/dist/{plugins → extensions}/components/GridHelperComponent.js +0 -0
- /package/dist/{plugins → extensions}/components/GridHelperComponent.min.js +0 -0
- /package/dist/{plugins → extensions}/components/GridHelperComponent.module.js +0 -0
- /package/dist/{plugins → extensions}/components/LightHelperComponent.js +0 -0
- /package/dist/{plugins → extensions}/components/LightHelperComponent.min.js +0 -0
- /package/dist/{plugins → extensions}/components/LightHelperComponent.module.js +0 -0
- /package/dist/{plugins → extensions}/components/RoomEnvironmentComponent.js +0 -0
- /package/dist/{plugins → extensions}/components/RoomEnvironmentComponent.min.js +0 -0
- /package/dist/{plugins → extensions}/components/RoomEnvironmentComponent.module.js +0 -0
- /package/{plugins → extensions}/components/GridHelperComponent.ts +0 -0
- /package/{plugins → extensions}/components/LightHelperComponent.ts +0 -0
- /package/{plugins → extensions}/components/RoomEnvironmentComponent.ts +0 -0
- /package/{plugins → extensions}/loaders/IFCX/IFCXLoader.ts +0 -0
- /package/{plugins → extensions}/loaders/IFCX/index.ts +0 -0
- /package/{plugins → extensions}/loaders/IFCX/render.js +0 -0
- /package/{plugins → extensions}/loaders/Potree/index.ts +0 -0
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
///////////////////////////////////////////////////////////////////////////////
|
|
23
23
|
|
|
24
24
|
import { Box3, Object3D } from "three";
|
|
25
|
+
import { IInfo, Info } from "@inweb/viewer-core";
|
|
25
26
|
|
|
26
27
|
import { ModelImpl } from "../../models/ModelImpl";
|
|
27
28
|
import { DynamicGltfLoader } from "./DynamicGltfLoader.js";
|
|
@@ -30,7 +31,30 @@ import { DynamicGltfLoader } from "./DynamicGltfLoader.js";
|
|
|
30
31
|
|
|
31
32
|
export class DynamicModelImpl extends ModelImpl {
|
|
32
33
|
public gltfLoader: DynamicGltfLoader;
|
|
33
|
-
|
|
34
|
+
|
|
35
|
+
override getInfo(): IInfo {
|
|
36
|
+
const stats = this.gltfLoader.getStats();
|
|
37
|
+
|
|
38
|
+
const info = new Info();
|
|
39
|
+
|
|
40
|
+
info.scene.objects = stats.scene.beforeOptimization.objects;
|
|
41
|
+
info.scene.triangles = stats.scene.beforeOptimization.triangles;
|
|
42
|
+
info.scene.lines = stats.scene.beforeOptimization.lines;
|
|
43
|
+
info.scene.edges = stats.scene.beforeOptimization.edges;
|
|
44
|
+
|
|
45
|
+
info.optimizedScene.objects = stats.scene.afterOptimization.objects;
|
|
46
|
+
info.optimizedScene.triangles = stats.scene.afterOptimization.triangles;
|
|
47
|
+
info.optimizedScene.lines = stats.scene.afterOptimization.lines;
|
|
48
|
+
info.optimizedScene.edges = stats.scene.afterOptimization.edges;
|
|
49
|
+
|
|
50
|
+
info.memory.geometries = stats.memory.geometries.count;
|
|
51
|
+
info.memory.geometryBytes = stats.memory.geometries.bytes;
|
|
52
|
+
info.memory.textures = stats.memory.textures.count;
|
|
53
|
+
info.memory.materials = stats.memory.materials.count;
|
|
54
|
+
info.memory.totalEstimatedGpuBytes = stats.memory.totalEstimatedGpuBytes;
|
|
55
|
+
|
|
56
|
+
return info;
|
|
57
|
+
}
|
|
34
58
|
|
|
35
59
|
override getExtents(target: Box3): Box3 {
|
|
36
60
|
return target.union(this.gltfLoader.getTotalGeometryExtent());
|
|
@@ -53,35 +77,46 @@ export class DynamicModelImpl extends ModelImpl {
|
|
|
53
77
|
}
|
|
54
78
|
|
|
55
79
|
override getObjectsByHandles(handles: string | string[]): Object3D[] {
|
|
56
|
-
const
|
|
80
|
+
const ownHandles = this.getOwnHandles(handles);
|
|
81
|
+
if (ownHandles.length === 0) return [];
|
|
82
|
+
|
|
83
|
+
const handlesSet = new Set(ownHandles);
|
|
84
|
+
|
|
57
85
|
const objects = [];
|
|
58
86
|
handlesSet.forEach((handle) => {
|
|
59
|
-
|
|
60
|
-
const handles = this.gltfLoader.handleToObjects.get(handle2) || [];
|
|
61
|
-
objects.push(...Array.from(handles));
|
|
87
|
+
objects.push(...this.gltfLoader.getObjectsByHandle(handle));
|
|
62
88
|
});
|
|
89
|
+
|
|
63
90
|
return objects;
|
|
64
91
|
}
|
|
65
92
|
|
|
66
93
|
override getHandlesByObjects(objects: Object3D | Object3D[]): string[] {
|
|
67
|
-
const
|
|
68
|
-
|
|
94
|
+
const ownObjects = this.getOwnObjects(objects);
|
|
95
|
+
if (ownObjects.length === 0) return [];
|
|
96
|
+
|
|
97
|
+
const handleSet = new Set<string>();
|
|
98
|
+
ownObjects.forEach((object) => {
|
|
99
|
+
const handle = object.userData.handle;
|
|
100
|
+
if (handle) handleSet.add(handle);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
return Array.from(handleSet);
|
|
69
104
|
}
|
|
70
105
|
|
|
71
106
|
override hideObjects(objects: Object3D | Object3D[]): this {
|
|
72
|
-
const handles =
|
|
107
|
+
const handles = this.getHandlesByObjects(objects);
|
|
73
108
|
this.gltfLoader.hideObjects(handles);
|
|
74
109
|
return this;
|
|
75
110
|
}
|
|
76
111
|
|
|
77
112
|
override isolateObjects(objects: Object3D | Object3D[]): this {
|
|
78
|
-
const handles =
|
|
113
|
+
const handles = this.getHandlesByObjects(objects);
|
|
79
114
|
this.gltfLoader.isolateObjects(new Set(handles));
|
|
80
115
|
return this;
|
|
81
116
|
}
|
|
82
117
|
|
|
83
118
|
override showObjects(objects: Object3D | Object3D[]): this {
|
|
84
|
-
const handles =
|
|
119
|
+
const handles = this.getHandlesByObjects(objects);
|
|
85
120
|
this.gltfLoader.showObjects(handles);
|
|
86
121
|
return this;
|
|
87
122
|
}
|
|
@@ -58,12 +58,17 @@ export class GltfStructure {
|
|
|
58
58
|
this.materials = new Map();
|
|
59
59
|
this.textureCache = new Map();
|
|
60
60
|
this.materialCache = new Map();
|
|
61
|
+
this.uri = "";
|
|
62
|
+
this._nextObjectId = 0;
|
|
63
|
+
this.loadingAborted = false;
|
|
64
|
+
this.criticalError = null;
|
|
61
65
|
}
|
|
62
66
|
|
|
63
67
|
async initialize(loader) {
|
|
64
68
|
this.json = await this.loadController.loadJson();
|
|
65
69
|
this.baseUrl = await this.loadController.baseUrl();
|
|
66
70
|
this.loader = loader;
|
|
71
|
+
this.uri = this.json.buffers[0].uri || "";
|
|
67
72
|
}
|
|
68
73
|
|
|
69
74
|
clear() {
|
|
@@ -82,6 +87,8 @@ export class GltfStructure {
|
|
|
82
87
|
|
|
83
88
|
this.activeChunkLoads = 0;
|
|
84
89
|
this.chunkQueue = [];
|
|
90
|
+
this.loadingAborted = false;
|
|
91
|
+
this.criticalError = null;
|
|
85
92
|
}
|
|
86
93
|
|
|
87
94
|
getJson() {
|
|
@@ -90,6 +97,10 @@ export class GltfStructure {
|
|
|
90
97
|
|
|
91
98
|
scheduleRequest(request) {
|
|
92
99
|
return new Promise((resolve, reject) => {
|
|
100
|
+
if (this.loadingAborted) {
|
|
101
|
+
reject(this.criticalError || new Error("Structure loading has been aborted due to critical error"));
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
93
104
|
this.pendingRequests.push({
|
|
94
105
|
...request,
|
|
95
106
|
_resolve: resolve,
|
|
@@ -98,6 +109,52 @@ export class GltfStructure {
|
|
|
98
109
|
});
|
|
99
110
|
}
|
|
100
111
|
|
|
112
|
+
isCriticalHttpError(error) {
|
|
113
|
+
if (!error) return false;
|
|
114
|
+
|
|
115
|
+
const status = error.status || error.statusCode || error.code;
|
|
116
|
+
|
|
117
|
+
if (typeof status === "number") {
|
|
118
|
+
return status >= 400 && status < 600;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (error.message) {
|
|
122
|
+
const match = error.message.match(/HTTP\s+(\d{3})/i);
|
|
123
|
+
if (match) {
|
|
124
|
+
const code = parseInt(match[1], 10);
|
|
125
|
+
return code >= 400 && code < 600;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
abortLoading(error) {
|
|
133
|
+
if (this.loadingAborted) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
this.loadingAborted = true;
|
|
138
|
+
this.criticalError = error;
|
|
139
|
+
|
|
140
|
+
const requests = [...this.pendingRequests];
|
|
141
|
+
this.pendingRequests = [];
|
|
142
|
+
|
|
143
|
+
for (const req of requests) {
|
|
144
|
+
if (req._reject) {
|
|
145
|
+
req._reject(error);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
console.error(
|
|
150
|
+
`❌ Critical error for structure "${this.id}". All further loading aborted.`,
|
|
151
|
+
`\n Error: ${error.message || error}`,
|
|
152
|
+
`\n Rejected ${requests.length} pending chunk requests.`
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
throw error;
|
|
156
|
+
}
|
|
157
|
+
|
|
101
158
|
async flushBufferRequests() {
|
|
102
159
|
if (!this.pendingRequests || this.pendingRequests.length === 0) return;
|
|
103
160
|
const requests = [...this.pendingRequests];
|
|
@@ -162,11 +219,18 @@ export class GltfStructure {
|
|
|
162
219
|
}
|
|
163
220
|
|
|
164
221
|
const promises = finalRanges.map(async (range, index) => {
|
|
222
|
+
if (this.loadingAborted) {
|
|
223
|
+
for (const req of range.requests) {
|
|
224
|
+
req._reject(this.criticalError || new Error("Structure loading aborted"));
|
|
225
|
+
}
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
|
|
165
229
|
await this.loader.waitForChunkSlot();
|
|
166
230
|
|
|
167
231
|
try {
|
|
168
232
|
const length = range.end - range.start;
|
|
169
|
-
const buffer = await this.loadController.loadBinaryData([{ offset: range.start, length }]);
|
|
233
|
+
const buffer = await this.loadController.loadBinaryData([{ offset: range.start, length }], this.uri);
|
|
170
234
|
|
|
171
235
|
for (const req of range.requests) {
|
|
172
236
|
const relOffset = req.offset - range.start;
|
|
@@ -180,7 +244,12 @@ export class GltfStructure {
|
|
|
180
244
|
for (const req of range.requests) {
|
|
181
245
|
req._reject(error);
|
|
182
246
|
}
|
|
183
|
-
|
|
247
|
+
|
|
248
|
+
if (this.isCriticalHttpError(error)) {
|
|
249
|
+
this.abortLoading(error);
|
|
250
|
+
} else {
|
|
251
|
+
console.warn(`Failed to load chunk ${index + 1}/${finalRanges.length} (${range.start}-${range.end}):`, error);
|
|
252
|
+
}
|
|
184
253
|
} finally {
|
|
185
254
|
this.loader.releaseChunkSlot();
|
|
186
255
|
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
// Copyright (C) 2002-2025, Open Design Alliance (the "Alliance").
|
|
3
|
+
// All rights reserved.
|
|
4
|
+
//
|
|
5
|
+
// This software and its documentation and related materials are owned by
|
|
6
|
+
// the Alliance. The software may only be incorporated into application
|
|
7
|
+
// programs owned by members of the Alliance, subject to a signed
|
|
8
|
+
// Membership Agreement and Supplemental Software License Agreement with the
|
|
9
|
+
// Alliance. The structure and organization of this software are the valuable
|
|
10
|
+
// trade secrets of the Alliance and its suppliers. The software is also
|
|
11
|
+
// protected by copyright law and international treaty provisions. Application
|
|
12
|
+
// programs incorporating this software must include the following statement
|
|
13
|
+
// with their copyright notices:
|
|
14
|
+
//
|
|
15
|
+
// This application incorporates Open Design Alliance software pursuant to a
|
|
16
|
+
// license agreement with Open Design Alliance.
|
|
17
|
+
// Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance.
|
|
18
|
+
// All rights reserved.
|
|
19
|
+
//
|
|
20
|
+
// By use of this software, its documentation or related materials, you
|
|
21
|
+
// acknowledge and accept the above terms.
|
|
22
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
23
|
+
|
|
24
|
+
// ===================== AI-CODE-FILE ======================
|
|
25
|
+
// Source: Claude Sonnet 4.5
|
|
26
|
+
// Date: 2025-28-10
|
|
27
|
+
// Reviewer: roman.mochalov@opendesign.com
|
|
28
|
+
// Issue: CLOUD-5933
|
|
29
|
+
// Notes: Originally AI-generated, modified manually
|
|
30
|
+
// =========================================================
|
|
31
|
+
|
|
32
|
+
const BINARY_EXTENSION_HEADER_MAGIC = "glTF";
|
|
33
|
+
const BINARY_EXTENSION_HEADER_LENGTH = 12;
|
|
34
|
+
const BINARY_EXTENSION_CHUNK_TYPES = { JSON: 0x4e4f534a, BIN: 0x004e4042 };
|
|
35
|
+
|
|
36
|
+
export class GLTFBinaryExtension {
|
|
37
|
+
public content: string;
|
|
38
|
+
public body: ArrayBuffer;
|
|
39
|
+
|
|
40
|
+
constructor(data: ArrayBuffer) {
|
|
41
|
+
const headerView = new DataView(data, 0, BINARY_EXTENSION_HEADER_LENGTH);
|
|
42
|
+
const textDecoder = new TextDecoder();
|
|
43
|
+
|
|
44
|
+
const magic = textDecoder.decode(new Uint8Array(data.slice(0, 4)));
|
|
45
|
+
|
|
46
|
+
if (magic !== BINARY_EXTENSION_HEADER_MAGIC) {
|
|
47
|
+
this.content = textDecoder.decode(data);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const header = {
|
|
52
|
+
magic,
|
|
53
|
+
version: headerView.getUint32(4, true),
|
|
54
|
+
length: headerView.getUint32(8, true),
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
if (header.magic !== BINARY_EXTENSION_HEADER_MAGIC) {
|
|
58
|
+
throw new Error("Unsupported glTF-Binary header.");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (header.version < 2.0) {
|
|
62
|
+
throw new Error("Legacy binary file detected.");
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const chunkContentsLength = header.length - BINARY_EXTENSION_HEADER_LENGTH;
|
|
66
|
+
const chunkView = new DataView(data, BINARY_EXTENSION_HEADER_LENGTH);
|
|
67
|
+
let chunkIndex = 0;
|
|
68
|
+
|
|
69
|
+
while (chunkIndex < chunkContentsLength) {
|
|
70
|
+
const chunkLength = chunkView.getUint32(chunkIndex, true);
|
|
71
|
+
chunkIndex += 4;
|
|
72
|
+
|
|
73
|
+
const chunkType = chunkView.getUint32(chunkIndex, true);
|
|
74
|
+
chunkIndex += 4;
|
|
75
|
+
|
|
76
|
+
if (chunkType === BINARY_EXTENSION_CHUNK_TYPES.JSON) {
|
|
77
|
+
const contentArray = new Uint8Array(data, BINARY_EXTENSION_HEADER_LENGTH + chunkIndex, chunkLength);
|
|
78
|
+
this.content = textDecoder.decode(contentArray);
|
|
79
|
+
} else if (chunkType === BINARY_EXTENSION_CHUNK_TYPES.BIN) {
|
|
80
|
+
const byteOffset = BINARY_EXTENSION_HEADER_LENGTH + chunkIndex;
|
|
81
|
+
this.body = data.slice(byteOffset, byteOffset + chunkLength);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
chunkIndex += chunkLength;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (typeof this.content === "undefined") {
|
|
88
|
+
throw new Error("JSON content not found.");
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -22,27 +22,28 @@
|
|
|
22
22
|
///////////////////////////////////////////////////////////////////////////////
|
|
23
23
|
|
|
24
24
|
import { Group } from "three";
|
|
25
|
-
import {
|
|
25
|
+
import { Loader, LoadParams } from "@inweb/viewer-core";
|
|
26
26
|
|
|
27
27
|
import { Viewer } from "../Viewer";
|
|
28
28
|
import { DynamicModelImpl } from "./DynamicGltfLoader/DynamicModelImpl";
|
|
29
29
|
import { DynamicGltfLoader } from "./DynamicGltfLoader/DynamicGltfLoader.js";
|
|
30
30
|
import { GltfStructure } from "./DynamicGltfLoader/GltfStructure.js";
|
|
31
31
|
|
|
32
|
-
export class GLTFCloudDynamicLoader
|
|
32
|
+
export class GLTFCloudDynamicLoader extends Loader {
|
|
33
33
|
public viewer: Viewer;
|
|
34
34
|
public gltfLoader: DynamicGltfLoader;
|
|
35
35
|
public requestId = 0;
|
|
36
36
|
|
|
37
37
|
constructor(viewer: Viewer) {
|
|
38
|
+
super();
|
|
38
39
|
this.viewer = viewer;
|
|
39
40
|
}
|
|
40
41
|
|
|
41
|
-
dispose() {
|
|
42
|
+
override dispose() {
|
|
42
43
|
if (this.gltfLoader) this.gltfLoader.clear();
|
|
43
44
|
}
|
|
44
45
|
|
|
45
|
-
isSupport(file: any): boolean {
|
|
46
|
+
override isSupport(file: any): boolean {
|
|
46
47
|
return (
|
|
47
48
|
typeof file === "object" &&
|
|
48
49
|
typeof file.database === "string" &&
|
|
@@ -52,7 +53,7 @@ export class GLTFCloudDynamicLoader implements ILoader {
|
|
|
52
53
|
);
|
|
53
54
|
}
|
|
54
55
|
|
|
55
|
-
async load(model: any, format?: string, params
|
|
56
|
+
override async load(model: any, format?: string, params: LoadParams = {}): Promise<this> {
|
|
56
57
|
const scene = new Group();
|
|
57
58
|
|
|
58
59
|
this.gltfLoader = new DynamicGltfLoader(this.viewer.camera, scene, this.viewer.renderer);
|
|
@@ -60,13 +61,11 @@ export class GLTFCloudDynamicLoader implements ILoader {
|
|
|
60
61
|
this.gltfLoader.setVisibleEdges(this.viewer.options.edgeModel);
|
|
61
62
|
// this.gltfLoader.setMaxConcurrentChunks(this.viewer.options.maxConcurrentChunks);
|
|
62
63
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
modelImpl.viewer = this.viewer;
|
|
67
|
-
modelImpl.gltfLoader = this.gltfLoader;
|
|
68
|
-
modelImpl.modelId = model.id;
|
|
64
|
+
const modelImpl = new DynamicModelImpl(scene);
|
|
65
|
+
modelImpl.id = model.file.id;
|
|
66
|
+
modelImpl.gltfLoader = this.gltfLoader;
|
|
69
67
|
|
|
68
|
+
this.gltfLoader.addEventListener("databasechunk", (data) => {
|
|
70
69
|
this.viewer.scene.add(scene);
|
|
71
70
|
this.viewer.models.push(modelImpl);
|
|
72
71
|
|
|
@@ -77,11 +76,6 @@ export class GLTFCloudDynamicLoader implements ILoader {
|
|
|
77
76
|
this.viewer.emitEvent({ type: "databasechunk", data: scene, file: model.file, model });
|
|
78
77
|
});
|
|
79
78
|
|
|
80
|
-
this.gltfLoader.addEventListener("geometryprogress", (data) => {
|
|
81
|
-
const progress = data.loaded / data.total;
|
|
82
|
-
this.viewer.emitEvent({ type: "geometryprogress", data: progress, file: model.file, model });
|
|
83
|
-
});
|
|
84
|
-
|
|
85
79
|
this.gltfLoader.addEventListener("geometryerror", (data) => {
|
|
86
80
|
this.viewer.emitEvent({ type: "geometryerror", data, file: model.file, model });
|
|
87
81
|
});
|
|
@@ -93,7 +87,7 @@ export class GLTFCloudDynamicLoader implements ILoader {
|
|
|
93
87
|
const loadController = {
|
|
94
88
|
loadJson: async () => {
|
|
95
89
|
const progress = (progress: number) => {
|
|
96
|
-
this.viewer.emitEvent({ type: "geometryprogress", data: progress, file: model });
|
|
90
|
+
this.viewer.emitEvent({ type: "geometryprogress", data: progress, file: model.file, model });
|
|
97
91
|
};
|
|
98
92
|
|
|
99
93
|
const arrayBuffer = await model.downloadResource(
|
|
@@ -127,7 +121,7 @@ export class GLTFCloudDynamicLoader implements ILoader {
|
|
|
127
121
|
baseUrl: () => Promise.resolve(`${model.httpClient.serverUrl}${model.path}/`),
|
|
128
122
|
};
|
|
129
123
|
|
|
130
|
-
const structure = new GltfStructure(
|
|
124
|
+
const structure = new GltfStructure(modelImpl.id, loadController);
|
|
131
125
|
|
|
132
126
|
await this.gltfLoader.loadStructure(structure);
|
|
133
127
|
await this.gltfLoader.loadNodes();
|
|
@@ -135,7 +129,7 @@ export class GLTFCloudDynamicLoader implements ILoader {
|
|
|
135
129
|
return this;
|
|
136
130
|
}
|
|
137
131
|
|
|
138
|
-
cancel() {
|
|
132
|
+
override cancel() {
|
|
139
133
|
if (this.gltfLoader) this.gltfLoader.abortLoading();
|
|
140
134
|
}
|
|
141
135
|
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
// Copyright (C) 2002-2025, Open Design Alliance (the "Alliance").
|
|
3
|
+
// All rights reserved.
|
|
4
|
+
//
|
|
5
|
+
// This software and its documentation and related materials are owned by
|
|
6
|
+
// the Alliance. The software may only be incorporated into application
|
|
7
|
+
// programs owned by members of the Alliance, subject to a signed
|
|
8
|
+
// Membership Agreement and Supplemental Software License Agreement with the
|
|
9
|
+
// Alliance. The structure and organization of this software are the valuable
|
|
10
|
+
// trade secrets of the Alliance and its suppliers. The software is also
|
|
11
|
+
// protected by copyright law and international treaty provisions. Application
|
|
12
|
+
// programs incorporating this software must include the following statement
|
|
13
|
+
// with their copyright notices:
|
|
14
|
+
//
|
|
15
|
+
// This application incorporates Open Design Alliance software pursuant to a
|
|
16
|
+
// license agreement with Open Design Alliance.
|
|
17
|
+
// Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance.
|
|
18
|
+
// All rights reserved.
|
|
19
|
+
//
|
|
20
|
+
// By use of this software, its documentation or related materials, you
|
|
21
|
+
// acknowledge and accept the above terms.
|
|
22
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
23
|
+
|
|
24
|
+
import { FileLoader, Group, LoaderUtils } from "three";
|
|
25
|
+
import { Loader } from "@inweb/viewer-core";
|
|
26
|
+
|
|
27
|
+
import { Viewer } from "../Viewer";
|
|
28
|
+
import { DynamicModelImpl } from "./DynamicGltfLoader/DynamicModelImpl";
|
|
29
|
+
import { DynamicGltfLoader } from "./DynamicGltfLoader/DynamicGltfLoader.js";
|
|
30
|
+
import { GltfStructure } from "./DynamicGltfLoader/GltfStructure.js";
|
|
31
|
+
import { GLTFLoadingManager, GLTFLoadParams } from "./GLTFLoadingManager";
|
|
32
|
+
import { GLTFBinaryExtension } from "./GLTFBinaryExtension";
|
|
33
|
+
import { RangesLoader } from "./RangesLoader";
|
|
34
|
+
|
|
35
|
+
export class GLTFFileDynamicLoader extends Loader {
|
|
36
|
+
public viewer: Viewer;
|
|
37
|
+
private gltfLoader: DynamicGltfLoader;
|
|
38
|
+
private manager: GLTFLoadingManager;
|
|
39
|
+
private gltf: any;
|
|
40
|
+
private bin: ArrayBuffer;
|
|
41
|
+
|
|
42
|
+
constructor(viewer: Viewer) {
|
|
43
|
+
super();
|
|
44
|
+
this.viewer = viewer;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
override dispose() {
|
|
48
|
+
if (this.gltfLoader) this.gltfLoader.clear();
|
|
49
|
+
if (this.manager) this.manager.dispose();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
override isSupport(file: any, format?: string): boolean {
|
|
53
|
+
return (
|
|
54
|
+
(typeof file === "string" || file instanceof globalThis.File || file instanceof ArrayBuffer) &&
|
|
55
|
+
/(gltf|glb)$/i.test(format)
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
override async load(file: any, format?: string, params?: GLTFLoadParams): Promise<this> {
|
|
60
|
+
this.manager = new GLTFLoadingManager(file, params);
|
|
61
|
+
|
|
62
|
+
const scene = new Group();
|
|
63
|
+
|
|
64
|
+
this.gltfLoader = new DynamicGltfLoader(this.viewer.camera, scene, this.viewer.renderer);
|
|
65
|
+
this.gltfLoader.memoryLimit = this.viewer.options.memoryLimit;
|
|
66
|
+
this.gltfLoader.visibleEdges = this.viewer.options.edgeModel;
|
|
67
|
+
|
|
68
|
+
const modelImpl = new DynamicModelImpl(scene);
|
|
69
|
+
modelImpl.id = params.modelId || this.extractFileName(file);
|
|
70
|
+
modelImpl.gltfLoader = this.gltfLoader;
|
|
71
|
+
|
|
72
|
+
this.gltfLoader.addEventListener("databasechunk", () => {
|
|
73
|
+
this.viewer.scene.add(scene);
|
|
74
|
+
this.viewer.models.push(modelImpl);
|
|
75
|
+
|
|
76
|
+
this.viewer.syncOptions();
|
|
77
|
+
this.viewer.syncOverlay();
|
|
78
|
+
this.viewer.update();
|
|
79
|
+
|
|
80
|
+
this.viewer.emitEvent({ type: "databasechunk", data: scene, file });
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
this.gltfLoader.addEventListener("geometryerror", (data) => {
|
|
84
|
+
this.viewer.emitEvent({ type: "geometryerror", data, file });
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
this.gltfLoader.addEventListener("update", (data) => {
|
|
88
|
+
this.viewer.update();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const loadController = {
|
|
92
|
+
loadJson: async () => {
|
|
93
|
+
const loader = new FileLoader(this.manager);
|
|
94
|
+
loader.setPath(this.manager.path);
|
|
95
|
+
loader.setRequestHeader((params.requestHeader as any) || {});
|
|
96
|
+
loader.setWithCredentials(params.withCredentials || loader.withCredentials);
|
|
97
|
+
loader.setResponseType("arraybuffer");
|
|
98
|
+
|
|
99
|
+
const progress = (event: ProgressEvent) => {
|
|
100
|
+
const { lengthComputable, loaded, total } = event;
|
|
101
|
+
const progress = lengthComputable ? loaded / total : 1;
|
|
102
|
+
this.viewer.emitEvent({ type: "geometryprogress", data: progress, file });
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const data = await loader.loadAsync(this.manager.fileURL, progress);
|
|
106
|
+
|
|
107
|
+
const extension = new GLTFBinaryExtension(data as ArrayBuffer);
|
|
108
|
+
this.gltf = JSON.parse(extension.content);
|
|
109
|
+
this.bin = extension.body;
|
|
110
|
+
|
|
111
|
+
return this.gltf;
|
|
112
|
+
},
|
|
113
|
+
|
|
114
|
+
loadBinaryData: (ranges, uri = "") => {
|
|
115
|
+
const loader = new RangesLoader();
|
|
116
|
+
loader.setRequestHeader((params.requestHeader as any) || {});
|
|
117
|
+
loader.setWithCredentials(params.withCredentials || false);
|
|
118
|
+
loader.setAbortSignal(this.gltfLoader.abortController.signal);
|
|
119
|
+
|
|
120
|
+
if (this.bin) return loader.extractRanges(this.bin, ranges);
|
|
121
|
+
|
|
122
|
+
const path = this.manager.path || this.manager.resourcePath;
|
|
123
|
+
const url = LoaderUtils.resolveURL(uri, path);
|
|
124
|
+
|
|
125
|
+
return loader.load(this.manager.resolveURL(url), ranges);
|
|
126
|
+
},
|
|
127
|
+
|
|
128
|
+
baseUrl: () => {
|
|
129
|
+
const path = this.manager.path || this.manager.resourcePath;
|
|
130
|
+
return Promise.resolve(path);
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const structure = new GltfStructure(modelImpl.id, loadController);
|
|
135
|
+
|
|
136
|
+
await this.gltfLoader.loadStructure(structure);
|
|
137
|
+
await this.gltfLoader.loadNodes();
|
|
138
|
+
|
|
139
|
+
return this;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
override cancel() {
|
|
143
|
+
if (this.gltfLoader) this.gltfLoader.abortLoading();
|
|
144
|
+
}
|
|
145
|
+
}
|
|
@@ -21,16 +21,17 @@
|
|
|
21
21
|
// acknowledge and accept the above terms.
|
|
22
22
|
///////////////////////////////////////////////////////////////////////////////
|
|
23
23
|
|
|
24
|
+
import { LoadParams } from "@inweb/viewer-core";
|
|
24
25
|
import { LoadingManager, LoaderUtils } from "three";
|
|
25
26
|
|
|
26
27
|
export type GLTFFileSource = string | globalThis.File | ArrayBuffer;
|
|
27
28
|
|
|
28
|
-
export type GLTFLoadParams = {
|
|
29
|
+
export type GLTFLoadParams = LoadParams & {
|
|
30
|
+
requestHeader?: HeadersInit;
|
|
31
|
+
withCredentials?: boolean;
|
|
29
32
|
path?: string;
|
|
30
33
|
externalFiles?: Map<string, GLTFFileSource>;
|
|
31
34
|
crossOrigin?: string;
|
|
32
|
-
requestHeader?: HeadersInit;
|
|
33
|
-
withCredentials?: boolean;
|
|
34
35
|
};
|
|
35
36
|
|
|
36
37
|
export class GLTFLoadingManager extends LoadingManager {
|
|
@@ -72,6 +73,6 @@ export class GLTFLoadingManager extends LoadingManager {
|
|
|
72
73
|
}
|
|
73
74
|
|
|
74
75
|
dispose() {
|
|
75
|
-
this.dataURLs.forEach(URL.revokeObjectURL);
|
|
76
|
+
this.dataURLs.forEach((dataURL) => URL.revokeObjectURL(dataURL));
|
|
76
77
|
}
|
|
77
78
|
}
|