import TempNode from '../core/Node.js'; import { ShaderNode, EPSILON, vec3, sub, mul, div, cond, lessThan, equal, max } from '../shadernode/ShaderNodeBaseElements.js'; export const BurnNode = new ShaderNode( ( { base, blend } ) => { const fn = ( c ) => cond( lessThan( blend[ c ], EPSILON ), blend[ c ], max( sub( 1.0, div( sub( 1.0, base[ c ] ), blend[ c ] ) ), 0 ) ); return vec3( fn( 'x' ), fn( 'y' ), fn( 'z' ) ); } ); export const DodgeNode = new ShaderNode( ( { base, blend } ) => { const fn = ( c ) => cond( equal( blend[ c ], 1.0 ), blend[ c ], max( div( base[ c ], sub( 1.0, blend[ c ] ) ), 0 ) ); return vec3( fn( 'x' ), fn( 'y' ), fn( 'z' ) ); } ); export const ScreenNode = new ShaderNode( ( { base, blend } ) => { const fn = ( c ) => sub( 1.0, mul( sub( 1.0, base[ c ] ), sub( 1.0, blend[ c ] ) ) ); return vec3( fn( 'x' ), fn( 'y' ), fn( 'z' ) ); } ); export const OverlayNode = new ShaderNode( ( { base, blend } ) => { const fn = ( c ) => cond( lessThan( base[ c ], 0.5 ), mul( 2.0, base[ c ], blend[ c ] ), sub( 1.0, mul( sub( 1.0, base[ c ] ), sub( 1.0, blend[ c ] ) ) ) ); return vec3( fn( 'x' ), fn( 'y' ), fn( 'z' ) ); } ); class BlendModeNode extends TempNode { static BURN = 'burn'; static DODGE = 'dodge'; static SCREEN = 'screen'; static OVERLAY = 'overlay'; constructor( blendMode, baseNode, blendNode ) { super(); this.blendMode = blendMode; this.baseNode = baseNode; this.blendNode = blendNode; } construct() { const { blendMode, baseNode, blendNode } = this; const params = { base: baseNode, blend: blendNode }; let outputNode = null; if ( blendMode === BlendModeNode.BURN ) { outputNode = BurnNode.call( params ); } else if ( blendMode === BlendModeNode.DODGE ) { outputNode = DodgeNode.call( params ); } else if ( blendMode === BlendModeNode.SCREEN ) { outputNode = ScreenNode.call( params ); } else if ( blendMode === BlendModeNode.OVERLAY ) { outputNode = OverlayNode.call( params ); } return outputNode; } } export default BlendModeNode;