Home Reference Source

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