@iwsdk/core 0.3.2 → 0.4.1

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.
Files changed (127) hide show
  1. package/dist/asset/asset-manager.d.ts +20 -3
  2. package/dist/asset/asset-manager.d.ts.map +1 -1
  3. package/dist/asset/asset-manager.js +19 -4
  4. package/dist/asset/asset-manager.js.map +1 -1
  5. package/dist/asset/loaders/gltf-loader.d.ts +35 -3
  6. package/dist/asset/loaders/gltf-loader.d.ts.map +1 -1
  7. package/dist/asset/loaders/gltf-loader.js +38 -4
  8. package/dist/asset/loaders/gltf-loader.js.map +1 -1
  9. package/dist/camera/camera-system.d.ts +2 -1
  10. package/dist/camera/camera-system.d.ts.map +1 -1
  11. package/dist/camera/camera-system.js +6 -6
  12. package/dist/camera/camera-system.js.map +1 -1
  13. package/dist/depth/depth-sensing-system.d.ts +2 -0
  14. package/dist/depth/depth-sensing-system.d.ts.map +1 -1
  15. package/dist/depth/depth-sensing-system.js +18 -16
  16. package/dist/depth/depth-sensing-system.js.map +1 -1
  17. package/dist/ecs/system.d.ts +5 -2
  18. package/dist/ecs/system.d.ts.map +1 -1
  19. package/dist/ecs/system.js +2 -0
  20. package/dist/ecs/system.js.map +1 -1
  21. package/dist/ecs/world.d.ts +26 -4
  22. package/dist/ecs/world.d.ts.map +1 -1
  23. package/dist/ecs/world.js +2 -2
  24. package/dist/ecs/world.js.map +1 -1
  25. package/dist/environment-raycast/environment-raycast.js +2 -2
  26. package/dist/environment-raycast/environment-raycast.js.map +1 -1
  27. package/dist/grab/grab-system.d.ts.map +1 -1
  28. package/dist/grab/grab-system.js +7 -7
  29. package/dist/grab/grab-system.js.map +1 -1
  30. package/dist/index.d.ts +1 -0
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +9 -0
  33. package/dist/index.js.map +1 -1
  34. package/dist/init/browser-camera.d.ts +44 -0
  35. package/dist/init/browser-camera.d.ts.map +1 -0
  36. package/dist/init/browser-camera.js +58 -0
  37. package/dist/init/browser-camera.js.map +1 -0
  38. package/dist/init/player-camera.d.ts +9 -0
  39. package/dist/init/player-camera.d.ts.map +1 -0
  40. package/dist/init/player-camera.js +14 -0
  41. package/dist/init/player-camera.js.map +1 -0
  42. package/dist/init/world-initializer.d.ts +30 -4
  43. package/dist/init/world-initializer.d.ts.map +1 -1
  44. package/dist/init/world-initializer.js +135 -33
  45. package/dist/init/world-initializer.js.map +1 -1
  46. package/dist/init/xr.d.ts +10 -0
  47. package/dist/init/xr.d.ts.map +1 -1
  48. package/dist/init/xr.js +8 -1
  49. package/dist/init/xr.js.map +1 -1
  50. package/dist/input/canvas-pointer-system.d.ts +44 -0
  51. package/dist/input/canvas-pointer-system.d.ts.map +1 -0
  52. package/dist/input/canvas-pointer-system.js +90 -0
  53. package/dist/input/canvas-pointer-system.js.map +1 -0
  54. package/dist/input/index.d.ts +5 -0
  55. package/dist/input/index.d.ts.map +1 -1
  56. package/dist/input/input-actions.d.ts +139 -0
  57. package/dist/input/input-actions.d.ts.map +1 -0
  58. package/dist/input/input-actions.js +357 -0
  59. package/dist/input/input-actions.js.map +1 -0
  60. package/dist/input/input-manager.d.ts +56 -0
  61. package/dist/input/input-manager.d.ts.map +1 -0
  62. package/dist/input/input-manager.js +89 -0
  63. package/dist/input/input-manager.js.map +1 -0
  64. package/dist/input/input-system.d.ts +149 -137
  65. package/dist/input/input-system.d.ts.map +1 -1
  66. package/dist/input/input-system.js +30 -66
  67. package/dist/input/input-system.js.map +1 -1
  68. package/dist/input/stateful-browser-gamepad.d.ts +40 -0
  69. package/dist/input/stateful-browser-gamepad.d.ts.map +1 -0
  70. package/dist/input/stateful-browser-gamepad.js +139 -0
  71. package/dist/input/stateful-browser-gamepad.js.map +1 -0
  72. package/dist/input/stateful-keyboard.d.ts +23 -0
  73. package/dist/input/stateful-keyboard.d.ts.map +1 -0
  74. package/dist/input/stateful-keyboard.js +63 -0
  75. package/dist/input/stateful-keyboard.js.map +1 -0
  76. package/dist/layers/index.d.ts +10 -0
  77. package/dist/layers/index.d.ts.map +1 -0
  78. package/dist/layers/xr-cylinder-layer.d.ts +62 -0
  79. package/dist/layers/xr-cylinder-layer.d.ts.map +1 -0
  80. package/dist/layers/xr-cylinder-layer.js +48 -0
  81. package/dist/layers/xr-cylinder-layer.js.map +1 -0
  82. package/dist/layers/xr-layer-system.d.ts +296 -0
  83. package/dist/layers/xr-layer-system.d.ts.map +1 -0
  84. package/dist/layers/xr-layer-system.js +378 -0
  85. package/dist/layers/xr-layer-system.js.map +1 -0
  86. package/dist/layers/xr-quad-layer.d.ts +57 -0
  87. package/dist/layers/xr-quad-layer.d.ts.map +1 -0
  88. package/dist/layers/xr-quad-layer.js +46 -0
  89. package/dist/layers/xr-quad-layer.js.map +1 -0
  90. package/dist/locomotion/index.d.ts +1 -0
  91. package/dist/locomotion/index.d.ts.map +1 -1
  92. package/dist/locomotion/locomotion-input-provider.d.ts +39 -0
  93. package/dist/locomotion/locomotion-input-provider.d.ts.map +1 -0
  94. package/dist/locomotion/locomotion-input-provider.js +109 -0
  95. package/dist/locomotion/locomotion-input-provider.js.map +1 -0
  96. package/dist/locomotion/locomotion.d.ts +11 -11
  97. package/dist/locomotion/locomotion.d.ts.map +1 -1
  98. package/dist/locomotion/locomotion.js +10 -10
  99. package/dist/locomotion/locomotion.js.map +1 -1
  100. package/dist/locomotion/slide.d.ts +12 -12
  101. package/dist/locomotion/slide.d.ts.map +1 -1
  102. package/dist/locomotion/slide.js +11 -15
  103. package/dist/locomotion/slide.js.map +1 -1
  104. package/dist/locomotion/teleport.d.ts +11 -1
  105. package/dist/locomotion/teleport.d.ts.map +1 -1
  106. package/dist/locomotion/teleport.js +10 -30
  107. package/dist/locomotion/teleport.js.map +1 -1
  108. package/dist/locomotion/turn.d.ts +11 -0
  109. package/dist/locomotion/turn.d.ts.map +1 -1
  110. package/dist/locomotion/turn.js +14 -25
  111. package/dist/locomotion/turn.js.map +1 -1
  112. package/dist/mcp/ecs-debug-tools.d.ts.map +1 -1
  113. package/dist/mcp/ecs-debug-tools.js +20 -13
  114. package/dist/mcp/ecs-debug-tools.js.map +1 -1
  115. package/dist/runtime/scene-pointer-descendants.d.ts +15 -0
  116. package/dist/runtime/scene-pointer-descendants.d.ts.map +1 -0
  117. package/dist/ui/screenspace.d.ts +4 -2
  118. package/dist/ui/screenspace.d.ts.map +1 -1
  119. package/dist/ui/screenspace.js +16 -4
  120. package/dist/ui/screenspace.js.map +1 -1
  121. package/dist/ui/ui.d.ts +7 -20
  122. package/dist/ui/ui.d.ts.map +1 -1
  123. package/dist/ui/ui.js +6 -29
  124. package/dist/ui/ui.js.map +1 -1
  125. package/dist/version.d.ts +1 -1
  126. package/dist/version.js +1 -1
  127. package/package.json +5 -5
