WebXRAbstractFeature.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. import { Observable } from "../../Misc/observable.js";
  2. import { Logger } from "../../Misc/logger.js";
  3. /**
  4. * This is the base class for all WebXR features.
  5. * Since most features require almost the same resources and callbacks, this class can be used to simplify the development
  6. * Note that since the features manager is using the `IWebXRFeature` you are in no way obligated to use this class
  7. */
  8. export class WebXRAbstractFeature {
  9. /**
  10. * The name of the native xr feature name (like anchor, hit-test, or hand-tracking)
  11. */
  12. get xrNativeFeatureName() {
  13. return this._xrNativeFeatureName;
  14. }
  15. set xrNativeFeatureName(name) {
  16. // check if feature was initialized while in session but needs to be initialized before the session starts
  17. if (!this._xrSessionManager.isNative && name && this._xrSessionManager.inXRSession && this._xrSessionManager.enabledFeatures?.indexOf(name) === -1) {
  18. Logger.Warn(`The feature ${name} needs to be enabled before starting the XR session. Note - It is still possible it is not supported.`);
  19. }
  20. this._xrNativeFeatureName = name;
  21. }
  22. /**
  23. * Construct a new (abstract) WebXR feature
  24. * @param _xrSessionManager the xr session manager for this feature
  25. */
  26. constructor(_xrSessionManager) {
  27. this._xrSessionManager = _xrSessionManager;
  28. this._attached = false;
  29. this._removeOnDetach = [];
  30. /**
  31. * Is this feature disposed?
  32. */
  33. this.isDisposed = false;
  34. /**
  35. * Should auto-attach be disabled?
  36. */
  37. this.disableAutoAttach = false;
  38. this._xrNativeFeatureName = "";
  39. /**
  40. * Observers registered here will be executed when the feature is attached
  41. */
  42. this.onFeatureAttachObservable = new Observable();
  43. /**
  44. * Observers registered here will be executed when the feature is detached
  45. */
  46. this.onFeatureDetachObservable = new Observable();
  47. }
  48. /**
  49. * Is this feature attached
  50. */
  51. get attached() {
  52. return this._attached;
  53. }
  54. /**
  55. * attach this feature
  56. *
  57. * @param force should attachment be forced (even when already attached)
  58. * @returns true if successful, false is failed or already attached
  59. */
  60. attach(force) {
  61. // do not attach a disposed feature
  62. if (this.isDisposed) {
  63. return false;
  64. }
  65. if (!force) {
  66. if (this.attached) {
  67. return false;
  68. }
  69. }
  70. else {
  71. if (this.attached) {
  72. // detach first, to be sure
  73. this.detach();
  74. }
  75. }
  76. // if this is a native WebXR feature, check if it is enabled on the session
  77. // For now only check if not using babylon native
  78. // vision OS doesn't support the enabledFeatures array, so just warn instead of failing
  79. if (!this._xrSessionManager.enabledFeatures) {
  80. Logger.Warn("session.enabledFeatures is not available on this device. It is possible that this feature is not supported.");
  81. }
  82. else if (!this._xrSessionManager.isNative && this.xrNativeFeatureName && this._xrSessionManager.enabledFeatures.indexOf(this.xrNativeFeatureName) === -1) {
  83. return false;
  84. }
  85. this._attached = true;
  86. this._addNewAttachObserver(this._xrSessionManager.onXRFrameObservable, (frame) => this._onXRFrame(frame));
  87. this.onFeatureAttachObservable.notifyObservers(this);
  88. return true;
  89. }
  90. /**
  91. * detach this feature.
  92. *
  93. * @returns true if successful, false if failed or already detached
  94. */
  95. detach() {
  96. if (!this._attached) {
  97. this.disableAutoAttach = true;
  98. return false;
  99. }
  100. this._attached = false;
  101. this._removeOnDetach.forEach((toRemove) => {
  102. toRemove.observable.remove(toRemove.observer);
  103. });
  104. this.onFeatureDetachObservable.notifyObservers(this);
  105. return true;
  106. }
  107. /**
  108. * Dispose this feature and all of the resources attached
  109. */
  110. dispose() {
  111. this.detach();
  112. this.isDisposed = true;
  113. this.onFeatureAttachObservable.clear();
  114. this.onFeatureDetachObservable.clear();
  115. }
  116. /**
  117. * This function will be executed during before enabling the feature and can be used to not-allow enabling it.
  118. * Note that at this point the session has NOT started, so this is purely checking if the browser supports it
  119. *
  120. * @returns whether or not the feature is compatible in this environment
  121. */
  122. isCompatible() {
  123. return true;
  124. }
  125. /**
  126. * This is used to register callbacks that will automatically be removed when detach is called.
  127. * @param observable the observable to which the observer will be attached
  128. * @param callback the callback to register
  129. * @param insertFirst should the callback be executed as soon as it is registered
  130. */
  131. _addNewAttachObserver(observable, callback, insertFirst) {
  132. this._removeOnDetach.push({
  133. observable,
  134. observer: observable.add(callback, undefined, insertFirst),
  135. });
  136. }
  137. }
  138. //# sourceMappingURL=WebXRAbstractFeature.js.map