Skip to content

Commit ec16a14

Browse files
authored
TSL: Add switch/case. (#30935)
* TSL: Add switch/case. * StackNode: Support Case() sequence. * StackNode: Refactor `Case()`.
1 parent f35e494 commit ec16a14

File tree

3 files changed

+105
-1
lines changed

3 files changed

+105
-1
lines changed

src/Three.TSL.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export const F_Schlick = TSL.F_Schlick;
1313
export const Fn = TSL.Fn;
1414
export const INFINITY = TSL.INFINITY;
1515
export const If = TSL.If;
16+
export const Switch = TSL.Switch;
1617
export const Loop = TSL.Loop;
1718
export const NodeShaderStage = TSL.NodeShaderStage;
1819
export const NodeType = TSL.NodeType;

src/nodes/core/StackNode.js

Lines changed: 103 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import Node from './Node.js';
22
import { select } from '../math/ConditionalNode.js';
3-
import { ShaderNode, nodeProxy, getCurrentStack, setCurrentStack } from '../tsl/TSLBase.js';
3+
import { ShaderNode, nodeProxy, getCurrentStack, setCurrentStack, nodeObject } from '../tsl/TSLBase.js';
44

55
/**
66
* Stack is a helper for Nodes that need to produce stack-based code instead of continuous flow.
@@ -57,6 +57,16 @@ class StackNode extends Node {
5757
*/
5858
this._currentCond = null;
5959

60+
/**
61+
* The expression node. Only
62+
* relevant for Switch/Case.
63+
*
64+
* @private
65+
* @type {Node}
66+
* @default null
67+
*/
68+
this._expressionNode = null;
69+
6070
/**
6171
* This flag can be used for type testing.
6272
*
@@ -143,6 +153,98 @@ class StackNode extends Node {
143153

144154
}
145155

156+
/**
157+
* Represents a `switch` statement in TSL.
158+
*
159+
* @param {any} expression - Represents the expression.
160+
* @param {Function} method - TSL code which is executed if the condition evaluates to `true`.
161+
* @return {StackNode} A reference to this stack node.
162+
*/
163+
Switch( expression ) {
164+
165+
this._expressionNode = nodeObject( expression );
166+
167+
return this;
168+
169+
}
170+
171+
/**
172+
* Represents a `case` statement in TSL. The TSL version accepts an arbitrary numbers of values.
173+
* The last parameter must be the callback method that should be executed in the `true` case.
174+
*
175+
* @param {...any} params - The values of the `Case()` statement as well as the callback method.
176+
* @return {StackNode} A reference to this stack node.
177+
*/
178+
Case( ...params ) {
179+
180+
const caseNodes = [];
181+
182+
// extract case nodes from the parameter list
183+
184+
if ( params.length >= 2 ) {
185+
186+
for ( let i = 0; i < params.length - 1; i ++ ) {
187+
188+
caseNodes.push( this._expressionNode.equal( nodeObject( params[ i ] ) ) );
189+
190+
}
191+
192+
} else {
193+
194+
throw new Error( 'TSL: Invalid parameter length. Case() requires at least two parameters.' );
195+
196+
}
197+
198+
// extract method
199+
200+
const method = params[ params.length - 1 ];
201+
const methodNode = new ShaderNode( method );
202+
203+
// chain multiple cases when using Case( 1, 2, 3, () => {} )
204+
205+
let caseNode = caseNodes[ 0 ];
206+
207+
for ( let i = 1; i < caseNodes.length; i ++ ) {
208+
209+
caseNode = caseNode.or( caseNodes[ i ] );
210+
211+
}
212+
213+
// build condition
214+
215+
const condNode = select( caseNode, methodNode );
216+
217+
if ( this._currentCond === null ) {
218+
219+
this._currentCond = condNode;
220+
221+
return this.add( this._currentCond );
222+
223+
} else {
224+
225+
this._currentCond.elseNode = condNode;
226+
this._currentCond = condNode;
227+
228+
return this;
229+
230+
}
231+
232+
}
233+
234+
/**
235+
* Represents the default code block of a Switch/Case statement.
236+
*
237+
* @param {Function} method - TSL code which is executed in the `else` case.
238+
* @return {StackNode} A reference to this stack node.
239+
*/
240+
Default( method ) {
241+
242+
this.Else( method );
243+
244+
return this;
245+
246+
}
247+
146248
build( builder, ...params ) {
147249

148250
const previousStack = getCurrentStack();

src/nodes/tsl/TSLCore.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -705,6 +705,7 @@ export const setCurrentStack = ( stack ) => {
705705
export const getCurrentStack = () => currentStack;
706706

707707
export const If = ( ...params ) => currentStack.If( ...params );
708+
export const Switch = ( ...params ) => currentStack.Switch( ...params );
708709

709710
export function append( node ) {
710711

0 commit comments

Comments
 (0)