engine.ts 76 KB

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