engine.js 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954
  1. import { InternalTexture, InternalTextureSource } from "../Materials/Textures/internalTexture.js";
  2. import { EngineStore } from "./engineStore.js";
  3. import { ThinEngine } from "./thinEngine.js";
  4. import { PerformanceMonitor } from "../Misc/performanceMonitor.js";
  5. import { WebGLDataBuffer } from "../Meshes/WebGL/webGLDataBuffer.js";
  6. import { Logger } from "../Misc/logger.js";
  7. import { WebGLHardwareTexture } from "./WebGL/webGLHardwareTexture.js";
  8. import "./Extensions/engine.alpha.js";
  9. import "./Extensions/engine.readTexture.js";
  10. import "./Extensions/engine.dynamicBuffer.js";
  11. import "./AbstractEngine/abstractEngine.loadingScreen.js";
  12. import "./AbstractEngine/abstractEngine.dom.js";
  13. import "./AbstractEngine/abstractEngine.states.js";
  14. import "./AbstractEngine/abstractEngine.renderPass.js";
  15. import "./AbstractEngine/abstractEngine.texture.js";
  16. import { AbstractEngine } from "./abstractEngine.js";
  17. import { CreateImageBitmapFromSource, ExitFullscreen, ExitPointerlock, GetFontOffset, RequestFullscreen, RequestPointerlock, ResizeImageBitmap, _CommonDispose, _CommonInit, } from "./engine.common.js";
  18. import { PerfCounter } from "../Misc/perfCounter.js";
  19. import "../Audio/audioEngine.js";
  20. /**
  21. * The engine class is responsible for interfacing with all lower-level APIs such as WebGL and Audio
  22. */
  23. export class Engine extends ThinEngine {
  24. /**
  25. * Returns the current npm package of the sdk
  26. */
  27. // Not mixed with Version for tooling purpose.
  28. static get NpmPackage() {
  29. return AbstractEngine.NpmPackage;
  30. }
  31. /**
  32. * Returns the current version of the framework
  33. */
  34. static get Version() {
  35. return AbstractEngine.Version;
  36. }
  37. /** Gets the list of created engines */
  38. static get Instances() {
  39. return EngineStore.Instances;
  40. }
  41. /**
  42. * Gets the latest created engine
  43. */
  44. static get LastCreatedEngine() {
  45. return EngineStore.LastCreatedEngine;
  46. }
  47. /**
  48. * Gets the latest created scene
  49. */
  50. static get LastCreatedScene() {
  51. return EngineStore.LastCreatedScene;
  52. }
  53. /** @internal */
  54. /**
  55. * Will flag all materials in all scenes in all engines as dirty to trigger new shader compilation
  56. * @param flag defines which part of the materials must be marked as dirty
  57. * @param predicate defines a predicate used to filter which materials should be affected
  58. */
  59. static MarkAllMaterialsAsDirty(flag, predicate) {
  60. for (let engineIndex = 0; engineIndex < Engine.Instances.length; engineIndex++) {
  61. const engine = Engine.Instances[engineIndex];
  62. for (let sceneIndex = 0; sceneIndex < engine.scenes.length; sceneIndex++) {
  63. engine.scenes[sceneIndex].markAllMaterialsAsDirty(flag, predicate);
  64. }
  65. }
  66. }
  67. // eslint-disable-next-line jsdoc/require-returns-check
  68. /**
  69. * Method called to create the default loading screen.
  70. * This can be overridden in your own app.
  71. * @param canvas The rendering canvas element
  72. * @returns The loading screen
  73. */
  74. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  75. static DefaultLoadingScreenFactory(canvas) {
  76. return AbstractEngine.DefaultLoadingScreenFactory(canvas);
  77. }
  78. get _supportsHardwareTextureRescaling() {
  79. return !!Engine._RescalePostProcessFactory;
  80. }
  81. _measureFps() {
  82. this._performanceMonitor.sampleFrame();
  83. this._fps = this._performanceMonitor.averageFPS;
  84. this._deltaTime = this._performanceMonitor.instantaneousFrameTime || 0;
  85. }
  86. /**
  87. * Gets the performance monitor attached to this engine
  88. * @see https://doc.babylonjs.com/features/featuresDeepDive/scene/optimize_your_scene#engineinstrumentation
  89. */
  90. get performanceMonitor() {
  91. return this._performanceMonitor;
  92. }
  93. // Events
  94. /**
  95. * Creates a new engine
  96. * @param canvasOrContext defines the canvas or WebGL context to use for rendering. If you provide a WebGL context, Babylon.js will not hook events on the canvas (like pointers, keyboards, etc...) so no event observables will be available. This is mostly used when Babylon.js is used as a plugin on a system which already used the WebGL context
  97. * @param antialias defines enable antialiasing (default: false)
  98. * @param options defines further options to be sent to the getContext() function
  99. * @param adaptToDeviceRatio defines whether to adapt to the device's viewport characteristics (default: false)
  100. */
  101. constructor(canvasOrContext, antialias, options, adaptToDeviceRatio = false) {
  102. super(canvasOrContext, antialias, options, adaptToDeviceRatio);
  103. // Members
  104. /**
  105. * If set, will be used to request the next animation frame for the render loop
  106. */
  107. this.customAnimationFrameRequester = null;
  108. this._performanceMonitor = new PerformanceMonitor();
  109. this._drawCalls = new PerfCounter();
  110. if (!canvasOrContext) {
  111. return;
  112. }
  113. this._features.supportRenderPasses = true;
  114. options = this._creationOptions;
  115. if (canvasOrContext.getContext) {
  116. const canvas = canvasOrContext;
  117. this._sharedInit(canvas);
  118. }
  119. }
  120. _initGLContext() {
  121. super._initGLContext();
  122. this._rescalePostProcess = null;
  123. }
  124. /**
  125. * Shared initialization across engines types.
  126. * @param canvas The canvas associated with this instance of the engine.
  127. */
  128. _sharedInit(canvas) {
  129. super._sharedInit(canvas);
  130. _CommonInit(this, canvas, this._creationOptions);
  131. }
  132. /**
  133. * Resize an image and returns the image data as an uint8array
  134. * @param image image to resize
  135. * @param bufferWidth destination buffer width
  136. * @param bufferHeight destination buffer height
  137. * @returns an uint8array containing RGBA values of bufferWidth * bufferHeight size
  138. */
  139. resizeImageBitmap(image, bufferWidth, bufferHeight) {
  140. return ResizeImageBitmap(this, image, bufferWidth, bufferHeight);
  141. }
  142. /**
  143. * Engine abstraction for loading and creating an image bitmap from a given source string.
  144. * @param imageSource source to load the image from.
  145. * @param options An object that sets options for the image's extraction.
  146. * @returns ImageBitmap
  147. */
  148. _createImageBitmapFromSource(imageSource, options) {
  149. return CreateImageBitmapFromSource(this, imageSource, options);
  150. }
  151. /**
  152. * Toggle full screen mode
  153. * @param requestPointerLock defines if a pointer lock should be requested from the user
  154. */
  155. switchFullscreen(requestPointerLock) {
  156. if (this.isFullscreen) {
  157. this.exitFullscreen();
  158. }
  159. else {
  160. this.enterFullscreen(requestPointerLock);
  161. }
  162. }
  163. /**
  164. * Enters full screen mode
  165. * @param requestPointerLock defines if a pointer lock should be requested from the user
  166. */
  167. enterFullscreen(requestPointerLock) {
  168. if (!this.isFullscreen) {
  169. this._pointerLockRequested = requestPointerLock;
  170. if (this._renderingCanvas) {
  171. RequestFullscreen(this._renderingCanvas);
  172. }
  173. }
  174. }
  175. /**
  176. * Exits full screen mode
  177. */
  178. exitFullscreen() {
  179. if (this.isFullscreen) {
  180. ExitFullscreen();
  181. }
  182. }
  183. generateMipMapsForCubemap(texture, unbind = true) {
  184. if (texture.generateMipMaps) {
  185. const gl = this._gl;
  186. this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, texture, true);
  187. gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
  188. if (unbind) {
  189. this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, null);
  190. }
  191. }
  192. }
  193. /** States */
  194. /**
  195. * Sets a boolean indicating if the dithering state is enabled or disabled
  196. * @param value defines the dithering state
  197. */
  198. setDitheringState(value) {
  199. if (value) {
  200. this._gl.enable(this._gl.DITHER);
  201. }
  202. else {
  203. this._gl.disable(this._gl.DITHER);
  204. }
  205. }
  206. /**
  207. * Sets a boolean indicating if the rasterizer state is enabled or disabled
  208. * @param value defines the rasterizer state
  209. */
  210. setRasterizerState(value) {
  211. if (value) {
  212. this._gl.disable(this._gl.RASTERIZER_DISCARD);
  213. }
  214. else {
  215. this._gl.enable(this._gl.RASTERIZER_DISCARD);
  216. }
  217. }
  218. /**
  219. * Directly set the WebGL Viewport
  220. * @param x defines the x coordinate of the viewport (in screen space)
  221. * @param y defines the y coordinate of the viewport (in screen space)
  222. * @param width defines the width of the viewport (in screen space)
  223. * @param height defines the height of the viewport (in screen space)
  224. * @returns the current viewport Object (if any) that is being replaced by this call. You can restore this viewport later on to go back to the original state
  225. */
  226. setDirectViewport(x, y, width, height) {
  227. const currentViewport = this._cachedViewport;
  228. this._cachedViewport = null;
  229. this._viewport(x, y, width, height);
  230. return currentViewport;
  231. }
  232. /**
  233. * Executes a scissor clear (ie. a clear on a specific portion of the screen)
  234. * @param x defines the x-coordinate of the bottom left corner of the clear rectangle
  235. * @param y defines the y-coordinate of the corner of the clear rectangle
  236. * @param width defines the width of the clear rectangle
  237. * @param height defines the height of the clear rectangle
  238. * @param clearColor defines the clear color
  239. */
  240. scissorClear(x, y, width, height, clearColor) {
  241. this.enableScissor(x, y, width, height);
  242. this.clear(clearColor, true, true, true);
  243. this.disableScissor();
  244. }
  245. /**
  246. * Enable scissor test on a specific rectangle (ie. render will only be executed on a specific portion of the screen)
  247. * @param x defines the x-coordinate of the bottom left corner of the clear rectangle
  248. * @param y defines the y-coordinate of the corner of the clear rectangle
  249. * @param width defines the width of the clear rectangle
  250. * @param height defines the height of the clear rectangle
  251. */
  252. enableScissor(x, y, width, height) {
  253. const gl = this._gl;
  254. // Change state
  255. gl.enable(gl.SCISSOR_TEST);
  256. gl.scissor(x, y, width, height);
  257. }
  258. /**
  259. * Disable previously set scissor test rectangle
  260. */
  261. disableScissor() {
  262. const gl = this._gl;
  263. gl.disable(gl.SCISSOR_TEST);
  264. }
  265. /**
  266. * @internal
  267. */
  268. _loadFileAsync(url, offlineProvider, useArrayBuffer) {
  269. return new Promise((resolve, reject) => {
  270. this._loadFile(url, (data) => {
  271. resolve(data);
  272. }, undefined, offlineProvider, useArrayBuffer, (request, exception) => {
  273. reject(exception);
  274. });
  275. });
  276. }
  277. /**
  278. * Gets the source code of the vertex shader associated with a specific webGL program
  279. * @param program defines the program to use
  280. * @returns a string containing the source code of the vertex shader associated with the program
  281. */
  282. getVertexShaderSource(program) {
  283. const shaders = this._gl.getAttachedShaders(program);
  284. if (!shaders) {
  285. return null;
  286. }
  287. return this._gl.getShaderSource(shaders[0]);
  288. }
  289. /**
  290. * Gets the source code of the fragment shader associated with a specific webGL program
  291. * @param program defines the program to use
  292. * @returns a string containing the source code of the fragment shader associated with the program
  293. */
  294. getFragmentShaderSource(program) {
  295. const shaders = this._gl.getAttachedShaders(program);
  296. if (!shaders) {
  297. return null;
  298. }
  299. return this._gl.getShaderSource(shaders[1]);
  300. }
  301. /**
  302. * Sets a depth stencil texture from a render target to the according uniform.
  303. * @param channel The texture channel
  304. * @param uniform The uniform to set
  305. * @param texture The render target texture containing the depth stencil texture to apply
  306. * @param name The texture name
  307. */
  308. setDepthStencilTexture(channel, uniform, texture, name) {
  309. if (channel === undefined) {
  310. return;
  311. }
  312. if (uniform) {
  313. this._boundUniforms[channel] = uniform;
  314. }
  315. if (!texture || !texture.depthStencilTexture) {
  316. this._setTexture(channel, null, undefined, undefined, name);
  317. }
  318. else {
  319. this._setTexture(channel, texture, false, true, name);
  320. }
  321. }
  322. /**
  323. * Sets a texture to the context from a postprocess
  324. * @param channel defines the channel to use
  325. * @param postProcess defines the source postprocess
  326. * @param name name of the channel
  327. */
  328. setTextureFromPostProcess(channel, postProcess, name) {
  329. let postProcessInput = null;
  330. if (postProcess) {
  331. if (postProcess._forcedOutputTexture) {
  332. postProcessInput = postProcess._forcedOutputTexture;
  333. }
  334. else if (postProcess._textures.data[postProcess._currentRenderTextureInd]) {
  335. postProcessInput = postProcess._textures.data[postProcess._currentRenderTextureInd];
  336. }
  337. }
  338. this._bindTexture(channel, postProcessInput?.texture ?? null, name);
  339. }
  340. /**
  341. * Binds the output of the passed in post process to the texture channel specified
  342. * @param channel The channel the texture should be bound to
  343. * @param postProcess The post process which's output should be bound
  344. * @param name name of the channel
  345. */
  346. setTextureFromPostProcessOutput(channel, postProcess, name) {
  347. this._bindTexture(channel, postProcess?._outputTexture?.texture ?? null, name);
  348. }
  349. /**
  350. * sets the object from which width and height will be taken from when getting render width and height
  351. * Will fallback to the gl object
  352. * @param dimensions the framebuffer width and height that will be used.
  353. */
  354. set framebufferDimensionsObject(dimensions) {
  355. this._framebufferDimensionsObject = dimensions;
  356. if (this._framebufferDimensionsObject) {
  357. this.onResizeObservable.notifyObservers(this);
  358. }
  359. }
  360. _rebuildBuffers() {
  361. // Index / Vertex
  362. for (const scene of this.scenes) {
  363. scene.resetCachedMaterial();
  364. scene._rebuildGeometries();
  365. }
  366. for (const scene of this._virtualScenes) {
  367. scene.resetCachedMaterial();
  368. scene._rebuildGeometries();
  369. }
  370. super._rebuildBuffers();
  371. }
  372. /**
  373. * Get Font size information
  374. * @param font font name
  375. * @returns an object containing ascent, height and descent
  376. */
  377. getFontOffset(font) {
  378. return GetFontOffset(font);
  379. }
  380. /** @internal */
  381. _renderFrame() {
  382. for (let index = 0; index < this._activeRenderLoops.length; index++) {
  383. const renderFunction = this._activeRenderLoops[index];
  384. renderFunction();
  385. }
  386. }
  387. _cancelFrame() {
  388. if (this.customAnimationFrameRequester) {
  389. if (this._frameHandler !== 0) {
  390. this._frameHandler = 0;
  391. const { cancelAnimationFrame } = this.customAnimationFrameRequester;
  392. if (cancelAnimationFrame) {
  393. cancelAnimationFrame(this.customAnimationFrameRequester.requestID);
  394. }
  395. }
  396. }
  397. else {
  398. super._cancelFrame();
  399. }
  400. }
  401. _renderLoop() {
  402. this._frameHandler = 0;
  403. if (!this._contextWasLost) {
  404. let shouldRender = true;
  405. if (this.isDisposed || (!this.renderEvenInBackground && this._windowIsBackground)) {
  406. shouldRender = false;
  407. }
  408. if (shouldRender) {
  409. // Start new frame
  410. this.beginFrame();
  411. // Child canvases
  412. if (!this._renderViews()) {
  413. // Main frame
  414. this._renderFrame();
  415. }
  416. // Present
  417. this.endFrame();
  418. }
  419. }
  420. if (this._frameHandler === 0) {
  421. // Register new frame
  422. if (this.customAnimationFrameRequester) {
  423. this.customAnimationFrameRequester.requestID = this._queueNewFrame(this.customAnimationFrameRequester.renderFunction || this._boundRenderFunction, this.customAnimationFrameRequester);
  424. this._frameHandler = this.customAnimationFrameRequester.requestID;
  425. }
  426. else {
  427. this._frameHandler = this._queueNewFrame(this._boundRenderFunction, this.getHostWindow());
  428. }
  429. }
  430. }
  431. /** @internal */
  432. _renderViews() {
  433. return false;
  434. }
  435. /**
  436. * Enters Pointerlock mode
  437. */
  438. enterPointerlock() {
  439. if (this._renderingCanvas) {
  440. RequestPointerlock(this._renderingCanvas);
  441. }
  442. }
  443. /**
  444. * Exits Pointerlock mode
  445. */
  446. exitPointerlock() {
  447. ExitPointerlock();
  448. }
  449. /**
  450. * Begin a new frame
  451. */
  452. beginFrame() {
  453. this._measureFps();
  454. super.beginFrame();
  455. }
  456. /**
  457. * Force a specific size of the canvas
  458. * @param width defines the new canvas' width
  459. * @param height defines the new canvas' height
  460. * @param forceSetSize true to force setting the sizes of the underlying canvas
  461. * @returns true if the size was changed
  462. */
  463. setSize(width, height, forceSetSize = false) {
  464. if (!this._renderingCanvas) {
  465. return false;
  466. }
  467. if (!super.setSize(width, height, forceSetSize)) {
  468. return false;
  469. }
  470. if (this.scenes) {
  471. for (let index = 0; index < this.scenes.length; index++) {
  472. const scene = this.scenes[index];
  473. for (let camIndex = 0; camIndex < scene.cameras.length; camIndex++) {
  474. const cam = scene.cameras[camIndex];
  475. cam._currentRenderId = 0;
  476. }
  477. }
  478. if (this.onResizeObservable.hasObservers()) {
  479. this.onResizeObservable.notifyObservers(this);
  480. }
  481. }
  482. return true;
  483. }
  484. _deletePipelineContext(pipelineContext) {
  485. const webGLPipelineContext = pipelineContext;
  486. if (webGLPipelineContext && webGLPipelineContext.program) {
  487. if (webGLPipelineContext.transformFeedback) {
  488. this.deleteTransformFeedback(webGLPipelineContext.transformFeedback);
  489. webGLPipelineContext.transformFeedback = null;
  490. }
  491. }
  492. super._deletePipelineContext(pipelineContext);
  493. }
  494. createShaderProgram(pipelineContext, vertexCode, fragmentCode, defines, context, transformFeedbackVaryings = null) {
  495. context = context || this._gl;
  496. this.onBeforeShaderCompilationObservable.notifyObservers(this);
  497. const program = super.createShaderProgram(pipelineContext, vertexCode, fragmentCode, defines, context, transformFeedbackVaryings);
  498. this.onAfterShaderCompilationObservable.notifyObservers(this);
  499. return program;
  500. }
  501. _createShaderProgram(pipelineContext, vertexShader, fragmentShader, context, transformFeedbackVaryings = null) {
  502. const shaderProgram = context.createProgram();
  503. pipelineContext.program = shaderProgram;
  504. if (!shaderProgram) {
  505. throw new Error("Unable to create program");
  506. }
  507. context.attachShader(shaderProgram, vertexShader);
  508. context.attachShader(shaderProgram, fragmentShader);
  509. if (this.webGLVersion > 1 && transformFeedbackVaryings) {
  510. const transformFeedback = this.createTransformFeedback();
  511. this.bindTransformFeedback(transformFeedback);
  512. this.setTranformFeedbackVaryings(shaderProgram, transformFeedbackVaryings);
  513. pipelineContext.transformFeedback = transformFeedback;
  514. }
  515. context.linkProgram(shaderProgram);
  516. if (this.webGLVersion > 1 && transformFeedbackVaryings) {
  517. this.bindTransformFeedback(null);
  518. }
  519. pipelineContext.context = context;
  520. pipelineContext.vertexShader = vertexShader;
  521. pipelineContext.fragmentShader = fragmentShader;
  522. if (!pipelineContext.isParallelCompiled) {
  523. this._finalizePipelineContext(pipelineContext);
  524. }
  525. return shaderProgram;
  526. }
  527. /**
  528. * @internal
  529. */
  530. _releaseTexture(texture) {
  531. super._releaseTexture(texture);
  532. }
  533. /**
  534. * @internal
  535. */
  536. _releaseRenderTargetWrapper(rtWrapper) {
  537. super._releaseRenderTargetWrapper(rtWrapper);
  538. // Set output texture of post process to null if the framebuffer has been released/disposed
  539. this.scenes.forEach((scene) => {
  540. scene.postProcesses.forEach((postProcess) => {
  541. if (postProcess._outputTexture === rtWrapper) {
  542. postProcess._outputTexture = null;
  543. }
  544. });
  545. scene.cameras.forEach((camera) => {
  546. camera._postProcesses.forEach((postProcess) => {
  547. if (postProcess) {
  548. if (postProcess._outputTexture === rtWrapper) {
  549. postProcess._outputTexture = null;
  550. }
  551. }
  552. });
  553. });
  554. });
  555. }
  556. /**
  557. * @internal
  558. * Rescales a texture
  559. * @param source input texture
  560. * @param destination destination texture
  561. * @param scene scene to use to render the resize
  562. * @param internalFormat format to use when resizing
  563. * @param onComplete callback to be called when resize has completed
  564. */
  565. _rescaleTexture(source, destination, scene, internalFormat, onComplete) {
  566. this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_MAG_FILTER, this._gl.LINEAR);
  567. this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_MIN_FILTER, this._gl.LINEAR);
  568. this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_WRAP_S, this._gl.CLAMP_TO_EDGE);
  569. this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_WRAP_T, this._gl.CLAMP_TO_EDGE);
  570. const rtt = this.createRenderTargetTexture({
  571. width: destination.width,
  572. height: destination.height,
  573. }, {
  574. generateMipMaps: false,
  575. type: 0,
  576. samplingMode: 2,
  577. generateDepthBuffer: false,
  578. generateStencilBuffer: false,
  579. });
  580. if (!this._rescalePostProcess && Engine._RescalePostProcessFactory) {
  581. this._rescalePostProcess = Engine._RescalePostProcessFactory(this);
  582. }
  583. if (this._rescalePostProcess) {
  584. this._rescalePostProcess.externalTextureSamplerBinding = true;
  585. this._rescalePostProcess.getEffect().executeWhenCompiled(() => {
  586. this._rescalePostProcess.onApply = function (effect) {
  587. effect._bindTexture("textureSampler", source);
  588. };
  589. let hostingScene = scene;
  590. if (!hostingScene) {
  591. hostingScene = this.scenes[this.scenes.length - 1];
  592. }
  593. hostingScene.postProcessManager.directRender([this._rescalePostProcess], rtt, true);
  594. this._bindTextureDirectly(this._gl.TEXTURE_2D, destination, true);
  595. this._gl.copyTexImage2D(this._gl.TEXTURE_2D, 0, internalFormat, 0, 0, destination.width, destination.height, 0);
  596. this.unBindFramebuffer(rtt);
  597. rtt.dispose();
  598. if (onComplete) {
  599. onComplete();
  600. }
  601. });
  602. }
  603. }
  604. /**
  605. * Wraps an external web gl texture in a Babylon texture.
  606. * @param texture defines the external texture
  607. * @param hasMipMaps defines whether the external texture has mip maps (default: false)
  608. * @param samplingMode defines the sampling mode for the external texture (default: 3)
  609. * @param width defines the width for the external texture (default: 0)
  610. * @param height defines the height for the external texture (default: 0)
  611. * @returns the babylon internal texture
  612. */
  613. wrapWebGLTexture(texture, hasMipMaps = false, samplingMode = 3, width = 0, height = 0) {
  614. const hardwareTexture = new WebGLHardwareTexture(texture, this._gl);
  615. const internalTexture = new InternalTexture(this, InternalTextureSource.Unknown, true);
  616. internalTexture._hardwareTexture = hardwareTexture;
  617. internalTexture.baseWidth = width;
  618. internalTexture.baseHeight = height;
  619. internalTexture.width = width;
  620. internalTexture.height = height;
  621. internalTexture.isReady = true;
  622. internalTexture.useMipMaps = hasMipMaps;
  623. this.updateTextureSamplingMode(samplingMode, internalTexture);
  624. return internalTexture;
  625. }
  626. /**
  627. * @internal
  628. */
  629. _uploadImageToTexture(texture, image, faceIndex = 0, lod = 0) {
  630. const gl = this._gl;
  631. const textureType = this._getWebGLTextureType(texture.type);
  632. const format = this._getInternalFormat(texture.format);
  633. const internalFormat = this._getRGBABufferInternalSizedFormat(texture.type, format);
  634. const bindTarget = texture.isCube ? gl.TEXTURE_CUBE_MAP : gl.TEXTURE_2D;
  635. this._bindTextureDirectly(bindTarget, texture, true);
  636. this._unpackFlipY(texture.invertY);
  637. let target = gl.TEXTURE_2D;
  638. if (texture.isCube) {
  639. target = gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex;
  640. }
  641. gl.texImage2D(target, lod, internalFormat, format, textureType, image);
  642. this._bindTextureDirectly(bindTarget, null, true);
  643. }
  644. /**
  645. * Updates a depth texture Comparison Mode and Function.
  646. * If the comparison Function is equal to 0, the mode will be set to none.
  647. * Otherwise, this only works in webgl 2 and requires a shadow sampler in the shader.
  648. * @param texture The texture to set the comparison function for
  649. * @param comparisonFunction The comparison function to set, 0 if no comparison required
  650. */
  651. updateTextureComparisonFunction(texture, comparisonFunction) {
  652. if (this.webGLVersion === 1) {
  653. Logger.Error("WebGL 1 does not support texture comparison.");
  654. return;
  655. }
  656. const gl = this._gl;
  657. if (texture.isCube) {
  658. this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, texture, true);
  659. if (comparisonFunction === 0) {
  660. gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_COMPARE_FUNC, 515);
  661. gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_COMPARE_MODE, gl.NONE);
  662. }
  663. else {
  664. gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_COMPARE_FUNC, comparisonFunction);
  665. gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_COMPARE_MODE, gl.COMPARE_REF_TO_TEXTURE);
  666. }
  667. this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, null);
  668. }
  669. else {
  670. this._bindTextureDirectly(this._gl.TEXTURE_2D, texture, true);
  671. if (comparisonFunction === 0) {
  672. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_COMPARE_FUNC, 515);
  673. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_COMPARE_MODE, gl.NONE);
  674. }
  675. else {
  676. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_COMPARE_FUNC, comparisonFunction);
  677. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_COMPARE_MODE, gl.COMPARE_REF_TO_TEXTURE);
  678. }
  679. this._bindTextureDirectly(this._gl.TEXTURE_2D, null);
  680. }
  681. texture._comparisonFunction = comparisonFunction;
  682. }
  683. /**
  684. * Creates a webGL buffer to use with instantiation
  685. * @param capacity defines the size of the buffer
  686. * @returns the webGL buffer
  687. */
  688. createInstancesBuffer(capacity) {
  689. const buffer = this._gl.createBuffer();
  690. if (!buffer) {
  691. throw new Error("Unable to create instance buffer");
  692. }
  693. const result = new WebGLDataBuffer(buffer);
  694. result.capacity = capacity;
  695. this.bindArrayBuffer(result);
  696. this._gl.bufferData(this._gl.ARRAY_BUFFER, capacity, this._gl.DYNAMIC_DRAW);
  697. result.references = 1;
  698. return result;
  699. }
  700. /**
  701. * Delete a webGL buffer used with instantiation
  702. * @param buffer defines the webGL buffer to delete
  703. */
  704. deleteInstancesBuffer(buffer) {
  705. this._gl.deleteBuffer(buffer);
  706. }
  707. _clientWaitAsync(sync, flags = 0, intervalms = 10) {
  708. const gl = this._gl;
  709. return new Promise((resolve, reject) => {
  710. const check = () => {
  711. const res = gl.clientWaitSync(sync, flags, 0);
  712. if (res == gl.WAIT_FAILED) {
  713. reject();
  714. return;
  715. }
  716. if (res == gl.TIMEOUT_EXPIRED) {
  717. setTimeout(check, intervalms);
  718. return;
  719. }
  720. resolve();
  721. };
  722. check();
  723. });
  724. }
  725. /**
  726. * @internal
  727. */
  728. _readPixelsAsync(x, y, w, h, format, type, outputBuffer) {
  729. if (this._webGLVersion < 2) {
  730. throw new Error("_readPixelsAsync only work on WebGL2+");
  731. }
  732. const gl = this._gl;
  733. const buf = gl.createBuffer();
  734. gl.bindBuffer(gl.PIXEL_PACK_BUFFER, buf);
  735. gl.bufferData(gl.PIXEL_PACK_BUFFER, outputBuffer.byteLength, gl.STREAM_READ);
  736. gl.readPixels(x, y, w, h, format, type, 0);
  737. gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);
  738. const sync = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0);
  739. if (!sync) {
  740. return null;
  741. }
  742. gl.flush();
  743. return this._clientWaitAsync(sync, 0, 10).then(() => {
  744. gl.deleteSync(sync);
  745. gl.bindBuffer(gl.PIXEL_PACK_BUFFER, buf);
  746. gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 0, outputBuffer);
  747. gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);
  748. gl.deleteBuffer(buf);
  749. return outputBuffer;
  750. });
  751. }
  752. dispose() {
  753. // Rescale PP
  754. if (this._rescalePostProcess) {
  755. this._rescalePostProcess.dispose();
  756. }
  757. _CommonDispose(this, this._renderingCanvas);
  758. super.dispose();
  759. }
  760. }
  761. // Const statics
  762. /** Defines that alpha blending is disabled */
  763. Engine.ALPHA_DISABLE = 0;
  764. /** Defines that alpha blending to SRC ALPHA * SRC + DEST */
  765. Engine.ALPHA_ADD = 1;
  766. /** Defines that alpha blending to SRC ALPHA * SRC + (1 - SRC ALPHA) * DEST */
  767. Engine.ALPHA_COMBINE = 2;
  768. /** Defines that alpha blending to DEST - SRC * DEST */
  769. Engine.ALPHA_SUBTRACT = 3;
  770. /** Defines that alpha blending to SRC * DEST */
  771. Engine.ALPHA_MULTIPLY = 4;
  772. /** Defines that alpha blending to SRC ALPHA * SRC + (1 - SRC) * DEST */
  773. Engine.ALPHA_MAXIMIZED = 5;
  774. /** Defines that alpha blending to SRC + DEST */
  775. Engine.ALPHA_ONEONE = 6;
  776. /** Defines that alpha blending to SRC + (1 - SRC ALPHA) * DEST */
  777. Engine.ALPHA_PREMULTIPLIED = 7;
  778. /**
  779. * Defines that alpha blending to SRC + (1 - SRC ALPHA) * DEST
  780. * Alpha will be set to (1 - SRC ALPHA) * DEST ALPHA
  781. */
  782. Engine.ALPHA_PREMULTIPLIED_PORTERDUFF = 8;
  783. /** Defines that alpha blending to CST * SRC + (1 - CST) * DEST */
  784. Engine.ALPHA_INTERPOLATE = 9;
  785. /**
  786. * Defines that alpha blending to SRC + (1 - SRC) * DEST
  787. * Alpha will be set to SRC ALPHA + (1 - SRC ALPHA) * DEST ALPHA
  788. */
  789. Engine.ALPHA_SCREENMODE = 10;
  790. /** Defines that the resource is not delayed*/
  791. Engine.DELAYLOADSTATE_NONE = 0;
  792. /** Defines that the resource was successfully delay loaded */
  793. Engine.DELAYLOADSTATE_LOADED = 1;
  794. /** Defines that the resource is currently delay loading */
  795. Engine.DELAYLOADSTATE_LOADING = 2;
  796. /** Defines that the resource is delayed and has not started loading */
  797. Engine.DELAYLOADSTATE_NOTLOADED = 4;
  798. // Depht or Stencil test Constants.
  799. /** Passed to depthFunction or stencilFunction to specify depth or stencil tests will never pass. i.e. Nothing will be drawn */
  800. Engine.NEVER = 512;
  801. /** Passed to depthFunction or stencilFunction to specify depth or stencil tests will always pass. i.e. Pixels will be drawn in the order they are drawn */
  802. Engine.ALWAYS = 519;
  803. /** Passed to depthFunction or stencilFunction to specify depth or stencil tests will pass if the new depth value is less than the stored value */
  804. Engine.LESS = 513;
  805. /** Passed to depthFunction or stencilFunction to specify depth or stencil tests will pass if the new depth value is equals to the stored value */
  806. Engine.EQUAL = 514;
  807. /** Passed to depthFunction or stencilFunction to specify depth or stencil tests will pass if the new depth value is less than or equal to the stored value */
  808. Engine.LEQUAL = 515;
  809. /** Passed to depthFunction or stencilFunction to specify depth or stencil tests will pass if the new depth value is greater than the stored value */
  810. Engine.GREATER = 516;
  811. /** Passed to depthFunction or stencilFunction to specify depth or stencil tests will pass if the new depth value is greater than or equal to the stored value */
  812. Engine.GEQUAL = 518;
  813. /** Passed to depthFunction or stencilFunction to specify depth or stencil tests will pass if the new depth value is not equal to the stored value */
  814. Engine.NOTEQUAL = 517;
  815. // Stencil Actions Constants.
  816. /** Passed to stencilOperation to specify that stencil value must be kept */
  817. Engine.KEEP = 7680;
  818. /** Passed to stencilOperation to specify that stencil value must be replaced */
  819. Engine.REPLACE = 7681;
  820. /** Passed to stencilOperation to specify that stencil value must be incremented */
  821. Engine.INCR = 7682;
  822. /** Passed to stencilOperation to specify that stencil value must be decremented */
  823. Engine.DECR = 7683;
  824. /** Passed to stencilOperation to specify that stencil value must be inverted */
  825. Engine.INVERT = 5386;
  826. /** Passed to stencilOperation to specify that stencil value must be incremented with wrapping */
  827. Engine.INCR_WRAP = 34055;
  828. /** Passed to stencilOperation to specify that stencil value must be decremented with wrapping */
  829. Engine.DECR_WRAP = 34056;
  830. /** Texture is not repeating outside of 0..1 UVs */
  831. Engine.TEXTURE_CLAMP_ADDRESSMODE = 0;
  832. /** Texture is repeating outside of 0..1 UVs */
  833. Engine.TEXTURE_WRAP_ADDRESSMODE = 1;
  834. /** Texture is repeating and mirrored */
  835. Engine.TEXTURE_MIRROR_ADDRESSMODE = 2;
  836. /** ALPHA */
  837. Engine.TEXTUREFORMAT_ALPHA = 0;
  838. /** LUMINANCE */
  839. Engine.TEXTUREFORMAT_LUMINANCE = 1;
  840. /** LUMINANCE_ALPHA */
  841. Engine.TEXTUREFORMAT_LUMINANCE_ALPHA = 2;
  842. /** RGB */
  843. Engine.TEXTUREFORMAT_RGB = 4;
  844. /** RGBA */
  845. Engine.TEXTUREFORMAT_RGBA = 5;
  846. /** RED */
  847. Engine.TEXTUREFORMAT_RED = 6;
  848. /** RED (2nd reference) */
  849. Engine.TEXTUREFORMAT_R = 6;
  850. /** RG */
  851. Engine.TEXTUREFORMAT_RG = 7;
  852. /** RED_INTEGER */
  853. Engine.TEXTUREFORMAT_RED_INTEGER = 8;
  854. /** RED_INTEGER (2nd reference) */
  855. Engine.TEXTUREFORMAT_R_INTEGER = 8;
  856. /** RG_INTEGER */
  857. Engine.TEXTUREFORMAT_RG_INTEGER = 9;
  858. /** RGB_INTEGER */
  859. Engine.TEXTUREFORMAT_RGB_INTEGER = 10;
  860. /** RGBA_INTEGER */
  861. Engine.TEXTUREFORMAT_RGBA_INTEGER = 11;
  862. /** UNSIGNED_BYTE */
  863. Engine.TEXTURETYPE_UNSIGNED_BYTE = 0;
  864. /** UNSIGNED_BYTE (2nd reference) */
  865. Engine.TEXTURETYPE_UNSIGNED_INT = 0;
  866. /** FLOAT */
  867. Engine.TEXTURETYPE_FLOAT = 1;
  868. /** HALF_FLOAT */
  869. Engine.TEXTURETYPE_HALF_FLOAT = 2;
  870. /** BYTE */
  871. Engine.TEXTURETYPE_BYTE = 3;
  872. /** SHORT */
  873. Engine.TEXTURETYPE_SHORT = 4;
  874. /** UNSIGNED_SHORT */
  875. Engine.TEXTURETYPE_UNSIGNED_SHORT = 5;
  876. /** INT */
  877. Engine.TEXTURETYPE_INT = 6;
  878. /** UNSIGNED_INT */
  879. Engine.TEXTURETYPE_UNSIGNED_INTEGER = 7;
  880. /** UNSIGNED_SHORT_4_4_4_4 */
  881. Engine.TEXTURETYPE_UNSIGNED_SHORT_4_4_4_4 = 8;
  882. /** UNSIGNED_SHORT_5_5_5_1 */
  883. Engine.TEXTURETYPE_UNSIGNED_SHORT_5_5_5_1 = 9;
  884. /** UNSIGNED_SHORT_5_6_5 */
  885. Engine.TEXTURETYPE_UNSIGNED_SHORT_5_6_5 = 10;
  886. /** UNSIGNED_INT_2_10_10_10_REV */
  887. Engine.TEXTURETYPE_UNSIGNED_INT_2_10_10_10_REV = 11;
  888. /** UNSIGNED_INT_24_8 */
  889. Engine.TEXTURETYPE_UNSIGNED_INT_24_8 = 12;
  890. /** UNSIGNED_INT_10F_11F_11F_REV */
  891. Engine.TEXTURETYPE_UNSIGNED_INT_10F_11F_11F_REV = 13;
  892. /** UNSIGNED_INT_5_9_9_9_REV */
  893. Engine.TEXTURETYPE_UNSIGNED_INT_5_9_9_9_REV = 14;
  894. /** FLOAT_32_UNSIGNED_INT_24_8_REV */
  895. Engine.TEXTURETYPE_FLOAT_32_UNSIGNED_INT_24_8_REV = 15;
  896. /** nearest is mag = nearest and min = nearest and mip = none */
  897. Engine.TEXTURE_NEAREST_SAMPLINGMODE = 1;
  898. /** Bilinear is mag = linear and min = linear and mip = nearest */
  899. Engine.TEXTURE_BILINEAR_SAMPLINGMODE = 2;
  900. /** Trilinear is mag = linear and min = linear and mip = linear */
  901. Engine.TEXTURE_TRILINEAR_SAMPLINGMODE = 3;
  902. /** nearest is mag = nearest and min = nearest and mip = linear */
  903. Engine.TEXTURE_NEAREST_NEAREST_MIPLINEAR = 8;
  904. /** Bilinear is mag = linear and min = linear and mip = nearest */
  905. Engine.TEXTURE_LINEAR_LINEAR_MIPNEAREST = 11;
  906. /** Trilinear is mag = linear and min = linear and mip = linear */
  907. Engine.TEXTURE_LINEAR_LINEAR_MIPLINEAR = 3;
  908. /** mag = nearest and min = nearest and mip = nearest */
  909. Engine.TEXTURE_NEAREST_NEAREST_MIPNEAREST = 4;
  910. /** mag = nearest and min = linear and mip = nearest */
  911. Engine.TEXTURE_NEAREST_LINEAR_MIPNEAREST = 5;
  912. /** mag = nearest and min = linear and mip = linear */
  913. Engine.TEXTURE_NEAREST_LINEAR_MIPLINEAR = 6;
  914. /** mag = nearest and min = linear and mip = none */
  915. Engine.TEXTURE_NEAREST_LINEAR = 7;
  916. /** mag = nearest and min = nearest and mip = none */
  917. Engine.TEXTURE_NEAREST_NEAREST = 1;
  918. /** mag = linear and min = nearest and mip = nearest */
  919. Engine.TEXTURE_LINEAR_NEAREST_MIPNEAREST = 9;
  920. /** mag = linear and min = nearest and mip = linear */
  921. Engine.TEXTURE_LINEAR_NEAREST_MIPLINEAR = 10;
  922. /** mag = linear and min = linear and mip = none */
  923. Engine.TEXTURE_LINEAR_LINEAR = 2;
  924. /** mag = linear and min = nearest and mip = none */
  925. Engine.TEXTURE_LINEAR_NEAREST = 12;
  926. /** Explicit coordinates mode */
  927. Engine.TEXTURE_EXPLICIT_MODE = 0;
  928. /** Spherical coordinates mode */
  929. Engine.TEXTURE_SPHERICAL_MODE = 1;
  930. /** Planar coordinates mode */
  931. Engine.TEXTURE_PLANAR_MODE = 2;
  932. /** Cubic coordinates mode */
  933. Engine.TEXTURE_CUBIC_MODE = 3;
  934. /** Projection coordinates mode */
  935. Engine.TEXTURE_PROJECTION_MODE = 4;
  936. /** Skybox coordinates mode */
  937. Engine.TEXTURE_SKYBOX_MODE = 5;
  938. /** Inverse Cubic coordinates mode */
  939. Engine.TEXTURE_INVCUBIC_MODE = 6;
  940. /** Equirectangular coordinates mode */
  941. Engine.TEXTURE_EQUIRECTANGULAR_MODE = 7;
  942. /** Equirectangular Fixed coordinates mode */
  943. Engine.TEXTURE_FIXED_EQUIRECTANGULAR_MODE = 8;
  944. /** Equirectangular Fixed Mirrored coordinates mode */
  945. Engine.TEXTURE_FIXED_EQUIRECTANGULAR_MIRRORED_MODE = 9;
  946. // Texture rescaling mode
  947. /** Defines that texture rescaling will use a floor to find the closer power of 2 size */
  948. Engine.SCALEMODE_FLOOR = 1;
  949. /** Defines that texture rescaling will look for the nearest power of 2 size */
  950. Engine.SCALEMODE_NEAREST = 2;
  951. /** Defines that texture rescaling will use a ceil to find the closer power of 2 size */
  952. Engine.SCALEMODE_CEILING = 3;
  953. //# sourceMappingURL=engine.js.map