WGSLNodeFunction.js 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. import NodeFunction from '../../../nodes/core/NodeFunction.js';
  2. import NodeFunctionInput from '../../../nodes/core/NodeFunctionInput.js';
  3. const declarationRegexp = /^[fn]*\s*([a-z_0-9]+)?\s*\(([\s\S]*?)\)\s*[\-\>]*\s*([a-z_0-9]+)?/i;
  4. const propertiesRegexp = /[a-z_0-9]+|<(.*?)>+/ig;
  5. const wgslTypeLib = {
  6. 'f32': 'float',
  7. 'i32': 'int',
  8. 'u32': 'uint',
  9. 'bool': 'bool',
  10. 'vec2<f32>': 'vec2',
  11. 'vec2<i32>': 'ivec2',
  12. 'vec2<u32>': 'uvec2',
  13. 'vec2<bool>': 'bvec2',
  14. 'vec3<f32>': 'vec3',
  15. 'vec3<i32>': 'ivec3',
  16. 'vec3<u32>': 'uvec3',
  17. 'vec3<bool>': 'bvec3',
  18. 'vec4<f32>': 'vec4',
  19. 'vec4<i32>': 'ivec4',
  20. 'vec4<u32>': 'uvec4',
  21. 'vec4<bool>': 'bvec4',
  22. 'mat2x2<f32>': 'mat2',
  23. 'mat2x2<i32>': 'imat2',
  24. 'mat2x2<u32>': 'umat2',
  25. 'mat2x2<bool>': 'bmat2',
  26. 'mat3x3<f32>': 'mat3',
  27. 'mat3x3<i32>': 'imat3',
  28. 'mat3x3<u32>': 'umat3',
  29. 'mat3x3<bool>': 'bmat3',
  30. 'mat4x4<f32>': 'mat4',
  31. 'mat4x4<i32>': 'imat4',
  32. 'mat4x4<u32>': 'umat4',
  33. 'mat4x4<bool>': 'bmat4'
  34. };
  35. const parse = ( source ) => {
  36. source = source.trim();
  37. const declaration = source.match( declarationRegexp );
  38. if ( declaration !== null && declaration.length === 4 ) {
  39. // tokenizer
  40. const inputsCode = declaration[ 2 ];
  41. const propsMatches = [];
  42. let nameMatch = null;
  43. while ( ( nameMatch = propertiesRegexp.exec( inputsCode ) ) !== null ) {
  44. propsMatches.push( nameMatch );
  45. }
  46. // parser
  47. const inputs = [];
  48. let i = 0;
  49. while ( i < propsMatches.length ) {
  50. // default
  51. const name = propsMatches[ i ++ ][ 0 ];
  52. let type = propsMatches[ i ++ ][ 0 ];
  53. // precision
  54. if ( i < propsMatches.length && propsMatches[ i ][ 0 ].startsWith( '<' ) === true ) {
  55. const elementType = propsMatches[ i ++ ][ 0 ];
  56. // If primitive data type
  57. if ( ! elementType.includes( ',' ) ) {
  58. type += elementType;
  59. }
  60. }
  61. type = wgslTypeLib[ type ] || type;
  62. // add input
  63. inputs.push( new NodeFunctionInput( type, name ) );
  64. }
  65. //
  66. const blockCode = source.substring( declaration[ 0 ].length );
  67. const name = declaration[ 1 ] !== undefined ? declaration[ 1 ] : '';
  68. const type = declaration[ 3 ] || 'void';
  69. return {
  70. type,
  71. inputs,
  72. name,
  73. inputsCode,
  74. blockCode
  75. };
  76. } else {
  77. throw new Error( 'FunctionNode: Function is not a WGSL code.' );
  78. }
  79. };
  80. class WGSLNodeFunction extends NodeFunction {
  81. constructor( source ) {
  82. const { type, inputs, name, inputsCode, blockCode } = parse( source );
  83. super( type, inputs, name );
  84. this.inputsCode = inputsCode;
  85. this.blockCode = blockCode;
  86. }
  87. getCode( name = this.name ) {
  88. const type = this.type !== 'void' ? '-> ' + this.type : '';
  89. return `fn ${ name } ( ${ this.inputsCode.trim() } ) ${ type }` + this.blockCode;
  90. }
  91. }
  92. export default WGSLNodeFunction;