engine.ts 73 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921
  1. import { Observable } from "../Misc/observable";
  2. import { Nullable } from "../types";
  3. import { Scene } from "../scene";
  4. import { InternalTexture } from "../Materials/Textures/internalTexture";
  5. import { IOfflineProvider } from "../Offline/IOfflineProvider";
  6. import { ILoadingScreen } from "../Loading/loadingScreen";
  7. import { DomManagement } from "../Misc/domManagement";
  8. import { EngineStore } from "./engineStore";
  9. import { _DevTools } from '../Misc/devTools';
  10. import { WebGLPipelineContext } from './WebGL/webGLPipelineContext';
  11. import { IPipelineContext } from './IPipelineContext';
  12. import { ICustomAnimationFrameRequester } from '../Misc/customAnimationFrameRequester';
  13. import { ThinEngine, EngineOptions } from './thinEngine';
  14. import { Constants } from './constants';
  15. import { IViewportLike, IColor4Like } from '../Maths/math.like';
  16. import { RenderTargetTexture } from '../Materials/Textures/renderTargetTexture';
  17. import { PerformanceMonitor } from '../Misc/performanceMonitor';
  18. import { DataBuffer } from '../Meshes/dataBuffer';
  19. import { PerfCounter } from '../Misc/perfCounter';
  20. import { WebGLDataBuffer } from '../Meshes/WebGL/webGLDataBuffer';
  21. import { Logger } from '../Misc/logger';
  22. import "./Extensions/engine.alpha";
  23. import "./Extensions/engine.readTexture";
  24. import "./Extensions/engine.dynamicBuffer";
  25. import { IAudioEngine } from '../Audio/Interfaces/IAudioEngine';
  26. declare type Material = import("../Materials/material").Material;
  27. declare type PostProcess = import("../PostProcesses/postProcess").PostProcess;
  28. /**
  29. * Defines the interface used by display changed events
  30. */
  31. export interface IDisplayChangedEventArgs {
  32. /** Gets the vrDisplay object (if any) */
  33. vrDisplay: Nullable<any>;
  34. /** Gets a boolean indicating if webVR is supported */
  35. vrSupported: boolean;
  36. }
  37. /**
  38. * Defines the interface used by objects containing a viewport (like a camera)
  39. */
  40. interface IViewportOwnerLike {
  41. /**
  42. * Gets or sets the viewport
  43. */
  44. viewport: IViewportLike;
  45. }
  46. /**
  47. * The engine class is responsible for interfacing with all lower-level APIs such as WebGL and Audio
  48. */
  49. export class Engine extends ThinEngine {
  50. // Const statics
  51. /** Defines that alpha blending is disabled */
  52. public static readonly ALPHA_DISABLE = Constants.ALPHA_DISABLE;
  53. /** Defines that alpha blending to SRC ALPHA * SRC + DEST */
  54. public static readonly ALPHA_ADD = Constants.ALPHA_ADD;
  55. /** Defines that alpha blending to SRC ALPHA * SRC + (1 - SRC ALPHA) * DEST */
  56. public static readonly ALPHA_COMBINE = Constants.ALPHA_COMBINE;
  57. /** Defines that alpha blending to DEST - SRC * DEST */
  58. public static readonly ALPHA_SUBTRACT = Constants.ALPHA_SUBTRACT;
  59. /** Defines that alpha blending to SRC * DEST */
  60. public static readonly ALPHA_MULTIPLY = Constants.ALPHA_MULTIPLY;
  61. /** Defines that alpha blending to SRC ALPHA * SRC + (1 - SRC) * DEST */
  62. public static readonly ALPHA_MAXIMIZED = Constants.ALPHA_MAXIMIZED;
  63. /** Defines that alpha blending to SRC + DEST */
  64. public static readonly ALPHA_ONEONE = Constants.ALPHA_ONEONE;
  65. /** Defines that alpha blending to SRC + (1 - SRC ALPHA) * DEST */
  66. public static readonly ALPHA_PREMULTIPLIED = Constants.ALPHA_PREMULTIPLIED;
  67. /**
  68. * Defines that alpha blending to SRC + (1 - SRC ALPHA) * DEST
  69. * Alpha will be set to (1 - SRC ALPHA) * DEST ALPHA
  70. */
  71. public static readonly ALPHA_PREMULTIPLIED_PORTERDUFF = Constants.ALPHA_PREMULTIPLIED_PORTERDUFF;
  72. /** Defines that alpha blending to CST * SRC + (1 - CST) * DEST */
  73. public static readonly ALPHA_INTERPOLATE = Constants.ALPHA_INTERPOLATE;
  74. /**
  75. * Defines that alpha blending to SRC + (1 - SRC) * DEST
  76. * Alpha will be set to SRC ALPHA + (1 - SRC ALPHA) * DEST ALPHA
  77. */
  78. public static readonly ALPHA_SCREENMODE = Constants.ALPHA_SCREENMODE;
  79. /** Defines that the ressource is not delayed*/
  80. public static readonly DELAYLOADSTATE_NONE = Constants.DELAYLOADSTATE_NONE;
  81. /** Defines that the ressource was successfully delay loaded */
  82. public static readonly DELAYLOADSTATE_LOADED = Constants.DELAYLOADSTATE_LOADED;
  83. /** Defines that the ressource is currently delay loading */
  84. public static readonly DELAYLOADSTATE_LOADING = Constants.DELAYLOADSTATE_LOADING;
  85. /** Defines that the ressource is delayed and has not started loading */
  86. public static readonly DELAYLOADSTATE_NOTLOADED = Constants.DELAYLOADSTATE_NOTLOADED;
  87. // Depht or Stencil test Constants.
  88. /** Passed to depthFunction or stencilFunction to specify depth or stencil tests will never pass. i.e. Nothing will be drawn */
  89. public static readonly NEVER = Constants.NEVER;
  90. /** 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 */
  91. public static readonly ALWAYS = Constants.ALWAYS;
  92. /** Passed to depthFunction or stencilFunction to specify depth or stencil tests will pass if the new depth value is less than the stored value */
  93. public static readonly LESS = Constants.LESS;
  94. /** Passed to depthFunction or stencilFunction to specify depth or stencil tests will pass if the new depth value is equals to the stored value */
  95. public static readonly EQUAL = Constants.EQUAL;
  96. /** 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 */
  97. public static readonly LEQUAL = Constants.LEQUAL;
  98. /** Passed to depthFunction or stencilFunction to specify depth or stencil tests will pass if the new depth value is greater than the stored value */
  99. public static readonly GREATER = Constants.GREATER;
  100. /** 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 */
  101. public static readonly GEQUAL = Constants.GEQUAL;
  102. /** 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 */
  103. public static readonly NOTEQUAL = Constants.NOTEQUAL;
  104. // Stencil Actions Constants.
  105. /** Passed to stencilOperation to specify that stencil value must be kept */
  106. public static readonly KEEP = Constants.KEEP;
  107. /** Passed to stencilOperation to specify that stencil value must be replaced */
  108. public static readonly REPLACE = Constants.REPLACE;
  109. /** Passed to stencilOperation to specify that stencil value must be incremented */
  110. public static readonly INCR = Constants.INCR;
  111. /** Passed to stencilOperation to specify that stencil value must be decremented */
  112. public static readonly DECR = Constants.DECR;
  113. /** Passed to stencilOperation to specify that stencil value must be inverted */
  114. public static readonly INVERT = Constants.INVERT;
  115. /** Passed to stencilOperation to specify that stencil value must be incremented with wrapping */
  116. public static readonly INCR_WRAP = Constants.INCR_WRAP;
  117. /** Passed to stencilOperation to specify that stencil value must be decremented with wrapping */
  118. public static readonly DECR_WRAP = Constants.DECR_WRAP;
  119. /** Texture is not repeating outside of 0..1 UVs */
  120. public static readonly TEXTURE_CLAMP_ADDRESSMODE = Constants.TEXTURE_CLAMP_ADDRESSMODE;
  121. /** Texture is repeating outside of 0..1 UVs */
  122. public static readonly TEXTURE_WRAP_ADDRESSMODE = Constants.TEXTURE_WRAP_ADDRESSMODE;
  123. /** Texture is repeating and mirrored */
  124. public static readonly TEXTURE_MIRROR_ADDRESSMODE = Constants.TEXTURE_MIRROR_ADDRESSMODE;
  125. /** ALPHA */
  126. public static readonly TEXTUREFORMAT_ALPHA = Constants.TEXTUREFORMAT_ALPHA;
  127. /** LUMINANCE */
  128. public static readonly TEXTUREFORMAT_LUMINANCE = Constants.TEXTUREFORMAT_LUMINANCE;
  129. /** LUMINANCE_ALPHA */
  130. public static readonly TEXTUREFORMAT_LUMINANCE_ALPHA = Constants.TEXTUREFORMAT_LUMINANCE_ALPHA;
  131. /** RGB */
  132. public static readonly TEXTUREFORMAT_RGB = Constants.TEXTUREFORMAT_RGB;
  133. /** RGBA */
  134. public static readonly TEXTUREFORMAT_RGBA = Constants.TEXTUREFORMAT_RGBA;
  135. /** RED */
  136. public static readonly TEXTUREFORMAT_RED = Constants.TEXTUREFORMAT_RED;
  137. /** RED (2nd reference) */
  138. public static readonly TEXTUREFORMAT_R = Constants.TEXTUREFORMAT_R;
  139. /** RG */
  140. public static readonly TEXTUREFORMAT_RG = Constants.TEXTUREFORMAT_RG;
  141. /** RED_INTEGER */
  142. public static readonly TEXTUREFORMAT_RED_INTEGER = Constants.TEXTUREFORMAT_RED_INTEGER;
  143. /** RED_INTEGER (2nd reference) */
  144. public static readonly TEXTUREFORMAT_R_INTEGER = Constants.TEXTUREFORMAT_R_INTEGER;
  145. /** RG_INTEGER */
  146. public static readonly TEXTUREFORMAT_RG_INTEGER = Constants.TEXTUREFORMAT_RG_INTEGER;
  147. /** RGB_INTEGER */
  148. public static readonly TEXTUREFORMAT_RGB_INTEGER = Constants.TEXTUREFORMAT_RGB_INTEGER;
  149. /** RGBA_INTEGER */
  150. public static readonly TEXTUREFORMAT_RGBA_INTEGER = Constants.TEXTUREFORMAT_RGBA_INTEGER;
  151. /** UNSIGNED_BYTE */
  152. public static readonly TEXTURETYPE_UNSIGNED_BYTE = Constants.TEXTURETYPE_UNSIGNED_BYTE;
  153. /** UNSIGNED_BYTE (2nd reference) */
  154. public static readonly TEXTURETYPE_UNSIGNED_INT = Constants.TEXTURETYPE_UNSIGNED_INT;
  155. /** FLOAT */
  156. public static readonly TEXTURETYPE_FLOAT = Constants.TEXTURETYPE_FLOAT;
  157. /** HALF_FLOAT */
  158. public static readonly TEXTURETYPE_HALF_FLOAT = Constants.TEXTURETYPE_HALF_FLOAT;
  159. /** BYTE */
  160. public static readonly TEXTURETYPE_BYTE = Constants.TEXTURETYPE_BYTE;
  161. /** SHORT */
  162. public static readonly TEXTURETYPE_SHORT = Constants.TEXTURETYPE_SHORT;
  163. /** UNSIGNED_SHORT */
  164. public static readonly TEXTURETYPE_UNSIGNED_SHORT = Constants.TEXTURETYPE_UNSIGNED_SHORT;
  165. /** INT */
  166. public static readonly TEXTURETYPE_INT = Constants.TEXTURETYPE_INT;
  167. /** UNSIGNED_INT */
  168. public static readonly TEXTURETYPE_UNSIGNED_INTEGER = Constants.TEXTURETYPE_UNSIGNED_INTEGER;
  169. /** UNSIGNED_SHORT_4_4_4_4 */
  170. public static readonly TEXTURETYPE_UNSIGNED_SHORT_4_4_4_4 = Constants.TEXTURETYPE_UNSIGNED_SHORT_4_4_4_4;
  171. /** UNSIGNED_SHORT_5_5_5_1 */
  172. public static readonly TEXTURETYPE_UNSIGNED_SHORT_5_5_5_1 = Constants.TEXTURETYPE_UNSIGNED_SHORT_5_5_5_1;
  173. /** UNSIGNED_SHORT_5_6_5 */
  174. public static readonly TEXTURETYPE_UNSIGNED_SHORT_5_6_5 = Constants.TEXTURETYPE_UNSIGNED_SHORT_5_6_5;
  175. /** UNSIGNED_INT_2_10_10_10_REV */
  176. public static readonly TEXTURETYPE_UNSIGNED_INT_2_10_10_10_REV = Constants.TEXTURETYPE_UNSIGNED_INT_2_10_10_10_REV;
  177. /** UNSIGNED_INT_24_8 */
  178. public static readonly TEXTURETYPE_UNSIGNED_INT_24_8 = Constants.TEXTURETYPE_UNSIGNED_INT_24_8;
  179. /** UNSIGNED_INT_10F_11F_11F_REV */
  180. public static readonly TEXTURETYPE_UNSIGNED_INT_10F_11F_11F_REV = Constants.TEXTURETYPE_UNSIGNED_INT_10F_11F_11F_REV;
  181. /** UNSIGNED_INT_5_9_9_9_REV */
  182. public static readonly TEXTURETYPE_UNSIGNED_INT_5_9_9_9_REV = Constants.TEXTURETYPE_UNSIGNED_INT_5_9_9_9_REV;
  183. /** FLOAT_32_UNSIGNED_INT_24_8_REV */
  184. public static readonly TEXTURETYPE_FLOAT_32_UNSIGNED_INT_24_8_REV = Constants.TEXTURETYPE_FLOAT_32_UNSIGNED_INT_24_8_REV;
  185. /** nearest is mag = nearest and min = nearest and mip = linear */
  186. public static readonly TEXTURE_NEAREST_SAMPLINGMODE = Constants.TEXTURE_NEAREST_SAMPLINGMODE;
  187. /** Bilinear is mag = linear and min = linear and mip = nearest */
  188. public static readonly TEXTURE_BILINEAR_SAMPLINGMODE = Constants.TEXTURE_BILINEAR_SAMPLINGMODE;
  189. /** Trilinear is mag = linear and min = linear and mip = linear */
  190. public static readonly TEXTURE_TRILINEAR_SAMPLINGMODE = Constants.TEXTURE_TRILINEAR_SAMPLINGMODE;
  191. /** nearest is mag = nearest and min = nearest and mip = linear */
  192. public static readonly TEXTURE_NEAREST_NEAREST_MIPLINEAR = Constants.TEXTURE_NEAREST_NEAREST_MIPLINEAR;
  193. /** Bilinear is mag = linear and min = linear and mip = nearest */
  194. public static readonly TEXTURE_LINEAR_LINEAR_MIPNEAREST = Constants.TEXTURE_LINEAR_LINEAR_MIPNEAREST;
  195. /** Trilinear is mag = linear and min = linear and mip = linear */
  196. public static readonly TEXTURE_LINEAR_LINEAR_MIPLINEAR = Constants.TEXTURE_LINEAR_LINEAR_MIPLINEAR;
  197. /** mag = nearest and min = nearest and mip = nearest */
  198. public static readonly TEXTURE_NEAREST_NEAREST_MIPNEAREST = Constants.TEXTURE_NEAREST_NEAREST_MIPNEAREST;
  199. /** mag = nearest and min = linear and mip = nearest */
  200. public static readonly TEXTURE_NEAREST_LINEAR_MIPNEAREST = Constants.TEXTURE_NEAREST_LINEAR_MIPNEAREST;
  201. /** mag = nearest and min = linear and mip = linear */
  202. public static readonly TEXTURE_NEAREST_LINEAR_MIPLINEAR = Constants.TEXTURE_NEAREST_LINEAR_MIPLINEAR;
  203. /** mag = nearest and min = linear and mip = none */
  204. public static readonly TEXTURE_NEAREST_LINEAR = Constants.TEXTURE_NEAREST_LINEAR;
  205. /** mag = nearest and min = nearest and mip = none */
  206. public static readonly TEXTURE_NEAREST_NEAREST = Constants.TEXTURE_NEAREST_NEAREST;
  207. /** mag = linear and min = nearest and mip = nearest */
  208. public static readonly TEXTURE_LINEAR_NEAREST_MIPNEAREST = Constants.TEXTURE_LINEAR_NEAREST_MIPNEAREST;
  209. /** mag = linear and min = nearest and mip = linear */
  210. public static readonly TEXTURE_LINEAR_NEAREST_MIPLINEAR = Constants.TEXTURE_LINEAR_NEAREST_MIPLINEAR;
  211. /** mag = linear and min = linear and mip = none */
  212. public static readonly TEXTURE_LINEAR_LINEAR = Constants.TEXTURE_LINEAR_LINEAR;
  213. /** mag = linear and min = nearest and mip = none */
  214. public static readonly TEXTURE_LINEAR_NEAREST = Constants.TEXTURE_LINEAR_NEAREST;
  215. /** Explicit coordinates mode */
  216. public static readonly TEXTURE_EXPLICIT_MODE = Constants.TEXTURE_EXPLICIT_MODE;
  217. /** Spherical coordinates mode */
  218. public static readonly TEXTURE_SPHERICAL_MODE = Constants.TEXTURE_SPHERICAL_MODE;
  219. /** Planar coordinates mode */
  220. public static readonly TEXTURE_PLANAR_MODE = Constants.TEXTURE_PLANAR_MODE;
  221. /** Cubic coordinates mode */
  222. public static readonly TEXTURE_CUBIC_MODE = Constants.TEXTURE_CUBIC_MODE;
  223. /** Projection coordinates mode */
  224. public static readonly TEXTURE_PROJECTION_MODE = Constants.TEXTURE_PROJECTION_MODE;
  225. /** Skybox coordinates mode */
  226. public static readonly TEXTURE_SKYBOX_MODE = Constants.TEXTURE_SKYBOX_MODE;
  227. /** Inverse Cubic coordinates mode */
  228. public static readonly TEXTURE_INVCUBIC_MODE = Constants.TEXTURE_INVCUBIC_MODE;
  229. /** Equirectangular coordinates mode */
  230. public static readonly TEXTURE_EQUIRECTANGULAR_MODE = Constants.TEXTURE_EQUIRECTANGULAR_MODE;
  231. /** Equirectangular Fixed coordinates mode */
  232. public static readonly TEXTURE_FIXED_EQUIRECTANGULAR_MODE = Constants.TEXTURE_FIXED_EQUIRECTANGULAR_MODE;
  233. /** Equirectangular Fixed Mirrored coordinates mode */
  234. public static readonly TEXTURE_FIXED_EQUIRECTANGULAR_MIRRORED_MODE = Constants.TEXTURE_FIXED_EQUIRECTANGULAR_MIRRORED_MODE;
  235. // Texture rescaling mode
  236. /** Defines that texture rescaling will use a floor to find the closer power of 2 size */
  237. public static readonly SCALEMODE_FLOOR = Constants.SCALEMODE_FLOOR;
  238. /** Defines that texture rescaling will look for the nearest power of 2 size */
  239. public static readonly SCALEMODE_NEAREST = Constants.SCALEMODE_NEAREST;
  240. /** Defines that texture rescaling will use a ceil to find the closer power of 2 size */
  241. public static readonly SCALEMODE_CEILING = Constants.SCALEMODE_CEILING;
  242. /**
  243. * Returns the current npm package of the sdk
  244. */
  245. // Not mixed with Version for tooling purpose.
  246. public static get NpmPackage(): string {
  247. return ThinEngine.NpmPackage;
  248. }
  249. /**
  250. * Returns the current version of the framework
  251. */
  252. public static get Version(): string {
  253. return ThinEngine.Version;
  254. }
  255. /** Gets the list of created engines */
  256. public static get Instances(): Engine[] {
  257. return EngineStore.Instances;
  258. }
  259. /**
  260. * Gets the latest created engine
  261. */
  262. public static get LastCreatedEngine(): Nullable<Engine> {
  263. return EngineStore.LastCreatedEngine;
  264. }
  265. /**
  266. * Gets the latest created scene
  267. */
  268. public static get LastCreatedScene(): Nullable<Scene> {
  269. return EngineStore.LastCreatedScene;
  270. }
  271. /**
  272. * Will flag all materials in all scenes in all engines as dirty to trigger new shader compilation
  273. * @param flag defines which part of the materials must be marked as dirty
  274. * @param predicate defines a predicate used to filter which materials should be affected
  275. */
  276. public static MarkAllMaterialsAsDirty(flag: number, predicate?: (mat: Material) => boolean): void {
  277. for (var engineIndex = 0; engineIndex < Engine.Instances.length; engineIndex++) {
  278. var engine = Engine.Instances[engineIndex];
  279. for (var sceneIndex = 0; sceneIndex < engine.scenes.length; sceneIndex++) {
  280. engine.scenes[sceneIndex].markAllMaterialsAsDirty(flag, predicate);
  281. }
  282. }
  283. }
  284. /**
  285. * Method called to create the default loading screen.
  286. * This can be overriden in your own app.
  287. * @param canvas The rendering canvas element
  288. * @returns The loading screen
  289. */
  290. public static DefaultLoadingScreenFactory(canvas: HTMLCanvasElement): ILoadingScreen {
  291. throw _DevTools.WarnImport("LoadingScreen");
  292. }
  293. /**
  294. * Method called to create the default rescale post process on each engine.
  295. */
  296. public static _RescalePostProcessFactory: Nullable<(engine: Engine) => PostProcess> = null;
  297. // Members
  298. /**
  299. * Gets or sets a boolean to enable/disable IndexedDB support and avoid XHR on .manifest
  300. **/
  301. public enableOfflineSupport = false;
  302. /**
  303. * Gets or sets a boolean to enable/disable checking manifest if IndexedDB support is enabled (js will always consider the database is up to date)
  304. **/
  305. public disableManifestCheck = false;
  306. /**
  307. * Gets the list of created scenes
  308. */
  309. public scenes = new Array<Scene>();
  310. /**
  311. * Event raised when a new scene is created
  312. */
  313. public onNewSceneAddedObservable = new Observable<Scene>();
  314. /**
  315. * Gets the list of created postprocesses
  316. */
  317. public postProcesses = new Array<PostProcess>();
  318. /**
  319. * Gets a boolean indicating if the pointer is currently locked
  320. */
  321. public isPointerLock = false;
  322. // Observables
  323. /**
  324. * Observable event triggered each time the rendering canvas is resized
  325. */
  326. public onResizeObservable = new Observable<Engine>();
  327. /**
  328. * Observable event triggered each time the canvas loses focus
  329. */
  330. public onCanvasBlurObservable = new Observable<Engine>();
  331. /**
  332. * Observable event triggered each time the canvas gains focus
  333. */
  334. public onCanvasFocusObservable = new Observable<Engine>();
  335. /**
  336. * Observable event triggered each time the canvas receives pointerout event
  337. */
  338. public onCanvasPointerOutObservable = new Observable<PointerEvent>();
  339. /**
  340. * Observable raised when the engine begins a new frame
  341. */
  342. public onBeginFrameObservable = new Observable<Engine>();
  343. /**
  344. * If set, will be used to request the next animation frame for the render loop
  345. */
  346. public customAnimationFrameRequester: Nullable<ICustomAnimationFrameRequester> = null;
  347. /**
  348. * Observable raised when the engine ends the current frame
  349. */
  350. public onEndFrameObservable = new Observable<Engine>();
  351. /**
  352. * Observable raised when the engine is about to compile a shader
  353. */
  354. public onBeforeShaderCompilationObservable = new Observable<Engine>();
  355. /**
  356. * Observable raised when the engine has jsut compiled a shader
  357. */
  358. public onAfterShaderCompilationObservable = new Observable<Engine>();
  359. /**
  360. * Gets the audio engine
  361. * @see https://doc.babylonjs.com/how_to/playing_sounds_and_music
  362. * @ignorenaming
  363. */
  364. public static audioEngine: IAudioEngine;
  365. /**
  366. * Default AudioEngine factory responsible of creating the Audio Engine.
  367. * By default, this will create a BabylonJS Audio Engine if the workload has been embedded.
  368. */
  369. public static AudioEngineFactory: (hostElement: Nullable<HTMLElement>) => IAudioEngine;
  370. /**
  371. * Default offline support factory responsible of creating a tool used to store data locally.
  372. * By default, this will create a Database object if the workload has been embedded.
  373. */
  374. public static OfflineProviderFactory: (urlToScene: string, callbackManifestChecked: (checked: boolean) => any, disableManifestCheck: boolean) => IOfflineProvider;
  375. private _loadingScreen: ILoadingScreen;
  376. private _pointerLockRequested: boolean;
  377. private _rescalePostProcess: PostProcess;
  378. // Deterministic lockstepMaxSteps
  379. private _deterministicLockstep: boolean = false;
  380. private _lockstepMaxSteps: number = 4;
  381. private _timeStep: number = 1 / 60;
  382. protected get _supportsHardwareTextureRescaling() {
  383. return !!Engine._RescalePostProcessFactory;
  384. }
  385. // FPS
  386. private _fps = 60;
  387. private _deltaTime = 0;
  388. /** @hidden */
  389. public _drawCalls = new PerfCounter();
  390. /** Gets or sets the tab index to set to the rendering canvas. 1 is the minimum value to set to be able to capture keyboard events */
  391. public canvasTabIndex = 1;
  392. /**
  393. * Turn this value on if you want to pause FPS computation when in background
  394. */
  395. public disablePerformanceMonitorInBackground = false;
  396. private _performanceMonitor = new PerformanceMonitor();
  397. /**
  398. * Gets the performance monitor attached to this engine
  399. * @see https://doc.babylonjs.com/how_to/optimizing_your_scene#engineinstrumentation
  400. */
  401. public get performanceMonitor(): PerformanceMonitor {
  402. return this._performanceMonitor;
  403. }
  404. // Focus
  405. private _onFocus: () => void;
  406. private _onBlur: () => void;
  407. private _onCanvasPointerOut: (event: PointerEvent) => void;
  408. private _onCanvasBlur: () => void;
  409. private _onCanvasFocus: () => void;
  410. private _onFullscreenChange: () => void;
  411. private _onPointerLockChange: () => void;
  412. // Events
  413. /**
  414. * Gets the HTML element used to attach event listeners
  415. * @returns a HTML element
  416. */
  417. public getInputElement(): Nullable<HTMLElement> {
  418. return this._renderingCanvas;
  419. }
  420. /**
  421. * Creates a new engine
  422. * @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 alreay used the WebGL context
  423. * @param antialias defines enable antialiasing (default: false)
  424. * @param options defines further options to be sent to the getContext() function
  425. * @param adaptToDeviceRatio defines whether to adapt to the device's viewport characteristics (default: false)
  426. */
  427. constructor(canvasOrContext: Nullable<HTMLCanvasElement | WebGLRenderingContext>, antialias?: boolean, options?: EngineOptions, adaptToDeviceRatio: boolean = false) {
  428. super(canvasOrContext, antialias, options, adaptToDeviceRatio);
  429. Engine.Instances.push(this);
  430. if (!canvasOrContext) {
  431. return;
  432. }
  433. options = this._creationOptions;
  434. if ((<any>canvasOrContext).getContext) {
  435. let canvas = <HTMLCanvasElement>canvasOrContext;
  436. this._onCanvasFocus = () => {
  437. this.onCanvasFocusObservable.notifyObservers(this);
  438. };
  439. this._onCanvasBlur = () => {
  440. this.onCanvasBlurObservable.notifyObservers(this);
  441. };
  442. canvas.addEventListener("focus", this._onCanvasFocus);
  443. canvas.addEventListener("blur", this._onCanvasBlur);
  444. this._onBlur = () => {
  445. if (this.disablePerformanceMonitorInBackground) {
  446. this._performanceMonitor.disable();
  447. }
  448. this._windowIsBackground = true;
  449. };
  450. this._onFocus = () => {
  451. if (this.disablePerformanceMonitorInBackground) {
  452. this._performanceMonitor.enable();
  453. }
  454. this._windowIsBackground = false;
  455. };
  456. this._onCanvasPointerOut = (ev) => {
  457. this.onCanvasPointerOutObservable.notifyObservers(ev);
  458. };
  459. canvas.addEventListener("pointerout", this._onCanvasPointerOut);
  460. if (DomManagement.IsWindowObjectExist()) {
  461. let hostWindow = this.getHostWindow()!;
  462. hostWindow.addEventListener("blur", this._onBlur);
  463. hostWindow.addEventListener("focus", this._onFocus);
  464. let anyDoc = document as any;
  465. // Fullscreen
  466. this._onFullscreenChange = () => {
  467. if (anyDoc.fullscreen !== undefined) {
  468. this.isFullscreen = anyDoc.fullscreen;
  469. } else if (anyDoc.mozFullScreen !== undefined) {
  470. this.isFullscreen = anyDoc.mozFullScreen;
  471. } else if (anyDoc.webkitIsFullScreen !== undefined) {
  472. this.isFullscreen = anyDoc.webkitIsFullScreen;
  473. } else if (anyDoc.msIsFullScreen !== undefined) {
  474. this.isFullscreen = anyDoc.msIsFullScreen;
  475. }
  476. // Pointer lock
  477. if (this.isFullscreen && this._pointerLockRequested && canvas) {
  478. Engine._RequestPointerlock(canvas);
  479. }
  480. };
  481. document.addEventListener("fullscreenchange", this._onFullscreenChange, false);
  482. document.addEventListener("mozfullscreenchange", this._onFullscreenChange, false);
  483. document.addEventListener("webkitfullscreenchange", this._onFullscreenChange, false);
  484. document.addEventListener("msfullscreenchange", this._onFullscreenChange, false);
  485. // Pointer lock
  486. this._onPointerLockChange = () => {
  487. this.isPointerLock = (anyDoc.mozPointerLockElement === canvas ||
  488. anyDoc.webkitPointerLockElement === canvas ||
  489. anyDoc.msPointerLockElement === canvas ||
  490. anyDoc.pointerLockElement === canvas
  491. );
  492. };
  493. document.addEventListener("pointerlockchange", this._onPointerLockChange, false);
  494. document.addEventListener("mspointerlockchange", this._onPointerLockChange, false);
  495. document.addEventListener("mozpointerlockchange", this._onPointerLockChange, false);
  496. document.addEventListener("webkitpointerlockchange", this._onPointerLockChange, false);
  497. // Create Audio Engine if needed.
  498. if (!Engine.audioEngine && options.audioEngine && Engine.AudioEngineFactory) {
  499. Engine.audioEngine = Engine.AudioEngineFactory(this.getRenderingCanvas());
  500. }
  501. }
  502. this._connectVREvents();
  503. this.enableOfflineSupport = Engine.OfflineProviderFactory !== undefined;
  504. if (!options.doNotHandleTouchAction) {
  505. this._disableTouchAction();
  506. }
  507. this._deterministicLockstep = !!options.deterministicLockstep;
  508. this._lockstepMaxSteps = options.lockstepMaxSteps || 0;
  509. this._timeStep = options.timeStep || 1 / 60;
  510. }
  511. // Load WebVR Devices
  512. this._prepareVRComponent();
  513. if (options.autoEnableWebVR) {
  514. this.initWebVR();
  515. }
  516. }
  517. /**
  518. * Gets current aspect ratio
  519. * @param viewportOwner defines the camera to use to get the aspect ratio
  520. * @param useScreen defines if screen size must be used (or the current render target if any)
  521. * @returns a number defining the aspect ratio
  522. */
  523. public getAspectRatio(viewportOwner: IViewportOwnerLike, useScreen = false): number {
  524. var viewport = viewportOwner.viewport;
  525. return (this.getRenderWidth(useScreen) * viewport.width) / (this.getRenderHeight(useScreen) * viewport.height);
  526. }
  527. /**
  528. * Gets current screen aspect ratio
  529. * @returns a number defining the aspect ratio
  530. */
  531. public getScreenAspectRatio(): number {
  532. return (this.getRenderWidth(true)) / (this.getRenderHeight(true));
  533. }
  534. /**
  535. * Gets the client rect of the HTML canvas attached with the current webGL context
  536. * @returns a client rectanglee
  537. */
  538. public getRenderingCanvasClientRect(): Nullable<ClientRect> {
  539. if (!this._renderingCanvas) {
  540. return null;
  541. }
  542. return this._renderingCanvas.getBoundingClientRect();
  543. }
  544. /**
  545. * Gets the client rect of the HTML element used for events
  546. * @returns a client rectanglee
  547. */
  548. public getInputElementClientRect(): Nullable<ClientRect> {
  549. if (!this._renderingCanvas) {
  550. return null;
  551. }
  552. return this.getInputElement()!.getBoundingClientRect();
  553. }
  554. /**
  555. * Gets a boolean indicating that the engine is running in deterministic lock step mode
  556. * @see https://doc.babylonjs.com/babylon101/animations#deterministic-lockstep
  557. * @returns true if engine is in deterministic lock step mode
  558. */
  559. public isDeterministicLockStep(): boolean {
  560. return this._deterministicLockstep;
  561. }
  562. /**
  563. * Gets the max steps when engine is running in deterministic lock step
  564. * @see https://doc.babylonjs.com/babylon101/animations#deterministic-lockstep
  565. * @returns the max steps
  566. */
  567. public getLockstepMaxSteps(): number {
  568. return this._lockstepMaxSteps;
  569. }
  570. /**
  571. * Returns the time in ms between steps when using deterministic lock step.
  572. * @returns time step in (ms)
  573. */
  574. public getTimeStep(): number {
  575. return this._timeStep * 1000;
  576. }
  577. /**
  578. * Force the mipmap generation for the given render target texture
  579. * @param texture defines the render target texture to use
  580. * @param unbind defines whether or not to unbind the texture after generation. Defaults to true.
  581. */
  582. public generateMipMapsForCubemap(texture: InternalTexture, unbind = true) {
  583. if (texture.generateMipMaps) {
  584. var gl = this._gl;
  585. this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, texture, true);
  586. gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
  587. if (unbind) {
  588. this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, null);
  589. }
  590. }
  591. }
  592. /** States */
  593. /**
  594. * Set various states to the webGL context
  595. * @param culling defines backface culling state
  596. * @param zOffset defines the value to apply to zOffset (0 by default)
  597. * @param force defines if states must be applied even if cache is up to date
  598. * @param reverseSide defines if culling must be reversed (CCW instead of CW and CW instead of CCW)
  599. */
  600. public setState(culling: boolean, zOffset: number = 0, force?: boolean, reverseSide = false): void {
  601. // Culling
  602. if (this._depthCullingState.cull !== culling || force) {
  603. this._depthCullingState.cull = culling;
  604. }
  605. // Cull face
  606. var cullFace = this.cullBackFaces ? this._gl.BACK : this._gl.FRONT;
  607. if (this._depthCullingState.cullFace !== cullFace || force) {
  608. this._depthCullingState.cullFace = cullFace;
  609. }
  610. // Z offset
  611. this.setZOffset(zOffset);
  612. // Front face
  613. var frontFace = reverseSide ? this._gl.CW : this._gl.CCW;
  614. if (this._depthCullingState.frontFace !== frontFace || force) {
  615. this._depthCullingState.frontFace = frontFace;
  616. }
  617. }
  618. /**
  619. * Set the z offset to apply to current rendering
  620. * @param value defines the offset to apply
  621. */
  622. public setZOffset(value: number): void {
  623. this._depthCullingState.zOffset = value;
  624. }
  625. /**
  626. * Gets the current value of the zOffset
  627. * @returns the current zOffset state
  628. */
  629. public getZOffset(): number {
  630. return this._depthCullingState.zOffset;
  631. }
  632. /**
  633. * Enable or disable depth buffering
  634. * @param enable defines the state to set
  635. */
  636. public setDepthBuffer(enable: boolean): void {
  637. this._depthCullingState.depthTest = enable;
  638. }
  639. /**
  640. * Gets a boolean indicating if depth writing is enabled
  641. * @returns the current depth writing state
  642. */
  643. public getDepthWrite(): boolean {
  644. return this._depthCullingState.depthMask;
  645. }
  646. /**
  647. * Enable or disable depth writing
  648. * @param enable defines the state to set
  649. */
  650. public setDepthWrite(enable: boolean): void {
  651. this._depthCullingState.depthMask = enable;
  652. }
  653. /**
  654. * Gets a boolean indicating if stencil buffer is enabled
  655. * @returns the current stencil buffer state
  656. */
  657. public getStencilBuffer(): boolean {
  658. return this._stencilState.stencilTest;
  659. }
  660. /**
  661. * Enable or disable the stencil buffer
  662. * @param enable defines if the stencil buffer must be enabled or disabled
  663. */
  664. public setStencilBuffer(enable: boolean): void {
  665. this._stencilState.stencilTest = enable;
  666. }
  667. /**
  668. * Gets the current stencil mask
  669. * @returns a number defining the new stencil mask to use
  670. */
  671. public getStencilMask(): number {
  672. return this._stencilState.stencilMask;
  673. }
  674. /**
  675. * Sets the current stencil mask
  676. * @param mask defines the new stencil mask to use
  677. */
  678. public setStencilMask(mask: number): void {
  679. this._stencilState.stencilMask = mask;
  680. }
  681. /**
  682. * Gets the current stencil function
  683. * @returns a number defining the stencil function to use
  684. */
  685. public getStencilFunction(): number {
  686. return this._stencilState.stencilFunc;
  687. }
  688. /**
  689. * Gets the current stencil reference value
  690. * @returns a number defining the stencil reference value to use
  691. */
  692. public getStencilFunctionReference(): number {
  693. return this._stencilState.stencilFuncRef;
  694. }
  695. /**
  696. * Gets the current stencil mask
  697. * @returns a number defining the stencil mask to use
  698. */
  699. public getStencilFunctionMask(): number {
  700. return this._stencilState.stencilFuncMask;
  701. }
  702. /**
  703. * Sets the current stencil function
  704. * @param stencilFunc defines the new stencil function to use
  705. */
  706. public setStencilFunction(stencilFunc: number) {
  707. this._stencilState.stencilFunc = stencilFunc;
  708. }
  709. /**
  710. * Sets the current stencil reference
  711. * @param reference defines the new stencil reference to use
  712. */
  713. public setStencilFunctionReference(reference: number) {
  714. this._stencilState.stencilFuncRef = reference;
  715. }
  716. /**
  717. * Sets the current stencil mask
  718. * @param mask defines the new stencil mask to use
  719. */
  720. public setStencilFunctionMask(mask: number) {
  721. this._stencilState.stencilFuncMask = mask;
  722. }
  723. /**
  724. * Gets the current stencil operation when stencil fails
  725. * @returns a number defining stencil operation to use when stencil fails
  726. */
  727. public getStencilOperationFail(): number {
  728. return this._stencilState.stencilOpStencilFail;
  729. }
  730. /**
  731. * Gets the current stencil operation when depth fails
  732. * @returns a number defining stencil operation to use when depth fails
  733. */
  734. public getStencilOperationDepthFail(): number {
  735. return this._stencilState.stencilOpDepthFail;
  736. }
  737. /**
  738. * Gets the current stencil operation when stencil passes
  739. * @returns a number defining stencil operation to use when stencil passes
  740. */
  741. public getStencilOperationPass(): number {
  742. return this._stencilState.stencilOpStencilDepthPass;
  743. }
  744. /**
  745. * Sets the stencil operation to use when stencil fails
  746. * @param operation defines the stencil operation to use when stencil fails
  747. */
  748. public setStencilOperationFail(operation: number): void {
  749. this._stencilState.stencilOpStencilFail = operation;
  750. }
  751. /**
  752. * Sets the stencil operation to use when depth fails
  753. * @param operation defines the stencil operation to use when depth fails
  754. */
  755. public setStencilOperationDepthFail(operation: number): void {
  756. this._stencilState.stencilOpDepthFail = operation;
  757. }
  758. /**
  759. * Sets the stencil operation to use when stencil passes
  760. * @param operation defines the stencil operation to use when stencil passes
  761. */
  762. public setStencilOperationPass(operation: number): void {
  763. this._stencilState.stencilOpStencilDepthPass = operation;
  764. }
  765. /**
  766. * Sets a boolean indicating if the dithering state is enabled or disabled
  767. * @param value defines the dithering state
  768. */
  769. public setDitheringState(value: boolean): void {
  770. if (value) {
  771. this._gl.enable(this._gl.DITHER);
  772. } else {
  773. this._gl.disable(this._gl.DITHER);
  774. }
  775. }
  776. /**
  777. * Sets a boolean indicating if the rasterizer state is enabled or disabled
  778. * @param value defines the rasterizer state
  779. */
  780. public setRasterizerState(value: boolean): void {
  781. if (value) {
  782. this._gl.disable(this._gl.RASTERIZER_DISCARD);
  783. } else {
  784. this._gl.enable(this._gl.RASTERIZER_DISCARD);
  785. }
  786. }
  787. /**
  788. * Gets the current depth function
  789. * @returns a number defining the depth function
  790. */
  791. public getDepthFunction(): Nullable<number> {
  792. return this._depthCullingState.depthFunc;
  793. }
  794. /**
  795. * Sets the current depth function
  796. * @param depthFunc defines the function to use
  797. */
  798. public setDepthFunction(depthFunc: number) {
  799. this._depthCullingState.depthFunc = depthFunc;
  800. }
  801. /**
  802. * Sets the current depth function to GREATER
  803. */
  804. public setDepthFunctionToGreater(): void {
  805. this._depthCullingState.depthFunc = this._gl.GREATER;
  806. }
  807. /**
  808. * Sets the current depth function to GEQUAL
  809. */
  810. public setDepthFunctionToGreaterOrEqual(): void {
  811. this._depthCullingState.depthFunc = this._gl.GEQUAL;
  812. }
  813. /**
  814. * Sets the current depth function to LESS
  815. */
  816. public setDepthFunctionToLess(): void {
  817. this._depthCullingState.depthFunc = this._gl.LESS;
  818. }
  819. /**
  820. * Sets the current depth function to LEQUAL
  821. */
  822. public setDepthFunctionToLessOrEqual(): void {
  823. this._depthCullingState.depthFunc = this._gl.LEQUAL;
  824. }
  825. private _cachedStencilBuffer: boolean;
  826. private _cachedStencilFunction: number;
  827. private _cachedStencilMask: number;
  828. private _cachedStencilOperationPass: number;
  829. private _cachedStencilOperationFail: number;
  830. private _cachedStencilOperationDepthFail: number;
  831. private _cachedStencilReference: number;
  832. /**
  833. * Caches the the state of the stencil buffer
  834. */
  835. public cacheStencilState() {
  836. this._cachedStencilBuffer = this.getStencilBuffer();
  837. this._cachedStencilFunction = this.getStencilFunction();
  838. this._cachedStencilMask = this.getStencilMask();
  839. this._cachedStencilOperationPass = this.getStencilOperationPass();
  840. this._cachedStencilOperationFail = this.getStencilOperationFail();
  841. this._cachedStencilOperationDepthFail = this.getStencilOperationDepthFail();
  842. this._cachedStencilReference = this.getStencilFunctionReference();
  843. }
  844. /**
  845. * Restores the state of the stencil buffer
  846. */
  847. public restoreStencilState() {
  848. this.setStencilFunction(this._cachedStencilFunction);
  849. this.setStencilMask(this._cachedStencilMask);
  850. this.setStencilBuffer(this._cachedStencilBuffer);
  851. this.setStencilOperationPass(this._cachedStencilOperationPass);
  852. this.setStencilOperationFail(this._cachedStencilOperationFail);
  853. this.setStencilOperationDepthFail(this._cachedStencilOperationDepthFail);
  854. this.setStencilFunctionReference(this._cachedStencilReference);
  855. }
  856. /**
  857. * Directly set the WebGL Viewport
  858. * @param x defines the x coordinate of the viewport (in screen space)
  859. * @param y defines the y coordinate of the viewport (in screen space)
  860. * @param width defines the width of the viewport (in screen space)
  861. * @param height defines the height of the viewport (in screen space)
  862. * @return 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
  863. */
  864. public setDirectViewport(x: number, y: number, width: number, height: number): Nullable<IViewportLike> {
  865. let currentViewport = this._cachedViewport;
  866. this._cachedViewport = null;
  867. this._viewport(x, y, width, height);
  868. return currentViewport;
  869. }
  870. /**
  871. * Executes a scissor clear (ie. a clear on a specific portion of the screen)
  872. * @param x defines the x-coordinate of the top left corner of the clear rectangle
  873. * @param y defines the y-coordinate of the corner of the clear rectangle
  874. * @param width defines the width of the clear rectangle
  875. * @param height defines the height of the clear rectangle
  876. * @param clearColor defines the clear color
  877. */
  878. public scissorClear(x: number, y: number, width: number, height: number, clearColor: IColor4Like): void {
  879. this.enableScissor(x, y, width, height);
  880. this.clear(clearColor, true, true, true);
  881. this.disableScissor();
  882. }
  883. /**
  884. * Enable scissor test on a specific rectangle (ie. render will only be executed on a specific portion of the screen)
  885. * @param x defines the x-coordinate of the top left corner of the clear rectangle
  886. * @param y defines the y-coordinate of the corner of the clear rectangle
  887. * @param width defines the width of the clear rectangle
  888. * @param height defines the height of the clear rectangle
  889. */
  890. public enableScissor(x: number, y: number, width: number, height: number): void {
  891. let gl = this._gl;
  892. // Change state
  893. gl.enable(gl.SCISSOR_TEST);
  894. gl.scissor(x, y, width, height);
  895. }
  896. /**
  897. * Disable previously set scissor test rectangle
  898. */
  899. public disableScissor() {
  900. let gl = this._gl;
  901. gl.disable(gl.SCISSOR_TEST);
  902. }
  903. protected _reportDrawCall() {
  904. this._drawCalls.addCount(1, false);
  905. }
  906. /**
  907. * Initializes a webVR display and starts listening to display change events
  908. * The onVRDisplayChangedObservable will be notified upon these changes
  909. * @returns The onVRDisplayChangedObservable
  910. */
  911. public initWebVR(): Observable<IDisplayChangedEventArgs> {
  912. throw _DevTools.WarnImport("WebVRCamera");
  913. }
  914. /** @hidden */
  915. public _prepareVRComponent() {
  916. // Do nothing as the engine side effect will overload it
  917. }
  918. /** @hidden */
  919. public _connectVREvents(canvas?: HTMLCanvasElement, document?: any) {
  920. // Do nothing as the engine side effect will overload it
  921. }
  922. /** @hidden */
  923. public _submitVRFrame() {
  924. // Do nothing as the engine side effect will overload it
  925. }
  926. /**
  927. * Call this function to leave webVR mode
  928. * Will do nothing if webVR is not supported or if there is no webVR device
  929. * @see https://doc.babylonjs.com/how_to/webvr_camera
  930. */
  931. public disableVR() {
  932. // Do nothing as the engine side effect will overload it
  933. }
  934. /**
  935. * Gets a boolean indicating that the system is in VR mode and is presenting
  936. * @returns true if VR mode is engaged
  937. */
  938. public isVRPresenting() {
  939. return false;
  940. }
  941. /** @hidden */
  942. public _requestVRFrame() {
  943. // Do nothing as the engine side effect will overload it
  944. }
  945. /** @hidden */
  946. public _loadFileAsync(url: string, offlineProvider?: IOfflineProvider, useArrayBuffer?: boolean): Promise<string | ArrayBuffer> {
  947. return new Promise((resolve, reject) => {
  948. this._loadFile(url, (data) => {
  949. resolve(data);
  950. }, undefined, offlineProvider, useArrayBuffer, (request, exception) => {
  951. reject(exception);
  952. });
  953. });
  954. }
  955. /**
  956. * Gets the source code of the vertex shader associated with a specific webGL program
  957. * @param program defines the program to use
  958. * @returns a string containing the source code of the vertex shader associated with the program
  959. */
  960. public getVertexShaderSource(program: WebGLProgram): Nullable<string> {
  961. var shaders = this._gl.getAttachedShaders(program);
  962. if (!shaders) {
  963. return null;
  964. }
  965. return this._gl.getShaderSource(shaders[0]);
  966. }
  967. /**
  968. * Gets the source code of the fragment shader associated with a specific webGL program
  969. * @param program defines the program to use
  970. * @returns a string containing the source code of the fragment shader associated with the program
  971. */
  972. public getFragmentShaderSource(program: WebGLProgram): Nullable<string> {
  973. var shaders = this._gl.getAttachedShaders(program);
  974. if (!shaders) {
  975. return null;
  976. }
  977. return this._gl.getShaderSource(shaders[1]);
  978. }
  979. /**
  980. * Sets a depth stencil texture from a render target to the according uniform.
  981. * @param channel The texture channel
  982. * @param uniform The uniform to set
  983. * @param texture The render target texture containing the depth stencil texture to apply
  984. */
  985. public setDepthStencilTexture(channel: number, uniform: Nullable<WebGLUniformLocation>, texture: Nullable<RenderTargetTexture>): void {
  986. if (channel === undefined) {
  987. return;
  988. }
  989. if (uniform) {
  990. this._boundUniforms[channel] = uniform;
  991. }
  992. if (!texture || !texture.depthStencilTexture) {
  993. this._setTexture(channel, null);
  994. }
  995. else {
  996. this._setTexture(channel, texture, false, true);
  997. }
  998. }
  999. /**
  1000. * Sets a texture to the webGL context from a postprocess
  1001. * @param channel defines the channel to use
  1002. * @param postProcess defines the source postprocess
  1003. */
  1004. public setTextureFromPostProcess(channel: number, postProcess: Nullable<PostProcess>): void {
  1005. this._bindTexture(channel, postProcess ? postProcess._textures.data[postProcess._currentRenderTextureInd] : null);
  1006. }
  1007. /**
  1008. * Binds the output of the passed in post process to the texture channel specified
  1009. * @param channel The channel the texture should be bound to
  1010. * @param postProcess The post process which's output should be bound
  1011. */
  1012. public setTextureFromPostProcessOutput(channel: number, postProcess: Nullable<PostProcess>): void {
  1013. this._bindTexture(channel, postProcess ? postProcess._outputTexture : null);
  1014. }
  1015. protected _rebuildBuffers(): void {
  1016. // Index / Vertex
  1017. for (var scene of this.scenes) {
  1018. scene.resetCachedMaterial();
  1019. scene._rebuildGeometries();
  1020. scene._rebuildTextures();
  1021. }
  1022. super._rebuildBuffers();
  1023. }
  1024. /** @hidden */
  1025. public _renderFrame() {
  1026. for (var index = 0; index < this._activeRenderLoops.length; index++) {
  1027. var renderFunction = this._activeRenderLoops[index];
  1028. renderFunction();
  1029. }
  1030. }
  1031. public _renderLoop(): void {
  1032. if (!this._contextWasLost) {
  1033. var shouldRender = true;
  1034. if (!this.renderEvenInBackground && this._windowIsBackground) {
  1035. shouldRender = false;
  1036. }
  1037. if (shouldRender) {
  1038. // Start new frame
  1039. this.beginFrame();
  1040. // Child canvases
  1041. if (!this._renderViews()) {
  1042. // Main frame
  1043. this._renderFrame();
  1044. }
  1045. // Present
  1046. this.endFrame();
  1047. }
  1048. }
  1049. if (this._activeRenderLoops.length > 0) {
  1050. // Register new frame
  1051. if (this.customAnimationFrameRequester) {
  1052. this.customAnimationFrameRequester.requestID = this._queueNewFrame(this.customAnimationFrameRequester.renderFunction || this._boundRenderFunction, this.customAnimationFrameRequester);
  1053. this._frameHandler = this.customAnimationFrameRequester.requestID;
  1054. } else if (this.isVRPresenting()) {
  1055. this._requestVRFrame();
  1056. } else {
  1057. this._frameHandler = this._queueNewFrame(this._boundRenderFunction, this.getHostWindow());
  1058. }
  1059. } else {
  1060. this._renderingQueueLaunched = false;
  1061. }
  1062. }
  1063. /** @hidden */
  1064. public _renderViews() {
  1065. return false;
  1066. }
  1067. /**
  1068. * Toggle full screen mode
  1069. * @param requestPointerLock defines if a pointer lock should be requested from the user
  1070. */
  1071. public switchFullscreen(requestPointerLock: boolean): void {
  1072. if (this.isFullscreen) {
  1073. this.exitFullscreen();
  1074. } else {
  1075. this.enterFullscreen(requestPointerLock);
  1076. }
  1077. }
  1078. /**
  1079. * Enters full screen mode
  1080. * @param requestPointerLock defines if a pointer lock should be requested from the user
  1081. */
  1082. public enterFullscreen(requestPointerLock: boolean): void {
  1083. if (!this.isFullscreen) {
  1084. this._pointerLockRequested = requestPointerLock;
  1085. if (this._renderingCanvas) {
  1086. Engine._RequestFullscreen(this._renderingCanvas);
  1087. }
  1088. }
  1089. }
  1090. /**
  1091. * Exits full screen mode
  1092. */
  1093. public exitFullscreen(): void {
  1094. if (this.isFullscreen) {
  1095. Engine._ExitFullscreen();
  1096. }
  1097. }
  1098. /**
  1099. * Enters Pointerlock mode
  1100. */
  1101. public enterPointerlock(): void {
  1102. if (this._renderingCanvas) {
  1103. Engine._RequestPointerlock(this._renderingCanvas);
  1104. }
  1105. }
  1106. /**
  1107. * Exits Pointerlock mode
  1108. */
  1109. public exitPointerlock(): void {
  1110. Engine._ExitPointerlock();
  1111. }
  1112. /**
  1113. * Begin a new frame
  1114. */
  1115. public beginFrame(): void {
  1116. this._measureFps();
  1117. this.onBeginFrameObservable.notifyObservers(this);
  1118. super.beginFrame();
  1119. }
  1120. /**
  1121. * Enf the current frame
  1122. */
  1123. public endFrame(): void {
  1124. super.endFrame();
  1125. this._submitVRFrame();
  1126. this.onEndFrameObservable.notifyObservers(this);
  1127. }
  1128. public resize(): void {
  1129. // We're not resizing the size of the canvas while in VR mode & presenting
  1130. if (this.isVRPresenting()) {
  1131. return;
  1132. }
  1133. super.resize();
  1134. }
  1135. /**
  1136. * Force a specific size of the canvas
  1137. * @param width defines the new canvas' width
  1138. * @param height defines the new canvas' height
  1139. * @returns true if the size was changed
  1140. */
  1141. public setSize(width: number, height: number): boolean {
  1142. if (!this._renderingCanvas) {
  1143. return false;
  1144. }
  1145. if (!super.setSize(width, height)) {
  1146. return false;
  1147. }
  1148. if (this.scenes) {
  1149. for (var index = 0; index < this.scenes.length; index++) {
  1150. var scene = this.scenes[index];
  1151. for (var camIndex = 0; camIndex < scene.cameras.length; camIndex++) {
  1152. var cam = scene.cameras[camIndex];
  1153. cam._currentRenderId = 0;
  1154. }
  1155. }
  1156. if (this.onResizeObservable.hasObservers()) {
  1157. this.onResizeObservable.notifyObservers(this);
  1158. }
  1159. }
  1160. return true;
  1161. }
  1162. public _deletePipelineContext(pipelineContext: IPipelineContext): void {
  1163. let webGLPipelineContext = pipelineContext as WebGLPipelineContext;
  1164. if (webGLPipelineContext && webGLPipelineContext.program) {
  1165. if (webGLPipelineContext.transformFeedback) {
  1166. this.deleteTransformFeedback(webGLPipelineContext.transformFeedback);
  1167. webGLPipelineContext.transformFeedback = null;
  1168. }
  1169. }
  1170. super._deletePipelineContext(pipelineContext);
  1171. }
  1172. public createShaderProgram(pipelineContext: IPipelineContext, vertexCode: string, fragmentCode: string, defines: Nullable<string>, context?: WebGLRenderingContext, transformFeedbackVaryings: Nullable<string[]> = null): WebGLProgram {
  1173. context = context || this._gl;
  1174. this.onBeforeShaderCompilationObservable.notifyObservers(this);
  1175. let program = super.createShaderProgram(pipelineContext, vertexCode, fragmentCode, defines, context, transformFeedbackVaryings);
  1176. this.onAfterShaderCompilationObservable.notifyObservers(this);
  1177. return program;
  1178. }
  1179. protected _createShaderProgram(pipelineContext: WebGLPipelineContext, vertexShader: WebGLShader, fragmentShader: WebGLShader, context: WebGLRenderingContext, transformFeedbackVaryings: Nullable<string[]> = null): WebGLProgram {
  1180. var shaderProgram = context.createProgram();
  1181. pipelineContext.program = shaderProgram;
  1182. if (!shaderProgram) {
  1183. throw new Error("Unable to create program");
  1184. }
  1185. context.attachShader(shaderProgram, vertexShader);
  1186. context.attachShader(shaderProgram, fragmentShader);
  1187. if (this.webGLVersion > 1 && transformFeedbackVaryings) {
  1188. let transformFeedback = this.createTransformFeedback();
  1189. this.bindTransformFeedback(transformFeedback);
  1190. this.setTranformFeedbackVaryings(shaderProgram, transformFeedbackVaryings);
  1191. pipelineContext.transformFeedback = transformFeedback;
  1192. }
  1193. context.linkProgram(shaderProgram);
  1194. if (this.webGLVersion > 1 && transformFeedbackVaryings) {
  1195. this.bindTransformFeedback(null);
  1196. }
  1197. pipelineContext.context = context;
  1198. pipelineContext.vertexShader = vertexShader;
  1199. pipelineContext.fragmentShader = fragmentShader;
  1200. if (!pipelineContext.isParallelCompiled) {
  1201. this._finalizePipelineContext(pipelineContext);
  1202. }
  1203. return shaderProgram;
  1204. }
  1205. public _releaseTexture(texture: InternalTexture): void {
  1206. super._releaseTexture(texture);
  1207. // Set output texture of post process to null if the texture has been released/disposed
  1208. this.scenes.forEach((scene) => {
  1209. scene.postProcesses.forEach((postProcess) => {
  1210. if (postProcess._outputTexture == texture) {
  1211. postProcess._outputTexture = null;
  1212. }
  1213. });
  1214. scene.cameras.forEach((camera) => {
  1215. camera._postProcesses.forEach((postProcess) => {
  1216. if (postProcess) {
  1217. if (postProcess._outputTexture == texture) {
  1218. postProcess._outputTexture = null;
  1219. }
  1220. }
  1221. });
  1222. });
  1223. });
  1224. }
  1225. /**
  1226. * @hidden
  1227. * Rescales a texture
  1228. * @param source input texutre
  1229. * @param destination destination texture
  1230. * @param scene scene to use to render the resize
  1231. * @param internalFormat format to use when resizing
  1232. * @param onComplete callback to be called when resize has completed
  1233. */
  1234. public _rescaleTexture(source: InternalTexture, destination: InternalTexture, scene: Nullable<any>, internalFormat: number, onComplete: () => void): void {
  1235. this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_MAG_FILTER, this._gl.LINEAR);
  1236. this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_MIN_FILTER, this._gl.LINEAR);
  1237. this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_WRAP_S, this._gl.CLAMP_TO_EDGE);
  1238. this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_WRAP_T, this._gl.CLAMP_TO_EDGE);
  1239. let rtt = this.createRenderTargetTexture({
  1240. width: destination.width,
  1241. height: destination.height,
  1242. }, {
  1243. generateMipMaps: false,
  1244. type: Constants.TEXTURETYPE_UNSIGNED_INT,
  1245. samplingMode: Constants.TEXTURE_BILINEAR_SAMPLINGMODE,
  1246. generateDepthBuffer: false,
  1247. generateStencilBuffer: false
  1248. }
  1249. );
  1250. if (!this._rescalePostProcess && Engine._RescalePostProcessFactory) {
  1251. this._rescalePostProcess = Engine._RescalePostProcessFactory(this);
  1252. }
  1253. this._rescalePostProcess.getEffect().executeWhenCompiled(() => {
  1254. this._rescalePostProcess.onApply = function(effect) {
  1255. effect._bindTexture("textureSampler", source);
  1256. };
  1257. let hostingScene: Scene = scene;
  1258. if (!hostingScene) {
  1259. hostingScene = this.scenes[this.scenes.length - 1];
  1260. }
  1261. hostingScene.postProcessManager.directRender([this._rescalePostProcess], rtt, true);
  1262. this._bindTextureDirectly(this._gl.TEXTURE_2D, destination, true);
  1263. this._gl.copyTexImage2D(this._gl.TEXTURE_2D, 0, internalFormat, 0, 0, destination.width, destination.height, 0);
  1264. this.unBindFramebuffer(rtt);
  1265. this._releaseTexture(rtt);
  1266. if (onComplete) {
  1267. onComplete();
  1268. }
  1269. });
  1270. }
  1271. // FPS
  1272. /**
  1273. * Gets the current framerate
  1274. * @returns a number representing the framerate
  1275. */
  1276. public getFps(): number {
  1277. return this._fps;
  1278. }
  1279. /**
  1280. * Gets the time spent between current and previous frame
  1281. * @returns a number representing the delta time in ms
  1282. */
  1283. public getDeltaTime(): number {
  1284. return this._deltaTime;
  1285. }
  1286. private _measureFps(): void {
  1287. this._performanceMonitor.sampleFrame();
  1288. this._fps = this._performanceMonitor.averageFPS;
  1289. this._deltaTime = this._performanceMonitor.instantaneousFrameTime || 0;
  1290. }
  1291. /** @hidden */
  1292. public _uploadImageToTexture(texture: InternalTexture, image: HTMLImageElement | ImageBitmap, faceIndex: number = 0, lod: number = 0) {
  1293. var gl = this._gl;
  1294. var textureType = this._getWebGLTextureType(texture.type);
  1295. var format = this._getInternalFormat(texture.format);
  1296. var internalFormat = this._getRGBABufferInternalSizedFormat(texture.type, format);
  1297. var bindTarget = texture.isCube ? gl.TEXTURE_CUBE_MAP : gl.TEXTURE_2D;
  1298. this._bindTextureDirectly(bindTarget, texture, true);
  1299. this._unpackFlipY(texture.invertY);
  1300. var target = gl.TEXTURE_2D;
  1301. if (texture.isCube) {
  1302. target = gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex;
  1303. }
  1304. gl.texImage2D(target, lod, internalFormat, format, textureType, image);
  1305. this._bindTextureDirectly(bindTarget, null, true);
  1306. }
  1307. /**
  1308. * Updates the sample count of a render target texture
  1309. * @see https://doc.babylonjs.com/features/webgl2#multisample-render-targets
  1310. * @param texture defines the texture to update
  1311. * @param samples defines the sample count to set
  1312. * @returns the effective sample count (could be 0 if multisample render targets are not supported)
  1313. */
  1314. public updateRenderTargetTextureSampleCount(texture: Nullable<InternalTexture>, samples: number): number {
  1315. if (this.webGLVersion < 2 || !texture) {
  1316. return 1;
  1317. }
  1318. if (texture.samples === samples) {
  1319. return samples;
  1320. }
  1321. var gl = this._gl;
  1322. samples = Math.min(samples, this.getCaps().maxMSAASamples);
  1323. // Dispose previous render buffers
  1324. if (texture._depthStencilBuffer) {
  1325. gl.deleteRenderbuffer(texture._depthStencilBuffer);
  1326. texture._depthStencilBuffer = null;
  1327. }
  1328. if (texture._MSAAFramebuffer) {
  1329. gl.deleteFramebuffer(texture._MSAAFramebuffer);
  1330. texture._MSAAFramebuffer = null;
  1331. }
  1332. if (texture._MSAARenderBuffer) {
  1333. gl.deleteRenderbuffer(texture._MSAARenderBuffer);
  1334. texture._MSAARenderBuffer = null;
  1335. }
  1336. if (samples > 1 && gl.renderbufferStorageMultisample) {
  1337. let framebuffer = gl.createFramebuffer();
  1338. if (!framebuffer) {
  1339. throw new Error("Unable to create multi sampled framebuffer");
  1340. }
  1341. texture._MSAAFramebuffer = framebuffer;
  1342. this._bindUnboundFramebuffer(texture._MSAAFramebuffer);
  1343. var colorRenderbuffer = gl.createRenderbuffer();
  1344. if (!colorRenderbuffer) {
  1345. throw new Error("Unable to create multi sampled framebuffer");
  1346. }
  1347. gl.bindRenderbuffer(gl.RENDERBUFFER, colorRenderbuffer);
  1348. gl.renderbufferStorageMultisample(gl.RENDERBUFFER, samples, this._getRGBAMultiSampleBufferFormat(texture.type), texture.width, texture.height);
  1349. gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorRenderbuffer);
  1350. texture._MSAARenderBuffer = colorRenderbuffer;
  1351. } else {
  1352. this._bindUnboundFramebuffer(texture._framebuffer);
  1353. }
  1354. texture.samples = samples;
  1355. texture._depthStencilBuffer = this._setupFramebufferDepthAttachments(texture._generateStencilBuffer, texture._generateDepthBuffer, texture.width, texture.height, samples);
  1356. this._bindUnboundFramebuffer(null);
  1357. return samples;
  1358. }
  1359. /**
  1360. * Updates a depth texture Comparison Mode and Function.
  1361. * If the comparison Function is equal to 0, the mode will be set to none.
  1362. * Otherwise, this only works in webgl 2 and requires a shadow sampler in the shader.
  1363. * @param texture The texture to set the comparison function for
  1364. * @param comparisonFunction The comparison function to set, 0 if no comparison required
  1365. */
  1366. public updateTextureComparisonFunction(texture: InternalTexture, comparisonFunction: number): void {
  1367. if (this.webGLVersion === 1) {
  1368. Logger.Error("WebGL 1 does not support texture comparison.");
  1369. return;
  1370. }
  1371. var gl = this._gl;
  1372. if (texture.isCube) {
  1373. this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, texture, true);
  1374. if (comparisonFunction === 0) {
  1375. gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_COMPARE_FUNC, Constants.LEQUAL);
  1376. gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_COMPARE_MODE, gl.NONE);
  1377. }
  1378. else {
  1379. gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_COMPARE_FUNC, comparisonFunction);
  1380. gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_COMPARE_MODE, gl.COMPARE_REF_TO_TEXTURE);
  1381. }
  1382. this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, null);
  1383. } else {
  1384. this._bindTextureDirectly(this._gl.TEXTURE_2D, texture, true);
  1385. if (comparisonFunction === 0) {
  1386. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_COMPARE_FUNC, Constants.LEQUAL);
  1387. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_COMPARE_MODE, gl.NONE);
  1388. }
  1389. else {
  1390. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_COMPARE_FUNC, comparisonFunction);
  1391. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_COMPARE_MODE, gl.COMPARE_REF_TO_TEXTURE);
  1392. }
  1393. this._bindTextureDirectly(this._gl.TEXTURE_2D, null);
  1394. }
  1395. texture._comparisonFunction = comparisonFunction;
  1396. }
  1397. /**
  1398. * Creates a webGL buffer to use with instanciation
  1399. * @param capacity defines the size of the buffer
  1400. * @returns the webGL buffer
  1401. */
  1402. public createInstancesBuffer(capacity: number): DataBuffer {
  1403. var buffer = this._gl.createBuffer();
  1404. if (!buffer) {
  1405. throw new Error("Unable to create instance buffer");
  1406. }
  1407. var result = new WebGLDataBuffer(buffer);
  1408. result.capacity = capacity;
  1409. this.bindArrayBuffer(result);
  1410. this._gl.bufferData(this._gl.ARRAY_BUFFER, capacity, this._gl.DYNAMIC_DRAW);
  1411. return result;
  1412. }
  1413. /**
  1414. * Delete a webGL buffer used with instanciation
  1415. * @param buffer defines the webGL buffer to delete
  1416. */
  1417. public deleteInstancesBuffer(buffer: WebGLBuffer): void {
  1418. this._gl.deleteBuffer(buffer);
  1419. }
  1420. private _clientWaitAsync(sync: WebGLSync, flags = 0, interval_ms = 10) {
  1421. let gl = <WebGL2RenderingContext>(this._gl as any);
  1422. return new Promise((resolve, reject) => {
  1423. let check = () => {
  1424. const res = gl.clientWaitSync(sync, flags, 0);
  1425. if (res == gl.WAIT_FAILED) {
  1426. reject();
  1427. return;
  1428. }
  1429. if (res == gl.TIMEOUT_EXPIRED) {
  1430. setTimeout(check, interval_ms);
  1431. return;
  1432. }
  1433. resolve();
  1434. };
  1435. check();
  1436. });
  1437. }
  1438. /** @hidden */
  1439. public _readPixelsAsync(x: number, y: number, w: number, h: number, format: number, type: number, outputBuffer: ArrayBufferView) {
  1440. if (this._webGLVersion < 2) {
  1441. throw new Error("_readPixelsAsync only work on WebGL2+");
  1442. }
  1443. let gl = <WebGL2RenderingContext>(this._gl as any);
  1444. const buf = gl.createBuffer();
  1445. gl.bindBuffer(gl.PIXEL_PACK_BUFFER, buf);
  1446. gl.bufferData(gl.PIXEL_PACK_BUFFER, outputBuffer.byteLength, gl.STREAM_READ);
  1447. gl.readPixels(x, y, w, h, format, type, 0);
  1448. gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);
  1449. const sync = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0);
  1450. if (!sync) {
  1451. return null;
  1452. }
  1453. gl.flush();
  1454. return this._clientWaitAsync(sync, 0, 10).then(() => {
  1455. gl.deleteSync(sync);
  1456. gl.bindBuffer(gl.PIXEL_PACK_BUFFER, buf);
  1457. gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 0, outputBuffer);
  1458. gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);
  1459. gl.deleteBuffer(buf);
  1460. return outputBuffer;
  1461. });
  1462. }
  1463. public dispose(): void {
  1464. this.hideLoadingUI();
  1465. this.onNewSceneAddedObservable.clear();
  1466. // Release postProcesses
  1467. while (this.postProcesses.length) {
  1468. this.postProcesses[0].dispose();
  1469. }
  1470. // Rescale PP
  1471. if (this._rescalePostProcess) {
  1472. this._rescalePostProcess.dispose();
  1473. }
  1474. // Release scenes
  1475. while (this.scenes.length) {
  1476. this.scenes[0].dispose();
  1477. }
  1478. // Release audio engine
  1479. if (Engine.Instances.length === 1 && Engine.audioEngine) {
  1480. Engine.audioEngine.dispose();
  1481. }
  1482. //WebVR
  1483. this.disableVR();
  1484. // Events
  1485. if (DomManagement.IsWindowObjectExist()) {
  1486. window.removeEventListener("blur", this._onBlur);
  1487. window.removeEventListener("focus", this._onFocus);
  1488. if (this._renderingCanvas) {
  1489. this._renderingCanvas.removeEventListener("focus", this._onCanvasFocus);
  1490. this._renderingCanvas.removeEventListener("blur", this._onCanvasBlur);
  1491. this._renderingCanvas.removeEventListener("pointerout", this._onCanvasPointerOut);
  1492. }
  1493. if (DomManagement.IsDocumentAvailable()) {
  1494. document.removeEventListener("fullscreenchange", this._onFullscreenChange);
  1495. document.removeEventListener("mozfullscreenchange", this._onFullscreenChange);
  1496. document.removeEventListener("webkitfullscreenchange", this._onFullscreenChange);
  1497. document.removeEventListener("msfullscreenchange", this._onFullscreenChange);
  1498. document.removeEventListener("pointerlockchange", this._onPointerLockChange);
  1499. document.removeEventListener("mspointerlockchange", this._onPointerLockChange);
  1500. document.removeEventListener("mozpointerlockchange", this._onPointerLockChange);
  1501. document.removeEventListener("webkitpointerlockchange", this._onPointerLockChange);
  1502. }
  1503. }
  1504. super.dispose();
  1505. // Remove from Instances
  1506. var index = Engine.Instances.indexOf(this);
  1507. if (index >= 0) {
  1508. Engine.Instances.splice(index, 1);
  1509. }
  1510. // Observables
  1511. this.onResizeObservable.clear();
  1512. this.onCanvasBlurObservable.clear();
  1513. this.onCanvasFocusObservable.clear();
  1514. this.onCanvasPointerOutObservable.clear();
  1515. this.onBeginFrameObservable.clear();
  1516. this.onEndFrameObservable.clear();
  1517. }
  1518. private _disableTouchAction(): void {
  1519. if (!this._renderingCanvas || !this._renderingCanvas.setAttribute) {
  1520. return;
  1521. }
  1522. this._renderingCanvas.setAttribute("touch-action", "none");
  1523. this._renderingCanvas.style.touchAction = "none";
  1524. (this._renderingCanvas.style as any).msTouchAction = "none";
  1525. }
  1526. // Loading screen
  1527. /**
  1528. * Display the loading screen
  1529. * @see https://doc.babylonjs.com/how_to/creating_a_custom_loading_screen
  1530. */
  1531. public displayLoadingUI(): void {
  1532. if (!DomManagement.IsWindowObjectExist()) {
  1533. return;
  1534. }
  1535. const loadingScreen = this.loadingScreen;
  1536. if (loadingScreen) {
  1537. loadingScreen.displayLoadingUI();
  1538. }
  1539. }
  1540. /**
  1541. * Hide the loading screen
  1542. * @see https://doc.babylonjs.com/how_to/creating_a_custom_loading_screen
  1543. */
  1544. public hideLoadingUI(): void {
  1545. if (!DomManagement.IsWindowObjectExist()) {
  1546. return;
  1547. }
  1548. const loadingScreen = this._loadingScreen;
  1549. if (loadingScreen) {
  1550. loadingScreen.hideLoadingUI();
  1551. }
  1552. }
  1553. /**
  1554. * Gets the current loading screen object
  1555. * @see https://doc.babylonjs.com/how_to/creating_a_custom_loading_screen
  1556. */
  1557. public get loadingScreen(): ILoadingScreen {
  1558. if (!this._loadingScreen && this._renderingCanvas) {
  1559. this._loadingScreen = Engine.DefaultLoadingScreenFactory(this._renderingCanvas);
  1560. }
  1561. return this._loadingScreen;
  1562. }
  1563. /**
  1564. * Sets the current loading screen object
  1565. * @see https://doc.babylonjs.com/how_to/creating_a_custom_loading_screen
  1566. */
  1567. public set loadingScreen(loadingScreen: ILoadingScreen) {
  1568. this._loadingScreen = loadingScreen;
  1569. }
  1570. /**
  1571. * Sets the current loading screen text
  1572. * @see https://doc.babylonjs.com/how_to/creating_a_custom_loading_screen
  1573. */
  1574. public set loadingUIText(text: string) {
  1575. this.loadingScreen.loadingUIText = text;
  1576. }
  1577. /**
  1578. * Sets the current loading screen background color
  1579. * @see https://doc.babylonjs.com/how_to/creating_a_custom_loading_screen
  1580. */
  1581. public set loadingUIBackgroundColor(color: string) {
  1582. this.loadingScreen.loadingUIBackgroundColor = color;
  1583. }
  1584. /** Pointerlock and fullscreen */
  1585. /**
  1586. * Ask the browser to promote the current element to pointerlock mode
  1587. * @param element defines the DOM element to promote
  1588. */
  1589. static _RequestPointerlock(element: HTMLElement): void {
  1590. element.requestPointerLock = element.requestPointerLock || (<any>element).msRequestPointerLock || (<any>element).mozRequestPointerLock || (<any>element).webkitRequestPointerLock;
  1591. if (element.requestPointerLock) {
  1592. element.requestPointerLock();
  1593. }
  1594. }
  1595. /**
  1596. * Asks the browser to exit pointerlock mode
  1597. */
  1598. static _ExitPointerlock(): void {
  1599. let anyDoc = document as any;
  1600. document.exitPointerLock = document.exitPointerLock || anyDoc.msExitPointerLock || anyDoc.mozExitPointerLock || anyDoc.webkitExitPointerLock;
  1601. if (document.exitPointerLock) {
  1602. document.exitPointerLock();
  1603. }
  1604. }
  1605. /**
  1606. * Ask the browser to promote the current element to fullscreen rendering mode
  1607. * @param element defines the DOM element to promote
  1608. */
  1609. static _RequestFullscreen(element: HTMLElement): void {
  1610. var requestFunction = element.requestFullscreen || (<any>element).msRequestFullscreen || (<any>element).webkitRequestFullscreen || (<any>element).mozRequestFullScreen;
  1611. if (!requestFunction) { return; }
  1612. requestFunction.call(element);
  1613. }
  1614. /**
  1615. * Asks the browser to exit fullscreen mode
  1616. */
  1617. static _ExitFullscreen(): void {
  1618. let anyDoc = document as any;
  1619. if (document.exitFullscreen) {
  1620. document.exitFullscreen();
  1621. }
  1622. else if (anyDoc.mozCancelFullScreen) {
  1623. anyDoc.mozCancelFullScreen();
  1624. }
  1625. else if (anyDoc.webkitCancelFullScreen) {
  1626. anyDoc.webkitCancelFullScreen();
  1627. }
  1628. else if (anyDoc.msCancelFullScreen) {
  1629. anyDoc.msCancelFullScreen();
  1630. }
  1631. }
  1632. }