engine.ts 78 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027
  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. declare type Material = import("../Materials/material").Material;
  25. declare type PostProcess = import("../PostProcesses/postProcess").PostProcess;
  26. /**
  27. * Defines the interface used by display changed events
  28. */
  29. export interface IDisplayChangedEventArgs {
  30. /** Gets the vrDisplay object (if any) */
  31. vrDisplay: Nullable<any>;
  32. /** Gets a boolean indicating if webVR is supported */
  33. vrSupported: boolean;
  34. }
  35. /**
  36. * Defines the interface used by objects containing a viewport (like a camera)
  37. */
  38. interface IViewportOwnerLike {
  39. /**
  40. * Gets or sets the viewport
  41. */
  42. viewport: IViewportLike;
  43. }
  44. /**
  45. * The engine class is responsible for interfacing with all lower-level APIs such as WebGL and Audio
  46. */
  47. export class Engine extends ThinEngine {
  48. // Const statics
  49. /** Defines that alpha blending is disabled */
  50. public static readonly ALPHA_DISABLE = Constants.ALPHA_DISABLE;
  51. /** Defines that alpha blending to SRC ALPHA * SRC + DEST */
  52. public static readonly ALPHA_ADD = Constants.ALPHA_ADD;
  53. /** Defines that alpha blending to SRC ALPHA * SRC + (1 - SRC ALPHA) * DEST */
  54. public static readonly ALPHA_COMBINE = Constants.ALPHA_COMBINE;
  55. /** Defines that alpha blending to DEST - SRC * DEST */
  56. public static readonly ALPHA_SUBTRACT = Constants.ALPHA_SUBTRACT;
  57. /** Defines that alpha blending to SRC * DEST */
  58. public static readonly ALPHA_MULTIPLY = Constants.ALPHA_MULTIPLY;
  59. /** Defines that alpha blending to SRC ALPHA * SRC + (1 - SRC) * DEST */
  60. public static readonly ALPHA_MAXIMIZED = Constants.ALPHA_MAXIMIZED;
  61. /** Defines that alpha blending to SRC + DEST */
  62. public static readonly ALPHA_ONEONE = Constants.ALPHA_ONEONE;
  63. /** Defines that alpha blending to SRC + (1 - SRC ALPHA) * DEST */
  64. public static readonly ALPHA_PREMULTIPLIED = Constants.ALPHA_PREMULTIPLIED;
  65. /**
  66. * Defines that alpha blending to SRC + (1 - SRC ALPHA) * DEST
  67. * Alpha will be set to (1 - SRC ALPHA) * DEST ALPHA
  68. */
  69. public static readonly ALPHA_PREMULTIPLIED_PORTERDUFF = Constants.ALPHA_PREMULTIPLIED_PORTERDUFF;
  70. /** Defines that alpha blending to CST * SRC + (1 - CST) * DEST */
  71. public static readonly ALPHA_INTERPOLATE = Constants.ALPHA_INTERPOLATE;
  72. /**
  73. * Defines that alpha blending to SRC + (1 - SRC) * DEST
  74. * Alpha will be set to SRC ALPHA + (1 - SRC ALPHA) * DEST ALPHA
  75. */
  76. public static readonly ALPHA_SCREENMODE = Constants.ALPHA_SCREENMODE;
  77. /** Defines that the ressource is not delayed*/
  78. public static readonly DELAYLOADSTATE_NONE = Constants.DELAYLOADSTATE_NONE;
  79. /** Defines that the ressource was successfully delay loaded */
  80. public static readonly DELAYLOADSTATE_LOADED = Constants.DELAYLOADSTATE_LOADED;
  81. /** Defines that the ressource is currently delay loading */
  82. public static readonly DELAYLOADSTATE_LOADING = Constants.DELAYLOADSTATE_LOADING;
  83. /** Defines that the ressource is delayed and has not started loading */
  84. public static readonly DELAYLOADSTATE_NOTLOADED = Constants.DELAYLOADSTATE_NOTLOADED;
  85. // Depht or Stencil test Constants.
  86. /** Passed to depthFunction or stencilFunction to specify depth or stencil tests will never pass. i.e. Nothing will be drawn */
  87. public static readonly NEVER = Constants.NEVER;
  88. /** 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 */
  89. public static readonly ALWAYS = Constants.ALWAYS;
  90. /** Passed to depthFunction or stencilFunction to specify depth or stencil tests will pass if the new depth value is less than the stored value */
  91. public static readonly LESS = Constants.LESS;
  92. /** Passed to depthFunction or stencilFunction to specify depth or stencil tests will pass if the new depth value is equals to the stored value */
  93. public static readonly EQUAL = Constants.EQUAL;
  94. /** 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 */
  95. public static readonly LEQUAL = Constants.LEQUAL;
  96. /** Passed to depthFunction or stencilFunction to specify depth or stencil tests will pass if the new depth value is greater than the stored value */
  97. public static readonly GREATER = Constants.GREATER;
  98. /** 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 */
  99. public static readonly GEQUAL = Constants.GEQUAL;
  100. /** 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 */
  101. public static readonly NOTEQUAL = Constants.NOTEQUAL;
  102. // Stencil Actions Constants.
  103. /** Passed to stencilOperation to specify that stencil value must be kept */
  104. public static readonly KEEP = Constants.KEEP;
  105. /** Passed to stencilOperation to specify that stencil value must be replaced */
  106. public static readonly REPLACE = Constants.REPLACE;
  107. /** Passed to stencilOperation to specify that stencil value must be incremented */
  108. public static readonly INCR = Constants.INCR;
  109. /** Passed to stencilOperation to specify that stencil value must be decremented */
  110. public static readonly DECR = Constants.DECR;
  111. /** Passed to stencilOperation to specify that stencil value must be inverted */
  112. public static readonly INVERT = Constants.INVERT;
  113. /** Passed to stencilOperation to specify that stencil value must be incremented with wrapping */
  114. public static readonly INCR_WRAP = Constants.INCR_WRAP;
  115. /** Passed to stencilOperation to specify that stencil value must be decremented with wrapping */
  116. public static readonly DECR_WRAP = Constants.DECR_WRAP;
  117. /** Texture is not repeating outside of 0..1 UVs */
  118. public static readonly TEXTURE_CLAMP_ADDRESSMODE = Constants.TEXTURE_CLAMP_ADDRESSMODE;
  119. /** Texture is repeating outside of 0..1 UVs */
  120. public static readonly TEXTURE_WRAP_ADDRESSMODE = Constants.TEXTURE_WRAP_ADDRESSMODE;
  121. /** Texture is repeating and mirrored */
  122. public static readonly TEXTURE_MIRROR_ADDRESSMODE = Constants.TEXTURE_MIRROR_ADDRESSMODE;
  123. /** ALPHA */
  124. public static readonly TEXTUREFORMAT_ALPHA = Constants.TEXTUREFORMAT_ALPHA;
  125. /** LUMINANCE */
  126. public static readonly TEXTUREFORMAT_LUMINANCE = Constants.TEXTUREFORMAT_LUMINANCE;
  127. /** LUMINANCE_ALPHA */
  128. public static readonly TEXTUREFORMAT_LUMINANCE_ALPHA = Constants.TEXTUREFORMAT_LUMINANCE_ALPHA;
  129. /** RGB */
  130. public static readonly TEXTUREFORMAT_RGB = Constants.TEXTUREFORMAT_RGB;
  131. /** RGBA */
  132. public static readonly TEXTUREFORMAT_RGBA = Constants.TEXTUREFORMAT_RGBA;
  133. /** RED */
  134. public static readonly TEXTUREFORMAT_RED = Constants.TEXTUREFORMAT_RED;
  135. /** RED (2nd reference) */
  136. public static readonly TEXTUREFORMAT_R = Constants.TEXTUREFORMAT_R;
  137. /** RG */
  138. public static readonly TEXTUREFORMAT_RG = Constants.TEXTUREFORMAT_RG;
  139. /** RED_INTEGER */
  140. public static readonly TEXTUREFORMAT_RED_INTEGER = Constants.TEXTUREFORMAT_RED_INTEGER;
  141. /** RED_INTEGER (2nd reference) */
  142. public static readonly TEXTUREFORMAT_R_INTEGER = Constants.TEXTUREFORMAT_R_INTEGER;
  143. /** RG_INTEGER */
  144. public static readonly TEXTUREFORMAT_RG_INTEGER = Constants.TEXTUREFORMAT_RG_INTEGER;
  145. /** RGB_INTEGER */
  146. public static readonly TEXTUREFORMAT_RGB_INTEGER = Constants.TEXTUREFORMAT_RGB_INTEGER;
  147. /** RGBA_INTEGER */
  148. public static readonly TEXTUREFORMAT_RGBA_INTEGER = Constants.TEXTUREFORMAT_RGBA_INTEGER;
  149. /** UNSIGNED_BYTE */
  150. public static readonly TEXTURETYPE_UNSIGNED_BYTE = Constants.TEXTURETYPE_UNSIGNED_BYTE;
  151. /** UNSIGNED_BYTE (2nd reference) */
  152. public static readonly TEXTURETYPE_UNSIGNED_INT = Constants.TEXTURETYPE_UNSIGNED_INT;
  153. /** FLOAT */
  154. public static readonly TEXTURETYPE_FLOAT = Constants.TEXTURETYPE_FLOAT;
  155. /** HALF_FLOAT */
  156. public static readonly TEXTURETYPE_HALF_FLOAT = Constants.TEXTURETYPE_HALF_FLOAT;
  157. /** BYTE */
  158. public static readonly TEXTURETYPE_BYTE = Constants.TEXTURETYPE_BYTE;
  159. /** SHORT */
  160. public static readonly TEXTURETYPE_SHORT = Constants.TEXTURETYPE_SHORT;
  161. /** UNSIGNED_SHORT */
  162. public static readonly TEXTURETYPE_UNSIGNED_SHORT = Constants.TEXTURETYPE_UNSIGNED_SHORT;
  163. /** INT */
  164. public static readonly TEXTURETYPE_INT = Constants.TEXTURETYPE_INT;
  165. /** UNSIGNED_INT */
  166. public static readonly TEXTURETYPE_UNSIGNED_INTEGER = Constants.TEXTURETYPE_UNSIGNED_INTEGER;
  167. /** UNSIGNED_SHORT_4_4_4_4 */
  168. public static readonly TEXTURETYPE_UNSIGNED_SHORT_4_4_4_4 = Constants.TEXTURETYPE_UNSIGNED_SHORT_4_4_4_4;
  169. /** UNSIGNED_SHORT_5_5_5_1 */
  170. public static readonly TEXTURETYPE_UNSIGNED_SHORT_5_5_5_1 = Constants.TEXTURETYPE_UNSIGNED_SHORT_5_5_5_1;
  171. /** UNSIGNED_SHORT_5_6_5 */
  172. public static readonly TEXTURETYPE_UNSIGNED_SHORT_5_6_5 = Constants.TEXTURETYPE_UNSIGNED_SHORT_5_6_5;
  173. /** UNSIGNED_INT_2_10_10_10_REV */
  174. public static readonly TEXTURETYPE_UNSIGNED_INT_2_10_10_10_REV = Constants.TEXTURETYPE_UNSIGNED_INT_2_10_10_10_REV;
  175. /** UNSIGNED_INT_24_8 */
  176. public static readonly TEXTURETYPE_UNSIGNED_INT_24_8 = Constants.TEXTURETYPE_UNSIGNED_INT_24_8;
  177. /** UNSIGNED_INT_10F_11F_11F_REV */
  178. public static readonly TEXTURETYPE_UNSIGNED_INT_10F_11F_11F_REV = Constants.TEXTURETYPE_UNSIGNED_INT_10F_11F_11F_REV;
  179. /** UNSIGNED_INT_5_9_9_9_REV */
  180. public static readonly TEXTURETYPE_UNSIGNED_INT_5_9_9_9_REV = Constants.TEXTURETYPE_UNSIGNED_INT_5_9_9_9_REV;
  181. /** FLOAT_32_UNSIGNED_INT_24_8_REV */
  182. public static readonly TEXTURETYPE_FLOAT_32_UNSIGNED_INT_24_8_REV = Constants.TEXTURETYPE_FLOAT_32_UNSIGNED_INT_24_8_REV;
  183. /** nearest is mag = nearest and min = nearest and mip = linear */
  184. public static readonly TEXTURE_NEAREST_SAMPLINGMODE = Constants.TEXTURE_NEAREST_SAMPLINGMODE;
  185. /** Bilinear is mag = linear and min = linear and mip = nearest */
  186. public static readonly TEXTURE_BILINEAR_SAMPLINGMODE = Constants.TEXTURE_BILINEAR_SAMPLINGMODE;
  187. /** Trilinear is mag = linear and min = linear and mip = linear */
  188. public static readonly TEXTURE_TRILINEAR_SAMPLINGMODE = Constants.TEXTURE_TRILINEAR_SAMPLINGMODE;
  189. /** nearest is mag = nearest and min = nearest and mip = linear */
  190. public static readonly TEXTURE_NEAREST_NEAREST_MIPLINEAR = Constants.TEXTURE_NEAREST_NEAREST_MIPLINEAR;
  191. /** Bilinear is mag = linear and min = linear and mip = nearest */
  192. public static readonly TEXTURE_LINEAR_LINEAR_MIPNEAREST = Constants.TEXTURE_LINEAR_LINEAR_MIPNEAREST;
  193. /** Trilinear is mag = linear and min = linear and mip = linear */
  194. public static readonly TEXTURE_LINEAR_LINEAR_MIPLINEAR = Constants.TEXTURE_LINEAR_LINEAR_MIPLINEAR;
  195. /** mag = nearest and min = nearest and mip = nearest */
  196. public static readonly TEXTURE_NEAREST_NEAREST_MIPNEAREST = Constants.TEXTURE_NEAREST_NEAREST_MIPNEAREST;
  197. /** mag = nearest and min = linear and mip = nearest */
  198. public static readonly TEXTURE_NEAREST_LINEAR_MIPNEAREST = Constants.TEXTURE_NEAREST_LINEAR_MIPNEAREST;
  199. /** mag = nearest and min = linear and mip = linear */
  200. public static readonly TEXTURE_NEAREST_LINEAR_MIPLINEAR = Constants.TEXTURE_NEAREST_LINEAR_MIPLINEAR;
  201. /** mag = nearest and min = linear and mip = none */
  202. public static readonly TEXTURE_NEAREST_LINEAR = Constants.TEXTURE_NEAREST_LINEAR;
  203. /** mag = nearest and min = nearest and mip = none */
  204. public static readonly TEXTURE_NEAREST_NEAREST = Constants.TEXTURE_NEAREST_NEAREST;
  205. /** mag = linear and min = nearest and mip = nearest */
  206. public static readonly TEXTURE_LINEAR_NEAREST_MIPNEAREST = Constants.TEXTURE_LINEAR_NEAREST_MIPNEAREST;
  207. /** mag = linear and min = nearest and mip = linear */
  208. public static readonly TEXTURE_LINEAR_NEAREST_MIPLINEAR = Constants.TEXTURE_LINEAR_NEAREST_MIPLINEAR;
  209. /** mag = linear and min = linear and mip = none */
  210. public static readonly TEXTURE_LINEAR_LINEAR = Constants.TEXTURE_LINEAR_LINEAR;
  211. /** mag = linear and min = nearest and mip = none */
  212. public static readonly TEXTURE_LINEAR_NEAREST = Constants.TEXTURE_LINEAR_NEAREST;
  213. /** Explicit coordinates mode */
  214. public static readonly TEXTURE_EXPLICIT_MODE = Constants.TEXTURE_EXPLICIT_MODE;
  215. /** Spherical coordinates mode */
  216. public static readonly TEXTURE_SPHERICAL_MODE = Constants.TEXTURE_SPHERICAL_MODE;
  217. /** Planar coordinates mode */
  218. public static readonly TEXTURE_PLANAR_MODE = Constants.TEXTURE_PLANAR_MODE;
  219. /** Cubic coordinates mode */
  220. public static readonly TEXTURE_CUBIC_MODE = Constants.TEXTURE_CUBIC_MODE;
  221. /** Projection coordinates mode */
  222. public static readonly TEXTURE_PROJECTION_MODE = Constants.TEXTURE_PROJECTION_MODE;
  223. /** Skybox coordinates mode */
  224. public static readonly TEXTURE_SKYBOX_MODE = Constants.TEXTURE_SKYBOX_MODE;
  225. /** Inverse Cubic coordinates mode */
  226. public static readonly TEXTURE_INVCUBIC_MODE = Constants.TEXTURE_INVCUBIC_MODE;
  227. /** Equirectangular coordinates mode */
  228. public static readonly TEXTURE_EQUIRECTANGULAR_MODE = Constants.TEXTURE_EQUIRECTANGULAR_MODE;
  229. /** Equirectangular Fixed coordinates mode */
  230. public static readonly TEXTURE_FIXED_EQUIRECTANGULAR_MODE = Constants.TEXTURE_FIXED_EQUIRECTANGULAR_MODE;
  231. /** Equirectangular Fixed Mirrored coordinates mode */
  232. public static readonly TEXTURE_FIXED_EQUIRECTANGULAR_MIRRORED_MODE = Constants.TEXTURE_FIXED_EQUIRECTANGULAR_MIRRORED_MODE;
  233. // Texture rescaling mode
  234. /** Defines that texture rescaling will use a floor to find the closer power of 2 size */
  235. public static readonly SCALEMODE_FLOOR = Constants.SCALEMODE_FLOOR;
  236. /** Defines that texture rescaling will look for the nearest power of 2 size */
  237. public static readonly SCALEMODE_NEAREST = Constants.SCALEMODE_NEAREST;
  238. /** Defines that texture rescaling will use a ceil to find the closer power of 2 size */
  239. public static readonly SCALEMODE_CEILING = Constants.SCALEMODE_CEILING;
  240. /**
  241. * Returns the current npm package of the sdk
  242. */
  243. // Not mixed with Version for tooling purpose.
  244. public static get NpmPackage(): string {
  245. return ThinEngine.NpmPackage;
  246. }
  247. /**
  248. * Returns the current version of the framework
  249. */
  250. public static get Version(): string {
  251. return ThinEngine.Version;
  252. }
  253. /** Gets the list of created engines */
  254. public static get Instances(): Engine[] {
  255. return EngineStore.Instances;
  256. }
  257. /**
  258. * Gets the latest created engine
  259. */
  260. public static get LastCreatedEngine(): Nullable<Engine> {
  261. return EngineStore.LastCreatedEngine;
  262. }
  263. /**
  264. * Gets the latest created scene
  265. */
  266. public static get LastCreatedScene(): Nullable<Scene> {
  267. return EngineStore.LastCreatedScene;
  268. }
  269. /**
  270. * Will flag all materials in all scenes in all engines as dirty to trigger new shader compilation
  271. * @param flag defines which part of the materials must be marked as dirty
  272. * @param predicate defines a predicate used to filter which materials should be affected
  273. */
  274. public static MarkAllMaterialsAsDirty(flag: number, predicate?: (mat: Material) => boolean): void {
  275. for (var engineIndex = 0; engineIndex < Engine.Instances.length; engineIndex++) {
  276. var engine = Engine.Instances[engineIndex];
  277. for (var sceneIndex = 0; sceneIndex < engine.scenes.length; sceneIndex++) {
  278. engine.scenes[sceneIndex].markAllMaterialsAsDirty(flag, predicate);
  279. }
  280. }
  281. }
  282. /**
  283. * Method called to create the default loading screen.
  284. * This can be overriden in your own app.
  285. * @param canvas The rendering canvas element
  286. * @returns The loading screen
  287. */
  288. public static DefaultLoadingScreenFactory(canvas: HTMLCanvasElement): ILoadingScreen {
  289. throw _DevTools.WarnImport("LoadingScreen");
  290. }
  291. /**
  292. * Method called to create the default rescale post process on each engine.
  293. */
  294. public static _RescalePostProcessFactory: Nullable<(engine: Engine) => PostProcess> = null;
  295. // Members
  296. /**
  297. * Gets or sets a boolean to enable/disable IndexedDB support and avoid XHR on .manifest
  298. **/
  299. public enableOfflineSupport = false;
  300. /**
  301. * 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)
  302. **/
  303. public disableManifestCheck = false;
  304. /**
  305. * Gets the list of created scenes
  306. */
  307. public scenes = new Array<Scene>();
  308. /**
  309. * Event raised when a new scene is created
  310. */
  311. public onNewSceneAddedObservable = new Observable<Scene>();
  312. /**
  313. * Gets the list of created postprocesses
  314. */
  315. public postProcesses = new Array<PostProcess>();
  316. /**
  317. * Gets a boolean indicating if the pointer is currently locked
  318. */
  319. public isPointerLock = false;
  320. // Observables
  321. /**
  322. * Observable event triggered each time the rendering canvas is resized
  323. */
  324. public onResizeObservable = new Observable<Engine>();
  325. /**
  326. * Observable event triggered each time the canvas loses focus
  327. */
  328. public onCanvasBlurObservable = new Observable<Engine>();
  329. /**
  330. * Observable event triggered each time the canvas gains focus
  331. */
  332. public onCanvasFocusObservable = new Observable<Engine>();
  333. /**
  334. * Observable event triggered each time the canvas receives pointerout event
  335. */
  336. public onCanvasPointerOutObservable = new Observable<PointerEvent>();
  337. /**
  338. * Observable raised when the engine begins a new frame
  339. */
  340. public onBeginFrameObservable = new Observable<Engine>();
  341. /**
  342. * If set, will be used to request the next animation frame for the render loop
  343. */
  344. public customAnimationFrameRequester: Nullable<ICustomAnimationFrameRequester> = null;
  345. /**
  346. * Observable raised when the engine ends the current frame
  347. */
  348. public onEndFrameObservable = new Observable<Engine>();
  349. /**
  350. * Observable raised when the engine is about to compile a shader
  351. */
  352. public onBeforeShaderCompilationObservable = new Observable<Engine>();
  353. /**
  354. * Observable raised when the engine has jsut compiled a shader
  355. */
  356. public onAfterShaderCompilationObservable = new Observable<Engine>();
  357. /**
  358. * Gets the audio engine
  359. * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music
  360. * @ignorenaming
  361. */
  362. public static audioEngine: IAudioEngine;
  363. /**
  364. * Default AudioEngine factory responsible of creating the Audio Engine.
  365. * By default, this will create a BabylonJS Audio Engine if the workload has been embedded.
  366. */
  367. public static AudioEngineFactory: (hostElement: Nullable<HTMLElement>) => IAudioEngine;
  368. /**
  369. * Default offline support factory responsible of creating a tool used to store data locally.
  370. * By default, this will create a Database object if the workload has been embedded.
  371. */
  372. public static OfflineProviderFactory: (urlToScene: string, callbackManifestChecked: (checked: boolean) => any, disableManifestCheck: boolean) => IOfflineProvider;
  373. private _loadingScreen: ILoadingScreen;
  374. private _pointerLockRequested: boolean;
  375. private _dummyFramebuffer: WebGLFramebuffer;
  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 http://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 http://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 http://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 http://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. */
  1139. public setSize(width: number, height: number): void {
  1140. if (!this._renderingCanvas) {
  1141. return;
  1142. }
  1143. super.setSize(width, height);
  1144. if (this.scenes) {
  1145. for (var index = 0; index < this.scenes.length; index++) {
  1146. var scene = this.scenes[index];
  1147. for (var camIndex = 0; camIndex < scene.cameras.length; camIndex++) {
  1148. var cam = scene.cameras[camIndex];
  1149. cam._currentRenderId = 0;
  1150. }
  1151. }
  1152. if (this.onResizeObservable.hasObservers) {
  1153. this.onResizeObservable.notifyObservers(this);
  1154. }
  1155. }
  1156. }
  1157. /**
  1158. * Updates a dynamic vertex buffer.
  1159. * @param vertexBuffer the vertex buffer to update
  1160. * @param data the data used to update the vertex buffer
  1161. * @param byteOffset the byte offset of the data
  1162. * @param byteLength the byte length of the data
  1163. */
  1164. public updateDynamicVertexBuffer(vertexBuffer: DataBuffer, data: DataArray, byteOffset?: number, byteLength?: number): void {
  1165. this.bindArrayBuffer(vertexBuffer);
  1166. if (byteOffset === undefined) {
  1167. byteOffset = 0;
  1168. }
  1169. const dataLength = (data as number[]).length || (data as ArrayBuffer).byteLength;
  1170. if (byteLength === undefined || byteLength >= dataLength && byteOffset === 0) {
  1171. if (data instanceof Array) {
  1172. this._gl.bufferSubData(this._gl.ARRAY_BUFFER, byteOffset, new Float32Array(data));
  1173. } else {
  1174. this._gl.bufferSubData(this._gl.ARRAY_BUFFER, byteOffset, <ArrayBuffer>data);
  1175. }
  1176. } else {
  1177. if (data instanceof Array) {
  1178. this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, new Float32Array(data).subarray(byteOffset, byteOffset + byteLength));
  1179. } else {
  1180. if (data instanceof ArrayBuffer) {
  1181. data = new Uint8Array(data, byteOffset, byteLength);
  1182. } else {
  1183. data = new Uint8Array(data.buffer, data.byteOffset + byteOffset, byteLength);
  1184. }
  1185. this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, <ArrayBuffer>data);
  1186. }
  1187. }
  1188. this._resetVertexBufferBinding();
  1189. }
  1190. public _deletePipelineContext(pipelineContext: IPipelineContext): void {
  1191. let webGLPipelineContext = pipelineContext as WebGLPipelineContext;
  1192. if (webGLPipelineContext && webGLPipelineContext.program) {
  1193. if (webGLPipelineContext.transformFeedback) {
  1194. this.deleteTransformFeedback(webGLPipelineContext.transformFeedback);
  1195. webGLPipelineContext.transformFeedback = null;
  1196. }
  1197. }
  1198. super._deletePipelineContext(pipelineContext);
  1199. }
  1200. public createShaderProgram(pipelineContext: IPipelineContext, vertexCode: string, fragmentCode: string, defines: Nullable<string>, context?: WebGLRenderingContext, transformFeedbackVaryings: Nullable<string[]> = null): WebGLProgram {
  1201. context = context || this._gl;
  1202. this.onBeforeShaderCompilationObservable.notifyObservers(this);
  1203. let program = super.createShaderProgram(pipelineContext, vertexCode, fragmentCode, defines, context, transformFeedbackVaryings);
  1204. this.onAfterShaderCompilationObservable.notifyObservers(this);
  1205. return program;
  1206. }
  1207. protected _createShaderProgram(pipelineContext: WebGLPipelineContext, vertexShader: WebGLShader, fragmentShader: WebGLShader, context: WebGLRenderingContext, transformFeedbackVaryings: Nullable<string[]> = null): WebGLProgram {
  1208. var shaderProgram = context.createProgram();
  1209. pipelineContext.program = shaderProgram;
  1210. if (!shaderProgram) {
  1211. throw new Error("Unable to create program");
  1212. }
  1213. context.attachShader(shaderProgram, vertexShader);
  1214. context.attachShader(shaderProgram, fragmentShader);
  1215. if (this.webGLVersion > 1 && transformFeedbackVaryings) {
  1216. let transformFeedback = this.createTransformFeedback();
  1217. this.bindTransformFeedback(transformFeedback);
  1218. this.setTranformFeedbackVaryings(shaderProgram, transformFeedbackVaryings);
  1219. pipelineContext.transformFeedback = transformFeedback;
  1220. }
  1221. context.linkProgram(shaderProgram);
  1222. if (this.webGLVersion > 1 && transformFeedbackVaryings) {
  1223. this.bindTransformFeedback(null);
  1224. }
  1225. pipelineContext.context = context;
  1226. pipelineContext.vertexShader = vertexShader;
  1227. pipelineContext.fragmentShader = fragmentShader;
  1228. if (!pipelineContext.isParallelCompiled) {
  1229. this._finalizePipelineContext(pipelineContext);
  1230. }
  1231. return shaderProgram;
  1232. }
  1233. public _releaseTexture(texture: InternalTexture): void {
  1234. super._releaseTexture(texture);
  1235. // Set output texture of post process to null if the texture has been released/disposed
  1236. this.scenes.forEach((scene) => {
  1237. scene.postProcesses.forEach((postProcess) => {
  1238. if (postProcess._outputTexture == texture) {
  1239. postProcess._outputTexture = null;
  1240. }
  1241. });
  1242. scene.cameras.forEach((camera) => {
  1243. camera._postProcesses.forEach((postProcess) => {
  1244. if (postProcess) {
  1245. if (postProcess._outputTexture == texture) {
  1246. postProcess._outputTexture = null;
  1247. }
  1248. }
  1249. });
  1250. });
  1251. });
  1252. }
  1253. /**
  1254. * @hidden
  1255. * Rescales a texture
  1256. * @param source input texutre
  1257. * @param destination destination texture
  1258. * @param scene scene to use to render the resize
  1259. * @param internalFormat format to use when resizing
  1260. * @param onComplete callback to be called when resize has completed
  1261. */
  1262. public _rescaleTexture(source: InternalTexture, destination: InternalTexture, scene: Nullable<any>, internalFormat: number, onComplete: () => void): void {
  1263. this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_MAG_FILTER, this._gl.LINEAR);
  1264. this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_MIN_FILTER, this._gl.LINEAR);
  1265. this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_WRAP_S, this._gl.CLAMP_TO_EDGE);
  1266. this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_WRAP_T, this._gl.CLAMP_TO_EDGE);
  1267. let rtt = this.createRenderTargetTexture({
  1268. width: destination.width,
  1269. height: destination.height,
  1270. }, {
  1271. generateMipMaps: false,
  1272. type: Constants.TEXTURETYPE_UNSIGNED_INT,
  1273. samplingMode: Constants.TEXTURE_BILINEAR_SAMPLINGMODE,
  1274. generateDepthBuffer: false,
  1275. generateStencilBuffer: false
  1276. }
  1277. );
  1278. if (!this._rescalePostProcess && Engine._RescalePostProcessFactory) {
  1279. this._rescalePostProcess = Engine._RescalePostProcessFactory(this);
  1280. }
  1281. this._rescalePostProcess.getEffect().executeWhenCompiled(() => {
  1282. this._rescalePostProcess.onApply = function(effect) {
  1283. effect._bindTexture("textureSampler", source);
  1284. };
  1285. let hostingScene: Scene = scene;
  1286. if (!hostingScene) {
  1287. hostingScene = this.scenes[this.scenes.length - 1];
  1288. }
  1289. hostingScene.postProcessManager.directRender([this._rescalePostProcess], rtt, true);
  1290. this._bindTextureDirectly(this._gl.TEXTURE_2D, destination, true);
  1291. this._gl.copyTexImage2D(this._gl.TEXTURE_2D, 0, internalFormat, 0, 0, destination.width, destination.height, 0);
  1292. this.unBindFramebuffer(rtt);
  1293. this._releaseTexture(rtt);
  1294. if (onComplete) {
  1295. onComplete();
  1296. }
  1297. });
  1298. }
  1299. // FPS
  1300. /**
  1301. * Gets the current framerate
  1302. * @returns a number representing the framerate
  1303. */
  1304. public getFps(): number {
  1305. return this._fps;
  1306. }
  1307. /**
  1308. * Gets the time spent between current and previous frame
  1309. * @returns a number representing the delta time in ms
  1310. */
  1311. public getDeltaTime(): number {
  1312. return this._deltaTime;
  1313. }
  1314. private _measureFps(): void {
  1315. this._performanceMonitor.sampleFrame();
  1316. this._fps = this._performanceMonitor.averageFPS;
  1317. this._deltaTime = this._performanceMonitor.instantaneousFrameTime || 0;
  1318. }
  1319. /** @hidden */
  1320. public _uploadImageToTexture(texture: InternalTexture, image: HTMLImageElement | ImageBitmap, faceIndex: number = 0, lod: number = 0) {
  1321. var gl = this._gl;
  1322. var textureType = this._getWebGLTextureType(texture.type);
  1323. var format = this._getInternalFormat(texture.format);
  1324. var internalFormat = this._getRGBABufferInternalSizedFormat(texture.type, format);
  1325. var bindTarget = texture.isCube ? gl.TEXTURE_CUBE_MAP : gl.TEXTURE_2D;
  1326. this._bindTextureDirectly(bindTarget, texture, true);
  1327. this._unpackFlipY(texture.invertY);
  1328. var target = gl.TEXTURE_2D;
  1329. if (texture.isCube) {
  1330. target = gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex;
  1331. }
  1332. gl.texImage2D(target, lod, internalFormat, format, textureType, image);
  1333. this._bindTextureDirectly(bindTarget, null, true);
  1334. }
  1335. /**
  1336. * Update a dynamic index buffer
  1337. * @param indexBuffer defines the target index buffer
  1338. * @param indices defines the data to update
  1339. * @param offset defines the offset in the target index buffer where update should start
  1340. */
  1341. public updateDynamicIndexBuffer(indexBuffer: DataBuffer, indices: IndicesArray, offset: number = 0): void {
  1342. // Force cache update
  1343. this._currentBoundBuffer[this._gl.ELEMENT_ARRAY_BUFFER] = null;
  1344. this.bindIndexBuffer(indexBuffer);
  1345. var arrayBuffer;
  1346. if (indices instanceof Uint16Array || indices instanceof Uint32Array) {
  1347. arrayBuffer = indices;
  1348. } else {
  1349. arrayBuffer = indexBuffer.is32Bits ? new Uint32Array(indices) : new Uint16Array(indices);
  1350. }
  1351. this._gl.bufferData(this._gl.ELEMENT_ARRAY_BUFFER, arrayBuffer, this._gl.DYNAMIC_DRAW);
  1352. this._resetIndexBufferBinding();
  1353. }
  1354. /**
  1355. * Updates the sample count of a render target texture
  1356. * @see http://doc.babylonjs.com/features/webgl2#multisample-render-targets
  1357. * @param texture defines the texture to update
  1358. * @param samples defines the sample count to set
  1359. * @returns the effective sample count (could be 0 if multisample render targets are not supported)
  1360. */
  1361. public updateRenderTargetTextureSampleCount(texture: Nullable<InternalTexture>, samples: number): number {
  1362. if (this.webGLVersion < 2 || !texture) {
  1363. return 1;
  1364. }
  1365. if (texture.samples === samples) {
  1366. return samples;
  1367. }
  1368. var gl = this._gl;
  1369. samples = Math.min(samples, this.getCaps().maxMSAASamples);
  1370. // Dispose previous render buffers
  1371. if (texture._depthStencilBuffer) {
  1372. gl.deleteRenderbuffer(texture._depthStencilBuffer);
  1373. texture._depthStencilBuffer = null;
  1374. }
  1375. if (texture._MSAAFramebuffer) {
  1376. gl.deleteFramebuffer(texture._MSAAFramebuffer);
  1377. texture._MSAAFramebuffer = null;
  1378. }
  1379. if (texture._MSAARenderBuffer) {
  1380. gl.deleteRenderbuffer(texture._MSAARenderBuffer);
  1381. texture._MSAARenderBuffer = null;
  1382. }
  1383. if (samples > 1 && gl.renderbufferStorageMultisample) {
  1384. let framebuffer = gl.createFramebuffer();
  1385. if (!framebuffer) {
  1386. throw new Error("Unable to create multi sampled framebuffer");
  1387. }
  1388. texture._MSAAFramebuffer = framebuffer;
  1389. this._bindUnboundFramebuffer(texture._MSAAFramebuffer);
  1390. var colorRenderbuffer = gl.createRenderbuffer();
  1391. if (!colorRenderbuffer) {
  1392. throw new Error("Unable to create multi sampled framebuffer");
  1393. }
  1394. gl.bindRenderbuffer(gl.RENDERBUFFER, colorRenderbuffer);
  1395. gl.renderbufferStorageMultisample(gl.RENDERBUFFER, samples, this._getRGBAMultiSampleBufferFormat(texture.type), texture.width, texture.height);
  1396. gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorRenderbuffer);
  1397. texture._MSAARenderBuffer = colorRenderbuffer;
  1398. } else {
  1399. this._bindUnboundFramebuffer(texture._framebuffer);
  1400. }
  1401. texture.samples = samples;
  1402. texture._depthStencilBuffer = this._setupFramebufferDepthAttachments(texture._generateStencilBuffer, texture._generateDepthBuffer, texture.width, texture.height, samples);
  1403. this._bindUnboundFramebuffer(null);
  1404. return samples;
  1405. }
  1406. /**
  1407. * Updates a depth texture Comparison Mode and Function.
  1408. * If the comparison Function is equal to 0, the mode will be set to none.
  1409. * Otherwise, this only works in webgl 2 and requires a shadow sampler in the shader.
  1410. * @param texture The texture to set the comparison function for
  1411. * @param comparisonFunction The comparison function to set, 0 if no comparison required
  1412. */
  1413. public updateTextureComparisonFunction(texture: InternalTexture, comparisonFunction: number): void {
  1414. if (this.webGLVersion === 1) {
  1415. Logger.Error("WebGL 1 does not support texture comparison.");
  1416. return;
  1417. }
  1418. var gl = this._gl;
  1419. if (texture.isCube) {
  1420. this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, texture, true);
  1421. if (comparisonFunction === 0) {
  1422. gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_COMPARE_FUNC, Constants.LEQUAL);
  1423. gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_COMPARE_MODE, gl.NONE);
  1424. }
  1425. else {
  1426. gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_COMPARE_FUNC, comparisonFunction);
  1427. gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_COMPARE_MODE, gl.COMPARE_REF_TO_TEXTURE);
  1428. }
  1429. this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, null);
  1430. } else {
  1431. this._bindTextureDirectly(this._gl.TEXTURE_2D, texture, true);
  1432. if (comparisonFunction === 0) {
  1433. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_COMPARE_FUNC, Constants.LEQUAL);
  1434. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_COMPARE_MODE, gl.NONE);
  1435. }
  1436. else {
  1437. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_COMPARE_FUNC, comparisonFunction);
  1438. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_COMPARE_MODE, gl.COMPARE_REF_TO_TEXTURE);
  1439. }
  1440. this._bindTextureDirectly(this._gl.TEXTURE_2D, null);
  1441. }
  1442. texture._comparisonFunction = comparisonFunction;
  1443. }
  1444. /**
  1445. * Creates a webGL buffer to use with instanciation
  1446. * @param capacity defines the size of the buffer
  1447. * @returns the webGL buffer
  1448. */
  1449. public createInstancesBuffer(capacity: number): DataBuffer {
  1450. var buffer = this._gl.createBuffer();
  1451. if (!buffer) {
  1452. throw new Error("Unable to create instance buffer");
  1453. }
  1454. var result = new WebGLDataBuffer(buffer);
  1455. result.capacity = capacity;
  1456. this.bindArrayBuffer(result);
  1457. this._gl.bufferData(this._gl.ARRAY_BUFFER, capacity, this._gl.DYNAMIC_DRAW);
  1458. return result;
  1459. }
  1460. /**
  1461. * Delete a webGL buffer used with instanciation
  1462. * @param buffer defines the webGL buffer to delete
  1463. */
  1464. public deleteInstancesBuffer(buffer: WebGLBuffer): void {
  1465. this._gl.deleteBuffer(buffer);
  1466. }
  1467. private _clientWaitAsync(sync: WebGLSync, flags = 0, interval_ms = 10) {
  1468. let gl = <WebGL2RenderingContext>(this._gl as any);
  1469. return new Promise((resolve, reject) => {
  1470. let check = () => {
  1471. const res = gl.clientWaitSync(sync, flags, 0);
  1472. if (res == gl.WAIT_FAILED) {
  1473. reject();
  1474. return;
  1475. }
  1476. if (res == gl.TIMEOUT_EXPIRED) {
  1477. setTimeout(check, interval_ms);
  1478. return;
  1479. }
  1480. resolve();
  1481. };
  1482. check();
  1483. });
  1484. }
  1485. /** @hidden */
  1486. public _readPixelsAsync(x: number, y: number, w: number, h: number, format: number, type: number, outputBuffer: ArrayBufferView) {
  1487. if (this._webGLVersion < 2) {
  1488. throw new Error("_readPixelsAsync only work on WebGL2+");
  1489. }
  1490. let gl = <WebGL2RenderingContext>(this._gl as any);
  1491. const buf = gl.createBuffer();
  1492. gl.bindBuffer(gl.PIXEL_PACK_BUFFER, buf);
  1493. gl.bufferData(gl.PIXEL_PACK_BUFFER, outputBuffer.byteLength, gl.STREAM_READ);
  1494. gl.readPixels(x, y, w, h, format, type, 0);
  1495. gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);
  1496. const sync = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0);
  1497. if (!sync) {
  1498. return null;
  1499. }
  1500. gl.flush();
  1501. return this._clientWaitAsync(sync, 0, 10).then(() => {
  1502. gl.deleteSync(sync);
  1503. gl.bindBuffer(gl.PIXEL_PACK_BUFFER, buf);
  1504. gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 0, outputBuffer);
  1505. gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);
  1506. gl.deleteBuffer(buf);
  1507. return outputBuffer;
  1508. });
  1509. }
  1510. /** @hidden */
  1511. public _readTexturePixels(texture: InternalTexture, width: number, height: number, faceIndex = -1, level = 0, buffer: Nullable<ArrayBufferView> = null): ArrayBufferView {
  1512. let gl = this._gl;
  1513. if (!gl) {
  1514. throw new Error ("Engine does not have gl rendering context.");
  1515. }
  1516. if (!this._dummyFramebuffer) {
  1517. let dummy = gl.createFramebuffer();
  1518. if (!dummy) {
  1519. throw new Error("Unable to create dummy framebuffer");
  1520. }
  1521. this._dummyFramebuffer = dummy;
  1522. }
  1523. gl.bindFramebuffer(gl.FRAMEBUFFER, this._dummyFramebuffer);
  1524. if (faceIndex > -1) {
  1525. gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, texture._webGLTexture, level);
  1526. } else {
  1527. gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture._webGLTexture, level);
  1528. }
  1529. let readType = (texture.type !== undefined) ? this._getWebGLTextureType(texture.type) : gl.UNSIGNED_BYTE;
  1530. switch (readType) {
  1531. case gl.UNSIGNED_BYTE:
  1532. if (!buffer) {
  1533. buffer = new Uint8Array(4 * width * height);
  1534. }
  1535. readType = gl.UNSIGNED_BYTE;
  1536. break;
  1537. default:
  1538. if (!buffer) {
  1539. buffer = new Float32Array(4 * width * height);
  1540. }
  1541. readType = gl.FLOAT;
  1542. break;
  1543. }
  1544. gl.readPixels(0, 0, width, height, gl.RGBA, readType, <DataView>buffer);
  1545. gl.bindFramebuffer(gl.FRAMEBUFFER, this._currentFramebuffer);
  1546. return buffer;
  1547. }
  1548. public dispose(): void {
  1549. this.hideLoadingUI();
  1550. this.onNewSceneAddedObservable.clear();
  1551. // Release postProcesses
  1552. while (this.postProcesses.length) {
  1553. this.postProcesses[0].dispose();
  1554. }
  1555. // Rescale PP
  1556. if (this._rescalePostProcess) {
  1557. this._rescalePostProcess.dispose();
  1558. }
  1559. // Release scenes
  1560. while (this.scenes.length) {
  1561. this.scenes[0].dispose();
  1562. }
  1563. // Release audio engine
  1564. if (Engine.Instances.length === 1 && Engine.audioEngine) {
  1565. Engine.audioEngine.dispose();
  1566. }
  1567. if (this._dummyFramebuffer) {
  1568. this._gl.deleteFramebuffer(this._dummyFramebuffer);
  1569. }
  1570. //WebVR
  1571. this.disableVR();
  1572. // Events
  1573. if (DomManagement.IsWindowObjectExist()) {
  1574. window.removeEventListener("blur", this._onBlur);
  1575. window.removeEventListener("focus", this._onFocus);
  1576. if (this._renderingCanvas) {
  1577. this._renderingCanvas.removeEventListener("focus", this._onCanvasFocus);
  1578. this._renderingCanvas.removeEventListener("blur", this._onCanvasBlur);
  1579. this._renderingCanvas.removeEventListener("pointerout", this._onCanvasPointerOut);
  1580. }
  1581. if (DomManagement.IsDocumentAvailable()) {
  1582. document.removeEventListener("fullscreenchange", this._onFullscreenChange);
  1583. document.removeEventListener("mozfullscreenchange", this._onFullscreenChange);
  1584. document.removeEventListener("webkitfullscreenchange", this._onFullscreenChange);
  1585. document.removeEventListener("msfullscreenchange", this._onFullscreenChange);
  1586. document.removeEventListener("pointerlockchange", this._onPointerLockChange);
  1587. document.removeEventListener("mspointerlockchange", this._onPointerLockChange);
  1588. document.removeEventListener("mozpointerlockchange", this._onPointerLockChange);
  1589. document.removeEventListener("webkitpointerlockchange", this._onPointerLockChange);
  1590. }
  1591. }
  1592. super.dispose();
  1593. // Remove from Instances
  1594. var index = Engine.Instances.indexOf(this);
  1595. if (index >= 0) {
  1596. Engine.Instances.splice(index, 1);
  1597. }
  1598. // Observables
  1599. this.onResizeObservable.clear();
  1600. this.onCanvasBlurObservable.clear();
  1601. this.onCanvasFocusObservable.clear();
  1602. this.onCanvasPointerOutObservable.clear();
  1603. this.onBeginFrameObservable.clear();
  1604. this.onEndFrameObservable.clear();
  1605. }
  1606. private _disableTouchAction(): void {
  1607. if (!this._renderingCanvas || !this._renderingCanvas.setAttribute) {
  1608. return;
  1609. }
  1610. this._renderingCanvas.setAttribute("touch-action", "none");
  1611. this._renderingCanvas.style.touchAction = "none";
  1612. this._renderingCanvas.style.msTouchAction = "none";
  1613. }
  1614. // Loading screen
  1615. /**
  1616. * Display the loading screen
  1617. * @see http://doc.babylonjs.com/how_to/creating_a_custom_loading_screen
  1618. */
  1619. public displayLoadingUI(): void {
  1620. if (!DomManagement.IsWindowObjectExist()) {
  1621. return;
  1622. }
  1623. const loadingScreen = this.loadingScreen;
  1624. if (loadingScreen) {
  1625. loadingScreen.displayLoadingUI();
  1626. }
  1627. }
  1628. /**
  1629. * Hide the loading screen
  1630. * @see http://doc.babylonjs.com/how_to/creating_a_custom_loading_screen
  1631. */
  1632. public hideLoadingUI(): void {
  1633. if (!DomManagement.IsWindowObjectExist()) {
  1634. return;
  1635. }
  1636. const loadingScreen = this._loadingScreen;
  1637. if (loadingScreen) {
  1638. loadingScreen.hideLoadingUI();
  1639. }
  1640. }
  1641. /**
  1642. * Gets the current loading screen object
  1643. * @see http://doc.babylonjs.com/how_to/creating_a_custom_loading_screen
  1644. */
  1645. public get loadingScreen(): ILoadingScreen {
  1646. if (!this._loadingScreen && this._renderingCanvas) {
  1647. this._loadingScreen = Engine.DefaultLoadingScreenFactory(this._renderingCanvas);
  1648. }
  1649. return this._loadingScreen;
  1650. }
  1651. /**
  1652. * Sets the current loading screen object
  1653. * @see http://doc.babylonjs.com/how_to/creating_a_custom_loading_screen
  1654. */
  1655. public set loadingScreen(loadingScreen: ILoadingScreen) {
  1656. this._loadingScreen = loadingScreen;
  1657. }
  1658. /**
  1659. * Sets the current loading screen text
  1660. * @see http://doc.babylonjs.com/how_to/creating_a_custom_loading_screen
  1661. */
  1662. public set loadingUIText(text: string) {
  1663. this.loadingScreen.loadingUIText = text;
  1664. }
  1665. /**
  1666. * Sets the current loading screen background color
  1667. * @see http://doc.babylonjs.com/how_to/creating_a_custom_loading_screen
  1668. */
  1669. public set loadingUIBackgroundColor(color: string) {
  1670. this.loadingScreen.loadingUIBackgroundColor = color;
  1671. }
  1672. /** Pointerlock and fullscreen */
  1673. /**
  1674. * Ask the browser to promote the current element to pointerlock mode
  1675. * @param element defines the DOM element to promote
  1676. */
  1677. static _RequestPointerlock(element: HTMLElement): void {
  1678. element.requestPointerLock = element.requestPointerLock || (<any>element).msRequestPointerLock || (<any>element).mozRequestPointerLock || (<any>element).webkitRequestPointerLock;
  1679. if (element.requestPointerLock) {
  1680. element.requestPointerLock();
  1681. }
  1682. }
  1683. /**
  1684. * Asks the browser to exit pointerlock mode
  1685. */
  1686. static _ExitPointerlock(): void {
  1687. let anyDoc = document as any;
  1688. document.exitPointerLock = document.exitPointerLock || anyDoc.msExitPointerLock || anyDoc.mozExitPointerLock || anyDoc.webkitExitPointerLock;
  1689. if (document.exitPointerLock) {
  1690. document.exitPointerLock();
  1691. }
  1692. }
  1693. /**
  1694. * Ask the browser to promote the current element to fullscreen rendering mode
  1695. * @param element defines the DOM element to promote
  1696. */
  1697. static _RequestFullscreen(element: HTMLElement): void {
  1698. var requestFunction = element.requestFullscreen || (<any>element).msRequestFullscreen || (<any>element).webkitRequestFullscreen || (<any>element).mozRequestFullScreen;
  1699. if (!requestFunction) { return; }
  1700. requestFunction.call(element);
  1701. }
  1702. /**
  1703. * Asks the browser to exit fullscreen mode
  1704. */
  1705. static _ExitFullscreen(): void {
  1706. let anyDoc = document as any;
  1707. if (document.exitFullscreen) {
  1708. document.exitFullscreen();
  1709. }
  1710. else if (anyDoc.mozCancelFullScreen) {
  1711. anyDoc.mozCancelFullScreen();
  1712. }
  1713. else if (anyDoc.webkitCancelFullScreen) {
  1714. anyDoc.webkitCancelFullScreen();
  1715. }
  1716. else if (anyDoc.msCancelFullScreen) {
  1717. anyDoc.msCancelFullScreen();
  1718. }
  1719. }
  1720. }