diff --git a/examples/jsm/renderers/nodes/parsers/WGSLNodeFunction.js b/examples/jsm/renderers/nodes/parsers/WGSLNodeFunction.js new file mode 100644 index 00000000000000..221e490a2ae290 --- /dev/null +++ b/examples/jsm/renderers/nodes/parsers/WGSLNodeFunction.js @@ -0,0 +1,89 @@ +import NodeFunction from '../core/NodeFunction.js'; +import NodeFunctionInput from '../core/NodeFunctionInput.js'; + +const declarationRegexp = /^fn\s*([a-z_0-9]+)?\s*\(([\s\S]*?)\)\s*\-\>\s*([a-z_0-9]+)?/i; +const propertiesRegexp = /[a-z_0-9]+/ig; + +const parse = ( source ) => { + + source = source.trim(); + + const declaration = source.match( declarationRegexp ); + + if ( declaration !== null && declaration.length === 4 ) { + + // tokenizer + + const inputsCode = declaration[ 2 ]; + const propsMatches = []; + + let nameMatch = null; + + while ( ( nameMatch = propertiesRegexp.exec( inputsCode ) ) !== null ) { + + propsMatches.push( nameMatch ); + + } + + // parser + + const inputs = []; + + let i = 0; + + while ( i < propsMatches.length ) { + + const name = propsMatches[ i ++ ][ 0 ]; + const type = propsMatches[ i ++ ][ 0 ]; + + propsMatches[ i ++ ][ 0 ]; // precision + + inputs.push( new NodeFunctionInput( type, name ) ); + + } + + // + + const blockCode = source.substring( declaration[ 0 ].length ); + + const name = declaration[ 1 ] !== undefined ? declaration[ 1 ] : ''; + const type = declaration[ 3 ]; + + return { + type, + inputs, + name, + inputsCode, + blockCode + }; + + } else { + + throw new Error( 'FunctionNode: Function is not a WGSL code.' ); + + } + +}; + +class WGSLNodeFunction extends NodeFunction { + + constructor( source ) { + + const { type, inputs, name, inputsCode, blockCode } = parse( source ); + + super( type, inputs, name ); + + this.inputsCode = inputsCode; + this.blockCode = blockCode; + + } + + getCode( name = this.name ) { + + return `fn ${ name } ( ${ this.inputsCode.trim() } ) -> ${ this.type }` + this.blockCode; + + } + +} + +export default WGSLNodeFunction; diff --git a/examples/jsm/renderers/nodes/parsers/WGSLNodeParser.js b/examples/jsm/renderers/nodes/parsers/WGSLNodeParser.js new file mode 100644 index 00000000000000..4f62a3bc0bcc31 --- /dev/null +++ b/examples/jsm/renderers/nodes/parsers/WGSLNodeParser.js @@ -0,0 +1,14 @@ +import NodeParser from '../core/NodeParser.js'; +import WGSLNodeFunction from './WGSLNodeFunction.js'; + +class WGSLNodeParser extends NodeParser { + + parseFunction( source ) { + + return new WGSLNodeFunction( source ); + + } + +} + +export default WGSLNodeParser; diff --git a/examples/jsm/renderers/webgpu/nodes/WebGPUNodeBuilder.js b/examples/jsm/renderers/webgpu/nodes/WebGPUNodeBuilder.js index 804dc2c2c3c931..8a0dd71c1ff1e6 100644 --- a/examples/jsm/renderers/webgpu/nodes/WebGPUNodeBuilder.js +++ b/examples/jsm/renderers/webgpu/nodes/WebGPUNodeBuilder.js @@ -21,6 +21,7 @@ import ModelViewProjectionNode from '../../nodes/accessors/ModelViewProjectionNo import SkinningNode from '../../nodes/accessors/SkinningNode.js'; import LightContextNode from '../../nodes/lights/LightContextNode.js'; import OperatorNode from '../../nodes/math/OperatorNode.js'; +import WGSLNodeParser from '../../nodes/parsers/WGSLNodeParser.js'; const wgslTypeLib = { float: 'f32', @@ -68,7 +69,7 @@ class WebGPUNodeBuilder extends NodeBuilder { constructor( object, renderer, lightNode = null ) { - super( object, renderer ); + super( object, renderer, new WGSLNodeParser() ); this.lightNode = lightNode;