123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262 |
- 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 ConstNode from '../core/ConstNode.js';
- import { getValueFromType } from '../core/NodeUtils.js';
- const shaderNodeHandler = {
- construct( NodeClosure, params ) {
- const inputs = params.shift();
- return NodeClosure( nodeObjects( inputs ), ...params );
- },
- get: function ( node, prop ) {
- if ( typeof prop === 'string' && node[ prop ] === undefined ) {
- if ( /^[xyzwrgbastpq]{1,4}$/.test( prop ) === true ) {
- // accessing properties ( swizzle )
- prop = prop
- .replace( /r|s/g, 'x' )
- .replace( /g|t/g, 'y' )
- .replace( /b|p/g, 'z' )
- .replace( /a|q/g, 'w' );
- return nodeObject( new SplitNode( node, prop ) );
- } else if ( /^\d+$/.test( prop ) === true ) {
- // accessing array
- return nodeObject( new ArrayElementNode( node, new ConstNode( Number( prop ), 'uint' ) ) );
- }
- }
- return node[ prop ];
- }
- };
- const nodeObjectsCacheMap = new WeakMap();
- const ShaderNodeObject = function ( obj ) {
- const type = typeof obj;
- if ( ( type === 'number' ) || ( type === 'boolean' ) ) {
- return nodeObject( getAutoTypedConstNode( obj ) );
- } else if ( type === 'object' ) {
- if ( obj?.isNode === true ) {
- let nodeObject = nodeObjectsCacheMap.get( obj );
- if ( nodeObject === undefined ) {
- nodeObject = new Proxy( obj, shaderNodeHandler );
- nodeObjectsCacheMap.set( obj, nodeObject );
- nodeObjectsCacheMap.set( nodeObject, nodeObject );
- }
- return nodeObject;
- }
- }
- return obj;
- };
- const ShaderNodeObjects = function ( objects ) {
- for ( const name in objects ) {
- objects[ name ] = nodeObject( objects[ name ] );
- }
- return objects;
- };
- const ShaderNodeArray = function ( array ) {
- const len = array.length;
- for ( let i = 0; i < len; i ++ ) {
- array[ i ] = nodeObject( array[ i ] );
- }
- return array;
- };
- const ShaderNodeProxy = function ( NodeClass, scope = null, factor = null ) {
- if ( scope === null ) {
- return ( ...params ) => {
- return nodeObject( new NodeClass( ...nodeArray( params ) ) );
- };
- } else if ( factor === null ) {
- return ( ...params ) => {
- return nodeObject( new NodeClass( scope, ...nodeArray( params ) ) );
- };
- } else {
- factor = nodeObject( factor );
- return ( ...params ) => {
- return nodeObject( new NodeClass( scope, ...nodeArray( params ), factor ) );
- };
- }
- };
- const ShaderNodeImmutable = function ( NodeClass, ...params ) {
- return nodeObject( new NodeClass( ...nodeArray( params ) ) );
- };
- const ShaderNodeScript = function ( jsFunc ) {
- // @TODO: Move this to Node extended class
- const self = {
- build: ( builder ) => {
- self.call( {}, builder );
- return '';
- },
- call: ( inputs, builder ) => {
- inputs = nodeObjects( inputs );
- return nodeObject( jsFunc( inputs, builder ) );
- }
- };
- return self;
- };
- export const ShaderNode = new Proxy( ShaderNodeScript, shaderNodeHandler );
- export const nodeObject = ( val ) => /* new */ ShaderNodeObject( val );
- export const nodeObjects = ( val ) => new ShaderNodeObjects( val );
- export const nodeArray = ( val ) => new ShaderNodeArray( val );
- export const nodeProxy = ( ...val ) => new ShaderNodeProxy( ...val );
- export const nodeImmutable = ( ...val ) => new ShaderNodeImmutable( ...val );
- 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 ) );
- export const cacheMaps = { bool: boolsCacheMap, uint: uintsCacheMap, ints: intsCacheMap, float: floatsCacheMap };
- const constNodesCacheMap = new Map( [ ...boolsCacheMap, ...floatsCacheMap ] );
- const getAutoTypedConstNode = ( value ) => {
- if ( constNodesCacheMap.has( value ) ) {
- return constNodesCacheMap.get( value );
- } else if ( value.isNode === true ) {
- return value;
- } else {
- return new ConstNode( value );
- }
- };
- export const ConvertType = function ( type, cacheMap = null ) {
- return ( ...params ) => {
- if ( params.length === 0 ) {
- return nodeObject( new ConstNode( getValueFromType( type ), type ) );
- } else {
- if ( type === 'color' && params[ 0 ].isNode !== true ) {
- params = [ getValueFromType( type, ...params ) ];
- }
- if ( params.length === 1 && cacheMap !== null && cacheMap.has( params[ 0 ] ) ) {
- return cacheMap.get( params[ 0 ] );
- }
- const nodes = params.map( getAutoTypedConstNode );
- if ( nodes.length === 1 ) {
- return nodeObject( nodes[ 0 ].nodeType === type ? nodes[ 0 ] : new ConvertNode( nodes[ 0 ], type ) );
- }
- return nodeObject( new ConvertNode( new JoinNode( nodes ), type ) );
- }
- };
- };
- export const getConstNodeType = ( value ) => value.nodeType || value.convertTo || ( typeof value === 'string' ? value : null );
|