engine.ts 88 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238
  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 { _TimeToken } from "../Instrumentation/timeToken";
  6. import { IAudioEngine } from "../Audio/audioEngine";
  7. import { IOfflineProvider } from "../Offline/IOfflineProvider";
  8. import { ILoadingScreen } from "../Loading/loadingScreen";
  9. import { DomManagement } from "../Misc/domManagement";
  10. import { EngineStore } from "./engineStore";
  11. import { _DevTools } from '../Misc/devTools';
  12. import { WebGLPipelineContext } from './WebGL/webGLPipelineContext';
  13. import { IPipelineContext } from './IPipelineContext';
  14. import { ICustomAnimationFrameRequester } from '../Misc/customAnimationFrameRequester';
  15. import { ThinEngine, EngineOptions } from './thinEngine';
  16. import { Constants } from './constants';
  17. import { IViewportLike, IColor4Like } from '../Maths/math.like';
  18. import { RenderTargetTexture } from '../Materials/Textures/renderTargetTexture';
  19. import { PerformanceMonitor } from '../Misc/performanceMonitor';
  20. import { DataBuffer } from '../Meshes/dataBuffer';
  21. import { PerfCounter } from '../Misc/perfCounter';
  22. import { WebGLDataBuffer } from '../Meshes/WebGL/webGLDataBuffer';
  23. import { Logger } from '../Misc/logger';
  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. /** @hidden */
  378. protected _alphaMode = Constants.ALPHA_ADD;
  379. /** @hidden */
  380. protected _alphaEquation = Constants.ALPHA_DISABLE;
  381. // Deterministic lockstepMaxSteps
  382. private _deterministicLockstep: boolean = false;
  383. private _lockstepMaxSteps: number = 4;
  384. private _timeStep: number = 1 / 60;
  385. protected get _supportsHardwareTextureRescaling() {
  386. return !!Engine._RescalePostProcessFactory;
  387. }
  388. // FPS
  389. private _fps = 60;
  390. private _deltaTime = 0;
  391. /** @hidden */
  392. public _drawCalls = new PerfCounter();
  393. /**
  394. * Turn this value on if you want to pause FPS computation when in background
  395. */
  396. public disablePerformanceMonitorInBackground = false;
  397. private _performanceMonitor = new PerformanceMonitor();
  398. /**
  399. * Gets the performance monitor attached to this engine
  400. * @see http://doc.babylonjs.com/how_to/optimizing_your_scene#engineinstrumentation
  401. */
  402. public get performanceMonitor(): PerformanceMonitor {
  403. return this._performanceMonitor;
  404. }
  405. // Focus
  406. private _onFocus: () => void;
  407. private _onBlur: () => void;
  408. private _onCanvasPointerOut: (event: PointerEvent) => void;
  409. private _onCanvasBlur: () => void;
  410. private _onCanvasFocus: () => void;
  411. private _onFullscreenChange: () => void;
  412. private _onPointerLockChange: () => void;
  413. // Events
  414. /**
  415. * Gets the HTML element used to attach event listeners
  416. * @returns a HTML element
  417. */
  418. public getInputElement(): Nullable<HTMLElement> {
  419. return this._renderingCanvas;
  420. }
  421. /**
  422. * Creates a new engine
  423. * @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
  424. * @param antialias defines enable antialiasing (default: false)
  425. * @param options defines further options to be sent to the getContext() function
  426. * @param adaptToDeviceRatio defines whether to adapt to the device's viewport characteristics (default: false)
  427. */
  428. constructor(canvasOrContext: Nullable<HTMLCanvasElement | WebGLRenderingContext>, antialias?: boolean, options?: EngineOptions, adaptToDeviceRatio: boolean = false) {
  429. super(canvasOrContext, antialias, options, adaptToDeviceRatio);
  430. if (!canvasOrContext) {
  431. return;
  432. }
  433. options = this._creationOptions;
  434. Engine.Instances.push(this);
  435. if ((<HTMLCanvasElement>canvasOrContext).getContext) {
  436. let canvas = <HTMLCanvasElement>canvasOrContext;
  437. this._onCanvasFocus = () => {
  438. this.onCanvasFocusObservable.notifyObservers(this);
  439. };
  440. this._onCanvasBlur = () => {
  441. this.onCanvasBlurObservable.notifyObservers(this);
  442. };
  443. canvas.addEventListener("focus", this._onCanvasFocus);
  444. canvas.addEventListener("blur", this._onCanvasBlur);
  445. this._onBlur = () => {
  446. if (this.disablePerformanceMonitorInBackground) {
  447. this._performanceMonitor.disable();
  448. }
  449. this._windowIsBackground = true;
  450. };
  451. this._onFocus = () => {
  452. if (this.disablePerformanceMonitorInBackground) {
  453. this._performanceMonitor.enable();
  454. }
  455. this._windowIsBackground = false;
  456. };
  457. this._onCanvasPointerOut = (ev) => {
  458. this.onCanvasPointerOutObservable.notifyObservers(ev);
  459. };
  460. canvas.addEventListener("pointerout", this._onCanvasPointerOut);
  461. if (DomManagement.IsWindowObjectExist()) {
  462. let hostWindow = this.getHostWindow()!;
  463. hostWindow.addEventListener("blur", this._onBlur);
  464. hostWindow.addEventListener("focus", this._onFocus);
  465. let anyDoc = document as any;
  466. // Fullscreen
  467. this._onFullscreenChange = () => {
  468. if (anyDoc.fullscreen !== undefined) {
  469. this.isFullscreen = anyDoc.fullscreen;
  470. } else if (anyDoc.mozFullScreen !== undefined) {
  471. this.isFullscreen = anyDoc.mozFullScreen;
  472. } else if (anyDoc.webkitIsFullScreen !== undefined) {
  473. this.isFullscreen = anyDoc.webkitIsFullScreen;
  474. } else if (anyDoc.msIsFullScreen !== undefined) {
  475. this.isFullscreen = anyDoc.msIsFullScreen;
  476. }
  477. // Pointer lock
  478. if (this.isFullscreen && this._pointerLockRequested && canvas) {
  479. Engine._RequestPointerlock(canvas);
  480. }
  481. };
  482. document.addEventListener("fullscreenchange", this._onFullscreenChange, false);
  483. document.addEventListener("mozfullscreenchange", this._onFullscreenChange, false);
  484. document.addEventListener("webkitfullscreenchange", this._onFullscreenChange, false);
  485. document.addEventListener("msfullscreenchange", this._onFullscreenChange, false);
  486. // Pointer lock
  487. this._onPointerLockChange = () => {
  488. this.isPointerLock = (anyDoc.mozPointerLockElement === canvas ||
  489. anyDoc.webkitPointerLockElement === canvas ||
  490. anyDoc.msPointerLockElement === canvas ||
  491. anyDoc.pointerLockElement === canvas
  492. );
  493. };
  494. document.addEventListener("pointerlockchange", this._onPointerLockChange, false);
  495. document.addEventListener("mspointerlockchange", this._onPointerLockChange, false);
  496. document.addEventListener("mozpointerlockchange", this._onPointerLockChange, false);
  497. document.addEventListener("webkitpointerlockchange", this._onPointerLockChange, false);
  498. // Create Audio Engine if needed.
  499. if (!Engine.audioEngine && options.audioEngine && Engine.AudioEngineFactory) {
  500. Engine.audioEngine = Engine.AudioEngineFactory(this.getRenderingCanvas());
  501. }
  502. }
  503. this._connectVREvents();
  504. this.enableOfflineSupport = Engine.OfflineProviderFactory !== undefined;
  505. if (!options.doNotHandleTouchAction) {
  506. this._disableTouchAction();
  507. }
  508. this._deterministicLockstep = !!options.deterministicLockstep;
  509. this._lockstepMaxSteps = options.lockstepMaxSteps || 0;
  510. this._timeStep = options.timeStep || 1 / 60;
  511. }
  512. // Load WebVR Devices
  513. this._prepareVRComponent();
  514. if (options.autoEnableWebVR) {
  515. this.initWebVR();
  516. }
  517. }
  518. /**
  519. * Gets current aspect ratio
  520. * @param viewportOwner defines the camera to use to get the aspect ratio
  521. * @param useScreen defines if screen size must be used (or the current render target if any)
  522. * @returns a number defining the aspect ratio
  523. */
  524. public getAspectRatio(viewportOwner: IViewportOwnerLike, useScreen = false): number {
  525. var viewport = viewportOwner.viewport;
  526. return (this.getRenderWidth(useScreen) * viewport.width) / (this.getRenderHeight(useScreen) * viewport.height);
  527. }
  528. /**
  529. * Gets current screen aspect ratio
  530. * @returns a number defining the aspect ratio
  531. */
  532. public getScreenAspectRatio(): number {
  533. return (this.getRenderWidth(true)) / (this.getRenderHeight(true));
  534. }
  535. /**
  536. * Gets the client rect of the HTML canvas attached with the current webGL context
  537. * @returns a client rectanglee
  538. */
  539. public getRenderingCanvasClientRect(): Nullable<ClientRect> {
  540. if (!this._renderingCanvas) {
  541. return null;
  542. }
  543. return this._renderingCanvas.getBoundingClientRect();
  544. }
  545. /**
  546. * Gets the client rect of the HTML element used for events
  547. * @returns a client rectanglee
  548. */
  549. public getInputElementClientRect(): Nullable<ClientRect> {
  550. if (!this._renderingCanvas) {
  551. return null;
  552. }
  553. return this.getInputElement()!.getBoundingClientRect();
  554. }
  555. /**
  556. * Gets a boolean indicating that the engine is running in deterministic lock step mode
  557. * @see http://doc.babylonjs.com/babylon101/animations#deterministic-lockstep
  558. * @returns true if engine is in deterministic lock step mode
  559. */
  560. public isDeterministicLockStep(): boolean {
  561. return this._deterministicLockstep;
  562. }
  563. /**
  564. * Gets the max steps when engine is running in deterministic lock step
  565. * @see http://doc.babylonjs.com/babylon101/animations#deterministic-lockstep
  566. * @returns the max steps
  567. */
  568. public getLockstepMaxSteps(): number {
  569. return this._lockstepMaxSteps;
  570. }
  571. /**
  572. * Returns the time in ms between steps when using deterministic lock step.
  573. * @returns time step in (ms)
  574. */
  575. public getTimeStep(): number {
  576. return this._timeStep * 1000;
  577. }
  578. /**
  579. * Force the mipmap generation for the given render target texture
  580. * @param texture defines the render target texture to use
  581. */
  582. public generateMipMapsForCubemap(texture: InternalTexture) {
  583. if (texture.generateMipMaps) {
  584. var gl = this._gl;
  585. this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, texture, true);
  586. gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
  587. this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, null);
  588. }
  589. }
  590. /** States */
  591. /**
  592. * Set various states to the webGL context
  593. * @param culling defines backface culling state
  594. * @param zOffset defines the value to apply to zOffset (0 by default)
  595. * @param force defines if states must be applied even if cache is up to date
  596. * @param reverseSide defines if culling must be reversed (CCW instead of CW and CW instead of CCW)
  597. */
  598. public setState(culling: boolean, zOffset: number = 0, force?: boolean, reverseSide = false): void {
  599. // Culling
  600. if (this._depthCullingState.cull !== culling || force) {
  601. this._depthCullingState.cull = culling;
  602. }
  603. // Cull face
  604. var cullFace = this.cullBackFaces ? this._gl.BACK : this._gl.FRONT;
  605. if (this._depthCullingState.cullFace !== cullFace || force) {
  606. this._depthCullingState.cullFace = cullFace;
  607. }
  608. // Z offset
  609. this.setZOffset(zOffset);
  610. // Front face
  611. var frontFace = reverseSide ? this._gl.CW : this._gl.CCW;
  612. if (this._depthCullingState.frontFace !== frontFace || force) {
  613. this._depthCullingState.frontFace = frontFace;
  614. }
  615. }
  616. /**
  617. * Set the z offset to apply to current rendering
  618. * @param value defines the offset to apply
  619. */
  620. public setZOffset(value: number): void {
  621. this._depthCullingState.zOffset = value;
  622. }
  623. /**
  624. * Gets the current value of the zOffset
  625. * @returns the current zOffset state
  626. */
  627. public getZOffset(): number {
  628. return this._depthCullingState.zOffset;
  629. }
  630. /**
  631. * Enable or disable depth buffering
  632. * @param enable defines the state to set
  633. */
  634. public setDepthBuffer(enable: boolean): void {
  635. this._depthCullingState.depthTest = enable;
  636. }
  637. /**
  638. * Gets a boolean indicating if depth writing is enabled
  639. * @returns the current depth writing state
  640. */
  641. public getDepthWrite(): boolean {
  642. return this._depthCullingState.depthMask;
  643. }
  644. /**
  645. * Enable or disable depth writing
  646. * @param enable defines the state to set
  647. */
  648. public setDepthWrite(enable: boolean): void {
  649. this._depthCullingState.depthMask = enable;
  650. }
  651. /**
  652. * Enable or disable color writing
  653. * @param enable defines the state to set
  654. */
  655. public setColorWrite(enable: boolean): void {
  656. this._gl.colorMask(enable, enable, enable, enable);
  657. this._colorWrite = enable;
  658. }
  659. /**
  660. * Gets a boolean indicating if color writing is enabled
  661. * @returns the current color writing state
  662. */
  663. public getColorWrite(): boolean {
  664. return this._colorWrite;
  665. }
  666. /**
  667. * Sets alpha constants used by some alpha blending modes
  668. * @param r defines the red component
  669. * @param g defines the green component
  670. * @param b defines the blue component
  671. * @param a defines the alpha component
  672. */
  673. public setAlphaConstants(r: number, g: number, b: number, a: number) {
  674. this._alphaState.setAlphaBlendConstants(r, g, b, a);
  675. }
  676. /**
  677. * Sets the current alpha mode
  678. * @param mode defines the mode to use (one of the Engine.ALPHA_XXX)
  679. * @param noDepthWriteChange defines if depth writing state should remains unchanged (false by default)
  680. * @see http://doc.babylonjs.com/resources/transparency_and_how_meshes_are_rendered
  681. */
  682. public setAlphaMode(mode: number, noDepthWriteChange: boolean = false): void {
  683. if (this._alphaMode === mode) {
  684. return;
  685. }
  686. switch (mode) {
  687. case Constants.ALPHA_DISABLE:
  688. this._alphaState.alphaBlend = false;
  689. break;
  690. case Constants.ALPHA_PREMULTIPLIED:
  691. this._alphaState.setAlphaBlendFunctionParameters(this._gl.ONE, this._gl.ONE_MINUS_SRC_ALPHA, this._gl.ONE, this._gl.ONE);
  692. this._alphaState.alphaBlend = true;
  693. break;
  694. case Constants.ALPHA_PREMULTIPLIED_PORTERDUFF:
  695. this._alphaState.setAlphaBlendFunctionParameters(this._gl.ONE, this._gl.ONE_MINUS_SRC_ALPHA, this._gl.ONE, this._gl.ONE_MINUS_SRC_ALPHA);
  696. this._alphaState.alphaBlend = true;
  697. break;
  698. case Constants.ALPHA_COMBINE:
  699. this._alphaState.setAlphaBlendFunctionParameters(this._gl.SRC_ALPHA, this._gl.ONE_MINUS_SRC_ALPHA, this._gl.ONE, this._gl.ONE);
  700. this._alphaState.alphaBlend = true;
  701. break;
  702. case Constants.ALPHA_ONEONE:
  703. this._alphaState.setAlphaBlendFunctionParameters(this._gl.ONE, this._gl.ONE, this._gl.ZERO, this._gl.ONE);
  704. this._alphaState.alphaBlend = true;
  705. break;
  706. case Constants.ALPHA_ADD:
  707. this._alphaState.setAlphaBlendFunctionParameters(this._gl.SRC_ALPHA, this._gl.ONE, this._gl.ZERO, this._gl.ONE);
  708. this._alphaState.alphaBlend = true;
  709. break;
  710. case Constants.ALPHA_SUBTRACT:
  711. this._alphaState.setAlphaBlendFunctionParameters(this._gl.ZERO, this._gl.ONE_MINUS_SRC_COLOR, this._gl.ONE, this._gl.ONE);
  712. this._alphaState.alphaBlend = true;
  713. break;
  714. case Constants.ALPHA_MULTIPLY:
  715. this._alphaState.setAlphaBlendFunctionParameters(this._gl.DST_COLOR, this._gl.ZERO, this._gl.ONE, this._gl.ONE);
  716. this._alphaState.alphaBlend = true;
  717. break;
  718. case Constants.ALPHA_MAXIMIZED:
  719. this._alphaState.setAlphaBlendFunctionParameters(this._gl.SRC_ALPHA, this._gl.ONE_MINUS_SRC_COLOR, this._gl.ONE, this._gl.ONE);
  720. this._alphaState.alphaBlend = true;
  721. break;
  722. case Constants.ALPHA_INTERPOLATE:
  723. this._alphaState.setAlphaBlendFunctionParameters(this._gl.CONSTANT_COLOR, this._gl.ONE_MINUS_CONSTANT_COLOR, this._gl.CONSTANT_ALPHA, this._gl.ONE_MINUS_CONSTANT_ALPHA);
  724. this._alphaState.alphaBlend = true;
  725. break;
  726. case Constants.ALPHA_SCREENMODE:
  727. this._alphaState.setAlphaBlendFunctionParameters(this._gl.ONE, this._gl.ONE_MINUS_SRC_COLOR, this._gl.ONE, this._gl.ONE_MINUS_SRC_ALPHA);
  728. this._alphaState.alphaBlend = true;
  729. break;
  730. case Constants.ALPHA_ONEONE_ONEONE:
  731. this._alphaState.setAlphaBlendFunctionParameters(this._gl.ONE, this._gl.ONE, this._gl.ONE, this._gl.ONE);
  732. this._alphaState.alphaBlend = true;
  733. break;
  734. case Constants.ALPHA_ALPHATOCOLOR:
  735. this._alphaState.setAlphaBlendFunctionParameters(this._gl.DST_ALPHA, this._gl.ONE, this._gl.ZERO, this._gl.ZERO);
  736. this._alphaState.alphaBlend = true;
  737. break;
  738. case Constants.ALPHA_REVERSEONEMINUS:
  739. this._alphaState.setAlphaBlendFunctionParameters(this._gl.ONE_MINUS_DST_COLOR, this._gl.ONE_MINUS_SRC_COLOR, this._gl.ONE_MINUS_DST_ALPHA, this._gl.ONE_MINUS_SRC_ALPHA);
  740. this._alphaState.alphaBlend = true;
  741. break;
  742. case Constants.ALPHA_SRC_DSTONEMINUSSRCALPHA:
  743. this._alphaState.setAlphaBlendFunctionParameters(this._gl.ONE, this._gl.ONE_MINUS_SRC_ALPHA, this._gl.ONE, this._gl.ONE_MINUS_SRC_ALPHA);
  744. this._alphaState.alphaBlend = true;
  745. break;
  746. case Constants.ALPHA_ONEONE_ONEZERO:
  747. this._alphaState.setAlphaBlendFunctionParameters(this._gl.ONE, this._gl.ONE, this._gl.ONE, this._gl.ZERO);
  748. this._alphaState.alphaBlend = true;
  749. break;
  750. }
  751. if (!noDepthWriteChange) {
  752. this.setDepthWrite(mode === Constants.ALPHA_DISABLE);
  753. }
  754. this._alphaMode = mode;
  755. }
  756. /**
  757. * Gets the current alpha mode
  758. * @see http://doc.babylonjs.com/resources/transparency_and_how_meshes_are_rendered
  759. * @returns the current alpha mode
  760. */
  761. public getAlphaMode(): number {
  762. return this._alphaMode;
  763. }
  764. /**
  765. * Sets the current alpha equation
  766. * @param equation defines the equation to use (one of the Engine.ALPHA_EQUATION_XXX)
  767. */
  768. public setAlphaEquation(equation: number): void {
  769. if (this._alphaEquation === equation) {
  770. return;
  771. }
  772. switch (equation) {
  773. case Constants.ALPHA_EQUATION_ADD:
  774. this._alphaState.setAlphaEquationParameters(this._gl.FUNC_ADD, this._gl.FUNC_ADD);
  775. break;
  776. case Constants.ALPHA_EQUATION_SUBSTRACT:
  777. this._alphaState.setAlphaEquationParameters(this._gl.FUNC_SUBTRACT, this._gl.FUNC_SUBTRACT);
  778. break;
  779. case Constants.ALPHA_EQUATION_REVERSE_SUBTRACT:
  780. this._alphaState.setAlphaEquationParameters(this._gl.FUNC_REVERSE_SUBTRACT, this._gl.FUNC_REVERSE_SUBTRACT);
  781. break;
  782. case Constants.ALPHA_EQUATION_MAX:
  783. this._alphaState.setAlphaEquationParameters(this._gl.MAX, this._gl.MAX);
  784. break;
  785. case Constants.ALPHA_EQUATION_MIN:
  786. this._alphaState.setAlphaEquationParameters(this._gl.MIN, this._gl.MIN);
  787. break;
  788. case Constants.ALPHA_EQUATION_DARKEN:
  789. this._alphaState.setAlphaEquationParameters(this._gl.MIN, this._gl.FUNC_ADD);
  790. break;
  791. }
  792. this._alphaEquation = equation;
  793. }
  794. /**
  795. * Gets the current alpha equation.
  796. * @returns the current alpha equation
  797. */
  798. public getAlphaEquation(): number {
  799. return this._alphaEquation;
  800. }
  801. /**
  802. * Gets a boolean indicating if stencil buffer is enabled
  803. * @returns the current stencil buffer state
  804. */
  805. public getStencilBuffer(): boolean {
  806. return this._stencilState.stencilTest;
  807. }
  808. /**
  809. * Enable or disable the stencil buffer
  810. * @param enable defines if the stencil buffer must be enabled or disabled
  811. */
  812. public setStencilBuffer(enable: boolean): void {
  813. this._stencilState.stencilTest = enable;
  814. }
  815. /**
  816. * Gets the current stencil mask
  817. * @returns a number defining the new stencil mask to use
  818. */
  819. public getStencilMask(): number {
  820. return this._stencilState.stencilMask;
  821. }
  822. /**
  823. * Sets the current stencil mask
  824. * @param mask defines the new stencil mask to use
  825. */
  826. public setStencilMask(mask: number): void {
  827. this._stencilState.stencilMask = mask;
  828. }
  829. /**
  830. * Gets the current stencil function
  831. * @returns a number defining the stencil function to use
  832. */
  833. public getStencilFunction(): number {
  834. return this._stencilState.stencilFunc;
  835. }
  836. /**
  837. * Gets the current stencil reference value
  838. * @returns a number defining the stencil reference value to use
  839. */
  840. public getStencilFunctionReference(): number {
  841. return this._stencilState.stencilFuncRef;
  842. }
  843. /**
  844. * Gets the current stencil mask
  845. * @returns a number defining the stencil mask to use
  846. */
  847. public getStencilFunctionMask(): number {
  848. return this._stencilState.stencilFuncMask;
  849. }
  850. /**
  851. * Sets the current stencil function
  852. * @param stencilFunc defines the new stencil function to use
  853. */
  854. public setStencilFunction(stencilFunc: number) {
  855. this._stencilState.stencilFunc = stencilFunc;
  856. }
  857. /**
  858. * Sets the current stencil reference
  859. * @param reference defines the new stencil reference to use
  860. */
  861. public setStencilFunctionReference(reference: number) {
  862. this._stencilState.stencilFuncRef = reference;
  863. }
  864. /**
  865. * Sets the current stencil mask
  866. * @param mask defines the new stencil mask to use
  867. */
  868. public setStencilFunctionMask(mask: number) {
  869. this._stencilState.stencilFuncMask = mask;
  870. }
  871. /**
  872. * Gets the current stencil operation when stencil fails
  873. * @returns a number defining stencil operation to use when stencil fails
  874. */
  875. public getStencilOperationFail(): number {
  876. return this._stencilState.stencilOpStencilFail;
  877. }
  878. /**
  879. * Gets the current stencil operation when depth fails
  880. * @returns a number defining stencil operation to use when depth fails
  881. */
  882. public getStencilOperationDepthFail(): number {
  883. return this._stencilState.stencilOpDepthFail;
  884. }
  885. /**
  886. * Gets the current stencil operation when stencil passes
  887. * @returns a number defining stencil operation to use when stencil passes
  888. */
  889. public getStencilOperationPass(): number {
  890. return this._stencilState.stencilOpStencilDepthPass;
  891. }
  892. /**
  893. * Sets the stencil operation to use when stencil fails
  894. * @param operation defines the stencil operation to use when stencil fails
  895. */
  896. public setStencilOperationFail(operation: number): void {
  897. this._stencilState.stencilOpStencilFail = operation;
  898. }
  899. /**
  900. * Sets the stencil operation to use when depth fails
  901. * @param operation defines the stencil operation to use when depth fails
  902. */
  903. public setStencilOperationDepthFail(operation: number): void {
  904. this._stencilState.stencilOpDepthFail = operation;
  905. }
  906. /**
  907. * Sets the stencil operation to use when stencil passes
  908. * @param operation defines the stencil operation to use when stencil passes
  909. */
  910. public setStencilOperationPass(operation: number): void {
  911. this._stencilState.stencilOpStencilDepthPass = operation;
  912. }
  913. /**
  914. * Sets a boolean indicating if the dithering state is enabled or disabled
  915. * @param value defines the dithering state
  916. */
  917. public setDitheringState(value: boolean): void {
  918. if (value) {
  919. this._gl.enable(this._gl.DITHER);
  920. } else {
  921. this._gl.disable(this._gl.DITHER);
  922. }
  923. }
  924. /**
  925. * Sets a boolean indicating if the rasterizer state is enabled or disabled
  926. * @param value defines the rasterizer state
  927. */
  928. public setRasterizerState(value: boolean): void {
  929. if (value) {
  930. this._gl.disable(this._gl.RASTERIZER_DISCARD);
  931. } else {
  932. this._gl.enable(this._gl.RASTERIZER_DISCARD);
  933. }
  934. }
  935. /**
  936. * Gets the current depth function
  937. * @returns a number defining the depth function
  938. */
  939. public getDepthFunction(): Nullable<number> {
  940. return this._depthCullingState.depthFunc;
  941. }
  942. /**
  943. * Sets the current depth function
  944. * @param depthFunc defines the function to use
  945. */
  946. public setDepthFunction(depthFunc: number) {
  947. this._depthCullingState.depthFunc = depthFunc;
  948. }
  949. /**
  950. * Sets the current depth function to GREATER
  951. */
  952. public setDepthFunctionToGreater(): void {
  953. this._depthCullingState.depthFunc = this._gl.GREATER;
  954. }
  955. /**
  956. * Sets the current depth function to GEQUAL
  957. */
  958. public setDepthFunctionToGreaterOrEqual(): void {
  959. this._depthCullingState.depthFunc = this._gl.GEQUAL;
  960. }
  961. /**
  962. * Sets the current depth function to LESS
  963. */
  964. public setDepthFunctionToLess(): void {
  965. this._depthCullingState.depthFunc = this._gl.LESS;
  966. }
  967. /**
  968. * Sets the current depth function to LEQUAL
  969. */
  970. public setDepthFunctionToLessOrEqual(): void {
  971. this._depthCullingState.depthFunc = this._gl.LEQUAL;
  972. }
  973. private _cachedStencilBuffer: boolean;
  974. private _cachedStencilFunction: number;
  975. private _cachedStencilMask: number;
  976. private _cachedStencilOperationPass: number;
  977. private _cachedStencilOperationFail: number;
  978. private _cachedStencilOperationDepthFail: number;
  979. private _cachedStencilReference: number;
  980. /**
  981. * Caches the the state of the stencil buffer
  982. */
  983. public cacheStencilState() {
  984. this._cachedStencilBuffer = this.getStencilBuffer();
  985. this._cachedStencilFunction = this.getStencilFunction();
  986. this._cachedStencilMask = this.getStencilMask();
  987. this._cachedStencilOperationPass = this.getStencilOperationPass();
  988. this._cachedStencilOperationFail = this.getStencilOperationFail();
  989. this._cachedStencilOperationDepthFail = this.getStencilOperationDepthFail();
  990. this._cachedStencilReference = this.getStencilFunctionReference();
  991. }
  992. /**
  993. * Restores the state of the stencil buffer
  994. */
  995. public restoreStencilState() {
  996. this.setStencilFunction(this._cachedStencilFunction);
  997. this.setStencilMask(this._cachedStencilMask);
  998. this.setStencilBuffer(this._cachedStencilBuffer);
  999. this.setStencilOperationPass(this._cachedStencilOperationPass);
  1000. this.setStencilOperationFail(this._cachedStencilOperationFail);
  1001. this.setStencilOperationDepthFail(this._cachedStencilOperationDepthFail);
  1002. this.setStencilFunctionReference(this._cachedStencilReference);
  1003. }
  1004. /**
  1005. * Directly set the WebGL Viewport
  1006. * @param x defines the x coordinate of the viewport (in screen space)
  1007. * @param y defines the y coordinate of the viewport (in screen space)
  1008. * @param width defines the width of the viewport (in screen space)
  1009. * @param height defines the height of the viewport (in screen space)
  1010. * @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
  1011. */
  1012. public setDirectViewport(x: number, y: number, width: number, height: number): Nullable<IViewportLike> {
  1013. let currentViewport = this._cachedViewport;
  1014. this._cachedViewport = null;
  1015. this._viewport(x, y, width, height);
  1016. return currentViewport;
  1017. }
  1018. /**
  1019. * Executes a scissor clear (ie. a clear on a specific portion of the screen)
  1020. * @param x defines the x-coordinate of the top left corner of the clear rectangle
  1021. * @param y defines the y-coordinate of the corner of the clear rectangle
  1022. * @param width defines the width of the clear rectangle
  1023. * @param height defines the height of the clear rectangle
  1024. * @param clearColor defines the clear color
  1025. */
  1026. public scissorClear(x: number, y: number, width: number, height: number, clearColor: IColor4Like): void {
  1027. this.enableScissor(x, y, width, height);
  1028. this.clear(clearColor, true, true, true);
  1029. this.disableScissor();
  1030. }
  1031. /**
  1032. * Enable scissor test on a specific rectangle (ie. render will only be executed on a specific portion of the screen)
  1033. * @param x defines the x-coordinate of the top left corner of the clear rectangle
  1034. * @param y defines the y-coordinate of the corner of the clear rectangle
  1035. * @param width defines the width of the clear rectangle
  1036. * @param height defines the height of the clear rectangle
  1037. */
  1038. public enableScissor(x: number, y: number, width: number, height: number): void {
  1039. let gl = this._gl;
  1040. // Change state
  1041. gl.enable(gl.SCISSOR_TEST);
  1042. gl.scissor(x, y, width, height);
  1043. }
  1044. /**
  1045. * Disable previously set scissor test rectangle
  1046. */
  1047. public disableScissor() {
  1048. let gl = this._gl;
  1049. gl.disable(gl.SCISSOR_TEST);
  1050. }
  1051. protected _reportDrawCall() {
  1052. this._drawCalls.addCount(1, false);
  1053. }
  1054. /**
  1055. * Initializes a webVR display and starts listening to display change events
  1056. * The onVRDisplayChangedObservable will be notified upon these changes
  1057. * @returns The onVRDisplayChangedObservable
  1058. */
  1059. public initWebVR(): Observable<IDisplayChangedEventArgs> {
  1060. throw _DevTools.WarnImport("WebVRCamera");
  1061. }
  1062. /** @hidden */
  1063. public _prepareVRComponent() {
  1064. // Do nothing as the engine side effect will overload it
  1065. }
  1066. /** @hidden */
  1067. public _connectVREvents(canvas?: HTMLCanvasElement, document?: any) {
  1068. // Do nothing as the engine side effect will overload it
  1069. }
  1070. /** @hidden */
  1071. public _submitVRFrame() {
  1072. // Do nothing as the engine side effect will overload it
  1073. }
  1074. /**
  1075. * Call this function to leave webVR mode
  1076. * Will do nothing if webVR is not supported or if there is no webVR device
  1077. * @see http://doc.babylonjs.com/how_to/webvr_camera
  1078. */
  1079. public disableVR() {
  1080. // Do nothing as the engine side effect will overload it
  1081. }
  1082. /**
  1083. * Gets a boolean indicating that the system is in VR mode and is presenting
  1084. * @returns true if VR mode is engaged
  1085. */
  1086. public isVRPresenting() {
  1087. return false;
  1088. }
  1089. /** @hidden */
  1090. public _requestVRFrame() {
  1091. // Do nothing as the engine side effect will overload it
  1092. }
  1093. /** @hidden */
  1094. public _loadFileAsync(url: string, offlineProvider?: IOfflineProvider, useArrayBuffer?: boolean): Promise<string | ArrayBuffer> {
  1095. return new Promise((resolve, reject) => {
  1096. this._loadFile(url, (data) => {
  1097. resolve(data);
  1098. }, undefined, offlineProvider, useArrayBuffer, (request, exception) => {
  1099. reject(exception);
  1100. });
  1101. });
  1102. }
  1103. /**
  1104. * Gets the source code of the vertex shader associated with a specific webGL program
  1105. * @param program defines the program to use
  1106. * @returns a string containing the source code of the vertex shader associated with the program
  1107. */
  1108. public getVertexShaderSource(program: WebGLProgram): Nullable<string> {
  1109. var shaders = this._gl.getAttachedShaders(program);
  1110. if (!shaders) {
  1111. return null;
  1112. }
  1113. return this._gl.getShaderSource(shaders[0]);
  1114. }
  1115. /**
  1116. * Gets the source code of the fragment shader associated with a specific webGL program
  1117. * @param program defines the program to use
  1118. * @returns a string containing the source code of the fragment shader associated with the program
  1119. */
  1120. public getFragmentShaderSource(program: WebGLProgram): Nullable<string> {
  1121. var shaders = this._gl.getAttachedShaders(program);
  1122. if (!shaders) {
  1123. return null;
  1124. }
  1125. return this._gl.getShaderSource(shaders[1]);
  1126. }
  1127. /**
  1128. * Reads pixels from the current frame buffer. Please note that this function can be slow
  1129. * @param x defines the x coordinate of the rectangle where pixels must be read
  1130. * @param y defines the y coordinate of the rectangle where pixels must be read
  1131. * @param width defines the width of the rectangle where pixels must be read
  1132. * @param height defines the height of the rectangle where pixels must be read
  1133. * @returns a Uint8Array containing RGBA colors
  1134. */
  1135. public readPixels(x: number, y: number, width: number, height: number): Uint8Array {
  1136. var data = new Uint8Array(height * width * 4);
  1137. this._gl.readPixels(x, y, width, height, this._gl.RGBA, this._gl.UNSIGNED_BYTE, data);
  1138. return data;
  1139. }
  1140. /**
  1141. * Sets a depth stencil texture from a render target to the according uniform.
  1142. * @param channel The texture channel
  1143. * @param uniform The uniform to set
  1144. * @param texture The render target texture containing the depth stencil texture to apply
  1145. */
  1146. public setDepthStencilTexture(channel: number, uniform: Nullable<WebGLUniformLocation>, texture: Nullable<RenderTargetTexture>): void {
  1147. if (channel === undefined) {
  1148. return;
  1149. }
  1150. if (uniform) {
  1151. this._boundUniforms[channel] = uniform;
  1152. }
  1153. if (!texture || !texture.depthStencilTexture) {
  1154. this._setTexture(channel, null);
  1155. }
  1156. else {
  1157. this._setTexture(channel, texture, false, true);
  1158. }
  1159. }
  1160. /**
  1161. * Sets a texture to the webGL context from a postprocess
  1162. * @param channel defines the channel to use
  1163. * @param postProcess defines the source postprocess
  1164. */
  1165. public setTextureFromPostProcess(channel: number, postProcess: Nullable<PostProcess>): void {
  1166. this._bindTexture(channel, postProcess ? postProcess._textures.data[postProcess._currentRenderTextureInd] : null);
  1167. }
  1168. /**
  1169. * Binds the output of the passed in post process to the texture channel specified
  1170. * @param channel The channel the texture should be bound to
  1171. * @param postProcess The post process which's output should be bound
  1172. */
  1173. public setTextureFromPostProcessOutput(channel: number, postProcess: Nullable<PostProcess>): void {
  1174. this._bindTexture(channel, postProcess ? postProcess._outputTexture : null);
  1175. }
  1176. /** @hidden */
  1177. public _convertRGBtoRGBATextureData(rgbData: any, width: number, height: number, textureType: number): ArrayBufferView {
  1178. // Create new RGBA data container.
  1179. var rgbaData: any;
  1180. if (textureType === Constants.TEXTURETYPE_FLOAT) {
  1181. rgbaData = new Float32Array(width * height * 4);
  1182. }
  1183. else {
  1184. rgbaData = new Uint32Array(width * height * 4);
  1185. }
  1186. // Convert each pixel.
  1187. for (let x = 0; x < width; x++) {
  1188. for (let y = 0; y < height; y++) {
  1189. let index = (y * width + x) * 3;
  1190. let newIndex = (y * width + x) * 4;
  1191. // Map Old Value to new value.
  1192. rgbaData[newIndex + 0] = rgbData[index + 0];
  1193. rgbaData[newIndex + 1] = rgbData[index + 1];
  1194. rgbaData[newIndex + 2] = rgbData[index + 2];
  1195. // Add fully opaque alpha channel.
  1196. rgbaData[newIndex + 3] = 1;
  1197. }
  1198. }
  1199. return rgbaData;
  1200. }
  1201. protected _rebuildBuffers(): void {
  1202. // Index / Vertex
  1203. for (var scene of this.scenes) {
  1204. scene.resetCachedMaterial();
  1205. scene._rebuildGeometries();
  1206. scene._rebuildTextures();
  1207. }
  1208. super._rebuildBuffers();
  1209. }
  1210. /** @hidden */
  1211. public _renderFrame() {
  1212. for (var index = 0; index < this._activeRenderLoops.length; index++) {
  1213. var renderFunction = this._activeRenderLoops[index];
  1214. renderFunction();
  1215. }
  1216. }
  1217. public _renderLoop(): void {
  1218. if (!this._contextWasLost) {
  1219. var shouldRender = true;
  1220. if (!this.renderEvenInBackground && this._windowIsBackground) {
  1221. shouldRender = false;
  1222. }
  1223. if (shouldRender) {
  1224. // Start new frame
  1225. this.beginFrame();
  1226. // Child canvases
  1227. if (!this._renderViews()) {
  1228. // Main frame
  1229. this._renderFrame();
  1230. }
  1231. // Present
  1232. this.endFrame();
  1233. }
  1234. }
  1235. if (this._activeRenderLoops.length > 0) {
  1236. // Register new frame
  1237. if (this.customAnimationFrameRequester) {
  1238. this.customAnimationFrameRequester.requestID = this._queueNewFrame(this.customAnimationFrameRequester.renderFunction || this._boundRenderFunction, this.customAnimationFrameRequester);
  1239. this._frameHandler = this.customAnimationFrameRequester.requestID;
  1240. } else if (this.isVRPresenting()) {
  1241. this._requestVRFrame();
  1242. } else {
  1243. this._frameHandler = this._queueNewFrame(this._boundRenderFunction, this.getHostWindow());
  1244. }
  1245. } else {
  1246. this._renderingQueueLaunched = false;
  1247. }
  1248. }
  1249. /** @hidden */
  1250. public _renderViews() {
  1251. return false;
  1252. }
  1253. /**
  1254. * Toggle full screen mode
  1255. * @param requestPointerLock defines if a pointer lock should be requested from the user
  1256. */
  1257. public switchFullscreen(requestPointerLock: boolean): void {
  1258. if (this.isFullscreen) {
  1259. this.exitFullscreen();
  1260. } else {
  1261. this.enterFullscreen(requestPointerLock);
  1262. }
  1263. }
  1264. /**
  1265. * Enters full screen mode
  1266. * @param requestPointerLock defines if a pointer lock should be requested from the user
  1267. */
  1268. public enterFullscreen(requestPointerLock: boolean): void {
  1269. if (!this.isFullscreen) {
  1270. this._pointerLockRequested = requestPointerLock;
  1271. if (this._renderingCanvas) {
  1272. Engine._RequestFullscreen(this._renderingCanvas);
  1273. }
  1274. }
  1275. }
  1276. /**
  1277. * Exits full screen mode
  1278. */
  1279. public exitFullscreen(): void {
  1280. if (this.isFullscreen) {
  1281. Engine._ExitFullscreen();
  1282. }
  1283. }
  1284. /**
  1285. * Enters Pointerlock mode
  1286. */
  1287. public enterPointerlock(): void {
  1288. if (this._renderingCanvas) {
  1289. Engine._RequestPointerlock(this._renderingCanvas);
  1290. }
  1291. }
  1292. /**
  1293. * Exits Pointerlock mode
  1294. */
  1295. public exitPointerlock(): void {
  1296. Engine._ExitPointerlock();
  1297. }
  1298. /**
  1299. * Begin a new frame
  1300. */
  1301. public beginFrame(): void {
  1302. this._measureFps();
  1303. this.onBeginFrameObservable.notifyObservers(this);
  1304. super.beginFrame();
  1305. }
  1306. /**
  1307. * Enf the current frame
  1308. */
  1309. public endFrame(): void {
  1310. super.endFrame();
  1311. this._submitVRFrame();
  1312. this.onEndFrameObservable.notifyObservers(this);
  1313. }
  1314. public resize(): void {
  1315. // We're not resizing the size of the canvas while in VR mode & presenting
  1316. if (this.isVRPresenting()) {
  1317. return;
  1318. }
  1319. super.resize();
  1320. }
  1321. /**
  1322. * Set the compressed texture format to use, based on the formats you have, and the formats
  1323. * supported by the hardware / browser.
  1324. *
  1325. * Khronos Texture Container (.ktx) files are used to support this. This format has the
  1326. * advantage of being specifically designed for OpenGL. Header elements directly correspond
  1327. * to API arguments needed to compressed textures. This puts the burden on the container
  1328. * generator to house the arcane code for determining these for current & future formats.
  1329. *
  1330. * for description see https://www.khronos.org/opengles/sdk/tools/KTX/
  1331. * for file layout see https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/
  1332. *
  1333. * Note: The result of this call is not taken into account when a texture is base64.
  1334. *
  1335. * @param formatsAvailable defines the list of those format families you have created
  1336. * on your server. Syntax: '-' + format family + '.ktx'. (Case and order do not matter.)
  1337. *
  1338. * Current families are astc, dxt, pvrtc, etc2, & etc1.
  1339. * @returns The extension selected.
  1340. */
  1341. public setTextureFormatToUse(formatsAvailable: Array<string>): Nullable<string> {
  1342. for (var i = 0, len1 = this.texturesSupported.length; i < len1; i++) {
  1343. for (var j = 0, len2 = formatsAvailable.length; j < len2; j++) {
  1344. if (this._texturesSupported[i] === formatsAvailable[j].toLowerCase()) {
  1345. return this._textureFormatInUse = this._texturesSupported[i];
  1346. }
  1347. }
  1348. }
  1349. // actively set format to nothing, to allow this to be called more than once
  1350. // and possibly fail the 2nd time
  1351. this._textureFormatInUse = null;
  1352. return null;
  1353. }
  1354. /**
  1355. * Force a specific size of the canvas
  1356. * @param width defines the new canvas' width
  1357. * @param height defines the new canvas' height
  1358. */
  1359. public setSize(width: number, height: number): void {
  1360. if (!this._renderingCanvas) {
  1361. return;
  1362. }
  1363. super.setSize(width, height);
  1364. if (this.scenes) {
  1365. for (var index = 0; index < this.scenes.length; index++) {
  1366. var scene = this.scenes[index];
  1367. for (var camIndex = 0; camIndex < scene.cameras.length; camIndex++) {
  1368. var cam = scene.cameras[camIndex];
  1369. cam._currentRenderId = 0;
  1370. }
  1371. }
  1372. if (this.onResizeObservable.hasObservers) {
  1373. this.onResizeObservable.notifyObservers(this);
  1374. }
  1375. }
  1376. }
  1377. /**
  1378. * Updates a dynamic vertex buffer.
  1379. * @param vertexBuffer the vertex buffer to update
  1380. * @param data the data used to update the vertex buffer
  1381. * @param byteOffset the byte offset of the data
  1382. * @param byteLength the byte length of the data
  1383. */
  1384. public updateDynamicVertexBuffer(vertexBuffer: DataBuffer, data: DataArray, byteOffset?: number, byteLength?: number): void {
  1385. this.bindArrayBuffer(vertexBuffer);
  1386. if (byteOffset === undefined) {
  1387. byteOffset = 0;
  1388. }
  1389. const dataLength = (data as number[]).length || (data as ArrayBuffer).byteLength;
  1390. if (byteLength === undefined || byteLength >= dataLength && byteOffset === 0) {
  1391. if (data instanceof Array) {
  1392. this._gl.bufferSubData(this._gl.ARRAY_BUFFER, byteOffset, new Float32Array(data));
  1393. } else {
  1394. this._gl.bufferSubData(this._gl.ARRAY_BUFFER, byteOffset, <ArrayBuffer>data);
  1395. }
  1396. } else {
  1397. if (data instanceof Array) {
  1398. this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, new Float32Array(data).subarray(byteOffset, byteOffset + byteLength));
  1399. } else {
  1400. if (data instanceof ArrayBuffer) {
  1401. data = new Uint8Array(data, byteOffset, byteLength);
  1402. } else {
  1403. data = new Uint8Array(data.buffer, data.byteOffset + byteOffset, byteLength);
  1404. }
  1405. this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, <ArrayBuffer>data);
  1406. }
  1407. }
  1408. this._resetVertexBufferBinding();
  1409. }
  1410. public _deletePipelineContext(pipelineContext: IPipelineContext): void {
  1411. let webGLPipelineContext = pipelineContext as WebGLPipelineContext;
  1412. if (webGLPipelineContext && webGLPipelineContext.program) {
  1413. if (webGLPipelineContext.transformFeedback) {
  1414. this.deleteTransformFeedback(webGLPipelineContext.transformFeedback);
  1415. webGLPipelineContext.transformFeedback = null;
  1416. }
  1417. }
  1418. super._deletePipelineContext(pipelineContext);
  1419. }
  1420. public createShaderProgram(pipelineContext: IPipelineContext, vertexCode: string, fragmentCode: string, defines: Nullable<string>, context?: WebGLRenderingContext, transformFeedbackVaryings: Nullable<string[]> = null): WebGLProgram {
  1421. context = context || this._gl;
  1422. this.onBeforeShaderCompilationObservable.notifyObservers(this);
  1423. let program = super.createShaderProgram(pipelineContext, vertexCode, fragmentCode, defines, context, transformFeedbackVaryings);
  1424. this.onAfterShaderCompilationObservable.notifyObservers(this);
  1425. return program;
  1426. }
  1427. protected _createShaderProgram(pipelineContext: WebGLPipelineContext, vertexShader: WebGLShader, fragmentShader: WebGLShader, context: WebGLRenderingContext, transformFeedbackVaryings: Nullable<string[]> = null): WebGLProgram {
  1428. var shaderProgram = context.createProgram();
  1429. pipelineContext.program = shaderProgram;
  1430. if (!shaderProgram) {
  1431. throw new Error("Unable to create program");
  1432. }
  1433. context.attachShader(shaderProgram, vertexShader);
  1434. context.attachShader(shaderProgram, fragmentShader);
  1435. if (this.webGLVersion > 1 && transformFeedbackVaryings) {
  1436. let transformFeedback = this.createTransformFeedback();
  1437. this.bindTransformFeedback(transformFeedback);
  1438. this.setTranformFeedbackVaryings(shaderProgram, transformFeedbackVaryings);
  1439. pipelineContext.transformFeedback = transformFeedback;
  1440. }
  1441. context.linkProgram(shaderProgram);
  1442. if (this.webGLVersion > 1 && transformFeedbackVaryings) {
  1443. this.bindTransformFeedback(null);
  1444. }
  1445. pipelineContext.context = context;
  1446. pipelineContext.vertexShader = vertexShader;
  1447. pipelineContext.fragmentShader = fragmentShader;
  1448. if (!pipelineContext.isParallelCompiled) {
  1449. this._finalizePipelineContext(pipelineContext);
  1450. }
  1451. return shaderProgram;
  1452. }
  1453. public _releaseTexture(texture: InternalTexture): void {
  1454. super._releaseTexture(texture);
  1455. // Set output texture of post process to null if the texture has been released/disposed
  1456. this.scenes.forEach((scene) => {
  1457. scene.postProcesses.forEach((postProcess) => {
  1458. if (postProcess._outputTexture == texture) {
  1459. postProcess._outputTexture = null;
  1460. }
  1461. });
  1462. scene.cameras.forEach((camera) => {
  1463. camera._postProcesses.forEach((postProcess) => {
  1464. if (postProcess) {
  1465. if (postProcess._outputTexture == texture) {
  1466. postProcess._outputTexture = null;
  1467. }
  1468. }
  1469. });
  1470. });
  1471. });
  1472. }
  1473. /**
  1474. * @hidden
  1475. * Rescales a texture
  1476. * @param source input texutre
  1477. * @param destination destination texture
  1478. * @param scene scene to use to render the resize
  1479. * @param internalFormat format to use when resizing
  1480. * @param onComplete callback to be called when resize has completed
  1481. */
  1482. public _rescaleTexture(source: InternalTexture, destination: InternalTexture, scene: Nullable<any>, internalFormat: number, onComplete: () => void): void {
  1483. this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_MAG_FILTER, this._gl.LINEAR);
  1484. this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_MIN_FILTER, this._gl.LINEAR);
  1485. this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_WRAP_S, this._gl.CLAMP_TO_EDGE);
  1486. this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_WRAP_T, this._gl.CLAMP_TO_EDGE);
  1487. let rtt = this.createRenderTargetTexture({
  1488. width: destination.width,
  1489. height: destination.height,
  1490. }, {
  1491. generateMipMaps: false,
  1492. type: Constants.TEXTURETYPE_UNSIGNED_INT,
  1493. samplingMode: Constants.TEXTURE_BILINEAR_SAMPLINGMODE,
  1494. generateDepthBuffer: false,
  1495. generateStencilBuffer: false
  1496. }
  1497. );
  1498. if (!this._rescalePostProcess && Engine._RescalePostProcessFactory) {
  1499. this._rescalePostProcess = Engine._RescalePostProcessFactory(this);
  1500. }
  1501. this._rescalePostProcess.getEffect().executeWhenCompiled(() => {
  1502. this._rescalePostProcess.onApply = function(effect) {
  1503. effect._bindTexture("textureSampler", source);
  1504. };
  1505. let hostingScene: Scene = scene;
  1506. if (!hostingScene) {
  1507. hostingScene = this.scenes[this.scenes.length - 1];
  1508. }
  1509. hostingScene.postProcessManager.directRender([this._rescalePostProcess], rtt, true);
  1510. this._bindTextureDirectly(this._gl.TEXTURE_2D, destination, true);
  1511. this._gl.copyTexImage2D(this._gl.TEXTURE_2D, 0, internalFormat, 0, 0, destination.width, destination.height, 0);
  1512. this.unBindFramebuffer(rtt);
  1513. this._releaseTexture(rtt);
  1514. if (onComplete) {
  1515. onComplete();
  1516. }
  1517. });
  1518. }
  1519. // FPS
  1520. /**
  1521. * Gets the current framerate
  1522. * @returns a number representing the framerate
  1523. */
  1524. public getFps(): number {
  1525. return this._fps;
  1526. }
  1527. /**
  1528. * Gets the time spent between current and previous frame
  1529. * @returns a number representing the delta time in ms
  1530. */
  1531. public getDeltaTime(): number {
  1532. return this._deltaTime;
  1533. }
  1534. private _measureFps(): void {
  1535. this._performanceMonitor.sampleFrame();
  1536. this._fps = this._performanceMonitor.averageFPS;
  1537. this._deltaTime = this._performanceMonitor.instantaneousFrameTime || 0;
  1538. }
  1539. /** @hidden */
  1540. public _uploadImageToTexture(texture: InternalTexture, image: HTMLImageElement | ImageBitmap, faceIndex: number = 0, lod: number = 0) {
  1541. var gl = this._gl;
  1542. var textureType = this._getWebGLTextureType(texture.type);
  1543. var format = this._getInternalFormat(texture.format);
  1544. var internalFormat = this._getRGBABufferInternalSizedFormat(texture.type, format);
  1545. var bindTarget = texture.isCube ? gl.TEXTURE_CUBE_MAP : gl.TEXTURE_2D;
  1546. this._bindTextureDirectly(bindTarget, texture, true);
  1547. this._unpackFlipY(texture.invertY);
  1548. var target = gl.TEXTURE_2D;
  1549. if (texture.isCube) {
  1550. target = gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex;
  1551. }
  1552. gl.texImage2D(target, lod, internalFormat, format, textureType, image);
  1553. this._bindTextureDirectly(bindTarget, null, true);
  1554. }
  1555. /**
  1556. * Sets the frame buffer Depth / Stencil attachement of the render target to the defined depth stencil texture.
  1557. * @param renderTarget The render target to set the frame buffer for
  1558. */
  1559. public setFrameBufferDepthStencilTexture(renderTarget: RenderTargetTexture): void {
  1560. // Create the framebuffer
  1561. var internalTexture = renderTarget.getInternalTexture();
  1562. if (!internalTexture || !internalTexture._framebuffer || !renderTarget.depthStencilTexture) {
  1563. return;
  1564. }
  1565. var gl = this._gl;
  1566. var depthStencilTexture = renderTarget.depthStencilTexture;
  1567. this._bindUnboundFramebuffer(internalTexture._framebuffer);
  1568. if (depthStencilTexture.isCube) {
  1569. if (depthStencilTexture._generateStencilBuffer) {
  1570. gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.TEXTURE_CUBE_MAP_POSITIVE_X, depthStencilTexture._webGLTexture, 0);
  1571. }
  1572. else {
  1573. gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_CUBE_MAP_POSITIVE_X, depthStencilTexture._webGLTexture, 0);
  1574. }
  1575. }
  1576. else {
  1577. if (depthStencilTexture._generateStencilBuffer) {
  1578. gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.TEXTURE_2D, depthStencilTexture._webGLTexture, 0);
  1579. }
  1580. else {
  1581. gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, depthStencilTexture._webGLTexture, 0);
  1582. }
  1583. }
  1584. this._bindUnboundFramebuffer(null);
  1585. }
  1586. /**
  1587. * Update a dynamic index buffer
  1588. * @param indexBuffer defines the target index buffer
  1589. * @param indices defines the data to update
  1590. * @param offset defines the offset in the target index buffer where update should start
  1591. */
  1592. public updateDynamicIndexBuffer(indexBuffer: DataBuffer, indices: IndicesArray, offset: number = 0): void {
  1593. // Force cache update
  1594. this._currentBoundBuffer[this._gl.ELEMENT_ARRAY_BUFFER] = null;
  1595. this.bindIndexBuffer(indexBuffer);
  1596. var arrayBuffer;
  1597. if (indices instanceof Uint16Array || indices instanceof Uint32Array) {
  1598. arrayBuffer = indices;
  1599. } else {
  1600. arrayBuffer = indexBuffer.is32Bits ? new Uint32Array(indices) : new Uint16Array(indices);
  1601. }
  1602. this._gl.bufferData(this._gl.ELEMENT_ARRAY_BUFFER, arrayBuffer, this._gl.DYNAMIC_DRAW);
  1603. this._resetIndexBufferBinding();
  1604. }
  1605. /**
  1606. * Updates the sample count of a render target texture
  1607. * @see http://doc.babylonjs.com/features/webgl2#multisample-render-targets
  1608. * @param texture defines the texture to update
  1609. * @param samples defines the sample count to set
  1610. * @returns the effective sample count (could be 0 if multisample render targets are not supported)
  1611. */
  1612. public updateRenderTargetTextureSampleCount(texture: Nullable<InternalTexture>, samples: number): number {
  1613. if (this.webGLVersion < 2 || !texture) {
  1614. return 1;
  1615. }
  1616. if (texture.samples === samples) {
  1617. return samples;
  1618. }
  1619. var gl = this._gl;
  1620. samples = Math.min(samples, this.getCaps().maxMSAASamples);
  1621. // Dispose previous render buffers
  1622. if (texture._depthStencilBuffer) {
  1623. gl.deleteRenderbuffer(texture._depthStencilBuffer);
  1624. texture._depthStencilBuffer = null;
  1625. }
  1626. if (texture._MSAAFramebuffer) {
  1627. gl.deleteFramebuffer(texture._MSAAFramebuffer);
  1628. texture._MSAAFramebuffer = null;
  1629. }
  1630. if (texture._MSAARenderBuffer) {
  1631. gl.deleteRenderbuffer(texture._MSAARenderBuffer);
  1632. texture._MSAARenderBuffer = null;
  1633. }
  1634. if (samples > 1) {
  1635. let framebuffer = gl.createFramebuffer();
  1636. if (!framebuffer) {
  1637. throw new Error("Unable to create multi sampled framebuffer");
  1638. }
  1639. texture._MSAAFramebuffer = framebuffer;
  1640. this._bindUnboundFramebuffer(texture._MSAAFramebuffer);
  1641. var colorRenderbuffer = gl.createRenderbuffer();
  1642. if (!colorRenderbuffer) {
  1643. throw new Error("Unable to create multi sampled framebuffer");
  1644. }
  1645. gl.bindRenderbuffer(gl.RENDERBUFFER, colorRenderbuffer);
  1646. gl.renderbufferStorageMultisample(gl.RENDERBUFFER, samples, this._getRGBAMultiSampleBufferFormat(texture.type), texture.width, texture.height);
  1647. gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorRenderbuffer);
  1648. texture._MSAARenderBuffer = colorRenderbuffer;
  1649. } else {
  1650. this._bindUnboundFramebuffer(texture._framebuffer);
  1651. }
  1652. texture.samples = samples;
  1653. texture._depthStencilBuffer = this._setupFramebufferDepthAttachments(texture._generateStencilBuffer, texture._generateDepthBuffer, texture.width, texture.height, samples);
  1654. gl.bindRenderbuffer(gl.RENDERBUFFER, null);
  1655. this._bindUnboundFramebuffer(null);
  1656. return samples;
  1657. }
  1658. /**
  1659. * Updates a depth texture Comparison Mode and Function.
  1660. * If the comparison Function is equal to 0, the mode will be set to none.
  1661. * Otherwise, this only works in webgl 2 and requires a shadow sampler in the shader.
  1662. * @param texture The texture to set the comparison function for
  1663. * @param comparisonFunction The comparison function to set, 0 if no comparison required
  1664. */
  1665. public updateTextureComparisonFunction(texture: InternalTexture, comparisonFunction: number): void {
  1666. if (this.webGLVersion === 1) {
  1667. Logger.Error("WebGL 1 does not support texture comparison.");
  1668. return;
  1669. }
  1670. var gl = this._gl;
  1671. if (texture.isCube) {
  1672. this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, texture, true);
  1673. if (comparisonFunction === 0) {
  1674. gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_COMPARE_FUNC, Constants.LEQUAL);
  1675. gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_COMPARE_MODE, gl.NONE);
  1676. }
  1677. else {
  1678. gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_COMPARE_FUNC, comparisonFunction);
  1679. gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_COMPARE_MODE, gl.COMPARE_REF_TO_TEXTURE);
  1680. }
  1681. this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, null);
  1682. } else {
  1683. this._bindTextureDirectly(this._gl.TEXTURE_2D, texture, true);
  1684. if (comparisonFunction === 0) {
  1685. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_COMPARE_FUNC, Constants.LEQUAL);
  1686. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_COMPARE_MODE, gl.NONE);
  1687. }
  1688. else {
  1689. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_COMPARE_FUNC, comparisonFunction);
  1690. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_COMPARE_MODE, gl.COMPARE_REF_TO_TEXTURE);
  1691. }
  1692. this._bindTextureDirectly(this._gl.TEXTURE_2D, null);
  1693. }
  1694. texture._comparisonFunction = comparisonFunction;
  1695. }
  1696. /**
  1697. * Creates a webGL buffer to use with instanciation
  1698. * @param capacity defines the size of the buffer
  1699. * @returns the webGL buffer
  1700. */
  1701. public createInstancesBuffer(capacity: number): DataBuffer {
  1702. var buffer = this._gl.createBuffer();
  1703. if (!buffer) {
  1704. throw new Error("Unable to create instance buffer");
  1705. }
  1706. var result = new WebGLDataBuffer(buffer);
  1707. result.capacity = capacity;
  1708. this.bindArrayBuffer(result);
  1709. this._gl.bufferData(this._gl.ARRAY_BUFFER, capacity, this._gl.DYNAMIC_DRAW);
  1710. return result;
  1711. }
  1712. /**
  1713. * Delete a webGL buffer used with instanciation
  1714. * @param buffer defines the webGL buffer to delete
  1715. */
  1716. public deleteInstancesBuffer(buffer: WebGLBuffer): void {
  1717. this._gl.deleteBuffer(buffer);
  1718. }
  1719. /** @hidden */
  1720. public _readTexturePixels(texture: InternalTexture, width: number, height: number, faceIndex = -1, level = 0, buffer: Nullable<ArrayBufferView> = null): ArrayBufferView {
  1721. let gl = this._gl;
  1722. if (!this._dummyFramebuffer) {
  1723. let dummy = gl.createFramebuffer();
  1724. if (!dummy) {
  1725. throw new Error("Unable to create dummy framebuffer");
  1726. }
  1727. this._dummyFramebuffer = dummy;
  1728. }
  1729. gl.bindFramebuffer(gl.FRAMEBUFFER, this._dummyFramebuffer);
  1730. if (faceIndex > -1) {
  1731. gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, texture._webGLTexture, level);
  1732. } else {
  1733. gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture._webGLTexture, level);
  1734. }
  1735. let readType = (texture.type !== undefined) ? this._getWebGLTextureType(texture.type) : gl.UNSIGNED_BYTE;
  1736. switch (readType) {
  1737. case gl.UNSIGNED_BYTE:
  1738. if (!buffer) {
  1739. buffer = new Uint8Array(4 * width * height);
  1740. }
  1741. readType = gl.UNSIGNED_BYTE;
  1742. break;
  1743. default:
  1744. if (!buffer) {
  1745. buffer = new Float32Array(4 * width * height);
  1746. }
  1747. readType = gl.FLOAT;
  1748. break;
  1749. }
  1750. gl.readPixels(0, 0, width, height, gl.RGBA, readType, <DataView>buffer);
  1751. gl.bindFramebuffer(gl.FRAMEBUFFER, this._currentFramebuffer);
  1752. return buffer;
  1753. }
  1754. public dispose(): void {
  1755. this.hideLoadingUI();
  1756. this.onNewSceneAddedObservable.clear();
  1757. // Release postProcesses
  1758. while (this.postProcesses.length) {
  1759. this.postProcesses[0].dispose();
  1760. }
  1761. // Rescale PP
  1762. if (this._rescalePostProcess) {
  1763. this._rescalePostProcess.dispose();
  1764. }
  1765. // Release scenes
  1766. while (this.scenes.length) {
  1767. this.scenes[0].dispose();
  1768. }
  1769. // Release audio engine
  1770. if (Engine.Instances.length === 1 && Engine.audioEngine) {
  1771. Engine.audioEngine.dispose();
  1772. }
  1773. if (this._dummyFramebuffer) {
  1774. this._gl.deleteFramebuffer(this._dummyFramebuffer);
  1775. }
  1776. //WebVR
  1777. this.disableVR();
  1778. // Events
  1779. if (DomManagement.IsWindowObjectExist()) {
  1780. window.removeEventListener("blur", this._onBlur);
  1781. window.removeEventListener("focus", this._onFocus);
  1782. if (this._renderingCanvas) {
  1783. this._renderingCanvas.removeEventListener("focus", this._onCanvasFocus);
  1784. this._renderingCanvas.removeEventListener("blur", this._onCanvasBlur);
  1785. this._renderingCanvas.removeEventListener("pointerout", this._onCanvasPointerOut);
  1786. }
  1787. document.removeEventListener("fullscreenchange", this._onFullscreenChange);
  1788. document.removeEventListener("mozfullscreenchange", this._onFullscreenChange);
  1789. document.removeEventListener("webkitfullscreenchange", this._onFullscreenChange);
  1790. document.removeEventListener("msfullscreenchange", this._onFullscreenChange);
  1791. document.removeEventListener("pointerlockchange", this._onPointerLockChange);
  1792. document.removeEventListener("mspointerlockchange", this._onPointerLockChange);
  1793. document.removeEventListener("mozpointerlockchange", this._onPointerLockChange);
  1794. document.removeEventListener("webkitpointerlockchange", this._onPointerLockChange);
  1795. }
  1796. super.dispose();
  1797. // Remove from Instances
  1798. var index = Engine.Instances.indexOf(this);
  1799. if (index >= 0) {
  1800. Engine.Instances.splice(index, 1);
  1801. }
  1802. // Observables
  1803. this.onResizeObservable.clear();
  1804. this.onCanvasBlurObservable.clear();
  1805. this.onCanvasFocusObservable.clear();
  1806. this.onCanvasPointerOutObservable.clear();
  1807. this.onBeginFrameObservable.clear();
  1808. this.onEndFrameObservable.clear();
  1809. }
  1810. private _disableTouchAction(): void {
  1811. if (!this._renderingCanvas || !this._renderingCanvas.setAttribute) {
  1812. return;
  1813. }
  1814. this._renderingCanvas.setAttribute("touch-action", "none");
  1815. this._renderingCanvas.style.touchAction = "none";
  1816. this._renderingCanvas.style.msTouchAction = "none";
  1817. }
  1818. // Loading screen
  1819. /**
  1820. * Display the loading screen
  1821. * @see http://doc.babylonjs.com/how_to/creating_a_custom_loading_screen
  1822. */
  1823. public displayLoadingUI(): void {
  1824. if (!DomManagement.IsWindowObjectExist()) {
  1825. return;
  1826. }
  1827. const loadingScreen = this.loadingScreen;
  1828. if (loadingScreen) {
  1829. loadingScreen.displayLoadingUI();
  1830. }
  1831. }
  1832. /**
  1833. * Hide the loading screen
  1834. * @see http://doc.babylonjs.com/how_to/creating_a_custom_loading_screen
  1835. */
  1836. public hideLoadingUI(): void {
  1837. if (!DomManagement.IsWindowObjectExist()) {
  1838. return;
  1839. }
  1840. const loadingScreen = this._loadingScreen;
  1841. if (loadingScreen) {
  1842. loadingScreen.hideLoadingUI();
  1843. }
  1844. }
  1845. /**
  1846. * Gets the current loading screen object
  1847. * @see http://doc.babylonjs.com/how_to/creating_a_custom_loading_screen
  1848. */
  1849. public get loadingScreen(): ILoadingScreen {
  1850. if (!this._loadingScreen && this._renderingCanvas) {
  1851. this._loadingScreen = Engine.DefaultLoadingScreenFactory(this._renderingCanvas);
  1852. }
  1853. return this._loadingScreen;
  1854. }
  1855. /**
  1856. * Sets the current loading screen object
  1857. * @see http://doc.babylonjs.com/how_to/creating_a_custom_loading_screen
  1858. */
  1859. public set loadingScreen(loadingScreen: ILoadingScreen) {
  1860. this._loadingScreen = loadingScreen;
  1861. }
  1862. /**
  1863. * Sets the current loading screen text
  1864. * @see http://doc.babylonjs.com/how_to/creating_a_custom_loading_screen
  1865. */
  1866. public set loadingUIText(text: string) {
  1867. this.loadingScreen.loadingUIText = text;
  1868. }
  1869. /**
  1870. * Sets the current loading screen background color
  1871. * @see http://doc.babylonjs.com/how_to/creating_a_custom_loading_screen
  1872. */
  1873. public set loadingUIBackgroundColor(color: string) {
  1874. this.loadingScreen.loadingUIBackgroundColor = color;
  1875. }
  1876. /** Pointerlock and fullscreen */
  1877. /**
  1878. * Ask the browser to promote the current element to pointerlock mode
  1879. * @param element defines the DOM element to promote
  1880. */
  1881. static _RequestPointerlock(element: HTMLElement): void {
  1882. element.requestPointerLock = element.requestPointerLock || (<any>element).msRequestPointerLock || (<any>element).mozRequestPointerLock || (<any>element).webkitRequestPointerLock;
  1883. if (element.requestPointerLock) {
  1884. element.requestPointerLock();
  1885. }
  1886. }
  1887. /**
  1888. * Asks the browser to exit pointerlock mode
  1889. */
  1890. static _ExitPointerlock(): void {
  1891. let anyDoc = document as any;
  1892. document.exitPointerLock = document.exitPointerLock || anyDoc.msExitPointerLock || anyDoc.mozExitPointerLock || anyDoc.webkitExitPointerLock;
  1893. if (document.exitPointerLock) {
  1894. document.exitPointerLock();
  1895. }
  1896. }
  1897. /**
  1898. * Ask the browser to promote the current element to fullscreen rendering mode
  1899. * @param element defines the DOM element to promote
  1900. */
  1901. static _RequestFullscreen(element: HTMLElement): void {
  1902. var requestFunction = element.requestFullscreen || (<any>element).msRequestFullscreen || (<any>element).webkitRequestFullscreen || (<any>element).mozRequestFullScreen;
  1903. if (!requestFunction) { return; }
  1904. requestFunction.call(element);
  1905. }
  1906. /**
  1907. * Asks the browser to exit fullscreen mode
  1908. */
  1909. static _ExitFullscreen(): void {
  1910. let anyDoc = document as any;
  1911. if (document.exitFullscreen) {
  1912. document.exitFullscreen();
  1913. }
  1914. else if (anyDoc.mozCancelFullScreen) {
  1915. anyDoc.mozCancelFullScreen();
  1916. }
  1917. else if (anyDoc.webkitCancelFullScreen) {
  1918. anyDoc.webkitCancelFullScreen();
  1919. }
  1920. else if (anyDoc.msCancelFullScreen) {
  1921. anyDoc.msCancelFullScreen();
  1922. }
  1923. }
  1924. }