WebXRAbstractFeature.ts 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. import { IWebXRFeature } from '../webXRFeaturesManager';
  2. import { Observer, Observable, EventState } from '../../Misc/observable';
  3. import { Nullable } from '../../types';
  4. import { WebXRSessionManager } from '../webXRSessionManager';
  5. /**
  6. * This is the base class for all WebXR features.
  7. * Since most features require almost the same resources and callbacks, this class can be used to simplify the development
  8. * Note that since the features manager is using the `IWebXRFeature` you are in no way obligated to use this class
  9. */
  10. export abstract class WebXRAbstractFeature implements IWebXRFeature {
  11. /**
  12. * Construct a new (abstract) webxr feature
  13. * @param _xrSessionManager the xr session manager for this feature
  14. */
  15. constructor(protected _xrSessionManager: WebXRSessionManager) {
  16. }
  17. private _attached: boolean = false;
  18. private _removeOnDetach: {
  19. observer: Nullable<Observer<any>>;
  20. observable: Observable<any>;
  21. }[] = [];
  22. /**
  23. * Is this feature attached
  24. */
  25. public get attached() {
  26. return this._attached;
  27. }
  28. /**
  29. * Should auto-attach be disabled?
  30. */
  31. public disableAutoAttach: boolean = false;
  32. /**
  33. * attach this feature
  34. *
  35. * @param force should attachment be forced (even when already attached)
  36. * @returns true if successful, false is failed or already attached
  37. */
  38. public attach(force?: boolean): boolean {
  39. if (!force) {
  40. if (this.attached) {
  41. return false;
  42. }
  43. } else {
  44. if (this.attached) {
  45. // detach first, to be sure
  46. this.detach();
  47. }
  48. }
  49. this._attached = true;
  50. this._addNewAttachObserver(this._xrSessionManager.onXRFrameObservable, (frame) => this._onXRFrame(frame));
  51. return true;
  52. }
  53. /**
  54. * detach this feature.
  55. *
  56. * @returns true if successful, false if failed or already detached
  57. */
  58. public detach(): boolean {
  59. if (!this._attached) {
  60. this.disableAutoAttach = true;
  61. return false;
  62. }
  63. this._attached = false;
  64. this._removeOnDetach.forEach((toRemove) => {
  65. toRemove.observable.remove(toRemove.observer);
  66. });
  67. return true;
  68. }
  69. /**
  70. * Dispose this feature and all of the resources attached
  71. */
  72. public dispose(): void {
  73. this.detach();
  74. }
  75. /**
  76. * Code in this function will be executed on each xrFrame received from the browser.
  77. * This function will not execute after the feature is detached.
  78. * @param _xrFrame the current frame
  79. */
  80. protected abstract _onXRFrame(_xrFrame: XRFrame): void;
  81. /**
  82. * This is used to register callbacks that will automatically be removed when detach is called.
  83. * @param observable the observable to which the observer will be attached
  84. * @param callback the callback to register
  85. */
  86. protected _addNewAttachObserver<T>(observable: Observable<T>, callback: (eventData: T, eventState: EventState) => void) {
  87. this._removeOnDetach.push({
  88. observable,
  89. observer: observable.add(callback)
  90. });
  91. }
  92. }