babylon.effect.ts 59 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501
  1. module BABYLON {
  2. /**
  3. * EffectFallbacks can be used to add fallbacks (properties to disable) to certain properties when desired to improve performance.
  4. * (Eg. Start at high quality with reflection and fog, if fps is low, remove reflection, if still low remove fog)
  5. */
  6. export class EffectFallbacks {
  7. private _defines: { [key: string]: Array<String> } = {};
  8. private _currentRank = 32;
  9. private _maxRank = -1;
  10. private _mesh: Nullable<AbstractMesh>;
  11. /**
  12. * Removes the fallback from the bound mesh.
  13. */
  14. public unBindMesh() {
  15. this._mesh = null;
  16. }
  17. /**
  18. * Adds a fallback on the specified property.
  19. * @param rank The rank of the fallback (Lower ranks will be fallbacked to first)
  20. * @param define The name of the define in the shader
  21. */
  22. public addFallback(rank: number, define: string): void {
  23. if (!this._defines[rank]) {
  24. if (rank < this._currentRank) {
  25. this._currentRank = rank;
  26. }
  27. if (rank > this._maxRank) {
  28. this._maxRank = rank;
  29. }
  30. this._defines[rank] = new Array<String>();
  31. }
  32. this._defines[rank].push(define);
  33. }
  34. /**
  35. * Sets the mesh to use CPU skinning when needing to fallback.
  36. * @param rank The rank of the fallback (Lower ranks will be fallbacked to first)
  37. * @param mesh The mesh to use the fallbacks.
  38. */
  39. public addCPUSkinningFallback(rank: number, mesh: AbstractMesh) {
  40. this._mesh = mesh;
  41. if (rank < this._currentRank) {
  42. this._currentRank = rank;
  43. }
  44. if (rank > this._maxRank) {
  45. this._maxRank = rank;
  46. }
  47. }
  48. /**
  49. * Checks to see if more fallbacks are still availible.
  50. */
  51. public get isMoreFallbacks(): boolean {
  52. return this._currentRank <= this._maxRank;
  53. }
  54. /**
  55. * Removes the defines that shoould be removed when falling back.
  56. * @param currentDefines defines the current define statements for the shader.
  57. * @param effect defines the current effect we try to compile
  58. * @returns The resulting defines with defines of the current rank removed.
  59. */
  60. public reduce(currentDefines: string, effect: Effect): string {
  61. // First we try to switch to CPU skinning
  62. if (this._mesh && this._mesh.computeBonesUsingShaders && this._mesh.numBoneInfluencers > 0 && this._mesh.material) {
  63. this._mesh.computeBonesUsingShaders = false;
  64. currentDefines = currentDefines.replace("#define NUM_BONE_INFLUENCERS " + this._mesh.numBoneInfluencers, "#define NUM_BONE_INFLUENCERS 0");
  65. effect._bonesComputationForcedToCPU = true;
  66. var scene = this._mesh.getScene();
  67. for (var index = 0; index < scene.meshes.length; index++) {
  68. var otherMesh = scene.meshes[index];
  69. if (!otherMesh.material) {
  70. continue;
  71. }
  72. if (!otherMesh.computeBonesUsingShaders || otherMesh.numBoneInfluencers === 0) {
  73. continue;
  74. }
  75. if (otherMesh.material.getEffect() === effect) {
  76. otherMesh.computeBonesUsingShaders = false;
  77. } else if (otherMesh.subMeshes) {
  78. for (var subMesh of otherMesh.subMeshes) {
  79. let subMeshEffect = subMesh.effect;
  80. if (subMeshEffect === effect) {
  81. otherMesh.computeBonesUsingShaders = false;
  82. break;
  83. }
  84. }
  85. }
  86. }
  87. }
  88. else {
  89. var currentFallbacks = this._defines[this._currentRank];
  90. if (currentFallbacks) {
  91. for (var index = 0; index < currentFallbacks.length; index++) {
  92. currentDefines = currentDefines.replace("#define " + currentFallbacks[index], "");
  93. }
  94. }
  95. this._currentRank++;
  96. }
  97. return currentDefines;
  98. }
  99. }
  100. /**
  101. * Options to be used when creating an effect.
  102. */
  103. export class EffectCreationOptions {
  104. /**
  105. * Atrributes that will be used in the shader.
  106. */
  107. public attributes: string[];
  108. /**
  109. * Uniform varible names that will be set in the shader.
  110. */
  111. public uniformsNames: string[];
  112. /**
  113. * Uniform buffer varible names that will be set in the shader.
  114. */
  115. public uniformBuffersNames: string[];
  116. /**
  117. * Sampler texture variable names that will be set in the shader.
  118. */
  119. public samplers: string[];
  120. /**
  121. * Define statements that will be set in the shader.
  122. */
  123. public defines: any;
  124. /**
  125. * Possible fallbacks for this effect to improve performance when needed.
  126. */
  127. public fallbacks: Nullable<EffectFallbacks>;
  128. /**
  129. * Callback that will be called when the shader is compiled.
  130. */
  131. public onCompiled: Nullable<(effect: Effect) => void>;
  132. /**
  133. * Callback that will be called if an error occurs during shader compilation.
  134. */
  135. public onError: Nullable<(effect: Effect, errors: string) => void>;
  136. /**
  137. * Parameters to be used with Babylons include syntax to iterate over an array (eg. {lights: 10})
  138. */
  139. public indexParameters: any;
  140. /**
  141. * Max number of lights that can be used in the shader.
  142. */
  143. public maxSimultaneousLights: number;
  144. /**
  145. * See https://developer.mozilla.org/en-US/docs/Web/API/WebGL2RenderingContext/transformFeedbackVaryings
  146. */
  147. public transformFeedbackVaryings: Nullable<string[]>;
  148. }
  149. /**
  150. * Effect containing vertex and fragment shader that can be executed on an object.
  151. */
  152. export class Effect {
  153. /**
  154. * Name of the effect.
  155. */
  156. public name: any;
  157. /**
  158. * String container all the define statements that should be set on the shader.
  159. */
  160. public defines: string;
  161. /**
  162. * Callback that will be called when the shader is compiled.
  163. */
  164. public onCompiled: Nullable<(effect: Effect) => void>;
  165. /**
  166. * Callback that will be called if an error occurs during shader compilation.
  167. */
  168. public onError: Nullable<(effect: Effect, errors: string) => void>;
  169. /**
  170. * Callback that will be called when effect is bound.
  171. */
  172. public onBind: Nullable<(effect: Effect) => void>;
  173. /**
  174. * Unique ID of the effect.
  175. */
  176. public uniqueId = 0;
  177. /**
  178. * Observable that will be called when the shader is compiled.
  179. * It is recommended to use executeWhenCompile() or to make sure that scene.isReady() is called to get this observable raised.
  180. */
  181. public onCompileObservable = new Observable<Effect>();
  182. /**
  183. * Observable that will be called if an error occurs during shader compilation.
  184. */
  185. public onErrorObservable = new Observable<Effect>();
  186. /** @hidden */
  187. public _onBindObservable: Nullable<Observable<Effect>>;
  188. /**
  189. * Observable that will be called when effect is bound.
  190. */
  191. public get onBindObservable(): Observable<Effect> {
  192. if (!this._onBindObservable) {
  193. this._onBindObservable = new Observable<Effect>();
  194. }
  195. return this._onBindObservable;
  196. }
  197. /** @hidden */
  198. public _bonesComputationForcedToCPU = false;
  199. private static _uniqueIdSeed = 0;
  200. private _engine: Engine;
  201. private _uniformBuffersNames: { [key: string]: number } = {};
  202. private _uniformsNames: string[];
  203. private _samplers: string[];
  204. private _isReady = false;
  205. private _compilationError = "";
  206. private _attributesNames: string[];
  207. private _attributes: number[];
  208. private _uniforms: Nullable<WebGLUniformLocation>[];
  209. /**
  210. * Key for the effect.
  211. * @hidden
  212. */
  213. public _key: string;
  214. private _indexParameters: any;
  215. private _fallbacks: Nullable<EffectFallbacks>;
  216. private _vertexSourceCode: string;
  217. private _fragmentSourceCode: string;
  218. private _vertexSourceCodeOverride: string;
  219. private _fragmentSourceCodeOverride: string;
  220. private _transformFeedbackVaryings: Nullable<string[]>;
  221. /**
  222. * Compiled shader to webGL program.
  223. * @hidden
  224. */
  225. public _program: WebGLProgram;
  226. private _valueCache: { [key: string]: any };
  227. private static _baseCache: { [key: number]: WebGLBuffer } = {};
  228. /**
  229. * Instantiates an effect.
  230. * An effect can be used to create/manage/execute vertex and fragment shaders.
  231. * @param baseName Name of the effect.
  232. * @param attributesNamesOrOptions List of attribute names that will be passed to the shader or set of all options to create the effect.
  233. * @param uniformsNamesOrEngine List of uniform variable names that will be passed to the shader or the engine that will be used to render effect.
  234. * @param samplers List of sampler variables that will be passed to the shader.
  235. * @param engine Engine to be used to render the effect
  236. * @param defines Define statements to be added to the shader.
  237. * @param fallbacks Possible fallbacks for this effect to improve performance when needed.
  238. * @param onCompiled Callback that will be called when the shader is compiled.
  239. * @param onError Callback that will be called if an error occurs during shader compilation.
  240. * @param indexParameters Parameters to be used with Babylons include syntax to iterate over an array (eg. {lights: 10})
  241. */
  242. constructor(baseName: any, attributesNamesOrOptions: string[] | EffectCreationOptions, uniformsNamesOrEngine: string[] | Engine, samplers: Nullable<string[]> = null, engine?: Engine, defines: Nullable<string> = null,
  243. fallbacks: Nullable<EffectFallbacks> = null, onCompiled: Nullable<(effect: Effect) => void> = null, onError: Nullable<(effect: Effect, errors: string) => void> = null, indexParameters?: any) {
  244. this.name = baseName;
  245. if ((<EffectCreationOptions>attributesNamesOrOptions).attributes) {
  246. var options = <EffectCreationOptions>attributesNamesOrOptions;
  247. this._engine = <Engine>uniformsNamesOrEngine;
  248. this._attributesNames = options.attributes;
  249. this._uniformsNames = options.uniformsNames.concat(options.samplers);
  250. this._samplers = options.samplers.slice();
  251. this.defines = options.defines;
  252. this.onError = options.onError;
  253. this.onCompiled = options.onCompiled;
  254. this._fallbacks = options.fallbacks;
  255. this._indexParameters = options.indexParameters;
  256. this._transformFeedbackVaryings = options.transformFeedbackVaryings;
  257. if (options.uniformBuffersNames) {
  258. for (var i = 0; i < options.uniformBuffersNames.length; i++) {
  259. this._uniformBuffersNames[options.uniformBuffersNames[i]] = i;
  260. }
  261. }
  262. } else {
  263. this._engine = <Engine>engine;
  264. this.defines = <string>defines;
  265. this._uniformsNames = (<string[]>uniformsNamesOrEngine).concat(<string[]>samplers);
  266. this._samplers = samplers ? <string[]>samplers.slice() : [];
  267. this._attributesNames = (<string[]>attributesNamesOrOptions);
  268. this.onError = onError;
  269. this.onCompiled = onCompiled;
  270. this._indexParameters = indexParameters;
  271. this._fallbacks = fallbacks;
  272. }
  273. this.uniqueId = Effect._uniqueIdSeed++;
  274. var vertexSource: any;
  275. var fragmentSource: any;
  276. if (baseName.vertexElement) {
  277. vertexSource = document.getElementById(baseName.vertexElement);
  278. if (!vertexSource) {
  279. vertexSource = baseName.vertexElement;
  280. }
  281. } else {
  282. vertexSource = baseName.vertex || baseName;
  283. }
  284. if (baseName.fragmentElement) {
  285. fragmentSource = document.getElementById(baseName.fragmentElement);
  286. if (!fragmentSource) {
  287. fragmentSource = baseName.fragmentElement;
  288. }
  289. } else {
  290. fragmentSource = baseName.fragment || baseName;
  291. }
  292. this._loadVertexShader(vertexSource, (vertexCode) => {
  293. this._processIncludes(vertexCode, (vertexCodeWithIncludes) => {
  294. this._processShaderConversion(vertexCodeWithIncludes, false, (migratedVertexCode) => {
  295. this._loadFragmentShader(fragmentSource, (fragmentCode) => {
  296. this._processIncludes(fragmentCode, (fragmentCodeWithIncludes) => {
  297. this._processShaderConversion(fragmentCodeWithIncludes, true, (migratedFragmentCode) => {
  298. if (baseName) {
  299. var vertex = baseName.vertexElement || baseName.vertex || baseName;
  300. var fragment = baseName.fragmentElement || baseName.fragment || baseName;
  301. this._vertexSourceCode = "#define SHADER_NAME vertex:" + vertex + "\n" + migratedVertexCode;
  302. this._fragmentSourceCode = "#define SHADER_NAME fragment:" + fragment + "\n" + migratedFragmentCode;
  303. } else {
  304. this._vertexSourceCode = migratedVertexCode;
  305. this._fragmentSourceCode = migratedFragmentCode;
  306. }
  307. this._prepareEffect();
  308. });
  309. });
  310. });
  311. });
  312. });
  313. });
  314. }
  315. /**
  316. * Unique key for this effect
  317. */
  318. public get key(): string {
  319. return this._key;
  320. }
  321. /**
  322. * If the effect has been compiled and prepared.
  323. * @returns if the effect is compiled and prepared.
  324. */
  325. public isReady(): boolean {
  326. if (!this._isReady && this._program && this._program.isParallelCompiled) {
  327. return this._engine._isProgramCompiled(this._program);
  328. }
  329. return this._isReady;
  330. }
  331. /**
  332. * The engine the effect was initialized with.
  333. * @returns the engine.
  334. */
  335. public getEngine(): Engine {
  336. return this._engine;
  337. }
  338. /**
  339. * The compiled webGL program for the effect
  340. * @returns the webGL program.
  341. */
  342. public getProgram(): WebGLProgram {
  343. return this._program;
  344. }
  345. /**
  346. * The set of names of attribute variables for the shader.
  347. * @returns An array of attribute names.
  348. */
  349. public getAttributesNames(): string[] {
  350. return this._attributesNames;
  351. }
  352. /**
  353. * Returns the attribute at the given index.
  354. * @param index The index of the attribute.
  355. * @returns The location of the attribute.
  356. */
  357. public getAttributeLocation(index: number): number {
  358. return this._attributes[index];
  359. }
  360. /**
  361. * Returns the attribute based on the name of the variable.
  362. * @param name of the attribute to look up.
  363. * @returns the attribute location.
  364. */
  365. public getAttributeLocationByName(name: string): number {
  366. var index = this._attributesNames.indexOf(name);
  367. return this._attributes[index];
  368. }
  369. /**
  370. * The number of attributes.
  371. * @returns the numnber of attributes.
  372. */
  373. public getAttributesCount(): number {
  374. return this._attributes.length;
  375. }
  376. /**
  377. * Gets the index of a uniform variable.
  378. * @param uniformName of the uniform to look up.
  379. * @returns the index.
  380. */
  381. public getUniformIndex(uniformName: string): number {
  382. return this._uniformsNames.indexOf(uniformName);
  383. }
  384. /**
  385. * Returns the attribute based on the name of the variable.
  386. * @param uniformName of the uniform to look up.
  387. * @returns the location of the uniform.
  388. */
  389. public getUniform(uniformName: string): Nullable<WebGLUniformLocation> {
  390. return this._uniforms[this._uniformsNames.indexOf(uniformName)];
  391. }
  392. /**
  393. * Returns an array of sampler variable names
  394. * @returns The array of sampler variable neames.
  395. */
  396. public getSamplers(): string[] {
  397. return this._samplers;
  398. }
  399. /**
  400. * The error from the last compilation.
  401. * @returns the error string.
  402. */
  403. public getCompilationError(): string {
  404. return this._compilationError;
  405. }
  406. /**
  407. * Adds a callback to the onCompiled observable and call the callback imediatly if already ready.
  408. * @param func The callback to be used.
  409. */
  410. public executeWhenCompiled(func: (effect: Effect) => void): void {
  411. if (this.isReady()) {
  412. func(this);
  413. return;
  414. }
  415. this.onCompileObservable.add((effect) => {
  416. func(effect);
  417. });
  418. if (!this._program || this._program.isParallelCompiled) {
  419. setTimeout(() => {
  420. this._checkIsReady();
  421. }, 16);
  422. }
  423. }
  424. private _checkIsReady() {
  425. if (this.isReady()) {
  426. return;
  427. }
  428. setTimeout(() => {
  429. this._checkIsReady();
  430. }, 16);
  431. }
  432. /** @hidden */
  433. public _loadVertexShader(vertex: any, callback: (data: any) => void): void {
  434. if (Tools.IsWindowObjectExist()) {
  435. // DOM element ?
  436. if (vertex instanceof HTMLElement) {
  437. var vertexCode = Tools.GetDOMTextContent(vertex);
  438. callback(vertexCode);
  439. return;
  440. }
  441. }
  442. // Base64 encoded ?
  443. if (vertex.substr(0, 7) === "base64:") {
  444. var vertexBinary = window.atob(vertex.substr(7));
  445. callback(vertexBinary);
  446. return;
  447. }
  448. // Is in local store ?
  449. if (Effect.ShadersStore[vertex + "VertexShader"]) {
  450. callback(Effect.ShadersStore[vertex + "VertexShader"]);
  451. return;
  452. }
  453. var vertexShaderUrl;
  454. if (vertex[0] === "." || vertex[0] === "/" || vertex.indexOf("http") > -1) {
  455. vertexShaderUrl = vertex;
  456. } else {
  457. vertexShaderUrl = Engine.ShadersRepository + vertex;
  458. }
  459. // Vertex shader
  460. this._engine._loadFile(vertexShaderUrl + ".vertex.fx", callback);
  461. }
  462. /** @hidden */
  463. public _loadFragmentShader(fragment: any, callback: (data: any) => void): void {
  464. if (Tools.IsWindowObjectExist()) {
  465. // DOM element ?
  466. if (fragment instanceof HTMLElement) {
  467. var fragmentCode = Tools.GetDOMTextContent(fragment);
  468. callback(fragmentCode);
  469. return;
  470. }
  471. }
  472. // Base64 encoded ?
  473. if (fragment.substr(0, 7) === "base64:") {
  474. var fragmentBinary = window.atob(fragment.substr(7));
  475. callback(fragmentBinary);
  476. return;
  477. }
  478. // Is in local store ?
  479. if (Effect.ShadersStore[fragment + "PixelShader"]) {
  480. callback(Effect.ShadersStore[fragment + "PixelShader"]);
  481. return;
  482. }
  483. if (Effect.ShadersStore[fragment + "FragmentShader"]) {
  484. callback(Effect.ShadersStore[fragment + "FragmentShader"]);
  485. return;
  486. }
  487. var fragmentShaderUrl;
  488. if (fragment[0] === "." || fragment[0] === "/" || fragment.indexOf("http") > -1) {
  489. fragmentShaderUrl = fragment;
  490. } else {
  491. fragmentShaderUrl = Engine.ShadersRepository + fragment;
  492. }
  493. // Fragment shader
  494. this._engine._loadFile(fragmentShaderUrl + ".fragment.fx", callback);
  495. }
  496. /** @hidden */
  497. public _dumpShadersSource(vertexCode: string, fragmentCode: string, defines: string): void {
  498. // Rebuild shaders source code
  499. var shaderVersion = (this._engine.webGLVersion > 1) ? "#version 300 es\n#define WEBGL2 \n" : "";
  500. var prefix = shaderVersion + (defines ? defines + "\n" : "");
  501. vertexCode = prefix + vertexCode;
  502. fragmentCode = prefix + fragmentCode;
  503. // Number lines of shaders source code
  504. var i = 2;
  505. var regex = /\n/gm;
  506. var formattedVertexCode = "\n1\t" + vertexCode.replace(regex, function() { return "\n" + (i++) + "\t"; });
  507. i = 2;
  508. var formattedFragmentCode = "\n1\t" + fragmentCode.replace(regex, function() { return "\n" + (i++) + "\t"; });
  509. // Dump shaders name and formatted source code
  510. if (this.name.vertexElement) {
  511. Tools.Error("Vertex shader: " + this.name.vertexElement + formattedVertexCode);
  512. Tools.Error("Fragment shader: " + this.name.fragmentElement + formattedFragmentCode);
  513. }
  514. else if (this.name.vertex) {
  515. Tools.Error("Vertex shader: " + this.name.vertex + formattedVertexCode);
  516. Tools.Error("Fragment shader: " + this.name.fragment + formattedFragmentCode);
  517. }
  518. else {
  519. Tools.Error("Vertex shader: " + this.name + formattedVertexCode);
  520. Tools.Error("Fragment shader: " + this.name + formattedFragmentCode);
  521. }
  522. }
  523. private _processShaderConversion(sourceCode: string, isFragment: boolean, callback: (data: any) => void): void {
  524. var preparedSourceCode = this._processPrecision(sourceCode);
  525. if (this._engine.webGLVersion == 1) {
  526. callback(preparedSourceCode);
  527. return;
  528. }
  529. // Already converted
  530. if (preparedSourceCode.indexOf("#version 3") !== -1) {
  531. callback(preparedSourceCode.replace("#version 300 es", ""));
  532. return;
  533. }
  534. var hasDrawBuffersExtension = preparedSourceCode.search(/#extension.+GL_EXT_draw_buffers.+require/) !== -1;
  535. // Remove extensions
  536. // #extension GL_OES_standard_derivatives : enable
  537. // #extension GL_EXT_shader_texture_lod : enable
  538. // #extension GL_EXT_frag_depth : enable
  539. // #extension GL_EXT_draw_buffers : require
  540. var regex = /#extension.+(GL_OES_standard_derivatives|GL_EXT_shader_texture_lod|GL_EXT_frag_depth|GL_EXT_draw_buffers).+(enable|require)/g;
  541. var result = preparedSourceCode.replace(regex, "");
  542. // Migrate to GLSL v300
  543. result = result.replace(/varying(?![\n\r])\s/g, isFragment ? "in " : "out ");
  544. result = result.replace(/attribute[ \t]/g, "in ");
  545. result = result.replace(/[ \t]attribute/g, " in");
  546. result = result.replace(/texture2D\s*\(/g, "texture(");
  547. if (isFragment) {
  548. result = result.replace(/texture2DLodEXT\s*\(/g, "textureLod(");
  549. result = result.replace(/textureCubeLodEXT\s*\(/g, "textureLod(");
  550. result = result.replace(/textureCube\s*\(/g, "texture(");
  551. result = result.replace(/gl_FragDepthEXT/g, "gl_FragDepth");
  552. result = result.replace(/gl_FragColor/g, "glFragColor");
  553. result = result.replace(/gl_FragData/g, "glFragData");
  554. result = result.replace(/void\s+?main\s*\(/g, (hasDrawBuffersExtension ? "" : "out vec4 glFragColor;\n") + "void main(");
  555. }
  556. callback(result);
  557. }
  558. private _processIncludes(sourceCode: string, callback: (data: any) => void): void {
  559. var regex = /#include<(.+)>(\((.*)\))*(\[(.*)\])*/g;
  560. var match = regex.exec(sourceCode);
  561. var returnValue = new String(sourceCode);
  562. while (match != null) {
  563. var includeFile = match[1];
  564. // Uniform declaration
  565. if (includeFile.indexOf("__decl__") !== -1) {
  566. includeFile = includeFile.replace(/__decl__/, "");
  567. if (this._engine.supportsUniformBuffers) {
  568. includeFile = includeFile.replace(/Vertex/, "Ubo");
  569. includeFile = includeFile.replace(/Fragment/, "Ubo");
  570. }
  571. includeFile = includeFile + "Declaration";
  572. }
  573. if (Effect.IncludesShadersStore[includeFile]) {
  574. // Substitution
  575. var includeContent = Effect.IncludesShadersStore[includeFile];
  576. if (match[2]) {
  577. var splits = match[3].split(",");
  578. for (var index = 0; index < splits.length; index += 2) {
  579. var source = new RegExp(splits[index], "g");
  580. var dest = splits[index + 1];
  581. includeContent = includeContent.replace(source, dest);
  582. }
  583. }
  584. if (match[4]) {
  585. var indexString = match[5];
  586. if (indexString.indexOf("..") !== -1) {
  587. var indexSplits = indexString.split("..");
  588. var minIndex = parseInt(indexSplits[0]);
  589. var maxIndex = parseInt(indexSplits[1]);
  590. var sourceIncludeContent = includeContent.slice(0);
  591. includeContent = "";
  592. if (isNaN(maxIndex)) {
  593. maxIndex = this._indexParameters[indexSplits[1]];
  594. }
  595. for (var i = minIndex; i < maxIndex; i++) {
  596. if (!this._engine.supportsUniformBuffers) {
  597. // Ubo replacement
  598. sourceIncludeContent = sourceIncludeContent.replace(/light\{X\}.(\w*)/g, (str: string, p1: string) => {
  599. return p1 + "{X}";
  600. });
  601. }
  602. includeContent += sourceIncludeContent.replace(/\{X\}/g, i.toString()) + "\n";
  603. }
  604. } else {
  605. if (!this._engine.supportsUniformBuffers) {
  606. // Ubo replacement
  607. includeContent = includeContent.replace(/light\{X\}.(\w*)/g, (str: string, p1: string) => {
  608. return p1 + "{X}";
  609. });
  610. }
  611. includeContent = includeContent.replace(/\{X\}/g, indexString);
  612. }
  613. }
  614. // Replace
  615. returnValue = returnValue.replace(match[0], includeContent);
  616. } else {
  617. var includeShaderUrl = Engine.ShadersRepository + "ShadersInclude/" + includeFile + ".fx";
  618. this._engine._loadFile(includeShaderUrl, (fileContent) => {
  619. Effect.IncludesShadersStore[includeFile] = fileContent as string;
  620. this._processIncludes(<string>returnValue, callback);
  621. });
  622. return;
  623. }
  624. match = regex.exec(sourceCode);
  625. }
  626. callback(returnValue);
  627. }
  628. private _processPrecision(source: string): string {
  629. if (source.indexOf("precision highp float") === -1) {
  630. if (!this._engine.getCaps().highPrecisionShaderSupported) {
  631. source = "precision mediump float;\n" + source;
  632. } else {
  633. source = "precision highp float;\n" + source;
  634. }
  635. } else {
  636. if (!this._engine.getCaps().highPrecisionShaderSupported) { // Moving highp to mediump
  637. source = source.replace("precision highp float", "precision mediump float");
  638. }
  639. }
  640. return source;
  641. }
  642. /**
  643. * Recompiles the webGL program
  644. * @param vertexSourceCode The source code for the vertex shader.
  645. * @param fragmentSourceCode The source code for the fragment shader.
  646. * @param onCompiled Callback called when completed.
  647. * @param onError Callback called on error.
  648. * @hidden
  649. */
  650. public _rebuildProgram(vertexSourceCode: string, fragmentSourceCode: string, onCompiled: (program: WebGLProgram) => void, onError: (message: string) => void) {
  651. this._isReady = false;
  652. this._vertexSourceCodeOverride = vertexSourceCode;
  653. this._fragmentSourceCodeOverride = fragmentSourceCode;
  654. this.onError = (effect, error) => {
  655. if (onError) {
  656. onError(error);
  657. }
  658. };
  659. this.onCompiled = () => {
  660. var scenes = this.getEngine().scenes;
  661. for (var i = 0; i < scenes.length; i++) {
  662. scenes[i].markAllMaterialsAsDirty(Material.TextureDirtyFlag);
  663. }
  664. if (onCompiled) {
  665. onCompiled(this._program);
  666. }
  667. };
  668. this._fallbacks = null;
  669. this._prepareEffect();
  670. }
  671. /**
  672. * Gets the uniform locations of the the specified variable names
  673. * @param names THe names of the variables to lookup.
  674. * @returns Array of locations in the same order as variable names.
  675. */
  676. public getSpecificUniformLocations(names: string[]): Nullable<WebGLUniformLocation>[] {
  677. let engine = this._engine;
  678. return engine.getUniforms(this._program, names);
  679. }
  680. /**
  681. * Prepares the effect
  682. * @hidden
  683. */
  684. public _prepareEffect() {
  685. let attributesNames = this._attributesNames;
  686. let defines = this.defines;
  687. let fallbacks = this._fallbacks;
  688. this._valueCache = {};
  689. var previousProgram = this._program;
  690. try {
  691. let engine = this._engine;
  692. if (this._vertexSourceCodeOverride && this._fragmentSourceCodeOverride) {
  693. this._program = engine.createRawShaderProgram(this._vertexSourceCodeOverride, this._fragmentSourceCodeOverride, undefined, this._transformFeedbackVaryings);
  694. }
  695. else {
  696. this._program = engine.createShaderProgram(this._vertexSourceCode, this._fragmentSourceCode, defines, undefined, this._transformFeedbackVaryings);
  697. }
  698. this._program.__SPECTOR_rebuildProgram = this._rebuildProgram.bind(this);
  699. engine._executeWhenProgramIsCompiled(this._program, () => {
  700. if (engine.supportsUniformBuffers) {
  701. for (var name in this._uniformBuffersNames) {
  702. this.bindUniformBlock(name, this._uniformBuffersNames[name]);
  703. }
  704. }
  705. this._uniforms = engine.getUniforms(this._program, this._uniformsNames);
  706. this._attributes = engine.getAttributes(this._program, attributesNames);
  707. var index: number;
  708. for (index = 0; index < this._samplers.length; index++) {
  709. var sampler = this.getUniform(this._samplers[index]);
  710. if (sampler == null) {
  711. this._samplers.splice(index, 1);
  712. index--;
  713. }
  714. }
  715. engine.bindSamplers(this);
  716. this._compilationError = "";
  717. this._isReady = true;
  718. if (this.onCompiled) {
  719. this.onCompiled(this);
  720. }
  721. this.onCompileObservable.notifyObservers(this);
  722. this.onCompileObservable.clear();
  723. // Unbind mesh reference in fallbacks
  724. if (this._fallbacks) {
  725. this._fallbacks.unBindMesh();
  726. }
  727. if (previousProgram) {
  728. this.getEngine()._deleteProgram(previousProgram);
  729. }
  730. });
  731. if (this._program.isParallelCompiled) {
  732. this._checkIsReady();
  733. }
  734. } catch (e) {
  735. this._compilationError = e.message;
  736. // Let's go through fallbacks then
  737. Tools.Error("Unable to compile effect:");
  738. Tools.Error("Uniforms: " + this._uniformsNames.map(function(uniform) {
  739. return " " + uniform;
  740. }));
  741. Tools.Error("Attributes: " + attributesNames.map(function(attribute) {
  742. return " " + attribute;
  743. }));
  744. Tools.Error("Error: " + this._compilationError);
  745. if (previousProgram) {
  746. this._program = previousProgram;
  747. this._isReady = true;
  748. if (this.onError) {
  749. this.onError(this, this._compilationError);
  750. }
  751. this.onErrorObservable.notifyObservers(this);
  752. }
  753. if (fallbacks && fallbacks.isMoreFallbacks) {
  754. Tools.Error("Trying next fallback.");
  755. this.defines = fallbacks.reduce(this.defines, this);
  756. this._prepareEffect();
  757. } else { // Sorry we did everything we can
  758. if (this.onError) {
  759. this.onError(this, this._compilationError);
  760. }
  761. this.onErrorObservable.notifyObservers(this);
  762. this.onErrorObservable.clear();
  763. // Unbind mesh reference in fallbacks
  764. if (this._fallbacks) {
  765. this._fallbacks.unBindMesh();
  766. }
  767. }
  768. }
  769. }
  770. /**
  771. * Checks if the effect is supported. (Must be called after compilation)
  772. */
  773. public get isSupported(): boolean {
  774. return this._compilationError === "";
  775. }
  776. /**
  777. * Binds a texture to the engine to be used as output of the shader.
  778. * @param channel Name of the output variable.
  779. * @param texture Texture to bind.
  780. * @hidden
  781. */
  782. public _bindTexture(channel: string, texture: InternalTexture): void {
  783. this._engine._bindTexture(this._samplers.indexOf(channel), texture);
  784. }
  785. /**
  786. * Sets a texture on the engine to be used in the shader.
  787. * @param channel Name of the sampler variable.
  788. * @param texture Texture to set.
  789. */
  790. public setTexture(channel: string, texture: Nullable<BaseTexture>): void {
  791. this._engine.setTexture(this._samplers.indexOf(channel), this.getUniform(channel), texture);
  792. }
  793. /**
  794. * Sets a depth stencil texture from a render target on the engine to be used in the shader.
  795. * @param channel Name of the sampler variable.
  796. * @param texture Texture to set.
  797. */
  798. public setDepthStencilTexture(channel: string, texture: Nullable<RenderTargetTexture>): void {
  799. this._engine.setDepthStencilTexture(this._samplers.indexOf(channel), this.getUniform(channel), texture);
  800. }
  801. /**
  802. * Sets an array of textures on the engine to be used in the shader.
  803. * @param channel Name of the variable.
  804. * @param textures Textures to set.
  805. */
  806. public setTextureArray(channel: string, textures: BaseTexture[]): void {
  807. if (this._samplers.indexOf(channel + "Ex") === -1) {
  808. var initialPos = this._samplers.indexOf(channel);
  809. for (var index = 1; index < textures.length; index++) {
  810. this._samplers.splice(initialPos + index, 0, channel + "Ex");
  811. }
  812. }
  813. this._engine.setTextureArray(this._samplers.indexOf(channel), this.getUniform(channel), textures);
  814. }
  815. /**
  816. * Sets a texture to be the input of the specified post process. (To use the output, pass in the next post process in the pipeline)
  817. * @param channel Name of the sampler variable.
  818. * @param postProcess Post process to get the input texture from.
  819. */
  820. public setTextureFromPostProcess(channel: string, postProcess: Nullable<PostProcess>): void {
  821. this._engine.setTextureFromPostProcess(this._samplers.indexOf(channel), postProcess);
  822. }
  823. /**
  824. * (Warning! setTextureFromPostProcessOutput may be desired instead)
  825. * Sets the input texture of the passed in post process to be input of this effect. (To use the output of the passed in post process use setTextureFromPostProcessOutput)
  826. * @param channel Name of the sampler variable.
  827. * @param postProcess Post process to get the output texture from.
  828. */
  829. public setTextureFromPostProcessOutput(channel: string, postProcess: Nullable<PostProcess>): void {
  830. this._engine.setTextureFromPostProcessOutput(this._samplers.indexOf(channel), postProcess);
  831. }
  832. /** @hidden */
  833. public _cacheMatrix(uniformName: string, matrix: Matrix): boolean {
  834. var cache = this._valueCache[uniformName];
  835. var flag = matrix.updateFlag;
  836. if (cache !== undefined && cache === flag) {
  837. return false;
  838. }
  839. this._valueCache[uniformName] = flag;
  840. return true;
  841. }
  842. /** @hidden */
  843. public _cacheFloat2(uniformName: string, x: number, y: number): boolean {
  844. var cache = this._valueCache[uniformName];
  845. if (!cache) {
  846. cache = [x, y];
  847. this._valueCache[uniformName] = cache;
  848. return true;
  849. }
  850. var changed = false;
  851. if (cache[0] !== x) {
  852. cache[0] = x;
  853. changed = true;
  854. }
  855. if (cache[1] !== y) {
  856. cache[1] = y;
  857. changed = true;
  858. }
  859. return changed;
  860. }
  861. /** @hidden */
  862. public _cacheFloat3(uniformName: string, x: number, y: number, z: number): boolean {
  863. var cache = this._valueCache[uniformName];
  864. if (!cache) {
  865. cache = [x, y, z];
  866. this._valueCache[uniformName] = cache;
  867. return true;
  868. }
  869. var changed = false;
  870. if (cache[0] !== x) {
  871. cache[0] = x;
  872. changed = true;
  873. }
  874. if (cache[1] !== y) {
  875. cache[1] = y;
  876. changed = true;
  877. }
  878. if (cache[2] !== z) {
  879. cache[2] = z;
  880. changed = true;
  881. }
  882. return changed;
  883. }
  884. /** @hidden */
  885. public _cacheFloat4(uniformName: string, x: number, y: number, z: number, w: number): boolean {
  886. var cache = this._valueCache[uniformName];
  887. if (!cache) {
  888. cache = [x, y, z, w];
  889. this._valueCache[uniformName] = cache;
  890. return true;
  891. }
  892. var changed = false;
  893. if (cache[0] !== x) {
  894. cache[0] = x;
  895. changed = true;
  896. }
  897. if (cache[1] !== y) {
  898. cache[1] = y;
  899. changed = true;
  900. }
  901. if (cache[2] !== z) {
  902. cache[2] = z;
  903. changed = true;
  904. }
  905. if (cache[3] !== w) {
  906. cache[3] = w;
  907. changed = true;
  908. }
  909. return changed;
  910. }
  911. /**
  912. * Binds a buffer to a uniform.
  913. * @param buffer Buffer to bind.
  914. * @param name Name of the uniform variable to bind to.
  915. */
  916. public bindUniformBuffer(buffer: WebGLBuffer, name: string): void {
  917. let bufferName = this._uniformBuffersNames[name];
  918. if (bufferName === undefined || Effect._baseCache[bufferName] === buffer) {
  919. return;
  920. }
  921. Effect._baseCache[bufferName] = buffer;
  922. this._engine.bindUniformBufferBase(buffer, bufferName);
  923. }
  924. /**
  925. * Binds block to a uniform.
  926. * @param blockName Name of the block to bind.
  927. * @param index Index to bind.
  928. */
  929. public bindUniformBlock(blockName: string, index: number): void {
  930. this._engine.bindUniformBlock(this._program, blockName, index);
  931. }
  932. /**
  933. * Sets an interger value on a uniform variable.
  934. * @param uniformName Name of the variable.
  935. * @param value Value to be set.
  936. * @returns this effect.
  937. */
  938. public setInt(uniformName: string, value: number): Effect {
  939. var cache = this._valueCache[uniformName];
  940. if (cache !== undefined && cache === value) {
  941. return this;
  942. }
  943. this._valueCache[uniformName] = value;
  944. this._engine.setInt(this.getUniform(uniformName), value);
  945. return this;
  946. }
  947. /**
  948. * Sets an int array on a uniform variable.
  949. * @param uniformName Name of the variable.
  950. * @param array array to be set.
  951. * @returns this effect.
  952. */
  953. public setIntArray(uniformName: string, array: Int32Array): Effect {
  954. this._valueCache[uniformName] = null;
  955. this._engine.setIntArray(this.getUniform(uniformName), array);
  956. return this;
  957. }
  958. /**
  959. * Sets an int array 2 on a uniform variable. (Array is specified as single array eg. [1,2,3,4] will result in [[1,2],[3,4]] in the shader)
  960. * @param uniformName Name of the variable.
  961. * @param array array to be set.
  962. * @returns this effect.
  963. */
  964. public setIntArray2(uniformName: string, array: Int32Array): Effect {
  965. this._valueCache[uniformName] = null;
  966. this._engine.setIntArray2(this.getUniform(uniformName), array);
  967. return this;
  968. }
  969. /**
  970. * Sets an int array 3 on a uniform variable. (Array is specified as single array eg. [1,2,3,4,5,6] will result in [[1,2,3],[4,5,6]] in the shader)
  971. * @param uniformName Name of the variable.
  972. * @param array array to be set.
  973. * @returns this effect.
  974. */
  975. public setIntArray3(uniformName: string, array: Int32Array): Effect {
  976. this._valueCache[uniformName] = null;
  977. this._engine.setIntArray3(this.getUniform(uniformName), array);
  978. return this;
  979. }
  980. /**
  981. * Sets an int array 4 on a uniform variable. (Array is specified as single array eg. [1,2,3,4,5,6,7,8] will result in [[1,2,3,4],[5,6,7,8]] in the shader)
  982. * @param uniformName Name of the variable.
  983. * @param array array to be set.
  984. * @returns this effect.
  985. */
  986. public setIntArray4(uniformName: string, array: Int32Array): Effect {
  987. this._valueCache[uniformName] = null;
  988. this._engine.setIntArray4(this.getUniform(uniformName), array);
  989. return this;
  990. }
  991. /**
  992. * Sets an float array on a uniform variable.
  993. * @param uniformName Name of the variable.
  994. * @param array array to be set.
  995. * @returns this effect.
  996. */
  997. public setFloatArray(uniformName: string, array: Float32Array): Effect {
  998. this._valueCache[uniformName] = null;
  999. this._engine.setFloatArray(this.getUniform(uniformName), array);
  1000. return this;
  1001. }
  1002. /**
  1003. * Sets an float array 2 on a uniform variable. (Array is specified as single array eg. [1,2,3,4] will result in [[1,2],[3,4]] in the shader)
  1004. * @param uniformName Name of the variable.
  1005. * @param array array to be set.
  1006. * @returns this effect.
  1007. */
  1008. public setFloatArray2(uniformName: string, array: Float32Array): Effect {
  1009. this._valueCache[uniformName] = null;
  1010. this._engine.setFloatArray2(this.getUniform(uniformName), array);
  1011. return this;
  1012. }
  1013. /**
  1014. * Sets an float array 3 on a uniform variable. (Array is specified as single array eg. [1,2,3,4,5,6] will result in [[1,2,3],[4,5,6]] in the shader)
  1015. * @param uniformName Name of the variable.
  1016. * @param array array to be set.
  1017. * @returns this effect.
  1018. */
  1019. public setFloatArray3(uniformName: string, array: Float32Array): Effect {
  1020. this._valueCache[uniformName] = null;
  1021. this._engine.setFloatArray3(this.getUniform(uniformName), array);
  1022. return this;
  1023. }
  1024. /**
  1025. * Sets an float array 4 on a uniform variable. (Array is specified as single array eg. [1,2,3,4,5,6,7,8] will result in [[1,2,3,4],[5,6,7,8]] in the shader)
  1026. * @param uniformName Name of the variable.
  1027. * @param array array to be set.
  1028. * @returns this effect.
  1029. */
  1030. public setFloatArray4(uniformName: string, array: Float32Array): Effect {
  1031. this._valueCache[uniformName] = null;
  1032. this._engine.setFloatArray4(this.getUniform(uniformName), array);
  1033. return this;
  1034. }
  1035. /**
  1036. * Sets an array on a uniform variable.
  1037. * @param uniformName Name of the variable.
  1038. * @param array array to be set.
  1039. * @returns this effect.
  1040. */
  1041. public setArray(uniformName: string, array: number[]): Effect {
  1042. this._valueCache[uniformName] = null;
  1043. this._engine.setArray(this.getUniform(uniformName), array);
  1044. return this;
  1045. }
  1046. /**
  1047. * Sets an array 2 on a uniform variable. (Array is specified as single array eg. [1,2,3,4] will result in [[1,2],[3,4]] in the shader)
  1048. * @param uniformName Name of the variable.
  1049. * @param array array to be set.
  1050. * @returns this effect.
  1051. */
  1052. public setArray2(uniformName: string, array: number[]): Effect {
  1053. this._valueCache[uniformName] = null;
  1054. this._engine.setArray2(this.getUniform(uniformName), array);
  1055. return this;
  1056. }
  1057. /**
  1058. * Sets an array 3 on a uniform variable. (Array is specified as single array eg. [1,2,3,4,5,6] will result in [[1,2,3],[4,5,6]] in the shader)
  1059. * @param uniformName Name of the variable.
  1060. * @param array array to be set.
  1061. * @returns this effect.
  1062. */
  1063. public setArray3(uniformName: string, array: number[]): Effect {
  1064. this._valueCache[uniformName] = null;
  1065. this._engine.setArray3(this.getUniform(uniformName), array);
  1066. return this;
  1067. }
  1068. /**
  1069. * Sets an array 4 on a uniform variable. (Array is specified as single array eg. [1,2,3,4,5,6,7,8] will result in [[1,2,3,4],[5,6,7,8]] in the shader)
  1070. * @param uniformName Name of the variable.
  1071. * @param array array to be set.
  1072. * @returns this effect.
  1073. */
  1074. public setArray4(uniformName: string, array: number[]): Effect {
  1075. this._valueCache[uniformName] = null;
  1076. this._engine.setArray4(this.getUniform(uniformName), array);
  1077. return this;
  1078. }
  1079. /**
  1080. * Sets matrices on a uniform variable.
  1081. * @param uniformName Name of the variable.
  1082. * @param matrices matrices to be set.
  1083. * @returns this effect.
  1084. */
  1085. public setMatrices(uniformName: string, matrices: Float32Array): Effect {
  1086. if (!matrices) {
  1087. return this;
  1088. }
  1089. this._valueCache[uniformName] = null;
  1090. this._engine.setMatrices(this.getUniform(uniformName), matrices);
  1091. return this;
  1092. }
  1093. /**
  1094. * Sets matrix on a uniform variable.
  1095. * @param uniformName Name of the variable.
  1096. * @param matrix matrix to be set.
  1097. * @returns this effect.
  1098. */
  1099. public setMatrix(uniformName: string, matrix: Matrix): Effect {
  1100. if (this._cacheMatrix(uniformName, matrix)) {
  1101. this._engine.setMatrix(this.getUniform(uniformName), matrix);
  1102. }
  1103. return this;
  1104. }
  1105. /**
  1106. * Sets a 3x3 matrix on a uniform variable. (Speicified as [1,2,3,4,5,6,7,8,9] will result in [1,2,3][4,5,6][7,8,9] matrix)
  1107. * @param uniformName Name of the variable.
  1108. * @param matrix matrix to be set.
  1109. * @returns this effect.
  1110. */
  1111. public setMatrix3x3(uniformName: string, matrix: Float32Array): Effect {
  1112. this._valueCache[uniformName] = null;
  1113. this._engine.setMatrix3x3(this.getUniform(uniformName), matrix);
  1114. return this;
  1115. }
  1116. /**
  1117. * Sets a 2x2 matrix on a uniform variable. (Speicified as [1,2,3,4] will result in [1,2][3,4] matrix)
  1118. * @param uniformName Name of the variable.
  1119. * @param matrix matrix to be set.
  1120. * @returns this effect.
  1121. */
  1122. public setMatrix2x2(uniformName: string, matrix: Float32Array): Effect {
  1123. this._valueCache[uniformName] = null;
  1124. this._engine.setMatrix2x2(this.getUniform(uniformName), matrix);
  1125. return this;
  1126. }
  1127. /**
  1128. * Sets a float on a uniform variable.
  1129. * @param uniformName Name of the variable.
  1130. * @param value value to be set.
  1131. * @returns this effect.
  1132. */
  1133. public setFloat(uniformName: string, value: number): Effect {
  1134. var cache = this._valueCache[uniformName];
  1135. if (cache !== undefined && cache === value) {
  1136. return this;
  1137. }
  1138. this._valueCache[uniformName] = value;
  1139. this._engine.setFloat(this.getUniform(uniformName), value);
  1140. return this;
  1141. }
  1142. /**
  1143. * Sets a boolean on a uniform variable.
  1144. * @param uniformName Name of the variable.
  1145. * @param bool value to be set.
  1146. * @returns this effect.
  1147. */
  1148. public setBool(uniformName: string, bool: boolean): Effect {
  1149. var cache = this._valueCache[uniformName];
  1150. if (cache !== undefined && cache === bool) {
  1151. return this;
  1152. }
  1153. this._valueCache[uniformName] = bool;
  1154. this._engine.setBool(this.getUniform(uniformName), bool ? 1 : 0);
  1155. return this;
  1156. }
  1157. /**
  1158. * Sets a Vector2 on a uniform variable.
  1159. * @param uniformName Name of the variable.
  1160. * @param vector2 vector2 to be set.
  1161. * @returns this effect.
  1162. */
  1163. public setVector2(uniformName: string, vector2: Vector2): Effect {
  1164. if (this._cacheFloat2(uniformName, vector2.x, vector2.y)) {
  1165. this._engine.setFloat2(this.getUniform(uniformName), vector2.x, vector2.y);
  1166. }
  1167. return this;
  1168. }
  1169. /**
  1170. * Sets a float2 on a uniform variable.
  1171. * @param uniformName Name of the variable.
  1172. * @param x First float in float2.
  1173. * @param y Second float in float2.
  1174. * @returns this effect.
  1175. */
  1176. public setFloat2(uniformName: string, x: number, y: number): Effect {
  1177. if (this._cacheFloat2(uniformName, x, y)) {
  1178. this._engine.setFloat2(this.getUniform(uniformName), x, y);
  1179. }
  1180. return this;
  1181. }
  1182. /**
  1183. * Sets a Vector3 on a uniform variable.
  1184. * @param uniformName Name of the variable.
  1185. * @param vector3 Value to be set.
  1186. * @returns this effect.
  1187. */
  1188. public setVector3(uniformName: string, vector3: Vector3): Effect {
  1189. if (this._cacheFloat3(uniformName, vector3.x, vector3.y, vector3.z)) {
  1190. this._engine.setFloat3(this.getUniform(uniformName), vector3.x, vector3.y, vector3.z);
  1191. }
  1192. return this;
  1193. }
  1194. /**
  1195. * Sets a float3 on a uniform variable.
  1196. * @param uniformName Name of the variable.
  1197. * @param x First float in float3.
  1198. * @param y Second float in float3.
  1199. * @param z Third float in float3.
  1200. * @returns this effect.
  1201. */
  1202. public setFloat3(uniformName: string, x: number, y: number, z: number): Effect {
  1203. if (this._cacheFloat3(uniformName, x, y, z)) {
  1204. this._engine.setFloat3(this.getUniform(uniformName), x, y, z);
  1205. }
  1206. return this;
  1207. }
  1208. /**
  1209. * Sets a Vector4 on a uniform variable.
  1210. * @param uniformName Name of the variable.
  1211. * @param vector4 Value to be set.
  1212. * @returns this effect.
  1213. */
  1214. public setVector4(uniformName: string, vector4: Vector4): Effect {
  1215. if (this._cacheFloat4(uniformName, vector4.x, vector4.y, vector4.z, vector4.w)) {
  1216. this._engine.setFloat4(this.getUniform(uniformName), vector4.x, vector4.y, vector4.z, vector4.w);
  1217. }
  1218. return this;
  1219. }
  1220. /**
  1221. * Sets a float4 on a uniform variable.
  1222. * @param uniformName Name of the variable.
  1223. * @param x First float in float4.
  1224. * @param y Second float in float4.
  1225. * @param z Third float in float4.
  1226. * @param w Fourth float in float4.
  1227. * @returns this effect.
  1228. */
  1229. public setFloat4(uniformName: string, x: number, y: number, z: number, w: number): Effect {
  1230. if (this._cacheFloat4(uniformName, x, y, z, w)) {
  1231. this._engine.setFloat4(this.getUniform(uniformName), x, y, z, w);
  1232. }
  1233. return this;
  1234. }
  1235. /**
  1236. * Sets a Color3 on a uniform variable.
  1237. * @param uniformName Name of the variable.
  1238. * @param color3 Value to be set.
  1239. * @returns this effect.
  1240. */
  1241. public setColor3(uniformName: string, color3: Color3): Effect {
  1242. if (this._cacheFloat3(uniformName, color3.r, color3.g, color3.b)) {
  1243. this._engine.setColor3(this.getUniform(uniformName), color3);
  1244. }
  1245. return this;
  1246. }
  1247. /**
  1248. * Sets a Color4 on a uniform variable.
  1249. * @param uniformName Name of the variable.
  1250. * @param color3 Value to be set.
  1251. * @param alpha Alpha value to be set.
  1252. * @returns this effect.
  1253. */
  1254. public setColor4(uniformName: string, color3: Color3, alpha: number): Effect {
  1255. if (this._cacheFloat4(uniformName, color3.r, color3.g, color3.b, alpha)) {
  1256. this._engine.setColor4(this.getUniform(uniformName), color3, alpha);
  1257. }
  1258. return this;
  1259. }
  1260. /**
  1261. * Sets a Color4 on a uniform variable
  1262. * @param uniformName defines the name of the variable
  1263. * @param color4 defines the value to be set
  1264. * @returns this effect.
  1265. */
  1266. public setDirectColor4(uniformName: string, color4: Color4): Effect {
  1267. if (this._cacheFloat4(uniformName, color4.r, color4.g, color4.b, color4.a)) {
  1268. this._engine.setDirectColor4(this.getUniform(uniformName), color4);
  1269. }
  1270. return this;
  1271. }
  1272. /**
  1273. * This function will add a new shader to the shader store
  1274. * @param name the name of the shader
  1275. * @param pixelShader optional pixel shader content
  1276. * @param vertexShader optional vertex shader content
  1277. */
  1278. public static RegisterShader(name: string, pixelShader?: string, vertexShader?: string) {
  1279. if (pixelShader) {
  1280. Effect.ShadersStore[`${name}PixelShader`] = pixelShader;
  1281. }
  1282. if (vertexShader) {
  1283. Effect.ShadersStore[`${name}VertexShader`] = vertexShader;
  1284. }
  1285. }
  1286. /**
  1287. * Store of each shader (The can be looked up using effect.key)
  1288. */
  1289. public static ShadersStore: { [key: string]: string } = {};
  1290. /**
  1291. * Store of each included file for a shader (The can be looked up using effect.key)
  1292. */
  1293. public static IncludesShadersStore: { [key: string]: string } = {};
  1294. /**
  1295. * Resets the cache of effects.
  1296. */
  1297. public static ResetCache() {
  1298. Effect._baseCache = {};
  1299. }
  1300. }
  1301. }