engine.ts 82 KB

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