@itwin/frontend-tiles 4.1.0-dev.7 → 4.1.0-dev.71
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/CHANGELOG.md +80 -1
- package/lib/cjs/BatchedTile.d.ts +1 -1
- package/lib/cjs/BatchedTile.d.ts.map +1 -1
- package/lib/cjs/BatchedTile.js +12 -32
- package/lib/cjs/BatchedTile.js.map +1 -1
- package/lib/cjs/BatchedTileTree.d.ts +3 -1
- package/lib/cjs/BatchedTileTree.d.ts.map +1 -1
- package/lib/cjs/BatchedTileTree.js +13 -0
- package/lib/cjs/BatchedTileTree.js.map +1 -1
- package/lib/cjs/BatchedTileTreeReference.js.map +1 -1
- package/lib/cjs/BatchedTilesetReader.js.map +1 -1
- package/lib/cjs/FrontendTiles.d.ts +83 -5
- package/lib/cjs/FrontendTiles.d.ts.map +1 -1
- package/lib/cjs/FrontendTiles.js +85 -3
- package/lib/cjs/FrontendTiles.js.map +1 -1
- package/lib/esm/BatchedTile.d.ts +1 -1
- package/lib/esm/BatchedTile.d.ts.map +1 -1
- package/lib/esm/BatchedTile.js +13 -33
- package/lib/esm/BatchedTile.js.map +1 -1
- package/lib/esm/BatchedTileTree.d.ts +3 -1
- package/lib/esm/BatchedTileTree.d.ts.map +1 -1
- package/lib/esm/BatchedTileTree.js +15 -2
- package/lib/esm/BatchedTileTree.js.map +1 -1
- package/lib/esm/BatchedTileTreeReference.js.map +1 -1
- package/lib/esm/BatchedTilesetReader.js.map +1 -1
- package/lib/esm/FrontendTiles.d.ts +83 -5
- package/lib/esm/FrontendTiles.d.ts.map +1 -1
- package/lib/esm/FrontendTiles.js +83 -3
- package/lib/esm/FrontendTiles.js.map +1 -1
- package/package.json +30 -21
- package/.rush/temp/operation/build/all.log +0 -3
- package/.rush/temp/operation/build/state.json +0 -3
- package/.rush/temp/package-deps_build.json +0 -24
- package/.rush/temp/shrinkwrap-deps.json +0 -266
- package/CHANGELOG.json +0 -53
- package/config/rush-project.json +0 -6
- package/frontend-tiles.build.error.log +0 -1
- package/frontend-tiles.build.log +0 -2
- package/lib/cjs/tsconfig.tsbuildinfo +0 -1
- package/lib/esm/tsconfig.tsbuildinfo +0 -1
- package/src/BatchedModels.ts +0 -58
- package/src/BatchedSpatialTileTreeRefs.ts +0 -226
- package/src/BatchedTile.ts +0 -206
- package/src/BatchedTileContentReader.ts +0 -96
- package/src/BatchedTileTree.ts +0 -74
- package/src/BatchedTileTreeReference.ts +0 -113
- package/src/BatchedTileTreeSupplier.ts +0 -52
- package/src/BatchedTilesetReader.ts +0 -113
- package/src/FrontendTiles.ts +0 -52
- package/src/LoggerCategory.ts +0 -8
- package/src/frontend-tiles.ts +0 -6
- package/tsconfig.json +0 -6
package/src/BatchedModels.ts
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
/*---------------------------------------------------------------------------------------------
|
|
2
|
-
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
|
|
3
|
-
* See LICENSE.md in the project root for license terms and full copyright notice.
|
|
4
|
-
*--------------------------------------------------------------------------------------------*/
|
|
5
|
-
|
|
6
|
-
import { Id64, Id64String } from "@itwin/core-bentley";
|
|
7
|
-
import { Range3d } from "@itwin/core-geometry";
|
|
8
|
-
import { ModelExtentsProps } from "@itwin/core-common";
|
|
9
|
-
import { IModelConnection, SpatialViewState } from "@itwin/core-frontend";
|
|
10
|
-
|
|
11
|
-
export class BatchedModels {
|
|
12
|
-
private readonly _iModel: IModelConnection;
|
|
13
|
-
private _viewedModels!: Set<Id64String>;
|
|
14
|
-
private readonly _viewedModelIdPairs = new Id64.Uint32Set();
|
|
15
|
-
private readonly _modelRanges = new Map<Id64String, Range3d>();
|
|
16
|
-
private _modelRangePromise?: Promise<void>;
|
|
17
|
-
|
|
18
|
-
public constructor(view: SpatialViewState) {
|
|
19
|
-
this._iModel = view.iModel;
|
|
20
|
-
this.setViewedModels(view.modelSelector.models);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
public setViewedModels(models: Set<Id64String>): void {
|
|
24
|
-
this._viewedModels = models;
|
|
25
|
-
this._viewedModelIdPairs.clear();
|
|
26
|
-
this._viewedModelIdPairs.addIds(models);
|
|
27
|
-
|
|
28
|
-
this._modelRangePromise = undefined;
|
|
29
|
-
const modelIds = Array.from(models).filter((modelId) => !this._modelRanges.has(modelId));
|
|
30
|
-
if (modelIds.length === 0)
|
|
31
|
-
return;
|
|
32
|
-
|
|
33
|
-
const modelRangePromise = this._modelRangePromise = this._iModel.models.queryExtents(modelIds).then((extents: ModelExtentsProps[]) => {
|
|
34
|
-
if (modelRangePromise !== this._modelRangePromise)
|
|
35
|
-
return;
|
|
36
|
-
|
|
37
|
-
this._modelRangePromise = undefined;
|
|
38
|
-
for (const extent of extents)
|
|
39
|
-
this._modelRanges.set(extent.id, Range3d.fromJSON(extent.extents));
|
|
40
|
-
}).catch(() => { });
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
public views(modelId: Id64String): boolean {
|
|
44
|
-
return this._viewedModels.has(modelId);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
public isViewed(modelIdLo: number, modelIdHi: number): boolean {
|
|
48
|
-
return this._viewedModelIdPairs.has(modelIdLo, modelIdHi);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
public unionRange(range: Range3d): void {
|
|
52
|
-
for (const id of this._viewedModels) {
|
|
53
|
-
const extent = this._modelRanges.get(id);
|
|
54
|
-
if (extent)
|
|
55
|
-
range.extendRange(extent);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
/*---------------------------------------------------------------------------------------------
|
|
2
|
-
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
|
|
3
|
-
* See LICENSE.md in the project root for license terms and full copyright notice.
|
|
4
|
-
*--------------------------------------------------------------------------------------------*/
|
|
5
|
-
|
|
6
|
-
import { assert } from "@itwin/core-bentley";
|
|
7
|
-
import { RenderSchedule } from "@itwin/core-common";
|
|
8
|
-
import {
|
|
9
|
-
AttachToViewportArgs, IModelConnection, SpatialTileTreeReferences, SpatialViewState, TileTreeLoadStatus, TileTreeOwner, TileTreeReference,
|
|
10
|
-
} from "@itwin/core-frontend";
|
|
11
|
-
import { AnimatedBatchedTileTreeReference, PrimaryBatchedTileTreeReference } from "./BatchedTileTreeReference";
|
|
12
|
-
import { getBatchedTileTreeOwner } from "./BatchedTileTreeSupplier";
|
|
13
|
-
import { BatchedModels } from "./BatchedModels";
|
|
14
|
-
import { ComputeSpatialTilesetBaseUrl, createFallbackSpatialTileTreeReferences } from "./FrontendTiles";
|
|
15
|
-
|
|
16
|
-
// Obtains tiles pre-published by mesh export service.
|
|
17
|
-
class BatchedSpatialTileTreeReferences implements SpatialTileTreeReferences {
|
|
18
|
-
private readonly _view: SpatialViewState;
|
|
19
|
-
private readonly _models: BatchedModels;
|
|
20
|
-
private _currentScript?: RenderSchedule.Script;
|
|
21
|
-
private _primaryRef!: PrimaryBatchedTileTreeReference;
|
|
22
|
-
private readonly _animatedRefs: AnimatedBatchedTileTreeReference[] = [];
|
|
23
|
-
private _onModelSelectorChanged?: () => void;
|
|
24
|
-
|
|
25
|
-
public constructor(baseUrl: URL, view: SpatialViewState) {
|
|
26
|
-
this._view = view;
|
|
27
|
-
this._models = new BatchedModels(view);
|
|
28
|
-
|
|
29
|
-
const script = view.displayStyle.scheduleScript;
|
|
30
|
-
this._currentScript = script?.requiresBatching ? script : undefined;
|
|
31
|
-
|
|
32
|
-
this.load(baseUrl, view.iModel);
|
|
33
|
-
|
|
34
|
-
assert(undefined !== this._primaryRef);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
private load(baseUrl: URL, iModel: IModelConnection): void {
|
|
38
|
-
const treeOwner = getBatchedTileTreeOwner(iModel, { baseUrl, script: this._currentScript });
|
|
39
|
-
this._primaryRef = new PrimaryBatchedTileTreeReference(treeOwner, this._models);
|
|
40
|
-
|
|
41
|
-
this.populateAnimatedReferences(treeOwner);
|
|
42
|
-
|
|
43
|
-
const onScriptChanged = (newScript: RenderSchedule.Script | undefined) => {
|
|
44
|
-
if (!newScript?.requiresBatching)
|
|
45
|
-
newScript = undefined;
|
|
46
|
-
|
|
47
|
-
const currentScript = this._currentScript;
|
|
48
|
-
this._currentScript = newScript;
|
|
49
|
-
|
|
50
|
-
if (newScript !== currentScript)
|
|
51
|
-
if (!newScript || !currentScript || !newScript.equals(currentScript))
|
|
52
|
-
this.load(baseUrl, iModel);
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
let removeScriptChangedListener = this._view.displayStyle.onScheduleScriptChanged.addListener((newScript) => onScriptChanged(newScript));
|
|
56
|
-
this._view.onDisplayStyleChanged.addListener((newStyle) => {
|
|
57
|
-
removeScriptChangedListener();
|
|
58
|
-
onScriptChanged(newStyle.scheduleScript);
|
|
59
|
-
removeScriptChangedListener = this._view.displayStyle.onScheduleScriptChanged.addListener((newScript) => onScriptChanged(newScript));
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
public *[Symbol.iterator](): Iterator<TileTreeReference> {
|
|
64
|
-
yield this._primaryRef;
|
|
65
|
-
|
|
66
|
-
for (const animatedRef of this._animatedRefs)
|
|
67
|
-
yield animatedRef;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
private populateAnimatedReferences(treeOwner: TileTreeOwner): void {
|
|
71
|
-
this._animatedRefs.length = 0;
|
|
72
|
-
const script = this._currentScript;
|
|
73
|
-
if (!script)
|
|
74
|
-
return;
|
|
75
|
-
|
|
76
|
-
const getCurrentTimePoint = () => this._view.displayStyle.settings.timePoint ?? script.duration.low;
|
|
77
|
-
for (const timeline of script.modelTimelines) {
|
|
78
|
-
const nodeIds = timeline.transformBatchIds;
|
|
79
|
-
for (const nodeId of nodeIds) {
|
|
80
|
-
this._animatedRefs.push(new AnimatedBatchedTileTreeReference(treeOwner, {
|
|
81
|
-
timeline,
|
|
82
|
-
nodeId,
|
|
83
|
-
getCurrentTimePoint,
|
|
84
|
-
}));
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
public update(): void {
|
|
90
|
-
this._models.setViewedModels(this._view.modelSelector.models);
|
|
91
|
-
if (this._onModelSelectorChanged)
|
|
92
|
-
this._onModelSelectorChanged();
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
public attachToViewport(args: AttachToViewportArgs): void {
|
|
96
|
-
this._onModelSelectorChanged = () => args.invalidateSymbologyOverrides();
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
public detachFromViewport(): void {
|
|
100
|
-
this._onModelSelectorChanged = undefined;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
public setDeactivated(): void {
|
|
104
|
-
// Used for debugging. Unimplemented here.
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// A placeholder used by [[ProxySpatialTileTreeReferences]] until asynchronous loading completes.
|
|
109
|
-
// It provides a TileTreeOwner that never loads a tile tree.
|
|
110
|
-
// This ensures that [ViewState.areAllTileTreesLoaded]($frontend) will not return `true` while we are loading.
|
|
111
|
-
class ProxyTileTreeReference extends TileTreeReference {
|
|
112
|
-
private readonly _treeOwner: TileTreeOwner;
|
|
113
|
-
|
|
114
|
-
public constructor(iModel: IModelConnection) {
|
|
115
|
-
super();
|
|
116
|
-
this._treeOwner = {
|
|
117
|
-
iModel,
|
|
118
|
-
tileTree: undefined,
|
|
119
|
-
loadStatus: TileTreeLoadStatus.NotLoaded,
|
|
120
|
-
load: () => undefined,
|
|
121
|
-
dispose: () => { },
|
|
122
|
-
loadTree: async () => Promise.resolve(undefined),
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
public override get treeOwner() {
|
|
127
|
-
return this._treeOwner;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
131
|
-
public override get _isLoadingComplete() {
|
|
132
|
-
return false;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// Serves as a placeholder while we asynchronously obtain the base URL for a pre-published tileset (or asynchronously determine
|
|
137
|
-
// that no such tileset exists).
|
|
138
|
-
class ProxySpatialTileTreeReferences implements SpatialTileTreeReferences {
|
|
139
|
-
// Once async loading completes, all methods will be forwarded to this implementation.
|
|
140
|
-
private _impl?: SpatialTileTreeReferences;
|
|
141
|
-
private readonly _proxyRef: ProxyTileTreeReference;
|
|
142
|
-
// Retained if attachToViewport is called while we are still loading; and reset if detachFromViewport is called while loading.
|
|
143
|
-
private _attachArgs?: AttachToViewportArgs;
|
|
144
|
-
|
|
145
|
-
public constructor(view: SpatialViewState, getBaseUrl: Promise<URL | undefined>) {
|
|
146
|
-
this._proxyRef = new ProxyTileTreeReference(view.iModel);
|
|
147
|
-
getBaseUrl.then((url: URL | undefined) => {
|
|
148
|
-
if (url) {
|
|
149
|
-
this.setTreeRefs(new BatchedSpatialTileTreeReferences(url, view));
|
|
150
|
-
} else {
|
|
151
|
-
this.setTreeRefs(createFallbackSpatialTileTreeReferences(view));
|
|
152
|
-
}
|
|
153
|
-
}).catch(() => {
|
|
154
|
-
this.setTreeRefs(createFallbackSpatialTileTreeReferences(view));
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
private setTreeRefs(refs: SpatialTileTreeReferences): void {
|
|
159
|
-
this._impl = refs;
|
|
160
|
-
if (this._attachArgs) {
|
|
161
|
-
this._impl.attachToViewport(this._attachArgs);
|
|
162
|
-
this._attachArgs.invalidateSymbologyOverrides();
|
|
163
|
-
this._attachArgs = undefined;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
public update(): void {
|
|
168
|
-
this._impl?.update();
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
public attachToViewport(args: AttachToViewportArgs): void {
|
|
172
|
-
if (this._impl)
|
|
173
|
-
this._impl.attachToViewport(args);
|
|
174
|
-
else
|
|
175
|
-
this._attachArgs = args;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
public detachFromViewport(): void {
|
|
179
|
-
if (this._impl)
|
|
180
|
-
this._impl.detachFromViewport();
|
|
181
|
-
else
|
|
182
|
-
this._attachArgs = undefined;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
public setDeactivated(): void { }
|
|
186
|
-
|
|
187
|
-
public *[Symbol.iterator](): Iterator<TileTreeReference> {
|
|
188
|
-
if (this._impl) {
|
|
189
|
-
for (const ref of this._impl)
|
|
190
|
-
yield ref;
|
|
191
|
-
} else {
|
|
192
|
-
yield this._proxyRef;
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
const iModelToBaseUrl = new Map<IModelConnection, URL | null | Promise<URL | undefined>>();
|
|
198
|
-
|
|
199
|
-
/** @internal */
|
|
200
|
-
export function createBatchedSpatialTileTreeReferences(view: SpatialViewState, computeBaseUrl: ComputeSpatialTilesetBaseUrl): SpatialTileTreeReferences {
|
|
201
|
-
const iModel = view.iModel;
|
|
202
|
-
let entry = iModelToBaseUrl.get(iModel);
|
|
203
|
-
if (undefined === entry) {
|
|
204
|
-
const promise = computeBaseUrl(iModel);
|
|
205
|
-
iModelToBaseUrl.set(iModel, entry = promise);
|
|
206
|
-
iModel.onClose.addOnce(() => iModelToBaseUrl.delete(iModel));
|
|
207
|
-
promise.then((url: URL | undefined) => {
|
|
208
|
-
if (iModelToBaseUrl.has(iModel))
|
|
209
|
-
iModelToBaseUrl.set(iModel, url ?? null);
|
|
210
|
-
}).catch(() => {
|
|
211
|
-
if (iModelToBaseUrl.has(iModel))
|
|
212
|
-
iModelToBaseUrl.set(iModel, null);
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
if (null === entry) {
|
|
217
|
-
// No tileset exists for this iModel - use default tile generation instead.
|
|
218
|
-
return createFallbackSpatialTileTreeReferences(view);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
if (entry instanceof Promise)
|
|
222
|
-
return new ProxySpatialTileTreeReferences(view, entry);
|
|
223
|
-
|
|
224
|
-
return new BatchedSpatialTileTreeReferences(entry, view);
|
|
225
|
-
}
|
|
226
|
-
|
package/src/BatchedTile.ts
DELETED
|
@@ -1,206 +0,0 @@
|
|
|
1
|
-
/*---------------------------------------------------------------------------------------------
|
|
2
|
-
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
|
|
3
|
-
* See LICENSE.md in the project root for license terms and full copyright notice.
|
|
4
|
-
*--------------------------------------------------------------------------------------------*/
|
|
5
|
-
|
|
6
|
-
import { assert, BeTimePoint, ByteStream, Logger } from "@itwin/core-bentley";
|
|
7
|
-
import { ColorDef, Tileset3dSchema } from "@itwin/core-common";
|
|
8
|
-
import {
|
|
9
|
-
GltfReaderProps, GraphicBuilder, ImdlReader, IModelApp, RealityTileLoader, RenderSystem, Tile, TileBoundingBoxes, TileContent,
|
|
10
|
-
TileDrawArgs, TileParams, TileRequest, TileRequestChannel, TileTreeLoadStatus, TileUser, TileVisibility, Viewport,
|
|
11
|
-
} from "@itwin/core-frontend";
|
|
12
|
-
import { loggerCategory } from "./LoggerCategory";
|
|
13
|
-
import { BatchedTileTree } from "./BatchedTileTree";
|
|
14
|
-
import { BatchedTileContentReader } from "./BatchedTileContentReader";
|
|
15
|
-
import { getMaxLevelsToSkip } from "./FrontendTiles";
|
|
16
|
-
|
|
17
|
-
/** @internal */
|
|
18
|
-
export interface BatchedTileParams extends TileParams {
|
|
19
|
-
childrenProps: Tileset3dSchema.Tile[] | undefined;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
let channel: TileRequestChannel | undefined;
|
|
23
|
-
|
|
24
|
-
/** @internal */
|
|
25
|
-
export class BatchedTile extends Tile {
|
|
26
|
-
private readonly _childrenProps?: Tileset3dSchema.Tile[];
|
|
27
|
-
private readonly _unskippable: boolean;
|
|
28
|
-
|
|
29
|
-
public get batchedTree(): BatchedTileTree {
|
|
30
|
-
return this.tree as BatchedTileTree;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
public constructor(params: BatchedTileParams, tree: BatchedTileTree) {
|
|
34
|
-
super(params, tree);
|
|
35
|
-
|
|
36
|
-
// The root tile never has content, so it doesn't count toward max levels to skip.
|
|
37
|
-
this._unskippable = 0 === (this.depth % getMaxLevelsToSkip());
|
|
38
|
-
|
|
39
|
-
if (params.childrenProps?.length)
|
|
40
|
-
this._childrenProps = params.childrenProps;
|
|
41
|
-
|
|
42
|
-
if (!this.contentId) {
|
|
43
|
-
this.setIsReady();
|
|
44
|
-
// mark "undisplayable"
|
|
45
|
-
this._maximumSize = 0;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
private get _batchedChildren(): BatchedTile[] | undefined {
|
|
50
|
-
return this.children as BatchedTile[] | undefined;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
public override computeLoadPriority(viewports: Iterable<Viewport>, _users: Iterable<TileUser>): number {
|
|
54
|
-
// Prioritize tiles closer to camera and center of attention (zoom point or screen center).
|
|
55
|
-
return RealityTileLoader.computeTileLocationPriority(this, viewports, this.tree.iModelTransform);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
public selectTiles(selected: Set<BatchedTile>, args: TileDrawArgs, closestDisplayableAncestor: BatchedTile | undefined): void {
|
|
59
|
-
const vis = this.computeVisibility(args);
|
|
60
|
-
if (TileVisibility.OutsideFrustum === vis)
|
|
61
|
-
return;
|
|
62
|
-
|
|
63
|
-
if (this._unskippable) {
|
|
64
|
-
// Prevent this tile's content from being unloaded due to memory pressure.
|
|
65
|
-
args.touchedTiles.add(this);
|
|
66
|
-
args.markUsed(this);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
closestDisplayableAncestor = this.hasGraphics ? this : closestDisplayableAncestor;
|
|
70
|
-
if (TileVisibility.TooCoarse === vis && (this.isReady || !this._unskippable)) {
|
|
71
|
-
args.markUsed(this);
|
|
72
|
-
args.markReady(this);
|
|
73
|
-
const childrenLoadStatus = this.loadChildren();
|
|
74
|
-
if (TileTreeLoadStatus.Loading === childrenLoadStatus)
|
|
75
|
-
args.markChildrenLoading();
|
|
76
|
-
|
|
77
|
-
const children = this._batchedChildren;
|
|
78
|
-
if (children) {
|
|
79
|
-
for (const child of children)
|
|
80
|
-
child.selectTiles(selected, args, closestDisplayableAncestor);
|
|
81
|
-
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// We want to display this tile. Request its content if not already loaded.
|
|
87
|
-
if ((TileVisibility.Visible === vis || this._unskippable) && !this.isReady)
|
|
88
|
-
args.insertMissing(this);
|
|
89
|
-
|
|
90
|
-
if (closestDisplayableAncestor)
|
|
91
|
-
selected.add(closestDisplayableAncestor);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
protected override _loadChildren(resolve: (children: Tile[] | undefined) => void, reject: (error: Error) => void): void {
|
|
95
|
-
let children: BatchedTile[] | undefined;
|
|
96
|
-
if (this._childrenProps) {
|
|
97
|
-
try {
|
|
98
|
-
for (const childProps of this._childrenProps) {
|
|
99
|
-
const params = this.batchedTree.reader.readTileParams(childProps, this);
|
|
100
|
-
const child = new BatchedTile(params, this.batchedTree);
|
|
101
|
-
children = children ?? [];
|
|
102
|
-
children.push(child);
|
|
103
|
-
}
|
|
104
|
-
} catch (err) {
|
|
105
|
-
Logger.logException(loggerCategory, err);
|
|
106
|
-
children = undefined;
|
|
107
|
-
if (err instanceof Error)
|
|
108
|
-
reject(err);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
resolve(children);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
public override get channel(): TileRequestChannel {
|
|
116
|
-
if (!channel) {
|
|
117
|
-
channel = new TileRequestChannel("itwinjs-batched-models", 20);
|
|
118
|
-
IModelApp.tileAdmin.channels.add(channel);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
return channel;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
public override async requestContent(_isCanceled: () => boolean): Promise<TileRequest.Response> {
|
|
125
|
-
const url = new URL(this.contentId, this.batchedTree.reader.baseUrl);
|
|
126
|
-
url.search = this.batchedTree.reader.baseUrl.search;
|
|
127
|
-
const response = await fetch(url.toString());
|
|
128
|
-
return response.arrayBuffer();
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
public override async readContent(data: TileRequest.ResponseData, system: RenderSystem, shouldAbort?: () => boolean): Promise<TileContent> {
|
|
132
|
-
assert(data instanceof Uint8Array);
|
|
133
|
-
if (!(data instanceof Uint8Array))
|
|
134
|
-
return { };
|
|
135
|
-
|
|
136
|
-
let reader: ImdlReader | BatchedTileContentReader | undefined = ImdlReader.create({
|
|
137
|
-
stream: ByteStream.fromUint8Array(data),
|
|
138
|
-
iModel: this.tree.iModel,
|
|
139
|
-
modelId: this.tree.modelId,
|
|
140
|
-
is3d: true,
|
|
141
|
-
isLeaf: this.isLeaf,
|
|
142
|
-
system,
|
|
143
|
-
isCanceled: shouldAbort,
|
|
144
|
-
timeline: this.batchedTree.scheduleScript,
|
|
145
|
-
options: {
|
|
146
|
-
tileId: this.contentId,
|
|
147
|
-
},
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
if (!reader) {
|
|
151
|
-
const gltfProps = GltfReaderProps.create(data, false, this.batchedTree.reader.baseUrl);
|
|
152
|
-
if (gltfProps) {
|
|
153
|
-
reader = new BatchedTileContentReader({
|
|
154
|
-
props: gltfProps,
|
|
155
|
-
iModel: this.tree.iModel,
|
|
156
|
-
system,
|
|
157
|
-
shouldAbort,
|
|
158
|
-
vertexTableRequired: true,
|
|
159
|
-
modelId: this.tree.modelId,
|
|
160
|
-
isLeaf: this.isLeaf,
|
|
161
|
-
range: this.range,
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
if (!reader)
|
|
167
|
-
return { };
|
|
168
|
-
|
|
169
|
-
return reader.read();
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
protected override addRangeGraphic(builder: GraphicBuilder, type: TileBoundingBoxes): void {
|
|
173
|
-
if (TileBoundingBoxes.ChildVolumes !== type) {
|
|
174
|
-
super.addRangeGraphic(builder, type);
|
|
175
|
-
return;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
builder.setSymbology(ColorDef.green, ColorDef.green, 2);
|
|
179
|
-
builder.addRangeBox(this.range);
|
|
180
|
-
|
|
181
|
-
this.loadChildren();
|
|
182
|
-
const children = this.children;
|
|
183
|
-
if (!children)
|
|
184
|
-
return;
|
|
185
|
-
|
|
186
|
-
builder.setSymbology(ColorDef.blue, ColorDef.blue.withTransparency(0xdf), 1);
|
|
187
|
-
for (const child of children) {
|
|
188
|
-
const range = child.range;
|
|
189
|
-
builder.addRangeBox(range);
|
|
190
|
-
builder.addRangeBox(range, true);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
public prune(olderThan: BeTimePoint): void {
|
|
195
|
-
const children = this._batchedChildren;
|
|
196
|
-
if (!children)
|
|
197
|
-
return;
|
|
198
|
-
|
|
199
|
-
if (this.usageMarker.isExpired(olderThan)) {
|
|
200
|
-
this.disposeChildren();
|
|
201
|
-
} else {
|
|
202
|
-
for (const child of children)
|
|
203
|
-
child.prune(olderThan);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
}
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
/*---------------------------------------------------------------------------------------------
|
|
2
|
-
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
|
|
3
|
-
* See LICENSE.md in the project root for license terms and full copyright notice.
|
|
4
|
-
*--------------------------------------------------------------------------------------------*/
|
|
5
|
-
|
|
6
|
-
import { assert, Id64, Id64String } from "@itwin/core-bentley";
|
|
7
|
-
import { Range3d } from "@itwin/core-geometry";
|
|
8
|
-
import { Feature, FeatureTable, TileReadStatus } from "@itwin/core-common";
|
|
9
|
-
import {
|
|
10
|
-
GltfDataType, GltfMeshPrimitive, GltfReader, GltfReaderArgs, GltfReaderResult,
|
|
11
|
-
} from "@itwin/core-frontend";
|
|
12
|
-
|
|
13
|
-
interface BatchedTileReaderArgs extends GltfReaderArgs {
|
|
14
|
-
modelId: Id64String;
|
|
15
|
-
isLeaf: boolean;
|
|
16
|
-
range: Range3d;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/** Read batched tiles in 3d Tiles 1.1 format. Currently, we prefer to produce tiles in iMdl format, so this goes unused for now.
|
|
20
|
-
* @internal
|
|
21
|
-
*/
|
|
22
|
-
export class BatchedTileContentReader extends GltfReader {
|
|
23
|
-
private readonly _modelId: Id64String;
|
|
24
|
-
private readonly _isLeaf: boolean;
|
|
25
|
-
private readonly _range: Range3d;
|
|
26
|
-
|
|
27
|
-
public constructor(args: BatchedTileReaderArgs) {
|
|
28
|
-
super(args);
|
|
29
|
-
this._modelId = args.modelId;
|
|
30
|
-
this._isLeaf = args.isLeaf;
|
|
31
|
-
this._range = args.range;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
public override async read(): Promise<GltfReaderResult> {
|
|
35
|
-
const featureTable = this.readFeatureTable();
|
|
36
|
-
await this.resolveResources();
|
|
37
|
-
if (this._isCanceled)
|
|
38
|
-
return { readStatus: TileReadStatus.Canceled, isLeaf: this._isLeaf };
|
|
39
|
-
|
|
40
|
-
return this.readGltfAndCreateGraphics(this._isLeaf, featureTable, this._range);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
private readFeatureTable(): FeatureTable | undefined {
|
|
44
|
-
// ###TODO we're just assuming there's one property table with one u64 property containing element Ids.
|
|
45
|
-
const tables = this._glTF.extensions?.EXT_structural_metadata?.propertyTables;
|
|
46
|
-
const table = tables ? tables[0] : undefined;
|
|
47
|
-
const elementIdProperty = table?.properties ? table.properties.ElementId : undefined;
|
|
48
|
-
if (!elementIdProperty)
|
|
49
|
-
return undefined;
|
|
50
|
-
|
|
51
|
-
const bufferView = this._bufferViews[elementIdProperty.values];
|
|
52
|
-
if (!bufferView || undefined === bufferView.buffer)
|
|
53
|
-
return undefined;
|
|
54
|
-
|
|
55
|
-
const bufferData = this._buffers[bufferView.buffer]?.resolvedBuffer;
|
|
56
|
-
if (!bufferData)
|
|
57
|
-
return undefined;
|
|
58
|
-
|
|
59
|
-
assert(undefined !== bufferView.byteLength); // required by spec; TypeScript interface is wrong.
|
|
60
|
-
const byteOffset = bufferView.byteOffset ?? 0;
|
|
61
|
-
const bytes = bufferData.subarray(byteOffset, byteOffset + bufferView.byteLength);
|
|
62
|
-
|
|
63
|
-
// 2 u32s per element Id.
|
|
64
|
-
const elementIds = new Uint32Array(bytes.buffer, bytes.byteOffset, bytes.byteLength / 4);
|
|
65
|
-
const numFeatures = elementIds.length / 2;
|
|
66
|
-
const featureTable = new FeatureTable(numFeatures, this._modelId);
|
|
67
|
-
for (let i = 0; i < numFeatures; i++) {
|
|
68
|
-
const elementId = Id64.fromUint32Pair(elementIds[i * 2], elementIds[i * 2 + 1]);
|
|
69
|
-
featureTable.insertWithIndex(new Feature(elementId), i);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
return featureTable;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
protected override readPrimitiveFeatures(primitive: GltfMeshPrimitive): Feature | number[] | undefined {
|
|
76
|
-
const ext = primitive.extensions?.EXT_mesh_features;
|
|
77
|
-
if (ext) {
|
|
78
|
-
// ###TODO making assumptions here.
|
|
79
|
-
const view = this.getBufferView(primitive.attributes, `_FEATURE_ID_${ext.featureIds[0].attribute}`);
|
|
80
|
-
// NB: 32-bit integers are not supported, but 8- and 16-bit integers will be converted to them.
|
|
81
|
-
// With more than 64k features in the tile we represent the Ids as floats instead.
|
|
82
|
-
const featureIds = view?.toBufferData(GltfDataType.Float) ?? view?.toBufferData(GltfDataType.UInt32);
|
|
83
|
-
if (view && featureIds) {
|
|
84
|
-
const indices = [];
|
|
85
|
-
for (let i = 0; i < featureIds.count; i++) {
|
|
86
|
-
const featureId = featureIds.buffer[i * view.stride];
|
|
87
|
-
indices.push(featureId);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return indices;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
return new Feature(this._modelId);
|
|
95
|
-
}
|
|
96
|
-
}
|
package/src/BatchedTileTree.ts
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
/*---------------------------------------------------------------------------------------------
|
|
2
|
-
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
|
|
3
|
-
* See LICENSE.md in the project root for license terms and full copyright notice.
|
|
4
|
-
*--------------------------------------------------------------------------------------------*/
|
|
5
|
-
|
|
6
|
-
import { BeTimePoint } from "@itwin/core-bentley";
|
|
7
|
-
import { RenderMode, RenderSchedule, ViewFlagOverrides } from "@itwin/core-common";
|
|
8
|
-
import {
|
|
9
|
-
Tile, TileDrawArgs, TileTree, TileTreeParams,
|
|
10
|
-
} from "@itwin/core-frontend";
|
|
11
|
-
import { BatchedTile, BatchedTileParams } from "./BatchedTile";
|
|
12
|
-
import { BatchedTilesetReader } from "./BatchedTilesetReader";
|
|
13
|
-
|
|
14
|
-
/** @internal */
|
|
15
|
-
export interface BatchedTileTreeParams extends TileTreeParams {
|
|
16
|
-
rootTile: BatchedTileParams;
|
|
17
|
-
reader: BatchedTilesetReader;
|
|
18
|
-
script?: RenderSchedule.Script;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const viewFlagOverrides: ViewFlagOverrides = {
|
|
22
|
-
renderMode: RenderMode.SmoothShade,
|
|
23
|
-
visibleEdges: false,
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
/** @internal */
|
|
27
|
-
export class BatchedTileTree extends TileTree {
|
|
28
|
-
private readonly _rootTile: BatchedTile;
|
|
29
|
-
public readonly reader: BatchedTilesetReader;
|
|
30
|
-
public readonly scheduleScript?: RenderSchedule.Script;
|
|
31
|
-
|
|
32
|
-
public constructor(params: BatchedTileTreeParams) {
|
|
33
|
-
super(params);
|
|
34
|
-
this._rootTile = new BatchedTile(params.rootTile, this);
|
|
35
|
-
this.reader = params.reader;
|
|
36
|
-
this.scheduleScript = params.script;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
public override get rootTile(): BatchedTile {
|
|
40
|
-
return this._rootTile;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
public override get is3d(): boolean {
|
|
44
|
-
return true;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
public override get maxDepth(): number | undefined {
|
|
48
|
-
return undefined;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
public override get viewFlagOverrides(): ViewFlagOverrides {
|
|
52
|
-
return viewFlagOverrides;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
56
|
-
public override _selectTiles(args: TileDrawArgs): Tile[] {
|
|
57
|
-
const selected = new Set<BatchedTile>();
|
|
58
|
-
this.rootTile.selectTiles(selected, args, undefined);
|
|
59
|
-
return Array.from(selected);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
public override draw(args: TileDrawArgs): void {
|
|
63
|
-
const tiles = this.selectTiles(args);
|
|
64
|
-
for (const tile of tiles)
|
|
65
|
-
tile.drawGraphics(args);
|
|
66
|
-
|
|
67
|
-
args.drawGraphics();
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
public override prune(): void {
|
|
71
|
-
const olderThan = BeTimePoint.now().minus(this.expirationTime);
|
|
72
|
-
this.rootTile.prune(olderThan);
|
|
73
|
-
}
|
|
74
|
-
}
|