@vib3code/sdk 2.0.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.
- package/CHANGELOG.md +118 -0
- package/DOCS/BLUEPRINT_EXECUTION_PLAN_2026-01-07.md +34 -0
- package/DOCS/CI_TESTING.md +38 -0
- package/DOCS/CLI_ONBOARDING.md +75 -0
- package/DOCS/CONTROL_REFERENCE.md +64 -0
- package/DOCS/DEV_TRACK_ANALYSIS.md +77 -0
- package/DOCS/DEV_TRACK_PLAN_2026-01-07.md +42 -0
- package/DOCS/DEV_TRACK_SESSION_2026-01-31.md +220 -0
- package/DOCS/ENV_SETUP.md +189 -0
- package/DOCS/EXPORT_FORMATS.md +417 -0
- package/DOCS/GPU_DISPOSAL_GUIDE.md +21 -0
- package/DOCS/LICENSING_TIERS.md +275 -0
- package/DOCS/MASTER_PLAN_2026-01-31.md +570 -0
- package/DOCS/OBS_SETUP_GUIDE.md +98 -0
- package/DOCS/PROJECT_SETUP.md +66 -0
- package/DOCS/RENDERER_LIFECYCLE.md +40 -0
- package/DOCS/REPO_MANIFEST.md +121 -0
- package/DOCS/SESSION_014_PLAN.md +195 -0
- package/DOCS/SESSION_LOG_2026-01-07.md +56 -0
- package/DOCS/STRATEGIC_BLUEPRINT_2026-01-07.md +72 -0
- package/DOCS/SYSTEM_AUDIT_2026-01-30.md +738 -0
- package/DOCS/SYSTEM_INVENTORY.md +520 -0
- package/DOCS/TELEMETRY_EXPORTS.md +34 -0
- package/DOCS/WEBGPU_STATUS.md +38 -0
- package/DOCS/XR_BENCHMARKS.md +608 -0
- package/LICENSE +21 -0
- package/README.md +426 -0
- package/docs/.nojekyll +0 -0
- package/docs/01-dissolution_of_euclidean_hegemony.html +346 -0
- package/docs/02-hyperspatial_ego_death.html +346 -0
- package/docs/03-post_cartesian_sublime.html +346 -0
- package/docs/04-crystalline_void_meditation.html +346 -0
- package/docs/05-quantum_decoherence_ballet.html +346 -0
- package/docs/06-dissolution_of_euclidean_hegemony.html +346 -0
- package/docs/07-hyperspatial_ego_death.html +346 -0
- package/docs/08-post_cartesian_sublime.html +346 -0
- package/docs/09-crystalline_void_meditation.html +346 -0
- package/docs/10-quantum_decoherence_ballet.html +346 -0
- package/docs/11-dissolution_of_euclidean_hegemony.html +346 -0
- package/docs/12-hyperspatial_ego_death.html +346 -0
- package/docs/13-post_cartesian_sublime.html +346 -0
- package/docs/index.html +794 -0
- package/docs/test-hub.html +441 -0
- package/docs/url-state.js +102 -0
- package/docs/vib3-exports/01-quantum-quantum-tetrahedron-lattice.html +489 -0
- package/docs/vib3-exports/02-quantum-quantum-hypersphere-matrix.html +489 -0
- package/docs/vib3-exports/03-quantum-quantum-hypertetra-fractal.html +489 -0
- package/docs/vib3-exports/04-faceted-faceted-crystal-structure.html +407 -0
- package/docs/vib3-exports/05-faceted-faceted-klein-bottle.html +407 -0
- package/docs/vib3-exports/06-faceted-faceted-hypertetra-torus.html +407 -0
- package/docs/vib3-exports/07-holographic-holographic-wave-field.html +457 -0
- package/docs/vib3-exports/08-holographic-holographic-hypersphere-sphere.html +457 -0
- package/docs/vib3-exports/09-holographic-holographic-hypertetra-crystal.html +457 -0
- package/docs/vib3-exports/index.html +238 -0
- package/docs/webgpu-live.html +702 -0
- package/package.json +367 -0
- package/src/advanced/AIPresetGenerator.js +777 -0
- package/src/advanced/MIDIController.js +703 -0
- package/src/advanced/OffscreenWorker.js +1051 -0
- package/src/advanced/WebGPUCompute.js +1051 -0
- package/src/advanced/WebXRRenderer.js +680 -0
- package/src/agent/cli/AgentCLI.js +615 -0
- package/src/agent/cli/index.js +14 -0
- package/src/agent/index.js +73 -0
- package/src/agent/mcp/MCPServer.js +950 -0
- package/src/agent/mcp/index.js +9 -0
- package/src/agent/mcp/tools.js +548 -0
- package/src/agent/telemetry/EventStream.js +669 -0
- package/src/agent/telemetry/Instrumentation.js +618 -0
- package/src/agent/telemetry/TelemetryExporters.js +427 -0
- package/src/agent/telemetry/TelemetryService.js +464 -0
- package/src/agent/telemetry/index.js +52 -0
- package/src/benchmarks/BenchmarkRunner.js +381 -0
- package/src/benchmarks/MetricsCollector.js +299 -0
- package/src/benchmarks/index.js +9 -0
- package/src/benchmarks/scenes.js +259 -0
- package/src/cli/index.js +675 -0
- package/src/config/ApiConfig.js +88 -0
- package/src/core/CanvasManager.js +217 -0
- package/src/core/ErrorReporter.js +117 -0
- package/src/core/ParameterMapper.js +333 -0
- package/src/core/Parameters.js +396 -0
- package/src/core/RendererContracts.js +200 -0
- package/src/core/UnifiedResourceManager.js +370 -0
- package/src/core/VIB3Engine.js +636 -0
- package/src/core/renderers/FacetedRendererAdapter.js +32 -0
- package/src/core/renderers/HolographicRendererAdapter.js +29 -0
- package/src/core/renderers/QuantumRendererAdapter.js +29 -0
- package/src/core/renderers/RendererLifecycleManager.js +63 -0
- package/src/creative/ColorPresetsSystem.js +980 -0
- package/src/creative/ParameterTimeline.js +1061 -0
- package/src/creative/PostProcessingPipeline.js +1113 -0
- package/src/creative/TransitionAnimator.js +683 -0
- package/src/export/CSSExporter.js +226 -0
- package/src/export/CardGeneratorBase.js +279 -0
- package/src/export/ExportManager.js +580 -0
- package/src/export/FacetedCardGenerator.js +279 -0
- package/src/export/HolographicCardGenerator.js +543 -0
- package/src/export/LottieExporter.js +552 -0
- package/src/export/QuantumCardGenerator.js +315 -0
- package/src/export/SVGExporter.js +519 -0
- package/src/export/ShaderExporter.js +903 -0
- package/src/export/TradingCardGenerator.js +3055 -0
- package/src/export/TradingCardManager.js +181 -0
- package/src/export/VIB3PackageExporter.js +559 -0
- package/src/export/index.js +14 -0
- package/src/export/systems/TradingCardSystemFaceted.js +494 -0
- package/src/export/systems/TradingCardSystemHolographic.js +452 -0
- package/src/export/systems/TradingCardSystemQuantum.js +411 -0
- package/src/faceted/FacetedSystem.js +963 -0
- package/src/features/CollectionManager.js +433 -0
- package/src/gallery/CollectionManager.js +240 -0
- package/src/gallery/GallerySystem.js +485 -0
- package/src/geometry/GeometryFactory.js +314 -0
- package/src/geometry/GeometryLibrary.js +72 -0
- package/src/geometry/buffers/BufferBuilder.js +338 -0
- package/src/geometry/buffers/index.js +18 -0
- package/src/geometry/generators/Crystal.js +420 -0
- package/src/geometry/generators/Fractal.js +298 -0
- package/src/geometry/generators/KleinBottle.js +197 -0
- package/src/geometry/generators/Sphere.js +192 -0
- package/src/geometry/generators/Tesseract.js +160 -0
- package/src/geometry/generators/Tetrahedron.js +225 -0
- package/src/geometry/generators/Torus.js +304 -0
- package/src/geometry/generators/Wave.js +341 -0
- package/src/geometry/index.js +142 -0
- package/src/geometry/warp/HypersphereCore.js +211 -0
- package/src/geometry/warp/HypertetraCore.js +386 -0
- package/src/geometry/warp/index.js +57 -0
- package/src/holograms/HolographicVisualizer.js +1073 -0
- package/src/holograms/RealHolographicSystem.js +966 -0
- package/src/holograms/variantRegistry.js +69 -0
- package/src/integrations/FigmaPlugin.js +854 -0
- package/src/integrations/OBSMode.js +754 -0
- package/src/integrations/ThreeJsPackage.js +660 -0
- package/src/integrations/TouchDesignerExport.js +552 -0
- package/src/integrations/frameworks/Vib3React.js +591 -0
- package/src/integrations/frameworks/Vib3Svelte.js +654 -0
- package/src/integrations/frameworks/Vib3Vue.js +628 -0
- package/src/llm/LLMParameterInterface.js +240 -0
- package/src/llm/LLMParameterUI.js +577 -0
- package/src/math/Mat4x4.js +708 -0
- package/src/math/Projection.js +341 -0
- package/src/math/Rotor4D.js +637 -0
- package/src/math/Vec4.js +476 -0
- package/src/math/constants.js +164 -0
- package/src/math/index.js +68 -0
- package/src/math/projections.js +54 -0
- package/src/math/rotations.js +196 -0
- package/src/quantum/QuantumEngine.js +906 -0
- package/src/quantum/QuantumVisualizer.js +1103 -0
- package/src/reactivity/ReactivityConfig.js +499 -0
- package/src/reactivity/ReactivityManager.js +586 -0
- package/src/reactivity/SpatialInputSystem.js +1783 -0
- package/src/reactivity/index.js +93 -0
- package/src/render/CommandBuffer.js +465 -0
- package/src/render/MultiCanvasBridge.js +340 -0
- package/src/render/RenderCommand.js +514 -0
- package/src/render/RenderResourceRegistry.js +523 -0
- package/src/render/RenderState.js +552 -0
- package/src/render/RenderTarget.js +512 -0
- package/src/render/ShaderLoader.js +253 -0
- package/src/render/ShaderProgram.js +599 -0
- package/src/render/UnifiedRenderBridge.js +496 -0
- package/src/render/backends/WebGLBackend.js +1108 -0
- package/src/render/backends/WebGPUBackend.js +1409 -0
- package/src/render/commands/CommandBufferExecutor.js +607 -0
- package/src/render/commands/RenderCommandBuffer.js +661 -0
- package/src/render/commands/index.js +17 -0
- package/src/render/index.js +367 -0
- package/src/scene/Disposable.js +498 -0
- package/src/scene/MemoryPool.js +618 -0
- package/src/scene/Node4D.js +697 -0
- package/src/scene/ResourceManager.js +599 -0
- package/src/scene/Scene4D.js +540 -0
- package/src/scene/index.js +98 -0
- package/src/schemas/error.schema.json +84 -0
- package/src/schemas/extension.schema.json +88 -0
- package/src/schemas/index.js +214 -0
- package/src/schemas/parameters.schema.json +142 -0
- package/src/schemas/tool-pack.schema.json +44 -0
- package/src/schemas/tool-response.schema.json +127 -0
- package/src/shaders/common/fullscreen.vert.glsl +5 -0
- package/src/shaders/common/fullscreen.vert.wgsl +17 -0
- package/src/shaders/common/geometry24.glsl +65 -0
- package/src/shaders/common/geometry24.wgsl +54 -0
- package/src/shaders/common/rotation4d.glsl +85 -0
- package/src/shaders/common/rotation4d.wgsl +86 -0
- package/src/shaders/common/uniforms.glsl +44 -0
- package/src/shaders/common/uniforms.wgsl +48 -0
- package/src/shaders/faceted/faceted.frag.glsl +129 -0
- package/src/shaders/faceted/faceted.frag.wgsl +164 -0
- package/src/shaders/holographic/holographic.frag.glsl +406 -0
- package/src/shaders/holographic/holographic.frag.wgsl +185 -0
- package/src/shaders/quantum/quantum.frag.glsl +513 -0
- package/src/shaders/quantum/quantum.frag.wgsl +361 -0
- package/src/testing/ParallelTestFramework.js +519 -0
- package/src/testing/__snapshots__/exportFormats.test.js.snap +24 -0
- package/src/testing/exportFormats.test.js +8 -0
- package/src/testing/projections.test.js +14 -0
- package/src/testing/rotations.test.js +37 -0
- package/src/ui/InteractivityMenu.js +516 -0
- package/src/ui/StatusManager.js +96 -0
- package/src/ui/adaptive/renderers/webgpu/BufferLayout.ts +252 -0
- package/src/ui/adaptive/renderers/webgpu/PolytopeInstanceBuffer.ts +144 -0
- package/src/ui/adaptive/renderers/webgpu/TripleBufferedUniform.ts +170 -0
- package/src/ui/adaptive/renderers/webgpu/WebGPURenderer.ts +735 -0
- package/src/ui/adaptive/renderers/webgpu/index.ts +112 -0
- package/src/variations/VariationManager.js +431 -0
- package/src/viewer/AudioReactivity.js +505 -0
- package/src/viewer/CardBending.js +481 -0
- package/src/viewer/GalleryUI.js +832 -0
- package/src/viewer/ReactivityManager.js +590 -0
- package/src/viewer/TradingCardExporter.js +600 -0
- package/src/viewer/ViewerPortal.js +374 -0
- package/src/viewer/index.js +12 -0
- package/src/wasm/WasmLoader.js +296 -0
- package/src/wasm/index.js +132 -0
- package/tools/agentic/mcpTools.js +88 -0
- package/tools/cli/agent-cli.js +92 -0
- package/tools/export/formats.js +24 -0
- package/tools/math/rotation-baseline.mjs +64 -0
- package/tools/shader-sync-verify.js +937 -0
- package/tools/telemetry/manifestPipeline.js +141 -0
- package/tools/telemetry/telemetryEvents.js +35 -0
- package/types/adaptive-sdk.d.ts +185 -0
- package/types/advanced/AIPresetGenerator.d.ts +81 -0
- package/types/advanced/MIDIController.d.ts +100 -0
- package/types/advanced/OffscreenWorker.d.ts +82 -0
- package/types/advanced/WebGPUCompute.d.ts +52 -0
- package/types/advanced/WebXRRenderer.d.ts +77 -0
- package/types/advanced/index.d.ts +46 -0
- package/types/core/ErrorReporter.d.ts +50 -0
- package/types/core/VIB3Engine.d.ts +204 -0
- package/types/creative/ColorPresetsSystem.d.ts +91 -0
- package/types/creative/ParameterTimeline.d.ts +74 -0
- package/types/creative/PostProcessingPipeline.d.ts +109 -0
- package/types/creative/TransitionAnimator.d.ts +71 -0
- package/types/creative/index.d.ts +35 -0
- package/types/integrations/FigmaPlugin.d.ts +46 -0
- package/types/integrations/OBSMode.d.ts +74 -0
- package/types/integrations/ThreeJsPackage.d.ts +62 -0
- package/types/integrations/TouchDesignerExport.d.ts +36 -0
- package/types/integrations/Vib3React.d.ts +74 -0
- package/types/integrations/Vib3Svelte.d.ts +63 -0
- package/types/integrations/Vib3Vue.d.ts +55 -0
- package/types/integrations/index.d.ts +52 -0
- package/types/reactivity/SpatialInputSystem.d.ts +173 -0
- package/types/reactivity/index.d.ts +394 -0
- package/types/render/CommandBuffer.d.ts +169 -0
- package/types/render/RenderCommand.d.ts +312 -0
- package/types/render/RenderState.d.ts +279 -0
- package/types/render/RenderTarget.d.ts +254 -0
- package/types/render/ShaderProgram.d.ts +277 -0
- package/types/render/UnifiedRenderBridge.d.ts +143 -0
- package/types/render/WebGLBackend.d.ts +168 -0
- package/types/render/WebGPUBackend.d.ts +186 -0
- package/types/render/index.d.ts +141 -0
|
@@ -0,0 +1,680 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VIB3+ WebXR Immersive Renderer
|
|
3
|
+
* Renders 4D visualizations in VR/AR headsets via WebXR API.
|
|
4
|
+
*
|
|
5
|
+
* Provides stereoscopic rendering of VIB3 visualization systems
|
|
6
|
+
* inside immersive WebXR sessions (VR, AR, or inline). Integrates
|
|
7
|
+
* 6DOF head and controller tracking into the VIB3 parameter space,
|
|
8
|
+
* mapping physical orientation to 4D rotation planes.
|
|
9
|
+
*
|
|
10
|
+
* @module advanced/WebXRRenderer
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Supported XR session modes.
|
|
15
|
+
* @typedef {'immersive-vr'|'immersive-ar'|'inline'} XRSessionMode
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* 6DOF pose data extracted from an XR frame.
|
|
20
|
+
* @typedef {Object} SixDOFPose
|
|
21
|
+
* @property {Float32Array} position - [x, y, z] head position in meters
|
|
22
|
+
* @property {Float32Array} orientation - [x, y, z, w] quaternion
|
|
23
|
+
* @property {number} rotXY - Derived rotation in XY plane (radians)
|
|
24
|
+
* @property {number} rotXZ - Derived rotation in XZ plane (radians)
|
|
25
|
+
* @property {number} rotYZ - Derived rotation in YZ plane (radians)
|
|
26
|
+
* @property {number} rotXW - Mapped 4D rotation in XW plane (radians)
|
|
27
|
+
* @property {number} rotYW - Mapped 4D rotation in YW plane (radians)
|
|
28
|
+
* @property {number} rotZW - Mapped 4D rotation in ZW plane (radians)
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
export class WebXRRenderer {
|
|
32
|
+
/**
|
|
33
|
+
* @param {Object} engine - VIB3Engine instance
|
|
34
|
+
*/
|
|
35
|
+
constructor(engine) {
|
|
36
|
+
/** @type {Object} VIB3Engine reference */
|
|
37
|
+
this.engine = engine;
|
|
38
|
+
|
|
39
|
+
/** @type {XRSession|null} Active XR session */
|
|
40
|
+
this.xrSession = null;
|
|
41
|
+
|
|
42
|
+
/** @type {XRReferenceSpace|null} Reference space for pose calculations */
|
|
43
|
+
this.xrRefSpace = null;
|
|
44
|
+
|
|
45
|
+
/** @type {boolean} Whether an immersive session is active */
|
|
46
|
+
this.isImmersive = false;
|
|
47
|
+
|
|
48
|
+
/** @type {XRSessionMode} Current session mode */
|
|
49
|
+
this.mode = 'immersive-vr';
|
|
50
|
+
|
|
51
|
+
/** @type {WebGLRenderingContext|null} XR-compatible GL context */
|
|
52
|
+
this.gl = null;
|
|
53
|
+
|
|
54
|
+
/** @type {XRWebGLLayer|null} XR rendering layer */
|
|
55
|
+
this.xrGLLayer = null;
|
|
56
|
+
|
|
57
|
+
/** @type {number} Animation frame handle for cancellation */
|
|
58
|
+
this._animFrameHandle = 0;
|
|
59
|
+
|
|
60
|
+
/** @type {Map<string, XRInputSource>} Connected XR input sources */
|
|
61
|
+
this._inputSources = new Map();
|
|
62
|
+
|
|
63
|
+
/** @type {SixDOFPose|null} Most recent 6DOF pose data */
|
|
64
|
+
this._lastPose = null;
|
|
65
|
+
|
|
66
|
+
/** @type {Function|null} External frame callback */
|
|
67
|
+
this._onFrameCallback = null;
|
|
68
|
+
|
|
69
|
+
/** @type {boolean} Internal disposed flag */
|
|
70
|
+
this._disposed = false;
|
|
71
|
+
|
|
72
|
+
/** @type {Object} Support status cache */
|
|
73
|
+
this._supportCache = {};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// -----------------------------------------------------------------------
|
|
77
|
+
// Capability Detection
|
|
78
|
+
// -----------------------------------------------------------------------
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Check whether WebXR is available and which session modes are supported.
|
|
82
|
+
* @returns {Promise<{available: boolean, vr: boolean, ar: boolean, inline: boolean}>}
|
|
83
|
+
*/
|
|
84
|
+
async checkSupport() {
|
|
85
|
+
const result = { available: false, vr: false, ar: false, inline: false };
|
|
86
|
+
|
|
87
|
+
if (!navigator.xr) {
|
|
88
|
+
return result;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
result.available = true;
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
result.vr = await navigator.xr.isSessionSupported('immersive-vr');
|
|
95
|
+
} catch (_e) {
|
|
96
|
+
result.vr = false;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
try {
|
|
100
|
+
result.ar = await navigator.xr.isSessionSupported('immersive-ar');
|
|
101
|
+
} catch (_e) {
|
|
102
|
+
result.ar = false;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
result.inline = await navigator.xr.isSessionSupported('inline');
|
|
107
|
+
} catch (_e) {
|
|
108
|
+
result.inline = false;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
this._supportCache = result;
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// -----------------------------------------------------------------------
|
|
116
|
+
// Session Management
|
|
117
|
+
// -----------------------------------------------------------------------
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Start an immersive XR session.
|
|
121
|
+
* Creates an XR-compatible WebGL context, binds framebuffers, and begins
|
|
122
|
+
* the XR render loop.
|
|
123
|
+
*
|
|
124
|
+
* @param {XRSessionMode} [mode='immersive-vr'] - Session mode
|
|
125
|
+
* @returns {Promise<XRSession>} The active XR session
|
|
126
|
+
* @throws {Error} If WebXR is not supported or session request fails
|
|
127
|
+
*/
|
|
128
|
+
async startSession(mode = 'immersive-vr') {
|
|
129
|
+
if (this.xrSession) {
|
|
130
|
+
throw new Error('WebXRRenderer: Session already active. Call endSession() first.');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (!navigator.xr) {
|
|
134
|
+
throw new Error('WebXR API not available in this browser.');
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const supported = await navigator.xr.isSessionSupported(mode);
|
|
138
|
+
if (!supported) {
|
|
139
|
+
throw new Error(`WebXR mode "${mode}" is not supported on this device.`);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
this.mode = mode;
|
|
143
|
+
|
|
144
|
+
// Request session with required features
|
|
145
|
+
const sessionInit = {
|
|
146
|
+
requiredFeatures: ['local-floor'],
|
|
147
|
+
optionalFeatures: ['bounded-floor', 'hand-tracking']
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
this.xrSession = await navigator.xr.requestSession(mode, sessionInit);
|
|
151
|
+
this.isImmersive = mode.startsWith('immersive');
|
|
152
|
+
|
|
153
|
+
// Create XR-compatible WebGL context
|
|
154
|
+
this.gl = this._createXRGLContext();
|
|
155
|
+
|
|
156
|
+
// Create XR WebGL layer
|
|
157
|
+
this.xrGLLayer = new XRWebGLLayer(this.xrSession, this.gl);
|
|
158
|
+
|
|
159
|
+
// Apply render state
|
|
160
|
+
await this.xrSession.updateRenderState({
|
|
161
|
+
baseLayer: this.xrGLLayer,
|
|
162
|
+
depthNear: 0.1,
|
|
163
|
+
depthFar: 1000.0
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
// Obtain reference space
|
|
167
|
+
try {
|
|
168
|
+
this.xrRefSpace = await this.xrSession.requestReferenceSpace('local-floor');
|
|
169
|
+
} catch (_e) {
|
|
170
|
+
// Fall back to 'local' if 'local-floor' unavailable
|
|
171
|
+
this.xrRefSpace = await this.xrSession.requestReferenceSpace('local');
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Listen for input source changes
|
|
175
|
+
this.xrSession.addEventListener('inputsourceschange', (e) => {
|
|
176
|
+
this._onInputSourcesChange(e);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// Listen for session end
|
|
180
|
+
this.xrSession.addEventListener('end', () => {
|
|
181
|
+
this._onSessionEnd();
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
// Start render loop
|
|
185
|
+
this._animFrameHandle = this.xrSession.requestAnimationFrame(
|
|
186
|
+
(time, frame) => this.onXRFrame(time, frame)
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
return this.xrSession;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* End the current XR session gracefully.
|
|
194
|
+
* @returns {Promise<void>}
|
|
195
|
+
*/
|
|
196
|
+
async endSession() {
|
|
197
|
+
if (!this.xrSession) {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
try {
|
|
202
|
+
await this.xrSession.end();
|
|
203
|
+
} catch (_e) {
|
|
204
|
+
// Session may already be ended
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
this._onSessionEnd();
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Register a callback to be invoked each XR frame after rendering.
|
|
212
|
+
* Receives (time, frame, pose) arguments.
|
|
213
|
+
* @param {Function} callback
|
|
214
|
+
*/
|
|
215
|
+
onFrame(callback) {
|
|
216
|
+
this._onFrameCallback = callback;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// -----------------------------------------------------------------------
|
|
220
|
+
// Render Loop
|
|
221
|
+
// -----------------------------------------------------------------------
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* XR frame callback. Retrieves viewer pose, renders each eye, and
|
|
225
|
+
* extracts 6DOF data for SpatialInputSystem.
|
|
226
|
+
*
|
|
227
|
+
* @param {DOMHighResTimeStamp} time - Current timestamp
|
|
228
|
+
* @param {XRFrame} frame - XR frame object
|
|
229
|
+
*/
|
|
230
|
+
onXRFrame(time, frame) {
|
|
231
|
+
if (this._disposed || !this.xrSession) {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Request next frame first for smooth scheduling
|
|
236
|
+
this._animFrameHandle = this.xrSession.requestAnimationFrame(
|
|
237
|
+
(t, f) => this.onXRFrame(t, f)
|
|
238
|
+
);
|
|
239
|
+
|
|
240
|
+
const session = this.xrSession;
|
|
241
|
+
const glLayer = this.xrGLLayer;
|
|
242
|
+
const gl = this.gl;
|
|
243
|
+
|
|
244
|
+
if (!gl || !glLayer || !this.xrRefSpace) {
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const pose = frame.getViewerPose(this.xrRefSpace);
|
|
249
|
+
if (!pose) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Extract and store 6DOF data
|
|
254
|
+
this._lastPose = this._extract6DOF(pose);
|
|
255
|
+
|
|
256
|
+
// Bind XR framebuffer
|
|
257
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, glLayer.framebuffer);
|
|
258
|
+
gl.clearColor(0.0, 0.0, 0.0, 1.0);
|
|
259
|
+
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
260
|
+
|
|
261
|
+
// Render each eye view
|
|
262
|
+
for (const view of pose.views) {
|
|
263
|
+
const viewport = glLayer.getViewport(view);
|
|
264
|
+
if (viewport) {
|
|
265
|
+
this.renderEye(view, viewport);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Process controller inputs
|
|
270
|
+
this._processInputSources(frame);
|
|
271
|
+
|
|
272
|
+
// Invoke external callback
|
|
273
|
+
if (this._onFrameCallback) {
|
|
274
|
+
try {
|
|
275
|
+
this._onFrameCallback(time, frame, this._lastPose);
|
|
276
|
+
} catch (_e) {
|
|
277
|
+
// Swallow errors in external callback to preserve render loop
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Render the VIB3 visualization for a single eye.
|
|
284
|
+
*
|
|
285
|
+
* @param {XRView} view - XR view containing projection and transform matrices
|
|
286
|
+
* @param {XRViewport} viewport - Target viewport rectangle
|
|
287
|
+
*/
|
|
288
|
+
renderEye(view, viewport) {
|
|
289
|
+
const gl = this.gl;
|
|
290
|
+
if (!gl) return;
|
|
291
|
+
|
|
292
|
+
gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
|
|
293
|
+
|
|
294
|
+
// Extract matrices
|
|
295
|
+
const projectionMatrix = view.projectionMatrix;
|
|
296
|
+
const viewMatrix = view.transform.inverse.matrix;
|
|
297
|
+
|
|
298
|
+
// Apply 6DOF pose to VIB3 rotation parameters
|
|
299
|
+
if (this._lastPose && this.engine) {
|
|
300
|
+
this._applyPoseToEngine(this._lastPose);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// Render the current VIB3 system into this viewport
|
|
304
|
+
if (this.engine && typeof this.engine.renderFrame === 'function') {
|
|
305
|
+
this.engine.renderFrame({
|
|
306
|
+
gl,
|
|
307
|
+
projectionMatrix,
|
|
308
|
+
viewMatrix,
|
|
309
|
+
viewport: {
|
|
310
|
+
x: viewport.x,
|
|
311
|
+
y: viewport.y,
|
|
312
|
+
width: viewport.width,
|
|
313
|
+
height: viewport.height
|
|
314
|
+
},
|
|
315
|
+
isXR: true
|
|
316
|
+
});
|
|
317
|
+
} else {
|
|
318
|
+
// Fallback: draw a simple quad to confirm XR is active
|
|
319
|
+
this._renderFallbackQuad(gl, projectionMatrix, viewMatrix);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// -----------------------------------------------------------------------
|
|
324
|
+
// 6DOF Extraction
|
|
325
|
+
// -----------------------------------------------------------------------
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Extract 6DOF pose data and derive VIB3-compatible rotation angles.
|
|
329
|
+
* Maps physical head orientation to 3D rotation planes (XY, XZ, YZ)
|
|
330
|
+
* and position displacement to 4D rotation planes (XW, YW, ZW).
|
|
331
|
+
*
|
|
332
|
+
* @param {XRViewerPose} pose - Viewer pose from XRFrame
|
|
333
|
+
* @returns {SixDOFPose} Extracted and mapped pose data
|
|
334
|
+
*/
|
|
335
|
+
get6DOFInput() {
|
|
336
|
+
return this._lastPose;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* @param {XRViewerPose} pose
|
|
341
|
+
* @returns {SixDOFPose}
|
|
342
|
+
* @private
|
|
343
|
+
*/
|
|
344
|
+
_extract6DOF(pose) {
|
|
345
|
+
const transform = pose.transform;
|
|
346
|
+
const pos = transform.position;
|
|
347
|
+
const ori = transform.orientation;
|
|
348
|
+
|
|
349
|
+
const position = new Float32Array([pos.x, pos.y, pos.z]);
|
|
350
|
+
const orientation = new Float32Array([ori.x, ori.y, ori.z, ori.w]);
|
|
351
|
+
|
|
352
|
+
// Convert quaternion to Euler angles for 3D rotation planes
|
|
353
|
+
const euler = this._quaternionToEuler(ori.x, ori.y, ori.z, ori.w);
|
|
354
|
+
|
|
355
|
+
// Map position displacement to 4D rotations
|
|
356
|
+
// Scale: 1 meter of movement = 1 radian of 4D rotation
|
|
357
|
+
const posScale = 1.0;
|
|
358
|
+
const rotXW = pos.x * posScale;
|
|
359
|
+
const rotYW = pos.y * posScale;
|
|
360
|
+
const rotZW = pos.z * posScale;
|
|
361
|
+
|
|
362
|
+
return {
|
|
363
|
+
position,
|
|
364
|
+
orientation,
|
|
365
|
+
rotXY: euler.yaw, // Yaw -> XY plane
|
|
366
|
+
rotXZ: euler.pitch, // Pitch -> XZ plane
|
|
367
|
+
rotYZ: euler.roll, // Roll -> YZ plane
|
|
368
|
+
rotXW: this._wrapAngle(rotXW),
|
|
369
|
+
rotYW: this._wrapAngle(rotYW),
|
|
370
|
+
rotZW: this._wrapAngle(rotZW)
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Convert quaternion (x, y, z, w) to Euler angles (yaw, pitch, roll).
|
|
376
|
+
* Uses ZYX convention.
|
|
377
|
+
*
|
|
378
|
+
* @param {number} qx
|
|
379
|
+
* @param {number} qy
|
|
380
|
+
* @param {number} qz
|
|
381
|
+
* @param {number} qw
|
|
382
|
+
* @returns {{yaw: number, pitch: number, roll: number}}
|
|
383
|
+
* @private
|
|
384
|
+
*/
|
|
385
|
+
_quaternionToEuler(qx, qy, qz, qw) {
|
|
386
|
+
// Roll (X-axis)
|
|
387
|
+
const sinr_cosp = 2.0 * (qw * qx + qy * qz);
|
|
388
|
+
const cosr_cosp = 1.0 - 2.0 * (qx * qx + qy * qy);
|
|
389
|
+
const roll = Math.atan2(sinr_cosp, cosr_cosp);
|
|
390
|
+
|
|
391
|
+
// Pitch (Y-axis)
|
|
392
|
+
const sinp = 2.0 * (qw * qy - qz * qx);
|
|
393
|
+
let pitch;
|
|
394
|
+
if (Math.abs(sinp) >= 1.0) {
|
|
395
|
+
pitch = Math.sign(sinp) * (Math.PI / 2.0); // Clamp at poles
|
|
396
|
+
} else {
|
|
397
|
+
pitch = Math.asin(sinp);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// Yaw (Z-axis)
|
|
401
|
+
const siny_cosp = 2.0 * (qw * qz + qx * qy);
|
|
402
|
+
const cosy_cosp = 1.0 - 2.0 * (qy * qy + qz * qz);
|
|
403
|
+
const yaw = Math.atan2(siny_cosp, cosy_cosp);
|
|
404
|
+
|
|
405
|
+
return { yaw, pitch, roll };
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Wrap angle into [0, 2*PI) range.
|
|
410
|
+
* @param {number} angle - Angle in radians
|
|
411
|
+
* @returns {number}
|
|
412
|
+
* @private
|
|
413
|
+
*/
|
|
414
|
+
_wrapAngle(angle) {
|
|
415
|
+
const TWO_PI = Math.PI * 2.0;
|
|
416
|
+
let a = angle % TWO_PI;
|
|
417
|
+
if (a < 0) a += TWO_PI;
|
|
418
|
+
return a;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* Apply extracted 6DOF pose to the VIB3 engine parameters.
|
|
423
|
+
* @param {SixDOFPose} pose
|
|
424
|
+
* @private
|
|
425
|
+
*/
|
|
426
|
+
_applyPoseToEngine(pose) {
|
|
427
|
+
if (!this.engine || typeof this.engine.setParameter !== 'function') {
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
this.engine.setParameter('rot4dXY', pose.rotXY);
|
|
432
|
+
this.engine.setParameter('rot4dXZ', pose.rotXZ);
|
|
433
|
+
this.engine.setParameter('rot4dYZ', pose.rotYZ);
|
|
434
|
+
this.engine.setParameter('rot4dXW', pose.rotXW);
|
|
435
|
+
this.engine.setParameter('rot4dYW', pose.rotYW);
|
|
436
|
+
this.engine.setParameter('rot4dZW', pose.rotZW);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// -----------------------------------------------------------------------
|
|
440
|
+
// Input Sources (Controllers / Hands)
|
|
441
|
+
// -----------------------------------------------------------------------
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* Handle XR input source changes.
|
|
445
|
+
* @param {XRInputSourcesChangeEvent} event
|
|
446
|
+
* @private
|
|
447
|
+
*/
|
|
448
|
+
_onInputSourcesChange(event) {
|
|
449
|
+
for (const source of event.added) {
|
|
450
|
+
this._inputSources.set(source.handedness || 'none', source);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
for (const source of event.removed) {
|
|
454
|
+
this._inputSources.delete(source.handedness || 'none');
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* Process input sources each frame for controller data.
|
|
460
|
+
* Maps controller axes/buttons to VIB3 parameters.
|
|
461
|
+
*
|
|
462
|
+
* @param {XRFrame} frame
|
|
463
|
+
* @private
|
|
464
|
+
*/
|
|
465
|
+
_processInputSources(frame) {
|
|
466
|
+
if (!this.engine || typeof this.engine.setParameter !== 'function') {
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
for (const [hand, source] of this._inputSources) {
|
|
471
|
+
if (!source.gamepad) continue;
|
|
472
|
+
|
|
473
|
+
const gp = source.gamepad;
|
|
474
|
+
|
|
475
|
+
// Map thumbstick axes to additional parameters
|
|
476
|
+
if (gp.axes.length >= 2) {
|
|
477
|
+
if (hand === 'left') {
|
|
478
|
+
// Left stick: morph and chaos
|
|
479
|
+
const morphValue = (gp.axes[0] + 1.0) * 1.0; // 0..2
|
|
480
|
+
const chaosValue = (gp.axes[1] + 1.0) * 0.5; // 0..1
|
|
481
|
+
this.engine.setParameter('morphFactor', morphValue);
|
|
482
|
+
this.engine.setParameter('chaos', chaosValue);
|
|
483
|
+
} else if (hand === 'right') {
|
|
484
|
+
// Right stick: gridDensity and speed
|
|
485
|
+
const densityValue = 4.0 + (gp.axes[0] + 1.0) * 48.0; // 4..100
|
|
486
|
+
const speedValue = 0.1 + (gp.axes[1] + 1.0) * 1.45; // 0.1..3
|
|
487
|
+
this.engine.setParameter('gridDensity', densityValue);
|
|
488
|
+
this.engine.setParameter('speed', speedValue);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// Map trigger to intensity
|
|
493
|
+
if (gp.buttons.length > 0 && gp.buttons[0]) {
|
|
494
|
+
const triggerVal = gp.buttons[0].value; // 0..1
|
|
495
|
+
if (hand === 'right') {
|
|
496
|
+
this.engine.setParameter('intensity', triggerVal);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
// Map grip to dimension
|
|
501
|
+
if (gp.buttons.length > 1 && gp.buttons[1]) {
|
|
502
|
+
const gripVal = gp.buttons[1].value;
|
|
503
|
+
if (hand === 'left') {
|
|
504
|
+
const dimValue = 3.0 + gripVal * 1.5; // 3.0..4.5
|
|
505
|
+
this.engine.setParameter('dimension', dimValue);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
// A/B or X/Y buttons for geometry cycling
|
|
510
|
+
if (gp.buttons.length > 4 && gp.buttons[4] && gp.buttons[4].pressed) {
|
|
511
|
+
if (this.engine.getParameter) {
|
|
512
|
+
const currentGeom = this.engine.getParameter('geometry') || 0;
|
|
513
|
+
const nextGeom = (currentGeom + 1) % 24;
|
|
514
|
+
this.engine.setParameter('geometry', nextGeom);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// -----------------------------------------------------------------------
|
|
521
|
+
// GL Context & Fallback
|
|
522
|
+
// -----------------------------------------------------------------------
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Create a WebGL rendering context compatible with WebXR.
|
|
526
|
+
* @returns {WebGLRenderingContext}
|
|
527
|
+
* @private
|
|
528
|
+
*/
|
|
529
|
+
_createXRGLContext() {
|
|
530
|
+
const canvas = document.createElement('canvas');
|
|
531
|
+
const gl = canvas.getContext('webgl2', { xrCompatible: true })
|
|
532
|
+
|| canvas.getContext('webgl', { xrCompatible: true });
|
|
533
|
+
|
|
534
|
+
if (!gl) {
|
|
535
|
+
throw new Error('Failed to create XR-compatible WebGL context.');
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
gl.enable(gl.DEPTH_TEST);
|
|
539
|
+
gl.enable(gl.BLEND);
|
|
540
|
+
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
|
541
|
+
|
|
542
|
+
return gl;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Render a simple colored quad as a fallback when the VIB3 engine
|
|
547
|
+
* does not provide a renderFrame method.
|
|
548
|
+
*
|
|
549
|
+
* @param {WebGLRenderingContext} gl
|
|
550
|
+
* @param {Float32Array} projectionMatrix
|
|
551
|
+
* @param {Float32Array} viewMatrix
|
|
552
|
+
* @private
|
|
553
|
+
*/
|
|
554
|
+
_renderFallbackQuad(gl, projectionMatrix, viewMatrix) {
|
|
555
|
+
// Simple pass-through vertex shader
|
|
556
|
+
const vsSource = `
|
|
557
|
+
attribute vec4 a_position;
|
|
558
|
+
void main() {
|
|
559
|
+
gl_Position = a_position;
|
|
560
|
+
}
|
|
561
|
+
`;
|
|
562
|
+
|
|
563
|
+
// Animated color fragment shader
|
|
564
|
+
const fsSource = `
|
|
565
|
+
precision mediump float;
|
|
566
|
+
void main() {
|
|
567
|
+
gl_FragColor = vec4(0.2, 0.6, 1.0, 1.0);
|
|
568
|
+
}
|
|
569
|
+
`;
|
|
570
|
+
|
|
571
|
+
if (!this._fallbackProgram) {
|
|
572
|
+
const vs = this._compileShader(gl, gl.VERTEX_SHADER, vsSource);
|
|
573
|
+
const fs = this._compileShader(gl, gl.FRAGMENT_SHADER, fsSource);
|
|
574
|
+
if (!vs || !fs) return;
|
|
575
|
+
|
|
576
|
+
const program = gl.createProgram();
|
|
577
|
+
gl.attachShader(program, vs);
|
|
578
|
+
gl.attachShader(program, fs);
|
|
579
|
+
gl.linkProgram(program);
|
|
580
|
+
|
|
581
|
+
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
this._fallbackProgram = program;
|
|
586
|
+
|
|
587
|
+
// Full-screen triangle pair
|
|
588
|
+
const verts = new Float32Array([
|
|
589
|
+
-1, -1, 0, 1,
|
|
590
|
+
1, -1, 0, 1,
|
|
591
|
+
-1, 1, 0, 1,
|
|
592
|
+
1, 1, 0, 1
|
|
593
|
+
]);
|
|
594
|
+
|
|
595
|
+
this._fallbackVBO = gl.createBuffer();
|
|
596
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, this._fallbackVBO);
|
|
597
|
+
gl.bufferData(gl.ARRAY_BUFFER, verts, gl.STATIC_DRAW);
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
gl.useProgram(this._fallbackProgram);
|
|
601
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, this._fallbackVBO);
|
|
602
|
+
|
|
603
|
+
const posLoc = gl.getAttribLocation(this._fallbackProgram, 'a_position');
|
|
604
|
+
gl.enableVertexAttribArray(posLoc);
|
|
605
|
+
gl.vertexAttribPointer(posLoc, 4, gl.FLOAT, false, 0, 0);
|
|
606
|
+
|
|
607
|
+
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
/**
|
|
611
|
+
* Compile a GLSL shader.
|
|
612
|
+
* @param {WebGLRenderingContext} gl
|
|
613
|
+
* @param {number} type
|
|
614
|
+
* @param {string} source
|
|
615
|
+
* @returns {WebGLShader|null}
|
|
616
|
+
* @private
|
|
617
|
+
*/
|
|
618
|
+
_compileShader(gl, type, source) {
|
|
619
|
+
const shader = gl.createShader(type);
|
|
620
|
+
gl.shaderSource(shader, source);
|
|
621
|
+
gl.compileShader(shader);
|
|
622
|
+
|
|
623
|
+
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
|
624
|
+
gl.deleteShader(shader);
|
|
625
|
+
return null;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
return shader;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
// -----------------------------------------------------------------------
|
|
632
|
+
// Session End & Cleanup
|
|
633
|
+
// -----------------------------------------------------------------------
|
|
634
|
+
|
|
635
|
+
/**
|
|
636
|
+
* Internal handler for session termination.
|
|
637
|
+
* @private
|
|
638
|
+
*/
|
|
639
|
+
_onSessionEnd() {
|
|
640
|
+
this.xrSession = null;
|
|
641
|
+
this.xrRefSpace = null;
|
|
642
|
+
this.xrGLLayer = null;
|
|
643
|
+
this.isImmersive = false;
|
|
644
|
+
this._inputSources.clear();
|
|
645
|
+
this._lastPose = null;
|
|
646
|
+
this._animFrameHandle = 0;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
/**
|
|
650
|
+
* Dispose of all resources. After calling, this instance should not be reused.
|
|
651
|
+
*/
|
|
652
|
+
dispose() {
|
|
653
|
+
this._disposed = true;
|
|
654
|
+
|
|
655
|
+
if (this.xrSession) {
|
|
656
|
+
try {
|
|
657
|
+
this.xrSession.end();
|
|
658
|
+
} catch (_e) {
|
|
659
|
+
// Ignore
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
this._onSessionEnd();
|
|
664
|
+
|
|
665
|
+
if (this.gl) {
|
|
666
|
+
if (this._fallbackProgram) {
|
|
667
|
+
this.gl.deleteProgram(this._fallbackProgram);
|
|
668
|
+
this._fallbackProgram = null;
|
|
669
|
+
}
|
|
670
|
+
if (this._fallbackVBO) {
|
|
671
|
+
this.gl.deleteBuffer(this._fallbackVBO);
|
|
672
|
+
this._fallbackVBO = null;
|
|
673
|
+
}
|
|
674
|
+
this.gl = null;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
this.engine = null;
|
|
678
|
+
this._onFrameCallback = null;
|
|
679
|
+
}
|
|
680
|
+
}
|