Home Reference Source

cables_dev/cables/src/libs/cgl/shadermodifier/cgl_shadermodifier.js

  1. class ShaderModifier
  2. {
  3. constructor(cgl, name, options)
  4. {
  5. this._cgl = cgl;
  6. this._name = name;
  7. this._origShaders = {};
  8. this._uniforms = [];
  9. this._structUniforms = [];
  10. this._definesToggled = {};
  11. this._defines = {};
  12. this._mods = [];
  13. this._textures = [];
  14. this._boundShader = null;
  15. this._changedDefines = true;
  16. this._changedUniforms = true;
  17. this._modulesChanged = false;
  18. this.needsTexturePush = false;
  19. this._lastShader = null;
  20. this._attributes = [];
  21. if (options && options.opId) this.opId = options.opId;
  22.  
  23. if (this._cgl.glVersion == 1)
  24. {
  25. this._cgl.enableExtension("OES_texture_float");
  26. this._cgl.enableExtension("OES_texture_float_linear");
  27. this._cgl.enableExtension("OES_texture_half_float");
  28. this._cgl.enableExtension("OES_texture_half_float_linear");
  29. }
  30. }
  31.  
  32. bind(curShader, pushShader)
  33. {
  34. const shader = curShader || this._cgl.getShader();
  35. if (!shader) return;
  36.  
  37. this._boundShader = this._origShaders[shader.id];
  38. let missingMod = false;
  39.  
  40. if (this._boundShader && this._lastShader != this._boundShader.shader) // shader changed since last bind
  41. {
  42. if (!this._boundShader.shader.hasModule(this._mods[0].id)) missingMod = true;
  43. }
  44.  
  45. if (missingMod || !this._boundShader || shader.lastCompile != this._boundShader.lastCompile || this._modulesChanged || shader._needsRecompile)
  46. {
  47. if (this._boundShader) this._boundShader.shader.dispose();
  48. if (shader._needsRecompile) shader.compile();
  49. this.needsTexturePush = true;
  50.  
  51. this._boundShader = this._origShaders[shader.id] =
  52. {
  53. "lastCompile": shader.lastCompile,
  54. "orig": shader,
  55. "shader": shader.copy()
  56. };
  57.  
  58. this._addModulesToShader(this._boundShader.shader);
  59. this._updateDefinesShader(this._boundShader.shader);
  60. this._updateUniformsShader(this._boundShader.shader);
  61. }
  62.  
  63. this._boundShader.wireframe = shader.wireframe;
  64. if (this._changedDefines) this._updateDefines();
  65. if (this._changedUniforms) this._updateUniforms();
  66.  
  67. if (pushShader !== false) this._cgl.pushShader(this._boundShader.shader);
  68.  
  69. this._boundShader.shader.copyUniformValues(this._boundShader.orig);
  70.  
  71. if (this.needsTexturePush)
  72. {
  73. for (let j = 0; j < this._textures.length; j++)
  74. {
  75. const uniformName = this._textures[j][0];
  76. const tex = this._textures[j][1];
  77. const texType = this._textures[j][2];
  78.  
  79. if (this._getUniform(uniformName))
  80. {
  81. const name = this.getPrefixedName(uniformName);
  82. const uni = this._boundShader.shader.getUniform(name);
  83.  
  84. if (uni) this._boundShader.shader.pushTexture(uni, tex, texType);
  85. }
  86. }
  87.  
  88. this.needsTexturePush = false;
  89. this._textures.length = 0;
  90. }
  91.  
  92. this._modulesChanged = false;
  93.  
  94. this._boundShader.shader.fromMod = this;
  95.  
  96. if (this.onBind) this.onBind(this._boundShader.shader);
  97.  
  98. return this._boundShader.shader;
  99. }
  100.  
  101. unbind(popShader)
  102. {
  103. if (this._boundShader)
  104. {
  105. if (popShader !== false) this._cgl.popShader();
  106. // this._boundShader = null;
  107. // return true;
  108. }
  109. this._boundShader = null;
  110. }
  111.  
  112. _addModulesToShader(shader)
  113. {
  114. let firstMod;
  115.  
  116. if (this._mods.length > 1) firstMod = this._mods[0];
  117.  
  118. for (let i = 0; i < this._mods.length; i++) shader.addModule(this._mods[i], firstMod);
  119. }
  120.  
  121. _removeModulesFromShader(mod)
  122. {
  123. for (const j in this._origShaders) this._origShaders[j].shader.removeModule(mod);
  124. }
  125.  
  126. addModule(mod)
  127. {
  128. this._mods.push(mod);
  129. this._modulesChanged = true;
  130. }
  131.  
  132. removeModule(title)
  133. {
  134. const indicesToRemove = [];
  135.  
  136. let found = false;
  137. for (let i = 0; i < this._mods.length; i++)
  138. {
  139. if (this._mods[i].title == title)
  140. {
  141. found = true;
  142. this._removeModulesFromShader(this._mods[i]);
  143. indicesToRemove.push(i);
  144. }
  145. }
  146.  
  147. // * go in reverse order so the indices of the mods stay the same
  148. for (let j = indicesToRemove.length - 1; j >= 0; j -= 1)
  149. this._mods.splice(indicesToRemove[j], 1);
  150.  
  151. this._modulesChanged = true;
  152. }
  153.  
  154. _updateUniformsShader(shader)
  155. {
  156. for (let i = 0; i < this._uniforms.length; i++)
  157. {
  158. const uni = this._uniforms[i];
  159. const name = this.getPrefixedName(uni.name);
  160.  
  161. if (!shader.hasUniform(name) && !uni.structName)
  162. {
  163. let un = null;
  164. if (uni.shaderType === "both")
  165. {
  166. un = shader.addUniformBoth(uni.type, name, uni.v1, uni.v2, uni.v3, uni.v4);
  167. un.comment = "mod: " + this._name;
  168. }
  169. else if (uni.shaderType === "frag")
  170. {
  171. un = shader.addUniformFrag(uni.type, name, uni.v1, uni.v2, uni.v3, uni.v4);
  172. un.comment = "mod: " + this._name;
  173. }
  174. else if (uni.shaderType === "vert")
  175. {
  176. un = shader.addUniformVert(uni.type, name, uni.v1, uni.v2, uni.v3, uni.v4);
  177. un.comment = "mod: " + this._name;
  178. }
  179. }
  180. }
  181.  
  182. for (let j = 0; j < this._structUniforms.length; j += 1)
  183. {
  184. const structUniform = this._structUniforms[j];
  185. let structUniformName = structUniform.uniformName;
  186. let structName = structUniform.structName;
  187.  
  188. const members = structUniform.members;
  189.  
  190. structUniformName = this.getPrefixedName(structUniform.uniformName);
  191. structName = this.getPrefixedName(structUniform.structName);
  192.  
  193. if (structUniform.shaderType === "frag")
  194. {
  195. shader.addUniformStructFrag(structName, structUniformName, members);
  196. }
  197. if (structUniform.shaderType === "vert")
  198. {
  199. shader.addUniformStructVert(structName, structUniformName, members);
  200. }
  201. if (structUniform.shaderType === "both")
  202. {
  203. shader.addUniformStructBoth(structName, structUniformName, members);
  204. }
  205. }
  206. }
  207.  
  208. _updateUniforms()
  209. {
  210. for (const j in this._origShaders)
  211. this._updateUniformsShader(this._origShaders[j].shader);
  212.  
  213. this._changedUniforms = false;
  214. }
  215.  
  216. _setUniformValue(shader, uniformName, value)
  217. {
  218. const uniform = shader.getUniform(uniformName);
  219.  
  220. if (uniform) uniform.setValue(value);
  221. }
  222.  
  223. setUniformValue(name, value)
  224. {
  225. const uni = this._getUniform(name);
  226. if (!uni) return;
  227.  
  228. const defineName = this.getPrefixedName(name);
  229.  
  230. for (const j in this._origShaders)
  231. {
  232. this._setUniformValue(this._origShaders[j].shader, defineName, value);
  233. }
  234. }
  235.  
  236. hasUniform(name)
  237. {
  238. return this._getUniform(name);
  239. }
  240.  
  241. _getUniform(name)
  242. {
  243. for (let i = 0; i < this._uniforms.length; i++)
  244. {
  245. if (this._uniforms[i].name == name) return this._uniforms[i];
  246. if (this._uniforms[i].structName)
  247. {
  248. if (this._uniforms[i].propertyName == name) return this._uniforms[i];
  249. }
  250. }
  251. return false;
  252. }
  253.  
  254. _getStructUniform(uniName)
  255. {
  256. for (let i = 0; i < this._structUniforms.length; i += 1)
  257. if (this._structUniforms[i].uniformName === uniName) return this._structUniforms[i];
  258.  
  259. return null;
  260. }
  261.  
  262. _isStructUniform(name)
  263. {
  264. for (let i = 0; i < this._uniforms.length; i++)
  265. {
  266. if (this._uniforms[i].name == name) return false;
  267. if (this._uniforms[i].structName)
  268. {
  269. if (this._uniforms[i].propertyName == name) return true;
  270. }
  271. }
  272. return false;
  273. }
  274.  
  275.  
  276. addUniform(type, name, valOrPort, v2, v3, v4, structUniformName, structName, propertyName, shaderType)
  277. {
  278. if (!this._getUniform(name))
  279. {
  280. let _shaderType = "both";
  281. if (shaderType) _shaderType = shaderType;
  282.  
  283. this._uniforms.push(
  284. {
  285. "type": type,
  286. "name": name,
  287. "v1": valOrPort,
  288. "v2": v2,
  289. "v3": v3,
  290. "v4": v4,
  291. "structUniformName": structUniformName,
  292. "structName": structName,
  293. "propertyName": propertyName,
  294. "shaderType": _shaderType,
  295. });
  296. this._changedUniforms = true;
  297. }
  298. }
  299.  
  300. addUniformFrag(type, name, valOrPort, v2, v3, v4)
  301. {
  302. this.addUniform(type, name, valOrPort, v2, v3, v4, null, null, null, "frag");
  303. this._changedUniforms = true;
  304. }
  305.  
  306. addUniformVert(type, name, valOrPort, v2, v3, v4)
  307. {
  308. this.addUniform(type, name, valOrPort, v2, v3, v4, null, null, null, "vert");
  309. this._changedUniforms = true;
  310. }
  311.  
  312. addUniformBoth(type, name, valOrPort, v2, v3, v4)
  313. {
  314. this.addUniform(type, name, valOrPort, v2, v3, v4, null, null, null, "both");
  315. this._changedUniforms = true;
  316. }
  317.  
  318. addUniformStruct(structName, uniformName, members, shaderType)
  319. {
  320. for (let i = 0; i < members.length; i += 1)
  321. {
  322. const member = members[i];
  323. if ((member.type === "2i" || member.type === "i" || member.type === "3i") && shaderType === "both")
  324. console.error("Adding an integer struct member to both shaders can potentially error. Please use different structs for each shader. Error occured in struct:", structName, " with member:", member.name, " of type:", member.type, ".");
  325.  
  326. if (!this._getUniform(uniformName + "." + member.name))
  327. {
  328. this.addUniform(
  329. member.type,
  330. uniformName + "." + member.name,
  331. member.v1,
  332. member.v2,
  333. member.v3,
  334. member.v4,
  335. uniformName,
  336. structName,
  337. member.name,
  338. shaderType
  339. );
  340. }
  341. }
  342. if (!this._getStructUniform(uniformName))
  343. {
  344. this._structUniforms.push({
  345. "structName": structName,
  346. "uniformName": uniformName,
  347. "members": members,
  348. "shaderType": shaderType,
  349. });
  350. }
  351. }
  352.  
  353. addUniformStructVert(structName, uniformName, members)
  354. {
  355. this.addUniformStruct(structName, uniformName, members, "vert");
  356. }
  357.  
  358. addUniformStructFrag(structName, uniformName, members)
  359. {
  360. this.addUniformStruct(structName, uniformName, members, "frag");
  361. }
  362.  
  363. addUniformStructBoth(structName, uniformName, members)
  364. {
  365. this.addUniformStruct(structName, uniformName, members, "both");
  366. }
  367.  
  368. addAttribute(attr)
  369. {
  370. for (let i = 0; i < this._attributes.length; i++)
  371. {
  372. if (this._attributes[i].name == attr.name && this._attributes[i].nameFrag == attr.nameFrag) return;
  373. }
  374. this._attributes.push(attr);
  375. }
  376.  
  377. pushTexture(uniformName, tex, texType)
  378. {
  379. if (!tex) throw (new Error("no texture given to texturestack"));
  380.  
  381. this._textures.push([uniformName, tex, texType]);
  382. this.needsTexturePush = true;
  383. }
  384.  
  385. _removeUniformFromShader(name, shader)
  386. {
  387. if (shader.hasUniform(name)) shader.removeUniform(name);
  388. }
  389.  
  390. removeUniform(name)
  391. {
  392. if (this._getUniform(name))
  393. {
  394. for (let j = this._uniforms.length - 1; j >= 0; j -= 1)
  395. {
  396. const nameToRemove = name;
  397.  
  398. if (this._uniforms[j].name == name && !this._uniforms[j].structName)
  399. {
  400. for (const k in this._origShaders)
  401. {
  402. this._removeUniformFromShader(
  403. this.getPrefixedName(nameToRemove),
  404. this._origShaders[k].shader
  405. );
  406. }
  407.  
  408. this._uniforms.splice(j, 1);
  409. }
  410. }
  411. this._changedUniforms = true;
  412. }
  413. }
  414.  
  415. removeUniformStruct(uniformName)
  416. {
  417. if (this._getStructUniform(uniformName))
  418. {
  419. for (let i = this._structUniforms.length - 1; i >= 0; i -= 1)
  420. {
  421. const structToRemove = this._structUniforms[i];
  422.  
  423. if (structToRemove.uniformName === uniformName)
  424. {
  425. for (const j in this._origShaders)
  426. {
  427. for (let k = 0; k < structToRemove.members.length; k += 1)
  428. {
  429. const member = structToRemove.members[k];
  430. this._removeUniformFromShader(
  431. this.getPrefixedName(member.name),
  432. this._origShaders[j].shader
  433. );
  434. }
  435. }
  436.  
  437. this._structUniforms.splice(i, 1);
  438. }
  439. }
  440.  
  441. this._changedUniforms = true;
  442. }
  443. }
  444.  
  445.  
  446. getPrefixedName(name)
  447. {
  448. const prefix = this._mods[0].group;
  449. if (prefix === undefined)
  450. {
  451. return;
  452. }
  453. if (name.startsWith("MOD_"))
  454. {
  455. name = name.substr("MOD_".length);
  456. name = "mod" + prefix + "_" + name;
  457. }
  458. return name;
  459. }
  460.  
  461. _updateDefinesShader(shader)
  462. {
  463. for (const i in this._defines)
  464. {
  465. const name = this.getPrefixedName(i);
  466. if (this._defines[i] !== null && this._defines[i] !== undefined) shader.define(name, this._defines[i]);
  467. else shader.removeDefine(name);
  468. }
  469.  
  470. for (const i in this._definesToggled)
  471. {
  472. const name = this.getPrefixedName(i);
  473. shader.toggleDefine(name, this._definesToggled[i]);
  474. }
  475. }
  476.  
  477.  
  478. _updateDefines()
  479. {
  480. for (const j in this._origShaders) this._updateDefinesShader(this._origShaders[j].shader);
  481.  
  482. this._changedDefines = false;
  483. }
  484.  
  485. define(what, value)
  486. {
  487. if (value === undefined)value = true;
  488. this._defines[what] = value;
  489. this._changedDefines = true;
  490. }
  491.  
  492. removeDefine(name)
  493. {
  494. this._defines[name] = null;
  495. this._changedDefines = true;
  496. }
  497.  
  498. hasDefine(name)
  499. {
  500. if (this._defines[name] !== null && this._defines[name] !== undefined) return true;
  501. return false;
  502. }
  503.  
  504. toggleDefine(name, b)
  505. {
  506. this._changedDefines = true;
  507. this._definesToggled[name] = b;
  508. }
  509.  
  510. currentShader()
  511. {
  512. if (!this._boundShader) return null;
  513. return this._boundShader.shader;
  514. }
  515.  
  516. dispose()
  517. {
  518.  
  519. }
  520. }
  521.  
  522.  
  523. export { ShaderModifier };