bimatter-viewer-react 0.5.12 → 0.6.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 CHANGED
@@ -150,10 +150,16 @@ function App() {
150
150
  await loader.loadModel(["/models/model.bmt"]);
151
151
  await loader.loadModel(["/models/model.ifc"]);
152
152
  await loader.loadModel(["/models/model.ifc"], { useIfcSpace: true });
153
+ await loader.loadModel(["/models/model.bmt"], { materialMode: "performance" });
154
+ await loader.loadModel(["/models/model.bmt"], { useDoubleSideMaterial: true });
153
155
  await loader.loadModel(["/models/model.bmt", "/models/model.ifc"]);
154
156
  await loader.loadModel(files);
155
157
  ```
156
158
 
159
+ `materialMode: "performance"` uses a cheaper unlit material. Use `"quality"` or omit it for the default lit material.
160
+
161
+ `useDoubleSideMaterial` is disabled by default for better FPS. Enable it only when the model needs back faces to be visible.
162
+
157
163
  Use `useWorker` to parse BMT and IFC models outside the main thread:
158
164
 
159
165
  ```ts
@@ -531,6 +537,22 @@ if (viewer && firstLevel) {
531
537
  }
532
538
  ```
533
539
 
540
+ ## Performance Mode
541
+
542
+ Use `performanceMode` for heavy models or weaker GPUs:
543
+
544
+ ```tsx
545
+ <Viewer modelUrls={["/models/model.bmt"]} performanceMode />
546
+ ```
547
+
548
+ It caps canvas DPR at `1`, disables antialiasing, asks the browser for a high-performance GPU, and uses `materialMode="performance"` unless another material mode is passed.
549
+
550
+ You can also switch only the model material:
551
+
552
+ ```tsx
553
+ <Viewer modelUrls={["/models/model.bmt"]} materialMode="performance" />
554
+ ```
555
+
534
556
  ## Stats And Profiling
535
557
 
536
558
  Enable FPS stats and console timing logs:
@@ -191328,60 +191328,61 @@ var h_ = class {
191328
191328
  constructor(e) {
191329
191329
  this.parser = e;
191330
191330
  }
191331
- async serializeAllProperties(e, t) {
191332
- return await this.getPropertiesAsBlobs(e, t);
191333
- }
191334
- async getPropertiesAsBlobs(e, t) {
191335
- let n = await this.getAllRelDefinesByProps(e), r = {}, i = this.parser.GetLineIDsWithType(e, yd).get(0);
191336
- if (i === void 0) return r;
191337
- let a = await this.getItemProperty(e, i) ?? {
191338
- id: i,
191331
+ async serializeAllProperties(e, t, n) {
191332
+ return await this.getPropertiesAsBlobs(e, t, n);
191333
+ }
191334
+ async getPropertiesAsBlobs(e, t, n) {
191335
+ let r = await this.getAllRelDefinesByProps(e), i = r.size, a = t.size, o = {}, s = this.parser.GetLineIDsWithType(e, yd).get(0);
191336
+ if (s === void 0) return o;
191337
+ let c = await this.getItemProperty(e, s) ?? {
191338
+ id: s,
191339
191339
  props: {},
191340
191340
  sets: []
191341
191341
  };
191342
- a.sets = [], r[i] = a;
191343
- for (let t of n) {
191344
- let n = await this.getItemProperty(e, t);
191345
- if (n) {
191346
- let t = p_(n.RelatingPropertyDefinition);
191342
+ c.sets = [], o[s] = c;
191343
+ let l = 0;
191344
+ for (let t of r) {
191345
+ let r = await this.getItemProperty(e, t);
191346
+ if (r) {
191347
+ let t = p_(r.RelatingPropertyDefinition);
191347
191348
  if (t === null) continue;
191348
- let i = await this.getItemProperty(e, t, !0), a = {
191349
+ let n = await this.getItemProperty(e, t, !0), i = {
191349
191350
  id: t,
191350
191351
  guid: "null",
191351
191352
  name: "null",
191352
191353
  props: [],
191353
191354
  isQuantities: !1
191354
191355
  };
191355
- if (i && (i.HasProperties || i.Quantities)) {
191356
- if (i.Quantities) for (let e of i.Quantities) this.formatItemProperties(e);
191357
- if (i.HasProperties) for (let e of i.HasProperties) this.formatItemProperties(e);
191358
- a = {
191356
+ if (n && (n.HasProperties || n.Quantities)) {
191357
+ if (n.Quantities) for (let e of n.Quantities) this.formatItemProperties(e);
191358
+ if (n.HasProperties) for (let e of n.HasProperties) this.formatItemProperties(e);
191359
+ i = {
191359
191360
  id: t,
191360
- guid: this.getStringValue(i.GlobalId) ?? "null",
191361
- name: this.getStringValue(i.Name) ?? "null",
191362
- props: i.HasProperties ? i.HasProperties : i.Quantities ? i.Quantities : [],
191363
- isQuantities: !!i.Quantities
191361
+ guid: this.getStringValue(n.GlobalId) ?? "null",
191362
+ name: this.getStringValue(n.Name) ?? "null",
191363
+ props: n.HasProperties ? n.HasProperties : n.Quantities ? n.Quantities : [],
191364
+ isQuantities: !!n.Quantities
191364
191365
  };
191365
191366
  }
191366
- let o = m_(n.RelatedObjects);
191367
- for (let t of o) if (r[t]) r[t].sets ??= [], r[t].sets.push(a);
191367
+ let a = m_(r.RelatedObjects);
191368
+ for (let t of a) if (o[t]) o[t].sets ??= [], o[t].sets.push(i);
191368
191369
  else {
191369
191370
  let n = await this.getItemProperty(e, t);
191370
191371
  if (n) {
191371
- let e = this.getStringValue(n.GlobalId), i = n.Name, o = n.ObjectType, s = n.LongName, c = this.getStringValue(n.type), l = {
191372
- name: i,
191373
- typeName: o,
191372
+ let e = this.getStringValue(n.GlobalId), r = n.Name, a = n.ObjectType, s = n.LongName, c = this.getStringValue(n.type), l = {
191373
+ name: r,
191374
+ typeName: a,
191374
191375
  longName: s,
191375
191376
  type: c,
191376
191377
  elevation: void 0
191377
191378
  };
191378
- r[t] = {
191379
+ o[t] = {
191379
191380
  id: t,
191380
191381
  guid: e,
191381
191382
  props: l,
191382
- sets: [a]
191383
+ sets: [i]
191383
191384
  }, c === "IfcBuildingStorey" && (l.elevation = n.Elevation);
191384
- } else r[t] = {
191385
+ } else o[t] = {
191385
191386
  id: t,
191386
191387
  guid: "null",
191387
191388
  props: {
@@ -191391,16 +191392,29 @@ var h_ = class {
191391
191392
  type: "null",
191392
191393
  elevation: void 0
191393
191394
  },
191394
- sets: [a]
191395
+ sets: [i]
191395
191396
  };
191396
191397
  }
191397
191398
  }
191399
+ l += 1, this.shouldEmitProgress(l, i) && n?.({
191400
+ loaded: l,
191401
+ phase: "propertySets",
191402
+ total: i
191403
+ });
191398
191404
  }
191399
- for (let n of t) {
191400
- if (r[n]) continue;
191401
- let t = await this.getItemProperty(e, n);
191402
- t ? r[n] = {
191403
- id: n,
191405
+ let u = 0;
191406
+ for (let r of t) {
191407
+ if (o[r]) {
191408
+ u += 1, this.shouldEmitProgress(u, a) && n?.({
191409
+ loaded: u,
191410
+ phase: "elements",
191411
+ total: a
191412
+ });
191413
+ continue;
191414
+ }
191415
+ let t = await this.getItemProperty(e, r);
191416
+ t ? o[r] = {
191417
+ id: r,
191404
191418
  guid: this.getStringValue(t.GlobalId),
191405
191419
  props: {
191406
191420
  name: t.Name,
@@ -191410,8 +191424,8 @@ var h_ = class {
191410
191424
  elevation: void 0
191411
191425
  },
191412
191426
  sets: []
191413
- } : r[n] = {
191414
- id: n,
191427
+ } : o[r] = {
191428
+ id: r,
191415
191429
  guid: "null",
191416
191430
  props: {
191417
191431
  name: "null",
@@ -191421,9 +191435,13 @@ var h_ = class {
191421
191435
  elevation: void 0
191422
191436
  },
191423
191437
  sets: []
191424
- };
191438
+ }, u += 1, this.shouldEmitProgress(u, a) && n?.({
191439
+ loaded: u,
191440
+ phase: "elements",
191441
+ total: a
191442
+ });
191425
191443
  }
191426
- return r;
191444
+ return o;
191427
191445
  }
191428
191446
  async getItemProperty(e, t, n = !1) {
191429
191447
  try {
@@ -191585,6 +191603,9 @@ var h_ = class {
191585
191603
  let i = m_(n[t.related]);
191586
191604
  e[r] == null ? e[r] = i : e[r] = e[r].concat(i);
191587
191605
  }
191606
+ shouldEmitProgress(e, t) {
191607
+ return t <= 0 || e <= 0 || e >= t ? !0 : e % Math.max(1, Math.floor(t / 100)) === 0;
191608
+ }
191588
191609
  };
191589
191610
  //#endregion
191590
191611
  //#region src/viewer/Loaders/IFCLoader/IfcGrid.ts
@@ -191820,7 +191841,7 @@ var __ = class {
191820
191841
  n && (d[t] = this.transformGridData(n, l));
191821
191842
  }
191822
191843
  r?.onPhase?.("properties");
191823
- let f = await this.propertySerializer.serializeAllProperties(a, o), p = await this.propertySerializer.getSpatialStructure(a, !1);
191844
+ let f = await this.propertySerializer.serializeAllProperties(a, o, r?.onPropertiesProgress), p = await this.propertySerializer.getSpatialStructure(a, !1);
191824
191845
  return c.coordinationMatrix ??= this.coordinationMatrixData, c.props = f, c.structure = p, c.grids = d, {
191825
191846
  structure: p,
191826
191847
  propsData: f,
@@ -11,6 +11,16 @@ export type BmtActiveViewFilterParams = {
11
11
  modelID: number;
12
12
  };
13
13
  export type BmtActiveViewFilter = (params: BmtActiveViewFilterParams) => boolean;
14
+ export type BmtConverterProgressPhase = "preparing" | "filtering" | "properties" | "geometry" | "metadata" | "writing" | "complete";
15
+ export type BmtConverterProgressEvent = {
16
+ loaded?: number;
17
+ message?: string;
18
+ modelID: number;
19
+ modelIndex: number;
20
+ phase: BmtConverterProgressPhase;
21
+ progress: number;
22
+ total?: number;
23
+ };
14
24
  export type BmtConverterOptions = {
15
25
  activeView?: boolean;
16
26
  activeViewRoot?: Object3D | Object3D[] | null;
@@ -20,6 +30,7 @@ export type BmtConverterOptions = {
20
30
  fileNames?: Record<string | number, string>;
21
31
  filterElement?: BmtActiveViewFilter;
22
32
  maxMeshBytes?: number;
33
+ onProgress?: (progress: BmtConverterProgressEvent) => void;
23
34
  useIfcColors?: boolean;
24
35
  useIfcElementAssembly?: boolean;
25
36
  useIfcSpace?: boolean;
@@ -89,6 +100,8 @@ export declare class BmtConverter {
89
100
  private deflateBytes;
90
101
  private encodeText;
91
102
  private encodePrettyJson;
103
+ private shouldEmitItemProgress;
104
+ private clampProgress;
92
105
  private isRecord;
93
106
  }
94
107
  export declare const bmtConverter: BmtConverter;
@@ -1,5 +1,6 @@
1
1
  import pako from "pako";
2
2
  import type { ModelGridsData } from "../utils/ModelGrids";
3
+ import type { ViewerMaterialMode } from "../types";
3
4
  export type BmtIndexArray = Uint16Array | Uint32Array;
4
5
  export interface BmtMaterialData {
5
6
  r: number;
@@ -51,12 +52,17 @@ export type BmtModelStructureNode = {
51
52
  };
52
53
  export type BmtModelStructure = BmtModelStructureNode | BmtModelStructureNode[] | Record<string, BmtModelStructureNode>;
53
54
  export type BmtModelGeometryData = Record<number, BmtGeomData>;
55
+ export type BmtModelRenderSettings = {
56
+ materialMode?: ViewerMaterialMode;
57
+ useDoubleSideMaterial?: boolean;
58
+ };
54
59
  export interface BmtModelData {
55
60
  coordinationMatrix?: string;
56
61
  data: BmtModelGeometryData;
57
62
  grids?: ModelGridsData;
58
63
  name?: string;
59
64
  props: BmtModelProps;
65
+ renderSettings?: BmtModelRenderSettings;
60
66
  structure: BmtModelStructure;
61
67
  }
62
68
  export type BmtGeometryChunkData = {
@@ -1,4 +1,4 @@
1
- import { type IfcElementsAssembly } from "./PropertySerializer";
1
+ import { type IfcElementsAssembly, type IfcPropertiesProgressData } from "./PropertySerializer";
2
2
  import { Matrix4 } from "three";
3
3
  import { IfcAPI, type LocateFileHandlerFn } from "web-ifc";
4
4
  import { type GridData } from "./IfcGrid";
@@ -30,11 +30,13 @@ export type IfcGeometryProgressData = {
30
30
  processed: number;
31
31
  total: number;
32
32
  };
33
+ export type IfcPropertyProgressData = IfcPropertiesProgressData;
33
34
  export type IfcParsePhase = "opening" | "opened" | "streaming" | "properties" | "metadata";
34
35
  export type IfcParseCallbacks = {
35
36
  onGeometryChunk?: (chunk: IfcGeometryChunkData) => void;
36
37
  onGeometryProgress?: (progress: IfcGeometryProgressData) => void;
37
38
  onPhase?: (phase: IfcParsePhase) => void;
39
+ onPropertiesProgress?: (progress: IfcPropertyProgressData) => void;
38
40
  streamGeometryChunks?: boolean;
39
41
  };
40
42
  export declare class IFCLoader {
@@ -30,12 +30,18 @@ export type IfcElementsAssembly = {
30
30
  dict: Record<number, number>;
31
31
  ids: number[];
32
32
  };
33
+ export type IfcPropertiesProgressData = {
34
+ loaded: number;
35
+ phase: "propertySets" | "elements";
36
+ total: number;
37
+ };
38
+ export type IfcPropertiesProgressCallback = (progress: IfcPropertiesProgressData) => void;
33
39
  export declare class PropertySerializer {
34
40
  private PropsNames;
35
41
  readonly parser: IfcAPI;
36
42
  constructor(parser: IfcAPI);
37
- serializeAllProperties(modelID: number, ids: Set<number>): Promise<BmtModelProps>;
38
- getPropertiesAsBlobs(modelID: number, ids: Set<number>): Promise<BmtModelProps>;
43
+ serializeAllProperties(modelID: number, ids: Set<number>, onProgress?: IfcPropertiesProgressCallback): Promise<BmtModelProps>;
44
+ getPropertiesAsBlobs(modelID: number, ids: Set<number>, onProgress?: IfcPropertiesProgressCallback): Promise<BmtModelProps>;
39
45
  getItemProperty(modelID: number, id: number, flatten?: boolean): Promise<IfcLineData | null>;
40
46
  getElementsAssembly(modelID: number): Promise<IfcElementsAssembly>;
41
47
  private formatItemProperties;
@@ -53,5 +59,6 @@ export declare class PropertySerializer {
53
59
  newNode(id: number, data: IfcLineData): BmtModelStructureNode;
54
60
  getSpatialTreeChunks(modelID: number): Promise<SpatialTreeChunks>;
55
61
  saveChunk(chunks: SpatialTreeChunks, propNames: PropertyRelationConfig, rel: IfcLineData): void;
62
+ private shouldEmitProgress;
56
63
  }
57
64
  export {};
package/lib/Model.d.ts CHANGED
@@ -1,14 +1,16 @@
1
1
  import type { BmtModelData } from "./Loaders/BmtLoader";
2
2
  import { Matrix4, type DataTexture } from "three";
3
+ import type { ViewerMaterialMode } from "./types";
3
4
  type ModelProps = {
4
5
  colorPaletteTexture: DataTexture;
5
6
  coordinationMatrix?: Matrix4 | null;
6
7
  modelID: number;
7
8
  data: BmtModelData;
9
+ materialMode?: ViewerMaterialMode;
8
10
  };
9
11
  export declare function parseModelMatrix(matrix?: string): Matrix4 | null;
10
12
  export declare function getModelCoordinationMatrix(data: BmtModelData): Matrix4 | null;
11
13
  export declare function getModelCoordinationMatrixSource(data: BmtModelData): string | undefined;
12
- declare function Model({ colorPaletteTexture, coordinationMatrix, modelID, data, }: ModelProps): import("react/jsx-runtime").JSX.Element;
14
+ declare function Model({ colorPaletteTexture, coordinationMatrix, modelID, data, materialMode: materialModeOverride, }: ModelProps): import("react/jsx-runtime").JSX.Element;
13
15
  declare const _default: import("react").MemoExoticComponent<typeof Model>;
14
16
  export default _default;
@@ -1,12 +1,15 @@
1
1
  import React from "react";
2
2
  import { Matrix4, type DataTexture } from "three";
3
3
  import type { BmtGeomData, BmtMaterialData } from "./Loaders/BmtLoader";
4
+ import type { ViewerMaterialMode } from "./types";
4
5
  type SelectableMeshProps = {
5
6
  colorPaletteTexture: DataTexture;
6
7
  data: BmtGeomData;
7
8
  isIfcSpace?: boolean;
8
9
  material: BmtMaterialData;
10
+ materialMode?: ViewerMaterialMode;
9
11
  meshMatrix: Matrix4;
12
+ useDoubleSideMaterial?: boolean;
10
13
  };
11
- export declare const SelectableMesh: React.MemoExoticComponent<({ colorPaletteTexture, material, data, isIfcSpace, meshMatrix, }: SelectableMeshProps) => import("react/jsx-runtime").JSX.Element>;
14
+ export declare const SelectableMesh: React.MemoExoticComponent<({ colorPaletteTexture, material, materialMode, data, isIfcSpace, meshMatrix, useDoubleSideMaterial, }: SelectableMeshProps) => import("react/jsx-runtime").JSX.Element>;
12
15
  export {};
@@ -1,3 +1,4 @@
1
+ import { type Vector3 } from "three";
1
2
  import type { CameraUtilsApi } from "../Camera/useCameraUtils";
2
3
  import type { ViewerControlsRef, ViewerModelRef } from "../types";
3
- export default function useSelector(modelRef: ViewerModelRef, controlRef: ViewerControlsRef, cameraUtils: CameraUtilsApi): void;
4
+ export default function useSelector(modelRef: ViewerModelRef, controlRef: ViewerControlsRef, cameraUtils: CameraUtilsApi, setSelectionOrbitPoint?: (point: Vector3) => void): void;
package/lib/Viewer.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { type ComponentProps } from "react";
2
2
  import type { BmtModelData } from "./Loaders/BmtLoader";
3
3
  import { Canvas } from "@react-three/fiber";
4
+ import type { ViewerMaterialMode } from "./types";
4
5
  import { type ViewerApi, type ViewerSelection } from "./api/ViewerApi";
5
6
  import { type ViewerModelSource } from "./api/loader";
6
7
  type ModelsData = Record<number, BmtModelData>;
@@ -10,11 +11,13 @@ export type ViewerProps = {
10
11
  camera?: ComponentProps<typeof Canvas>["camera"];
11
12
  dpr?: ComponentProps<typeof Canvas>["dpr"];
12
13
  defaultSelected?: ViewerSelection;
14
+ materialMode?: ViewerMaterialMode;
13
15
  modelUrls?: string[];
14
16
  modelSources?: ViewerModelSource[];
15
17
  modelsData?: ModelsData;
16
18
  onReady?: (api: ViewerApi) => void;
17
19
  onSelectedChange?: (selected: ViewerSelection) => void;
20
+ performanceMode?: boolean;
18
21
  selected?: ViewerSelection;
19
22
  showNavCube?: boolean;
20
23
  showStats?: boolean;
@@ -1,5 +1,6 @@
1
1
  import { type BmtModelData } from "../Loaders/BmtLoader";
2
2
  import { type BmtWorkerGeometryChunk, type IfcWorkerGeometryChunk, type WorkerProgressEvent } from "../workers";
3
+ import type { ViewerMaterialMode } from "../types";
3
4
  export type ViewerModelSource = string | File;
4
5
  export type ViewerLoadedModels = Record<number, BmtModelData>;
5
6
  export type ViewerLoaderWorkerChunk = (BmtWorkerGeometryChunk | IfcWorkerGeometryChunk) & {
@@ -8,10 +9,12 @@ export type ViewerLoaderWorkerChunk = (BmtWorkerGeometryChunk | IfcWorkerGeometr
8
9
  export type ViewerLoadModelOptions = {
9
10
  chunk?: number;
10
11
  collectWorkerChunks?: boolean;
12
+ materialMode?: ViewerMaterialMode;
11
13
  maxMeshBytes?: number;
12
14
  onChunk?: (chunk: ViewerLoaderWorkerChunk) => void;
13
15
  onProgress?: (progress: WorkerProgressEvent) => void;
14
16
  streamGeometryChunks?: boolean;
17
+ useDoubleSideMaterial?: boolean;
15
18
  useIfcSpace?: boolean;
16
19
  useWorker?: boolean;
17
20
  wasmPath?: string;
@@ -34,6 +37,7 @@ declare class ViewerLoaderApi {
34
37
  private loadIfcModelInWorker;
35
38
  private loadBmtModelInWorker;
36
39
  private resetCoordinationMatrixState;
40
+ private applyRenderSettings;
37
41
  resetCoordinationMatrix(): void;
38
42
  loadModel(sources: ViewerModelSource | ViewerModelSource[], options?: ViewerLoadModelOptions): Promise<ViewerLoadedModels>;
39
43
  }