engine.ts 80 KB

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