@expofp/renderer 3.2.5 → 3.27.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 +111 -0
- package/dist/Renderer.d.ts +88 -0
- package/dist/Renderer.js +53 -0
- package/dist/controls/CameraControls.d.ts +102 -0
- package/dist/controls/CameraControls.js +239 -0
- package/dist/controls/camera-api.d.ts +206 -0
- package/dist/controls/camera-api.js +181 -0
- package/dist/controls/camera-move.d.ts +13 -0
- package/dist/controls/camera-move.js +18 -0
- package/dist/controls/camera-state.d.ts +40 -0
- package/dist/controls/camera-state.js +65 -0
- package/dist/controls/gestures.d.ts +70 -0
- package/dist/controls/gestures.js +84 -0
- package/dist/controls/handlers/Inertia.d.ts +111 -0
- package/dist/controls/handlers/Inertia.js +215 -0
- package/dist/controls/handlers/Pan.d.ts +23 -0
- package/dist/controls/handlers/Pan.js +32 -0
- package/dist/controls/handlers/Pitch.d.ts +94 -0
- package/dist/controls/handlers/Pitch.js +191 -0
- package/dist/controls/handlers/Roll.d.ts +103 -0
- package/dist/controls/handlers/Roll.js +182 -0
- package/dist/controls/handlers/Zoom.d.ts +15 -0
- package/dist/controls/handlers/Zoom.js +26 -0
- package/dist/controls/index.d.ts +56 -0
- package/dist/controls/index.js +58 -0
- package/dist/controls/zoom-to.d.ts +89 -0
- package/dist/controls/zoom-to.js +91 -0
- package/dist/core/InstanceUniforms.d.ts +93 -0
- package/dist/core/InstanceUniforms.js +266 -0
- package/dist/core/SquareDataTexture.d.ts +277 -0
- package/dist/core/SquareDataTexture.js +476 -0
- package/dist/core/batch/BatchedMesh.d.ts +74 -0
- package/dist/core/batch/BatchedMesh.js +149 -0
- package/dist/core/instanced/FrustumCulling.d.ts +141 -0
- package/dist/core/instanced/FrustumCulling.js +246 -0
- package/dist/core/instanced/InstancedMesh.d.ts +302 -0
- package/dist/core/instanced/InstancedMesh.js +497 -0
- package/dist/core/instanced/Instances.d.ts +119 -0
- package/dist/core/instanced/Instances.js +230 -0
- package/dist/core/instanced/Raycasting.d.ts +118 -0
- package/dist/core/instanced/Raycasting.js +134 -0
- package/dist/core/instanced/instanced-material.d.ts +77 -0
- package/dist/core/instanced/instanced-material.js +224 -0
- package/dist/core/lines/BatchedLines.d.ts +135 -0
- package/dist/core/lines/BatchedLines.js +213 -0
- package/dist/core/lines/FrustumCulling.d.ts +43 -0
- package/dist/core/lines/FrustumCulling.js +85 -0
- package/dist/core/lines/Raycasting.d.ts +44 -0
- package/dist/core/lines/Raycasting.js +91 -0
- package/dist/core/lines/lines-material.d.ts +47 -0
- package/dist/core/lines/lines-material.js +115 -0
- package/dist/core/shader-source.d.ts +50 -0
- package/dist/core/shader-source.js +84 -0
- package/dist/core/text/BatchedText.d.ts +227 -0
- package/dist/core/text/BatchedText.js +467 -0
- package/dist/core/text/MemberTexture.d.ts +90 -0
- package/dist/core/text/MemberTexture.js +194 -0
- package/dist/core/text/Text.d.ts +73 -0
- package/dist/core/text/Text.js +215 -0
- package/dist/core/text/batched-text-material.d.ts +56 -0
- package/dist/core/text/batched-text-material.js +121 -0
- package/dist/core/text/glyph-packing.d.ts +17 -0
- package/dist/core/text/glyph-packing.js +61 -0
- package/dist/core/typed-array.d.ts +16 -0
- package/dist/core/typed-array.js +20 -0
- package/dist/debug/components/DebugPanelProvider.d.ts +20 -0
- package/dist/debug/components/DebugPanelProvider.js +38 -0
- package/dist/debug/components/DebugTools.d.ts +22 -0
- package/dist/debug/components/DebugTools.js +28 -0
- package/dist/debug/components/Gui.d.ts +20 -0
- package/dist/debug/components/Gui.js +32 -0
- package/dist/debug/components/MemoryInfo.d.ts +22 -0
- package/dist/debug/components/MemoryInfo.js +42 -0
- package/dist/debug/components/Panel.d.ts +31 -0
- package/dist/debug/components/Panel.js +98 -0
- package/dist/debug/components/Stats.d.ts +9 -0
- package/dist/debug/components/Stats.js +24 -0
- package/dist/debug/debug-context.d.ts +41 -0
- package/dist/debug/debug-context.js +59 -0
- package/dist/debug/index.d.ts +51 -0
- package/dist/debug/index.js +64 -0
- package/dist/events/LayoutDriver.d.ts +31 -0
- package/dist/events/LayoutDriver.js +88 -0
- package/dist/events/PointerMissed.d.ts +23 -0
- package/dist/events/PointerMissed.js +58 -0
- package/dist/events/def-culling.d.ts +46 -0
- package/dist/events/def-culling.js +69 -0
- package/dist/events/layout-targets.d.ts +104 -0
- package/dist/events/layout-targets.js +245 -0
- package/dist/events/pointer.d.ts +118 -0
- package/dist/events/pointer.js +168 -0
- package/dist/external/ExternalCanvas.d.ts +56 -0
- package/dist/external/ExternalCanvas.js +178 -0
- package/dist/external/external-camera.d.ts +17 -0
- package/dist/external/external-camera.js +82 -0
- package/dist/external/external-events.d.ts +14 -0
- package/dist/external/external-events.js +33 -0
- package/dist/index.d.ts +11 -783
- package/dist/index.js +12 -8031
- package/dist/objects/Background.d.ts +31 -0
- package/dist/objects/Background.js +37 -0
- package/dist/objects/Lighting.d.ts +20 -0
- package/dist/objects/Lighting.js +85 -0
- package/dist/objects/containers/SlotContainer.d.ts +266 -0
- package/dist/objects/containers/SlotContainer.js +251 -0
- package/dist/objects/containers/hooks.d.ts +46 -0
- package/dist/objects/containers/hooks.js +118 -0
- package/dist/objects/containers/index.d.ts +6 -0
- package/dist/objects/containers/index.js +4 -0
- package/dist/objects/containers/keys.d.ts +10 -0
- package/dist/objects/containers/keys.js +18 -0
- package/dist/objects/containers/mesh-writes.d.ts +106 -0
- package/dist/objects/containers/mesh-writes.js +97 -0
- package/dist/objects/containers/props.d.ts +23 -0
- package/dist/objects/containers/props.js +1 -0
- package/dist/objects/images/ImageInstance.d.ts +29 -0
- package/dist/objects/images/ImageInstance.js +83 -0
- package/dist/objects/images/Images.d.ts +37 -0
- package/dist/objects/images/Images.js +204 -0
- package/dist/objects/images/atlas-packer.d.ts +128 -0
- package/dist/objects/images/atlas-packer.js +315 -0
- package/dist/objects/images/image-container.d.ts +51 -0
- package/dist/objects/images/image-container.js +70 -0
- package/dist/objects/images/index.d.ts +2 -0
- package/dist/objects/images/index.js +1 -0
- package/dist/objects/images/texture-budget.d.ts +120 -0
- package/dist/objects/images/texture-budget.js +215 -0
- package/dist/objects/layer/Layer.d.ts +27 -0
- package/dist/objects/layer/Layer.js +114 -0
- package/dist/objects/layer/index.d.ts +2 -0
- package/dist/objects/layer/index.js +1 -0
- package/dist/objects/layer/mount-scheduler.d.ts +102 -0
- package/dist/objects/layer/mount-scheduler.js +145 -0
- package/dist/objects/layer/visibility-gui.d.ts +19 -0
- package/dist/objects/layer/visibility-gui.js +93 -0
- package/dist/objects/lines/LineInstance.d.ts +21 -0
- package/dist/objects/lines/LineInstance.js +73 -0
- package/dist/objects/lines/Lines.d.ts +17 -0
- package/dist/objects/lines/Lines.js +29 -0
- package/dist/objects/lines/index.d.ts +2 -0
- package/dist/objects/lines/index.js +1 -0
- package/dist/objects/lines/line-container.d.ts +35 -0
- package/dist/objects/lines/line-container.js +40 -0
- package/dist/objects/materials/ColorMaterial.d.ts +85 -0
- package/dist/objects/materials/ColorMaterial.js +89 -0
- package/dist/objects/materials/LineMaterial.d.ts +44 -0
- package/dist/objects/materials/LineMaterial.js +72 -0
- package/dist/objects/materials/ModelMaterial.d.ts +41 -0
- package/dist/objects/materials/ModelMaterial.js +84 -0
- package/dist/objects/materials/TextureMaterial.d.ts +30 -0
- package/dist/objects/materials/TextureMaterial.js +29 -0
- package/dist/objects/materials/dim.d.ts +123 -0
- package/dist/objects/materials/dim.js +213 -0
- package/dist/objects/materials/shared.d.ts +6 -0
- package/dist/objects/materials/shared.js +51 -0
- package/dist/objects/models/ModelInstance.d.ts +22 -0
- package/dist/objects/models/ModelInstance.js +33 -0
- package/dist/objects/models/Models.d.ts +22 -0
- package/dist/objects/models/Models.js +177 -0
- package/dist/objects/models/gltf-cache.d.ts +17 -0
- package/dist/objects/models/gltf-cache.js +50 -0
- package/dist/objects/models/index.d.ts +2 -0
- package/dist/objects/models/index.js +1 -0
- package/dist/objects/models/model-asset.d.ts +48 -0
- package/dist/objects/models/model-asset.js +77 -0
- package/dist/objects/models/model-container.d.ts +139 -0
- package/dist/objects/models/model-container.js +227 -0
- package/dist/objects/shapes/ShapeInstance.d.ts +26 -0
- package/dist/objects/shapes/ShapeInstance.js +40 -0
- package/dist/objects/shapes/Shapes.d.ts +21 -0
- package/dist/objects/shapes/Shapes.js +120 -0
- package/dist/objects/shapes/index.d.ts +2 -0
- package/dist/objects/shapes/index.js +1 -0
- package/dist/objects/shapes/shape-container.d.ts +165 -0
- package/dist/objects/shapes/shape-container.js +272 -0
- package/dist/objects/shapes/shape-geometry.d.ts +27 -0
- package/dist/objects/shapes/shape-geometry.js +94 -0
- package/dist/objects/text/TextInstance.d.ts +22 -0
- package/dist/objects/text/TextInstance.js +95 -0
- package/dist/objects/text/Texts.d.ts +30 -0
- package/dist/objects/text/Texts.js +41 -0
- package/dist/objects/text/index.d.ts +2 -0
- package/dist/objects/text/index.js +1 -0
- package/dist/objects/text/text-container.d.ts +105 -0
- package/dist/objects/text/text-container.js +206 -0
- package/dist/objects/text/text-layout.d.ts +83 -0
- package/dist/objects/text/text-layout.js +154 -0
- package/dist/space/Camera.d.ts +103 -0
- package/dist/space/Camera.js +321 -0
- package/dist/space/Scene.d.ts +44 -0
- package/dist/space/Scene.js +112 -0
- package/dist/space/Space.d.ts +288 -0
- package/dist/space/Space.js +329 -0
- package/dist/space/VisibleRect.d.ts +72 -0
- package/dist/space/VisibleRect.js +129 -0
- package/dist/space/camera-handle.d.ts +67 -0
- package/dist/space/camera-handle.js +63 -0
- package/dist/space/camera-kind.d.ts +26 -0
- package/dist/space/camera-kind.js +30 -0
- package/dist/space/canvas-size.d.ts +24 -0
- package/dist/space/canvas-size.js +20 -0
- package/dist/space/clipping.d.ts +55 -0
- package/dist/space/clipping.js +108 -0
- package/dist/space/layout-measure.d.ts +65 -0
- package/dist/space/layout-measure.js +173 -0
- package/dist/space/viewport.d.ts +112 -0
- package/dist/space/viewport.js +67 -0
- package/dist/types/defs.d.ts +169 -0
- package/dist/types/defs.js +1 -0
- package/dist/types/events.d.ts +183 -0
- package/dist/types/events.js +1 -0
- package/dist/types/guards.d.ts +14 -0
- package/dist/types/guards.js +42 -0
- package/dist/update/index.d.ts +3 -0
- package/dist/update/index.js +2 -0
- package/dist/update/slot-writers.d.ts +30 -0
- package/dist/update/slot-writers.js +72 -0
- package/dist/update/store.d.ts +41 -0
- package/dist/update/store.js +98 -0
- package/dist/utils/arrays.d.ts +13 -0
- package/dist/utils/arrays.js +20 -0
- package/dist/utils/colors.d.ts +19 -0
- package/dist/utils/colors.js +27 -0
- package/dist/utils/logging.d.ts +26 -0
- package/dist/utils/logging.js +47 -0
- package/dist/utils/math.d.ts +24 -0
- package/dist/utils/math.js +27 -0
- package/package.json +67 -19
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { type CanvasProps } from '@react-three/fiber';
|
|
2
|
+
import { type ReactNode } from 'react';
|
|
3
|
+
/**
|
|
4
|
+
* Loads the debug chunk ahead of time — for a host that creates its own WebGL context.
|
|
5
|
+
*
|
|
6
|
+
* The chunk's evaluation is what instruments context creation for the GPU-memory panel
|
|
7
|
+
* (webgl-memory patches `getContext` as it loads), so a context created before it exists can never
|
|
8
|
+
* report memory figures. The renderer's own mount orders this itself; a MapLibre host does it by
|
|
9
|
+
* awaiting this before constructing the map, when debug is on. Idempotent, and the only eager cost
|
|
10
|
+
* is the call: the debug code still lives in its own lazy chunk.
|
|
11
|
+
*/
|
|
12
|
+
export declare function prepareDebug(): Promise<void>;
|
|
13
|
+
/** Props for {@link CanvasWithDebug}: the Canvas props plus the debug toggle. */
|
|
14
|
+
export interface CanvasWithDebugProps extends CanvasProps {
|
|
15
|
+
/** When falsy, the Canvas mounts untouched and no debug code is loaded. */
|
|
16
|
+
debugEnabled?: boolean;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The renderer's own Canvas with the debug ordering folded in: when `debugEnabled`, it suspends —
|
|
20
|
+
* into the boundary its parent provides — until the debug chunk has loaded, so the chunk's
|
|
21
|
+
* webgl-memory patch lands *before* the Canvas creates its context and the context is born
|
|
22
|
+
* instrumented. That ordering is this component's whole job, and it has to sit above `<Canvas>`:
|
|
23
|
+
* children mount only after the root is configured, which is after the context exists, so nothing
|
|
24
|
+
* inside the tree could order it. The overlay itself is {@link DebugOverlay}'s, inside the tree,
|
|
25
|
+
* the same in both mounts.
|
|
26
|
+
*
|
|
27
|
+
* Turning `debugEnabled` on at runtime is not supported: React keeps a suspending, already-mounted
|
|
28
|
+
* Canvas alive through the fallback, so the context is never recreated and the patch arrives too
|
|
29
|
+
* late for it. `debug` is derived from a module constant fixed for the session, so this never
|
|
30
|
+
* happens in practice.
|
|
31
|
+
* @param props - `debugEnabled` plus the Canvas props; `children` is the scene.
|
|
32
|
+
* @returns The Canvas, its context creation deferred behind the debug chunk when enabled.
|
|
33
|
+
*/
|
|
34
|
+
export declare function CanvasWithDebug(props: CanvasWithDebugProps): ReactNode;
|
|
35
|
+
/** Props for {@link DebugOverlay}: the toggle and the tree it may instrument. */
|
|
36
|
+
export interface DebugOverlayProps {
|
|
37
|
+
/** When falsy, the children render untouched and no debug code is loaded. */
|
|
38
|
+
enabled?: boolean;
|
|
39
|
+
/** The scene tree. */
|
|
40
|
+
children?: ReactNode;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Mounts the debug overlay around the scene tree when enabled — the same element in both mounts,
|
|
44
|
+
* which is what makes `debug` a shared prop: the GUI, the panels and the stats attach to the
|
|
45
|
+
* document, not to whichever canvas is drawing. Lazy behind the shared debug chunk; disabled, it
|
|
46
|
+
* is the children and nothing else.
|
|
47
|
+
* @param props - The toggle and the tree.
|
|
48
|
+
* @returns The tree, instrumented when enabled.
|
|
49
|
+
*/
|
|
50
|
+
export declare function DebugOverlay(props: DebugOverlayProps): ReactNode;
|
|
51
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Canvas } from '@react-three/fiber';
|
|
3
|
+
import { lazy, Suspense, use } from 'react';
|
|
4
|
+
/**
|
|
5
|
+
* The one debug chunk, shared by every consumer: the internal mount's context-patch gate, the
|
|
6
|
+
* overlay in both mounts' trees, and {@link prepareDebug}. Memoized so `use()` sees a stable
|
|
7
|
+
* promise and the chunk is fetched once.
|
|
8
|
+
*/
|
|
9
|
+
let debugChunk;
|
|
10
|
+
function loadDebugChunk() {
|
|
11
|
+
debugChunk ??= import('./components/DebugTools');
|
|
12
|
+
return debugChunk;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Loads the debug chunk ahead of time — for a host that creates its own WebGL context.
|
|
16
|
+
*
|
|
17
|
+
* The chunk's evaluation is what instruments context creation for the GPU-memory panel
|
|
18
|
+
* (webgl-memory patches `getContext` as it loads), so a context created before it exists can never
|
|
19
|
+
* report memory figures. The renderer's own mount orders this itself; a MapLibre host does it by
|
|
20
|
+
* awaiting this before constructing the map, when debug is on. Idempotent, and the only eager cost
|
|
21
|
+
* is the call: the debug code still lives in its own lazy chunk.
|
|
22
|
+
*/
|
|
23
|
+
export async function prepareDebug() {
|
|
24
|
+
await loadDebugChunk();
|
|
25
|
+
}
|
|
26
|
+
const DebugTools = lazy(() => import('./components/DebugTools').then((module) => ({ default: module.DebugTools })));
|
|
27
|
+
/**
|
|
28
|
+
* The renderer's own Canvas with the debug ordering folded in: when `debugEnabled`, it suspends —
|
|
29
|
+
* into the boundary its parent provides — until the debug chunk has loaded, so the chunk's
|
|
30
|
+
* webgl-memory patch lands *before* the Canvas creates its context and the context is born
|
|
31
|
+
* instrumented. That ordering is this component's whole job, and it has to sit above `<Canvas>`:
|
|
32
|
+
* children mount only after the root is configured, which is after the context exists, so nothing
|
|
33
|
+
* inside the tree could order it. The overlay itself is {@link DebugOverlay}'s, inside the tree,
|
|
34
|
+
* the same in both mounts.
|
|
35
|
+
*
|
|
36
|
+
* Turning `debugEnabled` on at runtime is not supported: React keeps a suspending, already-mounted
|
|
37
|
+
* Canvas alive through the fallback, so the context is never recreated and the patch arrives too
|
|
38
|
+
* late for it. `debug` is derived from a module constant fixed for the session, so this never
|
|
39
|
+
* happens in practice.
|
|
40
|
+
* @param props - `debugEnabled` plus the Canvas props; `children` is the scene.
|
|
41
|
+
* @returns The Canvas, its context creation deferred behind the debug chunk when enabled.
|
|
42
|
+
*/
|
|
43
|
+
export function CanvasWithDebug(props) {
|
|
44
|
+
const { debugEnabled, children, ...canvasProps } = props;
|
|
45
|
+
// `use` is built for conditional calls, and the condition is the point: an undebugged mount
|
|
46
|
+
// never touches the chunk.
|
|
47
|
+
if (debugEnabled)
|
|
48
|
+
use(loadDebugChunk());
|
|
49
|
+
return _jsx(Canvas, { ...canvasProps, children: children });
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Mounts the debug overlay around the scene tree when enabled — the same element in both mounts,
|
|
53
|
+
* which is what makes `debug` a shared prop: the GUI, the panels and the stats attach to the
|
|
54
|
+
* document, not to whichever canvas is drawing. Lazy behind the shared debug chunk; disabled, it
|
|
55
|
+
* is the children and nothing else.
|
|
56
|
+
* @param props - The toggle and the tree.
|
|
57
|
+
* @returns The tree, instrumented when enabled.
|
|
58
|
+
*/
|
|
59
|
+
export function DebugOverlay(props) {
|
|
60
|
+
const { enabled, children } = props;
|
|
61
|
+
if (!enabled)
|
|
62
|
+
return children;
|
|
63
|
+
return (_jsx(Suspense, { fallback: null, children: _jsx(DebugTools, { children: children }) }));
|
|
64
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
/** Props for {@link LayoutDriver}. */
|
|
3
|
+
export interface LayoutDriverProps {
|
|
4
|
+
/** The scene whose defs register as re-layout targets. */
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Drives camera-driven re-layout: it owns the renderer's {@link LayoutTargets} and watches both
|
|
9
|
+
* layout axes every frame — the pixel size, swept past an epsilon, and the roll, swept on any
|
|
10
|
+
* change — running each registered def's stale rules and writing back whatever they report changed.
|
|
11
|
+
*
|
|
12
|
+
* It runs at the default frame priority, after the controls have updated the camera at `-1`, so a
|
|
13
|
+
* frame lays out against the camera it is about to draw. And it runs only on frames something asked
|
|
14
|
+
* for: under the on-demand loop the camera's own movement is what requests them, so a still plan
|
|
15
|
+
* costs nothing at all.
|
|
16
|
+
*
|
|
17
|
+
* A move starts a **sweep**, never a synchronous pass: each frame drains the registry's backlog for
|
|
18
|
+
* at most {@link LAYOUT_BUDGET_MS}, defs inside the camera's frustum first, and asks for another
|
|
19
|
+
* frame while any backlog remains — so a plan of ten thousand labels re-lays out over a handful of
|
|
20
|
+
* frames instead of stalling one, and what the user is looking at is what lands first. The layouts
|
|
21
|
+
* stay inside the frame callback, before three's own render, so their attribute writes upload in
|
|
22
|
+
* the very frame that draws them.
|
|
23
|
+
*
|
|
24
|
+
* No React is involved in a re-layout. The handlers mutate def fields and the defs' own sync closures
|
|
25
|
+
* write them, so a zoom does not re-render a single component — which is what makes it affordable for
|
|
26
|
+
* every label in a plan to re-lay out while the camera moves.
|
|
27
|
+
* @param props - The scene to provide the registry to.
|
|
28
|
+
* @returns The scene, under the registry.
|
|
29
|
+
*/
|
|
30
|
+
export declare function LayoutDriver(props: LayoutDriverProps): import("react").JSX.Element;
|
|
31
|
+
//# sourceMappingURL=LayoutDriver.d.ts.map
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useFrame, useThree } from '@react-three/fiber';
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { Frustum } from 'three';
|
|
5
|
+
import { useCameraControls } from '../controls';
|
|
6
|
+
import { measurePixelSize, measureRoll, pixelSizeMoved } from '../space/layout-measure';
|
|
7
|
+
import { useSpace } from '../space/Space';
|
|
8
|
+
import { createLogger } from '../utils/logging';
|
|
9
|
+
import { planFrustum } from './def-culling';
|
|
10
|
+
import { createLayoutTargets, LayoutTargetsContext } from './layout-targets';
|
|
11
|
+
const logger = createLogger('layout');
|
|
12
|
+
/**
|
|
13
|
+
* How much of a frame one drain may spend running layout rules, in milliseconds — the same budget
|
|
14
|
+
* the legacy renderer's `UpdatesSystem` drained its update queue with. Small enough to leave a
|
|
15
|
+
* 60fps frame its render; the backlog it leaves is carried into the next frame, visible defs first.
|
|
16
|
+
*/
|
|
17
|
+
const LAYOUT_BUDGET_MS = 3;
|
|
18
|
+
/**
|
|
19
|
+
* Drives camera-driven re-layout: it owns the renderer's {@link LayoutTargets} and watches both
|
|
20
|
+
* layout axes every frame — the pixel size, swept past an epsilon, and the roll, swept on any
|
|
21
|
+
* change — running each registered def's stale rules and writing back whatever they report changed.
|
|
22
|
+
*
|
|
23
|
+
* It runs at the default frame priority, after the controls have updated the camera at `-1`, so a
|
|
24
|
+
* frame lays out against the camera it is about to draw. And it runs only on frames something asked
|
|
25
|
+
* for: under the on-demand loop the camera's own movement is what requests them, so a still plan
|
|
26
|
+
* costs nothing at all.
|
|
27
|
+
*
|
|
28
|
+
* A move starts a **sweep**, never a synchronous pass: each frame drains the registry's backlog for
|
|
29
|
+
* at most {@link LAYOUT_BUDGET_MS}, defs inside the camera's frustum first, and asks for another
|
|
30
|
+
* frame while any backlog remains — so a plan of ten thousand labels re-lays out over a handful of
|
|
31
|
+
* frames instead of stalling one, and what the user is looking at is what lands first. The layouts
|
|
32
|
+
* stay inside the frame callback, before three's own render, so their attribute writes upload in
|
|
33
|
+
* the very frame that draws them.
|
|
34
|
+
*
|
|
35
|
+
* No React is involved in a re-layout. The handlers mutate def fields and the defs' own sync closures
|
|
36
|
+
* write them, so a zoom does not re-render a single component — which is what makes it affordable for
|
|
37
|
+
* every label in a plan to re-lay out while the camera moves.
|
|
38
|
+
* @param props - The scene to provide the registry to.
|
|
39
|
+
* @returns The scene, under the registry.
|
|
40
|
+
*/
|
|
41
|
+
export function LayoutDriver(props) {
|
|
42
|
+
const { children } = props;
|
|
43
|
+
const camera = useThree((state) => state.camera);
|
|
44
|
+
const gl = useThree((state) => state.gl);
|
|
45
|
+
const invalidate = useThree((state) => state.invalidate);
|
|
46
|
+
const controls = useCameraControls();
|
|
47
|
+
const space = useSpace();
|
|
48
|
+
// Seeded from the camera as it stands, so defs registering before the first frame are laid out at
|
|
49
|
+
// the size they will be drawn at rather than at a placeholder. The measurement asks nothing of
|
|
50
|
+
// the controls — absent at this point whatever the mount order, since they publish themselves in
|
|
51
|
+
// an effect and this runs during render — which is also what lets this component be rendered,
|
|
52
|
+
// and tested, without any controls at all.
|
|
53
|
+
const [targets] = useState(() => createLayoutTargets(invalidate, measurePixelSize(camera, space, gl.domElement.width) ?? 1, measureRoll(camera, space, gl.domElement.width, gl.domElement.height) ?? 0));
|
|
54
|
+
useFrame((state) => {
|
|
55
|
+
const camera = state.camera;
|
|
56
|
+
const { width, height } = state.gl.domElement;
|
|
57
|
+
// One call for every camera — the renderer's own and external mode's folded matrix alike. The
|
|
58
|
+
// controls are handed over rather than branched on here: with them the reading is the cheap
|
|
59
|
+
// arithmetic the imperative renderer used, and without them it is measured off the matrices,
|
|
60
|
+
// which both cameras carry.
|
|
61
|
+
const pixelSize = measurePixelSize(camera, space, width, controls);
|
|
62
|
+
// The epsilon compares against the sweep's target size, so a camera that stopped mid-sweep does
|
|
63
|
+
// not re-mark the same sweep on every one of the frames that finish it.
|
|
64
|
+
if (pixelSize !== undefined && pixelSizeMoved(pixelSize, targets.pixelSize)) {
|
|
65
|
+
logger.debug(`pxToSvgScale ${+pixelSize.toFixed(3)}`);
|
|
66
|
+
targets.applyScale(pixelSize);
|
|
67
|
+
}
|
|
68
|
+
// Roll has no epsilon — the imperative renderer swept its roll handlers on any bearing change
|
|
69
|
+
// at all, and the rules themselves step in quarter turns, so almost every layout is a cheap
|
|
70
|
+
// no-write. Which of the two ways it is reached — the controls' own angle, or a measurement off
|
|
71
|
+
// the camera for external mode and bare scenes — is `measureRoll`'s to choose.
|
|
72
|
+
const roll = measureRoll(camera, space, width, height, controls);
|
|
73
|
+
if (roll !== undefined && roll !== targets.roll)
|
|
74
|
+
targets.applyRoll(roll);
|
|
75
|
+
if (!targets.hasWork)
|
|
76
|
+
return;
|
|
77
|
+
// Priority, never correctness: the frustum only decides who waits, and it is rebuilt each drain
|
|
78
|
+
// so a camera that pans mid-sweep re-prioritizes what is left.
|
|
79
|
+
const frustum = planFrustum(state.camera, space.matrix, _frustum);
|
|
80
|
+
// The writes self-invalidate through the defs' slot writers; this asks for the *extra* frame a
|
|
81
|
+
// leftover backlog needs, which is what keeps the demand loop ticking until the sweep is done.
|
|
82
|
+
if (targets.drain(frustum, LAYOUT_BUDGET_MS))
|
|
83
|
+
invalidate();
|
|
84
|
+
});
|
|
85
|
+
return _jsx(LayoutTargetsContext, { value: targets, children: children });
|
|
86
|
+
}
|
|
87
|
+
// Scratch for the drain's frustum, filled and consumed within one frame callback.
|
|
88
|
+
const _frustum = new Frustum();
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type PointerMissedEventData } from '../types/events';
|
|
2
|
+
/** Props for {@link PointerMissed}. */
|
|
3
|
+
export interface PointerMissedProps {
|
|
4
|
+
/** Called for a click that reached no layer handler. */
|
|
5
|
+
onPointerMissed?: (event: PointerMissedEventData) => void;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Publishes the renderer's missed-click handler, wrapped so it reports a plan position rather than
|
|
9
|
+
* the bare DOM event R3F hands out.
|
|
10
|
+
*
|
|
11
|
+
* Two reasons this is a component inside the canvas rather than the `onPointerMissed` prop `<Canvas>`
|
|
12
|
+
* already accepts. The position is only computable here: R3F sets up the pointer ray before deciding
|
|
13
|
+
* a click reached no handler, so the ray is still current when this runs and the scene can be
|
|
14
|
+
* searched along it — which is what a miss needs, since reaching no *handler* is not the same as
|
|
15
|
+
* striking nothing. And the canvas prop is effectively write-once —
|
|
16
|
+
* R3F copies it into its store under `if (!state.onPointerMissed)`, so a caller swapping the handler
|
|
17
|
+
* would keep firing the first one. Setting the store directly re-publishes on every change and clears
|
|
18
|
+
* the slot on unmount.
|
|
19
|
+
* @param props - The handler to publish.
|
|
20
|
+
* @returns Nothing; this renders no scene node.
|
|
21
|
+
*/
|
|
22
|
+
export declare function PointerMissed(props: PointerMissedProps): null;
|
|
23
|
+
//# sourceMappingURL=PointerMissed.d.ts.map
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { useThree } from '@react-three/fiber';
|
|
2
|
+
import { useEffect, useEffectEvent } from 'react';
|
|
3
|
+
import { useSpace } from '../space/Space';
|
|
4
|
+
import { missedPoint } from './pointer';
|
|
5
|
+
/**
|
|
6
|
+
* Publishes the renderer's missed-click handler, wrapped so it reports a plan position rather than
|
|
7
|
+
* the bare DOM event R3F hands out.
|
|
8
|
+
*
|
|
9
|
+
* Two reasons this is a component inside the canvas rather than the `onPointerMissed` prop `<Canvas>`
|
|
10
|
+
* already accepts. The position is only computable here: R3F sets up the pointer ray before deciding
|
|
11
|
+
* a click reached no handler, so the ray is still current when this runs and the scene can be
|
|
12
|
+
* searched along it — which is what a miss needs, since reaching no *handler* is not the same as
|
|
13
|
+
* striking nothing. And the canvas prop is effectively write-once —
|
|
14
|
+
* R3F copies it into its store under `if (!state.onPointerMissed)`, so a caller swapping the handler
|
|
15
|
+
* would keep firing the first one. Setting the store directly re-publishes on every change and clears
|
|
16
|
+
* the slot on unmount.
|
|
17
|
+
* @param props - The handler to publish.
|
|
18
|
+
* @returns Nothing; this renders no scene node.
|
|
19
|
+
*/
|
|
20
|
+
export function PointerMissed(props) {
|
|
21
|
+
const { onPointerMissed } = props;
|
|
22
|
+
const raycaster = useThree((state) => state.raycaster);
|
|
23
|
+
const scene = useThree((state) => state.scene);
|
|
24
|
+
const set = useThree((state) => state.set);
|
|
25
|
+
const space = useSpace();
|
|
26
|
+
/**
|
|
27
|
+
* Reports a missed click at the pointer's plan position.
|
|
28
|
+
*
|
|
29
|
+
* An effect event rather than a closure the publish effect rebuilds: the handler, the scene and
|
|
30
|
+
* the space are read fresh when a click arrives, so none of them is a dependency of the effect
|
|
31
|
+
* below. The space is the one that matters — a resize refits it on every step, and a publish that
|
|
32
|
+
* depended on it wrote the store twice per step, notifying every `useThree` subscriber in the
|
|
33
|
+
* renderer each time.
|
|
34
|
+
* **Clicks only, where R3F counts three events as one.** It dispatches this for `contextmenu` and
|
|
35
|
+
* `dblclick` as readily as for `click`, and a browser fires `contextmenu` on the *press* rather
|
|
36
|
+
* than the release — so a right-drag, which is how a pitch gesture begins, would report a miss
|
|
37
|
+
* before the gesture had moved at all, and a double-click would report a third on top of the two
|
|
38
|
+
* clicks that composed it. Only a real click has missed anything.
|
|
39
|
+
* @param nativeEvent - The DOM event; anything but a click is not one.
|
|
40
|
+
*/
|
|
41
|
+
const handleMissed = useEffectEvent((nativeEvent) => {
|
|
42
|
+
if (nativeEvent.type !== 'click')
|
|
43
|
+
return;
|
|
44
|
+
onPointerMissed?.({
|
|
45
|
+
point: missedPoint(raycaster, scene, space),
|
|
46
|
+
nativeEvent,
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
// Republished only when the caller's handler appears or disappears; which function it currently
|
|
50
|
+
// is stays out of the dependencies, like the space, because the effect event reads it at click
|
|
51
|
+
// time.
|
|
52
|
+
const handles = onPointerMissed !== undefined;
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
set({ onPointerMissed: handles ? handleMissed : undefined });
|
|
55
|
+
return () => set({ onPointerMissed: undefined });
|
|
56
|
+
}, [handles, set]);
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { type Rect } from '@expofp/geometry';
|
|
2
|
+
import { type Camera, Frustum, Matrix4, Sphere } from 'three';
|
|
3
|
+
import { type RenderableDef } from '../types/defs';
|
|
4
|
+
/**
|
|
5
|
+
* Encloses a def's bounds in a sphere the frustum can test, rotation-invariant by construction.
|
|
6
|
+
*
|
|
7
|
+
* Ported from the imperative renderer's `computeBoundingSphere` (fp-engine
|
|
8
|
+
* `renderer/src/util/geometry.ts`), which the legacy `UpdatesSystem` culled its update queue with.
|
|
9
|
+
* The sphere is centered at `bounds.center` — the rotation pivot — with a radius reaching the
|
|
10
|
+
* furthest corner of the rendered content, so no rotation can swing the content outside it. An
|
|
11
|
+
* `origin` (an image's anchor) shifts which part of the content hangs off the pivot, which widens
|
|
12
|
+
* the radius but never moves the center.
|
|
13
|
+
* @param bounds - The def's bounds.
|
|
14
|
+
* @param origin - The image anchor in `[0..1, 0..1]`, when the def has one; centered otherwise.
|
|
15
|
+
* @param out - Receives the result.
|
|
16
|
+
* @returns The sphere, in plan space.
|
|
17
|
+
*/
|
|
18
|
+
export declare function boundingSphereOf(bounds: Rect, origin: [number, number] | undefined, out: Sphere): Sphere;
|
|
19
|
+
/**
|
|
20
|
+
* Whether a def is entirely off screen, for the drain that lays visible defs out first.
|
|
21
|
+
*
|
|
22
|
+
* Only text and image defs are tested — the def kinds with one cheap `bounds` enclosure, and the
|
|
23
|
+
* bulk of any plan's re-layout targets (labels, dots, icons, markers). Everything else answers
|
|
24
|
+
* "not culled" and takes the priority pass, exactly as the legacy `UpdatesSystem` treated it.
|
|
25
|
+
* A `true` is a **priority** signal, never a correctness one: a culled def must still be laid out,
|
|
26
|
+
* just after the ones the camera can see.
|
|
27
|
+
* @param def - The def to test.
|
|
28
|
+
* @param frustum - The camera's frustum, in plan space — see {@link planFrustum}.
|
|
29
|
+
* @returns Whether the def can wait.
|
|
30
|
+
*/
|
|
31
|
+
export declare function culledBy(def: RenderableDef, frustum: Frustum): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* The camera's frustum brought into plan space, where def bounds live.
|
|
34
|
+
*
|
|
35
|
+
* The same composition the imperative renderer's `computeFrustumInModelSpace` used, with the
|
|
36
|
+
* scene's plan → world matrix standing in for the scene's `matrixWorld`: projecting through
|
|
37
|
+
* `projection · viewInverse · plan` makes the frustum's planes answer for plan coordinates
|
|
38
|
+
* directly, so a def is tested where it is authored and nothing per-def is transformed.
|
|
39
|
+
* @param camera - The camera in use.
|
|
40
|
+
* @param planMatrix - The plan → world matrix, from the scene's `Space`.
|
|
41
|
+
* @param out - A frustum to write into. Omit it and each call allocates, which is what makes the
|
|
42
|
+
* result safe to keep.
|
|
43
|
+
* @returns The frustum.
|
|
44
|
+
*/
|
|
45
|
+
export declare function planFrustum(camera: Camera, planMatrix: Matrix4, out?: Frustum): Frustum;
|
|
46
|
+
//# sourceMappingURL=def-culling.d.ts.map
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Frustum, Matrix4, Sphere, Vector3 } from 'three';
|
|
2
|
+
import { isImageDef, isTextDef } from '../types/guards';
|
|
3
|
+
/**
|
|
4
|
+
* Encloses a def's bounds in a sphere the frustum can test, rotation-invariant by construction.
|
|
5
|
+
*
|
|
6
|
+
* Ported from the imperative renderer's `computeBoundingSphere` (fp-engine
|
|
7
|
+
* `renderer/src/util/geometry.ts`), which the legacy `UpdatesSystem` culled its update queue with.
|
|
8
|
+
* The sphere is centered at `bounds.center` — the rotation pivot — with a radius reaching the
|
|
9
|
+
* furthest corner of the rendered content, so no rotation can swing the content outside it. An
|
|
10
|
+
* `origin` (an image's anchor) shifts which part of the content hangs off the pivot, which widens
|
|
11
|
+
* the radius but never moves the center.
|
|
12
|
+
* @param bounds - The def's bounds.
|
|
13
|
+
* @param origin - The image anchor in `[0..1, 0..1]`, when the def has one; centered otherwise.
|
|
14
|
+
* @param out - Receives the result.
|
|
15
|
+
* @returns The sphere, in plan space.
|
|
16
|
+
*/
|
|
17
|
+
export function boundingSphereOf(bounds, origin, out) {
|
|
18
|
+
const originX = origin?.[0] ?? 0.5;
|
|
19
|
+
const originY = origin?.[1] ?? 0.5;
|
|
20
|
+
const reachX = Math.max(originX, 1 - originX) * bounds.size.x;
|
|
21
|
+
const reachY = Math.max(originY, 1 - originY) * bounds.size.y;
|
|
22
|
+
_center.set(bounds.center.x, bounds.center.y, bounds.elevation);
|
|
23
|
+
out.set(_center, Math.hypot(reachX, reachY));
|
|
24
|
+
return out;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Whether a def is entirely off screen, for the drain that lays visible defs out first.
|
|
28
|
+
*
|
|
29
|
+
* Only text and image defs are tested — the def kinds with one cheap `bounds` enclosure, and the
|
|
30
|
+
* bulk of any plan's re-layout targets (labels, dots, icons, markers). Everything else answers
|
|
31
|
+
* "not culled" and takes the priority pass, exactly as the legacy `UpdatesSystem` treated it.
|
|
32
|
+
* A `true` is a **priority** signal, never a correctness one: a culled def must still be laid out,
|
|
33
|
+
* just after the ones the camera can see.
|
|
34
|
+
* @param def - The def to test.
|
|
35
|
+
* @param frustum - The camera's frustum, in plan space — see {@link planFrustum}.
|
|
36
|
+
* @returns Whether the def can wait.
|
|
37
|
+
*/
|
|
38
|
+
export function culledBy(def, frustum) {
|
|
39
|
+
if (isTextDef(def)) {
|
|
40
|
+
return !frustum.intersectsSphere(boundingSphereOf(def.bounds, undefined, _sphere));
|
|
41
|
+
}
|
|
42
|
+
if (isImageDef(def)) {
|
|
43
|
+
return !frustum.intersectsSphere(boundingSphereOf(def.bounds, def.origin, _sphere));
|
|
44
|
+
}
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* The camera's frustum brought into plan space, where def bounds live.
|
|
49
|
+
*
|
|
50
|
+
* The same composition the imperative renderer's `computeFrustumInModelSpace` used, with the
|
|
51
|
+
* scene's plan → world matrix standing in for the scene's `matrixWorld`: projecting through
|
|
52
|
+
* `projection · viewInverse · plan` makes the frustum's planes answer for plan coordinates
|
|
53
|
+
* directly, so a def is tested where it is authored and nothing per-def is transformed.
|
|
54
|
+
* @param camera - The camera in use.
|
|
55
|
+
* @param planMatrix - The plan → world matrix, from the scene's `Space`.
|
|
56
|
+
* @param out - A frustum to write into. Omit it and each call allocates, which is what makes the
|
|
57
|
+
* result safe to keep.
|
|
58
|
+
* @returns The frustum.
|
|
59
|
+
*/
|
|
60
|
+
export function planFrustum(camera, planMatrix, out = new Frustum()) {
|
|
61
|
+
_frustumMatrix
|
|
62
|
+
.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse)
|
|
63
|
+
.multiply(planMatrix);
|
|
64
|
+
return out.setFromProjectionMatrix(_frustumMatrix, camera.coordinateSystem);
|
|
65
|
+
}
|
|
66
|
+
// Scratch, each filled and consumed within one synchronous call.
|
|
67
|
+
const _center = new Vector3();
|
|
68
|
+
const _sphere = new Sphere();
|
|
69
|
+
const _frustumMatrix = new Matrix4();
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { type Frustum } from 'three';
|
|
2
|
+
import { type LayerDef, type RenderableDef } from '../types/defs';
|
|
3
|
+
/**
|
|
4
|
+
* The defs a renderer re-lays out when the camera moves: the pixel size and the roll are the two
|
|
5
|
+
* layout axes.
|
|
6
|
+
*
|
|
7
|
+
* Every def here declares its own `onScale` or `onRoll` — the registry never holds a handler, only
|
|
8
|
+
* the value each def's rule last ran at, per axis. One registry per renderer, reached through {@link LayoutTargetsContext},
|
|
9
|
+
* so two renderers showing the same defs at different zooms do not lay each other's out.
|
|
10
|
+
*
|
|
11
|
+
* A pixel-size move is a **sweep**, not a synchronous pass: {@link applyScale} marks every registered def
|
|
12
|
+
* stale and {@link drain} works the backlog off a frame's budget at a time, defs the camera can see
|
|
13
|
+
* first. The shape is the legacy renderer's `UpdatesSystem` (fp-engine `core/updates.ts`), whose
|
|
14
|
+
* pending/deferred queues and per-frame time budget this registry inherits — with the queue's unit
|
|
15
|
+
* changed from "def whose fields moved" to "def whose layout rule must re-run".
|
|
16
|
+
*/
|
|
17
|
+
export interface LayoutTargets {
|
|
18
|
+
/**
|
|
19
|
+
* The pixel size the registered defs are laid out at — from the moment {@link applyScale} marks a
|
|
20
|
+
* sweep, the size defs are being *brought* to, which is what the driver's epsilon must compare
|
|
21
|
+
* against so a camera that stopped moving does not re-mark the same sweep every frame.
|
|
22
|
+
*/
|
|
23
|
+
readonly pixelSize: number;
|
|
24
|
+
/**
|
|
25
|
+
* The roll the registered defs are laid out at, in radians clockwise from north — the second
|
|
26
|
+
* layout axis, compared the way {@link pixelSize} is: against the sweep's target, not the last
|
|
27
|
+
* drained value.
|
|
28
|
+
*/
|
|
29
|
+
readonly roll: number;
|
|
30
|
+
/** Whether a sweep still has defs to lay out — what makes a caller keep frames coming. */
|
|
31
|
+
readonly hasWork: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Registers defs for re-layout, and lays out the ones that are not current — so a def is current
|
|
34
|
+
* from the moment it is registered, and a membership change re-lays out only what it added.
|
|
35
|
+
* @param defs - The defs to lay out; every one of them declares an `onScale` or an `onRoll`.
|
|
36
|
+
* @returns An unregister function; it also drops whatever of these defs a sweep still queued.
|
|
37
|
+
*/
|
|
38
|
+
register(defs: readonly RenderableDef[]): () => void;
|
|
39
|
+
/**
|
|
40
|
+
* Starts a sweep: records the new pixel size and marks every registered def stale. Nothing is
|
|
41
|
+
* laid out here — that is {@link drain}'s job — so the frame that noticed the move pays only the
|
|
42
|
+
* marking. Applying again mid-sweep re-marks at the newer size, and a def the earlier sweep had
|
|
43
|
+
* not reached is simply laid out once, at that newer size: the backlog coalesces by construction.
|
|
44
|
+
* @param pixelSize - The new pixel size.
|
|
45
|
+
*/
|
|
46
|
+
applyScale(pixelSize: number): void;
|
|
47
|
+
/**
|
|
48
|
+
* Starts a roll sweep — {@link applyScale}'s counterpart on the other axis, marking only the defs that
|
|
49
|
+
* declare an `onRoll`. The two axes coalesce independently, and one {@link drain} works both off.
|
|
50
|
+
* @param roll - The new roll, in radians clockwise from north.
|
|
51
|
+
*/
|
|
52
|
+
applyRoll(roll: number): void;
|
|
53
|
+
/**
|
|
54
|
+
* Works off the sweep within a frame's budget, and says whether any backlog remains — the
|
|
55
|
+
* caller's cue to ask for another frame.
|
|
56
|
+
*
|
|
57
|
+
* Two passes, in the legacy `UpdatesSystem`'s shape: the stale defs first, except that a hidden
|
|
58
|
+
* def or one the frustum rejects is *deferred* rather than laid out; then the deferred ones, with
|
|
59
|
+
* whatever budget is left. Priority is all deferral buys — every def is still laid out before the
|
|
60
|
+
* sweep ends, because whether a def draws can be exactly what its rule decides. The budget is
|
|
61
|
+
* checked before each def, so even a blown budget lays at least one out and a sweep can never
|
|
62
|
+
* stall.
|
|
63
|
+
* @param frustum - The camera's frustum in plan space, when the caller has one; without it only
|
|
64
|
+
* hidden defs are deferred.
|
|
65
|
+
* @param budgetMs - How much of the frame a call may spend. Non-positive means no limit.
|
|
66
|
+
* @returns Whether defs remain for a later drain.
|
|
67
|
+
*/
|
|
68
|
+
drain(frustum?: Frustum, budgetMs?: number): boolean;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* The renderer's re-layout registry. Absent outside a renderer, where a layer simply registers
|
|
72
|
+
* nothing — which is what lets `Layer` be rendered bare in a spec.
|
|
73
|
+
*/
|
|
74
|
+
export declare const LayoutTargetsContext: import("react").Context<LayoutTargets | undefined>;
|
|
75
|
+
/**
|
|
76
|
+
* Registers a layer's re-layout targets for as long as the layer is mounted: the defs it holds that
|
|
77
|
+
* declare an `onScale`, and the layer itself when it declares one.
|
|
78
|
+
*
|
|
79
|
+
* A child *layer* is never registered here even when it declares a handler — it registers itself, and
|
|
80
|
+
* it has to: a handler assigned to a layer after mount re-renders that layer alone, so a registration
|
|
81
|
+
* held by its parent would never learn of it. Self-registration also covers the root, which has no
|
|
82
|
+
* parent layer to be registered by.
|
|
83
|
+
*
|
|
84
|
+
* Called from the layer rather than from its containers or their instances, because this is where
|
|
85
|
+
* both halves are already at hand. It also means a def is laid out whether or not its instance has
|
|
86
|
+
* mounted — defs are the source of truth, and a staged mount picks up whatever they hold when it
|
|
87
|
+
* admits them.
|
|
88
|
+
*
|
|
89
|
+
* Outside a renderer there is no registry and this does nothing, which is what lets a `Layer` be
|
|
90
|
+
* rendered bare in a spec.
|
|
91
|
+
* @param layer - The layer registering; itself a target when it declares a handler, which is how a
|
|
92
|
+
* layer whose *membership* depends on the camera re-derives it.
|
|
93
|
+
* @param children - The layer's children snapshot.
|
|
94
|
+
*/
|
|
95
|
+
export declare function useLayoutTargets(layer: LayerDef, children: readonly RenderableDef[]): void;
|
|
96
|
+
/**
|
|
97
|
+
* Builds a renderer's re-layout registry.
|
|
98
|
+
* @param invalidate - Requests a frame, for layouts that happen outside the frame loop.
|
|
99
|
+
* @param pixelSize - The pixel size defs are laid out at until the first frame moves it.
|
|
100
|
+
* @param roll - The roll defs are laid out at until the first frame moves it, in radians.
|
|
101
|
+
* @returns The registry.
|
|
102
|
+
*/
|
|
103
|
+
export declare function createLayoutTargets(invalidate: () => void, pixelSize: number, roll?: number): LayoutTargets;
|
|
104
|
+
//# sourceMappingURL=layout-targets.d.ts.map
|