@opsydyn/effect-three 0.0.0-stage → 0.2.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/CHANGELOG.md +69 -0
- package/LICENSE +21 -0
- package/README.md +189 -2
- package/dist/index-01kwfekm.js +5118 -0
- package/dist/index-01kwfekm.js.map +40 -0
- package/dist/index-4045wme0.js +129 -0
- package/dist/index-4045wme0.js.map +10 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1361 -0
- package/dist/index.js.map +14 -0
- package/dist/kernel/animation.d.ts +14 -0
- package/dist/kernel/animation.d.ts.map +1 -0
- package/dist/kernel/behaviours.d.ts +16 -0
- package/dist/kernel/behaviours.d.ts.map +1 -0
- package/dist/kernel/bodies.d.ts +60 -0
- package/dist/kernel/bodies.d.ts.map +1 -0
- package/dist/kernel/bodySources.d.ts +47 -0
- package/dist/kernel/bodySources.d.ts.map +1 -0
- package/dist/kernel/build.d.ts +564 -0
- package/dist/kernel/build.d.ts.map +1 -0
- package/dist/kernel/cameraMotion.d.ts +39 -0
- package/dist/kernel/cameraMotion.d.ts.map +1 -0
- package/dist/kernel/clock.d.ts +17 -0
- package/dist/kernel/clock.d.ts.map +1 -0
- package/dist/kernel/contactShadowPasses.d.ts +47 -0
- package/dist/kernel/contactShadowPasses.d.ts.map +1 -0
- package/dist/kernel/description.d.ts +1120 -0
- package/dist/kernel/description.d.ts.map +1 -0
- package/dist/kernel/diff.d.ts +90 -0
- package/dist/kernel/diff.d.ts.map +1 -0
- package/dist/kernel/environmentPresets.d.ts +30 -0
- package/dist/kernel/environmentPresets.d.ts.map +1 -0
- package/dist/kernel/equality.d.ts +64 -0
- package/dist/kernel/equality.d.ts.map +1 -0
- package/dist/kernel/frames.d.ts +55 -0
- package/dist/kernel/frames.d.ts.map +1 -0
- package/dist/kernel/index.d.ts +37 -0
- package/dist/kernel/index.d.ts.map +1 -0
- package/dist/kernel/index.js +335 -0
- package/dist/kernel/index.js.map +9 -0
- package/dist/kernel/instances.d.ts +26 -0
- package/dist/kernel/instances.d.ts.map +1 -0
- package/dist/kernel/labels.d.ts +51 -0
- package/dist/kernel/labels.d.ts.map +1 -0
- package/dist/kernel/loop.d.ts +49 -0
- package/dist/kernel/loop.d.ts.map +1 -0
- package/dist/kernel/materials.d.ts +24 -0
- package/dist/kernel/materials.d.ts.map +1 -0
- package/dist/kernel/motion.d.ts +36 -0
- package/dist/kernel/motion.d.ts.map +1 -0
- package/dist/kernel/orbit.d.ts +127 -0
- package/dist/kernel/orbit.d.ts.map +1 -0
- package/dist/kernel/overlays.d.ts +16 -0
- package/dist/kernel/overlays.d.ts.map +1 -0
- package/dist/kernel/performance.d.ts +41 -0
- package/dist/kernel/performance.d.ts.map +1 -0
- package/dist/kernel/physics.d.ts +166 -0
- package/dist/kernel/physics.d.ts.map +1 -0
- package/dist/kernel/physicsDebug.d.ts +18 -0
- package/dist/kernel/physicsDebug.d.ts.map +1 -0
- package/dist/kernel/pointer.d.ts +357 -0
- package/dist/kernel/pointer.d.ts.map +1 -0
- package/dist/kernel/renderKit.d.ts +49 -0
- package/dist/kernel/renderKit.d.ts.map +1 -0
- package/dist/kernel/renderer.d.ts +83 -0
- package/dist/kernel/renderer.d.ts.map +1 -0
- package/dist/kernel/resources.d.ts +112 -0
- package/dist/kernel/resources.d.ts.map +1 -0
- package/dist/kernel/sceneGraph.d.ts +155 -0
- package/dist/kernel/sceneGraph.d.ts.map +1 -0
- package/dist/kernel/sceneIndex.d.ts +90 -0
- package/dist/kernel/sceneIndex.d.ts.map +1 -0
- package/dist/kernel/stage.d.ts +87 -0
- package/dist/kernel/stage.d.ts.map +1 -0
- package/dist/kernel/textLayout.d.ts +29 -0
- package/dist/kernel/textLayout.d.ts.map +1 -0
- package/dist/kernel/tween.d.ts +35 -0
- package/dist/kernel/tween.d.ts.map +1 -0
- package/dist/kernel/xrInput.d.ts +107 -0
- package/dist/kernel/xrInput.d.ts.map +1 -0
- package/dist/kernel/xrLocomotion.d.ts +38 -0
- package/dist/kernel/xrLocomotion.d.ts.map +1 -0
- package/dist/runtime/FrameSource.d.ts +29 -0
- package/dist/runtime/FrameSource.d.ts.map +1 -0
- package/dist/runtime/ResourceRegistry.d.ts +18 -0
- package/dist/runtime/ResourceRegistry.d.ts.map +1 -0
- package/dist/runtime/SceneRuntime.d.ts +68 -0
- package/dist/runtime/SceneRuntime.d.ts.map +1 -0
- package/dist/runtime/SceneSchema.d.ts +2536 -0
- package/dist/runtime/SceneSchema.d.ts.map +1 -0
- package/dist/runtime/errors.d.ts +19 -0
- package/dist/runtime/errors.d.ts.map +1 -0
- package/dist/runtime/index.d.ts +11 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/webgl/contactShadows.d.ts +5 -0
- package/dist/webgl/contactShadows.d.ts.map +1 -0
- package/dist/webgl/index.d.ts +11 -0
- package/dist/webgl/index.d.ts.map +1 -0
- package/dist/webgl/index.js +239 -0
- package/dist/webgl/index.js.map +13 -0
- package/dist/webgl/shaderGrid.d.ts +27 -0
- package/dist/webgl/shaderGrid.d.ts.map +1 -0
- package/dist/webgl/sky.d.ts +4 -0
- package/dist/webgl/sky.d.ts.map +1 -0
- package/dist/webgpu/contactShadows.d.ts +5 -0
- package/dist/webgpu/contactShadows.d.ts.map +1 -0
- package/dist/webgpu/index.d.ts +10 -0
- package/dist/webgpu/index.d.ts.map +1 -0
- package/dist/webgpu/index.js +216 -0
- package/dist/webgpu/index.js.map +13 -0
- package/dist/webgpu/shaderGrid.d.ts +5 -0
- package/dist/webgpu/shaderGrid.d.ts.map +1 -0
- package/dist/webgpu/sky.d.ts +4 -0
- package/dist/webgpu/sky.d.ts.map +1 -0
- package/package.json +82 -4
- package/src/index.ts +11 -0
- package/src/kernel/animation.ts +24 -0
- package/src/kernel/behaviours.ts +36 -0
- package/src/kernel/bodies.ts +338 -0
- package/src/kernel/bodySources.ts +203 -0
- package/src/kernel/build.ts +1325 -0
- package/src/kernel/cameraMotion.ts +202 -0
- package/src/kernel/clock.ts +35 -0
- package/src/kernel/contactShadowPasses.ts +207 -0
- package/src/kernel/description.ts +1197 -0
- package/src/kernel/diff.ts +383 -0
- package/src/kernel/environmentPresets.ts +38 -0
- package/src/kernel/equality.ts +604 -0
- package/src/kernel/frames.ts +124 -0
- package/src/kernel/index.ts +274 -0
- package/src/kernel/instances.ts +97 -0
- package/src/kernel/labels.ts +54 -0
- package/src/kernel/loop.ts +248 -0
- package/src/kernel/materials.ts +258 -0
- package/src/kernel/motion.ts +75 -0
- package/src/kernel/orbit.ts +554 -0
- package/src/kernel/overlays.ts +130 -0
- package/src/kernel/performance.ts +101 -0
- package/src/kernel/physics.ts +361 -0
- package/src/kernel/physicsDebug.ts +68 -0
- package/src/kernel/pointer.ts +785 -0
- package/src/kernel/renderKit.ts +54 -0
- package/src/kernel/renderer.ts +136 -0
- package/src/kernel/resources.ts +504 -0
- package/src/kernel/sceneGraph.ts +1442 -0
- package/src/kernel/sceneIndex.ts +219 -0
- package/src/kernel/stage.ts +157 -0
- package/src/kernel/textLayout.ts +102 -0
- package/src/kernel/tween.ts +80 -0
- package/src/kernel/xrInput.ts +230 -0
- package/src/kernel/xrLocomotion.ts +72 -0
- package/src/runtime/FrameSource.ts +41 -0
- package/src/runtime/ResourceRegistry.ts +24 -0
- package/src/runtime/SceneRuntime.ts +229 -0
- package/src/runtime/SceneSchema.ts +983 -0
- package/src/runtime/errors.ts +18 -0
- package/src/runtime/index.ts +10 -0
- package/src/webgl/contactShadows.ts +67 -0
- package/src/webgl/index.ts +19 -0
- package/src/webgl/shaderGrid.ts +196 -0
- package/src/webgl/sky.ts +42 -0
- package/src/webgpu/contactShadows.ts +83 -0
- package/src/webgpu/index.ts +19 -0
- package/src/webgpu/shaderGrid.ts +158 -0
- package/src/webgpu/sky.ts +35 -0
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keyed diff: `(previous index, next description) => operations`.
|
|
3
|
+
*
|
|
4
|
+
* Pure. Operations are emitted in the order the applier must run them:
|
|
5
|
+
*
|
|
6
|
+
* 1. `SetCamera`, `DefineResources`
|
|
7
|
+
* 2. `Create`, `Replace`, `Move`, `Update` in depth-first pre-order (parents first)
|
|
8
|
+
* 3. `Remove`
|
|
9
|
+
* 4. `Order`, only where child order would otherwise be wrong
|
|
10
|
+
*
|
|
11
|
+
* Keys are unique across the scene, so a node keeps its identity when it moves between
|
|
12
|
+
* parents. A node whose kind changes under the same key is replaced.
|
|
13
|
+
*
|
|
14
|
+
* @module
|
|
15
|
+
*/
|
|
16
|
+
import type {
|
|
17
|
+
Camera,
|
|
18
|
+
RenderSettings,
|
|
19
|
+
ResourceDefinitions,
|
|
20
|
+
SceneDescription,
|
|
21
|
+
SceneNode,
|
|
22
|
+
View,
|
|
23
|
+
} from './description.ts';
|
|
24
|
+
import {
|
|
25
|
+
cameraEquals,
|
|
26
|
+
renderSettingsEquals,
|
|
27
|
+
animationEquals,
|
|
28
|
+
behaviourEquals,
|
|
29
|
+
bodyEquals,
|
|
30
|
+
geometryRefEquals,
|
|
31
|
+
labelMaterialEquals,
|
|
32
|
+
labelTypeEquals,
|
|
33
|
+
xrSpaceEquals,
|
|
34
|
+
shaderGridLookEquals,
|
|
35
|
+
instancesEqual,
|
|
36
|
+
materialRefEquals,
|
|
37
|
+
resourcesEqual,
|
|
38
|
+
rotationEquals,
|
|
39
|
+
transitionEquals,
|
|
40
|
+
viewsEqual,
|
|
41
|
+
vec3Equals,
|
|
42
|
+
} from './equality.ts';
|
|
43
|
+
import {
|
|
44
|
+
type DescriptionError,
|
|
45
|
+
indexScene,
|
|
46
|
+
type ParentKey,
|
|
47
|
+
type SceneIndex,
|
|
48
|
+
} from './sceneIndex.ts';
|
|
49
|
+
|
|
50
|
+
/** A node property that an `Update` changes. */
|
|
51
|
+
export type Field =
|
|
52
|
+
| 'position'
|
|
53
|
+
| 'rotation'
|
|
54
|
+
| 'scale'
|
|
55
|
+
| 'transition'
|
|
56
|
+
| 'geometry'
|
|
57
|
+
| 'material'
|
|
58
|
+
| 'interactive'
|
|
59
|
+
| 'color'
|
|
60
|
+
| 'intensity'
|
|
61
|
+
| 'groundColor'
|
|
62
|
+
| 'target'
|
|
63
|
+
| 'distance'
|
|
64
|
+
| 'angle'
|
|
65
|
+
| 'penumbra'
|
|
66
|
+
| 'decay'
|
|
67
|
+
| 'castShadow'
|
|
68
|
+
| 'receiveShadow'
|
|
69
|
+
| 'shadowMapSize'
|
|
70
|
+
| 'shadowBias'
|
|
71
|
+
| 'shadowArea'
|
|
72
|
+
| 'instances'
|
|
73
|
+
| 'id'
|
|
74
|
+
| 'animation'
|
|
75
|
+
| 'behaviour'
|
|
76
|
+
| 'size'
|
|
77
|
+
| 'divisions'
|
|
78
|
+
| 'centerColor'
|
|
79
|
+
| 'body'
|
|
80
|
+
/** A label's text or any of its type settings. */
|
|
81
|
+
| 'text'
|
|
82
|
+
/** A shader grid's look: anything but where it is. */
|
|
83
|
+
| 'grid'
|
|
84
|
+
/** The tracked space a group follows. */
|
|
85
|
+
| 'follow';
|
|
86
|
+
|
|
87
|
+
/** A single change to apply to the hosted scene graph. */
|
|
88
|
+
export type Op =
|
|
89
|
+
| { readonly _tag: 'SetCamera'; readonly camera: Camera }
|
|
90
|
+
| { readonly _tag: 'SetViews'; readonly views: ReadonlyArray<View> }
|
|
91
|
+
/** A render texture was created, resized or its scene changed (its own operations). */
|
|
92
|
+
| { readonly _tag: 'UpdateRenderTexture'; readonly id: string; readonly ops: ReadonlyArray<Op> }
|
|
93
|
+
| { readonly _tag: 'RemoveRenderTexture'; readonly id: string }
|
|
94
|
+
| { readonly _tag: 'SetRenderSettings'; readonly settings: RenderSettings }
|
|
95
|
+
| { readonly _tag: 'DefineResources'; readonly resources: ResourceDefinitions }
|
|
96
|
+
| { readonly _tag: 'Create'; readonly node: SceneNode; readonly parent: ParentKey }
|
|
97
|
+
| { readonly _tag: 'Replace'; readonly node: SceneNode; readonly parent: ParentKey }
|
|
98
|
+
| { readonly _tag: 'Move'; readonly key: string; readonly parent: ParentKey }
|
|
99
|
+
| {
|
|
100
|
+
readonly _tag: 'Update';
|
|
101
|
+
readonly node: SceneNode;
|
|
102
|
+
readonly fields: ReadonlyArray<Field>;
|
|
103
|
+
}
|
|
104
|
+
| { readonly _tag: 'Remove'; readonly key: string }
|
|
105
|
+
| { readonly _tag: 'Order'; readonly parent: ParentKey; readonly keys: ReadonlyArray<string> };
|
|
106
|
+
|
|
107
|
+
export type DiffResult =
|
|
108
|
+
| { readonly _tag: 'Diffed'; readonly ops: ReadonlyArray<Op>; readonly index: SceneIndex }
|
|
109
|
+
| { readonly _tag: 'Invalid'; readonly error: DescriptionError };
|
|
110
|
+
|
|
111
|
+
const noFields: ReadonlyArray<Field> = [];
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Fields that differ between two nodes, or `undefined` when the kind changed and the
|
|
115
|
+
* node must be replaced.
|
|
116
|
+
*/
|
|
117
|
+
export const changedFields = (
|
|
118
|
+
prev: SceneNode,
|
|
119
|
+
next: SceneNode,
|
|
120
|
+
): ReadonlyArray<Field> | undefined => {
|
|
121
|
+
if (prev === next) return noFields;
|
|
122
|
+
const fields: Array<Field> = [];
|
|
123
|
+
switch (next._tag) {
|
|
124
|
+
case 'Group': {
|
|
125
|
+
if (prev._tag !== 'Group') return undefined;
|
|
126
|
+
if (!behaviourEquals(prev.behaviour, next.behaviour)) fields.push('behaviour');
|
|
127
|
+
if (!vec3Equals(prev.position, next.position)) fields.push('position');
|
|
128
|
+
if (!rotationEquals(prev.rotation, next.rotation)) fields.push('rotation');
|
|
129
|
+
if (!vec3Equals(prev.scale, next.scale)) fields.push('scale');
|
|
130
|
+
if (!transitionEquals(prev.transition, next.transition)) fields.push('transition');
|
|
131
|
+
if (prev.interactive !== next.interactive) fields.push('interactive');
|
|
132
|
+
if (!bodyEquals(prev.body, next.body)) fields.push('body');
|
|
133
|
+
if (!xrSpaceEquals(prev.follow, next.follow)) fields.push('follow');
|
|
134
|
+
return fields;
|
|
135
|
+
}
|
|
136
|
+
case 'Mesh': {
|
|
137
|
+
if (prev._tag !== 'Mesh') return undefined;
|
|
138
|
+
if (!behaviourEquals(prev.behaviour, next.behaviour)) fields.push('behaviour');
|
|
139
|
+
if (!vec3Equals(prev.position, next.position)) fields.push('position');
|
|
140
|
+
if (!rotationEquals(prev.rotation, next.rotation)) fields.push('rotation');
|
|
141
|
+
if (!vec3Equals(prev.scale, next.scale)) fields.push('scale');
|
|
142
|
+
if (!transitionEquals(prev.transition, next.transition)) fields.push('transition');
|
|
143
|
+
if (!geometryRefEquals(prev.geometry, next.geometry)) fields.push('geometry');
|
|
144
|
+
if (!materialRefEquals(prev.material, next.material)) fields.push('material');
|
|
145
|
+
if (prev.interactive !== next.interactive) fields.push('interactive');
|
|
146
|
+
if (prev.castShadow !== next.castShadow) fields.push('castShadow');
|
|
147
|
+
if (prev.receiveShadow !== next.receiveShadow) fields.push('receiveShadow');
|
|
148
|
+
if (!bodyEquals(prev.body, next.body)) fields.push('body');
|
|
149
|
+
return fields;
|
|
150
|
+
}
|
|
151
|
+
case 'Instances': {
|
|
152
|
+
if (prev._tag !== 'Instances') return undefined;
|
|
153
|
+
if (!behaviourEquals(prev.behaviour, next.behaviour)) fields.push('behaviour');
|
|
154
|
+
if (!vec3Equals(prev.position, next.position)) fields.push('position');
|
|
155
|
+
if (!rotationEquals(prev.rotation, next.rotation)) fields.push('rotation');
|
|
156
|
+
if (!vec3Equals(prev.scale, next.scale)) fields.push('scale');
|
|
157
|
+
if (!transitionEquals(prev.transition, next.transition)) fields.push('transition');
|
|
158
|
+
if (!geometryRefEquals(prev.geometry, next.geometry)) fields.push('geometry');
|
|
159
|
+
if (!materialRefEquals(prev.material, next.material)) fields.push('material');
|
|
160
|
+
if (prev.interactive !== next.interactive) fields.push('interactive');
|
|
161
|
+
if (prev.castShadow !== next.castShadow) fields.push('castShadow');
|
|
162
|
+
if (prev.receiveShadow !== next.receiveShadow) fields.push('receiveShadow');
|
|
163
|
+
if (!instancesEqual(prev.instances, next.instances)) fields.push('instances');
|
|
164
|
+
if (!bodyEquals(prev.body, next.body)) fields.push('body');
|
|
165
|
+
return fields;
|
|
166
|
+
}
|
|
167
|
+
case 'Borrowed': {
|
|
168
|
+
if (prev._tag !== 'Borrowed') return undefined;
|
|
169
|
+
if (!behaviourEquals(prev.behaviour, next.behaviour)) fields.push('behaviour');
|
|
170
|
+
if (!vec3Equals(prev.position, next.position)) fields.push('position');
|
|
171
|
+
if (!rotationEquals(prev.rotation, next.rotation)) fields.push('rotation');
|
|
172
|
+
if (!vec3Equals(prev.scale, next.scale)) fields.push('scale');
|
|
173
|
+
if (!transitionEquals(prev.transition, next.transition)) fields.push('transition');
|
|
174
|
+
if (prev.id !== next.id) fields.push('id');
|
|
175
|
+
if (!animationEquals(prev.animation, next.animation)) fields.push('animation');
|
|
176
|
+
if (prev.interactive !== next.interactive) fields.push('interactive');
|
|
177
|
+
if (!bodyEquals(prev.body, next.body)) fields.push('body');
|
|
178
|
+
return fields;
|
|
179
|
+
}
|
|
180
|
+
case 'Label': {
|
|
181
|
+
if (prev._tag !== 'Label') return undefined;
|
|
182
|
+
if (!behaviourEquals(prev.behaviour, next.behaviour)) fields.push('behaviour');
|
|
183
|
+
if (!vec3Equals(prev.position, next.position)) fields.push('position');
|
|
184
|
+
if (!rotationEquals(prev.rotation, next.rotation)) fields.push('rotation');
|
|
185
|
+
if (!vec3Equals(prev.scale, next.scale)) fields.push('scale');
|
|
186
|
+
if (!transitionEquals(prev.transition, next.transition)) fields.push('transition');
|
|
187
|
+
if (prev.interactive !== next.interactive) fields.push('interactive');
|
|
188
|
+
if (!labelTypeEquals(prev, next)) fields.push('text');
|
|
189
|
+
if (!labelMaterialEquals(prev.material, next.material)) fields.push('material');
|
|
190
|
+
return fields;
|
|
191
|
+
}
|
|
192
|
+
case 'AmbientLight': {
|
|
193
|
+
if (prev._tag !== 'AmbientLight') return undefined;
|
|
194
|
+
if (!Object.is(prev.color, next.color)) fields.push('color');
|
|
195
|
+
if (!Object.is(prev.intensity, next.intensity)) fields.push('intensity');
|
|
196
|
+
return fields;
|
|
197
|
+
}
|
|
198
|
+
case 'DirectionalLight': {
|
|
199
|
+
if (prev._tag !== 'DirectionalLight') return undefined;
|
|
200
|
+
if (!Object.is(prev.color, next.color)) fields.push('color');
|
|
201
|
+
if (!Object.is(prev.intensity, next.intensity)) fields.push('intensity');
|
|
202
|
+
if (!vec3Equals(prev.position, next.position)) fields.push('position');
|
|
203
|
+
if (prev.castShadow !== next.castShadow) fields.push('castShadow');
|
|
204
|
+
if (!Object.is(prev.shadowMapSize, next.shadowMapSize)) fields.push('shadowMapSize');
|
|
205
|
+
if (!Object.is(prev.shadowBias, next.shadowBias)) fields.push('shadowBias');
|
|
206
|
+
if (!Object.is(prev.shadowArea, next.shadowArea)) fields.push('shadowArea');
|
|
207
|
+
return fields;
|
|
208
|
+
}
|
|
209
|
+
case 'PointLight': {
|
|
210
|
+
if (prev._tag !== 'PointLight') return undefined;
|
|
211
|
+
if (!Object.is(prev.color, next.color)) fields.push('color');
|
|
212
|
+
if (!Object.is(prev.intensity, next.intensity)) fields.push('intensity');
|
|
213
|
+
if (!vec3Equals(prev.position, next.position)) fields.push('position');
|
|
214
|
+
if (!Object.is(prev.distance, next.distance)) fields.push('distance');
|
|
215
|
+
if (!Object.is(prev.decay, next.decay)) fields.push('decay');
|
|
216
|
+
if (prev.castShadow !== next.castShadow) fields.push('castShadow');
|
|
217
|
+
if (!Object.is(prev.shadowMapSize, next.shadowMapSize)) fields.push('shadowMapSize');
|
|
218
|
+
if (!Object.is(prev.shadowBias, next.shadowBias)) fields.push('shadowBias');
|
|
219
|
+
return fields;
|
|
220
|
+
}
|
|
221
|
+
case 'SpotLight': {
|
|
222
|
+
if (prev._tag !== 'SpotLight') return undefined;
|
|
223
|
+
if (!Object.is(prev.color, next.color)) fields.push('color');
|
|
224
|
+
if (!Object.is(prev.intensity, next.intensity)) fields.push('intensity');
|
|
225
|
+
if (!vec3Equals(prev.position, next.position)) fields.push('position');
|
|
226
|
+
if (!vec3Equals(prev.target, next.target)) fields.push('target');
|
|
227
|
+
if (!Object.is(prev.distance, next.distance)) fields.push('distance');
|
|
228
|
+
if (!Object.is(prev.angle, next.angle)) fields.push('angle');
|
|
229
|
+
if (!Object.is(prev.penumbra, next.penumbra)) fields.push('penumbra');
|
|
230
|
+
if (!Object.is(prev.decay, next.decay)) fields.push('decay');
|
|
231
|
+
if (prev.castShadow !== next.castShadow) fields.push('castShadow');
|
|
232
|
+
if (!Object.is(prev.shadowMapSize, next.shadowMapSize)) fields.push('shadowMapSize');
|
|
233
|
+
if (!Object.is(prev.shadowBias, next.shadowBias)) fields.push('shadowBias');
|
|
234
|
+
return fields;
|
|
235
|
+
}
|
|
236
|
+
case 'ShaderGrid': {
|
|
237
|
+
if (prev._tag !== 'ShaderGrid') return undefined;
|
|
238
|
+
if (!vec3Equals(prev.position, next.position)) fields.push('position');
|
|
239
|
+
if (!vec3Equals(prev.rotation, next.rotation)) fields.push('rotation');
|
|
240
|
+
if (!shaderGridLookEquals(prev, next)) fields.push('grid');
|
|
241
|
+
return fields;
|
|
242
|
+
}
|
|
243
|
+
case 'Grid': {
|
|
244
|
+
if (prev._tag !== 'Grid') return undefined;
|
|
245
|
+
if (!vec3Equals(prev.position, next.position)) fields.push('position');
|
|
246
|
+
if (!Object.is(prev.size, next.size)) fields.push('size');
|
|
247
|
+
if (prev.divisions !== next.divisions) fields.push('divisions');
|
|
248
|
+
if (prev.color !== next.color) fields.push('color');
|
|
249
|
+
if (prev.centerColor !== next.centerColor) fields.push('centerColor');
|
|
250
|
+
return fields;
|
|
251
|
+
}
|
|
252
|
+
case 'HemisphereLight': {
|
|
253
|
+
if (prev._tag !== 'HemisphereLight') return undefined;
|
|
254
|
+
if (!Object.is(prev.color, next.color)) fields.push('color');
|
|
255
|
+
if (!Object.is(prev.groundColor, next.groundColor)) fields.push('groundColor');
|
|
256
|
+
if (!Object.is(prev.intensity, next.intensity)) fields.push('intensity');
|
|
257
|
+
if (!vec3Equals(prev.position, next.position)) fields.push('position');
|
|
258
|
+
return fields;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Whether a parent's children end up in `keys` order without an `Order`: its previous
|
|
265
|
+
* children still under it, in previous order, then those appended by this diff. Compared
|
|
266
|
+
* in place, as it runs for every parent on every reconcile.
|
|
267
|
+
*/
|
|
268
|
+
const inOrder = (
|
|
269
|
+
previous: ReadonlyArray<string>,
|
|
270
|
+
appended: ReadonlyArray<string>,
|
|
271
|
+
keys: ReadonlyArray<string>,
|
|
272
|
+
stays: (key: string) => boolean,
|
|
273
|
+
): boolean => {
|
|
274
|
+
let at = 0;
|
|
275
|
+
for (const key of previous) {
|
|
276
|
+
if (!stays(key)) continue;
|
|
277
|
+
if (keys[at] !== key) return false;
|
|
278
|
+
at++;
|
|
279
|
+
}
|
|
280
|
+
for (const key of appended) {
|
|
281
|
+
if (keys[at] !== key) return false;
|
|
282
|
+
at++;
|
|
283
|
+
}
|
|
284
|
+
return at === keys.length;
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
const noKeys: ReadonlyArray<string> = [];
|
|
288
|
+
|
|
289
|
+
const noBehaviours: ReadonlySet<string> = new Set();
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Diffs a validated previous scene against the next description. `behaviours` are the
|
|
293
|
+
* names registered with the scene; naming any other is invalid.
|
|
294
|
+
*/
|
|
295
|
+
export const diff = (
|
|
296
|
+
prev: SceneIndex,
|
|
297
|
+
next: SceneDescription,
|
|
298
|
+
behaviours: ReadonlySet<string> = noBehaviours,
|
|
299
|
+
): DiffResult => {
|
|
300
|
+
if (prev.description === next) return { _tag: 'Diffed', ops: [], index: prev };
|
|
301
|
+
const indexed = indexScene(next, behaviours);
|
|
302
|
+
if (indexed._tag === 'Invalid') return indexed;
|
|
303
|
+
const index = indexed.index;
|
|
304
|
+
const ops: Array<Op> = [];
|
|
305
|
+
|
|
306
|
+
const prevDescription = prev.description;
|
|
307
|
+
if (prevDescription === null || !cameraEquals(prevDescription.camera, next.camera)) {
|
|
308
|
+
ops.push({ _tag: 'SetCamera', camera: next.camera });
|
|
309
|
+
}
|
|
310
|
+
if (prevDescription === null || !viewsEqual(prevDescription.views, next.views)) {
|
|
311
|
+
ops.push({ _tag: 'SetViews', views: next.views });
|
|
312
|
+
}
|
|
313
|
+
if (prevDescription === null || !renderSettingsEquals(prevDescription.render, next.render)) {
|
|
314
|
+
ops.push({ _tag: 'SetRenderSettings', settings: next.render });
|
|
315
|
+
}
|
|
316
|
+
if (prevDescription === null || !resourcesEqual(prevDescription.resources, next.resources)) {
|
|
317
|
+
ops.push({ _tag: 'DefineResources', resources: next.resources });
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// Keys appended to each parent by this diff (created, or moved in from elsewhere).
|
|
321
|
+
const appended = new Map<ParentKey, Array<string>>();
|
|
322
|
+
const append = (parent: ParentKey, key: string): void => {
|
|
323
|
+
const list = appended.get(parent);
|
|
324
|
+
if (list === undefined) appended.set(parent, [key]);
|
|
325
|
+
else list.push(key);
|
|
326
|
+
};
|
|
327
|
+
// Parents whose hosted object was created by this diff: their children arrive in order.
|
|
328
|
+
const freshParents = new Set<string>();
|
|
329
|
+
// Whether any node changed parent (moved, or replaced under another).
|
|
330
|
+
let reparented = false;
|
|
331
|
+
|
|
332
|
+
for (const key of index.preOrder) {
|
|
333
|
+
const current = index.nodes.get(key);
|
|
334
|
+
if (current === undefined) continue;
|
|
335
|
+
const before = prev.nodes.get(key);
|
|
336
|
+
if (before === undefined) {
|
|
337
|
+
ops.push({ _tag: 'Create', node: current.node, parent: current.parent });
|
|
338
|
+
append(current.parent, key);
|
|
339
|
+
freshParents.add(key);
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
342
|
+
const fields = changedFields(before.node, current.node);
|
|
343
|
+
if (fields === undefined) {
|
|
344
|
+
ops.push({ _tag: 'Replace', node: current.node, parent: current.parent });
|
|
345
|
+
if (before.parent !== current.parent) {
|
|
346
|
+
reparented = true;
|
|
347
|
+
append(current.parent, key);
|
|
348
|
+
}
|
|
349
|
+
continue;
|
|
350
|
+
}
|
|
351
|
+
if (before.parent !== current.parent) {
|
|
352
|
+
reparented = true;
|
|
353
|
+
ops.push({ _tag: 'Move', key, parent: current.parent });
|
|
354
|
+
append(current.parent, key);
|
|
355
|
+
}
|
|
356
|
+
if (fields.length > 0) ops.push({ _tag: 'Update', node: current.node, fields });
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// With nothing created and as many nodes as before, every previous key is still here.
|
|
360
|
+
let removed = false;
|
|
361
|
+
if (freshParents.size > 0 || index.nodes.size !== prev.nodes.size) {
|
|
362
|
+
for (const key of prev.preOrder) {
|
|
363
|
+
if (index.nodes.has(key)) continue;
|
|
364
|
+
removed = true;
|
|
365
|
+
ops.push({ _tag: 'Remove', key });
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
// Nothing moved or removed: every previous child is still under its parent.
|
|
369
|
+
const settled = !reparented && !removed;
|
|
370
|
+
|
|
371
|
+
// After the steps above each parent holds its surviving children in previous order,
|
|
372
|
+
// followed by appended children in next order. Reorder only where that is wrong.
|
|
373
|
+
for (const [parent, keys] of index.children) {
|
|
374
|
+
if (parent !== null && freshParents.has(parent)) continue;
|
|
375
|
+
const stays = (key: string): boolean => settled || index.nodes.get(key)?.parent === parent;
|
|
376
|
+
const previous = prev.children.get(parent) ?? noKeys;
|
|
377
|
+
if (!inOrder(previous, appended.get(parent) ?? noKeys, keys, stays)) {
|
|
378
|
+
ops.push({ _tag: 'Order', parent, keys });
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
return { _tag: 'Diffed', ops, index };
|
|
383
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drei's environment presets (`src/helpers/environment-assets.ts` and the `CUBEMAP_ROOT` of
|
|
3
|
+
* `src/core/useEnvironment.tsx` at `bf6f4ad`): Poly Haven HDR panoramas (CC0) on Drei's
|
|
4
|
+
* asset repository at the commit Drei pins, served by a CDN. Nothing is fetched until an
|
|
5
|
+
* application loads one, as an environment map lent like any other:
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* environment.assets.loadEnvironment('sky', environmentPresetUrl('city'));
|
|
9
|
+
* scene({ environment: environment({ map: 'sky' }) });
|
|
10
|
+
* ```
|
|
11
|
+
*
|
|
12
|
+
* @module
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/** Each preset's file. */
|
|
16
|
+
export const environmentPresets = {
|
|
17
|
+
apartment: 'lebombo_1k.hdr',
|
|
18
|
+
city: 'potsdamer_platz_1k.hdr',
|
|
19
|
+
dawn: 'kiara_1_dawn_1k.hdr',
|
|
20
|
+
forest: 'forest_slope_1k.hdr',
|
|
21
|
+
lobby: 'st_fagans_interior_1k.hdr',
|
|
22
|
+
night: 'dikhololo_night_1k.hdr',
|
|
23
|
+
park: 'rooitou_park_1k.hdr',
|
|
24
|
+
studio: 'studio_small_03_1k.hdr',
|
|
25
|
+
sunset: 'venice_sunset_1k.hdr',
|
|
26
|
+
warehouse: 'empty_warehouse_01_1k.hdr',
|
|
27
|
+
} satisfies Readonly<Record<string, string>>;
|
|
28
|
+
|
|
29
|
+
export type EnvironmentPreset = keyof typeof environmentPresets;
|
|
30
|
+
|
|
31
|
+
/** Where Drei's presets are served from: its asset repository at the commit it pins. */
|
|
32
|
+
const dreiAssets = {
|
|
33
|
+
hdri: 'https://raw.githack.com/pmndrs/drei-assets/456060a26bbeb8fdf79326f224b6d99b8bcce736/hdri/',
|
|
34
|
+
} as const;
|
|
35
|
+
|
|
36
|
+
/** The URL of a preset's HDR file, for `assets.loadEnvironment`. */
|
|
37
|
+
export const environmentPresetUrl = (preset: EnvironmentPreset): string =>
|
|
38
|
+
`${dreiAssets.hdri}${environmentPresets[preset]}`;
|