|
|
@@ -611,7 +611,13 @@ const ConvertType = function ( type, cacheMap = null ) {
|
|
|
|
|
|
return ( ...params ) => {
|
|
|
|
|
|
- if ( params.length === 0 || ( ! [ 'bool', 'float', 'int', 'uint' ].includes( type ) && params.every( param => typeof param !== 'object' ) ) ) {
|
|
|
+ if ( params.length === 0 || ( ! [ 'bool', 'float', 'int', 'uint' ].includes( type ) && params.every( param => {
|
|
|
+
|
|
|
+ const paramType = typeof param;
|
|
|
+
|
|
|
+ return paramType !== 'object' && paramType !== 'function';
|
|
|
+
|
|
|
+ } ) ) ) {
|
|
|
|
|
|
params = [ getValueFromType( type, ...params ) ];
|
|
|
|
|
|
@@ -664,37 +670,90 @@ export const nodeProxyIntent = ( NodeClass, scope = null, factor = null, setting
|
|
|
|
|
|
let fnId = 0;
|
|
|
|
|
|
-export const Fn = ( jsFunc, layout = null ) => {
|
|
|
+class FnNode extends Node {
|
|
|
|
|
|
- let nodeType = null;
|
|
|
+ constructor( jsFunc, layout = null ) {
|
|
|
|
|
|
- if ( layout !== null ) {
|
|
|
-
|
|
|
- if ( typeof layout === 'object' ) {
|
|
|
+ super();
|
|
|
|
|
|
- nodeType = layout.return;
|
|
|
+ let nodeType = null;
|
|
|
|
|
|
- } else {
|
|
|
+ if ( layout !== null ) {
|
|
|
|
|
|
- if ( typeof layout === 'string' ) {
|
|
|
+ if ( typeof layout === 'object' ) {
|
|
|
|
|
|
- nodeType = layout;
|
|
|
+ nodeType = layout.return;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
- console.error( 'THREE.TSL: Invalid layout type.' );
|
|
|
+ if ( typeof layout === 'string' ) {
|
|
|
+
|
|
|
+ nodeType = layout;
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ console.error( 'THREE.TSL: Invalid layout type.' );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ layout = null;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ this.shaderNode = new ShaderNode( jsFunc, nodeType );
|
|
|
+
|
|
|
+ if ( layout !== null ) {
|
|
|
+
|
|
|
+ this.setLayout( layout );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ this.isFn = true;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ setLayout( layout ) {
|
|
|
+
|
|
|
+ const nodeType = this.shaderNode.nodeType;
|
|
|
+
|
|
|
+ if ( typeof layout.inputs !== 'object' ) {
|
|
|
+
|
|
|
+ const fullLayout = {
|
|
|
+ name: 'fn' + fnId ++,
|
|
|
+ type: nodeType,
|
|
|
+ inputs: []
|
|
|
+ };
|
|
|
+
|
|
|
+ for ( const name in layout ) {
|
|
|
+
|
|
|
+ if ( name === 'return' ) continue;
|
|
|
+
|
|
|
+ fullLayout.inputs.push( {
|
|
|
+ name: name,
|
|
|
+ type: layout[ name ]
|
|
|
+ } );
|
|
|
|
|
|
}
|
|
|
|
|
|
- layout = null;
|
|
|
+ layout = fullLayout;
|
|
|
|
|
|
}
|
|
|
|
|
|
+ this.shaderNode.setLayout( layout );
|
|
|
+
|
|
|
+ return this;
|
|
|
+
|
|
|
}
|
|
|
|
|
|
- const shaderNode = new ShaderNode( jsFunc, nodeType );
|
|
|
+ getNodeType( builder ) {
|
|
|
+
|
|
|
+ return this.shaderNode.getNodeType( builder ) || 'float';
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
- const fn = ( ...params ) => {
|
|
|
+ call( ...params ) {
|
|
|
|
|
|
let inputs;
|
|
|
|
|
|
@@ -712,71 +771,62 @@ export const Fn = ( jsFunc, layout = null ) => {
|
|
|
|
|
|
}
|
|
|
|
|
|
- const fnCall = shaderNode.call( inputs );
|
|
|
+ const fnCall = this.shaderNode.call( inputs );
|
|
|
|
|
|
- if ( nodeType === 'void' ) fnCall.toStack();
|
|
|
+ if ( this.shaderNode.nodeType === 'void' ) fnCall.toStack();
|
|
|
|
|
|
return fnCall.toVarIntent();
|
|
|
|
|
|
- };
|
|
|
+ }
|
|
|
|
|
|
- fn.shaderNode = shaderNode;
|
|
|
- fn.id = shaderNode.id;
|
|
|
+ once( subBuilds = null ) {
|
|
|
|
|
|
- fn.isFn = true;
|
|
|
+ this.shaderNode.once = true;
|
|
|
+ this.shaderNode.subBuilds = subBuilds;
|
|
|
|
|
|
- fn.getNodeType = ( ...params ) => shaderNode.getNodeType( ...params );
|
|
|
- fn.getCacheKey = ( ...params ) => shaderNode.getCacheKey( ...params );
|
|
|
+ return this;
|
|
|
|
|
|
- fn.setLayout = ( layout ) => {
|
|
|
+ }
|
|
|
|
|
|
- shaderNode.setLayout( layout );
|
|
|
+ generate( builder ) {
|
|
|
|
|
|
- return fn;
|
|
|
+ const type = this.getNodeType( builder );
|
|
|
|
|
|
- };
|
|
|
+ console.warn( 'THREE.TSL: "Fn()" was declared but not invoked. Try calling it like "Fn()( ...params )".' );
|
|
|
|
|
|
- fn.once = ( subBuilds = null ) => {
|
|
|
+ return builder.generateConst( type );
|
|
|
|
|
|
- shaderNode.once = true;
|
|
|
- shaderNode.subBuilds = subBuilds;
|
|
|
+ }
|
|
|
|
|
|
- return fn;
|
|
|
+}
|
|
|
|
|
|
- };
|
|
|
+export function Fn( jsFunc, layout = null ) {
|
|
|
|
|
|
- if ( layout !== null ) {
|
|
|
+ const instance = new FnNode( jsFunc, layout );
|
|
|
|
|
|
- if ( typeof layout.inputs !== 'object' ) {
|
|
|
+ return new Proxy( () => {}, {
|
|
|
|
|
|
- const fullLayout = {
|
|
|
- name: 'fn' + fnId ++,
|
|
|
- type: nodeType,
|
|
|
- inputs: []
|
|
|
- };
|
|
|
+ apply( target, thisArg, params ) {
|
|
|
|
|
|
- for ( const name in layout ) {
|
|
|
+ return instance.call( ...params );
|
|
|
|
|
|
- if ( name === 'return' ) continue;
|
|
|
+ },
|
|
|
|
|
|
- fullLayout.inputs.push( {
|
|
|
- name: name,
|
|
|
- type: layout[ name ]
|
|
|
- } );
|
|
|
+ get( target, prop, receiver ) {
|
|
|
|
|
|
- }
|
|
|
+ return Reflect.get( instance, prop, receiver );
|
|
|
|
|
|
- layout = fullLayout;
|
|
|
+ },
|
|
|
|
|
|
- }
|
|
|
+ set( target, prop, value, receiver ) {
|
|
|
|
|
|
- fn.setLayout( layout );
|
|
|
+ return Reflect.set( instance, prop, value, receiver );
|
|
|
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
- return fn;
|
|
|
+ } );
|
|
|
|
|
|
-};
|
|
|
+}
|
|
|
|
|
|
//
|
|
|
|