lecodes-sdk 1.1.0 → 2.0.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 +5 -2
- package/dist/editor.d.ts +12 -0
- package/dist/global.d.ts +4 -8
- package/dist/host.d.ts +2 -3
- package/dist/types/animate/tween/Animation.d.ts +0 -3
- package/dist/types/animate/tween/animateValue.d.ts +4 -2
- package/dist/types/animate/tween/easing.d.ts +8 -0
- package/dist/types/animate/tween/spec.d.ts +15 -7
- package/dist/types/audio/audio.d.ts +2 -1
- package/dist/types/canvas/Canvas.d.ts +40 -108
- package/dist/types/canvas/gen/cssColor.d.ts +17 -0
- package/dist/types/canvas/gen/recorder.d.ts +118 -0
- package/dist/types/canvas/gen/spec.d.ts +144 -0
- package/dist/types/core/color.d.ts +3 -1
- package/dist/types/core/pins.d.ts +18 -0
- package/dist/types/g2/Node2D.d.ts +5 -8
- package/dist/types/g2/Scene2D.d.ts +6 -2
- package/dist/types/gl/Foliage.d.ts +30 -7
- package/dist/types/gl/Light.d.ts +11 -0
- package/dist/types/gl/Lightmap.d.ts +13 -2
- package/dist/types/gl/Material.d.ts +17 -3
- package/dist/types/gl/Model.d.ts +6 -2
- package/dist/types/gl/Node.d.ts +3 -6
- package/dist/types/gl/Particles.d.ts +15 -0
- package/dist/types/gl/Scene.d.ts +41 -13
- package/dist/types/gl/Texture.d.ts +1 -1
- package/dist/types/gl/animation/Locomotion.d.ts +59 -3
- package/dist/types/gl/terrain/Terrain.d.ts +8 -0
- package/dist/types/inject.d.ts +11 -11
- package/dist/types/inject.editor.d.ts +1 -0
- package/dist/types/net/core.d.ts +7 -0
- package/dist/types/plugin.d.ts +76 -0
- package/dist/types/plugins/gen/camera/sdk/camera.d.ts +24 -0
- package/dist/types/plugins/gen/camera/sdk/camera.gen.d.ts +25 -0
- package/dist/types/plugins/{geolocation.d.ts → gen/geolocation/sdk/geolocation.d.ts} +2 -20
- package/dist/types/plugins/gen/geolocation/sdk/geolocation.gen.d.ts +31 -0
- package/dist/types/plugins/{map.d.ts → gen/map/sdk/map.d.ts} +9 -50
- package/dist/types/plugins/gen/map/sdk/map.gen.d.ts +53 -0
- package/dist/types/plugins/gen/push/sdk/push.d.ts +23 -0
- package/dist/types/plugins/gen/push/sdk/push.gen.d.ts +35 -0
- package/dist/types/plugins/{qr.d.ts → gen/qr-scanner/sdk/qr-scanner.d.ts} +2 -3
- package/dist/types/plugins/gen/qr-scanner/sdk/qr-scanner.gen.d.ts +15 -0
- package/dist/types/runtime/app.d.ts +9 -2
- package/dist/types/runtime/fetch.d.ts +2 -0
- package/dist/types/runtime/input.d.ts +8 -1
- package/dist/types/runtime/media.d.ts +6 -10
- package/dist/types/runtime/misc.d.ts +4 -1
- package/dist/types/runtime/net.d.ts +3 -2
- package/dist/types/runtime/touch.d.ts +32 -0
- package/dist/types/scene/defineScene.d.ts +43 -2
- package/dist/types/scene/editor.d.ts +52 -0
- package/dist/types/scene/gizmos.d.ts +7 -4
- package/dist/types/ui/NativeView.d.ts +6 -4
- package/dist/types/ui/UI.d.ts +1 -1
- package/dist/types/ui/UIBottomSheet.d.ts +6 -12
- package/dist/types/ui/UIButton.d.ts +12 -14
- package/dist/types/ui/UIContainer.d.ts +0 -6
- package/dist/types/ui/UIImage.d.ts +1 -4
- package/dist/types/ui/UIInput.d.ts +8 -24
- package/dist/types/ui/UIModal.d.ts +0 -2
- package/dist/types/ui/UINode.d.ts +70 -56
- package/dist/types/ui/UIPager.d.ts +28 -27
- package/dist/types/ui/UIPopover.d.ts +0 -2
- package/dist/types/ui/UIScreen.d.ts +12 -17
- package/dist/types/ui/UIScrollable.d.ts +1 -4
- package/dist/types/ui/UIText.d.ts +0 -2
- package/dist/types/ui/UIVideo.d.ts +3 -5
- package/dist/types/ui/UIVirtualizedList.d.ts +14 -16
- package/dist/types/ui/UIWidget.d.ts +10 -9
- package/dist/types/ui/colorKeys.gen.d.ts +9 -0
- package/dist/types/ui/presentable.d.ts +46 -32
- package/dist/types/ui/router.d.ts +18 -7
- package/dist/types/ui/styleColor.d.ts +1 -0
- package/dist/types/ui/transitions.d.ts +18 -0
- package/dist/types/ui/tree.d.ts +75 -0
- package/dist/types/version.d.ts +10 -0
- package/dist/types.json +1 -1
- package/package.json +12 -3
- package/prompts/2d.md +2 -6
- package/prompts/3d.md +1 -5
- package/prompts/README.md +142 -142
- package/prompts/canvas.md +9 -8
- package/prompts/compose.ts +1 -1
- package/prompts/core.md +3 -3
- package/prompts/design.md +1 -1
- package/prompts/dist/2d-game.md +77 -54
- package/prompts/dist/3d-app.md +75 -52
- package/prompts/dist/ar-app.md +74 -51
- package/prompts/dist/design.md +30 -8
- package/prompts/dist/ui-app.md +73 -46
- package/prompts/ui-design.md +2 -3
- package/prompts/ui.md +45 -37
- package/src/animate/tween/Animation.ts +262 -378
- package/src/animate/tween/animateValue.ts +103 -100
- package/src/animate/tween/easing.ts +10 -3
- package/src/animate/tween/spec.ts +505 -479
- package/src/audio/Sound.ts +3 -3
- package/src/audio/audio.ts +162 -161
- package/src/bridges/2d.d.ts +317 -0
- package/src/bridges/app.d.ts +91 -0
- package/src/bridges/audio.d.ts +97 -0
- package/src/bridges/canvas.d.ts +79 -0
- package/src/bridges/device.d.ts +72 -0
- package/src/bridges/fetch.d.ts +80 -0
- package/src/bridges/files.d.ts +70 -0
- package/src/bridges/gl.d.ts +1133 -0
- package/src/bridges/input.d.ts +72 -0
- package/src/bridges/media.d.ts +55 -0
- package/src/bridges/nav.d.ts +71 -0
- package/src/bridges/net.d.ts +52 -0
- package/src/bridges/service.d.ts +52 -0
- package/src/bridges/socket.d.ts +31 -0
- package/src/bridges/storage.d.ts +33 -0
- package/src/bridges/tree.d.ts +301 -0
- package/src/bridges/types.d.ts +49 -0
- package/src/canvas/Canvas.ts +114 -159
- package/src/canvas/gen/cssColor.ts +224 -0
- package/src/canvas/gen/recorder.ts +212 -0
- package/src/canvas/gen/spec.ts +201 -0
- package/src/chisel.ts +193 -0
- package/src/compile/assetMacro.ts +1 -1
- package/src/compile/bundler.ts +11 -2
- package/src/compile/compileProject.ts +43 -4
- package/src/compile/fontMacro.ts +3 -4
- package/src/compile/header.ts +26 -5
- package/src/compile/index.ts +3 -1
- package/src/compile/liteMaterial.ts +1 -1
- package/src/compile/sceneEditor.ts +11 -26
- package/src/core/color.ts +73 -30
- package/src/core/pins.ts +51 -0
- package/src/core/signals.ts +8 -1
- package/src/g2/CharacterController2D.ts +3 -3
- package/src/g2/Node2D.ts +57 -39
- package/src/g2/Physics2D.ts +2 -2
- package/src/g2/Scene2D.ts +35 -23
- package/src/g2/Texture2D.ts +1 -1
- package/src/g2/loop.ts +4 -4
- package/src/gl/Foliage.ts +72 -17
- package/src/gl/Geometry.ts +1 -2
- package/src/gl/Light.ts +13 -0
- package/src/gl/Lightmap.ts +45 -29
- package/src/gl/Material.ts +95 -51
- package/src/gl/Model.ts +172 -167
- package/src/gl/Node.ts +91 -24
- package/src/gl/Particles.ts +20 -1
- package/src/gl/Scene.ts +100 -44
- package/src/gl/Texture.ts +8 -7
- package/src/gl/animation/AnimationClip.ts +1 -1
- package/src/gl/animation/Locomotion.ts +77 -8
- package/src/gl/nav/NavMesh.ts +3 -4
- package/src/gl/physics/Physics.ts +2 -2
- package/src/gl/physics/physicsEvents.ts +3 -3
- package/src/gl/terrain/Terrain.ts +33 -5
- package/src/gl/touch.ts +14 -15
- package/src/host.d.ts +2 -3
- package/src/inject.editor.ts +7 -0
- package/src/inject.ts +233 -236
- package/src/net/core.ts +6 -5
- package/src/net/index.ts +1 -1
- package/src/net/replication.ts +1 -1
- package/src/plugin.ts +191 -0
- package/src/plugins/gen/camera/contract.d.ts +27 -0
- package/src/plugins/gen/camera/sdk/camera.gen.ts +46 -0
- package/src/plugins/gen/camera/sdk/camera.ts +57 -0
- package/src/plugins/gen/geolocation/contract.d.ts +50 -0
- package/src/plugins/gen/geolocation/sdk/geolocation.gen.ts +54 -0
- package/src/plugins/{geolocation.ts → gen/geolocation/sdk/geolocation.ts} +22 -43
- package/src/plugins/gen/map/contract.d.ts +144 -0
- package/src/plugins/gen/map/sdk/map.gen.ts +88 -0
- package/src/plugins/{map.ts → gen/map/sdk/map.ts} +68 -102
- package/src/plugins/gen/push/contract.d.ts +61 -0
- package/src/plugins/gen/push/sdk/push.gen.ts +60 -0
- package/src/plugins/gen/push/sdk/push.ts +105 -0
- package/src/plugins/gen/qr-scanner/contract.d.ts +16 -0
- package/src/plugins/gen/qr-scanner/sdk/qr-scanner.gen.ts +29 -0
- package/src/plugins/gen/qr-scanner/sdk/qr-scanner.ts +52 -0
- package/src/plugins/permission.ts +5 -4
- package/src/runtime/app.ts +20 -9
- package/src/runtime/appEvents.ts +5 -4
- package/src/runtime/channel.ts +18 -15
- package/src/runtime/clipboard.ts +4 -3
- package/src/runtime/datetime.ts +2 -1
- package/src/runtime/device.ts +17 -15
- package/src/runtime/fetch.ts +30 -20
- package/src/runtime/files.ts +16 -15
- package/src/runtime/input.ts +21 -8
- package/src/runtime/media.ts +50 -46
- package/src/runtime/misc.ts +7 -3
- package/src/runtime/net.ts +8 -7
- package/src/runtime/rpc.ts +1 -3
- package/src/runtime/service.ts +19 -14
- package/src/runtime/share.ts +4 -3
- package/src/runtime/storage.ts +6 -4
- package/src/runtime/touch.ts +32 -0
- package/src/scene/defineScene.ts +61 -365
- package/src/scene/editor.ts +408 -0
- package/src/scene/editorPlugins.ts +3 -3
- package/src/scene/gizmos.ts +154 -148
- package/src/server/db/marci/query.ts +1 -1
- package/src/server/host.ts +1 -1
- package/src/server/runtime.ts +1 -1
- package/src/ui/NativeView.ts +72 -25
- package/src/ui/UI.ts +3 -3
- package/src/ui/UIBottomSheet.ts +16 -17
- package/src/ui/UIButton.ts +54 -16
- package/src/ui/UIContainer.ts +0 -6
- package/src/ui/UIImage.ts +34 -30
- package/src/ui/UIInput.ts +29 -37
- package/src/ui/UIModal.ts +1 -3
- package/src/ui/UINode.ts +347 -297
- package/src/ui/UIPager.ts +93 -78
- package/src/ui/UIPopover.ts +0 -2
- package/src/ui/UIScreen.ts +41 -36
- package/src/ui/UIScrollable.ts +19 -13
- package/src/ui/UISpacer.ts +1 -1
- package/src/ui/UITabs.ts +8 -6
- package/src/ui/UIText.ts +7 -17
- package/src/ui/UIVideo.ts +30 -27
- package/src/ui/UIVirtualizedList.ts +58 -59
- package/src/ui/UIWidget.ts +38 -18
- package/src/ui/colorKeys.gen.ts +37 -0
- package/src/ui/fonts.ts +2 -2
- package/src/ui/presentable.ts +59 -42
- package/src/ui/router.ts +52 -35
- package/src/ui/styleColor.ts +56 -0
- package/src/ui/theme.ts +7 -6
- package/src/ui/transitions.ts +249 -0
- package/src/ui/tree.ts +346 -0
- package/src/version.ts +24 -0
- package/tests/helpers/engineWorld.ts +11 -0
- package/tests/helpers/fakeTree.ts +353 -0
- package/tests/helpers/hostStubs.ts +31 -0
- package/tests/helpers/index.ts +14 -0
- package/tests/helpers/memoryMarci.ts +124 -0
- package/tests/helpers/phases.ts +23 -0
- package/tests/helpers/preload.ts +18 -0
- package/tests/helpers/stubApp.ts +2 -0
- package/tests/helpers/stubDevice.ts +2 -0
- package/tests/helpers/stubFetch.ts +2 -0
- package/tests/helpers/stubInput.ts +2 -0
- package/dist/inject.js +0 -4730
- package/dist/types/core/registry.d.ts +0 -7
- package/dist/types/plugins/camera.d.ts +0 -25
- package/dist/types/plugins/push.d.ts +0 -46
- package/src/bridges.d.ts +0 -1760
- package/src/compile/__tests__/assetIconMacro.test.ts +0 -219
- package/src/compile/__tests__/assetMacro.test.ts +0 -100
- package/src/compile/__tests__/assetName.test.ts +0 -55
- package/src/compile/__tests__/compile.test.ts +0 -310
- package/src/compile/__tests__/detectEntry.test.ts +0 -151
- package/src/compile/__tests__/fontMacro.test.ts +0 -199
- package/src/compile/__tests__/serverSplit.test.ts +0 -27
- package/src/core/__tests__/stateMachine.test.ts +0 -132
- package/src/core/registry.ts +0 -23
- package/src/plugins/camera.ts +0 -81
- package/src/plugins/push.ts +0 -132
- package/src/plugins/qr.ts +0 -73
package/src/gl/Model.ts
CHANGED
|
@@ -1,167 +1,172 @@
|
|
|
1
|
-
// A loaded GLB model — its own node kind (a GLB is a node hierarchy with baked animation clips),
|
|
2
|
-
// distinct from Mesh (raw primitives, no animation). Animation is always present, reached as
|
|
3
|
-
// model.anim (an Animator over the GLB's clips — crossfades, blend spaces, layers when you need them):
|
|
4
|
-
// const hero = await Model.load(asset('./hero.glb'))
|
|
5
|
-
// hero.anim.play('Run', { loop: true })
|
|
6
|
-
|
|
7
|
-
import { fetch, type FetchResponse } from "../runtime/fetch"
|
|
8
|
-
import { Node } from "./Node"
|
|
9
|
-
import { Animator, _pushLod, type LodMode } from "./animation/Animator"
|
|
10
|
-
import { Material } from "./Material"
|
|
11
|
-
|
|
12
|
-
/** One polygon under a screen point — what `Model.pickTriangle` returns. `bones` are the vertex's raw
|
|
13
|
-
* JOINTS_0 / WEIGHTS_0 pairs (weight > 0; empty = unweighted), `bind` its position in mesh space,
|
|
14
|
-
* `world` its skinned position this frame. */
|
|
15
|
-
export interface TrianglePick {
|
|
16
|
-
/** the Model's root entity, and the mesh node's own entity (0 when the host has no entity for it) */
|
|
17
|
-
entity: number
|
|
18
|
-
node: number
|
|
19
|
-
nodeName: string
|
|
20
|
-
mesh: string
|
|
21
|
-
primitive: number
|
|
22
|
-
material: string
|
|
23
|
-
/**
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
/** @internal
|
|
42
|
-
|
|
43
|
-
/** @internal */
|
|
44
|
-
|
|
45
|
-
/** @internal */
|
|
46
|
-
|
|
47
|
-
/** @internal
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
get
|
|
64
|
-
set
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
*
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
*
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
m
|
|
110
|
-
|
|
111
|
-
if (
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
m.
|
|
115
|
-
m.
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
lightmap
|
|
132
|
-
|
|
133
|
-
*
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
}
|
|
1
|
+
// A loaded GLB model — its own node kind (a GLB is a node hierarchy with baked animation clips),
|
|
2
|
+
// distinct from Mesh (raw primitives, no animation). Animation is always present, reached as
|
|
3
|
+
// model.anim (an Animator over the GLB's clips — crossfades, blend spaces, layers when you need them):
|
|
4
|
+
// const hero = await Model.load(asset('./hero.glb'))
|
|
5
|
+
// hero.anim.play('Run', { loop: true })
|
|
6
|
+
|
|
7
|
+
import { fetch, type FetchResponse } from "../runtime/fetch"
|
|
8
|
+
import { Node, nodes } from "./Node"
|
|
9
|
+
import { Animator, _pushLod, type LodMode } from "./animation/Animator"
|
|
10
|
+
import { Material } from "./Material"
|
|
11
|
+
|
|
12
|
+
/** One polygon under a screen point — what `Model.pickTriangle` returns. `bones` are the vertex's raw
|
|
13
|
+
* JOINTS_0 / WEIGHTS_0 pairs (weight > 0; empty = unweighted), `bind` its position in mesh space,
|
|
14
|
+
* `world` its skinned position this frame. */
|
|
15
|
+
export interface TrianglePick {
|
|
16
|
+
/** the Model's root entity, and the mesh node's own entity (0 when the host has no entity for it) */
|
|
17
|
+
entity: number
|
|
18
|
+
node: number
|
|
19
|
+
nodeName: string
|
|
20
|
+
mesh: string
|
|
21
|
+
primitive: number
|
|
22
|
+
material: string
|
|
23
|
+
/** the node's lightmap group (scene-file extras), when it has one */
|
|
24
|
+
lightmapGroup?: number
|
|
25
|
+
/** triangle index within the primitive (index-buffer order), and whether the ray came from behind */
|
|
26
|
+
triangle: number
|
|
27
|
+
backface: boolean
|
|
28
|
+
distance: number
|
|
29
|
+
point: [number, number, number]
|
|
30
|
+
bary: [number, number, number]
|
|
31
|
+
/** the lightmap uv (TEXCOORD_1) at the hit, when the primitive carries one */
|
|
32
|
+
uv1?: [number, number]
|
|
33
|
+
skin: string
|
|
34
|
+
vertices: { index: number, bind: [number, number, number], world: [number, number, number], bones: { name: string, weight: number }[] }[]
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export class Model extends Node {
|
|
38
|
+
/** The model's Animator — always present, its clip table = the GLB's embedded clips. Configure
|
|
39
|
+
* more (external clips, blend spaces, layers) with `model.aspect(Animator, {...})`. */
|
|
40
|
+
declare readonly anim: Animator
|
|
41
|
+
/** @internal loaded through the lightmap material (a baked static); clones inherit it. */
|
|
42
|
+
_lightmapped = false
|
|
43
|
+
/** @internal loaded through the foliage tier (`Foliage`); clones inherit it. */
|
|
44
|
+
_foliage = false
|
|
45
|
+
/** @internal the shadow pair, mirrored here because the bridge writes both at once. */
|
|
46
|
+
_castShadows = true
|
|
47
|
+
/** @internal */
|
|
48
|
+
_receiveShadows = true
|
|
49
|
+
/** @internal */
|
|
50
|
+
_culling = true
|
|
51
|
+
/** @internal -1 = auto (see `lod`) */
|
|
52
|
+
_lodMesh = -1
|
|
53
|
+
|
|
54
|
+
constructor(internalId: number | Handle) {
|
|
55
|
+
super(internalId)
|
|
56
|
+
this.aspect(Animator)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Does this model cast a real-time shadow? Unlike Mesh (one renderable) a GLB is a whole
|
|
60
|
+
* hierarchy, so the flag goes to EVERY renderable of the instance. A first-person viewmodel —
|
|
61
|
+
* arms, weapon, attachments — sets it false: it lives in front of the camera and its shadow
|
|
62
|
+
* is never wanted. */
|
|
63
|
+
get castShadows(): boolean { return this._castShadows }
|
|
64
|
+
set castShadows(v: boolean) { this._castShadows = v; this._applyShadows() }
|
|
65
|
+
|
|
66
|
+
/** Is this model lit by other casters' shadows? Same instance-wide reach as castShadows. */
|
|
67
|
+
get receiveShadows(): boolean { return this._receiveShadows }
|
|
68
|
+
set receiveShadows(v: boolean) { this._receiveShadows = v; this._applyShadows() }
|
|
69
|
+
|
|
70
|
+
/** Frustum culling for the whole instance: a model the camera cannot see skips the draw and the
|
|
71
|
+
* shadow pass. ON by default where the host keeps a skinned mesh's bounds honest — the engine refits
|
|
72
|
+
* them to the joints every frame, so a walking, kneeling or ragdolled body is never culled while on
|
|
73
|
+
* screen (`_creator.skinnedCullingSupported`); OFF (always draw) on hosts without that, where
|
|
74
|
+
* Filament would cull an animated body by its bind-pose box. `false` = always draw (a skybox-sized
|
|
75
|
+
* mesh, a debugging aid); `true` forces it on regardless of the host. */
|
|
76
|
+
get culling(): boolean { return this._culling }
|
|
77
|
+
set culling(v: boolean) { this._culling = v; _creator.setGlbCulling(this.id, v) }
|
|
78
|
+
/** Level of detail (docs/lod-plan.md). `'auto'` (default): the engine shows the `_LOD<n>` mesh level
|
|
79
|
+
* that fits the model's size on screen (`lecodes assets doctor --lod` makes them) and scales the
|
|
80
|
+
* animation rate with it; a number 0–3 pins that level for both — `0` = always full detail (a hero,
|
|
81
|
+
* a showcase), `2`/`3` = always cheap (a crowd filler). `model.anim.lod = 'full'` keeps the animation
|
|
82
|
+
* exact while the mesh still switches. No-op on hosts without the LOD pass. */
|
|
83
|
+
get lod(): LodMode { return this._lodMesh < 0 ? "auto" : (this._lodMesh as 0 | 1 | 2 | 3) }
|
|
84
|
+
set lod(v: LodMode) { this._lodMesh = v === "auto" ? -1 : Math.max(0, Math.min(3, Math.round(v))); _pushLod(this) }
|
|
85
|
+
|
|
86
|
+
/** @internal the default for a fresh instance (load / clone), decided once per host. */
|
|
87
|
+
static _cullingDefault(): boolean {
|
|
88
|
+
if (Model._cullDefault === undefined) Model._cullDefault = !!_creator.skinnedCullingSupported?.()
|
|
89
|
+
return Model._cullDefault
|
|
90
|
+
}
|
|
91
|
+
private static _cullDefault: boolean | undefined
|
|
92
|
+
|
|
93
|
+
/** @internal both flags travel together — the bridge walks the instance once. */
|
|
94
|
+
_applyShadows(): void { _creator.setGlbShadows?.(this.id, this._castShadows, this._receiveShadows) }
|
|
95
|
+
|
|
96
|
+
/** DEBUG: the closest polygon of this model under a screen point (logical px — `Input.mouse.position`,
|
|
97
|
+
* a touch event's clientX/Y), tested against the CPU-skinned CURRENT pose, both faces. Names the
|
|
98
|
+
* triangle, its three vertices (bind + skinned positions) and their raw bone weights, so a stretched
|
|
99
|
+
* or misbound polygon can be traced to its binding. One full CPU skin of the model per call: click-rate
|
|
100
|
+
* only. null = miss, or a host without the pick (desktop today). */
|
|
101
|
+
pickTriangle(screenX: number, screenY: number): TrianglePick | null {
|
|
102
|
+
return _creator.pickTriangle?.(this.id, screenX, screenY) ?? null
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Duplicate this model — a deep copy of the GLB (meshes, skeleton, animation clips), attached to
|
|
106
|
+
* the same parent and scene and sharing this model's current transform. The clone has its own
|
|
107
|
+
* independent animation state (reach it via clone.anim). Mirrors this model's culling flag. */
|
|
108
|
+
clone(): Model {
|
|
109
|
+
const m = new Model(_creator.cloneEntity(this.id))
|
|
110
|
+
const id = m.id
|
|
111
|
+
if (_creator.entityIsOwned(id)) nodes.pin(m) // cloned into this model's parent / scene: native owns it
|
|
112
|
+
m._lightmapped = this._lightmapped
|
|
113
|
+
m._foliage = this._foliage
|
|
114
|
+
if (!this._culling) { m._culling = false; _creator.setGlbCulling(id, false) } // the engine default is on
|
|
115
|
+
if (this._lodMesh >= 0) { m._lodMesh = this._lodMesh; _pushLod(m) }
|
|
116
|
+
// the clone is a FRESH gltfio instance — it comes back with the asset's own shadow flags,
|
|
117
|
+
// not this model's, so a cleared flag has to be re-applied
|
|
118
|
+
m._castShadows = this._castShadows
|
|
119
|
+
m._receiveShadows = this._receiveShadows
|
|
120
|
+
if (!this._castShadows || !this._receiveShadows) m._applyShadows()
|
|
121
|
+
return m
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** Load a GLB model. Returns its root as a Model; play its baked clips via model.anim. */
|
|
125
|
+
static load(
|
|
126
|
+
source: string | FetchResponse,
|
|
127
|
+
options: {
|
|
128
|
+
/** Frustum culling — see `culling` (default: on where the host refits skinned bounds, else off). */
|
|
129
|
+
culling?: boolean
|
|
130
|
+
onProgress?: (p: { loaded: number, total?: number }) => void
|
|
131
|
+
/** Baked lighting (engines/bake). `true` = a STATIC: loads through the lightmap material so
|
|
132
|
+
* `Lightmap.load` can bind its atlas rect (the GLB needs TEXCOORD_1 — `lecodes assets doctor
|
|
133
|
+
* --lightmap-uv`) and takes nothing from the real-time lights once the bake applies. Omitted / `false` =
|
|
134
|
+
* the standard shader, lit real-time (movers). Hosts without lightmap support ignore it. */
|
|
135
|
+
lightmap?: boolean
|
|
136
|
+
/** Vegetation: load through the FOLIAGE tier (see `Foliage`) — wind, touch bending, distance fade,
|
|
137
|
+
* per-copy tint. Hosts without the tier fall back to the standard shader. */
|
|
138
|
+
foliage?: boolean
|
|
139
|
+
} = {},
|
|
140
|
+
): Promise<Model> {
|
|
141
|
+
if (typeof source === "string") {
|
|
142
|
+
return fetch(source, { useOnce: true, onProgress: options.onProgress }).then((resp) => {
|
|
143
|
+
if (resp.status >= 400) return Promise.reject(new Error(`Failed to load GLB from ${source}. HTTP ${resp.status}`))
|
|
144
|
+
return Model.load(resp, options)
|
|
145
|
+
})
|
|
146
|
+
}
|
|
147
|
+
return new Promise<Model>((resolve, reject) => {
|
|
148
|
+
// the provider path: a foliage model takes the vegetation tier's pair when the host carries it, a
|
|
149
|
+
// static the lightmap material + its masked twin; anything else the ubershader
|
|
150
|
+
const foliageWanted = !!options.foliage && !!_creator.setNextGlbLightmapped
|
|
151
|
+
let foliage = false
|
|
152
|
+
if (foliageWanted) {
|
|
153
|
+
const fol = Material._foliageTemplate()
|
|
154
|
+
const folMasked = fol && Material._foliageMaskedTemplate()
|
|
155
|
+
foliage = !!fol && !!folMasked
|
|
156
|
+
if (fol && folMasked) _creator.setNextGlbLightmapped!(Material.idOf(fol), Material.idOf(folMasked))
|
|
157
|
+
}
|
|
158
|
+
const lightmapped = !foliage && !!options.lightmap && !!_creator.setNextGlbLightmapped
|
|
159
|
+
if (lightmapped) _creator.setNextGlbLightmapped!(Material.idOf(Material._lightmapTemplate()), Material.idOf(Material._lightmapMaskedTemplate()))
|
|
160
|
+
_creator.createGlb((source as unknown as { _h: Handle })._h.id, (root) => {
|
|
161
|
+
if (!root) { reject(new Error("Failed to load GLB")); return }
|
|
162
|
+
const model = new Model(root)
|
|
163
|
+
const entityId = model.id
|
|
164
|
+
model._lightmapped = lightmapped
|
|
165
|
+
model._foliage = foliage
|
|
166
|
+
const culling = options.culling ?? Model._cullingDefault()
|
|
167
|
+
if (!culling) { model._culling = false; _creator.setGlbCulling(entityId, false) }
|
|
168
|
+
resolve(model)
|
|
169
|
+
}, reject)
|
|
170
|
+
})
|
|
171
|
+
}
|
|
172
|
+
}
|
package/src/gl/Node.ts
CHANGED
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
// A GLB import is the Model node kind (with the Animator aspect at model.anim). Hierarchy lives here.
|
|
7
7
|
|
|
8
8
|
import { AspectHost } from "../core/Aspect"
|
|
9
|
-
import {
|
|
9
|
+
import { DEAD_HANDLE, Pins, registerFreedKind } from "../core/pins"
|
|
10
|
+
import { OWNED_KIND_GL_ENTITY } from "../ui/tree"
|
|
10
11
|
import { Vec3, cx, cy, cz, type Vec3Like } from "../math/vec"
|
|
11
12
|
import { Quat, cw, type QuatLike } from "../math/quat"
|
|
12
13
|
import { Mat4, type Mat4Like } from "../math/mat4"
|
|
@@ -31,7 +32,38 @@ export type NodeTweenProps = {
|
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
/** id → Node, so host callbacks (touch hits, animation events) route back to the owning object. */
|
|
34
|
-
|
|
35
|
+
/** @internal The nodes native owns right now (in a scene / under a parent, or engine-created), by
|
|
36
|
+
* entity id — what a pick, a contact or an animation event resolves to. See core/pins.ts. */
|
|
37
|
+
export const nodes = new Pins<Node>()
|
|
38
|
+
|
|
39
|
+
// The loose wrappers, WEAKLY: a read-back (`parent` / `children` / `traverse` / `find`) must hand
|
|
40
|
+
// back the app's OWN handle while it exists. A loose root has no native owner, so no pin — the
|
|
41
|
+
// only other way to reach it from below was a throwaway wrapper, and anything put on that wrapper
|
|
42
|
+
// (IK's rig Animator on a bare tree's top) was lost to the app's handle. WeakRef keeps the owned
|
|
43
|
+
// model intact: the registry never holds a handle alive, a dropped root still finalizes, and a
|
|
44
|
+
// dead entry is dropped when met (or in the sweep every SWEEP registrations).
|
|
45
|
+
const loose = new Map<number, WeakRef<Node>>()
|
|
46
|
+
const SWEEP = 256
|
|
47
|
+
let sinceSweep = 0
|
|
48
|
+
const registerLoose = (n: Node): void => {
|
|
49
|
+
loose.set(n._h.id, new WeakRef(n))
|
|
50
|
+
if (++sinceSweep < SWEEP) return
|
|
51
|
+
sinceSweep = 0
|
|
52
|
+
for (const [id, ref] of loose) { const w = ref.deref(); if (!w || w._h.id !== id) loose.delete(id) }
|
|
53
|
+
}
|
|
54
|
+
/** @internal The wrapper for an entity id the runtime handed back: the pinned one, else the
|
|
55
|
+
* app's live loose handle, else a throwaway over the engine-owned id. */
|
|
56
|
+
export const nodeOf = (id: number): Node => {
|
|
57
|
+
const pinned = nodes.get(id)
|
|
58
|
+
if (pinned) return pinned
|
|
59
|
+
const ref = loose.get(id)
|
|
60
|
+
if (ref) {
|
|
61
|
+
const w = ref.deref()
|
|
62
|
+
if (w && w._h.id === id) return w
|
|
63
|
+
loose.delete(id)
|
|
64
|
+
}
|
|
65
|
+
return new Node(id)
|
|
66
|
+
}
|
|
35
67
|
|
|
36
68
|
export type NodeEvents = {
|
|
37
69
|
click: (ev: ClickEvent<Node | null>) => void
|
|
@@ -67,8 +99,12 @@ const findNodeByWalk = (rootId: number, name: string): number => {
|
|
|
67
99
|
const worldScratch = new Float32Array(3)
|
|
68
100
|
|
|
69
101
|
export class Node extends AspectHost<NodeEvents> implements CompWriter {
|
|
70
|
-
/**
|
|
71
|
-
|
|
102
|
+
/** @internal The entity's owned handle (`_h.id` = the entity id; DEAD_HANDLE once destroyed). An
|
|
103
|
+
* engine-created entity (a glTF part, an anchor) is wrapped from its number and pinned as the
|
|
104
|
+
* engine's; an entity WE created is loose until it gets a parent or a scene. */
|
|
105
|
+
_h: Handle
|
|
106
|
+
/** Native entity id. */
|
|
107
|
+
get id(): number { return this._h.id }
|
|
72
108
|
|
|
73
109
|
/** AR anchors only — whether the anchor is currently being tracked. Kept in step with the
|
|
74
110
|
* 'track' / 'untrack' events; `false` for any non-anchor node. */
|
|
@@ -80,10 +116,20 @@ export class Node extends AspectHost<NodeEvents> implements CompWriter {
|
|
|
80
116
|
/** Materials assigned through setMaterial, by primitive slot (a Mesh fills slot 0 itself). */
|
|
81
117
|
protected _materials?: Material[]
|
|
82
118
|
|
|
83
|
-
constructor(internalId?: number) {
|
|
119
|
+
constructor(internalId?: number | Handle) {
|
|
84
120
|
super()
|
|
85
|
-
|
|
86
|
-
|
|
121
|
+
registerFreedKind(OWNED_KIND_GL_ENTITY, nodes)
|
|
122
|
+
if (internalId === undefined) {
|
|
123
|
+
const h = _creator.createEntity()
|
|
124
|
+
this._h = typeof h === "number" ? { id: h } : h // a number only from a test stub
|
|
125
|
+
registerLoose(this)
|
|
126
|
+
} else if (typeof internalId === "number") {
|
|
127
|
+
this._h = { id: internalId } // engine-owned: findable while the engine keeps it
|
|
128
|
+
nodes.pin(this)
|
|
129
|
+
} else {
|
|
130
|
+
this._h = internalId // an owned root the runtime handed us (createGlb, cloneEntity)
|
|
131
|
+
registerLoose(this)
|
|
132
|
+
}
|
|
87
133
|
}
|
|
88
134
|
|
|
89
135
|
/** Geometry, if this node is a Mesh (used by physics auto-shape). Overridden by Mesh. */
|
|
@@ -263,29 +309,37 @@ export class Node extends AspectHost<NodeEvents> implements CompWriter {
|
|
|
263
309
|
// --- hierarchy ---
|
|
264
310
|
get parent(): Node | null {
|
|
265
311
|
const id = _creator.getParent(this.id)
|
|
266
|
-
return id === 0 ? null : (
|
|
312
|
+
return id === 0 ? null : nodeOf(id)
|
|
267
313
|
}
|
|
268
314
|
get children(): Node[] {
|
|
269
|
-
|
|
315
|
+
const n = _creator.getChildCount(this.id)
|
|
316
|
+
const out: Node[] = []
|
|
317
|
+
for (let i = 0; i < n; i++) { const id = _creator.getChild(this.id, i); out.push(nodeOf(id)) }
|
|
318
|
+
return out
|
|
270
319
|
}
|
|
271
320
|
get childCount(): number { return _creator.getChildCount(this.id) }
|
|
272
321
|
getChild(index: number): Node | null {
|
|
273
322
|
const id = _creator.getChild(this.id, index)
|
|
274
|
-
return id === 0 ? null : (
|
|
323
|
+
return id === 0 ? null : nodeOf(id)
|
|
275
324
|
}
|
|
276
325
|
/** Parent the given nodes under this one. */
|
|
277
326
|
add(...children: Node[]): this {
|
|
278
|
-
for (const c of children) _creator.setParent(c.id, this.id, false)
|
|
327
|
+
for (const c of children) { _creator.setParent(c.id, this.id, false); nodes.pin(c) }
|
|
279
328
|
return this
|
|
280
329
|
}
|
|
281
330
|
setParent(parent: Node | null, worldPositionStays = false): this {
|
|
282
|
-
if (parent === null)
|
|
283
|
-
|
|
331
|
+
if (parent === null) {
|
|
332
|
+
_creator.setParentNull(this.id, worldPositionStays)
|
|
333
|
+
if (!_creator.entityIsOwned(this.id)) nodes.unpin(this.id) // loose again: the handle owns it
|
|
334
|
+
} else {
|
|
335
|
+
_creator.setParent(this.id, parent.id, worldPositionStays)
|
|
336
|
+
nodes.pin(this)
|
|
337
|
+
}
|
|
284
338
|
return this
|
|
285
339
|
}
|
|
286
340
|
traverse(callback: (node: Node) => void): void {
|
|
287
341
|
callback(this)
|
|
288
|
-
_creator.traverse(this.id, (id) => callback(
|
|
342
|
+
_creator.traverse(this.id, (id) => callback(nodeOf(id)))
|
|
289
343
|
}
|
|
290
344
|
// --- materials (any renderable: a Mesh, or an internal node of a loaded Model) ---
|
|
291
345
|
/** The material assigned to slot 0 through this API (null before one is set — a GLB part's own
|
|
@@ -313,7 +367,7 @@ export class Node extends AspectHost<NodeEvents> implements CompWriter {
|
|
|
313
367
|
const hit = cache.get(name)
|
|
314
368
|
if (hit !== undefined) return hit
|
|
315
369
|
const id = _creator.findNode ? _creator.findNode(this.id, name) : findNodeByWalk(this.id, name)
|
|
316
|
-
const found = id ?
|
|
370
|
+
const found = id ? nodeOf(id) : null
|
|
317
371
|
cache.set(name, found)
|
|
318
372
|
return found
|
|
319
373
|
}
|
|
@@ -372,16 +426,29 @@ export class Node extends AspectHost<NodeEvents> implements CompWriter {
|
|
|
372
426
|
* `destroyEntity` frees the entity tree but knows nothing about JS-side aspects, and a destroyed
|
|
373
427
|
* node's `update()` must not keep ticking. Deepest nodes go first, then this one. */
|
|
374
428
|
destroy(): void {
|
|
429
|
+
if (this._h.id === 0) return
|
|
375
430
|
const subtree: Node[] = [this]
|
|
376
|
-
_creator.traverse(this.id, (id) => { const n =
|
|
377
|
-
for (let i = subtree.length - 1; i >= 0; i--)
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
431
|
+
_creator.traverse(this.id, (id) => { const n = nodes.get(id); if (n) subtree.push(n) })
|
|
432
|
+
for (let i = subtree.length - 1; i >= 0; i--) subtree[i]._detachAll()
|
|
433
|
+
const id = this.id
|
|
434
|
+
// Dead NOW — entity ids are recycled, and the runtime's freed report lands a drain later.
|
|
435
|
+
for (const n of subtree) { nodes.unpin(n.id); n._dead() }
|
|
436
|
+
_creator.destroyEntity(id)
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/** @internal The wrapper's resource is gone: no more native calls from here. */
|
|
440
|
+
_dead(): void {
|
|
441
|
+
this._xf = 0
|
|
442
|
+
this._xfKind = 0
|
|
443
|
+
loose.delete(this._h.id)
|
|
444
|
+
this._h = DEAD_HANDLE
|
|
445
|
+
}
|
|
446
|
+
/** @internal The runtime freed the entity underneath (an ancestor destroyed or dropped): the
|
|
447
|
+
* aspects detach (their onDetach runs after the entity is gone) and the wrapper is dead. */
|
|
448
|
+
_freed(): void {
|
|
449
|
+
if (this._h.id === 0) return
|
|
450
|
+
this._detachAll()
|
|
451
|
+
this._dead()
|
|
385
452
|
}
|
|
386
453
|
}
|
|
387
454
|
|
package/src/gl/Particles.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// All emitter/curve config crosses the bridge as ONE Float32Array of [tag, payloadLen, ...payload]
|
|
5
5
|
// records (_creator.setParticleSystemConfig) — the constructor batches every option into a single
|
|
6
6
|
// call, live setters send a one-record buffer. The tag values mirror CPART_TAG_* in
|
|
7
|
-
// creator-particles/include/creator-particles/creator-particles.h (guarded by tests/particles-tags.test.ts).
|
|
7
|
+
// creator-particles/include/creator-particles/creator-particles.h (guarded by tests/gl/particles-tags.test.ts).
|
|
8
8
|
//
|
|
9
9
|
// Curves over a particle's lifetime are built with curve()/colorCurve() chains — see the builders
|
|
10
10
|
// below. A builder's whole state is the flat `_data` array (the exact record payload), so the
|
|
@@ -42,6 +42,7 @@ const TAG_VELOCITY_LIFE = 19
|
|
|
42
42
|
const TAG_ORDER = 20
|
|
43
43
|
const TAG_SMOOTH_PATH = 21
|
|
44
44
|
const TAG_RIBBON_ORIENT = 22
|
|
45
|
+
const TAG_LIT = 23
|
|
45
46
|
/** `TrailOptions.orient` → the native axis code (0 = the camera-facing default). */
|
|
46
47
|
const RIBBON_AXIS: Record<"camera" | "x" | "y" | "z", number> = { camera: 0, x: 1, y: 2, z: 3 }
|
|
47
48
|
|
|
@@ -54,6 +55,7 @@ export const _particleTags = {
|
|
|
54
55
|
RENDER_MODE: TAG_RENDER_MODE, MESH_GEOMETRY: TAG_MESH_GEOMETRY,
|
|
55
56
|
ANGULAR_VELOCITY: TAG_ANGULAR_VELOCITY, GROUND: TAG_GROUND, VELOCITY_LIFE: TAG_VELOCITY_LIFE,
|
|
56
57
|
ORDER: TAG_ORDER, SMOOTH_PATH: TAG_SMOOTH_PATH, RIBBON_ORIENT: TAG_RIBBON_ORIENT,
|
|
58
|
+
LIT: TAG_LIT,
|
|
57
59
|
}
|
|
58
60
|
|
|
59
61
|
// --- curve builders -----------------------------------------------------------------------------
|
|
@@ -304,6 +306,15 @@ export type ParticlesOptions = ParticlesMaterialOptions & {
|
|
|
304
306
|
* without this the engine picks who covers whom per frame (smoke popping over a fireball).
|
|
305
307
|
* Default 0; a fireball wants 2, its smoke 1, a smoke trail -1. */
|
|
306
308
|
order?: number
|
|
309
|
+
/** Sprites take the light of the PLACE each one is in — the level's baked light grid (`env.lightmap.volume`).
|
|
310
|
+
* A sprite is unlit: its colour is the picture, which is right for fire and wrong for dust — a puff kicked up
|
|
311
|
+
* under an awning glows as if it stood in the sun. With `lit` every particle's colour is multiplied by the light
|
|
312
|
+
* where it is, relative to the level's OPEN ground: exactly the authored colour out in the sun, the ambient's
|
|
313
|
+
* share of it (tinted the way the shade is) under a roof — per particle, so a trail of puffs laid from the sun
|
|
314
|
+
* into the shade is lit along its length. Author the colour for the open; nothing else to tune. Without a grid
|
|
315
|
+
* — a level with no bake, a host that has none — the colours are drawn as authored. Points, quads, stretch and
|
|
316
|
+
* `Trail`; mesh particles are lit by their material. Default false. */
|
|
317
|
+
lit?: boolean
|
|
307
318
|
/** Coarse draw order among ALL blended draws, 0 (first) … 7 (last) — see `Mesh.renderPriority`.
|
|
308
319
|
* Default 5: meshes sit at 4 and decals at 3, so smoke covers a car's glass and its skid marks
|
|
309
320
|
* whatever the camera does (the engine's depth sort compares object centres, and an emitter's
|
|
@@ -492,6 +503,7 @@ export class Particles extends Node {
|
|
|
492
503
|
if (options.rateOverDistance !== undefined) out.push(TAG_RATE_DISTANCE, 1, options.rateOverDistance)
|
|
493
504
|
if (options.smooth !== undefined) out.push(TAG_SMOOTH_PATH, 1, options.smooth ? 1 : 0)
|
|
494
505
|
if (options.order !== undefined) out.push(TAG_ORDER, 1, options.order)
|
|
506
|
+
if (options.lit !== undefined) out.push(TAG_LIT, 1, options.lit ? 1 : 0)
|
|
495
507
|
if (options.rate !== undefined) out.push(TAG_RATE, 1, options.rate)
|
|
496
508
|
if (options.shape !== undefined) pushShape(out, options.shape)
|
|
497
509
|
if (options.velocityOverLife !== undefined) pushVelocityLife(out, options.velocityOverLife)
|
|
@@ -547,6 +559,8 @@ export class Particles extends Node {
|
|
|
547
559
|
/** Lay a frame's spawns along a curve through the emitter's path, not the straight chord. */
|
|
548
560
|
set smooth(val: boolean) { this._send([ TAG_SMOOTH_PATH, 1, val ? 1 : 0 ]) }
|
|
549
561
|
set order(val: number) { this._send([ TAG_ORDER, 1, val ]) }
|
|
562
|
+
/** Colours × the baked light where each particle is — see `ParticlesOptions.lit`. */
|
|
563
|
+
set lit(val: boolean) { this._send([ TAG_LIT, 1, val ? 1 : 0 ]) }
|
|
550
564
|
/** Coarse draw order, 0 … 7 — see `Mesh.renderPriority`. Write-only. */
|
|
551
565
|
set renderPriority(v: number) {
|
|
552
566
|
if (_creator.setRenderPriority) _creator.setRenderPriority(this.id, Math.max(0, Math.min(7, Math.round(v))))
|
|
@@ -644,6 +658,9 @@ export type TrailOptions = Omit<ParticlesMaterialOptions, "render" | "stretch">
|
|
|
644
658
|
* frame rate, since a longer frame bows further off its own chord. Default false; see
|
|
645
659
|
* `ParticlesOptions.smooth`. */
|
|
646
660
|
smooth?: boolean
|
|
661
|
+
/** The strip takes the baked light of the place each of its points is at — `ParticlesOptions.lit`. Smoke and
|
|
662
|
+
* dust trails; leave it off for a glowing one. Default false. */
|
|
663
|
+
lit?: boolean
|
|
647
664
|
/** Which way the strip's WIDTH points.
|
|
648
665
|
*
|
|
649
666
|
* `'camera'` (default) rolls the strip about its own length to stay flat to the viewer — it can
|
|
@@ -689,6 +706,7 @@ export class Trail extends Node {
|
|
|
689
706
|
TAG_LIFETIME, 2, time, time,
|
|
690
707
|
]
|
|
691
708
|
if (options.smooth) out.push(TAG_SMOOTH_PATH, 1, 1)
|
|
709
|
+
if (options.lit) out.push(TAG_LIT, 1, 1)
|
|
692
710
|
if (options.orient !== undefined || options.faceCamera !== undefined) {
|
|
693
711
|
this._orient = RIBBON_AXIS[options.orient ?? "camera"]
|
|
694
712
|
if (options.faceCamera !== undefined) this._faceCamera = options.faceCamera
|
|
@@ -732,6 +750,7 @@ export class Trail extends Node {
|
|
|
732
750
|
|
|
733
751
|
/** Follow a curve through the emitter's path instead of the straight chord between frames. */
|
|
734
752
|
set smooth(val: boolean) { this._send([ TAG_SMOOTH_PATH, 1, val ? 1 : 0 ]) }
|
|
753
|
+
set lit(val: boolean) { this._send([ TAG_LIT, 1, val ? 1 : 0 ]) }
|
|
735
754
|
|
|
736
755
|
/** Which way the strip's width points — see `TrailOptions.orient`. Keeps the current `faceCamera`. */
|
|
737
756
|
set orient(val: "camera" | "x" | "y" | "z") {
|