📄 TSLCore.js
¶
📊 Analysis Summary¶
Metric | Count |
---|---|
🔧 Functions | 53 |
🧱 Classes | 3 |
📦 Imports | 11 |
📊 Variables & Constants | 61 |
📚 Table of Contents¶
🛠️ File Location:¶
📂 src/nodes/tsl/TSLCore.js
📦 Imports¶
Name | Source |
---|---|
Node |
../core/Node.js |
ArrayElementNode |
../utils/ArrayElementNode.js |
ConvertNode |
../utils/ConvertNode.js |
JoinNode |
../utils/JoinNode.js |
SplitNode |
../utils/SplitNode.js |
SetNode |
../utils/SetNode.js |
FlipNode |
../utils/FlipNode.js |
ConstNode |
../core/ConstNode.js |
MemberNode |
../utils/MemberNode.js |
getValueFromType |
../core/NodeUtils.js |
getValueType |
../core/NodeUtils.js |
Variables & Constants¶
Name | Type | Kind | Value | Exported |
---|---|---|---|---|
currentStack |
any |
let/var | null |
✗ |
NodeElements |
Map<any, any> |
let/var | new Map() |
✗ |
shaderNodeHandler |
{ setup(NodeClosure: any, params: any... |
let/var | { setup( NodeClosure, params ) { const inputs = params.shift(); return NodeCl... |
✗ |
nodeObjectsCacheMap |
WeakMap<WeakKey, any> |
let/var | new WeakMap() |
✗ |
nodeBuilderFunctionsCacheMap |
WeakMap<WeakKey, any> |
let/var | new WeakMap() |
✗ |
len |
any |
let/var | array.length |
✗ |
fn |
any |
let/var | *not shown* |
✗ |
name |
any |
let/var | scope |
✗ |
minParams |
any |
let/var | *not shown* |
✗ |
maxParams |
any |
let/var | *not shown* |
✗ |
tslName |
any |
let/var | *not shown* |
✗ |
subBuild |
any |
let/var | builder.getClosestSubBuild( shaderNode.subBuilds ) \|\| '' |
✗ |
subBuildProperty |
any |
let/var | subBuild \|\| 'default' |
✗ |
previousSubBuildFn |
any |
let/var | builder.subBuildFn |
✗ |
result |
any |
let/var | null |
✗ |
inputs |
any |
let/var | inputNodes |
✗ |
index |
number |
let/var | 0 |
✗ |
value |
any |
let/var | *not shown* |
✗ |
value |
any |
let/var | *not shown* |
✗ |
secureNodeBuilder |
any |
let/var | new Proxy( builder, { get: ( target, property, receiver ) => { let value; if ... |
✗ |
jsFunc |
any |
let/var | shaderNode.jsFunc |
✗ |
outputNode |
any |
let/var | inputs !== null \|\| jsFunc.length > 1 ? jsFunc( inputs \|\| [], secureNodeBu... |
✗ |
result |
any |
let/var | null |
✗ |
bools |
boolean[] |
let/var | [ false, true ] |
✗ |
uints |
number[] |
let/var | [ 0, 1, 2, 3 ] |
✗ |
ints |
number[] |
let/var | [ - 1, - 2 ] |
✗ |
floats |
number[] |
let/var | [ 0.5, 1.5, 1 / 3, 1e-6, 1e6, Math.PI, Math.PI * 2, 1 / Math.PI, 2 / Math.PI,... |
✗ |
boolsCacheMap |
Map<any, any> |
let/var | new Map() |
✗ |
uintsCacheMap |
Map<any, any> |
let/var | new Map() |
✗ |
intsCacheMap |
Map<any, any> |
let/var | new Map( [ ...uintsCacheMap ].map( el => new ConstNode( el.value, 'int' ) ) ) |
✗ |
floatsCacheMap |
Map<any, any> |
let/var | new Map( [ ...intsCacheMap ].map( el => new ConstNode( el.value ) ) ) |
✗ |
cacheMaps |
{ bool: Map<any, any>; uint: Map<any,... |
let/var | { bool: boolsCacheMap, uint: uintsCacheMap, ints: intsCacheMap, float: floats... |
✗ |
constNodesCacheMap |
Map<any, any> |
let/var | new Map( [ ...boolsCacheMap, ...floatsCacheMap ] ) |
✗ |
paramType |
"string" \| "number" \| "bigint" \| "... |
let/var | typeof param |
✗ |
fnId |
number |
let/var | 0 |
✗ |
nodeType |
any |
let/var | null |
✗ |
nodeType |
any |
let/var | this.shaderNode.nodeType |
✗ |
fullLayout |
{ name: string; type: any; inputs: an... |
let/var | { name: 'fn' + fnId ++, type: nodeType, inputs: [] } |
✗ |
inputs |
any |
let/var | *not shown* |
✗ |
isArrayAsParameter |
any |
let/var | params[ 0 ] && ( params[ 0 ].isNode \|\| Object.getPrototypeOf( params[ 0 ] )... |
✗ |
instance |
FnNode |
let/var | new FnNode( jsFunc, layout ) |
✗ |
color |
any |
let/var | new ConvertType( 'color' ) |
✓ |
float |
any |
let/var | new ConvertType( 'float', cacheMaps.float ) |
✓ |
int |
any |
let/var | new ConvertType( 'int', cacheMaps.ints ) |
✓ |
uint |
any |
let/var | new ConvertType( 'uint', cacheMaps.uint ) |
✓ |
bool |
any |
let/var | new ConvertType( 'bool', cacheMaps.bool ) |
✓ |
vec2 |
any |
let/var | new ConvertType( 'vec2' ) |
✓ |
ivec2 |
any |
let/var | new ConvertType( 'ivec2' ) |
✓ |
uvec2 |
any |
let/var | new ConvertType( 'uvec2' ) |
✓ |
bvec2 |
any |
let/var | new ConvertType( 'bvec2' ) |
✓ |
vec3 |
any |
let/var | new ConvertType( 'vec3' ) |
✓ |
ivec3 |
any |
let/var | new ConvertType( 'ivec3' ) |
✓ |
uvec3 |
any |
let/var | new ConvertType( 'uvec3' ) |
✓ |
bvec3 |
any |
let/var | new ConvertType( 'bvec3' ) |
✓ |
vec4 |
any |
let/var | new ConvertType( 'vec4' ) |
✓ |
ivec4 |
any |
let/var | new ConvertType( 'ivec4' ) |
✓ |
uvec4 |
any |
let/var | new ConvertType( 'uvec4' ) |
✓ |
bvec4 |
any |
let/var | new ConvertType( 'bvec4' ) |
✓ |
mat2 |
any |
let/var | new ConvertType( 'mat2' ) |
✓ |
mat3 |
any |
let/var | new ConvertType( 'mat3' ) |
✓ |
mat4 |
any |
let/var | new ConvertType( 'mat4' ) |
✓ |
Functions¶
addMethodChaining(name: any, nodeElement: any): void
¶
Parameters:
name
any
nodeElement
any
Returns: void
Calls:
NodeElements.has
console.warn
NodeElements.set
Code
export function addMethodChaining( name, nodeElement ) {
if ( NodeElements.has( name ) ) {
console.warn( `THREE.TSL: Redefinition of method chaining '${ name }'.` );
return;
}
if ( typeof nodeElement !== 'function' ) throw new Error( `THREE.TSL: Node element ${ name } is not a function` );
NodeElements.set( name, nodeElement );
}
parseSwizzle(props: any): any
¶
Parameters:
props
any
Returns: any
Calls:
props.replace( /r|s/g, 'x' ).replace( /g|t/g, 'y' ).replace( /b|p/g, 'z' ).replace
Code
parseSwizzleAndSort(props: any): any
¶
Parameters:
props
any
Returns: any
Calls:
parseSwizzle( props ).split( '' ).sort().join
ShaderNodeObject(obj: any, altType: any): any
¶
Parameters:
obj
any
altType
any
Returns: any
Calls:
getValueType (from ../core/NodeUtils.js)
nodeObjectsCacheMap.get
nodeObjectsCacheMap.set
nodeObject
getConstNode
Fn
Code
function ( obj, altType = null ) {
const type = getValueType( obj );
if ( type === 'node' ) {
let nodeObject = nodeObjectsCacheMap.get( obj );
if ( nodeObject === undefined ) {
nodeObject = new Proxy( obj, shaderNodeHandler );
nodeObjectsCacheMap.set( obj, nodeObject );
nodeObjectsCacheMap.set( nodeObject, nodeObject );
}
return nodeObject;
} else if ( ( altType === null && ( type === 'float' || type === 'boolean' ) ) || ( type && type !== 'shader' && type !== 'string' ) ) {
return nodeObject( getConstNode( obj, altType ) );
} else if ( type === 'shader' ) {
return obj.isFn ? obj : Fn( obj );
}
return obj;
}
ShaderNodeObjects(objects: any, altType: any): any
¶
Parameters:
objects
any
altType
any
Returns: any
Calls:
nodeObject
Code
ShaderNodeArray(array: any, altType: any): any
¶
Parameters:
array
any
altType
any
Returns: any
Calls:
nodeObject
Code
ShaderNodeProxy(NodeClass: any, scope: any, factor: any, settings: any): (...params: any[]) => any
¶
Parameters:
NodeClass
any
scope
any
factor
any
settings
any
Returns: (...params: any[]) => any
Calls:
nodeObject
Object.assign
node.toVarIntent
/[a-z]/i.test
console.error
params.concat
new Array( minParams - params.length ).fill
params.slice
assignNode
nodeArray
verifyParamsLimit
Code
function ( NodeClass, scope = null, factor = null, settings = null ) {
function assignNode( node ) {
if ( settings !== null ) {
node = nodeObject( Object.assign( node, settings ) );
if ( settings.intent === true ) {
node = node.toVarIntent();
}
} else {
node = nodeObject( node );
}
return node;
}
let fn, name = scope, minParams, maxParams;
function verifyParamsLimit( params ) {
let tslName;
if ( name ) tslName = /[a-z]/i.test( name ) ? name + '()' : name;
else tslName = NodeClass.type;
if ( minParams !== undefined && params.length < minParams ) {
console.error( `THREE.TSL: "${ tslName }" parameter length is less than minimum required.` );
return params.concat( new Array( minParams - params.length ).fill( 0 ) );
} else if ( maxParams !== undefined && params.length > maxParams ) {
console.error( `THREE.TSL: "${ tslName }" parameter length exceeds limit.` );
return params.slice( 0, maxParams );
}
return params;
}
if ( scope === null ) {
fn = ( ...params ) => {
return assignNode( new NodeClass( ...nodeArray( verifyParamsLimit( params ) ) ) );
};
} else if ( factor !== null ) {
factor = nodeObject( factor );
fn = ( ...params ) => {
return assignNode( new NodeClass( scope, ...nodeArray( verifyParamsLimit( params ) ), factor ) );
};
} else {
fn = ( ...params ) => {
return assignNode( new NodeClass( scope, ...nodeArray( verifyParamsLimit( params ) ) ) );
};
}
fn.setParameterLength = ( ...params ) => {
if ( params.length === 1 ) minParams = maxParams = params[ 0 ];
else if ( params.length === 2 ) [ minParams, maxParams ] = params;
return fn;
};
fn.setName = ( value ) => {
name = value;
return fn;
};
return fn;
}
assignNode(node: any): any
¶
Parameters:
node
any
Returns: any
Calls:
nodeObject
Object.assign
node.toVarIntent
Code
verifyParamsLimit(params: any): any
¶
Parameters:
params
any
Returns: any
Calls:
/[a-z]/i.test
console.error
params.concat
new Array( minParams - params.length ).fill
params.slice
Code
function verifyParamsLimit( params ) {
let tslName;
if ( name ) tslName = /[a-z]/i.test( name ) ? name + '()' : name;
else tslName = NodeClass.type;
if ( minParams !== undefined && params.length < minParams ) {
console.error( `THREE.TSL: "${ tslName }" parameter length is less than minimum required.` );
return params.concat( new Array( minParams - params.length ).fill( 0 ) );
} else if ( maxParams !== undefined && params.length > maxParams ) {
console.error( `THREE.TSL: "${ tslName }" parameter length exceeds limit.` );
return params.slice( 0, maxParams );
}
return params;
}
ShaderNodeImmutable(NodeClass: any, params: any[]): any
¶
Parameters:
NodeClass
any
params
any[]
Returns: any
Calls:
nodeObject
nodeArray
Code
ShaderCallNodeInternal.getNodeType(builder: any): any
¶
Parameters:
builder
any
Returns: any
Calls:
this.getOutputNode( builder ).getNodeType
Code
ShaderCallNodeInternal.getMemberType(builder: any, name: any): any
¶
Parameters:
builder
any
name
any
Returns: any
Calls:
this.getOutputNode( builder ).getMemberType
Code
ShaderCallNodeInternal.call(builder: any): any
¶
Parameters:
builder
any
Returns: any
Calls:
builder.getNodeProperties
builder.getClosestSubBuild
nodeBuilderFunctionsCacheMap.get
nodeBuilderFunctionsCacheMap.set
functionNodesCacheMap.get
nodeObject
builder.buildFunctionNode
functionNodesCacheMap.set
builder.addInclude
functionNode.call
Array.isArray
Reflect.get
jsFunc
Internal Comments:
// (x2)
// If inputs is an array, we need to convert it to a Proxy (x2)
// so we can call TSL functions using the syntax `Fn( ( { r, g, b } ) => { ... } )` (x2)
// and call through `fn( 0, 1, 0 )` or `fn( { r: 0, g: 1, b: 0 } )` (x2)
Code
call( builder ) {
const { shaderNode, inputNodes } = this;
const properties = builder.getNodeProperties( shaderNode );
const subBuild = builder.getClosestSubBuild( shaderNode.subBuilds ) || '';
const subBuildProperty = subBuild || 'default';
if ( properties[ subBuildProperty ] ) {
return properties[ subBuildProperty ];
}
//
const previousSubBuildFn = builder.subBuildFn;
builder.subBuildFn = subBuild;
let result = null;
if ( shaderNode.layout ) {
let functionNodesCacheMap = nodeBuilderFunctionsCacheMap.get( builder.constructor );
if ( functionNodesCacheMap === undefined ) {
functionNodesCacheMap = new WeakMap();
nodeBuilderFunctionsCacheMap.set( builder.constructor, functionNodesCacheMap );
}
let functionNode = functionNodesCacheMap.get( shaderNode );
if ( functionNode === undefined ) {
functionNode = nodeObject( builder.buildFunctionNode( shaderNode ) );
functionNodesCacheMap.set( shaderNode, functionNode );
}
builder.addInclude( functionNode );
result = nodeObject( functionNode.call( inputNodes ) );
} else {
let inputs = inputNodes;
if ( Array.isArray( inputs ) ) {
// If inputs is an array, we need to convert it to a Proxy
// so we can call TSL functions using the syntax `Fn( ( { r, g, b } ) => { ... } )`
// and call through `fn( 0, 1, 0 )` or `fn( { r: 0, g: 1, b: 0 } )`
let index = 0;
inputs = new Proxy( inputs, {
get: ( target, property, receiver ) => {
let value;
if ( target[ property ] === undefined ) {
value = target[ index ++ ];
} else {
value = Reflect.get( target, property, receiver );
}
return value;
}
} );
}
const secureNodeBuilder = new Proxy( builder, {
get: ( target, property, receiver ) => {
let value;
if ( Symbol.iterator === property ) {
value = function* () {
yield undefined;
};
} else {
value = Reflect.get( target, property, receiver );
}
return value;
}
} );
const jsFunc = shaderNode.jsFunc;
const outputNode = inputs !== null || jsFunc.length > 1 ? jsFunc( inputs || [], secureNodeBuilder ) : jsFunc( secureNodeBuilder );
result = nodeObject( outputNode );
}
builder.subBuildFn = previousSubBuildFn;
if ( shaderNode.once ) {
properties[ subBuildProperty ] = result;
}
return result;
}
ShaderCallNodeInternal.setupOutput(builder: any): any
¶
Parameters:
builder
any
Returns: any
Calls:
builder.addStack
this.call
builder.removeStack
Code
ShaderCallNodeInternal.getOutputNode(builder: any): any
¶
Parameters:
builder
any
Returns: any
Calls:
builder.getNodeProperties
builder.getSubBuildOutput
this.setupOutput
builder.getClosestSubBuild
Code
getOutputNode( builder ) {
const properties = builder.getNodeProperties( this );
const subBuildOutput = builder.getSubBuildOutput( this );
properties[ subBuildOutput ] = properties[ subBuildOutput ] || this.setupOutput( builder );
properties[ subBuildOutput ].subBuild = builder.getClosestSubBuild( this );
return properties[ subBuildOutput ];
}
ShaderCallNodeInternal.build(builder: any, output: any): any
¶
Parameters:
builder
any
output
any
Returns: any
Calls:
builder.getBuildStage
builder.getNodeProperties
builder.getSubBuildOutput
this.getOutputNode
builder.getSubBuildProperty
properties[ subBuildOutput ].build
builder.getDataFromNode
nodeData.subBuilds.add
outputNode.build
Internal Comments:
// If the shaderNode has subBuilds, add them to the chaining nodes
// so they can be built later in the build process.
Code
build( builder, output = null ) {
let result = null;
const buildStage = builder.getBuildStage();
const properties = builder.getNodeProperties( this );
const subBuildOutput = builder.getSubBuildOutput( this );
const outputNode = this.getOutputNode( builder );
if ( buildStage === 'setup' ) {
const subBuildInitialized = builder.getSubBuildProperty( 'initialized', this );
if ( properties[ subBuildInitialized ] !== true ) {
properties[ subBuildInitialized ] = true;
properties[ subBuildOutput ] = this.getOutputNode( builder );
properties[ subBuildOutput ].build( builder );
// If the shaderNode has subBuilds, add them to the chaining nodes
// so they can be built later in the build process.
if ( this.shaderNode.subBuilds ) {
for ( const node of builder.chaining ) {
const nodeData = builder.getDataFromNode( node, 'any' );
nodeData.subBuilds = nodeData.subBuilds || new Set();
for ( const subBuild of this.shaderNode.subBuilds ) {
nodeData.subBuilds.add( subBuild );
}
//builder.getDataFromNode( node ).subBuilds = nodeData.subBuilds;
}
}
}
result = properties[ subBuildOutput ];
} else if ( buildStage === 'analyze' ) {
outputNode.build( builder, output );
} else if ( buildStage === 'generate' ) {
result = outputNode.build( builder, output ) || '';
}
return result;
}
get(target: any[], property: string | symbol, receiver: any): any
¶
Parameters:
target
any[]
property
string | symbol
receiver
any
Returns: any
Calls:
Reflect.get
Code
get(target: any[], property: string | symbol, receiver: any): any
¶
Parameters:
target
any[]
property
string | symbol
receiver
any
Returns: any
Calls:
Reflect.get
Code
get(target: any, property: string | symbol, receiver: any): any
¶
Parameters:
target
any
property
string | symbol
receiver
any
Returns: any
Calls:
Reflect.get
Code
get(target: any, property: string | symbol, receiver: any): any
¶
Parameters:
target
any
property
string | symbol
receiver
any
Returns: any
Calls:
Reflect.get
Code
get(target: any, property: string | symbol, receiver: any): any
¶
Parameters:
target
any
property
string | symbol
receiver
any
Returns: any
Calls:
Reflect.get
Code
get(target: any, property: string | symbol, receiver: any): any
¶
Parameters:
target
any
property
string | symbol
receiver
any
Returns: any
Calls:
Reflect.get
Code
ShaderNodeInternal.setLayout(layout: any): this
¶
Parameters:
layout
any
Returns: this
ShaderNodeInternal.call(inputs: any): any
¶
Parameters:
inputs
any
Returns: any
Calls:
nodeObjects
nodeObject
Code
ShaderNodeInternal.setup(): any
¶
Returns: any
Calls:
this.call
getConstNode(value: any, type: any): any
¶
Parameters:
value
any
type
any
Returns: any
Calls:
constNodesCacheMap.has
constNodesCacheMap.get
Code
ConvertType(type: any, cacheMap: any): (...params: any[]) => any
¶
Parameters:
type
any
cacheMap
any
Returns: (...params: any[]) => any
Calls:
console.error
nodeObject
[ 'bool', 'float', 'int', 'uint' ].includes
params.every
getValueFromType (from ../core/NodeUtils.js)
cacheMap.has
nodeObjectIntent
cacheMap.get
getConstNode
params.map
Code
function ( type, cacheMap = null ) {
return ( ...params ) => {
for ( const param of params ) {
if ( param === undefined ) {
console.error( `THREE.TSL: Invalid parameter for the type "${ type }".` );
return nodeObject( new ConstNode( 0, type ) );
}
}
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 ) ];
}
if ( params.length === 1 && cacheMap !== null && cacheMap.has( params[ 0 ] ) ) {
return nodeObjectIntent( cacheMap.get( params[ 0 ] ) );
}
if ( params.length === 1 ) {
const node = getConstNode( params[ 0 ], type );
if ( node.nodeType === type ) return nodeObjectIntent( node );
return nodeObjectIntent( new ConvertNode( node, type ) );
}
const nodes = params.map( param => getConstNode( param ) );
return nodeObjectIntent( new JoinNode( nodes, type ) );
};
}
defined(v: any): any
¶
Parameters:
v
any
Returns: any
getConstNodeType(value: any): any
¶
Parameters:
value
any
Returns: any
Code
ShaderNode(jsFunc: any, nodeType: any): any
¶
Parameters:
jsFunc
any
nodeType
any
Returns: any
Code
nodeObject(val: any, altType: any): any
¶
Parameters:
val
any
altType
any
Returns: any
Calls:
ShaderNodeObject
nodeObjectIntent(val: any, altType: any): any
¶
Parameters:
val
any
altType
any
Returns: any
Calls:
nodeObject( val, altType ).toVarIntent
nodeObjects(val: any, altType: any): any
¶
Parameters:
val
any
altType
any
Returns: any
nodeArray(val: any, altType: any): any
¶
Parameters:
val
any
altType
any
Returns: any
nodeProxy(NodeClass: any, scope: any, factor: any, settings: any): any
¶
Parameters:
NodeClass
any
scope
any
factor
any
settings
any
Returns: any
Code
nodeImmutable(NodeClass: any, params: any[]): any
¶
Parameters:
NodeClass
any
params
any[]
Returns: any
nodeProxyIntent(NodeClass: any, scope: any, factor: any, settings: {}): any
¶
Parameters:
NodeClass
any
scope
any
factor
any
settings
{}
Returns: any
Code
FnNode.setLayout(layout: any): this
¶
Parameters:
layout
any
Returns: this
Calls:
fullLayout.inputs.push
this.shaderNode.setLayout
Code
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 = fullLayout;
}
this.shaderNode.setLayout( layout );
return this;
}
FnNode.getNodeType(builder: any): any
¶
Parameters:
builder
any
Returns: any
Calls:
this.shaderNode.getNodeType
FnNode.call(params: any[]): any
¶
Parameters:
params
any[]
Returns: any
Calls:
nodeObjects
Object.getPrototypeOf
this.shaderNode.call
fnCall.toStack
fnCall.toVarIntent
Code
call( ...params ) {
let inputs;
nodeObjects( params );
const isArrayAsParameter = params[ 0 ] && ( params[ 0 ].isNode || Object.getPrototypeOf( params[ 0 ] ) !== Object.prototype );
if ( isArrayAsParameter ) {
inputs = [ ...params ];
} else {
inputs = params[ 0 ];
}
const fnCall = this.shaderNode.call( inputs );
if ( this.shaderNode.nodeType === 'void' ) fnCall.toStack();
return fnCall.toVarIntent();
}
FnNode.once(subBuilds: any): this
¶
Parameters:
subBuilds
any
Returns: this
Code
FnNode.generate(builder: any): any
¶
Parameters:
builder
any
Returns: any
Calls:
this.getNodeType
console.error
builder.generateConst
Code
Fn(jsFunc: any, layout: any): () => void
¶
Parameters:
jsFunc
any
layout
any
Returns: () => void
Calls:
instance.call
Reflect.get
Reflect.set
Code
export function Fn( jsFunc, layout = null ) {
const instance = new FnNode( jsFunc, layout );
return new Proxy( () => {}, {
apply( target, thisArg, params ) {
return instance.call( ...params );
},
get( target, prop, receiver ) {
return Reflect.get( instance, prop, receiver );
},
set( target, prop, value, receiver ) {
return Reflect.set( instance, prop, value, receiver );
}
} );
}
setCurrentStack(stack: any): void
¶
Parameters:
stack
any
Returns: void
Code
getCurrentStack(): any
¶
Returns: any
If(params: any[]): StackNode
¶
Parameters:
params
any[]
Returns: StackNode
Calls:
currentStack.If
Switch(params: any[]): StackNode
¶
Parameters:
params
any[]
Returns: StackNode
Calls:
currentStack.Switch
Stack(node: Node): Node
¶
JSDoc:
/**
* Add the given node to the current stack.
*
* @param {Node} node - The node to add.
* @returns {Node} The node that was added to the stack.
*/
Parameters:
node
Node
Returns: Node
Calls:
currentStack.add
string(value: string): any
¶
Parameters:
value
string
Returns: any
Calls:
nodeObject
arrayBuffer(value: any): any
¶
Parameters:
value
any
Returns: any
Calls:
nodeObject
convert(node: any, types: any): any
¶
Parameters:
node
any
types
any
Returns: any
Calls:
nodeObject
split(node: any, channels: any): any
¶
Parameters:
node
any
channels
any
Returns: any
Calls:
nodeObject
append(node: Node): Function
¶
Parameters:
node
Node
Returns: Function
Calls:
console.warn
Stack
Code
Classes¶
ShaderCallNodeInternal
¶
Class Code
class ShaderCallNodeInternal extends Node {
constructor( shaderNode, inputNodes ) {
super();
this.shaderNode = shaderNode;
this.inputNodes = inputNodes;
this.isShaderCallNodeInternal = true;
}
getNodeType( builder ) {
return this.shaderNode.nodeType || this.getOutputNode( builder ).getNodeType( builder );
}
getMemberType( builder, name ) {
return this.getOutputNode( builder ).getMemberType( builder, name );
}
call( builder ) {
const { shaderNode, inputNodes } = this;
const properties = builder.getNodeProperties( shaderNode );
const subBuild = builder.getClosestSubBuild( shaderNode.subBuilds ) || '';
const subBuildProperty = subBuild || 'default';
if ( properties[ subBuildProperty ] ) {
return properties[ subBuildProperty ];
}
//
const previousSubBuildFn = builder.subBuildFn;
builder.subBuildFn = subBuild;
let result = null;
if ( shaderNode.layout ) {
let functionNodesCacheMap = nodeBuilderFunctionsCacheMap.get( builder.constructor );
if ( functionNodesCacheMap === undefined ) {
functionNodesCacheMap = new WeakMap();
nodeBuilderFunctionsCacheMap.set( builder.constructor, functionNodesCacheMap );
}
let functionNode = functionNodesCacheMap.get( shaderNode );
if ( functionNode === undefined ) {
functionNode = nodeObject( builder.buildFunctionNode( shaderNode ) );
functionNodesCacheMap.set( shaderNode, functionNode );
}
builder.addInclude( functionNode );
result = nodeObject( functionNode.call( inputNodes ) );
} else {
let inputs = inputNodes;
if ( Array.isArray( inputs ) ) {
// If inputs is an array, we need to convert it to a Proxy
// so we can call TSL functions using the syntax `Fn( ( { r, g, b } ) => { ... } )`
// and call through `fn( 0, 1, 0 )` or `fn( { r: 0, g: 1, b: 0 } )`
let index = 0;
inputs = new Proxy( inputs, {
get: ( target, property, receiver ) => {
let value;
if ( target[ property ] === undefined ) {
value = target[ index ++ ];
} else {
value = Reflect.get( target, property, receiver );
}
return value;
}
} );
}
const secureNodeBuilder = new Proxy( builder, {
get: ( target, property, receiver ) => {
let value;
if ( Symbol.iterator === property ) {
value = function* () {
yield undefined;
};
} else {
value = Reflect.get( target, property, receiver );
}
return value;
}
} );
const jsFunc = shaderNode.jsFunc;
const outputNode = inputs !== null || jsFunc.length > 1 ? jsFunc( inputs || [], secureNodeBuilder ) : jsFunc( secureNodeBuilder );
result = nodeObject( outputNode );
}
builder.subBuildFn = previousSubBuildFn;
if ( shaderNode.once ) {
properties[ subBuildProperty ] = result;
}
return result;
}
setupOutput( builder ) {
builder.addStack();
builder.stack.outputNode = this.call( builder );
return builder.removeStack();
}
getOutputNode( builder ) {
const properties = builder.getNodeProperties( this );
const subBuildOutput = builder.getSubBuildOutput( this );
properties[ subBuildOutput ] = properties[ subBuildOutput ] || this.setupOutput( builder );
properties[ subBuildOutput ].subBuild = builder.getClosestSubBuild( this );
return properties[ subBuildOutput ];
}
build( builder, output = null ) {
let result = null;
const buildStage = builder.getBuildStage();
const properties = builder.getNodeProperties( this );
const subBuildOutput = builder.getSubBuildOutput( this );
const outputNode = this.getOutputNode( builder );
if ( buildStage === 'setup' ) {
const subBuildInitialized = builder.getSubBuildProperty( 'initialized', this );
if ( properties[ subBuildInitialized ] !== true ) {
properties[ subBuildInitialized ] = true;
properties[ subBuildOutput ] = this.getOutputNode( builder );
properties[ subBuildOutput ].build( builder );
// If the shaderNode has subBuilds, add them to the chaining nodes
// so they can be built later in the build process.
if ( this.shaderNode.subBuilds ) {
for ( const node of builder.chaining ) {
const nodeData = builder.getDataFromNode( node, 'any' );
nodeData.subBuilds = nodeData.subBuilds || new Set();
for ( const subBuild of this.shaderNode.subBuilds ) {
nodeData.subBuilds.add( subBuild );
}
//builder.getDataFromNode( node ).subBuilds = nodeData.subBuilds;
}
}
}
result = properties[ subBuildOutput ];
} else if ( buildStage === 'analyze' ) {
outputNode.build( builder, output );
} else if ( buildStage === 'generate' ) {
result = outputNode.build( builder, output ) || '';
}
return result;
}
}
Methods¶
getNodeType(builder: any): any
¶
Code
getMemberType(builder: any, name: any): any
¶
Code
call(builder: any): any
¶
Code
call( builder ) {
const { shaderNode, inputNodes } = this;
const properties = builder.getNodeProperties( shaderNode );
const subBuild = builder.getClosestSubBuild( shaderNode.subBuilds ) || '';
const subBuildProperty = subBuild || 'default';
if ( properties[ subBuildProperty ] ) {
return properties[ subBuildProperty ];
}
//
const previousSubBuildFn = builder.subBuildFn;
builder.subBuildFn = subBuild;
let result = null;
if ( shaderNode.layout ) {
let functionNodesCacheMap = nodeBuilderFunctionsCacheMap.get( builder.constructor );
if ( functionNodesCacheMap === undefined ) {
functionNodesCacheMap = new WeakMap();
nodeBuilderFunctionsCacheMap.set( builder.constructor, functionNodesCacheMap );
}
let functionNode = functionNodesCacheMap.get( shaderNode );
if ( functionNode === undefined ) {
functionNode = nodeObject( builder.buildFunctionNode( shaderNode ) );
functionNodesCacheMap.set( shaderNode, functionNode );
}
builder.addInclude( functionNode );
result = nodeObject( functionNode.call( inputNodes ) );
} else {
let inputs = inputNodes;
if ( Array.isArray( inputs ) ) {
// If inputs is an array, we need to convert it to a Proxy
// so we can call TSL functions using the syntax `Fn( ( { r, g, b } ) => { ... } )`
// and call through `fn( 0, 1, 0 )` or `fn( { r: 0, g: 1, b: 0 } )`
let index = 0;
inputs = new Proxy( inputs, {
get: ( target, property, receiver ) => {
let value;
if ( target[ property ] === undefined ) {
value = target[ index ++ ];
} else {
value = Reflect.get( target, property, receiver );
}
return value;
}
} );
}
const secureNodeBuilder = new Proxy( builder, {
get: ( target, property, receiver ) => {
let value;
if ( Symbol.iterator === property ) {
value = function* () {
yield undefined;
};
} else {
value = Reflect.get( target, property, receiver );
}
return value;
}
} );
const jsFunc = shaderNode.jsFunc;
const outputNode = inputs !== null || jsFunc.length > 1 ? jsFunc( inputs || [], secureNodeBuilder ) : jsFunc( secureNodeBuilder );
result = nodeObject( outputNode );
}
builder.subBuildFn = previousSubBuildFn;
if ( shaderNode.once ) {
properties[ subBuildProperty ] = result;
}
return result;
}
setupOutput(builder: any): any
¶
Code
getOutputNode(builder: any): any
¶
Code
getOutputNode( builder ) {
const properties = builder.getNodeProperties( this );
const subBuildOutput = builder.getSubBuildOutput( this );
properties[ subBuildOutput ] = properties[ subBuildOutput ] || this.setupOutput( builder );
properties[ subBuildOutput ].subBuild = builder.getClosestSubBuild( this );
return properties[ subBuildOutput ];
}
build(builder: any, output: any): any
¶
Code
build( builder, output = null ) {
let result = null;
const buildStage = builder.getBuildStage();
const properties = builder.getNodeProperties( this );
const subBuildOutput = builder.getSubBuildOutput( this );
const outputNode = this.getOutputNode( builder );
if ( buildStage === 'setup' ) {
const subBuildInitialized = builder.getSubBuildProperty( 'initialized', this );
if ( properties[ subBuildInitialized ] !== true ) {
properties[ subBuildInitialized ] = true;
properties[ subBuildOutput ] = this.getOutputNode( builder );
properties[ subBuildOutput ].build( builder );
// If the shaderNode has subBuilds, add them to the chaining nodes
// so they can be built later in the build process.
if ( this.shaderNode.subBuilds ) {
for ( const node of builder.chaining ) {
const nodeData = builder.getDataFromNode( node, 'any' );
nodeData.subBuilds = nodeData.subBuilds || new Set();
for ( const subBuild of this.shaderNode.subBuilds ) {
nodeData.subBuilds.add( subBuild );
}
//builder.getDataFromNode( node ).subBuilds = nodeData.subBuilds;
}
}
}
result = properties[ subBuildOutput ];
} else if ( buildStage === 'analyze' ) {
outputNode.build( builder, output );
} else if ( buildStage === 'generate' ) {
result = outputNode.build( builder, output ) || '';
}
return result;
}
ShaderNodeInternal
¶
Class Code
class ShaderNodeInternal extends Node {
constructor( jsFunc, nodeType ) {
super( nodeType );
this.jsFunc = jsFunc;
this.layout = null;
this.global = true;
this.once = false;
}
setLayout( layout ) {
this.layout = layout;
return this;
}
call( inputs = null ) {
nodeObjects( inputs );
return nodeObject( new ShaderCallNodeInternal( this, inputs ) );
}
setup() {
return this.call();
}
}
Methods¶
setLayout(layout: any): this
¶
call(inputs: any): any
¶
Code
setup(): any
¶
FnNode
¶
Class Code
class FnNode extends Node {
constructor( jsFunc, layout = null ) {
super();
let nodeType = null;
if ( layout !== null ) {
if ( typeof layout === 'object' ) {
nodeType = layout.return;
} else {
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 = fullLayout;
}
this.shaderNode.setLayout( layout );
return this;
}
getNodeType( builder ) {
return this.shaderNode.getNodeType( builder ) || 'float';
}
call( ...params ) {
let inputs;
nodeObjects( params );
const isArrayAsParameter = params[ 0 ] && ( params[ 0 ].isNode || Object.getPrototypeOf( params[ 0 ] ) !== Object.prototype );
if ( isArrayAsParameter ) {
inputs = [ ...params ];
} else {
inputs = params[ 0 ];
}
const fnCall = this.shaderNode.call( inputs );
if ( this.shaderNode.nodeType === 'void' ) fnCall.toStack();
return fnCall.toVarIntent();
}
once( subBuilds = null ) {
this.shaderNode.once = true;
this.shaderNode.subBuilds = subBuilds;
return this;
}
generate( builder ) {
const type = this.getNodeType( builder );
console.error( 'THREE.TSL: "Fn()" was declared but not invoked. Try calling it like "Fn()( ...params )".' );
return builder.generateConst( type );
}
}
Methods¶
setLayout(layout: any): this
¶
Code
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 = fullLayout;
}
this.shaderNode.setLayout( layout );
return this;
}
getNodeType(builder: any): any
¶
call(params: any[]): any
¶
Code
call( ...params ) {
let inputs;
nodeObjects( params );
const isArrayAsParameter = params[ 0 ] && ( params[ 0 ].isNode || Object.getPrototypeOf( params[ 0 ] ) !== Object.prototype );
if ( isArrayAsParameter ) {
inputs = [ ...params ];
} else {
inputs = params[ 0 ];
}
const fnCall = this.shaderNode.call( inputs );
if ( this.shaderNode.nodeType === 'void' ) fnCall.toStack();
return fnCall.toVarIntent();
}