nativeShaderProcessor.ts 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. import { WebGL2ShaderProcessor } from "../WebGL/webGL2ShaderProcessors";
  2. import { VertexBuffer } from "../../Meshes/buffer";
  3. // These numbers must match the values for bgfx::Attrib::Enum
  4. const attributeLocations: { [kind: string]: number } = {
  5. [VertexBuffer.PositionKind]: 0,
  6. [VertexBuffer.NormalKind]: 1,
  7. [VertexBuffer.TangentKind]: 2,
  8. [VertexBuffer.ColorKind]: 4,
  9. [VertexBuffer.MatricesIndicesKind]: 8,
  10. [VertexBuffer.MatricesWeightsKind]: 9,
  11. };
  12. // Must match bgfx::Attrib::TexCoord0
  13. const firstGenericAttributeLocation = 10;
  14. // Must match bgfx::Attrib::TexCoord7
  15. const lastGenericAttributeLocation = 17;
  16. /** @hidden */
  17. export class NativeShaderProcessor extends WebGL2ShaderProcessor {
  18. private _genericAttributeLocation: number;
  19. private _varyingLocationCount: number;
  20. private _varyingLocationMap: { [name: string]: number };
  21. private _replacements: Array<{ searchValue: RegExp, replaceValue: string }>;
  22. private _textureCount: number;
  23. private _uniforms: Array<string>;
  24. public lineProcessor(line: string): string {
  25. for (const replacement of this._replacements) {
  26. line = line.replace(replacement.searchValue, replacement.replaceValue);
  27. }
  28. return line;
  29. }
  30. public attributeProcessor(attribute: string): string {
  31. const match = attribute.match(/attribute\s+[^\s]+\s+([^\s]+)\s*(?:\[.+\])?\s*;/)!;
  32. const name = match[1];
  33. let location = attributeLocations[name];
  34. if (location === undefined) {
  35. location = this._genericAttributeLocation++;
  36. if (location > lastGenericAttributeLocation) {
  37. throw new Error("Exceeded maximum custom attributes");
  38. }
  39. }
  40. return `layout(location=${location}) ${super.attributeProcessor(attribute)}`;
  41. }
  42. public varyingProcessor(varying: string, isFragment: boolean): string {
  43. let location: number;
  44. if (isFragment) {
  45. location = this._varyingLocationMap[varying];
  46. }
  47. else {
  48. location = this._varyingLocationCount++;
  49. this._varyingLocationMap[varying] = location;
  50. }
  51. return `layout(location=${location}) ${super.varyingProcessor(varying, isFragment)}`;
  52. }
  53. public uniformProcessor(uniform: string): string {
  54. const match = uniform.match(/uniform\s+([^\s]+)\s+([^\s]+)\s*(?:\[.+\])?\s*;/)!;
  55. const type = match[1];
  56. const name = match[2];
  57. switch (type) {
  58. case "sampler2D":
  59. case "samplerCube": {
  60. const suffix = type.substr(7);
  61. const binding = this._textureCount++;
  62. this._replacements.push({ searchValue: new RegExp(`\\b${name}\\b`), replaceValue: `sampler${suffix}(${name}Texture, ${name})` });
  63. return `layout(binding=${binding}) uniform texture${suffix} ${name}Texture;\nlayout(binding=${binding}) uniform sampler ${name};`;
  64. }
  65. }
  66. this._uniforms.push(uniform);
  67. return this._uniforms.length === 1 ? "<UNIFORM>" : "";
  68. }
  69. public preProcessor(code: string, defines: string[], isFragment: boolean): string {
  70. this._genericAttributeLocation = firstGenericAttributeLocation;
  71. if (!isFragment) {
  72. this._varyingLocationCount = 0;
  73. this._varyingLocationMap = {};
  74. }
  75. this._replacements = [];
  76. this._textureCount = 0;
  77. this._uniforms = [];
  78. return code;
  79. }
  80. public postProcessor(code: string, defines: string[], isFragment: boolean): string {
  81. code = super.postProcessor(code, defines, isFragment);
  82. code = code.replace("<UNIFORM>", `uniform Frame {\n${this._uniforms.join("\n")}\n};`);
  83. code = code.replace("out vec4 glFragColor", "layout(location=0) out vec4 glFragColor");
  84. return code;
  85. }
  86. }