131 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			131 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
|  | import CodeNode from './CodeNode.js'; | ||
|  | import { addNodeClass } from '../core/Node.js'; | ||
|  | import { nodeObject } from '../shadernode/ShaderNode.js'; | ||
|  | 
 | ||
|  | class FunctionNode extends CodeNode { | ||
|  | 
 | ||
|  | 	constructor( code = '', includes = [], language = '' ) { | ||
|  | 
 | ||
|  | 		super( code, includes, language ); | ||
|  | 
 | ||
|  | 		this.keywords = {}; | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	getNodeType( builder ) { | ||
|  | 
 | ||
|  | 		return this.getNodeFunction( builder ).type; | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	getInputs( builder ) { | ||
|  | 
 | ||
|  | 		return this.getNodeFunction( builder ).inputs; | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	getNodeFunction( builder ) { | ||
|  | 
 | ||
|  | 		const nodeData = builder.getDataFromNode( this ); | ||
|  | 
 | ||
|  | 		let nodeFunction = nodeData.nodeFunction; | ||
|  | 
 | ||
|  | 		if ( nodeFunction === undefined ) { | ||
|  | 
 | ||
|  | 			nodeFunction = builder.parser.parseFunction( this.code ); | ||
|  | 
 | ||
|  | 			nodeData.nodeFunction = nodeFunction; | ||
|  | 
 | ||
|  | 		} | ||
|  | 
 | ||
|  | 		return nodeFunction; | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	generate( builder, output ) { | ||
|  | 
 | ||
|  | 		super.generate( builder ); | ||
|  | 
 | ||
|  | 		const nodeFunction = this.getNodeFunction( builder ); | ||
|  | 
 | ||
|  | 		const name = nodeFunction.name; | ||
|  | 		const type = nodeFunction.type; | ||
|  | 
 | ||
|  | 		const nodeCode = builder.getCodeFromNode( this, type ); | ||
|  | 
 | ||
|  | 		if ( name !== '' ) { | ||
|  | 
 | ||
|  | 			// use a custom property name
 | ||
|  | 
 | ||
|  | 			nodeCode.name = name; | ||
|  | 
 | ||
|  | 		} | ||
|  | 
 | ||
|  | 		const propertyName = builder.getPropertyName( nodeCode ); | ||
|  | 
 | ||
|  | 		let code = this.getNodeFunction( builder ).getCode( propertyName ); | ||
|  | 
 | ||
|  | 		const keywords = this.keywords; | ||
|  | 		const keywordsProperties = Object.keys( keywords ); | ||
|  | 
 | ||
|  | 		if ( keywordsProperties.length > 0 ) { | ||
|  | 
 | ||
|  | 			for ( const property of keywordsProperties ) { | ||
|  | 
 | ||
|  | 				const propertyRegExp = new RegExp( `\\b${property}\\b`, 'g' ); | ||
|  | 				const nodeProperty = keywords[ property ].build( builder, 'property' ); | ||
|  | 
 | ||
|  | 				code = code.replace( propertyRegExp, nodeProperty ); | ||
|  | 
 | ||
|  | 			} | ||
|  | 
 | ||
|  | 		} | ||
|  | 
 | ||
|  | 		nodeCode.code = code + '\n'; | ||
|  | 
 | ||
|  | 		if ( output === 'property' ) { | ||
|  | 
 | ||
|  | 			return propertyName; | ||
|  | 
 | ||
|  | 		} else { | ||
|  | 
 | ||
|  | 			return builder.format( `${ propertyName }()`, type, output ); | ||
|  | 
 | ||
|  | 		} | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | } | ||
|  | 
 | ||
|  | export default FunctionNode; | ||
|  | 
 | ||
|  | const nativeFn = ( code, includes = [], language = '' ) => { | ||
|  | 
 | ||
|  | 	for ( let i = 0; i < includes.length; i ++ ) { | ||
|  | 
 | ||
|  | 		const include = includes[ i ]; | ||
|  | 
 | ||
|  | 		// TSL Function: glslFn, wgslFn
 | ||
|  | 
 | ||
|  | 		if ( typeof include === 'function' ) { | ||
|  | 
 | ||
|  | 			includes[ i ] = include.functionNode; | ||
|  | 
 | ||
|  | 		} | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	const functionNode = nodeObject( new FunctionNode( code, includes, language ) ); | ||
|  | 
 | ||
|  | 	const fn = ( ...params ) => functionNode.call( ...params ); | ||
|  | 	fn.functionNode = functionNode; | ||
|  | 
 | ||
|  | 	return fn; | ||
|  | 
 | ||
|  | }; | ||
|  | 
 | ||
|  | export const glslFn = ( code, includes ) => nativeFn( code, includes, 'glsl' ); | ||
|  | export const wgslFn = ( code, includes ) => nativeFn( code, includes, 'wgsl' ); | ||
|  | 
 | ||
|  | addNodeClass( 'FunctionNode', FunctionNode ); |