|
|
@@ -13,6 +13,8 @@ let currentStack = null;
|
|
|
|
|
|
const NodeElements = new Map();
|
|
|
|
|
|
+// Extend Node Class for TSL using prototype
|
|
|
+
|
|
|
export function addMethodChaining( name, nodeElement ) {
|
|
|
|
|
|
if ( NodeElements.has( name ) ) {
|
|
|
@@ -26,152 +28,266 @@ export function addMethodChaining( name, nodeElement ) {
|
|
|
|
|
|
NodeElements.set( name, nodeElement );
|
|
|
|
|
|
+ if ( name !== 'assign' ) {
|
|
|
+
|
|
|
+ // Changing Node prototype to add method chaining
|
|
|
+
|
|
|
+ Node.prototype[ name ] = function ( ...params ) {
|
|
|
+
|
|
|
+ //if ( name === 'toVarIntent' ) return this;
|
|
|
+
|
|
|
+ return this.isStackNode ? this.add( nodeElement( ...params ) ) : nodeElement( this, ...params );
|
|
|
+
|
|
|
+ };
|
|
|
+
|
|
|
+ // Adding assign method chaining
|
|
|
+
|
|
|
+ Node.prototype[ name + 'Assign' ] = function ( ...params ) {
|
|
|
+
|
|
|
+ return this.isStackNode ? this.assign( params[ 0 ], nodeElement( ...params ) ) : this.assign( nodeElement( this, ...params ) );
|
|
|
+
|
|
|
+ };
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
|
|
|
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 parseSwizzleAndSort = ( props ) => parseSwizzle( props ).split( '' ).sort().join( '' );
|
|
|
|
|
|
-const shaderNodeHandler = {
|
|
|
+Node.prototype.assign = function ( ...params ) {
|
|
|
|
|
|
- setup( NodeClosure, params ) {
|
|
|
+ if ( this.isStackNode !== true ) {
|
|
|
|
|
|
- const inputs = params.shift();
|
|
|
+ currentStack.assign( this, ...params );
|
|
|
|
|
|
- return NodeClosure( nodeObjects( inputs ), ...params );
|
|
|
+ return this;
|
|
|
|
|
|
- },
|
|
|
+ } else {
|
|
|
|
|
|
- get( node, prop, nodeObj ) {
|
|
|
+ const nodeElement = NodeElements.get( 'assign' );
|
|
|
|
|
|
- if ( typeof prop === 'string' && node[ prop ] === undefined ) {
|
|
|
+ return this.add( nodeElement( ...params ) );
|
|
|
|
|
|
- if ( node.isStackNode !== true && prop === 'assign' ) {
|
|
|
+ }
|
|
|
|
|
|
- return ( ...params ) => {
|
|
|
+};
|
|
|
|
|
|
- currentStack.assign( nodeObj, ...params );
|
|
|
+Node.prototype.toVarIntent = function () {
|
|
|
|
|
|
- return nodeObj;
|
|
|
+ return this;
|
|
|
|
|
|
- };
|
|
|
+};
|
|
|
+
|
|
|
+Node.prototype.get = function ( value ) {
|
|
|
+
|
|
|
+ return new MemberNode( this, value );
|
|
|
|
|
|
- } else if ( NodeElements.has( prop ) ) {
|
|
|
+};
|
|
|
+
|
|
|
+// Cache prototype for TSL
|
|
|
+
|
|
|
+const proto = {};
|
|
|
+
|
|
|
+// Set swizzle properties for xyzw, rgba, and stpq.
|
|
|
+
|
|
|
+function setProtoSwizzle( property, altA, altB ) {
|
|
|
+
|
|
|
+ // swizzle properties
|
|
|
|
|
|
- const nodeElement = NodeElements.get( prop );
|
|
|
+ proto[ property ] = proto[ altA ] = proto[ altB ] = {
|
|
|
|
|
|
- return node.isStackNode ? ( ...params ) => nodeObj.add( nodeElement( ...params ) ) : ( ...params ) => nodeElement( nodeObj, ...params );
|
|
|
+ get() {
|
|
|
|
|
|
- } else if ( prop === 'toVarIntent' ) {
|
|
|
+ this._cache = this._cache || {};
|
|
|
|
|
|
- return () => nodeObj;
|
|
|
+ //
|
|
|
+
|
|
|
+ let split = this._cache[ property ];
|
|
|
|
|
|
- } else if ( prop === 'self' ) {
|
|
|
+ if ( split === undefined ) {
|
|
|
|
|
|
- return node;
|
|
|
+ split = new SplitNode( this, property );
|
|
|
|
|
|
- } else if ( prop.endsWith( 'Assign' ) && NodeElements.has( prop.slice( 0, prop.length - 'Assign'.length ) ) ) {
|
|
|
+ this._cache[ property ] = split;
|
|
|
|
|
|
- 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 ) );
|
|
|
+ return split;
|
|
|
|
|
|
- } else if ( /^[xyzwrgbastpq]{1,4}$/.test( prop ) === true ) {
|
|
|
+ },
|
|
|
|
|
|
- // accessing properties ( swizzle )
|
|
|
+ set( value ) {
|
|
|
|
|
|
- prop = parseSwizzle( prop );
|
|
|
+ this[ property ].assign( nodeObject( value ) );
|
|
|
|
|
|
- return nodeObject( new SplitNode( nodeObj, prop ) );
|
|
|
+ }
|
|
|
|
|
|
- } else if ( /^set[XYZWRGBASTPQ]{1,4}$/.test( prop ) === true ) {
|
|
|
+ };
|
|
|
|
|
|
- // set properties ( swizzle ) and sort to xyzw sequence
|
|
|
+ // set properties ( swizzle ) and sort to xyzw sequence
|
|
|
|
|
|
- prop = parseSwizzleAndSort( prop.slice( 3 ).toLowerCase() );
|
|
|
+ const propUpper = property.toUpperCase();
|
|
|
+ const altAUpper = altA.toUpperCase();
|
|
|
+ const altBUpper = altB.toUpperCase();
|
|
|
|
|
|
- return ( value ) => nodeObject( new SetNode( node, prop, nodeObject( value ) ) );
|
|
|
+ // Set methods for swizzle properties
|
|
|
|
|
|
- } else if ( /^flip[XYZWRGBASTPQ]{1,4}$/.test( prop ) === true ) {
|
|
|
+ Node.prototype[ 'set' + propUpper ] = Node.prototype[ 'set' + altAUpper ] = Node.prototype[ 'set' + altBUpper ] = function ( value ) {
|
|
|
|
|
|
- // set properties ( swizzle ) and sort to xyzw sequence
|
|
|
+ const swizzle = parseSwizzleAndSort( property );
|
|
|
+
|
|
|
+ return new SetNode( this, swizzle, nodeObject( value ) );
|
|
|
+
|
|
|
+ };
|
|
|
+
|
|
|
+ // Set methods for flip properties
|
|
|
+
|
|
|
+ Node.prototype[ 'flip' + propUpper ] = Node.prototype[ 'flip' + altAUpper ] = Node.prototype[ 'flip' + altBUpper ] = function () {
|
|
|
+
|
|
|
+ const swizzle = parseSwizzleAndSort( property );
|
|
|
+
|
|
|
+ return new FlipNode( this, swizzle );
|
|
|
+
|
|
|
+ };
|
|
|
+
|
|
|
+}
|
|
|
|
|
|
- prop = parseSwizzleAndSort( prop.slice( 4 ).toLowerCase() );
|
|
|
+const swizzleA = [ 'x', 'y', 'z', 'w' ];
|
|
|
+const swizzleB = [ 'r', 'g', 'b', 'a' ];
|
|
|
+const swizzleC = [ 's', 't', 'p', 'q' ];
|
|
|
|
|
|
- return () => nodeObject( new FlipNode( nodeObject( node ), prop ) );
|
|
|
+for ( let a = 0; a < 4; a ++ ) {
|
|
|
|
|
|
- } else if ( prop === 'width' || prop === 'height' || prop === 'depth' ) {
|
|
|
+ let prop = swizzleA[ a ];
|
|
|
+ let altA = swizzleB[ a ];
|
|
|
+ let altB = swizzleC[ a ];
|
|
|
|
|
|
- // accessing property
|
|
|
+ setProtoSwizzle( prop, altA, altB );
|
|
|
|
|
|
- if ( prop === 'width' ) prop = 'x';
|
|
|
- else if ( prop === 'height' ) prop = 'y';
|
|
|
- else if ( prop === 'depth' ) prop = 'z';
|
|
|
+ for ( let b = 0; b < 4; b ++ ) {
|
|
|
|
|
|
- return nodeObject( new SplitNode( node, prop ) );
|
|
|
+ prop = swizzleA[ a ] + swizzleA[ b ];
|
|
|
+ altA = swizzleB[ a ] + swizzleB[ b ];
|
|
|
+ altB = swizzleC[ a ] + swizzleC[ b ];
|
|
|
|
|
|
- } else if ( /^\d+$/.test( prop ) === true ) {
|
|
|
+ setProtoSwizzle( prop, altA, altB );
|
|
|
|
|
|
- // accessing array
|
|
|
+ for ( let c = 0; c < 4; c ++ ) {
|
|
|
|
|
|
- return nodeObject( new ArrayElementNode( nodeObj, new ConstNode( Number( prop ), 'uint' ) ) );
|
|
|
+ prop = swizzleA[ a ] + swizzleA[ b ] + swizzleA[ c ];
|
|
|
+ altA = swizzleB[ a ] + swizzleB[ b ] + swizzleB[ c ];
|
|
|
+ altB = swizzleC[ a ] + swizzleC[ b ] + swizzleC[ c ];
|
|
|
|
|
|
- } else if ( /^get$/.test( prop ) === true ) {
|
|
|
+ setProtoSwizzle( prop, altA, altB );
|
|
|
|
|
|
- // accessing properties
|
|
|
+ for ( let d = 0; d < 4; d ++ ) {
|
|
|
|
|
|
- return ( value ) => nodeObject( new MemberNode( nodeObj, value ) );
|
|
|
+ prop = swizzleA[ a ] + swizzleA[ b ] + swizzleA[ c ] + swizzleA[ d ];
|
|
|
+ altA = swizzleB[ a ] + swizzleB[ b ] + swizzleB[ c ] + swizzleB[ d ];
|
|
|
+ altB = swizzleC[ a ] + swizzleC[ b ] + swizzleC[ c ] + swizzleC[ d ];
|
|
|
+
|
|
|
+ setProtoSwizzle( prop, altA, altB );
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
- return Reflect.get( node, prop, nodeObj );
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+// Set/get static properties for array elements (0-31).
|
|
|
+
|
|
|
+for ( let i = 0; i < 32; i ++ ) {
|
|
|
|
|
|
- },
|
|
|
+ proto[ i ] = {
|
|
|
|
|
|
- set( node, prop, value, nodeObj ) {
|
|
|
+ get() {
|
|
|
|
|
|
- if ( typeof prop === 'string' && node[ prop ] === undefined ) {
|
|
|
+ this._cache = this._cache || {};
|
|
|
|
|
|
- // setting properties
|
|
|
+ //
|
|
|
+
|
|
|
+ let element = this._cache[ i ];
|
|
|
|
|
|
- if ( /^[xyzwrgbastpq]{1,4}$/.test( prop ) === true || prop === 'width' || prop === 'height' || prop === 'depth' || /^\d+$/.test( prop ) === true ) {
|
|
|
+ if ( element === undefined ) {
|
|
|
|
|
|
- nodeObj[ prop ].assign( value );
|
|
|
+ element = new ArrayElementNode( this, new ConstNode( i, 'uint' ) );
|
|
|
|
|
|
- return true;
|
|
|
+ this._cache[ i ] = element;
|
|
|
|
|
|
}
|
|
|
|
|
|
+ return element;
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ set( value ) {
|
|
|
+
|
|
|
+ this[ i ].assign( nodeObject( value ) );
|
|
|
+
|
|
|
}
|
|
|
|
|
|
- return Reflect.set( node, prop, value, nodeObj );
|
|
|
+ };
|
|
|
|
|
|
- }
|
|
|
+}
|
|
|
|
|
|
-};
|
|
|
+/*
|
|
|
+// Set properties for width, height, and depth.
|
|
|
|
|
|
-const nodeObjectsCacheMap = new WeakMap();
|
|
|
-const nodeBuilderFunctionsCacheMap = new WeakMap();
|
|
|
+function setProtoProperty( property, target ) {
|
|
|
|
|
|
-const ShaderNodeObject = function ( obj, altType = null ) {
|
|
|
+ proto[ property ] = {
|
|
|
|
|
|
- const type = getValueType( obj );
|
|
|
+ get() {
|
|
|
|
|
|
- if ( type === 'node' ) {
|
|
|
+ this._cache = this._cache || {};
|
|
|
+
|
|
|
+ //
|
|
|
|
|
|
- let nodeObject = nodeObjectsCacheMap.get( obj );
|
|
|
+ let split = this._cache[ target ];
|
|
|
|
|
|
- if ( nodeObject === undefined ) {
|
|
|
+ if ( split === undefined ) {
|
|
|
|
|
|
- nodeObject = new Proxy( obj, shaderNodeHandler );
|
|
|
+ split = new SplitNode( this, target );
|
|
|
|
|
|
- nodeObjectsCacheMap.set( obj, nodeObject );
|
|
|
- nodeObjectsCacheMap.set( nodeObject, nodeObject );
|
|
|
+ this._cache[ target ] = split;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ return split;
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ set( value ) {
|
|
|
+
|
|
|
+ this[ target ].assign( nodeObject( value ) );
|
|
|
|
|
|
}
|
|
|
|
|
|
- return nodeObject;
|
|
|
+ };
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+setProtoProperty( 'width', 'x' );
|
|
|
+setProtoProperty( 'height', 'y' );
|
|
|
+setProtoProperty( 'depth', 'z' );
|
|
|
+*/
|
|
|
+
|
|
|
+Object.defineProperties( Node.prototype, proto );
|
|
|
+
|
|
|
+// --- FINISH ---
|
|
|
+
|
|
|
+const nodeBuilderFunctionsCacheMap = new WeakMap();
|
|
|
+
|
|
|
+const ShaderNodeObject = function ( obj, altType = null ) {
|
|
|
+
|
|
|
+ const type = getValueType( obj );
|
|
|
+
|
|
|
+ if ( type === 'node' ) {
|
|
|
+
|
|
|
+ return obj;
|
|
|
|
|
|
} else if ( ( altType === null && ( type === 'float' || type === 'boolean' ) ) || ( type && type !== 'shader' && type !== 'string' ) ) {
|
|
|
|
|
|
@@ -778,7 +894,7 @@ export const getConstNodeType = ( value ) => ( value !== undefined && value !==
|
|
|
|
|
|
export function ShaderNode( jsFunc, nodeType ) {
|
|
|
|
|
|
- return new Proxy( new ShaderNodeInternal( jsFunc, nodeType ), shaderNodeHandler );
|
|
|
+ return new ShaderNodeInternal( jsFunc, nodeType );
|
|
|
|
|
|
}
|
|
|
|