添加关照、全局等高线、修改图层问题
This commit is contained in:
		
							
								
								
									
										84
									
								
								dist/electron/static/sdk/three/jsm/nodes/code/CodeNode.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								dist/electron/static/sdk/three/jsm/nodes/code/CodeNode.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,84 @@
 | 
			
		||||
import Node, { addNodeClass } from '../core/Node.js';
 | 
			
		||||
import { nodeProxy } from '../shadernode/ShaderNode.js';
 | 
			
		||||
 | 
			
		||||
class CodeNode extends Node {
 | 
			
		||||
 | 
			
		||||
	constructor( code = '', includes = [], language = '' ) {
 | 
			
		||||
 | 
			
		||||
		super( 'code' );
 | 
			
		||||
 | 
			
		||||
		this.isCodeNode = true;
 | 
			
		||||
 | 
			
		||||
		this.code = code;
 | 
			
		||||
		this.language = language;
 | 
			
		||||
 | 
			
		||||
		this.includes = includes;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	isGlobal() {
 | 
			
		||||
 | 
			
		||||
		return true;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	setIncludes( includes ) {
 | 
			
		||||
 | 
			
		||||
		this.includes = includes;
 | 
			
		||||
 | 
			
		||||
		return this;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	getIncludes( /*builder*/ ) {
 | 
			
		||||
 | 
			
		||||
		return this.includes;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	generate( builder ) {
 | 
			
		||||
 | 
			
		||||
		const includes = this.getIncludes( builder );
 | 
			
		||||
 | 
			
		||||
		for ( const include of includes ) {
 | 
			
		||||
 | 
			
		||||
			include.build( builder );
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		const nodeCode = builder.getCodeFromNode( this, this.getNodeType( builder ) );
 | 
			
		||||
		nodeCode.code = this.code;
 | 
			
		||||
 | 
			
		||||
		return nodeCode.code;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	serialize( data ) {
 | 
			
		||||
 | 
			
		||||
		super.serialize( data );
 | 
			
		||||
 | 
			
		||||
		data.code = this.code;
 | 
			
		||||
		data.language = this.language;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	deserialize( data ) {
 | 
			
		||||
 | 
			
		||||
		super.deserialize( data );
 | 
			
		||||
 | 
			
		||||
		this.code = data.code;
 | 
			
		||||
		this.language = data.language;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default CodeNode;
 | 
			
		||||
 | 
			
		||||
export const code = nodeProxy( CodeNode );
 | 
			
		||||
 | 
			
		||||
export const js = ( src, includes ) => code( src, includes, 'js' );
 | 
			
		||||
export const wgsl = ( src, includes ) => code( src, includes, 'wgsl' );
 | 
			
		||||
export const glsl = ( src, includes ) => code( src, includes, 'glsl' );
 | 
			
		||||
 | 
			
		||||
addNodeClass( 'CodeNode', CodeNode );
 | 
			
		||||
							
								
								
									
										37
									
								
								dist/electron/static/sdk/three/jsm/nodes/code/ExpressionNode.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								dist/electron/static/sdk/three/jsm/nodes/code/ExpressionNode.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,37 @@
 | 
			
		||||
import Node, { addNodeClass } from '../core/Node.js';
 | 
			
		||||
import { nodeProxy } from '../shadernode/ShaderNode.js';
 | 
			
		||||
 | 
			
		||||
class ExpressionNode extends Node {
 | 
			
		||||
 | 
			
		||||
	constructor( snippet = '', nodeType = 'void' ) {
 | 
			
		||||
 | 
			
		||||
		super( nodeType );
 | 
			
		||||
 | 
			
		||||
		this.snippet = snippet;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	generate( builder, output ) {
 | 
			
		||||
 | 
			
		||||
		const type = this.getNodeType( builder );
 | 
			
		||||
		const snippet = this.snippet;
 | 
			
		||||
 | 
			
		||||
		if ( type === 'void' ) {
 | 
			
		||||
 | 
			
		||||
			builder.addLineFlowCode( snippet );
 | 
			
		||||
 | 
			
		||||
		} else {
 | 
			
		||||
 | 
			
		||||
			return builder.format( `( ${ snippet } )`, type, output );
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default ExpressionNode;
 | 
			
		||||
 | 
			
		||||
export const expression = nodeProxy( ExpressionNode );
 | 
			
		||||
 | 
			
		||||
addNodeClass( 'ExpressionNode', ExpressionNode );
 | 
			
		||||
							
								
								
									
										96
									
								
								dist/electron/static/sdk/three/jsm/nodes/code/FunctionCallNode.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								dist/electron/static/sdk/three/jsm/nodes/code/FunctionCallNode.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,96 @@
 | 
			
		||||
import TempNode from '../core/TempNode.js';
 | 
			
		||||
import { addNodeClass } from '../core/Node.js';
 | 
			
		||||
import { addNodeElement, nodeArray, nodeObject, nodeObjects } from '../shadernode/ShaderNode.js';
 | 
			
		||||
 | 
			
		||||
class FunctionCallNode extends TempNode {
 | 
			
		||||
 | 
			
		||||
	constructor( functionNode = null, parameters = {} ) {
 | 
			
		||||
 | 
			
		||||
		super();
 | 
			
		||||
 | 
			
		||||
		this.functionNode = functionNode;
 | 
			
		||||
		this.parameters = parameters;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	setParameters( parameters ) {
 | 
			
		||||
 | 
			
		||||
		this.parameters = parameters;
 | 
			
		||||
 | 
			
		||||
		return this;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	getParameters() {
 | 
			
		||||
 | 
			
		||||
		return this.parameters;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	getNodeType( builder ) {
 | 
			
		||||
 | 
			
		||||
		return this.functionNode.getNodeType( builder );
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	generate( builder ) {
 | 
			
		||||
 | 
			
		||||
		const params = [];
 | 
			
		||||
 | 
			
		||||
		const functionNode = this.functionNode;
 | 
			
		||||
 | 
			
		||||
		const inputs = functionNode.getInputs( builder );
 | 
			
		||||
		const parameters = this.parameters;
 | 
			
		||||
 | 
			
		||||
		if ( Array.isArray( parameters ) ) {
 | 
			
		||||
 | 
			
		||||
			for ( let i = 0; i < parameters.length; i ++ ) {
 | 
			
		||||
 | 
			
		||||
				const inputNode = inputs[ i ];
 | 
			
		||||
				const node = parameters[ i ];
 | 
			
		||||
 | 
			
		||||
				params.push( node.build( builder, inputNode.type ) );
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		} else {
 | 
			
		||||
 | 
			
		||||
			for ( const inputNode of inputs ) {
 | 
			
		||||
 | 
			
		||||
				const node = parameters[ inputNode.name ];
 | 
			
		||||
 | 
			
		||||
				if ( node !== undefined ) {
 | 
			
		||||
 | 
			
		||||
					params.push( node.build( builder, inputNode.type ) );
 | 
			
		||||
 | 
			
		||||
				} else {
 | 
			
		||||
 | 
			
		||||
					throw new Error( `FunctionCallNode: Input '${inputNode.name}' not found in FunctionNode.` );
 | 
			
		||||
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		const functionName = functionNode.build( builder, 'property' );
 | 
			
		||||
 | 
			
		||||
		return `${functionName}( ${params.join( ', ' )} )`;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default FunctionCallNode;
 | 
			
		||||
 | 
			
		||||
export const call = ( func, ...params ) => {
 | 
			
		||||
 | 
			
		||||
	params = params.length > 1 || ( params[ 0 ] && params[ 0 ].isNode === true ) ? nodeArray( params ) : nodeObjects( params[ 0 ] );
 | 
			
		||||
 | 
			
		||||
	return nodeObject( new FunctionCallNode( nodeObject( func ), params ) );
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
addNodeElement( 'call', call );
 | 
			
		||||
 | 
			
		||||
addNodeClass( 'FunctionCallNode', FunctionCallNode );
 | 
			
		||||
							
								
								
									
										130
									
								
								dist/electron/static/sdk/three/jsm/nodes/code/FunctionNode.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								dist/electron/static/sdk/three/jsm/nodes/code/FunctionNode.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,130 @@
 | 
			
		||||
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 );
 | 
			
		||||
							
								
								
									
										488
									
								
								dist/electron/static/sdk/three/jsm/nodes/code/ScriptableNode.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										488
									
								
								dist/electron/static/sdk/three/jsm/nodes/code/ScriptableNode.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,488 @@
 | 
			
		||||
import Node, { addNodeClass } from '../core/Node.js';
 | 
			
		||||
import { scriptableValue } from './ScriptableValueNode.js';
 | 
			
		||||
import { addNodeElement, nodeProxy, float } from '../shadernode/ShaderNode.js';
 | 
			
		||||
 | 
			
		||||
class Resources extends Map {
 | 
			
		||||
 | 
			
		||||
	get( key, callback = null, ...params ) {
 | 
			
		||||
 | 
			
		||||
		if ( this.has( key ) ) return super.get( key );
 | 
			
		||||
 | 
			
		||||
		if ( callback !== null ) {
 | 
			
		||||
 | 
			
		||||
			const value = callback( ...params );
 | 
			
		||||
			this.set( key, value );
 | 
			
		||||
			return value;
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class Parameters {
 | 
			
		||||
 | 
			
		||||
	constructor( scriptableNode ) {
 | 
			
		||||
 | 
			
		||||
		this.scriptableNode = scriptableNode;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	get parameters() {
 | 
			
		||||
 | 
			
		||||
		return this.scriptableNode.parameters;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	get layout() {
 | 
			
		||||
 | 
			
		||||
		return this.scriptableNode.getLayout();
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	getInputLayout( id ) {
 | 
			
		||||
 | 
			
		||||
		return this.scriptableNode.getInputLayout( id );
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	get( name ) {
 | 
			
		||||
 | 
			
		||||
		const param = this.parameters[ name ];
 | 
			
		||||
		const value = param ? param.getValue() : null;
 | 
			
		||||
 | 
			
		||||
		return value;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const global = new Resources();
 | 
			
		||||
 | 
			
		||||
class ScriptableNode extends Node {
 | 
			
		||||
 | 
			
		||||
	constructor( codeNode = null, parameters = {} ) {
 | 
			
		||||
 | 
			
		||||
		super();
 | 
			
		||||
 | 
			
		||||
		this.codeNode = codeNode;
 | 
			
		||||
		this.parameters = parameters;
 | 
			
		||||
 | 
			
		||||
		this._local = new Resources();
 | 
			
		||||
		this._output = scriptableValue();
 | 
			
		||||
		this._outputs = {};
 | 
			
		||||
		this._source = this.source;
 | 
			
		||||
		this._method = null;
 | 
			
		||||
		this._object = null;
 | 
			
		||||
		this._value = null;
 | 
			
		||||
		this._needsOutputUpdate = true;
 | 
			
		||||
 | 
			
		||||
		this.onRefresh = this.onRefresh.bind( this );
 | 
			
		||||
 | 
			
		||||
		this.isScriptableNode = true;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	get source() {
 | 
			
		||||
 | 
			
		||||
		return this.codeNode ? this.codeNode.code : '';
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	setLocal( name, value ) {
 | 
			
		||||
 | 
			
		||||
		return this._local.set( name, value );
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	getLocal( name ) {
 | 
			
		||||
 | 
			
		||||
		return this._local.get( name );
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	onRefresh() {
 | 
			
		||||
 | 
			
		||||
		this._refresh();
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	getInputLayout( id ) {
 | 
			
		||||
 | 
			
		||||
		for ( const element of this.getLayout() ) {
 | 
			
		||||
 | 
			
		||||
			if ( element.inputType && ( element.id === id || element.name === id ) ) {
 | 
			
		||||
 | 
			
		||||
				return element;
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	getOutputLayout( id ) {
 | 
			
		||||
 | 
			
		||||
		for ( const element of this.getLayout() ) {
 | 
			
		||||
 | 
			
		||||
			if ( element.outputType && ( element.id === id || element.name === id ) ) {
 | 
			
		||||
 | 
			
		||||
				return element;
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	setOutput( name, value ) {
 | 
			
		||||
 | 
			
		||||
		const outputs = this._outputs;
 | 
			
		||||
 | 
			
		||||
		if ( outputs[ name ] === undefined ) {
 | 
			
		||||
 | 
			
		||||
			outputs[ name ] = scriptableValue( value );
 | 
			
		||||
 | 
			
		||||
		} else {
 | 
			
		||||
 | 
			
		||||
			outputs[ name ].value = value;
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return this;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	getOutput( name ) {
 | 
			
		||||
 | 
			
		||||
		return this._outputs[ name ];
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	getParameter( name ) {
 | 
			
		||||
 | 
			
		||||
		return this.parameters[ name ];
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	setParameter( name, value ) {
 | 
			
		||||
 | 
			
		||||
		const parameters = this.parameters;
 | 
			
		||||
 | 
			
		||||
		if ( value && value.isScriptableNode ) {
 | 
			
		||||
 | 
			
		||||
			this.deleteParameter( name );
 | 
			
		||||
 | 
			
		||||
			parameters[ name ] = value;
 | 
			
		||||
			parameters[ name ].getDefaultOutput().events.addEventListener( 'refresh', this.onRefresh );
 | 
			
		||||
 | 
			
		||||
		} else if ( value && value.isScriptableValueNode ) {
 | 
			
		||||
 | 
			
		||||
			this.deleteParameter( name );
 | 
			
		||||
 | 
			
		||||
			parameters[ name ] = value;
 | 
			
		||||
			parameters[ name ].events.addEventListener( 'refresh', this.onRefresh );
 | 
			
		||||
 | 
			
		||||
		} else if ( parameters[ name ] === undefined ) {
 | 
			
		||||
 | 
			
		||||
			parameters[ name ] = scriptableValue( value );
 | 
			
		||||
			parameters[ name ].events.addEventListener( 'refresh', this.onRefresh );
 | 
			
		||||
 | 
			
		||||
		} else {
 | 
			
		||||
 | 
			
		||||
			parameters[ name ].value = value;
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return this;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	getValue() {
 | 
			
		||||
 | 
			
		||||
		return this.getDefaultOutput().getValue();
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	deleteParameter( name ) {
 | 
			
		||||
 | 
			
		||||
		let valueNode = this.parameters[ name ];
 | 
			
		||||
 | 
			
		||||
		if ( valueNode ) {
 | 
			
		||||
 | 
			
		||||
			if ( valueNode.isScriptableNode ) valueNode = valueNode.getDefaultOutput();
 | 
			
		||||
 | 
			
		||||
			valueNode.events.removeEventListener( 'refresh', this.onRefresh );
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return this;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	clearParameters() {
 | 
			
		||||
 | 
			
		||||
		for ( const name of Object.keys( this.parameters ) ) {
 | 
			
		||||
 | 
			
		||||
			this.deleteParameter( name );
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		this.needsUpdate = true;
 | 
			
		||||
 | 
			
		||||
		return this;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	call( name, ...params ) {
 | 
			
		||||
 | 
			
		||||
		const object = this.getObject();
 | 
			
		||||
		const method = object[ name ];
 | 
			
		||||
 | 
			
		||||
		if ( typeof method === 'function' ) {
 | 
			
		||||
 | 
			
		||||
			return method( ...params );
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	async callAsync( name, ...params ) {
 | 
			
		||||
 | 
			
		||||
		const object = this.getObject();
 | 
			
		||||
		const method = object[ name ];
 | 
			
		||||
 | 
			
		||||
		if ( typeof method === 'function' ) {
 | 
			
		||||
 | 
			
		||||
			return method.constructor.name === 'AsyncFunction' ? await method( ...params ) : method( ...params );
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	getNodeType( builder ) {
 | 
			
		||||
 | 
			
		||||
		return this.getDefaultOutputNode().getNodeType( builder );
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	refresh( output = null ) {
 | 
			
		||||
 | 
			
		||||
		if ( output !== null ) {
 | 
			
		||||
 | 
			
		||||
			this.getOutput( output ).refresh();
 | 
			
		||||
 | 
			
		||||
		} else {
 | 
			
		||||
 | 
			
		||||
			this._refresh();
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	getObject() {
 | 
			
		||||
 | 
			
		||||
		if ( this.needsUpdate ) this.dispose();
 | 
			
		||||
		if ( this._object !== null ) return this._object;
 | 
			
		||||
 | 
			
		||||
		//
 | 
			
		||||
 | 
			
		||||
		const refresh = () => this.refresh();
 | 
			
		||||
		const setOutput = ( id, value ) => this.setOutput( id, value );
 | 
			
		||||
 | 
			
		||||
		const parameters = new Parameters( this );
 | 
			
		||||
 | 
			
		||||
		const THREE = global.get( 'THREE' );
 | 
			
		||||
		const TSL = global.get( 'TSL' );
 | 
			
		||||
 | 
			
		||||
		const method = this.getMethod( this.codeNode );
 | 
			
		||||
		const params = [ parameters, this._local, global, refresh, setOutput, THREE, TSL ];
 | 
			
		||||
 | 
			
		||||
		this._object = method( ...params );
 | 
			
		||||
 | 
			
		||||
		const layout = this._object.layout;
 | 
			
		||||
 | 
			
		||||
		if ( layout ) {
 | 
			
		||||
 | 
			
		||||
			if ( layout.cache === false ) {
 | 
			
		||||
 | 
			
		||||
				this._local.clear();
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// default output
 | 
			
		||||
			this._output.outputType = layout.outputType || null;
 | 
			
		||||
 | 
			
		||||
			if ( Array.isArray( layout.elements ) ) {
 | 
			
		||||
 | 
			
		||||
				for ( const element of layout.elements ) {
 | 
			
		||||
 | 
			
		||||
					const id = element.id || element.name;
 | 
			
		||||
 | 
			
		||||
					if ( element.inputType ) {
 | 
			
		||||
 | 
			
		||||
						if ( this.getParameter( id ) === undefined ) this.setParameter( id, null );
 | 
			
		||||
 | 
			
		||||
						this.getParameter( id ).inputType = element.inputType;
 | 
			
		||||
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					if ( element.outputType ) {
 | 
			
		||||
 | 
			
		||||
						if ( this.getOutput( id ) === undefined ) this.setOutput( id, null );
 | 
			
		||||
 | 
			
		||||
						this.getOutput( id ).outputType = element.outputType;
 | 
			
		||||
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return this._object;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	deserialize( data ) {
 | 
			
		||||
 | 
			
		||||
		super.deserialize( data );
 | 
			
		||||
 | 
			
		||||
		for ( const name in this.parameters ) {
 | 
			
		||||
 | 
			
		||||
			let valueNode = this.parameters[ name ];
 | 
			
		||||
 | 
			
		||||
			if ( valueNode.isScriptableNode ) valueNode = valueNode.getDefaultOutput();
 | 
			
		||||
 | 
			
		||||
			valueNode.events.addEventListener( 'refresh', this.onRefresh );
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	getLayout() {
 | 
			
		||||
 | 
			
		||||
		return this.getObject().layout;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	getDefaultOutputNode() {
 | 
			
		||||
 | 
			
		||||
		const output = this.getDefaultOutput().value;
 | 
			
		||||
 | 
			
		||||
		if ( output && output.isNode ) {
 | 
			
		||||
 | 
			
		||||
			return output;
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return float();
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	getDefaultOutput()	{
 | 
			
		||||
 | 
			
		||||
		return this._exec()._output;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	getMethod() {
 | 
			
		||||
 | 
			
		||||
		if ( this.needsUpdate ) this.dispose();
 | 
			
		||||
		if ( this._method !== null ) return this._method;
 | 
			
		||||
 | 
			
		||||
		//
 | 
			
		||||
 | 
			
		||||
		const parametersProps = [ 'parameters', 'local', 'global', 'refresh', 'setOutput', 'THREE', 'TSL' ];
 | 
			
		||||
		const interfaceProps = [ 'layout', 'init', 'main', 'dispose' ];
 | 
			
		||||
 | 
			
		||||
		const properties = interfaceProps.join( ', ' );
 | 
			
		||||
		const declarations = 'var ' + properties + '; var output = {};\n';
 | 
			
		||||
		const returns = '\nreturn { ...output, ' + properties + ' };';
 | 
			
		||||
 | 
			
		||||
		const code = declarations + this.codeNode.code + returns;
 | 
			
		||||
 | 
			
		||||
		//
 | 
			
		||||
 | 
			
		||||
		this._method = new Function( ...parametersProps, code );
 | 
			
		||||
 | 
			
		||||
		return this._method;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dispose() {
 | 
			
		||||
 | 
			
		||||
		if ( this._method === null ) return;
 | 
			
		||||
 | 
			
		||||
		if ( this._object && typeof this._object.dispose === 'function' ) {
 | 
			
		||||
 | 
			
		||||
			this._object.dispose();
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		this._method = null;
 | 
			
		||||
		this._object = null;
 | 
			
		||||
		this._source = null;
 | 
			
		||||
		this._value = null;
 | 
			
		||||
		this._needsOutputUpdate = true;
 | 
			
		||||
		this._output.value = null;
 | 
			
		||||
		this._outputs = {};
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	setup() {
 | 
			
		||||
 | 
			
		||||
		return this.getDefaultOutputNode();
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	set needsUpdate( value ) {
 | 
			
		||||
 | 
			
		||||
		if ( value === true ) this.dispose();
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	get needsUpdate() {
 | 
			
		||||
 | 
			
		||||
		return this.source !== this._source;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_exec()	{
 | 
			
		||||
 | 
			
		||||
		if ( this.codeNode === null ) return this;
 | 
			
		||||
 | 
			
		||||
		if ( this._needsOutputUpdate === true ) {
 | 
			
		||||
 | 
			
		||||
			this._value = this.call( 'main' );
 | 
			
		||||
 | 
			
		||||
			this._needsOutputUpdate = false;
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		this._output.value = this._value;
 | 
			
		||||
 | 
			
		||||
		return this;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_refresh() {
 | 
			
		||||
 | 
			
		||||
		this.needsUpdate = true;
 | 
			
		||||
 | 
			
		||||
		this._exec();
 | 
			
		||||
 | 
			
		||||
		this._output.refresh();
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default ScriptableNode;
 | 
			
		||||
 | 
			
		||||
export const scriptable = nodeProxy( ScriptableNode );
 | 
			
		||||
 | 
			
		||||
addNodeElement( 'scriptable', scriptable );
 | 
			
		||||
 | 
			
		||||
addNodeClass( 'ScriptableNode', ScriptableNode );
 | 
			
		||||
							
								
								
									
										167
									
								
								dist/electron/static/sdk/three/jsm/nodes/code/ScriptableValueNode.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										167
									
								
								dist/electron/static/sdk/three/jsm/nodes/code/ScriptableValueNode.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,167 @@
 | 
			
		||||
import Node, { addNodeClass } from '../core/Node.js';
 | 
			
		||||
import { arrayBufferToBase64, base64ToArrayBuffer } from '../core/NodeUtils.js';
 | 
			
		||||
import { addNodeElement, nodeProxy, float } from '../shadernode/ShaderNode.js';
 | 
			
		||||
import { EventDispatcher } from 'three';
 | 
			
		||||
 | 
			
		||||
class ScriptableValueNode extends Node {
 | 
			
		||||
 | 
			
		||||
	constructor( value = null ) {
 | 
			
		||||
 | 
			
		||||
		super();
 | 
			
		||||
 | 
			
		||||
		this._value = value;
 | 
			
		||||
		this._cache = null;
 | 
			
		||||
 | 
			
		||||
		this.inputType = null;
 | 
			
		||||
		this.outpuType = null;
 | 
			
		||||
 | 
			
		||||
		this.events = new EventDispatcher();
 | 
			
		||||
 | 
			
		||||
		this.isScriptableValueNode = true;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	get isScriptableOutputNode() {
 | 
			
		||||
 | 
			
		||||
		return this.outputType !== null;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	set value( val ) {
 | 
			
		||||
 | 
			
		||||
		if ( this._value === val ) return;
 | 
			
		||||
 | 
			
		||||
		if ( this._cache && this.inputType === 'URL' && this.value.value instanceof ArrayBuffer ) {
 | 
			
		||||
 | 
			
		||||
			URL.revokeObjectURL( this._cache );
 | 
			
		||||
 | 
			
		||||
			this._cache = null;
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		this._value = val;
 | 
			
		||||
 | 
			
		||||
		this.events.dispatchEvent( { type: 'change' } );
 | 
			
		||||
 | 
			
		||||
		this.refresh();
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	get value() {
 | 
			
		||||
 | 
			
		||||
		return this._value;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	refresh() {
 | 
			
		||||
 | 
			
		||||
		this.events.dispatchEvent( { type: 'refresh' } );
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	getValue() {
 | 
			
		||||
 | 
			
		||||
		const value = this.value;
 | 
			
		||||
 | 
			
		||||
		if ( value && this._cache === null && this.inputType === 'URL' && value.value instanceof ArrayBuffer ) {
 | 
			
		||||
 | 
			
		||||
			this._cache = URL.createObjectURL( new Blob( [ value.value ] ) );
 | 
			
		||||
 | 
			
		||||
		} else if ( value && value.value !== null && value.value !== undefined && (
 | 
			
		||||
			( ( this.inputType === 'URL' || this.inputType === 'String' ) && typeof value.value === 'string' ) ||
 | 
			
		||||
			( this.inputType === 'Number' && typeof value.value === 'number' ) ||
 | 
			
		||||
			( this.inputType === 'Vector2' && value.value.isVector2 ) ||
 | 
			
		||||
			( this.inputType === 'Vector3' && value.value.isVector3 ) ||
 | 
			
		||||
			( this.inputType === 'Vector4' && value.value.isVector4 ) ||
 | 
			
		||||
			( this.inputType === 'Color' && value.value.isColor ) ||
 | 
			
		||||
			( this.inputType === 'Matrix3' && value.value.isMatrix3 ) ||
 | 
			
		||||
			( this.inputType === 'Matrix4' && value.value.isMatrix4 )
 | 
			
		||||
		) ) {
 | 
			
		||||
 | 
			
		||||
			return value.value;
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return this._cache || value;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	getNodeType( builder ) {
 | 
			
		||||
 | 
			
		||||
		return this.value && this.value.isNode ? this.value.getNodeType( builder ) : 'float';
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	setup() {
 | 
			
		||||
 | 
			
		||||
		return this.value && this.value.isNode ? this.value : float();
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	serialize( data ) {
 | 
			
		||||
 | 
			
		||||
		super.serialize( data );
 | 
			
		||||
 | 
			
		||||
		if ( this.value !== null ) {
 | 
			
		||||
 | 
			
		||||
			if ( this.inputType === 'ArrayBuffer' ) {
 | 
			
		||||
 | 
			
		||||
				data.value = arrayBufferToBase64( this.value );
 | 
			
		||||
 | 
			
		||||
			} else {
 | 
			
		||||
 | 
			
		||||
				data.value = this.value ? this.value.toJSON( data.meta ).uuid : null;
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		} else {
 | 
			
		||||
 | 
			
		||||
			data.value = null;
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		data.inputType = this.inputType;
 | 
			
		||||
		data.outputType = this.outputType;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	deserialize( data ) {
 | 
			
		||||
 | 
			
		||||
		super.deserialize( data );
 | 
			
		||||
 | 
			
		||||
		let value = null;
 | 
			
		||||
 | 
			
		||||
		if ( data.value !== null ) {
 | 
			
		||||
 | 
			
		||||
			if ( data.inputType === 'ArrayBuffer' ) {
 | 
			
		||||
 | 
			
		||||
				value = base64ToArrayBuffer( data.value );
 | 
			
		||||
 | 
			
		||||
			} else if ( data.inputType === 'Texture' ) {
 | 
			
		||||
 | 
			
		||||
				value = data.meta.textures[ data.value ];
 | 
			
		||||
 | 
			
		||||
			} else {
 | 
			
		||||
 | 
			
		||||
				value = data.meta.nodes[ data.value ] || null;
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		this.value = value;
 | 
			
		||||
 | 
			
		||||
		this.inputType = data.inputType;
 | 
			
		||||
		this.outputType = data.outputType;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default ScriptableValueNode;
 | 
			
		||||
 | 
			
		||||
export const scriptableValue = nodeProxy( ScriptableValueNode );
 | 
			
		||||
 | 
			
		||||
addNodeElement( 'scriptableValue', scriptableValue );
 | 
			
		||||
 | 
			
		||||
addNodeClass( 'ScriptableValueNode', ScriptableValueNode );
 | 
			
		||||
		Reference in New Issue
	
	Block a user