|
@@ -1,5 +1,6 @@
|
|
import { WebXRSessionManager } from "./webXRSessionManager";
|
|
import { WebXRSessionManager } from "./webXRSessionManager";
|
|
import { IDisposable } from "../scene";
|
|
import { IDisposable } from "../scene";
|
|
|
|
+import { Tools } from "../Misc/tools";
|
|
|
|
|
|
/**
|
|
/**
|
|
* Defining the interface required for a (webxr) feature
|
|
* Defining the interface required for a (webxr) feature
|
|
@@ -29,6 +30,19 @@ export interface IWebXRFeature extends IDisposable {
|
|
* @returns true if successful.
|
|
* @returns true if successful.
|
|
*/
|
|
*/
|
|
detach(): boolean;
|
|
detach(): boolean;
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * This function will be executed during before enabling the feature and can be used to not-allow enabling it.
|
|
|
|
+ * Note that at this point the session has NOT started, so this is purely checking if the browser supports it
|
|
|
|
+ *
|
|
|
|
+ * @returns whether or not the feature is compatible in this environment
|
|
|
|
+ */
|
|
|
|
+ isCompatible(): boolean;
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * The name of the native xr feature name, if applicable (like anchor, hit-test, or hand-tracking)
|
|
|
|
+ */
|
|
|
|
+ xrNativeFeatureName?: string;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -90,6 +104,7 @@ export class WebXRFeaturesManager implements IDisposable {
|
|
featureImplementation: IWebXRFeature;
|
|
featureImplementation: IWebXRFeature;
|
|
version: number;
|
|
version: number;
|
|
enabled: boolean;
|
|
enabled: boolean;
|
|
|
|
+ required: boolean;
|
|
};
|
|
};
|
|
} = {};
|
|
} = {};
|
|
|
|
|
|
@@ -255,9 +270,10 @@ export class WebXRFeaturesManager implements IDisposable {
|
|
* @param version optional version to load. if not provided the latest version will be enabled
|
|
* @param version optional version to load. if not provided the latest version will be enabled
|
|
* @param moduleOptions options provided to the module. Ses the module documentation / constructor
|
|
* @param moduleOptions options provided to the module. Ses the module documentation / constructor
|
|
* @param attachIfPossible if set to true (default) the feature will be automatically attached, if it is currently possible
|
|
* @param attachIfPossible if set to true (default) the feature will be automatically attached, if it is currently possible
|
|
|
|
+ * @param required is this feature required to the app. If set to true the session init will fail if the feature is not available.
|
|
* @returns a new constructed feature or throws an error if feature not found.
|
|
* @returns a new constructed feature or throws an error if feature not found.
|
|
*/
|
|
*/
|
|
- public enableFeature(featureName: string | { Name: string }, version: number | string = "latest", moduleOptions: any = {}, attachIfPossible: boolean = true): IWebXRFeature {
|
|
|
|
|
|
+ public enableFeature(featureName: string | { Name: string }, version: number | string = "latest", moduleOptions: any = {}, attachIfPossible: boolean = true, required: boolean = true): IWebXRFeature {
|
|
const name = typeof featureName === "string" ? featureName : featureName.Name;
|
|
const name = typeof featureName === "string" ? featureName : featureName.Name;
|
|
let versionToLoad = 0;
|
|
let versionToLoad = 0;
|
|
if (typeof version === "string") {
|
|
if (typeof version === "string") {
|
|
@@ -291,24 +307,35 @@ export class WebXRFeaturesManager implements IDisposable {
|
|
this.disableFeature(name);
|
|
this.disableFeature(name);
|
|
}
|
|
}
|
|
|
|
|
|
- this._features[name] = {
|
|
|
|
- featureImplementation: constructFunction(),
|
|
|
|
- enabled: true,
|
|
|
|
- version: versionToLoad,
|
|
|
|
- };
|
|
|
|
|
|
+ const constructed = constructFunction();
|
|
|
|
+ if (constructed.isCompatible()) {
|
|
|
|
+ this._features[name] = {
|
|
|
|
+ featureImplementation: constructed,
|
|
|
|
+ enabled: true,
|
|
|
|
+ version: versionToLoad,
|
|
|
|
+ required,
|
|
|
|
+ };
|
|
|
|
|
|
- if (attachIfPossible) {
|
|
|
|
- // if session started already, request and enable
|
|
|
|
- if (this._xrSessionManager.session && !feature.featureImplementation.attached) {
|
|
|
|
- // enable feature
|
|
|
|
- this.attachFeature(name);
|
|
|
|
|
|
+ if (attachIfPossible) {
|
|
|
|
+ // if session started already, request and enable
|
|
|
|
+ if (this._xrSessionManager.session && !feature.featureImplementation.attached) {
|
|
|
|
+ // enable feature
|
|
|
|
+ this.attachFeature(name);
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ // disable auto-attach when session starts
|
|
|
|
+ this._features[name].featureImplementation.disableAutoAttach = true;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ return this._features[name].featureImplementation;
|
|
} else {
|
|
} else {
|
|
- // disable auto-attach when session starts
|
|
|
|
- this._features[name].featureImplementation.disableAutoAttach = true;
|
|
|
|
|
|
+ if (required) {
|
|
|
|
+ throw new Error("required feature not compatible");
|
|
|
|
+ } else {
|
|
|
|
+ Tools.Warn(`Feature ${name} not compatible with the current environment/browser and was not enabled.`);
|
|
|
|
+ return constructed;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
-
|
|
|
|
- return this._features[name].featureImplementation;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -327,4 +354,34 @@ export class WebXRFeaturesManager implements IDisposable {
|
|
public getEnabledFeatures() {
|
|
public getEnabledFeatures() {
|
|
return Object.keys(this._features);
|
|
return Object.keys(this._features);
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * This function will exten the session creation configuration object with enabled features.
|
|
|
|
+ * If, for example, the anchors feature is enabled, it will be automatically added to the optional or required features list,
|
|
|
|
+ * according to the defined "required" variable, provided during enableFeature call
|
|
|
|
+ * @param xrSessionInit the xr Session init object to extend
|
|
|
|
+ *
|
|
|
|
+ * @returns an extended XRSessionInit object
|
|
|
|
+ */
|
|
|
|
+ public extendXRSessionInitObject(xrSessionInit: XRSessionInit): XRSessionInit {
|
|
|
|
+ const enabledFeatures = this.getEnabledFeatures();
|
|
|
|
+ enabledFeatures.forEach((featureName) => {
|
|
|
|
+ const feature = this._features[featureName];
|
|
|
|
+ const nativeName = feature.featureImplementation.xrNativeFeatureName;
|
|
|
|
+ if (nativeName) {
|
|
|
|
+ if (feature.required) {
|
|
|
|
+ xrSessionInit.requiredFeatures = xrSessionInit.requiredFeatures || [];
|
|
|
|
+ if (xrSessionInit.requiredFeatures.indexOf(nativeName) === -1) {
|
|
|
|
+ xrSessionInit.requiredFeatures.push(nativeName);
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ xrSessionInit.optionalFeatures = xrSessionInit.optionalFeatures || [];
|
|
|
|
+ if (xrSessionInit.optionalFeatures.indexOf(nativeName) === -1) {
|
|
|
|
+ xrSessionInit.optionalFeatures.push(nativeName);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ return xrSessionInit;
|
|
|
|
+ }
|
|
}
|
|
}
|