@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
|
@@ -32,7 +32,12 @@ type ViewerState = {
|
|
|
32
32
|
cameraMode: 'perspective' | 'orthographic';
|
|
33
33
|
setCameraMode: (mode: 'perspective' | 'orthographic') => void;
|
|
34
34
|
sceneTheme: string;
|
|
35
|
+
/** The user's own pick, and the only theme that persists. */
|
|
36
|
+
savedSceneTheme: string;
|
|
35
37
|
setSceneTheme: (id: string) => void;
|
|
38
|
+
/** Show a theme without saving it (e.g. a project's own mood); `null`
|
|
39
|
+
* returns to the saved one. */
|
|
40
|
+
showSceneTheme: (id: string | null) => void;
|
|
36
41
|
renderContext: RenderContext;
|
|
37
42
|
setRenderContext: (context: RenderContext) => void;
|
|
38
43
|
/** True during a GLB bake/export pass. Renderers that normally draw via a
|
|
@@ -73,6 +78,12 @@ type ViewerState = {
|
|
|
73
78
|
unitExplicit: boolean;
|
|
74
79
|
levelMode: 'stacked' | 'exploded' | 'solo' | 'manual';
|
|
75
80
|
setLevelMode: (mode: 'stacked' | 'exploded' | 'solo' | 'manual') => void;
|
|
81
|
+
/**
|
|
82
|
+
* The editor's level display: stacked, with every level above the selected
|
|
83
|
+
* one hidden (the selected level and those below stay). Set by the host
|
|
84
|
+
* while editing; never persisted, so the viewer app keeps its own mode.
|
|
85
|
+
*/
|
|
86
|
+
hideLevelsAboveSelection: boolean;
|
|
76
87
|
wallMode: WallMode;
|
|
77
88
|
setWallMode: (mode: WallMode) => void;
|
|
78
89
|
showScans: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-viewer.d.ts","sourceRoot":"","sources":["../../src/store/use-viewer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,OAAO,EACP,QAAQ,EACR,YAAY,EACZ,SAAS,EACT,QAAQ,EACR,QAAQ,EACT,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAIrC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAGlE,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,QAAQ,CAAA;AAC/C,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,aAAa,CAAA;AACrD,MAAM,MAAM,QAAQ,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,aAAa,CAAA;AAEhE,KAAK,aAAa,GAAG;IACnB,UAAU,EAAE,YAAY,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IACrC,OAAO,EAAE,SAAS,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IAC/B,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IAC7B,WAAW,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAA;CAC9B,CAAA;AAED,KAAK,QAAQ,GAAG;IACd,eAAe,EAAE,QAAQ,EAAE,CAAA;IAC3B,cAAc,EAAE,QAAQ,EAAE,CAAA;CAC3B,CAAA;AAED,KAAK,WAAW,GAAG;IACjB,SAAS,EAAE,aAAa,CAAA;IACxB,aAAa,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IACpC,cAAc,EAAE,CAAC,EAAE,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,KAAK,IAAI,CAAA;IACnD,kBAAkB,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAA;IACpC,qBAAqB,EAAE,CAAC,GAAG,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,IAAI,CAAA;IACtD;+EAC2E;IAC3E,mBAAmB,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAA;IACrC,sBAAsB,EAAE,CAAC,GAAG,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,IAAI,CAAA;IACvD,kBAAkB,EAAE,MAAM,CAAA;IAC1B,qBAAqB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC7C,SAAS,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IAChD,YAAY,EAAE,CAAC,EAAE,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,KAAK,IAAI,CAAA;IAEjE,UAAU,EAAE,aAAa,GAAG,cAAc,CAAA;IAC1C,aAAa,EAAE,CAAC,IAAI,EAAE,aAAa,GAAG,cAAc,KAAK,IAAI,CAAA;IAE7D,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;
|
|
1
|
+
{"version":3,"file":"use-viewer.d.ts","sourceRoot":"","sources":["../../src/store/use-viewer.ts"],"names":[],"mappings":"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"}
|
package/dist/store/use-viewer.js
CHANGED
|
@@ -141,7 +141,9 @@ const useViewer = create()(persist((set) => ({
|
|
|
141
141
|
cameraMode: 'perspective',
|
|
142
142
|
setCameraMode: (mode) => set({ cameraMode: mode }),
|
|
143
143
|
sceneTheme: 'studio',
|
|
144
|
-
|
|
144
|
+
savedSceneTheme: 'studio',
|
|
145
|
+
setSceneTheme: (id) => set({ sceneTheme: id, savedSceneTheme: id }),
|
|
146
|
+
showSceneTheme: (id) => set((state) => ({ sceneTheme: id ?? state.savedSceneTheme })),
|
|
145
147
|
renderContext: 'editor',
|
|
146
148
|
setRenderContext: (context) => set({ renderContext: context }),
|
|
147
149
|
isExporting: false,
|
|
@@ -180,6 +182,7 @@ const useViewer = create()(persist((set) => ({
|
|
|
180
182
|
setMetricNotation: (metricNotation) => set({ unit: 'metric', metricNotation, unitExplicit: true }),
|
|
181
183
|
levelMode: 'stacked',
|
|
182
184
|
setLevelMode: (mode) => set({ levelMode: mode }),
|
|
185
|
+
hideLevelsAboveSelection: false,
|
|
183
186
|
wallMode: 'up',
|
|
184
187
|
setWallMode: (mode) => set({ wallMode: mode }),
|
|
185
188
|
showScans: true,
|
|
@@ -295,13 +298,17 @@ const useViewer = create()(persist((set) => ({
|
|
|
295
298
|
setInputDragging: (dragging) => set({ inputDragging: dragging }),
|
|
296
299
|
}), {
|
|
297
300
|
name: 'viewer-preferences',
|
|
298
|
-
merge: (persistedState, currentState) =>
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
301
|
+
merge: (persistedState, currentState) => {
|
|
302
|
+
const persisted = normalizePersistedViewerState(persistedState);
|
|
303
|
+
return {
|
|
304
|
+
...currentState,
|
|
305
|
+
...persisted,
|
|
306
|
+
savedSceneTheme: persisted.sceneTheme ?? currentState.savedSceneTheme,
|
|
307
|
+
};
|
|
308
|
+
},
|
|
302
309
|
partialize: (state) => ({
|
|
303
310
|
cameraMode: state.cameraMode,
|
|
304
|
-
sceneTheme: state.
|
|
311
|
+
sceneTheme: state.savedSceneTheme,
|
|
305
312
|
shadingByContext: state.shadingByContext,
|
|
306
313
|
textures: state.textures,
|
|
307
314
|
colorPreset: state.colorPreset,
|
|
@@ -1,6 +1,19 @@
|
|
|
1
|
-
import { type CeilingNode } from '@pascal-app/core';
|
|
1
|
+
import { type CeilingNode, type CeilingSurfaceCell, useScene } from '@pascal-app/core';
|
|
2
2
|
import * as THREE from 'three';
|
|
3
|
+
/** Name of the meshes a ceiling draws its paint regions with, one per region. */
|
|
4
|
+
export declare const CEILING_REGION_MESH = "ceiling-region";
|
|
5
|
+
/**
|
|
6
|
+
* The material a ceiling draws a region finish with. The ceiling's renderer
|
|
7
|
+
* owns materials (theme, textures, scene materials) and leaves this on the
|
|
8
|
+
* registered mesh; the system builds geometry and asks it.
|
|
9
|
+
*/
|
|
10
|
+
export type CeilingRegionMaterial = (finish: CeilingSurfaceCell['finish']) => THREE.Material;
|
|
11
|
+
type SceneNodes = ReturnType<typeof useScene.getState>['nodes'];
|
|
3
12
|
export declare const CeilingSystem: () => null;
|
|
13
|
+
/**
|
|
14
|
+
* Updates the geometry for a single ceiling
|
|
15
|
+
*/
|
|
16
|
+
export declare function updateCeilingGeometry(node: CeilingNode, mesh: THREE.Mesh, extraHoles?: Array<Array<[number, number]>>, nodes?: SceneNodes): void;
|
|
4
17
|
/**
|
|
5
18
|
* Generates flat ceiling geometry from polygon (no extrusion).
|
|
6
19
|
*
|
|
@@ -9,4 +22,5 @@ export declare const CeilingSystem: () => null;
|
|
|
9
22
|
* stored on the node — they are recomputed on every rebuild.
|
|
10
23
|
*/
|
|
11
24
|
export declare function generateCeilingGeometry(ceilingNode: CeilingNode, extraHoles?: Array<Array<[number, number]>>): THREE.BufferGeometry;
|
|
25
|
+
export {};
|
|
12
26
|
//# sourceMappingURL=ceiling-system.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ceiling-system.d.ts","sourceRoot":"","sources":["../../../src/systems/ceiling/ceiling-system.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"ceiling-system.d.ts","sourceRoot":"","sources":["../../../src/systems/ceiling/ceiling-system.tsx"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,WAAW,EAChB,KAAK,kBAAkB,EAYvB,QAAQ,EACT,MAAM,kBAAkB,CAAA;AAEzB,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,iFAAiF;AACjF,eAAO,MAAM,mBAAmB,mBAAmB,CAAA;AAEnD;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,QAAQ,CAAC,KAAK,KAAK,CAAC,QAAQ,CAAA;AAE5F,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAA;AAa/D,eAAO,MAAM,aAAa,YA4BzB,CAAA;AAsCD;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,WAAW,EACjB,IAAI,EAAE,KAAK,CAAC,IAAI,EAChB,UAAU,GAAE,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAM,EAC/C,KAAK,GAAE,UAAsC,QA8C9C;AAqDD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,WAAW,EACxB,UAAU,GAAE,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAM,GAC9C,KAAK,CAAC,cAAc,CA6DtB"}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import { getEffectiveNode, nodeRegistry, resolveCeilingHeight, sceneRegistry, useLiveTransforms, useScene, } from '@pascal-app/core';
|
|
1
|
+
import { CEILING_DRAW_OFFSET, CEILING_SURFACE_ROLE, ceilingPaintRegions, computeCeilingSurfaceCells, getEffectiveCutterNode, getEffectiveNode, hostedCutterHoles, isScriptedNode, nodeRegistry, resolveCeilingHeight, sceneRegistry, useLiveTransforms, useScene, } from '@pascal-app/core';
|
|
2
2
|
import { useFrame } from '@react-three/fiber';
|
|
3
3
|
import * as THREE from 'three';
|
|
4
|
+
import { mergeGeometries } from 'three/examples/jsm/utils/BufferGeometryUtils.js';
|
|
4
5
|
import { mergeSurfaceHolePolygons } from '../surface-hole-geometry';
|
|
6
|
+
/** Name of the meshes a ceiling draws its paint regions with, one per region. */
|
|
7
|
+
export const CEILING_REGION_MESH = 'ceiling-region';
|
|
5
8
|
function ensureUv2Attribute(geometry) {
|
|
6
9
|
const uv = geometry.getAttribute('uv');
|
|
7
10
|
if (!uv)
|
|
@@ -49,29 +52,53 @@ export const CeilingSystem = () => {
|
|
|
49
52
|
* participate just by declaring `capabilities.ceilingCut` on its definition.
|
|
50
53
|
*/
|
|
51
54
|
function collectCeilingHoles(ceiling, nodes) {
|
|
52
|
-
|
|
55
|
+
// Only the ceiling's own children can bind to it.
|
|
56
|
+
const hosted = { [ceiling.id]: ceiling };
|
|
57
|
+
for (const childId of ceiling.children ?? []) {
|
|
58
|
+
const child = nodes[childId];
|
|
59
|
+
if (child)
|
|
60
|
+
hosted[child.id] = getEffectiveCutterNode(child);
|
|
61
|
+
}
|
|
62
|
+
const holes = hostedCutterHoles(ceiling, hosted);
|
|
53
63
|
for (const childId of ceiling.children ?? []) {
|
|
54
64
|
const child = nodes[childId];
|
|
55
65
|
if (!child)
|
|
56
66
|
continue;
|
|
67
|
+
if (isScriptedNode(child) && child.source.manifest.cutters?.length)
|
|
68
|
+
continue;
|
|
57
69
|
const def = nodeRegistry.get(child.type);
|
|
58
70
|
const hole = def?.capabilities?.ceilingCut?.buildCeilingHole(child);
|
|
59
71
|
if (hole)
|
|
60
72
|
holes.push(hole);
|
|
61
73
|
}
|
|
74
|
+
for (const [, def] of nodeRegistry.entries())
|
|
75
|
+
holes.push(...(def.capabilities?.ceilingCut?.holesFor?.(ceiling) ?? []));
|
|
62
76
|
return holes;
|
|
63
77
|
}
|
|
64
78
|
/**
|
|
65
79
|
* Updates the geometry for a single ceiling
|
|
66
80
|
*/
|
|
67
|
-
function updateCeilingGeometry(node, mesh, extraHoles = [], nodes = useScene.getState().nodes) {
|
|
81
|
+
export function updateCeilingGeometry(node, mesh, extraHoles = [], nodes = useScene.getState().nodes) {
|
|
68
82
|
const newGeo = generateCeilingGeometry(node, extraHoles);
|
|
83
|
+
// Painted regions partition the underside: the ceiling's own mesh keeps what
|
|
84
|
+
// no region covers, and each region draws as its own single-material mesh,
|
|
85
|
+
// so batching buckets them by material like any other surface.
|
|
86
|
+
const regions = node.polygon.length >= 3 ? ceilingPaintRegions(node, nodes) : [];
|
|
87
|
+
const cells = regions.length
|
|
88
|
+
? computeCeilingSurfaceCells(node.polygon, [...mergeSurfaceHolePolygons(node.holes || []), ...extraHoles], regions)
|
|
89
|
+
: null;
|
|
90
|
+
const surface = cells?.find((cell) => cell.role === CEILING_SURFACE_ROLE);
|
|
69
91
|
mesh.geometry.dispose();
|
|
70
|
-
mesh.geometry = newGeo;
|
|
92
|
+
mesh.geometry = cells ? flatCeilingGeometry(surface?.polygons ?? []) : newGeo;
|
|
93
|
+
mesh.userData.paintRole = CEILING_SURFACE_ROLE;
|
|
94
|
+
syncCeilingRegionMeshes(mesh, (cells ?? []).filter((cell) => cell.role !== CEILING_SURFACE_ROLE));
|
|
71
95
|
const gridMesh = mesh.getObjectByName('ceiling-grid');
|
|
72
96
|
if (gridMesh) {
|
|
73
97
|
gridMesh.geometry.dispose();
|
|
74
|
-
gridMesh.geometry = newGeo.clone();
|
|
98
|
+
gridMesh.geometry = cells ? newGeo : newGeo.clone();
|
|
99
|
+
}
|
|
100
|
+
else if (cells) {
|
|
101
|
+
newGeo.dispose();
|
|
75
102
|
}
|
|
76
103
|
// Position at the ceiling height and reset X/Z so live-drag mesh
|
|
77
104
|
// offsets (set by move tools during the drag) don't leak into the
|
|
@@ -85,7 +112,60 @@ function updateCeilingGeometry(node, mesh, extraHoles = [], nodes = useScene.get
|
|
|
85
112
|
// follows-mode ceiling re-parks under the current plane on every rebuild
|
|
86
113
|
// (level-height edits / covering-slab changes dirty-mark ceilings).
|
|
87
114
|
// Slight offset to avoid z-fighting with upper-level slabs.
|
|
88
|
-
mesh.position.y =
|
|
115
|
+
mesh.position.y =
|
|
116
|
+
resolveCeilingHeight(node, nodes) - CEILING_DRAW_OFFSET + (liveTransform?.position[1] ?? 0);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* One child mesh per region cell, reused by position so a repaint keeps its
|
|
120
|
+
* mesh; surplus meshes go. The material comes from the renderer's resolver.
|
|
121
|
+
*/
|
|
122
|
+
function syncCeilingRegionMeshes(mesh, cells) {
|
|
123
|
+
const existing = mesh.children.filter((child) => child.isMesh && child.name === CEILING_REGION_MESH);
|
|
124
|
+
const resolve = mesh.userData.ceilingRegionMaterial;
|
|
125
|
+
cells.forEach((cell, index) => {
|
|
126
|
+
let region = existing[index];
|
|
127
|
+
if (!region) {
|
|
128
|
+
region = new THREE.Mesh();
|
|
129
|
+
region.name = CEILING_REGION_MESH;
|
|
130
|
+
mesh.add(region);
|
|
131
|
+
}
|
|
132
|
+
else
|
|
133
|
+
region.geometry.dispose();
|
|
134
|
+
region.geometry = flatCeilingGeometry(cell.polygons);
|
|
135
|
+
region.userData.paintRole = cell.role;
|
|
136
|
+
region.userData.finish = cell.finish;
|
|
137
|
+
region.userData.__fromGeometry = true;
|
|
138
|
+
region.material = resolve?.(cell.finish) ?? mesh.material;
|
|
139
|
+
});
|
|
140
|
+
for (const surplus of existing.slice(cells.length)) {
|
|
141
|
+
surplus.geometry.dispose();
|
|
142
|
+
surplus.removeFromParent();
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/** Flat geometry for level-XZ pieces, laid out the way `generateCeilingGeometry` lays a ceiling. */
|
|
146
|
+
function flatCeilingGeometry(pieces) {
|
|
147
|
+
const parts = pieces
|
|
148
|
+
.filter((piece) => piece.outer.length >= 3)
|
|
149
|
+
.map((piece) => {
|
|
150
|
+
const shape = new THREE.Shape(piece.outer.map(([x, z]) => new THREE.Vector2(x, -z)));
|
|
151
|
+
for (const hole of piece.holes)
|
|
152
|
+
if (hole.length >= 3)
|
|
153
|
+
shape.holes.push(new THREE.Path(hole.map(([x, z]) => new THREE.Vector2(x, -z))));
|
|
154
|
+
const geometry = new THREE.ShapeGeometry(shape);
|
|
155
|
+
geometry.rotateX(-Math.PI / 2);
|
|
156
|
+
geometry.computeVertexNormals();
|
|
157
|
+
ensureUv2Attribute(geometry);
|
|
158
|
+
return geometry;
|
|
159
|
+
});
|
|
160
|
+
if (parts.length === 0)
|
|
161
|
+
return generateCeilingGeometry({ polygon: [] });
|
|
162
|
+
if (parts.length === 1)
|
|
163
|
+
return parts[0];
|
|
164
|
+
const merged = mergeGeometries(parts) ?? parts[0];
|
|
165
|
+
for (const part of parts)
|
|
166
|
+
if (part !== merged)
|
|
167
|
+
part.dispose();
|
|
168
|
+
return merged;
|
|
89
169
|
}
|
|
90
170
|
/**
|
|
91
171
|
* Generates flat ceiling geometry from polygon (no extrusion).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"door-system.d.ts","sourceRoot":"","sources":["../../../src/systems/door/door-system.tsx"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,QAAQ,
|
|
1
|
+
{"version":3,"file":"door-system.d.ts","sourceRoot":"","sources":["../../../src/systems/door/door-system.tsx"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,QAAQ,EAcd,MAAM,kBAAkB,CAAA;AAGzB,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AA6D9B,eAAO,MAAM,UAAU,YAyHtB,CAAA;AAiqCD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,QAAQ,EACd,IAAI,EAAE,KAAK,CAAC,QAAQ,GAAG,SAAS,EAChC,KAAK,EAAE,MAAM,GACZ,OAAO,CA6GT;AA6wCD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,QAAQ,GAAG,KAAK,CAAC,IAAI,CAI/D"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { clampDoorOperationState, DEFAULT_WALL_THICKNESS, DoorNode as DoorNodeSchema, getDoorRenderOpenAmount, getEffectiveNode, getWallThickness, sceneRegistry, useInteractive, useLiveNodeOverrides, useScene, } from '@pascal-app/core';
|
|
1
|
+
import { clampDoorOperationState, DEFAULT_WALL_THICKNESS, DoorNode as DoorNodeSchema, getDoorRenderOpenAmount, getEffectiveNode, getOpeningWallPlacement, getWallThickness, sceneRegistry, scriptedSize, useInteractive, useLiveNodeOverrides, useScene, } from '@pascal-app/core';
|
|
2
2
|
import { useFrame } from '@react-three/fiber';
|
|
3
3
|
import { useEffect, useRef } from 'react';
|
|
4
4
|
import * as THREE from 'three';
|
|
5
5
|
import { applyWorldScaleBoxUVs } from '../../lib/box-uv';
|
|
6
|
-
import { createDefaultMaterial, createSurfaceRoleMaterial, glassMaterial as defaultGlassMaterial, baseMaterial as getBaseMaterial, resolveMaterialRef, } from '../../lib/materials';
|
|
6
|
+
import { createDefaultMaterial, createMaterial, createSurfaceRoleMaterial, glassMaterial as defaultGlassMaterial, baseMaterial as getBaseMaterial, resolveMaterialRef, } from '../../lib/materials';
|
|
7
7
|
import { timeSpan } from '../../lib/perf-tracks';
|
|
8
|
+
import { settleScriptedOpening } from '../../lib/scripted-opening';
|
|
8
9
|
import useViewer from '../../store/use-viewer';
|
|
9
10
|
import { getOpeningCutoutProxyDepth } from '../wall/opening-cutout-geometry';
|
|
10
11
|
// Invisible material for root mesh — used as selection hitbox only
|
|
@@ -146,9 +147,12 @@ export const DoorSystem = () => {
|
|
|
146
147
|
// rebuild reflects the in-flight drag without zustand churn. When
|
|
147
148
|
// no override is set this returns the scene node unchanged.
|
|
148
149
|
const effectiveNode = getEffectiveNode(node);
|
|
149
|
-
timeSpan('door', () => updateDoorMesh(effectiveNode, mesh), {
|
|
150
|
+
const built = timeSpan('door', () => updateDoorMesh(effectiveNode, mesh), {
|
|
150
151
|
properties: [['node', id]],
|
|
151
152
|
});
|
|
153
|
+
// A scripted opening stays dirty until its artifact has loaded.
|
|
154
|
+
if (!built)
|
|
155
|
+
continue;
|
|
152
156
|
clearDirty(id);
|
|
153
157
|
rebuiltDoorsThisFrame += 1;
|
|
154
158
|
// Rebuild the parent wall so its cutout reflects the updated door geometry
|
|
@@ -208,16 +212,21 @@ function doorSlotDefault(slotId) {
|
|
|
208
212
|
getBaseMaterial(currentShading));
|
|
209
213
|
}
|
|
210
214
|
// Resolve a door's slot to a material: the `node.slots` override (colored mode
|
|
211
|
-
// only) → the body
|
|
212
|
-
//
|
|
215
|
+
// only) → the door-wide `material` for the body (panel and frame; glass and
|
|
216
|
+
// hardware keep their own finish) → the body/glass/hardware default.
|
|
217
|
+
// Textures-off ignores overrides — the monochrome escape hatch.
|
|
213
218
|
function resolveDoorSlotMaterial(node, slotId) {
|
|
214
219
|
const fallback = doorSlotDefault(slotId);
|
|
215
220
|
if (!currentTextures)
|
|
216
221
|
return fallback;
|
|
217
222
|
const ref = node.slots?.[slotId];
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
223
|
+
const painted = ref ? resolveMaterialRef(ref, currentSceneMaterials, currentShading) : null;
|
|
224
|
+
if (painted)
|
|
225
|
+
return painted;
|
|
226
|
+
if (node.material && (slotId === 'panel' || slotId === 'frame')) {
|
|
227
|
+
return createMaterial(node.material, currentShading);
|
|
228
|
+
}
|
|
229
|
+
return fallback;
|
|
221
230
|
}
|
|
222
231
|
function addBox(parent, material, w, h, d, x, y, z) {
|
|
223
232
|
const geometry = new THREE.BoxGeometry(w, h, d);
|
|
@@ -676,7 +685,9 @@ function addLeafSegmentContent({ addLeafBox, addLeafShape, leafWidth, leafHeight
|
|
|
676
685
|
addLeafShape(baseMaterial, innerPanelShape, effectiveDepth);
|
|
677
686
|
}
|
|
678
687
|
else {
|
|
688
|
+
// A leaf is paneled on both faces, so the person sees the style from either side.
|
|
679
689
|
addLeafBox(baseMaterial, panelW, panelH, effectiveDepth, colX, segCenterY, panelZ);
|
|
690
|
+
addLeafBox(baseMaterial, panelW, panelH, effectiveDepth, colX, segCenterY, -panelZ);
|
|
680
691
|
}
|
|
681
692
|
}
|
|
682
693
|
}
|
|
@@ -1239,8 +1250,19 @@ function updateDoorMesh(rawNode, mesh) {
|
|
|
1239
1250
|
mesh.geometry = new THREE.BoxGeometry(node.width, node.height, node.frameDepth);
|
|
1240
1251
|
mesh.material = hitboxMaterial;
|
|
1241
1252
|
// Sync transform from node (React may lag behind the system by a frame during drag)
|
|
1242
|
-
|
|
1243
|
-
|
|
1253
|
+
const parent = node.parentId ? useScene.getState().nodes[node.parentId] : undefined;
|
|
1254
|
+
const placement = parent?.type === 'wall' && !node.roofSegmentId
|
|
1255
|
+
? getOpeningWallPlacement(getEffectiveNode(parent), node, useScene.getState().nodes)
|
|
1256
|
+
: node;
|
|
1257
|
+
mesh.position.set(...placement.position);
|
|
1258
|
+
mesh.rotation.set(...placement.rotation);
|
|
1259
|
+
// Built from a script: the renderer shows its artifact, not the parametric
|
|
1260
|
+
// frame, and the hit box is what the script built.
|
|
1261
|
+
if (node.source) {
|
|
1262
|
+
mesh.geometry.dispose();
|
|
1263
|
+
mesh.geometry = new THREE.BoxGeometry(...scriptedSize(node.source.manifest));
|
|
1264
|
+
return settleScriptedOpening(mesh);
|
|
1265
|
+
}
|
|
1244
1266
|
// Dispose and remove all old visual children; preserve 'cutout'
|
|
1245
1267
|
for (const child of [...mesh.children]) {
|
|
1246
1268
|
if (child.name === 'cutout')
|
|
@@ -1263,7 +1285,7 @@ function updateDoorMesh(rawNode, mesh) {
|
|
|
1263
1285
|
const clampedSwingAngle = Math.max(0, Math.min(Math.PI / 2, swingAngle));
|
|
1264
1286
|
if (openingKind === 'opening') {
|
|
1265
1287
|
syncDoorCutout(node, mesh);
|
|
1266
|
-
return;
|
|
1288
|
+
return true;
|
|
1267
1289
|
}
|
|
1268
1290
|
const insideWidth = width - 2 * frameThickness;
|
|
1269
1291
|
const leafH = height - frameThickness; // only top frame
|
|
@@ -1505,11 +1527,12 @@ function updateDoorMesh(rawNode, mesh) {
|
|
|
1505
1527
|
// … was not set" on a Draw(0, …)). Hide any empty mesh so it is never
|
|
1506
1528
|
// drawn (it would render nothing anyway).
|
|
1507
1529
|
hideEmptyGeometryMeshes(mesh);
|
|
1530
|
+
return true;
|
|
1508
1531
|
}
|
|
1509
1532
|
function hideEmptyGeometryMeshes(root) {
|
|
1510
1533
|
root.traverse((obj) => {
|
|
1511
1534
|
const child = obj;
|
|
1512
|
-
if (!child.isMesh
|
|
1535
|
+
if (!(child.isMesh && child.geometry))
|
|
1513
1536
|
return;
|
|
1514
1537
|
const position = child.geometry.getAttribute('position');
|
|
1515
1538
|
if (!position || position.count === 0)
|
|
@@ -1531,7 +1554,15 @@ function syncDoorCutout(node, mesh) {
|
|
|
1531
1554
|
mesh.add(cutout);
|
|
1532
1555
|
}
|
|
1533
1556
|
cutout.geometry.dispose();
|
|
1534
|
-
const depth =
|
|
1557
|
+
const { depth, center } = resolveOpeningCutoutProxy(node);
|
|
1558
|
+
cutout.position.set(0, 0, 0);
|
|
1559
|
+
if (center) {
|
|
1560
|
+
// Curved and justified walls place openings off the reference line. Remove
|
|
1561
|
+
// only the visual plane offset, preserving the frame's resolved floor datum.
|
|
1562
|
+
cutout.position
|
|
1563
|
+
.set(center[0] - mesh.position.x, 0, center[2] - mesh.position.z)
|
|
1564
|
+
.applyQuaternion(mesh.quaternion.clone().invert());
|
|
1565
|
+
}
|
|
1535
1566
|
const openingShape = getEffectiveOpeningShape(node);
|
|
1536
1567
|
if (openingShape === 'arch') {
|
|
1537
1568
|
cutout.geometry = new THREE.ExtrudeGeometry(createArchShape(-node.width / 2, node.width / 2, -node.height / 2, node.height / 2, getClampedArchHeight(node.width, node.height, node.archHeight)), {
|
|
@@ -1558,11 +1589,18 @@ function syncDoorCutout(node, mesh) {
|
|
|
1558
1589
|
// the proxy stays proud of both wall faces (front/back selection) without the
|
|
1559
1590
|
// old 1m depth that blanketed the floor. Falls back to the default thickness
|
|
1560
1591
|
// when the parent wall isn't a resolvable wall node.
|
|
1561
|
-
function
|
|
1592
|
+
function resolveOpeningCutoutProxy(node) {
|
|
1562
1593
|
const parentId = node.parentId;
|
|
1563
|
-
const
|
|
1564
|
-
const
|
|
1565
|
-
|
|
1594
|
+
const nodes = useScene.getState().nodes;
|
|
1595
|
+
const parent = parentId ? nodes[parentId] : undefined;
|
|
1596
|
+
const wall = parent?.type === 'wall' ? getEffectiveNode(parent) : undefined;
|
|
1597
|
+
const wallThickness = wall ? getWallThickness(wall) : DEFAULT_WALL_THICKNESS;
|
|
1598
|
+
return {
|
|
1599
|
+
depth: getOpeningCutoutProxyDepth(wallThickness),
|
|
1600
|
+
center: wall && !node.roofSegmentId && node.position[2] !== 0
|
|
1601
|
+
? getOpeningWallPlacement(wall, { ...node, position: [node.position[0], node.position[1], 0] }, nodes).position
|
|
1602
|
+
: undefined,
|
|
1603
|
+
};
|
|
1566
1604
|
}
|
|
1567
1605
|
/**
|
|
1568
1606
|
* Build a fresh door mesh for preview/ghost rendering.
|
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
* Runs at priority 1 — before the priority-2 systems (`GeometrySystem`,
|
|
15
15
|
* `ItemSystem`) so the dirty mark survives long enough for those to do
|
|
16
16
|
* their own work. Kinds with no geometry/system have no downstream dirty
|
|
17
|
-
* consumer, so this system clears their dirty mark after applying the lift
|
|
17
|
+
* consumer, so this system clears their dirty mark after applying the lift,
|
|
18
|
+
* at priority 2 like every other consumer: the node batch snapshots marks at
|
|
19
|
+
* priority 1, and a mark cleared there could run before that snapshot.
|
|
18
20
|
*/
|
|
19
21
|
export declare const FloorElevationSystem: () => null;
|
|
20
22
|
//# sourceMappingURL=floor-elevation-system.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"floor-elevation-system.d.ts","sourceRoot":"","sources":["../../../src/systems/floor-elevation/floor-elevation-system.tsx"],"names":[],"mappings":"AA8DA
|
|
1
|
+
{"version":3,"file":"floor-elevation-system.d.ts","sourceRoot":"","sources":["../../../src/systems/floor-elevation/floor-elevation-system.tsx"],"names":[],"mappings":"AA8DA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,oBAAoB,YAoNhC,CAAA"}
|
|
@@ -43,11 +43,17 @@ function restoreMountedExitPose(saved) {
|
|
|
43
43
|
* Runs at priority 1 — before the priority-2 systems (`GeometrySystem`,
|
|
44
44
|
* `ItemSystem`) so the dirty mark survives long enough for those to do
|
|
45
45
|
* their own work. Kinds with no geometry/system have no downstream dirty
|
|
46
|
-
* consumer, so this system clears their dirty mark after applying the lift
|
|
46
|
+
* consumer, so this system clears their dirty mark after applying the lift,
|
|
47
|
+
* at priority 2 like every other consumer: the node batch snapshots marks at
|
|
48
|
+
* priority 1, and a mark cleared there could run before that snapshot.
|
|
47
49
|
*/
|
|
48
50
|
export const FloorElevationSystem = () => {
|
|
49
51
|
const dirtyNodes = useScene((s) => s.dirtyNodes);
|
|
50
52
|
const clearDirty = useScene((s) => s.clearDirty);
|
|
53
|
+
const consumed = useMemo(() => new Set(), []);
|
|
54
|
+
// Meshes already lifted once. A mesh mounts at its base Y, and a remount (entering Preview
|
|
55
|
+
// builds a fresh viewer tree) raises no dirty mark, so the lift would never be applied.
|
|
56
|
+
const mounted = useMemo(() => ({ revision: -1, meshes: new WeakSet() }), []);
|
|
51
57
|
const preview = useMemo(() => ({
|
|
52
58
|
local: new Matrix4(),
|
|
53
59
|
target: new Matrix4(),
|
|
@@ -107,7 +113,8 @@ export const FloorElevationSystem = () => {
|
|
|
107
113
|
// during group drags over elevated slabs).
|
|
108
114
|
const overrides = useLiveNodeOverrides.getState().overrides;
|
|
109
115
|
const transforms = useLiveTransforms.getState().transforms;
|
|
110
|
-
|
|
116
|
+
const registryChanged = sceneRegistry.revision !== mounted.revision;
|
|
117
|
+
if (dirtyNodes.size === 0 && overrides.size === 0 && transforms.size === 0 && !registryChanged)
|
|
111
118
|
return;
|
|
112
119
|
const nodes = useScene.getState().nodes;
|
|
113
120
|
const applyLift = (id) => {
|
|
@@ -128,9 +135,11 @@ export const FloorElevationSystem = () => {
|
|
|
128
135
|
return;
|
|
129
136
|
if (effectiveNode.parentId !== node.parentId)
|
|
130
137
|
return;
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
138
|
+
// A mounted object still loading (a scripted column's artifact) keeps its mark, so
|
|
139
|
+
// scene-ready and bakes wait for it; settling marks the node dirty again.
|
|
140
|
+
const settled = def.capabilities?.batchable?.settled?.(mesh.userData) ?? true;
|
|
141
|
+
if (!(def.geometry || def.system) && dirtyNodes.has(id) && settled)
|
|
142
|
+
consumed.add(id);
|
|
134
143
|
// `applies === false` means the kind opts OUT of floor stacking for this
|
|
135
144
|
// node: its Y belongs to a host frame (a wall/ceiling-mounted item, a
|
|
136
145
|
// cabinet module inside a run, a wall duct terminal). `getFloorPlacedElevation`
|
|
@@ -162,6 +171,20 @@ export const FloorElevationSystem = () => {
|
|
|
162
171
|
});
|
|
163
172
|
mesh.position.y = visualPosition[1];
|
|
164
173
|
};
|
|
174
|
+
if (registryChanged) {
|
|
175
|
+
mounted.revision = sceneRegistry.revision;
|
|
176
|
+
for (const [kind, ids] of Object.entries(sceneRegistry.byType)) {
|
|
177
|
+
if (!nodeRegistry.get(kind)?.capabilities?.floorPlaced)
|
|
178
|
+
continue;
|
|
179
|
+
for (const id of ids) {
|
|
180
|
+
const mesh = sceneRegistry.nodes.get(id);
|
|
181
|
+
if (!mesh || mounted.meshes.has(mesh))
|
|
182
|
+
continue;
|
|
183
|
+
mounted.meshes.add(mesh);
|
|
184
|
+
applyLift(id);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
165
188
|
dirtyNodes.forEach((id) => {
|
|
166
189
|
applyLift(id);
|
|
167
190
|
});
|
|
@@ -174,6 +197,11 @@ export const FloorElevationSystem = () => {
|
|
|
174
197
|
applyLift(id);
|
|
175
198
|
});
|
|
176
199
|
}, 1);
|
|
200
|
+
useFrame(() => {
|
|
201
|
+
for (const id of consumed)
|
|
202
|
+
clearDirty(id);
|
|
203
|
+
consumed.clear();
|
|
204
|
+
}, 2);
|
|
177
205
|
// PostProcessing draws at priority 1 after this system; later callbacks would show one wrong frame per move.
|
|
178
206
|
useFrame(() => {
|
|
179
207
|
const nodes = useScene.getState().nodes;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"geometry-system.d.ts","sourceRoot":"","sources":["../../../src/systems/geometry/geometry-system.tsx"],"names":[],"mappings":"AAkBA,OAAO,EAAa,KAAK,KAAK,EAA4B,KAAK,QAAQ,EAAE,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"geometry-system.d.ts","sourceRoot":"","sources":["../../../src/systems/geometry/geometry-system.tsx"],"names":[],"mappings":"AAkBA,OAAO,EAAa,KAAK,KAAK,EAA4B,KAAK,QAAQ,EAAE,MAAM,OAAO,CAAA;AAatF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,eAAO,MAAM,cAAc,YA8N1B,CAAA;AA+KD,eAAe,cAAc,CAAA;AAE7B,MAAM,MAAM,uBAAuB,GAAG;IACpC,KAAK,EAAE,KAAK,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;CACZ,CAAA;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI,CAY7D;AAED,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,uBAAuB,CAAC,EAC3C,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,KAAK,EACZ,GAAG,EAAE,MAAM,GACV,OAAO,CAKT"}
|