gulp-processShaders.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. // Dependencies.
  2. var through = require('through2');
  3. var PluginError = require('plugin-error');
  4. let path = require('path');
  5. let fs = require('fs');
  6. /**
  7. * Template creating hidden ts file containing the shaders.
  8. */
  9. let tsShaderTemplate =
  10. `import { Effect } from "babylonjs";
  11. ##INCLUDES_PLACEHOLDER##
  12. let name = '##NAME_PLACEHOLDER##';
  13. let shader = \`##SHADER_PLACEHOLDER##\`;
  14. Effect.##SHADERSTORE_PLACEHOLDER##[name] = shader;
  15. export { shader, name };
  16. `;
  17. /**
  18. * Get the shaders name from their path.
  19. */
  20. function getShaderName(filename) {
  21. let parts = filename.split('.');
  22. if (parts[1] !== 'fx') {
  23. return parts[0] + (parts[1] === 'fragment' ? 'Pixel' : 'Vertex') + "Shader";
  24. } else {
  25. return parts[0];
  26. }
  27. }
  28. /**
  29. * Get the shaders included in the current one to generate to proper imports.
  30. */
  31. function getIncludes(sourceCode) {
  32. var regex = /#include<(.+)>(\((.*)\))*(\[(.*)\])*/g;
  33. var match = regex.exec(sourceCode);
  34. var includes = new Set();
  35. while (match != null) {
  36. let includeFile = match[1];
  37. // Uniform declaration
  38. if (includeFile.indexOf("__decl__") !== -1) {
  39. includeFile = includeFile.replace(/__decl__/, "");
  40. // Add non UBO import
  41. const noUBOFile = includeFile + "Declaration";
  42. includes.add(noUBOFile);
  43. includeFile = includeFile.replace(/Vertex/, "Ubo");
  44. includeFile = includeFile.replace(/Fragment/, "Ubo");
  45. const uBOFile = includeFile + "Declaration";
  46. includes.add(uBOFile);
  47. }
  48. else {
  49. includes.add(includeFile);
  50. }
  51. match = regex.exec(sourceCode);
  52. }
  53. return includes;
  54. }
  55. /**
  56. * Generate a ts file per shader file.
  57. */
  58. function main(isCore) {
  59. return through.obj(function (file, enc, cb) {
  60. if (file.isNull()) {
  61. cb(null, file);
  62. return;
  63. }
  64. if (file.isStream()) {
  65. cb(new PluginError("Process Shader", "Streaming not supported."));
  66. }
  67. const filename = path.basename(file.path);
  68. const normalized = path.normalize(file.path);
  69. const directory = path.dirname(normalized);
  70. const shaderName = getShaderName(filename);
  71. const tsFilename = filename.replace('.fx', '.ts');
  72. let fxData = file.contents.toString();
  73. // Remove Trailing whitespace...
  74. fxData = fxData.replace(/[^\S\r\n]+$/gm, "");
  75. // Generate imports for includes.
  76. let includeText = "";
  77. const includes = getIncludes(fxData);
  78. includes.forEach((entry) => {
  79. if (isCore) {
  80. includeText = includeText + `import "./ShadersInclude/${entry}";
  81. `;
  82. }
  83. else {
  84. includeText = includeText + `import "babylonjs/Shaders/ShadersInclude/${entry}";
  85. `;
  86. }
  87. });
  88. // Chose shader store.
  89. const shaderStore = directory.indexOf("ShadersInclude") > -1 ? "IncludesShadersStore" : "ShadersStore";
  90. // Fill template in.
  91. let tsContent = tsShaderTemplate.replace('##INCLUDES_PLACEHOLDER##', includeText);
  92. tsContent = tsContent.replace('##NAME_PLACEHOLDER##', shaderName);
  93. tsContent = tsContent.replace('##SHADER_PLACEHOLDER##', fxData);
  94. tsContent = tsContent.replace('##SHADERSTORE_PLACEHOLDER##', shaderStore);
  95. // Go to disk.
  96. fs.writeFileSync(directory + '/' + tsFilename, tsContent);
  97. return cb();
  98. });
  99. }
  100. module.exports = main;