629 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			629 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
|  | import Node, { addNodeClass } from '../core/Node.js'; | ||
|  | import ArrayElementNode from '../utils/ArrayElementNode.js'; | ||
|  | import ConvertNode from '../utils/ConvertNode.js'; | ||
|  | import JoinNode from '../utils/JoinNode.js'; | ||
|  | import SplitNode from '../utils/SplitNode.js'; | ||
|  | import SetNode from '../utils/SetNode.js'; | ||
|  | import ConstNode from '../core/ConstNode.js'; | ||
|  | import { getValueFromType, getValueType } from '../core/NodeUtils.js'; | ||
|  | 
 | ||
|  | //
 | ||
|  | 
 | ||
|  | let currentStack = null; | ||
|  | 
 | ||
|  | const NodeElements = new Map(); // @TODO: Currently only a few nodes are added, probably also add others
 | ||
|  | 
 | ||
|  | export function addNodeElement( name, nodeElement ) { | ||
|  | 
 | ||
|  | 	if ( NodeElements.has( name ) ) { | ||
|  | 
 | ||
|  | 		console.warn( `Redefinition of node element ${ name }` ); | ||
|  | 		return; | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if ( typeof nodeElement !== 'function' ) throw new Error( `Node element ${ name } is not a function` ); | ||
|  | 
 | ||
|  | 	NodeElements.set( name, nodeElement ); | ||
|  | 
 | ||
|  | } | ||
|  | 
 | ||
|  | const parseSwizzle = ( props ) => props.replace( /r|s/g, 'x' ).replace( /g|t/g, 'y' ).replace( /b|p/g, 'z' ).replace( /a|q/g, 'w' ); | ||
|  | 
 | ||
|  | const shaderNodeHandler = { | ||
|  | 
 | ||
|  | 	setup( NodeClosure, params ) { | ||
|  | 
 | ||
|  | 		const inputs = params.shift(); | ||
|  | 
 | ||
|  | 		return NodeClosure( nodeObjects( inputs ), ...params ); | ||
|  | 
 | ||
|  | 	}, | ||
|  | 
 | ||
|  | 	get( node, prop, nodeObj ) { | ||
|  | 
 | ||
|  | 		if ( typeof prop === 'string' && node[ prop ] === undefined ) { | ||
|  | 
 | ||
|  | 			if ( node.isStackNode !== true && prop === 'assign' ) { | ||
|  | 
 | ||
|  | 				return ( ...params ) => { | ||
|  | 
 | ||
|  | 					currentStack.assign( nodeObj, ...params ); | ||
|  | 
 | ||
|  | 					return nodeObj; | ||
|  | 
 | ||
|  | 				}; | ||
|  | 
 | ||
|  | 			} else if ( NodeElements.has( prop ) ) { | ||
|  | 
 | ||
|  | 				const nodeElement = NodeElements.get( prop ); | ||
|  | 
 | ||
|  | 				return node.isStackNode ? ( ...params ) => nodeObj.add( nodeElement( ...params ) ) : ( ...params ) => nodeElement( nodeObj, ...params ); | ||
|  | 
 | ||
|  | 			} else if ( prop === 'self' ) { | ||
|  | 
 | ||
|  | 				return node; | ||
|  | 
 | ||
|  | 			} else if ( prop.endsWith( 'Assign' ) && NodeElements.has( prop.slice( 0, prop.length - 'Assign'.length ) ) ) { | ||
|  | 
 | ||
|  | 				const nodeElement = NodeElements.get( prop.slice( 0, prop.length - 'Assign'.length ) ); | ||
|  | 
 | ||
|  | 				return node.isStackNode ? ( ...params ) => nodeObj.assign( params[ 0 ], nodeElement( ...params ) ) : ( ...params ) => nodeObj.assign( nodeElement( nodeObj, ...params ) ); | ||
|  | 
 | ||
|  | 			} else if ( /^[xyzwrgbastpq]{1,4}$/.test( prop ) === true ) { | ||
|  | 
 | ||
|  | 				// accessing properties ( swizzle )
 | ||
|  | 
 | ||
|  | 				prop = parseSwizzle( prop ); | ||
|  | 
 | ||
|  | 				return nodeObject( new SplitNode( nodeObj, prop ) ); | ||
|  | 
 | ||
|  | 			} else if ( /^set[XYZWRGBASTPQ]{1,4}$/.test( prop ) === true ) { | ||
|  | 
 | ||
|  | 				// set properties ( swizzle )
 | ||
|  | 
 | ||
|  | 				prop = parseSwizzle( prop.slice( 3 ).toLowerCase() ); | ||
|  | 
 | ||
|  | 				// sort to xyzw sequence
 | ||
|  | 
 | ||
|  | 				prop = prop.split( '' ).sort().join( '' ); | ||
|  | 
 | ||
|  | 				return ( value ) => nodeObject( new SetNode( node, prop, value ) ); | ||
|  | 
 | ||
|  | 			} else if ( prop === 'width' || prop === 'height' || prop === 'depth' ) { | ||
|  | 
 | ||
|  | 				// accessing property
 | ||
|  | 
 | ||
|  | 				if ( prop === 'width' ) prop = 'x'; | ||
|  | 				else if ( prop === 'height' ) prop = 'y'; | ||
|  | 				else if ( prop === 'depth' ) prop = 'z'; | ||
|  | 
 | ||
|  | 				return nodeObject( new SplitNode( node, prop ) ); | ||
|  | 
 | ||
|  | 			} else if ( /^\d+$/.test( prop ) === true ) { | ||
|  | 
 | ||
|  | 				// accessing array
 | ||
|  | 
 | ||
|  | 				return nodeObject( new ArrayElementNode( nodeObj, new ConstNode( Number( prop ), 'uint' ) ) ); | ||
|  | 
 | ||
|  | 			} | ||
|  | 
 | ||
|  | 		} | ||
|  | 
 | ||
|  | 		return Reflect.get( node, prop, nodeObj ); | ||
|  | 
 | ||
|  | 	}, | ||
|  | 
 | ||
|  | 	set( node, prop, value, nodeObj ) { | ||
|  | 
 | ||
|  | 		if ( typeof prop === 'string' && node[ prop ] === undefined ) { | ||
|  | 
 | ||
|  | 			// setting properties
 | ||
|  | 
 | ||
|  | 			if ( /^[xyzwrgbastpq]{1,4}$/.test( prop ) === true || prop === 'width' || prop === 'height' || prop === 'depth' || /^\d+$/.test( prop ) === true ) { | ||
|  | 
 | ||
|  | 				nodeObj[ prop ].assign( value ); | ||
|  | 
 | ||
|  | 				return true; | ||
|  | 
 | ||
|  | 			} | ||
|  | 
 | ||
|  | 		} | ||
|  | 
 | ||
|  | 		return Reflect.set( node, prop, value, nodeObj ); | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | }; | ||
|  | 
 | ||
|  | const nodeObjectsCacheMap = new WeakMap(); | ||
|  | const nodeBuilderFunctionsCacheMap = new WeakMap(); | ||
|  | 
 | ||
|  | const ShaderNodeObject = 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 tslFn( obj ); | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return obj; | ||
|  | 
 | ||
|  | }; | ||
|  | 
 | ||
|  | const ShaderNodeObjects = function ( objects, altType = null ) { | ||
|  | 
 | ||
|  | 	for ( const name in objects ) { | ||
|  | 
 | ||
|  | 		objects[ name ] = nodeObject( objects[ name ], altType ); | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return objects; | ||
|  | 
 | ||
|  | }; | ||
|  | 
 | ||
|  | const ShaderNodeArray = function ( array, altType = null ) { | ||
|  | 
 | ||
|  | 	const len = array.length; | ||
|  | 
 | ||
|  | 	for ( let i = 0; i < len; i ++ ) { | ||
|  | 
 | ||
|  | 		array[ i ] = nodeObject( array[ i ], altType ); | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return array; | ||
|  | 
 | ||
|  | }; | ||
|  | 
 | ||
|  | const ShaderNodeProxy = function ( NodeClass, scope = null, factor = null, settings = null ) { | ||
|  | 
 | ||
|  | 	const assignNode = ( node ) => nodeObject( settings !== null ? Object.assign( node, settings ) : node ); | ||
|  | 
 | ||
|  | 	if ( scope === null ) { | ||
|  | 
 | ||
|  | 		return ( ...params ) => { | ||
|  | 
 | ||
|  | 			return assignNode( new NodeClass( ...nodeArray( params ) ) ); | ||
|  | 
 | ||
|  | 		}; | ||
|  | 
 | ||
|  | 	} else if ( factor !== null ) { | ||
|  | 
 | ||
|  | 		factor = nodeObject( factor ); | ||
|  | 
 | ||
|  | 		return ( ...params ) => { | ||
|  | 
 | ||
|  | 			return assignNode( new NodeClass( scope, ...nodeArray( params ), factor ) ); | ||
|  | 
 | ||
|  | 		}; | ||
|  | 
 | ||
|  | 	} else { | ||
|  | 
 | ||
|  | 		return ( ...params ) => { | ||
|  | 
 | ||
|  | 			return assignNode( new NodeClass( scope, ...nodeArray( params ) ) ); | ||
|  | 
 | ||
|  | 		}; | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | }; | ||
|  | 
 | ||
|  | const ShaderNodeImmutable = function ( NodeClass, ...params ) { | ||
|  | 
 | ||
|  | 	return nodeObject( new NodeClass( ...nodeArray( params ) ) ); | ||
|  | 
 | ||
|  | }; | ||
|  | 
 | ||
|  | class ShaderCallNodeInternal extends Node { | ||
|  | 
 | ||
|  | 	constructor( shaderNode, inputNodes ) { | ||
|  | 
 | ||
|  | 		super(); | ||
|  | 
 | ||
|  | 		this.shaderNode = shaderNode; | ||
|  | 		this.inputNodes = inputNodes; | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	getNodeType( builder ) { | ||
|  | 
 | ||
|  | 		const { outputNode } = builder.getNodeProperties( this ); | ||
|  | 
 | ||
|  | 		return outputNode ? outputNode.getNodeType( builder ) : super.getNodeType( builder ); | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	call( builder ) { | ||
|  | 
 | ||
|  | 		const { shaderNode, inputNodes } = this; | ||
|  | 
 | ||
|  | 		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 ); | ||
|  | 
 | ||
|  | 			} | ||
|  | 
 | ||
|  | 			if ( builder.currentFunctionNode !== null ) { | ||
|  | 
 | ||
|  | 				builder.currentFunctionNode.includes.push( functionNode ); | ||
|  | 
 | ||
|  | 			} | ||
|  | 
 | ||
|  | 			return nodeObject( functionNode.call( inputNodes ) ); | ||
|  | 
 | ||
|  | 		} | ||
|  | 
 | ||
|  | 		const jsFunc = shaderNode.jsFunc; | ||
|  | 		const outputNode = inputNodes !== null ? jsFunc( inputNodes, builder.stack, builder ) : jsFunc( builder.stack, builder ); | ||
|  | 
 | ||
|  | 		return nodeObject( outputNode ); | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	setup( builder ) { | ||
|  | 
 | ||
|  | 		builder.addStack(); | ||
|  | 
 | ||
|  | 		builder.stack.outputNode = this.call( builder ); | ||
|  | 
 | ||
|  | 		return builder.removeStack(); | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	generate( builder, output ) { | ||
|  | 
 | ||
|  | 		const { outputNode } = builder.getNodeProperties( this ); | ||
|  | 
 | ||
|  | 		if ( outputNode === null ) { | ||
|  | 
 | ||
|  | 			// TSL: It's recommended to use `tslFn` in setup() pass.
 | ||
|  | 
 | ||
|  | 			return this.call( builder ).build( builder, output ); | ||
|  | 
 | ||
|  | 		} | ||
|  | 
 | ||
|  | 		return super.generate( builder, output ); | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | } | ||
|  | 
 | ||
|  | class ShaderNodeInternal extends Node { | ||
|  | 
 | ||
|  | 	constructor( jsFunc ) { | ||
|  | 
 | ||
|  | 		super(); | ||
|  | 
 | ||
|  | 		this.jsFunc = jsFunc; | ||
|  | 		this.layout = null; | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	get isArrayInput() { | ||
|  | 
 | ||
|  | 		return /^\((\s+)?\[/.test( this.jsFunc.toString() ); | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	setLayout( layout ) { | ||
|  | 
 | ||
|  | 		this.layout = layout; | ||
|  | 
 | ||
|  | 		return this; | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	call( inputs = null ) { | ||
|  | 
 | ||
|  | 		nodeObjects( inputs ); | ||
|  | 
 | ||
|  | 		return nodeObject( new ShaderCallNodeInternal( this, inputs ) ); | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	setup() { | ||
|  | 
 | ||
|  | 		return this.call(); | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | } | ||
|  | 
 | ||
|  | const bools = [ false, true ]; | ||
|  | const uints = [ 0, 1, 2, 3 ]; | ||
|  | const ints = [ - 1, - 2 ]; | ||
|  | const floats = [ 0.5, 1.5, 1 / 3, 1e-6, 1e6, Math.PI, Math.PI * 2, 1 / Math.PI, 2 / Math.PI, 1 / ( Math.PI * 2 ), Math.PI / 2 ]; | ||
|  | 
 | ||
|  | const boolsCacheMap = new Map(); | ||
|  | for ( const bool of bools ) boolsCacheMap.set( bool, new ConstNode( bool ) ); | ||
|  | 
 | ||
|  | const uintsCacheMap = new Map(); | ||
|  | for ( const uint of uints ) uintsCacheMap.set( uint, new ConstNode( uint, 'uint' ) ); | ||
|  | 
 | ||
|  | const intsCacheMap = new Map( [ ...uintsCacheMap ].map( el => new ConstNode( el.value, 'int' ) ) ); | ||
|  | for ( const int of ints ) intsCacheMap.set( int, new ConstNode( int, 'int' ) ); | ||
|  | 
 | ||
|  | const floatsCacheMap = new Map( [ ...intsCacheMap ].map( el => new ConstNode( el.value ) ) ); | ||
|  | for ( const float of floats ) floatsCacheMap.set( float, new ConstNode( float ) ); | ||
|  | for ( const float of floats ) floatsCacheMap.set( - float, new ConstNode( - float ) ); | ||
|  | 
 | ||
|  | const cacheMaps = { bool: boolsCacheMap, uint: uintsCacheMap, ints: intsCacheMap, float: floatsCacheMap }; | ||
|  | 
 | ||
|  | const constNodesCacheMap = new Map( [ ...boolsCacheMap, ...floatsCacheMap ] ); | ||
|  | 
 | ||
|  | const getConstNode = ( value, type ) => { | ||
|  | 
 | ||
|  | 	if ( constNodesCacheMap.has( value ) ) { | ||
|  | 
 | ||
|  | 		return constNodesCacheMap.get( value ); | ||
|  | 
 | ||
|  | 	} else if ( value.isNode === true ) { | ||
|  | 
 | ||
|  | 		return value; | ||
|  | 
 | ||
|  | 	} else { | ||
|  | 
 | ||
|  | 		return new ConstNode( value, type ); | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | }; | ||
|  | 
 | ||
|  | const safeGetNodeType = ( node ) => { | ||
|  | 
 | ||
|  | 	try { | ||
|  | 
 | ||
|  | 		return node.getNodeType(); | ||
|  | 
 | ||
|  | 	} catch ( _ ) { | ||
|  | 
 | ||
|  | 		return undefined; | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | }; | ||
|  | 
 | ||
|  | const ConvertType = function ( type, cacheMap = null ) { | ||
|  | 
 | ||
|  | 	return ( ...params ) => { | ||
|  | 
 | ||
|  | 		if ( params.length === 0 || ( ! [ 'bool', 'float', 'int', 'uint' ].includes( type ) && params.every( param => typeof param !== 'object' ) ) ) { | ||
|  | 
 | ||
|  | 			params = [ getValueFromType( type, ...params ) ]; | ||
|  | 
 | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if ( params.length === 1 && cacheMap !== null && cacheMap.has( params[ 0 ] ) ) { | ||
|  | 
 | ||
|  | 			return nodeObject( cacheMap.get( params[ 0 ] ) ); | ||
|  | 
 | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if ( params.length === 1 ) { | ||
|  | 
 | ||
|  | 			const node = getConstNode( params[ 0 ], type ); | ||
|  | 			if ( safeGetNodeType( node ) === type ) return nodeObject( node ); | ||
|  | 			return nodeObject( new ConvertNode( node, type ) ); | ||
|  | 
 | ||
|  | 		} | ||
|  | 
 | ||
|  | 		const nodes = params.map( param => getConstNode( param ) ); | ||
|  | 		return nodeObject( new JoinNode( nodes, type ) ); | ||
|  | 
 | ||
|  | 	}; | ||
|  | 
 | ||
|  | }; | ||
|  | 
 | ||
|  | // exports
 | ||
|  | 
 | ||
|  | export const defined = ( value ) => value && value.value; | ||
|  | 
 | ||
|  | // utils
 | ||
|  | 
 | ||
|  | export const getConstNodeType = ( value ) => ( value !== undefined && value !== null ) ? ( value.nodeType || value.convertTo || ( typeof value === 'string' ? value : null ) ) : null; | ||
|  | 
 | ||
|  | // shader node base
 | ||
|  | 
 | ||
|  | export function ShaderNode( jsFunc ) { | ||
|  | 
 | ||
|  | 	return new Proxy( new ShaderNodeInternal( jsFunc ), shaderNodeHandler ); | ||
|  | 
 | ||
|  | } | ||
|  | 
 | ||
|  | export const nodeObject = ( val, altType = null ) => /* new */ ShaderNodeObject( val, altType ); | ||
|  | export const nodeObjects = ( val, altType = null ) => new ShaderNodeObjects( val, altType ); | ||
|  | export const nodeArray = ( val, altType = null ) => new ShaderNodeArray( val, altType ); | ||
|  | export const nodeProxy = ( ...params ) => new ShaderNodeProxy( ...params ); | ||
|  | export const nodeImmutable = ( ...params ) => new ShaderNodeImmutable( ...params ); | ||
|  | 
 | ||
|  | export const tslFn = ( jsFunc ) => { | ||
|  | 
 | ||
|  | 	const shaderNode = new ShaderNode( jsFunc ); | ||
|  | 
 | ||
|  | 	const fn = ( ...params ) => { | ||
|  | 
 | ||
|  | 		let inputs; | ||
|  | 
 | ||
|  | 		nodeObjects( params ); | ||
|  | 
 | ||
|  | 		if ( params[ 0 ] && params[ 0 ].isNode ) { | ||
|  | 
 | ||
|  | 			inputs = [ ...params ]; | ||
|  | 
 | ||
|  | 		} else { | ||
|  | 
 | ||
|  | 			inputs = params[ 0 ]; | ||
|  | 
 | ||
|  | 		} | ||
|  | 
 | ||
|  | 		return shaderNode.call( inputs ); | ||
|  | 
 | ||
|  | 	}; | ||
|  | 
 | ||
|  | 	fn.shaderNode = shaderNode; | ||
|  | 	fn.setLayout = ( layout ) => { | ||
|  | 
 | ||
|  | 		shaderNode.setLayout( layout ); | ||
|  | 
 | ||
|  | 		return fn; | ||
|  | 
 | ||
|  | 	}; | ||
|  | 
 | ||
|  | 	return fn; | ||
|  | 
 | ||
|  | }; | ||
|  | 
 | ||
|  | addNodeClass( 'ShaderNode', ShaderNode ); | ||
|  | 
 | ||
|  | //
 | ||
|  | 
 | ||
|  | export const setCurrentStack = ( stack ) => { | ||
|  | 
 | ||
|  | 	if ( currentStack === stack ) { | ||
|  | 
 | ||
|  | 		//throw new Error( 'Stack already defined.' );
 | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	currentStack = stack; | ||
|  | 
 | ||
|  | }; | ||
|  | 
 | ||
|  | export const getCurrentStack = () => currentStack; | ||
|  | 
 | ||
|  | export const If = ( ...params ) => currentStack.if( ...params ); | ||
|  | 
 | ||
|  | export function append( node ) { | ||
|  | 
 | ||
|  | 	if ( currentStack ) currentStack.add( node ); | ||
|  | 
 | ||
|  | 	return node; | ||
|  | 
 | ||
|  | } | ||
|  | 
 | ||
|  | addNodeElement( 'append', append ); | ||
|  | 
 | ||
|  | // types
 | ||
|  | // @TODO: Maybe export from ConstNode.js?
 | ||
|  | 
 | ||
|  | export const color = new ConvertType( 'color' ); | ||
|  | 
 | ||
|  | export const float = new ConvertType( 'float', cacheMaps.float ); | ||
|  | export const int = new ConvertType( 'int', cacheMaps.ints ); | ||
|  | export const uint = new ConvertType( 'uint', cacheMaps.uint ); | ||
|  | export const bool = new ConvertType( 'bool', cacheMaps.bool ); | ||
|  | 
 | ||
|  | export const vec2 = new ConvertType( 'vec2' ); | ||
|  | export const ivec2 = new ConvertType( 'ivec2' ); | ||
|  | export const uvec2 = new ConvertType( 'uvec2' ); | ||
|  | export const bvec2 = new ConvertType( 'bvec2' ); | ||
|  | 
 | ||
|  | export const vec3 = new ConvertType( 'vec3' ); | ||
|  | export const ivec3 = new ConvertType( 'ivec3' ); | ||
|  | export const uvec3 = new ConvertType( 'uvec3' ); | ||
|  | export const bvec3 = new ConvertType( 'bvec3' ); | ||
|  | 
 | ||
|  | export const vec4 = new ConvertType( 'vec4' ); | ||
|  | export const ivec4 = new ConvertType( 'ivec4' ); | ||
|  | export const uvec4 = new ConvertType( 'uvec4' ); | ||
|  | export const bvec4 = new ConvertType( 'bvec4' ); | ||
|  | 
 | ||
|  | export const mat2 = new ConvertType( 'mat2' ); | ||
|  | export const imat2 = new ConvertType( 'imat2' ); | ||
|  | export const umat2 = new ConvertType( 'umat2' ); | ||
|  | export const bmat2 = new ConvertType( 'bmat2' ); | ||
|  | 
 | ||
|  | export const mat3 = new ConvertType( 'mat3' ); | ||
|  | export const imat3 = new ConvertType( 'imat3' ); | ||
|  | export const umat3 = new ConvertType( 'umat3' ); | ||
|  | export const bmat3 = new ConvertType( 'bmat3' ); | ||
|  | 
 | ||
|  | export const mat4 = new ConvertType( 'mat4' ); | ||
|  | export const imat4 = new ConvertType( 'imat4' ); | ||
|  | export const umat4 = new ConvertType( 'umat4' ); | ||
|  | export const bmat4 = new ConvertType( 'bmat4' ); | ||
|  | 
 | ||
|  | export const string = ( value = '' ) => nodeObject( new ConstNode( value, 'string' ) ); | ||
|  | export const arrayBuffer = ( value ) => nodeObject( new ConstNode( value, 'ArrayBuffer' ) ); | ||
|  | 
 | ||
|  | addNodeElement( 'color', color ); | ||
|  | addNodeElement( 'float', float ); | ||
|  | addNodeElement( 'int', int ); | ||
|  | addNodeElement( 'uint', uint ); | ||
|  | addNodeElement( 'bool', bool ); | ||
|  | addNodeElement( 'vec2', vec2 ); | ||
|  | addNodeElement( 'ivec2', ivec2 ); | ||
|  | addNodeElement( 'uvec2', uvec2 ); | ||
|  | addNodeElement( 'bvec2', bvec2 ); | ||
|  | addNodeElement( 'vec3', vec3 ); | ||
|  | addNodeElement( 'ivec3', ivec3 ); | ||
|  | addNodeElement( 'uvec3', uvec3 ); | ||
|  | addNodeElement( 'bvec3', bvec3 ); | ||
|  | addNodeElement( 'vec4', vec4 ); | ||
|  | addNodeElement( 'ivec4', ivec4 ); | ||
|  | addNodeElement( 'uvec4', uvec4 ); | ||
|  | addNodeElement( 'bvec4', bvec4 ); | ||
|  | addNodeElement( 'mat2', mat2 ); | ||
|  | addNodeElement( 'imat2', imat2 ); | ||
|  | addNodeElement( 'umat2', umat2 ); | ||
|  | addNodeElement( 'bmat2', bmat2 ); | ||
|  | addNodeElement( 'mat3', mat3 ); | ||
|  | addNodeElement( 'imat3', imat3 ); | ||
|  | addNodeElement( 'umat3', umat3 ); | ||
|  | addNodeElement( 'bmat3', bmat3 ); | ||
|  | addNodeElement( 'mat4', mat4 ); | ||
|  | addNodeElement( 'imat4', imat4 ); | ||
|  | addNodeElement( 'umat4', umat4 ); | ||
|  | addNodeElement( 'bmat4', bmat4 ); | ||
|  | addNodeElement( 'string', string ); | ||
|  | addNodeElement( 'arrayBuffer', arrayBuffer ); | ||
|  | 
 | ||
|  | // basic nodes
 | ||
|  | // HACK - we cannot export them from the corresponding files because of the cyclic dependency
 | ||
|  | export const element = nodeProxy( ArrayElementNode ); | ||
|  | export const convert = ( node, types ) => nodeObject( new ConvertNode( nodeObject( node ), types ) ); | ||
|  | export const split = ( node, channels ) => nodeObject( new SplitNode( nodeObject( node ), channels ) ); | ||
|  | 
 | ||
|  | addNodeElement( 'element', element ); | ||
|  | addNodeElement( 'convert', convert ); |