@expofp/renderer 0.0.0-experimental.cf063fc
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 +145 -0
- package/dist/Renderer.d.ts +102 -0
- package/dist/Renderer.js +96 -0
- package/dist/controls/CameraControls.d.ts +108 -0
- package/dist/controls/CameraControls.js +203 -0
- package/dist/controls/Controls.d.ts +53 -0
- package/dist/controls/Controls.js +54 -0
- package/dist/controls/camera-api.d.ts +226 -0
- package/dist/controls/camera-api.js +179 -0
- package/dist/controls/gestures.d.ts +71 -0
- package/dist/controls/gestures.js +98 -0
- package/dist/controls/handlers/DoubleTapZoom.d.ts +23 -0
- package/dist/controls/handlers/DoubleTapZoom.js +82 -0
- package/dist/controls/handlers/Inertia.d.ts +60 -0
- package/dist/controls/handlers/Inertia.js +222 -0
- package/dist/controls/handlers/Pan.d.ts +23 -0
- package/dist/controls/handlers/Pan.js +212 -0
- package/dist/controls/handlers/Pitch.d.ts +19 -0
- package/dist/controls/handlers/Pitch.js +200 -0
- package/dist/controls/handlers/Roll.d.ts +30 -0
- package/dist/controls/handlers/Roll.js +196 -0
- package/dist/controls/handlers/Zoom.d.ts +28 -0
- package/dist/controls/handlers/Zoom.js +34 -0
- package/dist/controls/hooks.d.ts +136 -0
- package/dist/controls/hooks.js +200 -0
- package/dist/controls/index.d.ts +9 -0
- package/dist/controls/index.js +7 -0
- package/dist/controls/zoom-to.d.ts +89 -0
- package/dist/controls/zoom-to.js +91 -0
- package/dist/core/InstanceUniforms.d.ts +108 -0
- package/dist/core/InstanceUniforms.js +298 -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 +155 -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 +228 -0
- package/dist/core/lines/BatchedLines.d.ts +137 -0
- package/dist/core/lines/BatchedLines.js +215 -0
- package/dist/core/lines/FrustumCullingLines.d.ts +44 -0
- package/dist/core/lines/FrustumCullingLines.js +85 -0
- package/dist/core/lines/RaycastingLines.d.ts +45 -0
- package/dist/core/lines/RaycastingLines.js +91 -0
- package/dist/core/lines/lines-material.d.ts +47 -0
- package/dist/core/lines/lines-material.js +124 -0
- package/dist/core/shader-source.d.ts +70 -0
- package/dist/core/shader-source.js +110 -0
- package/dist/core/sprites/BatchedSprites.d.ts +115 -0
- package/dist/core/sprites/BatchedSprites.js +173 -0
- package/dist/core/sprites/RaycastingSprites.d.ts +41 -0
- package/dist/core/sprites/RaycastingSprites.js +71 -0
- package/dist/core/sprites/sprite-material.d.ts +59 -0
- package/dist/core/sprites/sprite-material.js +192 -0
- package/dist/core/text/BatchedText.d.ts +233 -0
- package/dist/core/text/BatchedText.js +473 -0
- package/dist/core/text/MemberTexture.d.ts +90 -0
- package/dist/core/text/MemberTexture.js +289 -0
- package/dist/core/text/Text.d.ts +88 -0
- package/dist/core/text/Text.js +230 -0
- package/dist/core/text/batched-text-material.d.ts +56 -0
- package/dist/core/text/batched-text-material.js +123 -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 +50 -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 +22 -0
- package/dist/debug/components/Gui.js +42 -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 +104 -0
- package/dist/debug/components/Stats.d.ts +9 -0
- package/dist/debug/components/Stats.js +24 -0
- package/dist/debug/debug-chunk.d.ts +26 -0
- package/dist/debug/debug-chunk.js +32 -0
- package/dist/debug/debug-context.d.ts +41 -0
- package/dist/debug/debug-context.js +59 -0
- package/dist/debug/index.d.ts +41 -0
- package/dist/debug/index.js +43 -0
- package/dist/events/LayoutDriver.d.ts +36 -0
- package/dist/events/LayoutDriver.js +192 -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 +151 -0
- package/dist/events/layout-targets.js +397 -0
- package/dist/events/placement/box.d.ts +59 -0
- package/dist/events/placement/box.js +96 -0
- package/dist/events/placement/grid.d.ts +161 -0
- package/dist/events/placement/grid.js +235 -0
- package/dist/events/placement/index.d.ts +2 -0
- package/dist/events/placement/index.js +1 -0
- package/dist/events/placement/pass.d.ts +70 -0
- package/dist/events/placement/pass.js +617 -0
- package/dist/events/pointer.d.ts +194 -0
- package/dist/events/pointer.js +356 -0
- package/dist/external/ExternalCanvas.d.ts +56 -0
- package/dist/external/ExternalCanvas.js +177 -0
- package/dist/external/external-camera.d.ts +18 -0
- package/dist/external/external-camera.js +103 -0
- package/dist/external/external-events.d.ts +14 -0
- package/dist/external/external-events.js +33 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +14 -0
- package/dist/objects/Background.d.ts +31 -0
- package/dist/objects/Background.js +37 -0
- package/dist/objects/containers/SlotContainer.d.ts +312 -0
- package/dist/objects/containers/SlotContainer.js +311 -0
- package/dist/objects/containers/hooks.d.ts +61 -0
- package/dist/objects/containers/hooks.js +196 -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 +33 -0
- package/dist/objects/containers/props.js +1 -0
- package/dist/objects/images/ImageInstance.d.ts +29 -0
- package/dist/objects/images/ImageInstance.js +152 -0
- package/dist/objects/images/Images.d.ts +49 -0
- package/dist/objects/images/Images.js +394 -0
- package/dist/objects/images/atlas-packer.d.ts +129 -0
- package/dist/objects/images/atlas-packer.js +287 -0
- package/dist/objects/images/image-container.d.ts +74 -0
- package/dist/objects/images/image-container.js +100 -0
- package/dist/objects/images/index.d.ts +2 -0
- package/dist/objects/images/index.js +1 -0
- package/dist/objects/images/pack-sources.d.ts +190 -0
- package/dist/objects/images/pack-sources.js +272 -0
- package/dist/objects/images/texture-budget.d.ts +120 -0
- package/dist/objects/images/texture-budget.js +215 -0
- package/dist/objects/images/worker/atlas-worker.d.ts +56 -0
- package/dist/objects/images/worker/atlas-worker.js +123 -0
- package/dist/objects/images/worker/client.d.ts +62 -0
- package/dist/objects/images/worker/client.js +249 -0
- package/dist/objects/images/worker/index.d.ts +10 -0
- package/dist/objects/images/worker/index.js +1 -0
- package/dist/objects/layer/Layer.d.ts +28 -0
- package/dist/objects/layer/Layer.js +134 -0
- package/dist/objects/layer/index.d.ts +2 -0
- package/dist/objects/layer/index.js +1 -0
- package/dist/objects/layer/layer-context.d.ts +74 -0
- package/dist/objects/layer/layer-context.js +82 -0
- package/dist/objects/layer/mount-scheduler.d.ts +131 -0
- package/dist/objects/layer/mount-scheduler.js +289 -0
- package/dist/objects/layer/visibility-gui.d.ts +19 -0
- package/dist/objects/layer/visibility-gui.js +93 -0
- package/dist/objects/lighting/Lighting.d.ts +92 -0
- package/dist/objects/lighting/Lighting.js +384 -0
- package/dist/objects/lighting/OcclusionPasses.d.ts +23 -0
- package/dist/objects/lighting/OcclusionPasses.js +271 -0
- package/dist/objects/lighting/index.d.ts +11 -0
- package/dist/objects/lighting/index.js +10 -0
- package/dist/objects/lighting/lighting-gui.d.ts +24 -0
- package/dist/objects/lighting/lighting-gui.js +114 -0
- package/dist/objects/lighting/occluder.d.ts +34 -0
- package/dist/objects/lighting/occluder.js +62 -0
- package/dist/objects/lighting/occlusion-targets.d.ts +143 -0
- package/dist/objects/lighting/occlusion-targets.js +276 -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 +31 -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 +92 -0
- package/dist/objects/materials/ColorMaterial.js +124 -0
- package/dist/objects/materials/LineMaterial.d.ts +44 -0
- package/dist/objects/materials/LineMaterial.js +74 -0
- package/dist/objects/materials/ModelMaterial.d.ts +53 -0
- package/dist/objects/materials/ModelMaterial.js +111 -0
- package/dist/objects/materials/TextureMaterial.d.ts +33 -0
- package/dist/objects/materials/TextureMaterial.js +48 -0
- package/dist/objects/materials/effects/ao/ambient-occlusion-pass.d.ts +77 -0
- package/dist/objects/materials/effects/ao/ambient-occlusion-pass.js +296 -0
- package/dist/objects/materials/effects/ao/ambient-occlusion-patch.d.ts +29 -0
- package/dist/objects/materials/effects/ao/ambient-occlusion-patch.js +115 -0
- package/dist/objects/materials/effects/ao/blur-pass.d.ts +61 -0
- package/dist/objects/materials/effects/ao/blur-pass.js +101 -0
- package/dist/objects/materials/effects/ao/index.d.ts +129 -0
- package/dist/objects/materials/effects/ao/index.js +72 -0
- package/dist/objects/materials/effects/color-dim.d.ts +115 -0
- package/dist/objects/materials/effects/color-dim.js +206 -0
- package/dist/objects/materials/effects/contact-shadow.d.ts +100 -0
- package/dist/objects/materials/effects/contact-shadow.js +167 -0
- package/dist/objects/materials/effects/effects-context.d.ts +53 -0
- package/dist/objects/materials/effects/effects-context.js +24 -0
- package/dist/objects/materials/shared.d.ts +24 -0
- package/dist/objects/materials/shared.js +72 -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 +186 -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 +123 -0
- package/dist/objects/models/model-container.js +207 -0
- package/dist/objects/shapes/ShapeInstance.d.ts +26 -0
- package/dist/objects/shapes/ShapeInstance.js +39 -0
- package/dist/objects/shapes/Shapes.d.ts +21 -0
- package/dist/objects/shapes/Shapes.js +131 -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 +141 -0
- package/dist/objects/shapes/shape-container.js +242 -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 +43 -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 +121 -0
- package/dist/objects/text/text-container.js +229 -0
- package/dist/objects/text/text-layout.d.ts +92 -0
- package/dist/objects/text/text-layout.js +180 -0
- package/dist/space/Camera.d.ts +103 -0
- package/dist/space/Camera.js +321 -0
- package/dist/space/Scene.d.ts +47 -0
- package/dist/space/Scene.js +127 -0
- package/dist/space/Space.d.ts +325 -0
- package/dist/space/Space.js +359 -0
- package/dist/space/VisibleRect.d.ts +45 -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 +69 -0
- package/dist/space/clipping.js +130 -0
- package/dist/space/layout-measure.d.ts +67 -0
- package/dist/space/layout-measure.js +175 -0
- package/dist/space/viewport.d.ts +112 -0
- package/dist/space/viewport.js +67 -0
- package/dist/types/defs.d.ts +234 -0
- package/dist/types/defs.js +1 -0
- package/dist/types/events.d.ts +198 -0
- package/dist/types/events.js +1 -0
- package/dist/types/guards.d.ts +21 -0
- package/dist/types/guards.js +52 -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 +76 -0
- package/dist/update/store.d.ts +41 -0
- package/dist/update/store.js +104 -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/hot-state.d.ts +41 -0
- package/dist/utils/hot-state.js +37 -0
- package/dist/utils/logging.d.ts +29 -0
- package/dist/utils/logging.js +55 -0
- package/dist/utils/math.d.ts +52 -0
- package/dist/utils/math.js +76 -0
- package/package.json +79 -0
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
import { type Object3D } from 'three';
|
|
2
|
+
import { type UniformSchemaShader } from '../../core/InstanceUniforms';
|
|
3
|
+
import { type UniformValue } from '../../core/SquareDataTexture';
|
|
4
|
+
import { type RenderableDef } from '../../types/defs';
|
|
5
|
+
/**
|
|
6
|
+
* What a container needs from the mesh it writes into.
|
|
7
|
+
*
|
|
8
|
+
* A capability rather than a union of our mesh classes: `BatchedMeshImpl`, `InstancedMeshImpl`,
|
|
9
|
+
* `BatchedLinesImpl` and `BatchedTextImpl` share no base below `Object3D`, yet every one of them
|
|
10
|
+
* declares per-instance uniforms and hides an instance the same way — which is all a container
|
|
11
|
+
* touches generically. Everything else it reaches through its own mesh type, which the subclass
|
|
12
|
+
* names.
|
|
13
|
+
*/
|
|
14
|
+
export interface SlotMesh extends Object3D {
|
|
15
|
+
/**
|
|
16
|
+
* Declares per-instance uniforms, merged with whatever is already declared.
|
|
17
|
+
* @param schema - The uniforms to add.
|
|
18
|
+
*/
|
|
19
|
+
addUniforms(schema: UniformSchemaShader): void;
|
|
20
|
+
/**
|
|
21
|
+
* Writes one instance's uniform.
|
|
22
|
+
* @param slot - The instance to write.
|
|
23
|
+
* @param name - The uniform's name.
|
|
24
|
+
* @param value - The value to write.
|
|
25
|
+
*/
|
|
26
|
+
setUniformAt(slot: number, name: string, value: UniformValue): void;
|
|
27
|
+
/**
|
|
28
|
+
* Shows or hides one instance.
|
|
29
|
+
* @param slot - The instance to show or hide.
|
|
30
|
+
* @param visible - Whether it draws.
|
|
31
|
+
*/
|
|
32
|
+
setVisibleAt(slot: number, visible: boolean): void;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* An entry in a mesh's render list. Every mesh's sort callback receives a list of these — the
|
|
36
|
+
* published shapes differ in what else they carry, but each entry identifies its instance by
|
|
37
|
+
* `index`, which is all a paint-order sort needs.
|
|
38
|
+
*/
|
|
39
|
+
export interface RenderListItem {
|
|
40
|
+
/** The instance id the entry draws. */
|
|
41
|
+
index: number;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* One entry in the list `BatchedMesh.customSort` receives. three's published types describe only
|
|
45
|
+
* `start`, `count`, and `z`, but the runtime also passes `index` — the instance id — which is the
|
|
46
|
+
* only way a sort can map an entry back to the instance that produced it.
|
|
47
|
+
*/
|
|
48
|
+
export interface BatchedMeshRenderItem extends RenderListItem {
|
|
49
|
+
/** Offset of the instance's geometry in the shared draw range. */
|
|
50
|
+
start: number;
|
|
51
|
+
/** Length of the instance's geometry draw range. */
|
|
52
|
+
count: number;
|
|
53
|
+
/** Instance depth along the camera's view direction. */
|
|
54
|
+
z: number;
|
|
55
|
+
}
|
|
56
|
+
/** How one container differs from the default, passed up by its constructor. */
|
|
57
|
+
export interface SlotContainerOptions {
|
|
58
|
+
/**
|
|
59
|
+
* The per-instance uniforms the mesh declares on {@link SlotContainer.bind}. Defaults to the dim
|
|
60
|
+
* alone, which every def type carries. A container whose mesh needs more (an image's uv region, a
|
|
61
|
+
* model's opacity) passes the merged schema rather than declaring twice: `InstanceUniforms.add`
|
|
62
|
+
* rebuilds the backing texture, so two calls would build it twice per bind.
|
|
63
|
+
*/
|
|
64
|
+
schema?: UniformSchemaShader;
|
|
65
|
+
/**
|
|
66
|
+
* Sort the draw list descending, so the *first* instance drawn is the one that paints on top.
|
|
67
|
+
*
|
|
68
|
+
* For a batch whose material keeps the first fragment to reach a pixel and rejects the rest,
|
|
69
|
+
* which is how the line material stops translucent lines darkening where they overlap: there,
|
|
70
|
+
* draw order is the reverse of paint order. Slots are still labeled in paint order either way.
|
|
71
|
+
*/
|
|
72
|
+
reverse?: boolean;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* One layer's mesh bookkeeping: the bound mesh, which slot each def holds, and the paint order
|
|
76
|
+
* across them.
|
|
77
|
+
*
|
|
78
|
+
* A container is what stands between a layer's defs and one mesh. It is created during render,
|
|
79
|
+
* sized to the membership it first sees, and held in `useState` for as long as its component is
|
|
80
|
+
* mounted; the mesh itself is R3F's, constructed from the subclass's args and handed back through
|
|
81
|
+
* {@link bind}, so R3F owns its lifetime and disposal. Instances claim and release slots from their
|
|
82
|
+
* own effects, and write their type-specific state through the subclass's own methods.
|
|
83
|
+
*
|
|
84
|
+
* What lives here is everything that does not depend on which def type is drawn:
|
|
85
|
+
*
|
|
86
|
+
* - **Slot allocation**, in both directions. `slotOf` is what a paint-order pass over the layer's
|
|
87
|
+
* defs looks each def up with, and {@link defAt} is what turns a pointer hit — which names a mesh
|
|
88
|
+
* instance — back into the def that drew it. Slots come from a mesh's free list, so a released slot
|
|
89
|
+
* may be handed to a different def later; freeing by slot keeps both directions from outliving the
|
|
90
|
+
* claim they describe.
|
|
91
|
+
* - **Paint order**, explicitly. Instance ids come from a mesh's free list, so they do not track
|
|
92
|
+
* sibling order — a container that let slot order stand in for paint order would reorder itself
|
|
93
|
+
* after any claim/release churn, and again under StrictMode's remount, which re-claims in reverse.
|
|
94
|
+
* Explicit order is also what the 2D painter's algorithm needs: 2D content never writes depth, so
|
|
95
|
+
* nothing it draws is in the buffer for the next 2D fragment to test against, and the draw list's
|
|
96
|
+
* order is the only thing that decides overlap.
|
|
97
|
+
* - **The two fields every def type carries**, `hidden` and `dim`, through {@link setVisibleAt} and
|
|
98
|
+
* {@link setDimAt} — which is what lets one hook drive them for every def type.
|
|
99
|
+
*
|
|
100
|
+
* A subclass supplies {@link addInstance} and {@link removeInstance}, names its mesh and def types,
|
|
101
|
+
* and adds whatever its own defs need.
|
|
102
|
+
* @template R - The per-instance resource a claim allocates against (a geometry, a texture region,
|
|
103
|
+
* a line count); compared by identity, so a stable reference means a stable slot. `null` for a
|
|
104
|
+
* container whose members share everything.
|
|
105
|
+
* @template M - The mesh this container writes into.
|
|
106
|
+
* @template T - The def kind the layer holds.
|
|
107
|
+
*/
|
|
108
|
+
export declare abstract class SlotContainer<R, M extends SlotMesh = SlotMesh, T extends RenderableDef = RenderableDef> {
|
|
109
|
+
/**
|
|
110
|
+
* Sorts a mesh's render list into paint order. Assigned straight to the mesh's `customSort` JSX
|
|
111
|
+
* prop, whose R3F-generated type leaves the value effectively unchecked — so the entry type here
|
|
112
|
+
* needs no cast against three's published one, which omits `index`.
|
|
113
|
+
*
|
|
114
|
+
* An arrow property rather than a method, because it is handed over as a bare value and a
|
|
115
|
+
* prototype method would arrive unbound.
|
|
116
|
+
* @param list - The render list, sorted in place.
|
|
117
|
+
*/
|
|
118
|
+
readonly customSort: (list: RenderListItem[]) => void;
|
|
119
|
+
/**
|
|
120
|
+
* The layer's membership, in authored paint order. Kept so a def whose own dim changes can re-run
|
|
121
|
+
* the order pass without this container having re-rendered — `update(def)` reaches the instance,
|
|
122
|
+
* not here.
|
|
123
|
+
*/
|
|
124
|
+
protected layerDefs: readonly T[];
|
|
125
|
+
/**
|
|
126
|
+
* Whether the layer is dimmed, which is what a def without a `dim` of its own inherits.
|
|
127
|
+
*
|
|
128
|
+
* A flag rather than the layer's amount, because the amount is the shader's business and this is
|
|
129
|
+
* only ever asked a yes-or-no question. It is also what makes an eased layer dim cheap: the order
|
|
130
|
+
* pass re-runs when the value crosses zero, not on every frame of the ease.
|
|
131
|
+
*/
|
|
132
|
+
protected layerDimmed: boolean;
|
|
133
|
+
/**
|
|
134
|
+
* Whether each slot currently draws dimmed, so a dim write that does not cross the split costs
|
|
135
|
+
* nothing.
|
|
136
|
+
*/
|
|
137
|
+
protected readonly dimmedBySlot: (boolean | undefined)[];
|
|
138
|
+
/**
|
|
139
|
+
* Each def's order, durable and weak — collected with the def. It outlives a slot, so a re-claim
|
|
140
|
+
* can seed the new slot's order without waiting for the next order pass.
|
|
141
|
+
*/
|
|
142
|
+
private readonly orderByDef;
|
|
143
|
+
/** Each slot's place in the paint order, read by {@link customSort}. */
|
|
144
|
+
private readonly orderBySlot;
|
|
145
|
+
private readonly slotByDef;
|
|
146
|
+
private readonly defBySlot;
|
|
147
|
+
private readonly schema;
|
|
148
|
+
private readonly sortDirection;
|
|
149
|
+
/** Set by {@link bind}, which runs before any effect can claim a slot. */
|
|
150
|
+
private boundMesh;
|
|
151
|
+
/** What to run when a member turns out to belong in a sibling container; see {@link reportKindMismatch}. */
|
|
152
|
+
private kindMismatchHandler;
|
|
153
|
+
/**
|
|
154
|
+
* @param options - How this container differs from the default.
|
|
155
|
+
*/
|
|
156
|
+
constructor(options?: SlotContainerOptions);
|
|
157
|
+
/**
|
|
158
|
+
* The mesh every instance writes into. Undefined until {@link bind}; refs attach before passive
|
|
159
|
+
* effects run, so every claim and slot write sees it bound.
|
|
160
|
+
*/
|
|
161
|
+
get mesh(): M;
|
|
162
|
+
/**
|
|
163
|
+
* Binds the mesh R3F constructed from this container's args, declaring its per-instance uniforms.
|
|
164
|
+
*
|
|
165
|
+
* Bind-once: the ref-cleanup `null` and any re-bind are ignored, because React StrictMode cycles
|
|
166
|
+
* refs (attach → cleanup → attach) around a passive effect cycle — a container that forgot its
|
|
167
|
+
* mesh there would turn {@link release} into a no-op and leak the slot when the remounted instance
|
|
168
|
+
* re-claims, and one that re-declared its uniforms would strand the values already written into
|
|
169
|
+
* them.
|
|
170
|
+
* @param mesh - The mounted mesh, or the ref-cleanup `null`.
|
|
171
|
+
*/
|
|
172
|
+
bind(mesh: M | null): void;
|
|
173
|
+
/**
|
|
174
|
+
* Reserves a slot for one instance, backed by `resource`.
|
|
175
|
+
*
|
|
176
|
+
* Paint order is deliberately not a parameter: it is a property of the whole sibling list, so the
|
|
177
|
+
* component writes it for every def in one pass after each membership change (see
|
|
178
|
+
* {@link setPaintOrder}) — an instance never learns its index, which is what lets a memoized
|
|
179
|
+
* instance ignore structural re-renders entirely.
|
|
180
|
+
* @param def - The def the slot will draw; def-to-slot bookkeeping is keyed by its identity.
|
|
181
|
+
* @param resource - The per-instance resource to allocate against.
|
|
182
|
+
* @returns The slot index.
|
|
183
|
+
*/
|
|
184
|
+
claim(def: RenderableDef, resource: R): number;
|
|
185
|
+
/**
|
|
186
|
+
* Frees a slot, and everything recorded about the claim it held.
|
|
187
|
+
* @param slot - The slot to free.
|
|
188
|
+
*/
|
|
189
|
+
release(slot: number): void;
|
|
190
|
+
/**
|
|
191
|
+
* The def a mesh instance belongs to — the reverse of {@link claim}, and what picking asks, since
|
|
192
|
+
* an intersection names an instance and nothing else.
|
|
193
|
+
*
|
|
194
|
+
* The instance *is* the slot for every container but the text batch, whose defs own one member per
|
|
195
|
+
* line; that one overrides this to resolve the member's group first, which is why the parameter is
|
|
196
|
+
* the mesh's number rather than the container's.
|
|
197
|
+
* @param instance - The instance the mesh reported, or `undefined` for a hit that named none.
|
|
198
|
+
* @returns The def, or `undefined` when no claim holds that instance.
|
|
199
|
+
*/
|
|
200
|
+
defAt(instance: number | undefined): RenderableDef | undefined;
|
|
201
|
+
/**
|
|
202
|
+
* Where a def sits in this container's draw order, counted from the one drawn first.
|
|
203
|
+
*
|
|
204
|
+
* The public read of an assignment the order pass makes privately. Picking uses it to break a tie
|
|
205
|
+
* the depth buffer never resolved: two surfaces closer together than `depthSeparation` are drawn
|
|
206
|
+
* in list order rather than depth order, so list order is also what decides which of them the
|
|
207
|
+
* pointer is on (see `orderCoplanarHits`). Per def rather than per slot, because a slot is a mesh's
|
|
208
|
+
* own numbering out of a free list and a def is what the layer ordered.
|
|
209
|
+
*
|
|
210
|
+
* A def this container never ordered reports the first place rather than the last: nothing is known
|
|
211
|
+
* about where it drew, and the one thing that must not happen is for that to outrank a def whose
|
|
212
|
+
* place is known.
|
|
213
|
+
* @param def - The def to place.
|
|
214
|
+
* @returns Its place in the draw order.
|
|
215
|
+
*/
|
|
216
|
+
paintOrderOf(def: RenderableDef): number;
|
|
217
|
+
/**
|
|
218
|
+
* Registers what to do when a member turns out to belong in a sibling container; `undefined`
|
|
219
|
+
* clears it.
|
|
220
|
+
*
|
|
221
|
+
* Here rather than on each subclass because the situation is one situation: a layer is split
|
|
222
|
+
* across several containers by some property of the def, and that property can move after the def
|
|
223
|
+
* was placed. What splits them differs — a shape's color crossing alpha 1, a model's `opacity`,
|
|
224
|
+
* an image's orientation — but what a container does about it does not, and the component that
|
|
225
|
+
* owns the split is always the one that can repair it.
|
|
226
|
+
*
|
|
227
|
+
* A method rather than an assignable field because the container is held in `useState`, and the
|
|
228
|
+
* React Compiler rejects writing to a property of a state value ("This value cannot be modified").
|
|
229
|
+
* Calling a method is fine, which is how {@link reserve} already mutates.
|
|
230
|
+
* @param handler - The re-split to run, or `undefined` to clear it.
|
|
231
|
+
*/
|
|
232
|
+
setKindMismatchHandler(handler: (() => void) | undefined): void;
|
|
233
|
+
/**
|
|
234
|
+
* Reports that a member no longer belongs in this container, so it is drawing from the wrong mesh.
|
|
235
|
+
* Runs the registered handler, if any; a container mounted without one — in a spec, or bare —
|
|
236
|
+
* drops the report rather than failing, since nothing it could do would be more correct than
|
|
237
|
+
* carrying on.
|
|
238
|
+
*/
|
|
239
|
+
reportKindMismatch(): void;
|
|
240
|
+
/**
|
|
241
|
+
* Shows or hides one instance. Every def type carries `hidden`, so `useDefSync` drives this for
|
|
242
|
+
* all of them.
|
|
243
|
+
* @param slot - The slot to show or hide.
|
|
244
|
+
* @param visible - Whether the instance should draw.
|
|
245
|
+
*/
|
|
246
|
+
setVisibleAt(slot: number, visible: boolean): void;
|
|
247
|
+
/**
|
|
248
|
+
* Sets one instance's own dim, or clears it back to its layer's.
|
|
249
|
+
*
|
|
250
|
+
* The counterpart to {@link setVisibleAt}, and here for the same reason: `dim` is a `SharedDef`
|
|
251
|
+
* field, so `useDefSync` drives it for every def type. The raw field is passed through rather than
|
|
252
|
+
* an encoded amount, which keeps the sentinel — and the rest of the shader's contract — inside the
|
|
253
|
+
* material module that reads it.
|
|
254
|
+
* @param slot - The slot to dim.
|
|
255
|
+
* @param dim - The def's `dim`; `undefined` defers to the layer's.
|
|
256
|
+
*/
|
|
257
|
+
setDimAt(slot: number, dim: number | undefined): void;
|
|
258
|
+
/**
|
|
259
|
+
* Writes an encoded dim into a slot's uniform — the part of {@link setDimAt} that knows how a slot
|
|
260
|
+
* maps onto the mesh, split out so a container whose slot spans several mesh instances overrides
|
|
261
|
+
* only that and keeps the split-crossing check above.
|
|
262
|
+
* @param slot - The slot to write.
|
|
263
|
+
* @param amount - The encoded amount, from `instanceDim`.
|
|
264
|
+
*/
|
|
265
|
+
protected writeDim(slot: number, amount: number): void;
|
|
266
|
+
/**
|
|
267
|
+
* Declares the layer's membership and dim, and re-runs the order pass over them.
|
|
268
|
+
*
|
|
269
|
+
* The component calls this from an effect after each structural change — child effects run first,
|
|
270
|
+
* so every mounted instance has claimed by then. Defs that have not claimed yet are recorded
|
|
271
|
+
* anyway: a later claim seeds its slot's order from this assignment, which is what keeps a
|
|
272
|
+
* re-claim correctly ordered without React involvement.
|
|
273
|
+
* @param defs - The current membership, in paint order.
|
|
274
|
+
* @param layerDimmed - Whether the layer is dimmed, inherited by defs without a `dim` of their own.
|
|
275
|
+
*/
|
|
276
|
+
setPaintOrder(defs: readonly T[], layerDimmed: boolean): void;
|
|
277
|
+
/**
|
|
278
|
+
* The layer's defs in the order they draw, each labeled with its place in it.
|
|
279
|
+
*
|
|
280
|
+
* Every order pass starts here, the overriding ones included, so the labels exist whatever a
|
|
281
|
+
* container then does with the order — a sortable draw list for most of them, a rebuilt member
|
|
282
|
+
* list for a text batch. That is what lets {@link paintOrderOf} answer for any container's hits
|
|
283
|
+
* rather than only the ones whose mesh sorts.
|
|
284
|
+
* @returns The defs, dimmed first.
|
|
285
|
+
*/
|
|
286
|
+
protected orderedDefs(): readonly T[];
|
|
287
|
+
/**
|
|
288
|
+
* Labels every claimed slot with its place in the layer's draw order, undimmed defs last.
|
|
289
|
+
*
|
|
290
|
+
* Overridden by a container whose mesh has no sortable draw list, where ordering means handing the
|
|
291
|
+
* mesh a rebuilt member list instead.
|
|
292
|
+
*/
|
|
293
|
+
protected applyOrder(): void;
|
|
294
|
+
/**
|
|
295
|
+
* The slot a def holds, for an order pass walking the layer's defs.
|
|
296
|
+
* @param def - The def to look up.
|
|
297
|
+
* @returns The slot, or `undefined` when the def has not claimed one.
|
|
298
|
+
*/
|
|
299
|
+
protected slotOf(def: RenderableDef): number | undefined;
|
|
300
|
+
/**
|
|
301
|
+
* Allocates one instance in the mesh.
|
|
302
|
+
* @param resource - The per-instance resource to allocate against.
|
|
303
|
+
* @returns The slot the mesh allocated.
|
|
304
|
+
*/
|
|
305
|
+
protected abstract addInstance(resource: R): number;
|
|
306
|
+
/**
|
|
307
|
+
* Frees one instance in the mesh.
|
|
308
|
+
* @param slot - The slot to free.
|
|
309
|
+
*/
|
|
310
|
+
protected abstract removeInstance(slot: number): void;
|
|
311
|
+
}
|
|
312
|
+
//# sourceMappingURL=SlotContainer.d.ts.map
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
import { DIM_SCHEMA, DIM_UNIFORM, dimOrdered, instanceDim, isDimmed, } from '../materials/effects/color-dim';
|
|
2
|
+
/**
|
|
3
|
+
* One layer's mesh bookkeeping: the bound mesh, which slot each def holds, and the paint order
|
|
4
|
+
* across them.
|
|
5
|
+
*
|
|
6
|
+
* A container is what stands between a layer's defs and one mesh. It is created during render,
|
|
7
|
+
* sized to the membership it first sees, and held in `useState` for as long as its component is
|
|
8
|
+
* mounted; the mesh itself is R3F's, constructed from the subclass's args and handed back through
|
|
9
|
+
* {@link bind}, so R3F owns its lifetime and disposal. Instances claim and release slots from their
|
|
10
|
+
* own effects, and write their type-specific state through the subclass's own methods.
|
|
11
|
+
*
|
|
12
|
+
* What lives here is everything that does not depend on which def type is drawn:
|
|
13
|
+
*
|
|
14
|
+
* - **Slot allocation**, in both directions. `slotOf` is what a paint-order pass over the layer's
|
|
15
|
+
* defs looks each def up with, and {@link defAt} is what turns a pointer hit — which names a mesh
|
|
16
|
+
* instance — back into the def that drew it. Slots come from a mesh's free list, so a released slot
|
|
17
|
+
* may be handed to a different def later; freeing by slot keeps both directions from outliving the
|
|
18
|
+
* claim they describe.
|
|
19
|
+
* - **Paint order**, explicitly. Instance ids come from a mesh's free list, so they do not track
|
|
20
|
+
* sibling order — a container that let slot order stand in for paint order would reorder itself
|
|
21
|
+
* after any claim/release churn, and again under StrictMode's remount, which re-claims in reverse.
|
|
22
|
+
* Explicit order is also what the 2D painter's algorithm needs: 2D content never writes depth, so
|
|
23
|
+
* nothing it draws is in the buffer for the next 2D fragment to test against, and the draw list's
|
|
24
|
+
* order is the only thing that decides overlap.
|
|
25
|
+
* - **The two fields every def type carries**, `hidden` and `dim`, through {@link setVisibleAt} and
|
|
26
|
+
* {@link setDimAt} — which is what lets one hook drive them for every def type.
|
|
27
|
+
*
|
|
28
|
+
* A subclass supplies {@link addInstance} and {@link removeInstance}, names its mesh and def types,
|
|
29
|
+
* and adds whatever its own defs need.
|
|
30
|
+
* @template R - The per-instance resource a claim allocates against (a geometry, a texture region,
|
|
31
|
+
* a line count); compared by identity, so a stable reference means a stable slot. `null` for a
|
|
32
|
+
* container whose members share everything.
|
|
33
|
+
* @template M - The mesh this container writes into.
|
|
34
|
+
* @template T - The def kind the layer holds.
|
|
35
|
+
*/
|
|
36
|
+
export class SlotContainer {
|
|
37
|
+
/**
|
|
38
|
+
* Sorts a mesh's render list into paint order. Assigned straight to the mesh's `customSort` JSX
|
|
39
|
+
* prop, whose R3F-generated type leaves the value effectively unchecked — so the entry type here
|
|
40
|
+
* needs no cast against three's published one, which omits `index`.
|
|
41
|
+
*
|
|
42
|
+
* An arrow property rather than a method, because it is handed over as a bare value and a
|
|
43
|
+
* prototype method would arrive unbound.
|
|
44
|
+
* @param list - The render list, sorted in place.
|
|
45
|
+
*/
|
|
46
|
+
customSort = (list) => {
|
|
47
|
+
const order = this.orderBySlot;
|
|
48
|
+
list.sort((a, b) => this.sortDirection * ((order[a.index] ?? 0) - (order[b.index] ?? 0)));
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* The layer's membership, in authored paint order. Kept so a def whose own dim changes can re-run
|
|
52
|
+
* the order pass without this container having re-rendered — `update(def)` reaches the instance,
|
|
53
|
+
* not here.
|
|
54
|
+
*/
|
|
55
|
+
layerDefs = [];
|
|
56
|
+
/**
|
|
57
|
+
* Whether the layer is dimmed, which is what a def without a `dim` of its own inherits.
|
|
58
|
+
*
|
|
59
|
+
* A flag rather than the layer's amount, because the amount is the shader's business and this is
|
|
60
|
+
* only ever asked a yes-or-no question. It is also what makes an eased layer dim cheap: the order
|
|
61
|
+
* pass re-runs when the value crosses zero, not on every frame of the ease.
|
|
62
|
+
*/
|
|
63
|
+
layerDimmed = false;
|
|
64
|
+
/**
|
|
65
|
+
* Whether each slot currently draws dimmed, so a dim write that does not cross the split costs
|
|
66
|
+
* nothing.
|
|
67
|
+
*/
|
|
68
|
+
dimmedBySlot = [];
|
|
69
|
+
/**
|
|
70
|
+
* Each def's order, durable and weak — collected with the def. It outlives a slot, so a re-claim
|
|
71
|
+
* can seed the new slot's order without waiting for the next order pass.
|
|
72
|
+
*/
|
|
73
|
+
orderByDef = new WeakMap();
|
|
74
|
+
/** Each slot's place in the paint order, read by {@link customSort}. */
|
|
75
|
+
orderBySlot = [];
|
|
76
|
+
slotByDef = new Map();
|
|
77
|
+
defBySlot = new Map();
|
|
78
|
+
schema;
|
|
79
|
+
sortDirection;
|
|
80
|
+
/** Set by {@link bind}, which runs before any effect can claim a slot. */
|
|
81
|
+
boundMesh;
|
|
82
|
+
/** What to run when a member turns out to belong in a sibling container; see {@link reportKindMismatch}. */
|
|
83
|
+
kindMismatchHandler;
|
|
84
|
+
/**
|
|
85
|
+
* @param options - How this container differs from the default.
|
|
86
|
+
*/
|
|
87
|
+
constructor(options = {}) {
|
|
88
|
+
this.schema = options.schema ?? DIM_SCHEMA;
|
|
89
|
+
this.sortDirection = options.reverse ? -1 : 1;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* The mesh every instance writes into. Undefined until {@link bind}; refs attach before passive
|
|
93
|
+
* effects run, so every claim and slot write sees it bound.
|
|
94
|
+
*/
|
|
95
|
+
get mesh() {
|
|
96
|
+
// Asserted rather than guarded: reading before the ref attached is a programming error, and the
|
|
97
|
+
// ordering that rules it out is React's, not something a check here could repair.
|
|
98
|
+
return this.boundMesh;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Binds the mesh R3F constructed from this container's args, declaring its per-instance uniforms.
|
|
102
|
+
*
|
|
103
|
+
* Bind-once: the ref-cleanup `null` and any re-bind are ignored, because React StrictMode cycles
|
|
104
|
+
* refs (attach → cleanup → attach) around a passive effect cycle — a container that forgot its
|
|
105
|
+
* mesh there would turn {@link release} into a no-op and leak the slot when the remounted instance
|
|
106
|
+
* re-claims, and one that re-declared its uniforms would strand the values already written into
|
|
107
|
+
* them.
|
|
108
|
+
* @param mesh - The mounted mesh, or the ref-cleanup `null`.
|
|
109
|
+
*/
|
|
110
|
+
bind(mesh) {
|
|
111
|
+
if (!mesh || this.boundMesh)
|
|
112
|
+
return;
|
|
113
|
+
this.boundMesh = mesh;
|
|
114
|
+
// The material owns each uniform's name and shape; the mesh only has to declare the rows before
|
|
115
|
+
// any slot writes into them — which the ref this runs from guarantees, since refs attach before
|
|
116
|
+
// the effects that claim slots and long before the first draw.
|
|
117
|
+
mesh.addUniforms(this.schema);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Reserves a slot for one instance, backed by `resource`.
|
|
121
|
+
*
|
|
122
|
+
* Paint order is deliberately not a parameter: it is a property of the whole sibling list, so the
|
|
123
|
+
* component writes it for every def in one pass after each membership change (see
|
|
124
|
+
* {@link setPaintOrder}) — an instance never learns its index, which is what lets a memoized
|
|
125
|
+
* instance ignore structural re-renders entirely.
|
|
126
|
+
* @param def - The def the slot will draw; def-to-slot bookkeeping is keyed by its identity.
|
|
127
|
+
* @param resource - The per-instance resource to allocate against.
|
|
128
|
+
* @returns The slot index.
|
|
129
|
+
*/
|
|
130
|
+
claim(def, resource) {
|
|
131
|
+
const slot = this.addInstance(resource);
|
|
132
|
+
this.slotByDef.set(def, slot);
|
|
133
|
+
this.defBySlot.set(slot, def);
|
|
134
|
+
// Seeded from the durable assignment so a re-claim keeps its order; a first claim before any
|
|
135
|
+
// `setPaintOrder` defaults to 0 and the component's order pass relabels it in the same effect
|
|
136
|
+
// flush, before anything draws.
|
|
137
|
+
this.orderBySlot[slot] = this.orderByDef.get(def) ?? 0;
|
|
138
|
+
// Seeded here as well, so the instance's first `setDimAt` — every instance writes its dim as it
|
|
139
|
+
// mounts — reads the split it already draws on rather than `undefined`, and leaves the order
|
|
140
|
+
// pass to the structural one. Without it, mounting a layer of n defs runs n full order passes.
|
|
141
|
+
// A dim that arrives with the sync still crosses the split and still re-orders, and a claim
|
|
142
|
+
// made before the layer's own dim is known is relabelled by `setPaintOrder` in the same flush.
|
|
143
|
+
this.dimmedBySlot[slot] = isDimmed(def.dim, this.layerDimmed);
|
|
144
|
+
return slot;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Frees a slot, and everything recorded about the claim it held.
|
|
148
|
+
* @param slot - The slot to free.
|
|
149
|
+
*/
|
|
150
|
+
release(slot) {
|
|
151
|
+
this.removeInstance(slot);
|
|
152
|
+
this.orderBySlot[slot] = 0;
|
|
153
|
+
this.dimmedBySlot[slot] = undefined;
|
|
154
|
+
const def = this.defBySlot.get(slot);
|
|
155
|
+
if (!def)
|
|
156
|
+
return;
|
|
157
|
+
this.slotByDef.delete(def);
|
|
158
|
+
this.defBySlot.delete(slot);
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* The def a mesh instance belongs to — the reverse of {@link claim}, and what picking asks, since
|
|
162
|
+
* an intersection names an instance and nothing else.
|
|
163
|
+
*
|
|
164
|
+
* The instance *is* the slot for every container but the text batch, whose defs own one member per
|
|
165
|
+
* line; that one overrides this to resolve the member's group first, which is why the parameter is
|
|
166
|
+
* the mesh's number rather than the container's.
|
|
167
|
+
* @param instance - The instance the mesh reported, or `undefined` for a hit that named none.
|
|
168
|
+
* @returns The def, or `undefined` when no claim holds that instance.
|
|
169
|
+
*/
|
|
170
|
+
defAt(instance) {
|
|
171
|
+
return instance === undefined ? undefined : this.defBySlot.get(instance);
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Where a def sits in this container's draw order, counted from the one drawn first.
|
|
175
|
+
*
|
|
176
|
+
* The public read of an assignment the order pass makes privately. Picking uses it to break a tie
|
|
177
|
+
* the depth buffer never resolved: two surfaces closer together than `depthSeparation` are drawn
|
|
178
|
+
* in list order rather than depth order, so list order is also what decides which of them the
|
|
179
|
+
* pointer is on (see `orderCoplanarHits`). Per def rather than per slot, because a slot is a mesh's
|
|
180
|
+
* own numbering out of a free list and a def is what the layer ordered.
|
|
181
|
+
*
|
|
182
|
+
* A def this container never ordered reports the first place rather than the last: nothing is known
|
|
183
|
+
* about where it drew, and the one thing that must not happen is for that to outrank a def whose
|
|
184
|
+
* place is known.
|
|
185
|
+
* @param def - The def to place.
|
|
186
|
+
* @returns Its place in the draw order.
|
|
187
|
+
*/
|
|
188
|
+
paintOrderOf(def) {
|
|
189
|
+
return this.orderByDef.get(def) ?? 0;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Registers what to do when a member turns out to belong in a sibling container; `undefined`
|
|
193
|
+
* clears it.
|
|
194
|
+
*
|
|
195
|
+
* Here rather than on each subclass because the situation is one situation: a layer is split
|
|
196
|
+
* across several containers by some property of the def, and that property can move after the def
|
|
197
|
+
* was placed. What splits them differs — a shape's color crossing alpha 1, a model's `opacity`,
|
|
198
|
+
* an image's orientation — but what a container does about it does not, and the component that
|
|
199
|
+
* owns the split is always the one that can repair it.
|
|
200
|
+
*
|
|
201
|
+
* A method rather than an assignable field because the container is held in `useState`, and the
|
|
202
|
+
* React Compiler rejects writing to a property of a state value ("This value cannot be modified").
|
|
203
|
+
* Calling a method is fine, which is how {@link reserve} already mutates.
|
|
204
|
+
* @param handler - The re-split to run, or `undefined` to clear it.
|
|
205
|
+
*/
|
|
206
|
+
setKindMismatchHandler(handler) {
|
|
207
|
+
this.kindMismatchHandler = handler;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Reports that a member no longer belongs in this container, so it is drawing from the wrong mesh.
|
|
211
|
+
* Runs the registered handler, if any; a container mounted without one — in a spec, or bare —
|
|
212
|
+
* drops the report rather than failing, since nothing it could do would be more correct than
|
|
213
|
+
* carrying on.
|
|
214
|
+
*/
|
|
215
|
+
reportKindMismatch() {
|
|
216
|
+
this.kindMismatchHandler?.();
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Shows or hides one instance. Every def type carries `hidden`, so `useDefSync` drives this for
|
|
220
|
+
* all of them.
|
|
221
|
+
* @param slot - The slot to show or hide.
|
|
222
|
+
* @param visible - Whether the instance should draw.
|
|
223
|
+
*/
|
|
224
|
+
setVisibleAt(slot, visible) {
|
|
225
|
+
this.mesh.setVisibleAt(slot, visible);
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Sets one instance's own dim, or clears it back to its layer's.
|
|
229
|
+
*
|
|
230
|
+
* The counterpart to {@link setVisibleAt}, and here for the same reason: `dim` is a `SharedDef`
|
|
231
|
+
* field, so `useDefSync` drives it for every def type. The raw field is passed through rather than
|
|
232
|
+
* an encoded amount, which keeps the sentinel — and the rest of the shader's contract — inside the
|
|
233
|
+
* material module that reads it.
|
|
234
|
+
* @param slot - The slot to dim.
|
|
235
|
+
* @param dim - The def's `dim`; `undefined` defers to the layer's.
|
|
236
|
+
*/
|
|
237
|
+
setDimAt(slot, dim) {
|
|
238
|
+
this.writeDim(slot, instanceDim(dim));
|
|
239
|
+
// Crossing the dimmed/lit split changes where this def draws, and nothing else will notice: a
|
|
240
|
+
// def's own `update()` reaches its instance, never the component that renders this container.
|
|
241
|
+
const dimmed = isDimmed(dim, this.layerDimmed);
|
|
242
|
+
if (this.layerDefs.length === 0 || this.dimmedBySlot[slot] === dimmed)
|
|
243
|
+
return;
|
|
244
|
+
this.applyOrder();
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Writes an encoded dim into a slot's uniform — the part of {@link setDimAt} that knows how a slot
|
|
248
|
+
* maps onto the mesh, split out so a container whose slot spans several mesh instances overrides
|
|
249
|
+
* only that and keeps the split-crossing check above.
|
|
250
|
+
* @param slot - The slot to write.
|
|
251
|
+
* @param amount - The encoded amount, from `instanceDim`.
|
|
252
|
+
*/
|
|
253
|
+
writeDim(slot, amount) {
|
|
254
|
+
this.mesh.setUniformAt(slot, DIM_UNIFORM, amount);
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Declares the layer's membership and dim, and re-runs the order pass over them.
|
|
258
|
+
*
|
|
259
|
+
* The component calls this from an effect after each structural change — child effects run first,
|
|
260
|
+
* so every mounted instance has claimed by then. Defs that have not claimed yet are recorded
|
|
261
|
+
* anyway: a later claim seeds its slot's order from this assignment, which is what keeps a
|
|
262
|
+
* re-claim correctly ordered without React involvement.
|
|
263
|
+
* @param defs - The current membership, in paint order.
|
|
264
|
+
* @param layerDimmed - Whether the layer is dimmed, inherited by defs without a `dim` of their own.
|
|
265
|
+
*/
|
|
266
|
+
setPaintOrder(defs, layerDimmed) {
|
|
267
|
+
this.layerDefs = defs;
|
|
268
|
+
this.layerDimmed = layerDimmed;
|
|
269
|
+
this.applyOrder();
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* The layer's defs in the order they draw, each labeled with its place in it.
|
|
273
|
+
*
|
|
274
|
+
* Every order pass starts here, the overriding ones included, so the labels exist whatever a
|
|
275
|
+
* container then does with the order — a sortable draw list for most of them, a rebuilt member
|
|
276
|
+
* list for a text batch. That is what lets {@link paintOrderOf} answer for any container's hits
|
|
277
|
+
* rather than only the ones whose mesh sorts.
|
|
278
|
+
* @returns The defs, dimmed first.
|
|
279
|
+
*/
|
|
280
|
+
orderedDefs() {
|
|
281
|
+
const ordered = dimOrdered(this.layerDefs, this.layerDimmed);
|
|
282
|
+
for (let order = 0; order < ordered.length; order++)
|
|
283
|
+
this.orderByDef.set(ordered[order], order);
|
|
284
|
+
return ordered;
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Labels every claimed slot with its place in the layer's draw order, undimmed defs last.
|
|
288
|
+
*
|
|
289
|
+
* Overridden by a container whose mesh has no sortable draw list, where ordering means handing the
|
|
290
|
+
* mesh a rebuilt member list instead.
|
|
291
|
+
*/
|
|
292
|
+
applyOrder() {
|
|
293
|
+
const ordered = this.orderedDefs();
|
|
294
|
+
for (let order = 0; order < ordered.length; order++) {
|
|
295
|
+
const def = ordered[order];
|
|
296
|
+
const slot = this.slotOf(def);
|
|
297
|
+
if (slot === undefined)
|
|
298
|
+
continue;
|
|
299
|
+
this.orderBySlot[slot] = order;
|
|
300
|
+
this.dimmedBySlot[slot] = isDimmed(def.dim, this.layerDimmed);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* The slot a def holds, for an order pass walking the layer's defs.
|
|
305
|
+
* @param def - The def to look up.
|
|
306
|
+
* @returns The slot, or `undefined` when the def has not claimed one.
|
|
307
|
+
*/
|
|
308
|
+
slotOf(def) {
|
|
309
|
+
return this.slotByDef.get(def);
|
|
310
|
+
}
|
|
311
|
+
}
|