@@ -0,0 +1,296 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ import { Types } from '../ecs/index.js';
8
+ /**
9
+ * Internal component storing per-entity runtime state for active XR layers.
10
+ * Attached by {@link XRLayerSystem} when an entity qualifies; removed on
11
+ * teardown. Keeping state in a component rather than system-side maps makes
12
+ * the system stateless with respect to entities, which improves HMR behavior
13
+ * and allows runtime MCP tools to inspect layer state.
14
+ *
15
+ * @category Layers
16
+ */
17
+ export declare const XRLayerState: import("elics").Component<{
18
+ isQuad: {
19
+ type: Types.Boolean;
20
+ default: true;
21
+ };
22
+ mesh: {
23
+ type: Types.Object;
24
+ default: null;
25
+ };
26
+ renderTarget: {
27
+ type: Types.Object;
28
+ default: null;
29
+ };
30
+ fallbackMaterial: {
31
+ type: Types.Object;
32
+ default: null;
33
+ };
34
+ xrLayer: {
35
+ type: Types.Object;
36
+ default: null;
37
+ };
38
+ pixelWidth: {
39
+ type: Types.Int16;
40
+ default: number;
41
+ };
42
+ pixelHeight: {
43
+ type: Types.Int16;
44
+ default: number;
45
+ };
46
+ stencil: {
47
+ type: Types.Boolean;
48
+ default: false;
49
+ };
50
+ cachedTransform: {
51
+ type: Types.Object;
52
+ default: null;
53
+ };
54
+ }>;
55
+ declare const XRLayerSystem_base: import("elics").SystemConstructor<import("elics").SystemSchema, {
56
+ quadLayers: {
57
+ required: import("elics").Component<{
58
+ width: {
59
+ type: Types.Float32;
60
+ default: number;
61
+ };
62
+ height: {
63
+ type: Types.Float32;
64
+ default: number;
65
+ };
66
+ pixelWidth: {
67
+ type: Types.Int16;
68
+ default: number;
69
+ };
70
+ pixelHeight: {
71
+ type: Types.Int16;
72
+ default: number;
73
+ };
74
+ renderCallback: {
75
+ type: Types.Object;
76
+ default: null;
77
+ };
78
+ stencil: {
79
+ type: Types.Boolean;
80
+ default: false;
81
+ };
82
+ }>[];
83
+ };
84
+ cylinderLayers: {
85
+ required: import("elics").Component<{
86
+ radius: {
87
+ type: Types.Float32;
88
+ default: number;
89
+ };
90
+ centralAngle: {
91
+ type: Types.Float32;
92
+ default: number;
93
+ };
94
+ aspectRatio: {
95
+ type: Types.Float32;
96
+ default: number;
97
+ };
98
+ pixelWidth: {
99
+ type: Types.Int16;
100
+ default: number;
101
+ };
102
+ pixelHeight: {
103
+ type: Types.Int16;
104
+ default: number;
105
+ };
106
+ renderCallback: {
107
+ type: Types.Object;
108
+ default: null;
109
+ };
110
+ stencil: {
111
+ type: Types.Boolean;
112
+ default: false;
113
+ };
114
+ }>[];
115
+ };
116
+ activeLayers: {
117
+ required: import("elics").Component<{
118
+ isQuad: {
119
+ type: Types.Boolean;
120
+ default: true;
121
+ };
122
+ mesh: {
123
+ type: Types.Object;
124
+ default: null;
125
+ };
126
+ renderTarget: {
127
+ type: Types.Object;
128
+ default: null;
129
+ };
130
+ fallbackMaterial: {
131
+ type: Types.Object;
132
+ default: null;
133
+ };
134
+ xrLayer: {
135
+ type: Types.Object;
136
+ default: null;
137
+ };
138
+ pixelWidth: {
139
+ type: Types.Int16;
140
+ default: number;
141
+ };
142
+ pixelHeight: {
143
+ type: Types.Int16;
144
+ default: number;
145
+ };
146
+ stencil: {
147
+ type: Types.Boolean;
148
+ default: false;
149
+ };
150
+ cachedTransform: {
151
+ type: Types.Object;
152
+ default: null;
153
+ };
154
+ }>[];
155
+ };
156
+ }, import("../ecs/world.js").World, import("../ecs/system.js").System<import("elics").SystemSchema, {
157
+ quadLayers: {
158
+ required: import("elics").Component<{
159
+ width: {
160
+ type: Types.Float32;
161
+ default: number;
162
+ };
163
+ height: {
164
+ type: Types.Float32;
165
+ default: number;
166
+ };
167
+ pixelWidth: {
168
+ type: Types.Int16;
169
+ default: number;
170
+ };
171
+ pixelHeight: {
172
+ type: Types.Int16;
173
+ default: number;
174
+ };
175
+ renderCallback: {
176
+ type: Types.Object;
177
+ default: null;
178
+ };
179
+ stencil: {
180
+ type: Types.Boolean;
181
+ default: false;
182
+ };
183
+ }>[];
184
+ };
185
+ cylinderLayers: {
186
+ required: import("elics").Component<{
187
+ radius: {
188
+ type: Types.Float32;
189
+ default: number;
190
+ };
191
+ centralAngle: {
192
+ type: Types.Float32;
193
+ default: number;
194
+ };
195
+ aspectRatio: {
196
+ type: Types.Float32;
197
+ default: number;
198
+ };
199
+ pixelWidth: {
200
+ type: Types.Int16;
201
+ default: number;
202
+ };
203
+ pixelHeight: {
204
+ type: Types.Int16;
205
+ default: number;
206
+ };
207
+ renderCallback: {
208
+ type: Types.Object;
209
+ default: null;
210
+ };
211
+ stencil: {
212
+ type: Types.Boolean;
213
+ default: false;
214
+ };
215
+ }>[];
216
+ };
217
+ activeLayers: {
218
+ required: import("elics").Component<{
219
+ isQuad: {
220
+ type: Types.Boolean;
221
+ default: true;
222
+ };
223
+ mesh: {
224
+ type: Types.Object;
225
+ default: null;
226
+ };
227
+ renderTarget: {
228
+ type: Types.Object;
229
+ default: null;
230
+ };
231
+ fallbackMaterial: {
232
+ type: Types.Object;
233
+ default: null;
234
+ };
235
+ xrLayer: {
236
+ type: Types.Object;
237
+ default: null;
238
+ };
239
+ pixelWidth: {
240
+ type: Types.Int16;
241
+ default: number;
242
+ };
243
+ pixelHeight: {
244
+ type: Types.Int16;
245
+ default: number;
246
+ };
247
+ stencil: {
248
+ type: Types.Boolean;
249
+ default: false;
250
+ };
251
+ cachedTransform: {
252
+ type: Types.Object;
253
+ default: null;
254
+ };
255
+ }>[];
256
+ };
257
+ }>>;
258
+ /**
259
+ * XRLayerSystem manages WebXR quad and cylinder composition layers.
260
+ *
261
+ * For each entity with an {@link XRQuadLayer} or {@link XRCylinderLayer}
262
+ * component, the system:
263
+ * - Creates a mesh (plane or cylinder) as a child of the entity's object3D
264
+ * - Renders layer content each frame via the component's `renderCallback`
265
+ * - In XR sessions with layer support, creates native XR composition layers
266
+ * and switches the mesh to a punch-through material that makes the
267
+ * projection layer transparent where the content layer appears
268
+ * - Falls back to rendering the content onto a textured mesh outside XR
269
+ *
270
+ * @category Layers
271
+ */
272
+ export declare class XRLayerSystem extends XRLayerSystem_base {
273
+ private sessionUsesLayers;
274
+ init(): void;
275
+ update(): void;
276
+ private setupLayer;
277
+ private teardownLayer;
278
+ private handleSessionStart;
279
+ private handleSessionEnd;
280
+ private activateNativeLayer;
281
+ private deactivateNativeLayer;
282
+ /**
283
+ * Rebuild the session's render state layers array.
284
+ * Keeps the projection layer at index 0, then appends content layers.
285
+ */
286
+ private updateSessionLayers;
287
+ private renderLayers;
288
+ /**
289
+ * Update the native XR layer's transform only when the mesh has moved,
290
+ * avoiding per-frame XRRigidTransform allocations for static layers.
291
+ */
292
+ private syncLayerTransform;
293
+ private createRenderTarget;
294
+ }
295
+ export {};
296
+ //# sourceMappingURL=xr-layer-system.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xr-layer-system.d.ts","sourceRoot":"","sources":["../../src/layers/xr-layer-system.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAyC,KAAK,EAAE,MAAM,iBAAiB,CAAC;AA2C/E;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAcxB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEF;;;;;;;;;;;;;GAaG;AACH,qBAAa,aAAc,SAAQ,kBAIjC;IACA,OAAO,CAAC,iBAAiB,CAAS;IAElC,IAAI;IAyBJ,MAAM;IAWN,OAAO,CAAC,UAAU;IAwElB,OAAO,CAAC,aAAa;IAkCrB,OAAO,CAAC,kBAAkB;IAoB1B,OAAO,CAAC,gBAAgB;IAWxB,OAAO,CAAC,mBAAmB;IAmF3B,OAAO,CAAC,qBAAqB;IAqC7B;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAwB3B,OAAO,CAAC,YAAY;IAiEpB;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IA6B1B,OAAO,CAAC,kBAAkB;CAwB3B"}
@@ -0,0 +1,378 @@
1
+ import { createSystem } from '../ecs/system.js';
2
+ import '../ecs/world.js';
3
+ import { createComponent, Types } from 'elics';
4
+ import '../ecs/entity.js';
5
+ import '../ecs/component-registry.js';
6
+ import '../runtime/three.js';
7
+ import { XRCylinderLayer } from './xr-cylinder-layer.js';
8
+ import { XRQuadLayer } from './xr-quad-layer.js';
9
+ import { Vector3, Quaternion, Color, PlaneGeometry, CylinderGeometry, MeshBasicMaterial, Mesh, FrontSide, BackSide, CustomBlending, AddEquation, ZeroFactor, SRGBColorSpace, WebGLRenderTarget, DepthTexture, UnsignedByteType, RGBAFormat, UnsignedInt248Type, UnsignedIntType, DepthStencilFormat, DepthFormat } from 'three';
10
+
11
+ /**
12
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
13
+ *
14
+ * This source code is licensed under the MIT license found in the
15
+ * LICENSE file in the root directory of this source tree.
16
+ */
17
+ const _position = new Vector3();
18
+ const _quaternion = new Quaternion();
19
+ const _clearColor = new Color();
20
+ function toRigidTransform(pos, quat) {
21
+ return new XRRigidTransform({ x: pos.x, y: pos.y, z: pos.z }, { x: quat.x, y: quat.y, z: quat.z, w: quat.w });
22
+ }
23
+ /**
24
+ * Internal component storing per-entity runtime state for active XR layers.
25
+ * Attached by {@link XRLayerSystem} when an entity qualifies; removed on
26
+ * teardown. Keeping state in a component rather than system-side maps makes
27
+ * the system stateless with respect to entities, which improves HMR behavior
28
+ * and allows runtime MCP tools to inspect layer state.
29
+ *
30
+ * @category Layers
31
+ */
32
+ const XRLayerState = createComponent('XRLayerState', {
33
+ isQuad: { type: Types.Boolean, default: true },
34
+ mesh: { type: Types.Object, default: null },
35
+ renderTarget: { type: Types.Object, default: null },
36
+ fallbackMaterial: { type: Types.Object, default: null },
37
+ xrLayer: { type: Types.Object, default: null },
38
+ pixelWidth: { type: Types.Int16, default: 0 },
39
+ pixelHeight: { type: Types.Int16, default: 0 },
40
+ stencil: { type: Types.Boolean, default: false },
41
+ cachedTransform: { type: Types.Object, default: null },
42
+ }, 'Internal state for active XR layer entities');
43
+ /**
44
+ * XRLayerSystem manages WebXR quad and cylinder composition layers.
45
+ *
46
+ * For each entity with an {@link XRQuadLayer} or {@link XRCylinderLayer}
47
+ * component, the system:
48
+ * - Creates a mesh (plane or cylinder) as a child of the entity's object3D
49
+ * - Renders layer content each frame via the component's `renderCallback`
50
+ * - In XR sessions with layer support, creates native XR composition layers
51
+ * and switches the mesh to a punch-through material that makes the
52
+ * projection layer transparent where the content layer appears
53
+ * - Falls back to rendering the content onto a textured mesh outside XR
54
+ *
55
+ * @category Layers
56
+ */
57
+ class XRLayerSystem extends createSystem({
58
+ quadLayers: { required: [XRQuadLayer] },
59
+ cylinderLayers: { required: [XRCylinderLayer] },
60
+ activeLayers: { required: [XRLayerState] },
61
+ }) {
62
+ constructor() {
63
+ super(...arguments);
64
+ this.sessionUsesLayers = false;
65
+ }
66
+ init() {
67
+ const onSessionStart = () => this.handleSessionStart();
68
+ const onSessionEnd = () => this.handleSessionEnd();
69
+ this.xrManager.addEventListener('sessionstart', onSessionStart);
70
+ this.xrManager.addEventListener('sessionend', onSessionEnd);
71
+ this.cleanupFuncs.push(() => this.xrManager.removeEventListener('sessionstart', onSessionStart), () => this.xrManager.removeEventListener('sessionend', onSessionEnd));
72
+ this.queries.quadLayers.subscribe('qualify', (entity) => this.setupLayer(entity, 'quad'));
73
+ this.queries.quadLayers.subscribe('disqualify', (entity) => this.teardownLayer(entity));
74
+ this.queries.cylinderLayers.subscribe('qualify', (entity) => this.setupLayer(entity, 'cylinder'));
75
+ this.queries.cylinderLayers.subscribe('disqualify', (entity) => this.teardownLayer(entity));
76
+ }
77
+ update() {
78
+ if (this.queries.activeLayers.entities.size === 0) {
79
+ return;
80
+ }
81
+ this.renderLayers();
82
+ }
83
+ // ---------------------------------------------------------------------------
84
+ // Layer setup / teardown
85
+ // ---------------------------------------------------------------------------
86
+ setupLayer(entity, type) {
87
+ var _a;
88
+ const isQuad = type === 'quad';
89
+ const component = isQuad ? XRQuadLayer : XRCylinderLayer;
90
+ const pixelWidth = entity.getValue(component, 'pixelWidth');
91
+ const pixelHeight = entity.getValue(component, 'pixelHeight');
92
+ const stencil = entity.getValue(component, 'stencil');
93
+ let geometry;
94
+ let side;
95
+ if (isQuad) {
96
+ const width = entity.getValue(XRQuadLayer, 'width');
97
+ const height = entity.getValue(XRQuadLayer, 'height');
98
+ geometry = new PlaneGeometry(width, height);
99
+ side = FrontSide;
100
+ }
101
+ else {
102
+ const radius = entity.getValue(XRCylinderLayer, 'radius');
103
+ const centralAngle = entity.getValue(XRCylinderLayer, 'centralAngle');
104
+ const aspectRatio = entity.getValue(XRCylinderLayer, 'aspectRatio');
105
+ geometry = new CylinderGeometry(radius, radius, (radius * centralAngle) / aspectRatio, 64, 64, true, Math.PI - centralAngle / 2, centralAngle);
106
+ side = BackSide;
107
+ }
108
+ const renderTarget = this.createRenderTarget(pixelWidth, pixelHeight, stencil);
109
+ const fallbackMaterial = new MeshBasicMaterial({
110
+ color: 0xffffff,
111
+ side,
112
+ transparent: true,
113
+ });
114
+ fallbackMaterial.map = renderTarget.texture;
115
+ fallbackMaterial.map.offset.y = 1;
116
+ fallbackMaterial.map.repeat.y = -1;
117
+ const mesh = new Mesh(geometry, fallbackMaterial);
118
+ (_a = entity.object3D) === null || _a === void 0 ? void 0 : _a.add(mesh);
119
+ entity.addComponent(XRLayerState, {
120
+ isQuad,
121
+ mesh,
122
+ renderTarget,
123
+ fallbackMaterial,
124
+ pixelWidth,
125
+ pixelHeight,
126
+ stencil,
127
+ });
128
+ if (this.sessionUsesLayers) {
129
+ this.activateNativeLayer(entity);
130
+ this.updateSessionLayers();
131
+ }
132
+ }
133
+ teardownLayer(entity) {
134
+ const mesh = XRLayerState.data.mesh[entity.index];
135
+ if (!mesh) {
136
+ return;
137
+ }
138
+ const fallbackMaterial = XRLayerState.data.fallbackMaterial[entity.index];
139
+ const renderTarget = XRLayerState.data.renderTarget[entity.index];
140
+ const xrLayer = XRLayerState.data.xrLayer[entity.index];
141
+ if (xrLayer && this.sessionUsesLayers) {
142
+ entity.setValue(XRLayerState, 'xrLayer', null);
143
+ this.updateSessionLayers();
144
+ }
145
+ mesh.geometry.dispose();
146
+ fallbackMaterial.dispose();
147
+ if (mesh.material !== fallbackMaterial) {
148
+ mesh.material.dispose();
149
+ }
150
+ renderTarget.dispose();
151
+ mesh.removeFromParent();
152
+ entity.removeComponent(XRLayerState);
153
+ }
154
+ // ---------------------------------------------------------------------------
155
+ // XR session lifecycle
156
+ // ---------------------------------------------------------------------------
157
+ handleSessionStart() {
158
+ var _a;
159
+ const session = this.xrManager.getSession();
160
+ const layers = (_a = session === null || session === void 0 ? void 0 : session.renderState) === null || _a === void 0 ? void 0 : _a.layers;
161
+ // Need both a layers array AND a projection layer at index 0.
162
+ // The IWER emulator exposes an empty layers array which is truthy
163
+ // but has no projection layer -- treat that as "no layers support".
164
+ if (!(layers === null || layers === void 0 ? void 0 : layers.length)) {
165
+ this.sessionUsesLayers = false;
166
+ return;
167
+ }
168
+ this.sessionUsesLayers = true;
169
+ for (const entity of this.queries.activeLayers.entities) {
170
+ this.activateNativeLayer(entity);
171
+ }
172
+ this.updateSessionLayers();
173
+ }
174
+ handleSessionEnd() {
175
+ for (const entity of this.queries.activeLayers.entities) {
176
+ this.deactivateNativeLayer(entity);
177
+ }
178
+ this.sessionUsesLayers = false;
179
+ }
180
+ // ---------------------------------------------------------------------------
181
+ // Native layer management
182
+ // ---------------------------------------------------------------------------
183
+ activateNativeLayer(entity) {
184
+ const binding = this.xrManager.getBinding();
185
+ const session = this.xrManager.getSession();
186
+ if (!binding || !session) {
187
+ return;
188
+ }
189
+ const isQuad = !!XRLayerState.data.isQuad[entity.index];
190
+ const mesh = XRLayerState.data.mesh[entity.index];
191
+ const pixelWidth = XRLayerState.data.pixelWidth[entity.index];
192
+ const pixelHeight = XRLayerState.data.pixelHeight[entity.index];
193
+ const renderTarget = XRLayerState.data.renderTarget[entity.index];
194
+ const refSpace = this.xrManager.getReferenceSpace();
195
+ mesh.updateMatrixWorld(true);
196
+ mesh.getWorldPosition(_position);
197
+ mesh.getWorldQuaternion(_quaternion);
198
+ const transform = toRigidTransform(_position, _quaternion);
199
+ let xrLayer;
200
+ if (isQuad) {
201
+ const width = entity.getValue(XRQuadLayer, 'width');
202
+ const height = entity.getValue(XRQuadLayer, 'height');
203
+ xrLayer = binding.createQuadLayer({
204
+ transform,
205
+ width: width / 2,
206
+ height: height / 2,
207
+ space: refSpace,
208
+ viewPixelWidth: pixelWidth,
209
+ viewPixelHeight: pixelHeight,
210
+ clearOnAccess: false,
211
+ });
212
+ }
213
+ else {
214
+ const radius = entity.getValue(XRCylinderLayer, 'radius');
215
+ const centralAngle = entity.getValue(XRCylinderLayer, 'centralAngle');
216
+ const aspectRatio = entity.getValue(XRCylinderLayer, 'aspectRatio');
217
+ xrLayer = binding.createCylinderLayer({
218
+ transform,
219
+ radius,
220
+ centralAngle,
221
+ aspectRatio,
222
+ space: refSpace,
223
+ viewPixelWidth: pixelWidth,
224
+ viewPixelHeight: pixelHeight,
225
+ clearOnAccess: false,
226
+ });
227
+ }
228
+ entity.setValue(XRLayerState, 'xrLayer', xrLayer);
229
+ // Switch to punch-through material so the projection layer is
230
+ // transparent where this content layer appears.
231
+ const side = isQuad ? FrontSide : BackSide;
232
+ const punchMaterial = new MeshBasicMaterial({ color: 0xffffff, side });
233
+ punchMaterial.blending = CustomBlending;
234
+ punchMaterial.blendEquation = AddEquation;
235
+ punchMaterial.blendSrc = ZeroFactor;
236
+ punchMaterial.blendDst = ZeroFactor;
237
+ mesh.material = punchMaterial;
238
+ // Mark render target for external-texture usage and set colorSpace so
239
+ // that WebGLPrograms can derive the correct output encoding (super-three
240
+ // reads renderTarget.texture.colorSpace when isXRRenderTarget is true).
241
+ renderTarget.isXRRenderTarget = true;
242
+ renderTarget.texture.colorSpace = SRGBColorSpace;
243
+ entity.setValue(XRLayerState, 'cachedTransform', {
244
+ position: _position.clone(),
245
+ quaternion: _quaternion.clone(),
246
+ });
247
+ }
248
+ deactivateNativeLayer(entity) {
249
+ const mesh = XRLayerState.data.mesh[entity.index];
250
+ const fallbackMaterial = XRLayerState.data.fallbackMaterial[entity.index];
251
+ const pixelWidth = XRLayerState.data.pixelWidth[entity.index];
252
+ const pixelHeight = XRLayerState.data.pixelHeight[entity.index];
253
+ const stencil = !!XRLayerState.data.stencil[entity.index];
254
+ // Dispose punch-through material
255
+ if (mesh.material !== fallbackMaterial) {
256
+ mesh.material.dispose();
257
+ }
258
+ // Recreate render target so stale __hasExternalTextures state is cleared
259
+ const oldRenderTarget = XRLayerState.data.renderTarget[entity.index];
260
+ oldRenderTarget.dispose();
261
+ const newRenderTarget = this.createRenderTarget(pixelWidth, pixelHeight, stencil);
262
+ entity.setValue(XRLayerState, 'renderTarget', newRenderTarget);
263
+ // Restore fallback material with the fresh render target texture
264
+ fallbackMaterial.map = newRenderTarget.texture;
265
+ fallbackMaterial.map.offset.y = 1;
266
+ fallbackMaterial.map.repeat.y = -1;
267
+ mesh.material = fallbackMaterial;
268
+ entity.setValue(XRLayerState, 'xrLayer', null);
269
+ entity.setValue(XRLayerState, 'cachedTransform', null);
270
+ }
271
+ /**
272
+ * Rebuild the session's render state layers array.
273
+ * Keeps the projection layer at index 0, then appends content layers.
274
+ */
275
+ updateSessionLayers() {
276
+ const session = this.xrManager.getSession();
277
+ if (!(session === null || session === void 0 ? void 0 : session.renderState.layers)) {
278
+ return;
279
+ }
280
+ // Projection layer is always the first entry
281
+ const projLayer = session.renderState.layers[0];
282
+ const layers = projLayer ? [projLayer] : [];
283
+ for (const entity of this.queries.activeLayers.entities) {
284
+ const xrLayer = XRLayerState.data.xrLayer[entity.index];
285
+ if (xrLayer) {
286
+ layers.push(xrLayer);
287
+ }
288
+ }
289
+ session.updateRenderState({ layers });
290
+ }
291
+ // ---------------------------------------------------------------------------
292
+ // Per-frame rendering
293
+ // ---------------------------------------------------------------------------
294
+ renderLayers() {
295
+ const renderer = this.renderer;
296
+ const savedRenderTarget = renderer.getRenderTarget();
297
+ // Disable XR so renderer.render() uses the layer's own camera
298
+ // instead of the headset-tracked XR cameras.
299
+ const savedXrEnabled = renderer.xr.enabled;
300
+ renderer.xr.enabled = false;
301
+ // Save clear color so we can clear layers to transparent
302
+ renderer.getClearColor(_clearColor);
303
+ const savedClearAlpha = renderer.getClearAlpha();
304
+ renderer.setClearColor(0x000000, 0);
305
+ for (const entity of this.queries.activeLayers.entities) {
306
+ const isQuad = !!XRLayerState.data.isQuad[entity.index];
307
+ const component = isQuad ? XRQuadLayer : XRCylinderLayer;
308
+ const callback = entity.getValue(component, 'renderCallback');
309
+ if (!callback) {
310
+ continue;
311
+ }
312
+ const xrLayer = XRLayerState.data.xrLayer[entity.index];
313
+ const mesh = XRLayerState.data.mesh[entity.index];
314
+ const renderTarget = XRLayerState.data.renderTarget[entity.index];
315
+ if (this.sessionUsesLayers && xrLayer) {
316
+ // XR path: sync native layer transform and render to its texture
317
+ const binding = this.xrManager.getBinding();
318
+ const frame = this.xrFrame;
319
+ if (!binding || !frame) {
320
+ continue;
321
+ }
322
+ this.syncLayerTransform(xrLayer, mesh, entity);
323
+ const subImage = binding.getSubImage(xrLayer, frame);
324
+ renderer.setRenderTargetTextures(renderTarget, subImage.colorTexture, undefined);
325
+ renderer.setRenderTarget(renderTarget);
326
+ }
327
+ else {
328
+ // Fallback path: render to the internal render target
329
+ renderer.setRenderTarget(renderTarget);
330
+ }
331
+ callback();
332
+ }
333
+ // Restore renderer state
334
+ renderer.setClearColor(_clearColor, savedClearAlpha);
335
+ renderer.xr.enabled = savedXrEnabled;
336
+ renderer.setRenderTarget(savedRenderTarget);
337
+ }
338
+ // ---------------------------------------------------------------------------
339
+ // Helpers
340
+ // ---------------------------------------------------------------------------
341
+ /**
342
+ * Update the native XR layer's transform only when the mesh has moved,
343
+ * avoiding per-frame XRRigidTransform allocations for static layers.
344
+ */
345
+ syncLayerTransform(xrLayer, mesh, entity) {
346
+ mesh.updateMatrixWorld(true);
347
+ mesh.getWorldPosition(_position);
348
+ mesh.getWorldQuaternion(_quaternion);
349
+ const cached = XRLayerState.data.cachedTransform[entity.index];
350
+ if ((cached === null || cached === void 0 ? void 0 : cached.position.equals(_position)) &&
351
+ cached.quaternion.equals(_quaternion)) {
352
+ return;
353
+ }
354
+ xrLayer.transform = toRigidTransform(_position, _quaternion);
355
+ if (cached) {
356
+ cached.position.copy(_position);
357
+ cached.quaternion.copy(_quaternion);
358
+ }
359
+ else {
360
+ entity.setValue(XRLayerState, 'cachedTransform', {
361
+ position: _position.clone(),
362
+ quaternion: _quaternion.clone(),
363
+ });
364
+ }
365
+ }
366
+ createRenderTarget(width, height, stencil) {
367
+ return new WebGLRenderTarget(width, height, {
368
+ format: RGBAFormat,
369
+ type: UnsignedByteType,
370
+ depthTexture: new DepthTexture(width, height, stencil ? UnsignedInt248Type : UnsignedIntType, undefined, undefined, undefined, undefined, undefined, undefined, stencil ? DepthStencilFormat : DepthFormat),
371
+ samples: 4,
372
+ stencilBuffer: stencil,
373
+ });
374
+ }
375
+ }
376
+
377
+ export { XRLayerState, XRLayerSystem };
378
+ //# sourceMappingURL=xr-layer-system.js.map