Skip to content

Commit

Permalink
XR editor adaptation (#2165)
Browse files Browse the repository at this point in the history
* feat: xr support editor
  • Loading branch information
cptbtptpbcptdtptp authored Jul 19, 2024
1 parent f0655f9 commit 2439762
Show file tree
Hide file tree
Showing 15 changed files with 151 additions and 137 deletions.
11 changes: 11 additions & 0 deletions packages/core/src/utils/SafeLoopArray.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,17 @@ export class SafeLoopArray<T> {
this._loopArrayDirty = true;
}

/**
* Remove item from array that pass the specified comparison function.
* @param filter - The comparison function
*/
findAndRemove(filter: (value: T) => boolean): void {
const array = this._array;
for (let i = array.length - 1; i >= 0; i--) {
filter(array[i]) && this.removeByIndex(i);
}
}

/**
* The index of the item.
* @param item - The item which want to get the index
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { ClearableObjectPool } from "./ClearableObjectPool";
export type { IPoolElement } from "./ObjectPool";
export { ReturnableObjectPool } from "./ReturnableObjectPool";
export { SafeLoopArray } from "./SafeLoopArray";
13 changes: 2 additions & 11 deletions packages/loader/src/PrefabLoader.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,7 @@
import {
AssetPromise,
AssetType,
Engine,
EngineConfiguration,
Loader,
LoadItem,
resourceLoader,
ResourceManager
} from "@galacean/engine-core";
import { AssetPromise, AssetType, Loader, LoadItem, resourceLoader, ResourceManager } from "@galacean/engine-core";
import { PrefabParser } from "./prefab/PrefabParser";
import { PrefabResource } from "./prefab/PrefabResource";
import { IHierarchyFile } from "./resource-deserialize";
import { PrefabParser } from "./prefab/PrefabParser";

@resourceLoader(AssetType.Prefab, ["prefab"])
export class PrefabLoader extends Loader<PrefabResource> {
Expand Down
1 change: 0 additions & 1 deletion packages/loader/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,3 @@ export { KTX2Loader, KTX2Transcoder } from "./ktx2/KTX2Loader";
export { KTX2TargetFormat } from "./ktx2/KTX2TargetFormat";
export * from "./resource-deserialize";
export * from "./prefab/PrefabResource";
export { PrefabLoader } from "./PrefabLoader";
6 changes: 5 additions & 1 deletion packages/loader/src/resource-deserialize/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Engine } from "@galacean/engine-core";
import { BufferReader } from "./utils/BufferReader";
import { decoderMap, decoder } from "./utils/Decorator";
import { decoderMap } from "./utils/Decorator";
import { FileHeader } from "./utils/FileHeader";

export { MeshDecoder } from "./resources/mesh/MeshDecoder";
Expand Down Expand Up @@ -29,3 +29,7 @@ export * from "./resources/scene/SceneParser";
export * from "./resources/scene/MeshLoader";
export * from "./resources/scene/EditorTextureLoader";
export * from "./resources/parser/ParserContext";

export * from "./utils/BufferReader";
export * from "./utils/Decorator";
export * from "./utils/FileHeader";
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Engine, ReferResource, Scene } from "@galacean/engine-core";
import { Engine, Scene } from "@galacean/engine-core";
import type { IScene } from "../schema";
import { HierarchyParser } from "../parser/HierarchyParser";
import { ParserContext, ParserType } from "../parser/ParserContext";
Expand Down
11 changes: 10 additions & 1 deletion packages/xr-webxr/src/WebXRDevice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,16 @@ export class WebXRDevice implements IXRDevice {
}

isSupportedFeature(type: XRFeatureType): boolean {
return true;
switch (type) {
case XRFeatureType.HitTest:
case XRFeatureType.PlaneTracking:
return typeof XRPlane !== "undefined";
case XRFeatureType.AnchorTracking:
return typeof XRAnchor !== "undefined";
case XRFeatureType.ImageTracking:
// @ts-ignore
return typeof XRImageTrackingResult !== "undefined";
}
}

createPlatformFeature(type: XRFeatureType, ...args: any[]): WebXRFeature {
Expand Down
2 changes: 1 addition & 1 deletion packages/xr-webxr/src/WebXRSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ export class WebXRSession implements IXRSession {
session.removeEventListener("squeeze", onSessionEvent);
session.removeEventListener("squeezestart", onSessionEvent);
session.removeEventListener("squeezeend", onSessionEvent);
session.addEventListener("end", this._onSessionExit);
session.removeEventListener("end", this._onSessionExit);
this._events.length = 0;
}

Expand Down
122 changes: 26 additions & 96 deletions packages/xr/src/XRManagerExtended.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,22 @@ import { XRSessionManager } from "./session/XRSessionManager";
import { XRSessionMode } from "./session/XRSessionMode";
import { XRSessionState } from "./session/XRSessionState";
/**
* XRManager is the entry point of the XR system.
* @internal
*/
export class XRManagerExtended extends XRManager {
/** @internal */
static _featureMap: Map<TFeatureConstructor<XRFeature>, XRFeatureType> = new Map();

/** Input manager for XR. */
override inputManager: XRInputManager;
/** Session manager for XR. */
override sessionManager: XRSessionManager;
/** Camera manager for XR. */
override cameraManager: XRCameraManager;
override readonly features: XRFeature[] = [];

/** @internal */
_platformDevice: IXRDevice;

private _origin: Entity;
private _features: XRFeature[];

/**
* The current origin of XR space.
* @remarks The connection point between the virtual world and the real world ( XR Space )
*/
override get origin(): Entity {
return this._origin;
}
Expand All @@ -42,45 +35,31 @@ export class XRManagerExtended extends XRManager {
this._origin = value;
}

/**
* Check if the specified feature is supported.
* @param type - The type of the feature
* @returns If the feature is supported
*/
override isSupportedFeature<T extends XRFeature>(feature: TFeatureConstructor<T>): boolean {
return this._platformDevice.isSupportedFeature(XRManagerExtended._featureMap.get(feature));
}

/**
* Add feature based on the xr feature type.
* @param type - The type of the feature
* @param args - The constructor params of the feature
* @returns The feature which has been added
*/
override addFeature<T extends new (xrManager: XRManagerExtended, ...args: any[]) => XRFeature>(
type: T,
...args: TFeatureConstructorArguments<T>
): XRFeature | null {
): InstanceType<T> | null {
if (this.sessionManager._platformSession) {
throw new Error("Cannot add feature when the session is initialized.");
}
const { _features: features } = this;
if (!this._platformDevice.isSupportedFeature(XRManagerExtended._featureMap.get(type))) {
throw new Error("The feature is not supported");
}
const { features } = this;
for (let i = 0, n = features.length; i < n; i++) {
const feature = features[i];
if (feature instanceof type) throw new Error("The feature has been added");
if (features[i] instanceof type) throw new Error("The feature has been added");
}
const feature = new type(this, ...args);
this._features.push(feature);
const feature = new type(this, ...args) as InstanceType<T>;
features.push(feature);
return feature;
}

/**
* Get feature which match the type.
* @param type - The type of the feature
* @returns The feature which match type
*/
override getFeature<T extends XRFeature>(type: TFeatureConstructor<T>): T | null {
const { _features: features } = this;
const { features } = this;
for (let i = 0, n = features.length; i < n; i++) {
const feature = features[i];
if (feature instanceof type) {
Expand All @@ -89,26 +68,6 @@ export class XRManagerExtended extends XRManager {
}
}

override getFeatures<T extends XRFeature>(type: TFeatureConstructor<T>, out?: T[]): T[] {
if (out) {
out.length = 0;
} else {
out = [];
}
const { _features: features } = this;
for (let i = 0, n = features.length; i < n; i--) {
const feature = features[i];
feature instanceof type && out.push(feature);
}
return out;
}

/**
* Enter XR immersive mode, when you call this method, it will initialize and display the XR virtual world.
* @param sessionMode - The mode of the session
* @param autoRun - Whether to automatically run the session, when `autoRun` is set to true, xr will start working immediately after initialization. Otherwise, you need to call `sessionManager.run` later to work.
* @returns A promise that resolves if the XR virtual world is entered, otherwise rejects
*/
override enterXR(sessionMode: XRSessionMode, autoRun: boolean = true): Promise<void> {
const { sessionManager } = this;
if (sessionManager._platformSession) {
Expand All @@ -120,19 +79,16 @@ export class XRManagerExtended extends XRManager {
return new Promise((resolve, reject) => {
// 1. Check if this xr mode is supported
sessionManager.isSupportedMode(sessionMode).then(() => {
sessionManager._setState(XRSessionState.Initializing);
// 2. Initialize session
sessionManager._initialize(sessionMode, this._features).then(() => {
sessionManager._initialize(sessionMode, this.features).then(() => {
autoRun && sessionManager.run();
resolve();
}, reject);
}, reject);
});
}

/**
* Exit XR immersive mode, when you call this method, it will destroy the XR virtual world.
* @returns A promise that resolves if the XR virtual world is destroyed, otherwise rejects
*/
override exitXR(): Promise<void> {
return new Promise((resolve, reject) => {
this.sessionManager._exit().then(() => {
Expand All @@ -141,36 +97,26 @@ export class XRManagerExtended extends XRManager {
});
}

/**
* @internal
*/
override _initialize(engine: Engine, xrDevice: IXRDevice): void {
this._features = [];
this._platformDevice = xrDevice;
this.sessionManager = new XRSessionManager(this, engine);
this.inputManager = new XRInputManager(this, engine);
this.cameraManager = new XRCameraManager(this);
}

/**
* @internal
*/
override _update(): void {
const { sessionManager } = this;
if (sessionManager.state !== XRSessionState.Running) return;
sessionManager._onUpdate();
this.inputManager._onUpdate();
this.cameraManager._onUpdate();
const { _features: features } = this;
const { features } = this;
for (let i = 0, n = features.length; i < n; i++) {
const feature = features[i];
feature.enabled && feature._onUpdate();
}
}

/**
* @internal
*/
override _destroy(): void {
if (this.sessionManager._platformSession) {
this.exitXR().then(() => {
Expand All @@ -185,23 +131,14 @@ export class XRManagerExtended extends XRManager {
}
}

/**
* @internal
*/
override _getRequestAnimationFrame(): (callback: FrameRequestCallback) => number {
return this.sessionManager._getRequestAnimationFrame();
}

/**
* @internal
*/
override _getCancelAnimationFrame(): (id: number) => void {
return this.sessionManager._getCancelAnimationFrame();
}

/**
* @internal
*/
override _getCameraClearFlagsMask(type: CameraType): CameraClearFlags {
return this.cameraManager._getCameraClearFlagsMask(type);
}
Expand All @@ -210,7 +147,7 @@ export class XRManagerExtended extends XRManager {
* @internal
*/
_onSessionStop(): void {
const { _features: features } = this;
const { features } = this;
for (let i = 0, n = features.length; i < n; i++) {
const feature = features[i];
feature.enabled && feature._onSessionStop();
Expand All @@ -221,7 +158,7 @@ export class XRManagerExtended extends XRManager {
* @internal
*/
_onSessionInit(): void {
const { _features: features } = this;
const { features } = this;
for (let i = 0, n = features.length; i < n; i++) {
const feature = features[i];
feature.enabled && feature._onSessionInit();
Expand All @@ -233,7 +170,7 @@ export class XRManagerExtended extends XRManager {
*/
_onSessionStart(): void {
this.cameraManager._onSessionStart();
const { _features: features } = this;
const { features } = this;
for (let i = 0, n = features.length; i < n; i++) {
const feature = features[i];
feature.enabled && feature._onSessionStart();
Expand All @@ -245,7 +182,7 @@ export class XRManagerExtended extends XRManager {
*/
_onSessionExit(): void {
this.cameraManager._onSessionExit();
const { _features: features } = this;
const { features } = this;
for (let i = 0, n = features.length; i < n; i++) {
const feature = features[i];
feature.enabled && feature._onSessionExit();
Expand All @@ -264,6 +201,11 @@ export function registerXRFeature<T extends XRFeature>(type: XRFeatureType): (fe
};
}

export interface IXRListener {
fn: (...args: any[]) => any;
destroyed?: boolean;
}

type TFeatureConstructor<T extends XRFeature> = new (xrManager: XRManagerExtended, ...args: any[]) => T;

type TFeatureConstructorArguments<T extends new (xrManager: XRManagerExtended, ...args: any[]) => XRFeature> =
Expand All @@ -277,6 +219,8 @@ declare module "@galacean/engine" {
sessionManager: XRSessionManager;
/** Camera manager for XR. */
cameraManager: XRCameraManager;
/** Initialized features. */
readonly features: XRFeature[];

/**
* The current origin of XR space.
Expand All @@ -285,19 +229,6 @@ declare module "@galacean/engine" {
get origin(): Entity;
set origin(value: Entity);

/**
* Get all initialized features at this moment.
* @param type - The type of the feature
*/
getFeatures<T extends XRFeature>(type: TFeatureConstructor<T>): T[];

/**
* Get all initialized features at this moment.
* @param type - The type of the feature
* @param out - Save all features in `out`
*/
getFeatures<T extends XRFeature>(type: TFeatureConstructor<T>, out: T[]): T[];

/**
* Check if the specified feature is supported.
* @param type - The type of the feature
Expand All @@ -314,15 +245,14 @@ declare module "@galacean/engine" {
addFeature<T extends new (xrManager: XRManagerExtended, ...args: any[]) => XRFeature>(
type: T,
...args: TFeatureConstructorArguments<T>
): XRFeature | null;
): InstanceType<T> | null;

/**
* Get feature which match the type.
* @param type - The type of the feature
* @returns The feature which match type
*/
getFeature<T extends XRFeature>(type: TFeatureConstructor<T>): T | null;
getFeatures<T extends XRFeature>(type: TFeatureConstructor<T>, out?: T[]): T[];
/**
* Enter XR immersive mode, when you call this method, it will initialize and display the XR virtual world.
* @param sessionMode - The mode of the session
Expand Down
Loading

0 comments on commit 2439762

Please sign in to comment.