engine.ts 87 KB

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