489 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			489 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 
								 | 
							
								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 );
							 |