@pascal-app/viewer 1.0.3 → 1.0.4
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/dist/components/renderers/node-renderer.d.ts.map +1 -1
- package/dist/components/renderers/node-renderer.js +8 -3
- package/dist/components/viewer/frame-limiter.d.ts +1 -0
- package/dist/components/viewer/frame-limiter.d.ts.map +1 -1
- package/dist/components/viewer/frame-limiter.js +22 -3
- package/dist/components/viewer/glb-interactive.d.ts +25 -1
- package/dist/components/viewer/glb-interactive.d.ts.map +1 -1
- package/dist/components/viewer/glb-interactive.js +252 -85
- package/dist/components/viewer/glb-mechanisms.d.ts +10 -0
- package/dist/components/viewer/glb-mechanisms.d.ts.map +1 -0
- package/dist/components/viewer/glb-mechanisms.js +19 -0
- package/dist/components/viewer/glb-scene.d.ts +45 -27
- package/dist/components/viewer/glb-scene.d.ts.map +1 -1
- package/dist/components/viewer/glb-scene.js +420 -506
- package/dist/components/viewer/glb-walkthrough-controller.d.ts +1 -1
- package/dist/components/viewer/glb-walkthrough-controller.d.ts.map +1 -1
- package/dist/components/viewer/glb-walkthrough-controller.js +12 -1
- package/dist/components/viewer/index.d.ts +14 -0
- package/dist/components/viewer/index.d.ts.map +1 -1
- package/dist/components/viewer/index.js +84 -26
- package/dist/components/viewer/lights.d.ts.map +1 -1
- package/dist/components/viewer/lights.js +6 -1
- package/dist/components/viewer/perf-monitor.d.ts.map +1 -1
- package/dist/components/viewer/perf-monitor.js +6 -0
- package/dist/components/viewer/post-processing.d.ts.map +1 -1
- package/dist/components/viewer/post-processing.js +8 -3
- package/dist/components/viewer/registered-systems.d.ts.map +1 -1
- package/dist/components/viewer/registered-systems.js +16 -2
- package/dist/components/viewer/render-error.d.ts +18 -0
- package/dist/components/viewer/render-error.d.ts.map +1 -0
- package/dist/components/viewer/render-error.js +29 -0
- package/dist/components/viewer/scene-ground-replacement.d.ts +6 -0
- package/dist/components/viewer/scene-ground-replacement.d.ts.map +1 -1
- package/dist/components/viewer/scene-ground-replacement.js +15 -0
- package/dist/components/viewer/selection-manager.d.ts.map +1 -1
- package/dist/components/viewer/selection-manager.js +10 -0
- package/dist/components/viewer/viewer-camera.d.ts +4 -0
- package/dist/components/viewer/viewer-camera.d.ts.map +1 -1
- package/dist/components/viewer/viewer-camera.js +11 -1
- package/dist/index.d.ts +22 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -14
- package/dist/lib/asset-url.d.ts.map +1 -1
- package/dist/lib/asset-url.js +7 -1
- package/dist/lib/display-state.d.ts +25 -0
- package/dist/lib/display-state.d.ts.map +1 -0
- package/dist/lib/display-state.js +1 -0
- package/dist/lib/hero-pose.d.ts +12 -2
- package/dist/lib/hero-pose.d.ts.map +1 -1
- package/dist/lib/hero-pose.js +72 -5
- package/dist/lib/ink-edges.d.ts +4 -2
- package/dist/lib/ink-edges.d.ts.map +1 -1
- package/dist/lib/ink-edges.js +17 -7
- package/dist/lib/key-light-override.d.ts +11 -0
- package/dist/lib/key-light-override.d.ts.map +1 -0
- package/dist/lib/key-light-override.js +14 -0
- package/dist/lib/live-frame-hold.d.ts +14 -0
- package/dist/lib/live-frame-hold.d.ts.map +1 -0
- package/dist/lib/live-frame-hold.js +28 -0
- package/dist/lib/materials.d.ts +14 -7
- package/dist/lib/materials.d.ts.map +1 -1
- package/dist/lib/materials.js +31 -5
- package/dist/lib/node-top-surface-height.d.ts +6 -0
- package/dist/lib/node-top-surface-height.d.ts.map +1 -0
- package/dist/lib/node-top-surface-height.js +74 -0
- package/dist/lib/perf-probe-state.d.ts +39 -0
- package/dist/lib/perf-probe-state.d.ts.map +1 -0
- package/dist/lib/perf-probe-state.js +17 -0
- package/dist/lib/pointer-events.d.ts +8 -0
- package/dist/lib/pointer-events.d.ts.map +1 -1
- package/dist/lib/pointer-events.js +27 -4
- package/dist/lib/procedural-emission.d.ts +7 -0
- package/dist/lib/procedural-emission.d.ts.map +1 -0
- package/dist/lib/procedural-emission.js +54 -0
- package/dist/lib/scene-support-height.d.ts +4 -0
- package/dist/lib/scene-support-height.d.ts.map +1 -0
- package/dist/lib/scene-support-height.js +34 -0
- package/dist/lib/scene-visibility.d.ts +6 -0
- package/dist/lib/scene-visibility.d.ts.map +1 -1
- package/dist/lib/scene-visibility.js +15 -3
- package/dist/lib/scripted-opening.d.ts +11 -0
- package/dist/lib/scripted-opening.d.ts.map +1 -0
- package/dist/lib/scripted-opening.js +20 -0
- package/dist/lib/snapshot-pipeline.d.ts +32 -2
- package/dist/lib/snapshot-pipeline.d.ts.map +1 -1
- package/dist/lib/snapshot-pipeline.js +215 -105
- package/dist/lib/terrain-perimeter-fill.d.ts.map +1 -1
- package/dist/lib/terrain-perimeter-fill.js +22 -14
- package/dist/lib/zone-geometry.d.ts +11 -0
- package/dist/lib/zone-geometry.d.ts.map +1 -0
- package/dist/lib/zone-geometry.js +46 -0
- package/dist/store/use-item-light-pool.d.ts +14 -10
- package/dist/store/use-item-light-pool.d.ts.map +1 -1
- package/dist/store/use-item-light-pool.js +52 -26
- package/dist/store/use-viewer.d.ts +11 -0
- package/dist/store/use-viewer.d.ts.map +1 -1
- package/dist/store/use-viewer.js +13 -6
- package/dist/systems/ceiling/ceiling-system.d.ts +15 -1
- package/dist/systems/ceiling/ceiling-system.d.ts.map +1 -1
- package/dist/systems/ceiling/ceiling-system.js +86 -6
- package/dist/systems/door/door-system.d.ts.map +1 -1
- package/dist/systems/door/door-system.js +55 -17
- package/dist/systems/floor-elevation/floor-elevation-system.d.ts +3 -1
- package/dist/systems/floor-elevation/floor-elevation-system.d.ts.map +1 -1
- package/dist/systems/floor-elevation/floor-elevation-system.js +33 -5
- package/dist/systems/geometry/geometry-system.d.ts.map +1 -1
- package/dist/systems/geometry/geometry-system.js +71 -11
- package/dist/systems/interactive/interactive-system.d.ts.map +1 -1
- package/dist/systems/interactive/interactive-system.js +40 -15
- package/dist/systems/interactive/procedural-controls.d.ts +13 -0
- package/dist/systems/interactive/procedural-controls.d.ts.map +1 -0
- package/dist/systems/interactive/procedural-controls.js +17 -0
- package/dist/systems/interactive/scripted-clips.d.ts +19 -0
- package/dist/systems/interactive/scripted-clips.d.ts.map +1 -0
- package/dist/systems/interactive/scripted-clips.js +134 -0
- package/dist/systems/item/item-system.d.ts.map +1 -1
- package/dist/systems/item/item-system.js +9 -3
- package/dist/systems/item/object-cut-invalidation.d.ts +3 -0
- package/dist/systems/item/object-cut-invalidation.d.ts.map +1 -0
- package/dist/systems/item/object-cut-invalidation.js +68 -0
- package/dist/systems/item-light/item-light-system.d.ts +1 -1
- package/dist/systems/item-light/item-light-system.d.ts.map +1 -1
- package/dist/systems/item-light/item-light-system.js +47 -52
- package/dist/systems/level/level-system.d.ts.map +1 -1
- package/dist/systems/level/level-system.js +3 -5
- package/dist/systems/level/level-utils.d.ts +7 -4
- package/dist/systems/level/level-utils.d.ts.map +1 -1
- package/dist/systems/level/level-utils.js +17 -6
- package/dist/systems/level/shadow-only-levels.d.ts +9 -0
- package/dist/systems/level/shadow-only-levels.d.ts.map +1 -0
- package/dist/systems/level/shadow-only-levels.js +7 -0
- package/dist/systems/roof/roof-materials.d.ts +14 -2
- package/dist/systems/roof/roof-materials.d.ts.map +1 -1
- package/dist/systems/roof/roof-materials.js +54 -15
- package/dist/systems/roof/roof-system.d.ts +13 -3
- package/dist/systems/roof/roof-system.d.ts.map +1 -1
- package/dist/systems/roof/roof-system.js +188 -13
- package/dist/systems/slab/slab-system.d.ts +1 -1
- package/dist/systems/slab/slab-system.d.ts.map +1 -1
- package/dist/systems/slab/slab-system.js +49 -19
- package/dist/systems/stair/stair-system.d.ts.map +1 -1
- package/dist/systems/stair/stair-system.js +133 -354
- package/dist/systems/wall/wall-cutout-cache.d.ts +7 -0
- package/dist/systems/wall/wall-cutout-cache.d.ts.map +1 -1
- package/dist/systems/wall/wall-cutout-cache.js +46 -17
- package/dist/systems/wall/wall-cutout.d.ts +6 -0
- package/dist/systems/wall/wall-cutout.d.ts.map +1 -1
- package/dist/systems/wall/wall-cutout.js +42 -28
- package/dist/systems/wall/wall-finish-data.d.ts +22 -0
- package/dist/systems/wall/wall-finish-data.d.ts.map +1 -0
- package/dist/systems/wall/wall-finish-data.js +17 -0
- package/dist/systems/wall/wall-materials.d.ts +9 -4
- package/dist/systems/wall/wall-materials.d.ts.map +1 -1
- package/dist/systems/wall/wall-materials.js +99 -152
- package/dist/systems/wall/wall-system.d.ts +28 -2
- package/dist/systems/wall/wall-system.d.ts.map +1 -1
- package/dist/systems/wall/wall-system.js +582 -143
- package/dist/systems/window/window-system.d.ts +1 -1
- package/dist/systems/window/window-system.d.ts.map +1 -1
- package/dist/systems/window/window-system.js +41 -22
- package/package.json +5 -5
- package/dist/systems/fence/fence-system.d.ts +0 -22
- package/dist/systems/fence/fence-system.d.ts.map +0 -1
- package/dist/systems/fence/fence-system.js +0 -357
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
// New kind-specific modules belong in nodes; viewer must not depend on nodes.
|
|
2
2
|
// This extends the existing viewer-owned wall cutout and material implementation.
|
|
3
|
-
import { getEffectiveNode, getLibraryMaterialsVersion,
|
|
3
|
+
import { getEffectiveNode, getLibraryMaterialsVersion, sceneRegistry, useLiveNodeOverrides, useLiveTransforms, useScene, } from '@pascal-app/core';
|
|
4
4
|
import { Matrix4, Vector3 } from 'three';
|
|
5
5
|
import { getMaterialTextureVersion } from '../../lib/materials';
|
|
6
|
+
import { hasMaterialsForGroups } from '../../lib/pointer-events';
|
|
6
7
|
import useViewer, {} from '../../store/use-viewer';
|
|
8
|
+
import { getWallFinishRefs } from './wall-finish-data';
|
|
7
9
|
import { resolveWallMaterialVariant } from './wall-material-variant';
|
|
8
10
|
import { getHoverHighlightMaterials, getMaterialsForWall, getSelectionHighlightMaterials, } from './wall-materials';
|
|
9
11
|
export function sameMaterialArray(a, b) {
|
|
@@ -38,6 +40,9 @@ function materialsForVariant(variant, materials) {
|
|
|
38
40
|
}
|
|
39
41
|
}
|
|
40
42
|
}
|
|
43
|
+
function wallPaletteKey(mesh) {
|
|
44
|
+
return getWallFinishRefs(mesh.geometry).join('|');
|
|
45
|
+
}
|
|
41
46
|
// About 0.06 degrees: retain the previous side at edge-on poses without
|
|
42
47
|
// introducing a perceptible delay when an orbit crosses a wall's plane.
|
|
43
48
|
export const WALL_FACING_HYSTERESIS = 0.001;
|
|
@@ -131,7 +136,7 @@ export class WallCutoutCache {
|
|
|
131
136
|
const previewId = (state) => state && state.hoverHighlightMode !== 'default' && state.hoverHighlightMode !== 'delete'
|
|
132
137
|
? state.hoveredId
|
|
133
138
|
: null;
|
|
134
|
-
const releasedPreview = previewId(previous)
|
|
139
|
+
const releasedPreview = previewId(previous) === previewId(viewer) ? null : previewId(previous);
|
|
135
140
|
this.viewer = viewer;
|
|
136
141
|
const invalidated = overridesChanged ||
|
|
137
142
|
appearanceChanged ||
|
|
@@ -140,15 +145,16 @@ export class WallCutoutCache {
|
|
|
140
145
|
this.rebuilt.size > 0 ||
|
|
141
146
|
this.transformed.size > 0 ||
|
|
142
147
|
releasedPreview !== null;
|
|
143
|
-
|
|
148
|
+
const cutaway = viewer.wallMode === 'cutaway';
|
|
149
|
+
if (!invalidated && !cutaway)
|
|
144
150
|
return;
|
|
145
151
|
camera.getWorldDirection(this.cameraDirection);
|
|
146
152
|
this.cameraTarget.copy(this.cameraDirection).add(camera.position);
|
|
147
|
-
const cameraChanged =
|
|
153
|
+
const cameraChanged = cutaway &&
|
|
148
154
|
time - this.lastUpdateTime > 0.1 &&
|
|
149
155
|
(camera.position.distanceTo(this.lastCameraPosition) > 0.5 ||
|
|
150
156
|
this.cameraTarget.distanceTo(this.lastCameraTarget) > 0.3);
|
|
151
|
-
if (!invalidated
|
|
157
|
+
if (!(invalidated || cameraChanged))
|
|
152
158
|
return;
|
|
153
159
|
if (registryChanged || nodesChanged) {
|
|
154
160
|
for (const [id, wall] of this.walls) {
|
|
@@ -194,6 +200,7 @@ export class WallCutoutCache {
|
|
|
194
200
|
assignedMaterials: undefined,
|
|
195
201
|
visibleVariant: { key: 'visible', materials: [] },
|
|
196
202
|
hiddenVariant: { key: 'invisible', materials: [] },
|
|
203
|
+
paletteKey: '',
|
|
197
204
|
};
|
|
198
205
|
this.walls.set(id, wall);
|
|
199
206
|
}
|
|
@@ -203,7 +210,9 @@ export class WallCutoutCache {
|
|
|
203
210
|
this.refreshNormal(wall, visited);
|
|
204
211
|
const overrideChanged = this.overrides.get(id) !== overrides.get(id);
|
|
205
212
|
wall.node = getEffectiveNode(node);
|
|
206
|
-
|
|
213
|
+
const repaletted = rebuilt && wallPaletteKey(wall.mesh) !== wall.paletteKey;
|
|
214
|
+
const refresh = added || appearanceChanged || overrideChanged || (nodesChanged && changed) || repaletted;
|
|
215
|
+
if (refresh)
|
|
207
216
|
this.refreshAppearance(wall);
|
|
208
217
|
if (added ||
|
|
209
218
|
appearanceChanged ||
|
|
@@ -212,7 +221,7 @@ export class WallCutoutCache {
|
|
|
212
221
|
rebuilt ||
|
|
213
222
|
releasedPreview === id ||
|
|
214
223
|
cameraChanged) {
|
|
215
|
-
this.apply(wall, viewer.wallMode,
|
|
224
|
+
this.apply(wall, viewer.wallMode, refresh);
|
|
216
225
|
}
|
|
217
226
|
}
|
|
218
227
|
}
|
|
@@ -235,19 +244,35 @@ export class WallCutoutCache {
|
|
|
235
244
|
this.lastUpdateTime = time;
|
|
236
245
|
}
|
|
237
246
|
}
|
|
247
|
+
/**
|
|
248
|
+
* A rebuilt wall whose finish palette changed must swap materials in the same
|
|
249
|
+
* frame: its new groups already index the new palette.
|
|
250
|
+
*/
|
|
251
|
+
handleRebuilt(id) {
|
|
252
|
+
this.rebuilt.add(id);
|
|
253
|
+
const wall = this.walls.get(id);
|
|
254
|
+
const viewer = this.viewer;
|
|
255
|
+
if (!(wall && viewer) || wall.mesh !== sceneRegistry.nodes.get(id))
|
|
256
|
+
return;
|
|
257
|
+
if (wallPaletteKey(wall.mesh) === wall.paletteKey)
|
|
258
|
+
return;
|
|
259
|
+
const node = useScene.getState().nodes[id];
|
|
260
|
+
if (node?.type !== 'wall')
|
|
261
|
+
return;
|
|
262
|
+
wall.node = getEffectiveNode(node);
|
|
263
|
+
this.refreshAppearance(wall);
|
|
264
|
+
this.apply(wall, viewer.wallMode, true);
|
|
265
|
+
}
|
|
238
266
|
refreshAppearance(wall) {
|
|
239
267
|
const viewer = this.viewer;
|
|
240
268
|
const scene = useScene.getState();
|
|
241
269
|
const node = wall.node;
|
|
242
270
|
const deleted = viewer.hoverHighlightMode === 'delete' && viewer.hoveredId === node.id;
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
selectionHighlighted = !getWallFaceBandConfig(node, height).enabled;
|
|
249
|
-
}
|
|
250
|
-
const materials = this.materialResolver(node, viewer.shading, viewer.textures, viewer.colorPreset, viewer.sceneTheme, scene.materials);
|
|
271
|
+
// Painted parts stay readable while their wall is selected for editing.
|
|
272
|
+
const selectionHighlighted = !deleted && this.selected.has(node.id) && !(node.faceRegions?.length ?? 0);
|
|
273
|
+
const finishRefs = getWallFinishRefs(wall.mesh.geometry);
|
|
274
|
+
wall.paletteKey = finishRefs.join('|');
|
|
275
|
+
const materials = this.materialResolver(node, viewer.shading, viewer.textures, viewer.colorPreset, viewer.sceneTheme, scene.materials, finishRefs);
|
|
251
276
|
const variant = (hidden) => {
|
|
252
277
|
const key = resolveWallMaterialVariant({
|
|
253
278
|
translucentMode: viewer.wallMode === 'translucent',
|
|
@@ -289,11 +314,15 @@ export class WallCutoutCache {
|
|
|
289
314
|
if (wall.mesh.userData.wallHidden !== stamp)
|
|
290
315
|
wall.mesh.userData.wallHidden = stamp;
|
|
291
316
|
const variant = hidden ? wall.hiddenVariant : wall.visibleVariant;
|
|
292
|
-
// Non-highlight hover owns a temporary material until its
|
|
317
|
+
// Non-highlight hover (a paint preview) owns a temporary material until its
|
|
318
|
+
// restore callback runs — unless the rebuilt geometry now draws a finish that
|
|
319
|
+
// array has no entry for (a click just added one): then the new palette goes
|
|
320
|
+
// on and the preview is dropped, rather than leaving groups with no material.
|
|
293
321
|
const viewer = this.viewer;
|
|
294
322
|
if (viewer.hoveredId === wall.node.id &&
|
|
295
323
|
viewer.hoverHighlightMode !== 'default' &&
|
|
296
|
-
viewer.hoverHighlightMode !== 'delete'
|
|
324
|
+
viewer.hoverHighlightMode !== 'delete' &&
|
|
325
|
+
hasMaterialsForGroups(wall.mesh)) {
|
|
297
326
|
if (refresh)
|
|
298
327
|
wall.variantKey = undefined;
|
|
299
328
|
return;
|
|
@@ -20,6 +20,12 @@ export declare function runWallCutoutFrame(cache: WallCutoutCache, { camera, clo
|
|
|
20
20
|
* from the assigned material variant.
|
|
21
21
|
*/
|
|
22
22
|
export declare function getWallHideState(wallNode: WallNode, wallMesh: Mesh, wallMode: WallMode, cameraDir: Vector3): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* The walls as a capture draws them, until the returned function puts them back: a delete or a
|
|
25
|
+
* selection highlight taken off and, with `wholeWalls`, every wall whole whatever the wall mode.
|
|
26
|
+
* The palettes come from the renderer's own resolver, so a curtain wall keeps its glass.
|
|
27
|
+
*/
|
|
28
|
+
export declare function wallsForCapture(materialResolver: WallMaterialsResolver, viewerStore: WallCutoutViewerStore, wholeWalls: boolean): () => void;
|
|
23
29
|
export declare const WallCutout: ({ viewerStore, materialResolver, }: {
|
|
24
30
|
viewerStore?: WallCutoutViewerStore;
|
|
25
31
|
materialResolver?: WallMaterialsResolver;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wall-cutout.d.ts","sourceRoot":"","sources":["../../../src/systems/wall/wall-cutout.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAoD,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAGlG,OAAO,KAAK,EAAE,MAAM,EAAY,MAAM,OAAO,CAAA;AAC7C,OAAO,EAAE,KAAK,IAAI,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACjD,OAAkB,EAAE,KAAK,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AACjE,OAAO,EAEL,eAAe,EACf,KAAK,qBAAqB,EAE3B,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"wall-cutout.d.ts","sourceRoot":"","sources":["../../../src/systems/wall/wall-cutout.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAoD,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAGlG,OAAO,KAAK,EAAE,MAAM,EAAY,MAAM,OAAO,CAAA;AAC7C,OAAO,EAAE,KAAK,IAAI,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACjD,OAAkB,EAAE,KAAK,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AACjE,OAAO,EAEL,eAAe,EACf,KAAK,qBAAqB,EAE3B,MAAM,qBAAqB,CAAA;AAE5B,OAAO,EAGL,KAAK,qBAAqB,EAC3B,MAAM,kBAAkB,CAAA;AAKzB,eAAO,MAAM,0BAA0B,IAAI,CAAA;AAE3C,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,eAAe,EACtB,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,QAGtE;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,IAAI,EACd,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE,OAAO,GACjB,OAAO,CAKT;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,gBAAgB,EAAE,qBAAqB,EACvC,WAAW,EAAE,qBAAqB,EAClC,UAAU,EAAE,OAAO,GAClB,MAAM,IAAI,CAmCZ;AAED,eAAO,MAAM,UAAU,GAAI,oCAGxB;IACD,WAAW,CAAC,EAAE,qBAAqB,CAAA;IACnC,gBAAgB,CAAC,EAAE,qBAAqB,CAAA;CACzC,SAiCA,CAAA"}
|
|
@@ -4,6 +4,7 @@ import { useEffect, useMemo } from 'react';
|
|
|
4
4
|
import { Vector3 } from 'three/webgpu';
|
|
5
5
|
import useViewer, {} from '../../store/use-viewer';
|
|
6
6
|
import { sameMaterialArray, WallCutoutCache, wallHiddenFromFacing, } from './wall-cutout-cache';
|
|
7
|
+
import { getWallFinishRefs } from './wall-finish-data';
|
|
7
8
|
import { getMaterialsForWall, getSelectionHighlightMaterials, } from './wall-materials';
|
|
8
9
|
import { subscribeWallRebuilds } from './wall-rebuild-notifications';
|
|
9
10
|
const v = new Vector3();
|
|
@@ -27,43 +28,56 @@ export function getWallHideState(wallNode, wallMesh, wallMode, cameraDir) {
|
|
|
27
28
|
wallMesh.getWorldDirection(v);
|
|
28
29
|
return wallHiddenFromFacing(wallNode, wallMode, v.dot(cameraDir) < 0);
|
|
29
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* The walls as a capture draws them, until the returned function puts them back: a delete or a
|
|
33
|
+
* selection highlight taken off and, with `wholeWalls`, every wall whole whatever the wall mode.
|
|
34
|
+
* The palettes come from the renderer's own resolver, so a curtain wall keeps its glass.
|
|
35
|
+
*/
|
|
36
|
+
export function wallsForCapture(materialResolver, viewerStore, wholeWalls) {
|
|
37
|
+
const snapshot = new Map();
|
|
38
|
+
const viewer = viewerStore.getState();
|
|
39
|
+
sceneRegistry.byType.wall.forEach((wallId) => {
|
|
40
|
+
const wallMesh = sceneRegistry.nodes.get(wallId);
|
|
41
|
+
if (!wallMesh)
|
|
42
|
+
return;
|
|
43
|
+
const wallNode = useScene.getState().nodes[wallId];
|
|
44
|
+
if (wallNode?.type !== 'wall')
|
|
45
|
+
return;
|
|
46
|
+
const mats = materialResolver(wallNode, viewer.shading, viewer.textures, viewer.colorPreset, viewer.sceneTheme, useScene.getState().materials, getWallFinishRefs(wallMesh.geometry));
|
|
47
|
+
const current = wallMesh.material;
|
|
48
|
+
snapshot.set(wallMesh, current);
|
|
49
|
+
if (wholeWalls || current === mats.deleteVisible) {
|
|
50
|
+
wallMesh.material = mats.visible;
|
|
51
|
+
}
|
|
52
|
+
else if (current === mats.deleteInvisible) {
|
|
53
|
+
wallMesh.material = mats.invisible;
|
|
54
|
+
}
|
|
55
|
+
else if (current === mats.deleteTranslucent ||
|
|
56
|
+
sameMaterialArray(current, getSelectionHighlightMaterials(mats.translucent))) {
|
|
57
|
+
wallMesh.material = mats.translucent;
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
return () => {
|
|
61
|
+
snapshot.forEach((material, mesh) => {
|
|
62
|
+
mesh.material = material;
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
}
|
|
30
66
|
export const WallCutout = ({ viewerStore = useViewer, materialResolver = getMaterialsForWall, }) => {
|
|
31
67
|
const cache = useMemo(() => new WallCutoutCache(viewerStore, materialResolver), [viewerStore, materialResolver]);
|
|
32
|
-
useEffect(() => subscribeWallRebuilds((id) => cache.
|
|
68
|
+
useEffect(() => subscribeWallRebuilds((id) => cache.handleRebuilt(id)), [cache]);
|
|
33
69
|
useEffect(() => cache.subscribeLiveTransforms(), [cache]);
|
|
34
70
|
// Camera changes reach PostProcessing (1) in this frame. WallSystem (4)
|
|
35
71
|
// notifies the next frame; WallBatchSystem (5) reads this frame's stamps.
|
|
36
72
|
useFrame((state) => runWallCutoutFrame(cache, state), WALL_CUTOUT_FRAME_PRIORITY);
|
|
37
73
|
useEffect(() => {
|
|
38
|
-
|
|
39
|
-
const restoreForCapture = () => {
|
|
40
|
-
|
|
41
|
-
const wallMesh = sceneRegistry.nodes.get(wallId);
|
|
42
|
-
if (!wallMesh)
|
|
43
|
-
return;
|
|
44
|
-
const wallNode = useScene.getState().nodes[wallId];
|
|
45
|
-
if (wallNode?.type !== 'wall')
|
|
46
|
-
return;
|
|
47
|
-
const mats = materialResolver(wallNode, viewerStore.getState().shading, viewerStore.getState().textures, viewerStore.getState().colorPreset, viewerStore.getState().sceneTheme, useScene.getState().materials);
|
|
48
|
-
const current = wallMesh.material;
|
|
49
|
-
snapshot.set(wallMesh, current);
|
|
50
|
-
if (current === mats.deleteVisible) {
|
|
51
|
-
wallMesh.material = mats.visible;
|
|
52
|
-
}
|
|
53
|
-
else if (current === mats.deleteInvisible) {
|
|
54
|
-
wallMesh.material = mats.invisible;
|
|
55
|
-
}
|
|
56
|
-
else if (current === mats.deleteTranslucent ||
|
|
57
|
-
sameMaterialArray(current, getSelectionHighlightMaterials(mats.translucent))) {
|
|
58
|
-
wallMesh.material = mats.translucent;
|
|
59
|
-
}
|
|
60
|
-
});
|
|
74
|
+
let restore = null;
|
|
75
|
+
const restoreForCapture = (event) => {
|
|
76
|
+
restore = wallsForCapture(materialResolver, viewerStore, event?.wholeWalls === true);
|
|
61
77
|
};
|
|
62
78
|
const reapplyAfterCapture = () => {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
});
|
|
66
|
-
snapshot.clear();
|
|
79
|
+
restore?.();
|
|
80
|
+
restore = null;
|
|
67
81
|
};
|
|
68
82
|
emitter.on('thumbnail:before-capture', restoreForCapture);
|
|
69
83
|
emitter.on('thumbnail:after-capture', reapplyAfterCapture);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { BufferGeometry } from 'three';
|
|
2
|
+
/** A run of one face's base, in wall-local x (m) and local y. */
|
|
3
|
+
export type WallFaceBaseRun = {
|
|
4
|
+
start: number;
|
|
5
|
+
end: number;
|
|
6
|
+
y: number;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* What the wall's material array and the paint resolver need from a build: the
|
|
10
|
+
* finish refs behind material indices 3.. and each face's base runs (null when
|
|
11
|
+
* both faces stand on the wall's own base).
|
|
12
|
+
*/
|
|
13
|
+
export type WallFinishGeometryData = {
|
|
14
|
+
refs: readonly string[];
|
|
15
|
+
faceBase: Record<'a' | 'b', WallFaceBaseRun[]> | null;
|
|
16
|
+
};
|
|
17
|
+
export declare function getWallFinishData(geometry: BufferGeometry | undefined | null): WallFinishGeometryData | undefined;
|
|
18
|
+
/** Finish refs a built wall geometry's material indices 3.. point at. */
|
|
19
|
+
export declare function getWallFinishRefs(geometry: BufferGeometry | undefined | null): readonly string[];
|
|
20
|
+
/** Local y of a face's base at wall-local station `x` (0 when the faces share the wall base). */
|
|
21
|
+
export declare function getWallFaceBaseAt(data: Pick<WallFinishGeometryData, 'faceBase'> | undefined, face: 'a' | 'b', x: number): number;
|
|
22
|
+
//# sourceMappingURL=wall-finish-data.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wall-finish-data.d.ts","sourceRoot":"","sources":["../../../src/systems/wall/wall-finish-data.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAA;AAE3C,iEAAiE;AACjE,MAAM,MAAM,eAAe,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAEvE;;;;GAIG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;IACvB,QAAQ,EAAE,MAAM,CAAC,GAAG,GAAG,GAAG,EAAE,eAAe,EAAE,CAAC,GAAG,IAAI,CAAA;CACtD,CAAA;AAED,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,cAAc,GAAG,SAAS,GAAG,IAAI,GAC1C,sBAAsB,GAAG,SAAS,CAEpC;AAED,yEAAyE;AACzE,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,cAAc,GAAG,SAAS,GAAG,IAAI,GAAG,SAAS,MAAM,EAAE,CAEhG;AAED,iGAAiG;AACjG,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,IAAI,CAAC,sBAAsB,EAAE,UAAU,CAAC,GAAG,SAAS,EAC1D,IAAI,EAAE,GAAG,GAAG,GAAG,EACf,CAAC,EAAE,MAAM,GACR,MAAM,CAKR"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export function getWallFinishData(geometry) {
|
|
2
|
+
return geometry?.userData.wallFinish;
|
|
3
|
+
}
|
|
4
|
+
/** Finish refs a built wall geometry's material indices 3.. point at. */
|
|
5
|
+
export function getWallFinishRefs(geometry) {
|
|
6
|
+
return getWallFinishData(geometry)?.refs ?? [];
|
|
7
|
+
}
|
|
8
|
+
/** Local y of a face's base at wall-local station `x` (0 when the faces share the wall base). */
|
|
9
|
+
export function getWallFaceBaseAt(data, face, x) {
|
|
10
|
+
const runs = data?.faceBase?.[face];
|
|
11
|
+
if (!runs?.length)
|
|
12
|
+
return 0;
|
|
13
|
+
for (const run of runs)
|
|
14
|
+
if (x >= run.start && x < run.end)
|
|
15
|
+
return run.y;
|
|
16
|
+
return x < runs[0].start ? runs[0].y : runs.at(-1).y;
|
|
17
|
+
}
|
|
@@ -20,7 +20,7 @@ export type WallMaterialOverride = {
|
|
|
20
20
|
owned?: Material[];
|
|
21
21
|
};
|
|
22
22
|
};
|
|
23
|
-
export type WallMaterialsResolver = (wallNode: WallNode, shading?: RenderShading, textures?: boolean, colorPreset?: ColorPreset, sceneTheme?: string, sceneMaterials?: SceneMaterials) => WallMaterials;
|
|
23
|
+
export type WallMaterialsResolver = (wallNode: WallNode, shading?: RenderShading, textures?: boolean, colorPreset?: ColorPreset, sceneTheme?: string, sceneMaterials?: SceneMaterials, finishRefs?: readonly string[]) => WallMaterials;
|
|
24
24
|
/** Lazy light-emissive selection variant of a wall's material array (keeps texture). */
|
|
25
25
|
export declare function getSelectionHighlightMaterials(materials: WallMaterialArray): WallMaterialArray;
|
|
26
26
|
/**
|
|
@@ -29,8 +29,13 @@ export declare function getSelectionHighlightMaterials(materials: WallMaterialAr
|
|
|
29
29
|
* film so the wall the click would select reads under the cursor).
|
|
30
30
|
*/
|
|
31
31
|
export declare function getHoverHighlightMaterials(materials: WallMaterialArray): WallMaterialArray;
|
|
32
|
-
export declare function getWallMaterialHash(wallNode: WallNode, shading: RenderShading, sceneMaterials?: SceneMaterials, overrideHash?: string): string;
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
export declare function getWallMaterialHash(wallNode: WallNode, shading: RenderShading, sceneMaterials?: SceneMaterials, finishRefs?: readonly string[], overrideHash?: string): string;
|
|
33
|
+
/**
|
|
34
|
+
* A wall's material palette: 0 caps/edges (themed role), 1 face a, 2 face b,
|
|
35
|
+
* then one entry per `finishRefs` — the region and room finishes the built
|
|
36
|
+
* geometry's groups point at (`getWallFinishRefs(mesh.geometry)`).
|
|
37
|
+
*/
|
|
38
|
+
export declare function getMaterialsForWall(wallNode: WallNode, shading?: RenderShading, textures?: boolean, colorPreset?: ColorPreset, sceneTheme?: string, sceneMaterials?: SceneMaterials, finishRefs?: readonly string[], override?: WallMaterialOverride): WallMaterials;
|
|
39
|
+
export declare function getVisibleWallMaterials(wallNode: WallNode, shading?: RenderShading, textures?: boolean, colorPreset?: ColorPreset, sceneTheme?: string, sceneMaterials?: SceneMaterials, finishRefs?: readonly string[]): WallMaterialArray;
|
|
35
40
|
export {};
|
|
36
41
|
//# sourceMappingURL=wall-materials.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wall-materials.d.ts","sourceRoot":"","sources":["../../../src/systems/wall/wall-materials.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"wall-materials.d.ts","sourceRoot":"","sources":["../../../src/systems/wall/wall-materials.ts"],"names":[],"mappings":"AAAA,OAAO,EASL,KAAK,aAAa,EAClB,KAAK,eAAe,EAGpB,KAAK,QAAQ,EAGd,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAS,KAAK,QAAQ,EAAE,MAAM,OAAO,CAAA;AAG5C,OAAO,EAEL,KAAK,WAAW,EAMhB,KAAK,aAAa,EAInB,MAAM,qBAAqB,CAAA;AAE5B,KAAK,cAAc,GAAG,MAAM,CAAC,eAAe,EAAE,aAAa,CAAC,GAAG,SAAS,CAAA;AAexE,MAAM,MAAM,iBAAiB,GAAG,QAAQ,EAAE,CAAA;AAE1C,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,iBAAiB,CAAA;IAC1B,SAAS,EAAE,iBAAiB,CAAA;IAC5B,WAAW,EAAE,iBAAiB,CAAA;IAC9B,aAAa,EAAE,iBAAiB,CAAA;IAChC,eAAe,EAAE,iBAAiB,CAAA;IAClC,iBAAiB,EAAE,iBAAiB,CAAA;IACpC,YAAY,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,QAAQ,EAAE,CAAA;CAC1B;AAED,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM;QAAE,OAAO,EAAE,iBAAiB,CAAC;QAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAA;KAAE,CAAA;CACjE,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG,CAClC,QAAQ,EAAE,QAAQ,EAClB,OAAO,CAAC,EAAE,aAAa,EACvB,QAAQ,CAAC,EAAE,OAAO,EAClB,WAAW,CAAC,EAAE,WAAW,EACzB,UAAU,CAAC,EAAE,MAAM,EACnB,cAAc,CAAC,EAAE,cAAc,EAC/B,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,KAC3B,aAAa,CAAA;AA2QlB,wFAAwF;AACxF,wBAAgB,8BAA8B,CAAC,SAAS,EAAE,iBAAiB,GAAG,iBAAiB,CAS9F;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,iBAAiB,GAAG,iBAAiB,CAS1F;AA4DD,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,aAAa,EACtB,cAAc,CAAC,EAAE,cAAc,EAC/B,UAAU,GAAE,SAAS,MAAM,EAAO,EAClC,YAAY,CAAC,EAAE,MAAM,GACpB,MAAM,CAQR;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,QAAQ,EAClB,OAAO,GAAE,aAA0B,EACnC,QAAQ,UAAO,EACf,WAAW,GAAE,WAAoB,EACjC,UAAU,CAAC,EAAE,MAAM,EACnB,cAAc,CAAC,EAAE,cAAc,EAC/B,UAAU,GAAE,SAAS,MAAM,EAAO,EAClC,QAAQ,CAAC,EAAE,oBAAoB,GAC9B,aAAa,CAmFf;AAED,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,QAAQ,EAClB,OAAO,GAAE,aAA0B,EACnC,QAAQ,UAAO,EACf,WAAW,GAAE,WAAoB,EACjC,UAAU,CAAC,EAAE,MAAM,EACnB,cAAc,CAAC,EAAE,cAAc,EAC/B,UAAU,GAAE,SAAS,MAAM,EAAO,GACjC,iBAAiB,CAUnB"}
|