فهرست منبع

Adding the new webxr features manager

Raanan Weber 5 سال پیش
والد
کامیت
db4216dd99
2فایلهای تغییر یافته به همراه137 افزوده شده و 0 حذف شده
  1. 4 0
      src/Cameras/XR/webXRExperienceHelper.ts
  2. 133 0
      src/Cameras/XR/webXRFeaturesManager.ts

+ 4 - 0
src/Cameras/XR/webXRExperienceHelper.ts

@@ -7,6 +7,7 @@ import { Camera } from "../../Cameras/camera";
 import { WebXRSessionManager } from "./webXRSessionManager";
 import { WebXRCamera } from "./webXRCamera";
 import { WebXRState, WebXRRenderTarget } from './webXRTypes';
+import { WebXRFeaturesManager } from './webXRFeaturesManager';
 
 /**
  * Base set of functionality needed to create an XR experince (WebXRSessionManager, Camera, StateManagement, etc.)
@@ -42,6 +43,8 @@ export class WebXRExperienceHelper implements IDisposable {
     /** Session manager used to keep track of xr session */
     public sessionManager: WebXRSessionManager;
 
+    public featuresManager: WebXRFeaturesManager;
+
     private _nonVRCamera: Nullable<Camera> = null;
     private _originalSceneAutoClear = true;
 
@@ -69,6 +72,7 @@ export class WebXRExperienceHelper implements IDisposable {
     private constructor(private scene: Scene) {
         this.camera = new WebXRCamera("", scene);
         this.sessionManager = new WebXRSessionManager(scene);
+        this.featuresManager = new WebXRFeaturesManager(this.sessionManager);
         this.container = new AbstractMesh("WebXR Container", scene);
         this.camera.parent = this.container;
 

+ 133 - 0
src/Cameras/XR/webXRFeaturesManager.ts

@@ -0,0 +1,133 @@
+import { WebXRSessionManager } from './webXRSessionManager';
+import { IDisposable } from '../../scene';
+import { Observable } from '../../Misc/observable';
+
+export interface WebXRFeature extends IDisposable {
+    readonly name: string;
+    attachAsync(): Promise<boolean>;
+    detachAsync(): Promise<boolean>;
+}
+
+export type WebXRFeatureConstructor = (xrSessionManager: WebXRSessionManager, options?: any) => (() => WebXRFeature);
+
+export class WebXRFeaturesManager implements IDisposable {
+
+    private static readonly _AvailableFeatures: { [name: string]: WebXRFeatureConstructor } = {};
+
+    public static AddWebXRFeature(featureName: string, constructorFunction: WebXRFeatureConstructor) {
+        this._AvailableFeatures[featureName] = constructorFunction;
+    }
+
+    public static ConstructFeature(featureName: string, xrSessionManager: WebXRSessionManager, options?: any) {
+        const constructorFunction = this._AvailableFeatures[featureName];
+        if (!constructorFunction) {
+            // throw an error? return nothing?
+            return;
+        }
+
+        return constructorFunction(xrSessionManager, options);
+    }
+
+    public static GetAvailableFeatures() {
+        return Object.keys(this._AvailableFeatures);
+    }
+
+    private features: {
+        [name: string]: {
+            featureImplementation: WebXRFeature,
+            enabled: boolean,
+            attached: boolean
+        }
+    } = {};
+
+    public onFeatureAttachedObservable: Observable<WebXRFeature> = new Observable();
+    public onFeatureDetachedObservable: Observable<WebXRFeature> = new Observable();
+
+    constructor(private xrSessionManager: WebXRSessionManager) {
+        this.xrSessionManager.onXRSessionInit.add(() => {
+            this.getEnabledFeatures().forEach((featureName) => {
+                const feature = this.features[featureName];
+                if (feature.enabled && !feature.attached) {
+                    this.attachFeature(featureName);
+                }
+            });
+        });
+
+        this.xrSessionManager.onXRSessionEnded.add(() => {
+            this.getEnabledFeatures().forEach((featureName) => {
+                const feature = this.features[featureName];
+                if (feature.enabled && feature.attached) {
+                    // detach, but don't disable!
+                    this.detachFeature(featureName);
+                }
+            });
+        });
+    }
+
+    public enableFeature(featureName: string, options: any = {}, attachIfPossible: boolean = true): WebXRFeature {
+        const feature = this.features[featureName];
+        if (!feature || !feature.featureImplementation) {
+            const constructFunction = WebXRFeaturesManager.ConstructFeature(featureName, this.xrSessionManager, options);
+            if (!constructFunction) {
+                // report error?
+                throw new Error(`feature not found - ${featureName}`);
+            }
+
+            this.features[featureName] = {
+                featureImplementation: constructFunction(),
+                attached: false,
+                enabled: true
+            };
+        } else {
+            // make sure it is enabled now:
+            feature.enabled = true;
+        }
+
+        // if session started already, request and enable
+        if (this.xrSessionManager.session && !feature.attached && attachIfPossible) {
+            // enable feature
+            this.attachFeature(featureName);
+        }
+
+        return this.features[featureName].featureImplementation;
+    }
+
+    public disableFeature(featureName: string) {
+        const feature = this.features[featureName];
+        if (feature && feature.enabled) {
+            feature.enabled = false;
+            this.detachFeature(featureName);
+        }
+    }
+
+    public attachFeature(featureName: string) {
+        const feature = this.features[featureName];
+        if (feature && feature.enabled && !feature.attached) {
+            feature.featureImplementation.attachAsync().then(() => {
+                this.onFeatureAttachedObservable.notifyObservers(feature.featureImplementation);
+            });
+        }
+    }
+
+    public detachFeature(featureName: string) {
+        const feature = this.features[featureName];
+        if (feature && !feature.attached) {
+            feature.featureImplementation.detachAsync().then(() => {
+                this.onFeatureDetachedObservable.notifyObservers(feature.featureImplementation);
+            });
+        }
+    }
+
+    public getEnabledFeatures() {
+        return Object.keys(this.features);
+    }
+
+    public getEnabledFeature(featureName: string) {
+        return this.features[featureName] && this.features[featureName].featureImplementation;
+    }
+
+    dispose(): void {
+        this.getEnabledFeatures().forEach((feature) => this.features[feature].featureImplementation.dispose());
+    }
+
+}