engine.common.js 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. import { IsDocumentAvailable } from "../Misc/domManagement.js";
  2. import { AbstractEngine } from "./abstractEngine.js";
  3. import { EngineStore } from "./engineStore.js";
  4. /** @internal */
  5. function _DisableTouchAction(canvas) {
  6. if (!canvas || !canvas.setAttribute) {
  7. return;
  8. }
  9. canvas.setAttribute("touch-action", "none");
  10. canvas.style.touchAction = "none";
  11. canvas.style.webkitTapHighlightColor = "transparent";
  12. }
  13. /** @internal */
  14. export function _CommonInit(commonEngine, canvas, creationOptions) {
  15. commonEngine._onCanvasFocus = () => {
  16. commonEngine.onCanvasFocusObservable.notifyObservers(commonEngine);
  17. };
  18. commonEngine._onCanvasBlur = () => {
  19. commonEngine.onCanvasBlurObservable.notifyObservers(commonEngine);
  20. };
  21. commonEngine._onCanvasContextMenu = (evt) => {
  22. if (commonEngine.disableContextMenu) {
  23. evt.preventDefault();
  24. }
  25. };
  26. canvas.addEventListener("focus", commonEngine._onCanvasFocus);
  27. canvas.addEventListener("blur", commonEngine._onCanvasBlur);
  28. canvas.addEventListener("contextmenu", commonEngine._onCanvasContextMenu);
  29. commonEngine._onBlur = () => {
  30. if (commonEngine.disablePerformanceMonitorInBackground) {
  31. commonEngine.performanceMonitor.disable();
  32. }
  33. commonEngine._windowIsBackground = true;
  34. };
  35. commonEngine._onFocus = () => {
  36. if (commonEngine.disablePerformanceMonitorInBackground) {
  37. commonEngine.performanceMonitor.enable();
  38. }
  39. commonEngine._windowIsBackground = false;
  40. };
  41. commonEngine._onCanvasPointerOut = (ev) => {
  42. // Check that the element at the point of the pointer out isn't the canvas and if it isn't, notify observers
  43. // Note: This is a workaround for a bug with Safari
  44. if (document.elementFromPoint(ev.clientX, ev.clientY) !== canvas) {
  45. commonEngine.onCanvasPointerOutObservable.notifyObservers(ev);
  46. }
  47. };
  48. const hostWindow = commonEngine.getHostWindow(); // it calls IsWindowObjectExist()
  49. if (hostWindow && typeof hostWindow.addEventListener === "function") {
  50. hostWindow.addEventListener("blur", commonEngine._onBlur);
  51. hostWindow.addEventListener("focus", commonEngine._onFocus);
  52. }
  53. canvas.addEventListener("pointerout", commonEngine._onCanvasPointerOut);
  54. if (!creationOptions.doNotHandleTouchAction) {
  55. _DisableTouchAction(canvas);
  56. }
  57. // Create Audio Engine if needed.
  58. if (!AbstractEngine.audioEngine && creationOptions.audioEngine && AbstractEngine.AudioEngineFactory) {
  59. AbstractEngine.audioEngine = AbstractEngine.AudioEngineFactory(commonEngine.getRenderingCanvas(), commonEngine.getAudioContext(), commonEngine.getAudioDestination());
  60. }
  61. if (IsDocumentAvailable()) {
  62. // Fullscreen
  63. commonEngine._onFullscreenChange = () => {
  64. commonEngine.isFullscreen = !!document.fullscreenElement;
  65. // Pointer lock
  66. if (commonEngine.isFullscreen && commonEngine._pointerLockRequested && canvas) {
  67. RequestPointerlock(canvas);
  68. }
  69. };
  70. document.addEventListener("fullscreenchange", commonEngine._onFullscreenChange, false);
  71. document.addEventListener("webkitfullscreenchange", commonEngine._onFullscreenChange, false);
  72. // Pointer lock
  73. commonEngine._onPointerLockChange = () => {
  74. commonEngine.isPointerLock = document.pointerLockElement === canvas;
  75. };
  76. document.addEventListener("pointerlockchange", commonEngine._onPointerLockChange, false);
  77. document.addEventListener("webkitpointerlockchange", commonEngine._onPointerLockChange, false);
  78. }
  79. commonEngine.enableOfflineSupport = AbstractEngine.OfflineProviderFactory !== undefined;
  80. commonEngine._deterministicLockstep = !!creationOptions.deterministicLockstep;
  81. commonEngine._lockstepMaxSteps = creationOptions.lockstepMaxSteps || 0;
  82. commonEngine._timeStep = creationOptions.timeStep || 1 / 60;
  83. }
  84. /** @internal */
  85. export function _CommonDispose(commonEngine, canvas) {
  86. // Release audio engine
  87. if (EngineStore.Instances.length === 1 && AbstractEngine.audioEngine) {
  88. AbstractEngine.audioEngine.dispose();
  89. AbstractEngine.audioEngine = null;
  90. }
  91. // Events
  92. const hostWindow = commonEngine.getHostWindow(); // it calls IsWindowObjectExist()
  93. if (hostWindow && typeof hostWindow.removeEventListener === "function") {
  94. hostWindow.removeEventListener("blur", commonEngine._onBlur);
  95. hostWindow.removeEventListener("focus", commonEngine._onFocus);
  96. }
  97. if (canvas) {
  98. canvas.removeEventListener("focus", commonEngine._onCanvasFocus);
  99. canvas.removeEventListener("blur", commonEngine._onCanvasBlur);
  100. canvas.removeEventListener("pointerout", commonEngine._onCanvasPointerOut);
  101. canvas.removeEventListener("contextmenu", commonEngine._onCanvasContextMenu);
  102. }
  103. if (IsDocumentAvailable()) {
  104. document.removeEventListener("fullscreenchange", commonEngine._onFullscreenChange);
  105. document.removeEventListener("mozfullscreenchange", commonEngine._onFullscreenChange);
  106. document.removeEventListener("webkitfullscreenchange", commonEngine._onFullscreenChange);
  107. document.removeEventListener("msfullscreenchange", commonEngine._onFullscreenChange);
  108. document.removeEventListener("pointerlockchange", commonEngine._onPointerLockChange);
  109. document.removeEventListener("mspointerlockchange", commonEngine._onPointerLockChange);
  110. document.removeEventListener("mozpointerlockchange", commonEngine._onPointerLockChange);
  111. document.removeEventListener("webkitpointerlockchange", commonEngine._onPointerLockChange);
  112. }
  113. }
  114. /**
  115. * Get Font size information
  116. * @param font font name
  117. * @returns an object containing ascent, height and descent
  118. */
  119. export function GetFontOffset(font) {
  120. const text = document.createElement("span");
  121. text.innerHTML = "Hg";
  122. text.setAttribute("style", `font: ${font} !important`);
  123. const block = document.createElement("div");
  124. block.style.display = "inline-block";
  125. block.style.width = "1px";
  126. block.style.height = "0px";
  127. block.style.verticalAlign = "bottom";
  128. const div = document.createElement("div");
  129. div.style.whiteSpace = "nowrap";
  130. div.appendChild(text);
  131. div.appendChild(block);
  132. document.body.appendChild(div);
  133. let fontAscent = 0;
  134. let fontHeight = 0;
  135. try {
  136. fontHeight = block.getBoundingClientRect().top - text.getBoundingClientRect().top;
  137. block.style.verticalAlign = "baseline";
  138. fontAscent = block.getBoundingClientRect().top - text.getBoundingClientRect().top;
  139. }
  140. finally {
  141. document.body.removeChild(div);
  142. }
  143. return { ascent: fontAscent, height: fontHeight, descent: fontHeight - fontAscent };
  144. }
  145. /** @internal */
  146. export function CreateImageBitmapFromSource(engine, imageSource, options) {
  147. const promise = new Promise((resolve, reject) => {
  148. const image = new Image();
  149. image.onload = () => {
  150. image.decode().then(() => {
  151. engine.createImageBitmap(image, options).then((imageBitmap) => {
  152. resolve(imageBitmap);
  153. });
  154. });
  155. };
  156. image.onerror = () => {
  157. reject(`Error loading image ${image.src}`);
  158. };
  159. image.src = imageSource;
  160. });
  161. return promise;
  162. }
  163. /** @internal */
  164. export function ResizeImageBitmap(engine, image, bufferWidth, bufferHeight) {
  165. const canvas = engine.createCanvas(bufferWidth, bufferHeight);
  166. const context = canvas.getContext("2d");
  167. if (!context) {
  168. throw new Error("Unable to get 2d context for resizeImageBitmap");
  169. }
  170. context.drawImage(image, 0, 0);
  171. // Create VertexData from map data
  172. // Cast is due to wrong definition in lib.d.ts from ts 1.3 - https://github.com/Microsoft/TypeScript/issues/949
  173. const buffer = context.getImageData(0, 0, bufferWidth, bufferHeight).data;
  174. return buffer;
  175. }
  176. /**
  177. * Ask the browser to promote the current element to fullscreen rendering mode
  178. * @param element defines the DOM element to promote
  179. */
  180. export function RequestFullscreen(element) {
  181. const requestFunction = element.requestFullscreen || element.webkitRequestFullscreen;
  182. if (!requestFunction) {
  183. return;
  184. }
  185. requestFunction.call(element);
  186. }
  187. /**
  188. * Asks the browser to exit fullscreen mode
  189. */
  190. export function ExitFullscreen() {
  191. const anyDoc = document;
  192. if (document.exitFullscreen) {
  193. document.exitFullscreen();
  194. }
  195. else if (anyDoc.webkitCancelFullScreen) {
  196. anyDoc.webkitCancelFullScreen();
  197. }
  198. }
  199. /**
  200. * Ask the browser to promote the current element to pointerlock mode
  201. * @param element defines the DOM element to promote
  202. */
  203. export function RequestPointerlock(element) {
  204. if (element.requestPointerLock) {
  205. // In some browsers, requestPointerLock returns a promise.
  206. // Handle possible rejections to avoid an unhandled top-level exception.
  207. const promise = element.requestPointerLock();
  208. if (promise instanceof Promise)
  209. promise
  210. .then(() => {
  211. element.focus();
  212. })
  213. .catch(() => { });
  214. else
  215. element.focus();
  216. }
  217. }
  218. /**
  219. * Asks the browser to exit pointerlock mode
  220. */
  221. export function ExitPointerlock() {
  222. if (document.exitPointerLock) {
  223. document.exitPointerLock();
  224. }
  225. }
  226. //# sourceMappingURL=engine.common.js.map