From 4604181da7282fec803c9755dd03deb5bdd800b1 Mon Sep 17 00:00:00 2001 From: Dave Pagurek Date: Sun, 21 Jun 2026 15:40:52 -0400 Subject: [PATCH] Fix object returns in p5.strands hooks --- src/strands/ir_builders.js | 28 +++++------------- src/webgl/strands_glslBackend.js | 2 +- src/webgpu/strands_wgslBackend.js | 2 +- test/unit/visual/cases/webgl.js | 19 ++++++++++++ test/unit/visual/cases/webgpu.js | 19 ++++++++++++ .../000.png | Bin 0 -> 263 bytes .../metadata.json | 3 ++ .../000.png | Bin 0 -> 263 bytes .../metadata.json | 3 ++ 9 files changed, 53 insertions(+), 23 deletions(-) create mode 100644 test/unit/visual/screenshots/WebGL/p5.strands/hook returning a fresh struct (not the struct argument) applies modifications/000.png create mode 100644 test/unit/visual/screenshots/WebGL/p5.strands/hook returning a fresh struct (not the struct argument) applies modifications/metadata.json create mode 100644 test/unit/visual/screenshots/WebGPU/Shaders/hook returning a fresh struct (not the struct argument) applies modifications/000.png create mode 100644 test/unit/visual/screenshots/WebGPU/Shaders/hook returning a fresh struct (not the struct argument) applies modifications/metadata.json diff --git a/src/strands/ir_builders.js b/src/strands/ir_builders.js index 4ae69d90f4..0c4b139d75 100644 --- a/src/strands/ir_builders.js +++ b/src/strands/ir_builders.js @@ -344,38 +344,24 @@ export function castToFloat(strandsContext, dep) { return createStrandsNode(id, dimension, strandsContext); } -export function structConstructorNode(strandsContext, structTypeInfo, rawUserArgs) { +export function structConstructorNode(strandsContext, structTypeInfo, dependsOn) { const { cfg, dag } = strandsContext; - const { identifer, properties } = structTypeInfo; + const { properties } = structTypeInfo; - if (!(rawUserArgs.length === properties.length)) { + if (dependsOn.length !== properties.length) { FES.userError('type error', - `You've tried to construct a ${structTypeInfo.typeName} struct with ${rawUserArgs.length} properties, but it expects ${properties.length} properties.\n` + + `You've tried to construct a ${structTypeInfo.typeName} struct with ${dependsOn.length} properties, but it expects ${properties.length} properties.\n` + `The properties it expects are:\n` + - `${properties.map(prop => prop.name + ' ' + prop.DataType.baseType + prop.DataType.dimension)}` + `${properties.map(prop => `${prop.name}: ${prop.dataType.baseType}${prop.dataType.dimension}`).join(', ')}` ); } - const dependsOn = []; - for (let i = 0; i < properties.length; i++) { - const expectedProperty = properties[i]; - const { originalNodeID, mappedDependencies } = mapPrimitiveDepsToIDs(strandsContext, expectedProperty.dataType, rawUserArgs[i]); - if (originalNodeID) { - dependsOn.push(originalNodeID); - } - else { - dependsOn.push( - constructTypeFromIDs(strandsContext, expectedProperty.dataType, mappedDependencies) - ); - } - } - const nodeData = DAG.createNodeData({ nodeType: NodeType.OPERATION, opCode: OpCode.Nary.CONSTRUCTOR, dimension: properties.length, - baseType: structTypeInfo.typeName , - dependsOn + baseType: structTypeInfo.typeName, + dependsOn, }); const id = DAG.getOrCreateNode(dag, nodeData); CFG.recordInBasicBlock(cfg, cfg.currentBlock, id); diff --git a/src/webgl/strands_glslBackend.js b/src/webgl/strands_glslBackend.js index bbd05a5950..75bd44a2c1 100644 --- a/src/webgl/strands_glslBackend.js +++ b/src/webgl/strands_glslBackend.js @@ -249,7 +249,7 @@ export const glslBackend = { } const dag = strandsContext.dag; const rootNode = getNodeDataFromID(dag, rootNodeID); - if (isStructType(returnType)) { + if (isStructType(returnType) && rootNode.identifier) { const structTypeInfo = returnType; for (let i = 0; i < structTypeInfo.properties.length; i++) { const prop = structTypeInfo.properties[i]; diff --git a/src/webgpu/strands_wgslBackend.js b/src/webgpu/strands_wgslBackend.js index 79d0f2816b..0ba1c29772 100644 --- a/src/webgpu/strands_wgslBackend.js +++ b/src/webgpu/strands_wgslBackend.js @@ -410,7 +410,7 @@ export const wgslBackend = { } const dag = strandsContext.dag; const rootNode = getNodeDataFromID(dag, rootNodeID); - if (isStructType(returnType)) { + if (isStructType(returnType) && rootNode.identifier) { const structTypeInfo = returnType; for (let i = 0; i < structTypeInfo.properties.length; i++) { const prop = structTypeInfo.properties[i]; diff --git a/test/unit/visual/cases/webgl.js b/test/unit/visual/cases/webgl.js index 5d6b19e609..987ac0b07b 100644 --- a/test/unit/visual/cases/webgl.js +++ b/test/unit/visual/cases/webgl.js @@ -1500,6 +1500,25 @@ visualTest('randomGaussian() in a fragment loop averages to the mean', (p5, scre p5.circle(0, 0, 30); screenshot(); }); + + visualTest('hook returning a fresh struct (not the struct argument) applies modifications', (p5, screenshot) => { + p5.createCanvas(50, 50, p5.WEBGL); + const shader = p5.baseMaterialShader().modify(() => { + p5.worldInputs.begin(); + p5.worldInputs.set({ + position: p5.worldInputs.position.add([10, 0, 0]), + normal: p5.worldInputs.normal, + texCoord: p5.worldInputs.texCoord, + color: [1, 0, 0, 1], + }); + p5.worldInputs.end(); + }, { p5 }); + p5.background(0); + p5.noStroke(); + p5.shader(shader); + p5.plane(20, 20); + screenshot(); + }); }); visualSuite('background()', function () { diff --git a/test/unit/visual/cases/webgpu.js b/test/unit/visual/cases/webgpu.js index ee9679f45c..aeb46d9afb 100644 --- a/test/unit/visual/cases/webgpu.js +++ b/test/unit/visual/cases/webgpu.js @@ -364,6 +364,25 @@ visualSuite("WebGPU", function () { p5.plane(50, 50); await screenshot(); }); + + visualTest('hook returning a fresh struct (not the struct argument) applies modifications', async function(p5, screenshot) { + await p5.createCanvas(50, 50, p5.WEBGPU); + const shader = p5.baseMaterialShader().modify(() => { + p5.worldInputs.begin(); + p5.worldInputs.set({ + position: p5.worldInputs.position.add([10, 0, 0]), + normal: p5.worldInputs.normal, + texCoord: p5.worldInputs.texCoord, + color: [1, 0, 0, 1], + }); + p5.worldInputs.end(); + }, { p5 }); + p5.background(0); + p5.noStroke(); + p5.shader(shader); + p5.plane(20, 20); + await screenshot(); + }, { focus: true }); }); visualTest('randomGaussian() colors a basic shader (WebGPU)', async function(p5, screenshot) { diff --git a/test/unit/visual/screenshots/WebGL/p5.strands/hook returning a fresh struct (not the struct argument) applies modifications/000.png b/test/unit/visual/screenshots/WebGL/p5.strands/hook returning a fresh struct (not the struct argument) applies modifications/000.png new file mode 100644 index 0000000000000000000000000000000000000000..b4cb0984a7e724cf60e2d93d84e65d587e94f98d GIT binary patch literal 263 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=1|;R|J2nETJ)SO(Ar*{oraSUADDbdc{Qp1l z;~BMO2ZB^5A6U9Ex9k{qy5`ec5A7VY`u@u|)tpsyGe}Z8us)UPwyl`*-4{N+5{8X$ z<+>;4l`K1^>Xx=&SfpFk@yer{rcGzmtgQHzn-a1(l~?{aTGYd#u~M~X$s_U8hDr;T zOf#6&6|Zx=qhV6iArGy(jWwMU7wgTde7)nD4(FvDQxT4&1}hUGW#=FFW*?4EQ0X~y zr$Ny8!H0^TmWeZ^4U*Vo;4l`K1^>Xx=&SfpFk@yer{rcGzmtgQHzn-a1(l~?{aTGYd#u~M~X$s_U8hDr;T zOf#6&6|Zx=qhV6iArGy(jWwMU7wgTde7)nD4(FvDQxT4&1}hUGW#=FFW*?4EQ0X~y zr$Ny8!H0^TmWeZ^4U*Vo