Home Reference Source

cables_dev/cables/src/core/cg/cg_shader.js

  1. import { EventTarget } from "../eventtarget.js";
  2. import { simpleId } from "../utils.js";
  3.  
  4. class CgShader extends EventTarget
  5. {
  6. constructor()
  7. {
  8. super();
  9. this.id = simpleId();
  10. this._isValid = true;
  11. this._defines = [];
  12.  
  13. this._moduleNames = [];
  14. this._modules = [];
  15. this._moduleNumId = 0;
  16. }
  17.  
  18. /**
  19. * easily enable/disable a define without a value
  20. * @function toggleDefine
  21. * @memberof Shader
  22. * @instance
  23. * @param {name} name
  24. * @param {any} enabled value or port
  25. */
  26. toggleDefine(name, enabled)
  27. {
  28. if (enabled && typeof (enabled) == "object" && enabled.addEventListener) // port
  29. {
  30. if (enabled.changeListener)enabled.removeEventListener(enabled.changeListener);
  31.  
  32. enabled.onToggleDefine = (v) =>
  33. {
  34. this.toggleDefine(name, v);
  35. };
  36.  
  37. enabled.changeListener = enabled.on("change", enabled.onToggleDefine);
  38. enabled = enabled.get();
  39. }
  40.  
  41. if (enabled) this.define(name);
  42. else this.removeDefine(name);
  43. }
  44.  
  45. /**
  46. * add a define to a shader, e.g. #define DO_THIS_THAT 1
  47. * @function define
  48. * @memberof Shader
  49. * @instance
  50. * @param {String} name
  51. * @param {Any} value (can be empty)
  52. */
  53. define(name, value)
  54. {
  55. if (value === null || value === undefined) value = "";
  56.  
  57. if (typeof (value) == "object") // port
  58. {
  59. value.removeEventListener("change", value.onDefineChange);
  60. value.onDefineChange = (v) =>
  61. {
  62. this.define(name, v);
  63. };
  64. value.on("change", value.onDefineChange);
  65.  
  66. value = value.get();
  67. }
  68.  
  69.  
  70. for (let i = 0; i < this._defines.length; i++)
  71. {
  72. if (this._defines[i][0] == name && this._defines[i][1] == value) return;
  73. if (this._defines[i][0] == name)
  74. {
  75. this._defines[i][1] = value;
  76. this.setWhyCompile("define " + name + " " + value);
  77.  
  78. this._needsRecompile = true;
  79. return;
  80. }
  81. }
  82. this.setWhyCompile("define " + name + " " + value);
  83. this._needsRecompile = true;
  84. this._defines.push([name, value]);
  85. }
  86.  
  87. getDefines()
  88. {
  89. return this._defines;
  90. }
  91.  
  92. getDefine(name)
  93. {
  94. for (let i = 0; i < this._defines.length; i++)
  95. if (this._defines[i][0] == name) return this._defines[i][1];
  96. return null;
  97. }
  98.  
  99. /**
  100. * return true if shader has define
  101. * @function hasDefine
  102. * @memberof Shader
  103. * @instance
  104. * @param {String} name
  105. * @return {Boolean}
  106. */
  107. hasDefine(name)
  108. {
  109. for (let i = 0; i < this._defines.length; i++)
  110. if (this._defines[i][0] == name) return true;
  111. }
  112.  
  113. /**
  114. * remove a define from a shader
  115. * @param {name} name
  116. * @function removeDefine
  117. * @memberof Shader
  118. * @instance
  119. */
  120. removeDefine(name)
  121. {
  122. for (let i = 0; i < this._defines.length; i++)
  123. {
  124. if (this._defines[i][0] == name)
  125. {
  126. this._defines.splice(i, 1);
  127. this._needsRecompile = true;
  128.  
  129. this.setWhyCompile("define removed:" + name);
  130.  
  131. return;
  132. }
  133. }
  134. }
  135.  
  136.  
  137. hasModule(modId)
  138. {
  139. for (let i = 0; i < this._modules.length; i++)
  140. {
  141. if (this._modules[i].id == modId) return true;
  142. }
  143. return false;
  144. }
  145.  
  146. setModules(names)
  147. {
  148. this._moduleNames = names;
  149. }
  150.  
  151.  
  152. /**
  153. * remove a module from shader
  154. * @function removeModule
  155. * @memberof Shader
  156. * @instance
  157. * @param {shaderModule} mod the module to be removed
  158. */
  159. removeModule(mod)
  160. {
  161. for (let i = 0; i < this._modules.length; i++)
  162. {
  163. if (mod && mod.id)
  164. {
  165. if (this._modules[i].id == mod.id || !this._modules[i])
  166. {
  167. let found = true;
  168. while (found)
  169. {
  170. found = false;
  171. for (let j = 0; j < this._uniforms.length; j++)
  172. {
  173. if (this._uniforms[j].getName().startsWith(mod.prefix))
  174. {
  175. this._uniforms.splice(j, 1);
  176. found = true;
  177. continue;
  178. }
  179. }
  180. }
  181.  
  182. this._needsRecompile = true;
  183. this.setWhyCompile("remove module " + mod.title);
  184. this._modules.splice(i, 1);
  185. break;
  186. }
  187. }
  188. }
  189. }
  190.  
  191.  
  192. getNumModules()
  193. {
  194. return this._modules.length;
  195. }
  196.  
  197.  
  198. getCurrentModules() { return this._modules; }
  199.  
  200.  
  201. /**
  202. * add a module
  203. * @function addModule
  204. * @memberof Shader
  205. * @instance
  206. * @param {shaderModule} mod the module to be added
  207. * @param {shaderModule} [sibling] sibling module, new module will share the same group
  208. */
  209. addModule(mod, sibling)
  210. {
  211. if (this.hasModule(mod.id)) return;
  212. if (!mod.id) mod.id = CABLES.simpleId();
  213. if (!mod.numId) mod.numId = this._moduleNumId;
  214. if (!mod.num)mod.num = this._modules.length;
  215. if (sibling && !sibling.group) sibling.group = simpleId();
  216.  
  217. if (!mod.group)
  218. if (sibling) mod.group = sibling.group;
  219. else mod.group = simpleId();
  220.  
  221. mod.prefix = "mod" + mod.group + "_";
  222. this._modules.push(mod);
  223.  
  224. this._needsRecompile = true;
  225. this.setWhyCompile("add module " + mod.title);
  226. this._moduleNumId++;
  227.  
  228. return mod;
  229. }
  230.  
  231. getAttributeSrc(mod, srcHeadVert, srcVert)
  232. {
  233. if (mod.attributes)
  234. for (let k = 0; k < mod.attributes.length; k++)
  235. {
  236. const r = this._getAttrSrc(mod.attributes[k], false);
  237. if (r.srcHeadVert)srcHeadVert += r.srcHeadVert;
  238. if (r.srcVert)srcVert += r.srcVert;
  239. }
  240.  
  241. return { "srcHeadVert": srcHeadVert, "srcVert": srcVert };
  242. }
  243.  
  244. replaceModuleSrc()
  245. {
  246. let srcHeadVert = "";
  247.  
  248. for (let j = 0; j < this._modules.length; j++)
  249. {
  250. const mod = this._modules[j];
  251. if (mod.name == this._moduleNames[i])
  252. {
  253. srcHeadVert += "\n//---- MOD: group:" + mod.group + ": idx:" + j + " - prfx:" + mod.prefix + " - " + mod.title + " ------\n";
  254.  
  255. srcVert += "\n\n//---- MOD: " + mod.title + " / " + mod.priority + " ------\n";
  256.  
  257.  
  258. if (mod.getAttributeSrc)
  259. {
  260. const r = getAttributeSrc(mod, srcHeadVert, srcVert);
  261. if (r.srcHeadVert)srcHeadVert += r.srcHeadVert;
  262. if (r.srcVert)srcVert += r.srcVert;
  263. }
  264.  
  265.  
  266. srcHeadVert += mod.srcHeadVert || "";
  267. srcVert += mod.srcBodyVert || "";
  268.  
  269. srcHeadVert += "\n//---- end mod ------\n";
  270.  
  271. srcVert += "\n//---- end mod ------\n";
  272.  
  273. srcVert = srcVert.replace(/{{mod}}/g, mod.prefix);
  274. srcHeadVert = srcHeadVert.replace(/{{mod}}/g, mod.prefix);
  275.  
  276. srcVert = srcVert.replace(/MOD_/g, mod.prefix);
  277. srcHeadVert = srcHeadVert.replace(/MOD_/g, mod.prefix);
  278. }
  279. }
  280.  
  281.  
  282. vs = vs.replace("{{" + this._moduleNames[i] + "}}", srcVert);
  283. }
  284. }
  285.  
  286. export { CgShader };