|
1 | 1 | import Node from './Node.js';
|
2 | 2 | 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'; |
4 | 4 |
|
5 | 5 | /**
|
6 | 6 | * 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 {
|
57 | 57 | */
|
58 | 58 | this._currentCond = null;
|
59 | 59 |
|
| 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 | + |
60 | 70 | /**
|
61 | 71 | * This flag can be used for type testing.
|
62 | 72 | *
|
@@ -143,6 +153,98 @@ class StackNode extends Node {
|
143 | 153 |
|
144 | 154 | }
|
145 | 155 |
|
| 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 | + |
146 | 248 | build( builder, ...params ) {
|
147 | 249 |
|
148 | 250 | const previousStack = getCurrentStack();
|
|
0 commit comments