(generationContext, dag, nodeID)
| 425 | generationContext.write(`return ${this.generateExpression(generationContext, dag, rootNodeID)};`); |
| 426 | }, |
| 427 | generateExpression(generationContext, dag, nodeID) { |
| 428 | const node = getNodeDataFromID(dag, nodeID); |
| 429 | if (generationContext.tempNames?.[nodeID]) { |
| 430 | return generationContext.tempNames[nodeID]; |
| 431 | } |
| 432 | switch (node.nodeType) { |
| 433 | case NodeType.LITERAL: |
| 434 | if (node.baseType === BaseType.FLOAT) { |
| 435 | return node.value.toFixed(4); |
| 436 | } |
| 437 | else { |
| 438 | return node.value; |
| 439 | } |
| 440 | case NodeType.VARIABLE: |
| 441 | // Track shared variable usage context |
| 442 | if (generationContext.shaderContext && generationContext.strandsContext?.sharedVariables?.has(node.identifier)) { |
| 443 | const sharedVar = generationContext.strandsContext.sharedVariables.get(node.identifier); |
| 444 | if (generationContext.shaderContext === 'vertex') { |
| 445 | sharedVar.usedInVertex = true; |
| 446 | } else if (generationContext.shaderContext === 'fragment') { |
| 447 | sharedVar.usedInFragment = true; |
| 448 | } |
| 449 | } |
| 450 | |
| 451 | // Detect instanceID usage in fragment context and rewrite to varying name |
| 452 | if (node.identifier === this.instanceIdReference() && generationContext.shaderContext === 'fragment') { |
| 453 | generationContext.strandsContext._instanceIDUsedInFragment = true; |
| 454 | return INSTANCE_ID_VARYING_NAME; |
| 455 | } |
| 456 | |
| 457 | // Check if this is a uniform variable (but not a texture or storage buffer) |
| 458 | const uniform = generationContext.strandsContext?.uniforms?.find(uniform => uniform.name === node.identifier); |
| 459 | if (uniform && uniform.typeInfo.baseType !== 'sampler2D' && uniform.typeInfo.baseType !== 'storage') { |
| 460 | return `hooks.${node.identifier}`; |
| 461 | } |
| 462 | |
| 463 | return node.identifier; |
| 464 | case NodeType.OPERATION: |
| 465 | const useParantheses = node.usedBy.length > 0; |
| 466 | if (node.opCode === OpCode.Nary.CONSTRUCTOR) { |
| 467 | // TODO: differentiate casts and constructors for more efficient codegen. |
| 468 | // if (node.dependsOn.length === 1 && node.dimension === 1) { |
| 469 | // return this.generateExpression(generationContext, dag, node.dependsOn[0]); |
| 470 | // } |
| 471 | if (node.baseType === BaseType.SAMPLER2D) { |
| 472 | return this.generateExpression(generationContext, dag, node.dependsOn[0]); |
| 473 | } |
| 474 | const T = this.getTypeName(node.baseType, node.dimension); |
| 475 | const deps = node.dependsOn.map((dep) => this.generateExpression(generationContext, dag, dep)); |
| 476 | return `${T}(${deps.join(', ')})`; |
| 477 | } |
| 478 | if (node.opCode === OpCode.Nary.TERNARY) { |
| 479 | const [condID, trueID, falseID] = node.dependsOn; |
| 480 | const cond = this.generateExpression(generationContext, dag, condID); |
| 481 | const trueExpr = this.generateExpression(generationContext, dag, trueID); |
| 482 | const falseExpr = this.generateExpression(generationContext, dag, falseID); |
| 483 | return `select(${falseExpr}, ${trueExpr}, ${cond})`; |
| 484 | } |
nothing calls this directly
no test coverage detected