Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 24 additions & 9 deletions src/strands/strands_api.js
Original file line number Diff line number Diff line change
Expand Up @@ -404,35 +404,50 @@
CFG.pushBlock(cfg, entryBlockID);
const args = createHookArguments(strandsContext, hookType.parameters);
const userReturned = hookUserCallback(...args);

// Auto-return input if types match and user didn't return anything
let effectiveReturn = userReturned;
if (userReturned === undefined) {
const expected = hookType.returnType;
if (isStructType(expected.typeName)) {
if (hookType.parameters.length === 1) {
const paramType = hookType.parameters[0].type.typeName;
if (paramType === expected.typeName) {
effectiveReturn = args[0];
}
}
}
}

const expectedReturnType = hookType.returnType;
let rootNodeID = null;
if(isStructType(expectedReturnType)) {
const expectedStructType = structType(expectedReturnType);
if (userReturned instanceof StrandsNode) {
const returnedNode = getNodeDataFromID(strandsContext.dag, userReturned.id);
if (effectiveReturn instanceof StrandsNode) {
const returnedNode = getNodeDataFromID(strandsContext.dag, effectiveReturn.id);
if (returnedNode.baseType !== expectedStructType.typeName) {
FES.userError("type error", `You have returned a ${userReturned.baseType} from ${hookType.name} when a ${expectedStructType.typeName} was expected.`);
FES.userError("type error", `You have returned a ${effectiveReturn.baseType} from ${hookType.name} when a ${expectedStructType.typeName} was expected.`);
}
const newDeps = returnedNode.dependsOn.slice();
for (let i = 0; i < expectedStructType.properties.length; i++) {
const expectedType = expectedStructType.properties[i].dataType;
const receivedNode = createStrandsNode(returnedNode.dependsOn[i], dag.dependsOn[userReturned.id], strandsContext);
const receivedNode = createStrandsNode(returnedNode.dependsOn[i], dag.dependsOn[effectiveReturn.id], strandsContext);
newDeps[i] = enforceReturnTypeMatch(strandsContext, expectedType, receivedNode, hookType.name);
}
dag.dependsOn[userReturned.id] = newDeps;
rootNodeID = userReturned.id;
dag.dependsOn[effectiveReturn.id] = newDeps;
rootNodeID = effectiveReturn.id;
}
else {
const expectedProperties = expectedStructType.properties;
const newStructDependencies = [];
for (let i = 0; i < expectedProperties.length; i++) {
const expectedProp = expectedProperties[i];
const propName = expectedProp.name;
const receivedValue = userReturned[propName];
const receivedValue = effectiveReturn[propName];

Check failure on line 446 in src/strands/strands_api.js

View workflow job for this annotation

GitHub Actions / test (ubuntu-latest, chrome)

test/unit/visual/cases/webgl.js > WebGL > p5.strands > auto-return for shader hooks > auto-return works with getPixelInputs > matches expected screenshots

TypeError: Cannot read properties of undefined (reading 'normal') ❯ p5.hookImplementation src/strands/strands_api.js:446:50 ❯ eval src/strands/strands_transpiler.js:1078:39 ❯ src/strands/strands_transpiler.js:1087:20 ❯ p5.Shader.modify src/strands/p5.strands.js:114:9 ❯ test/unit/visual/cases/webgl.js:1023:48 ❯ test/unit/visual/visualTest.js:432:13

Check failure on line 446 in src/strands/strands_api.js

View workflow job for this annotation

GitHub Actions / test (ubuntu-latest, chrome)

test/unit/visual/cases/webgl.js > WebGL > p5.strands > auto-return for shader hooks > auto-return preserves multiple property modifications > matches expected screenshots

TypeError: Cannot read properties of undefined (reading 'position') ❯ p5.hookImplementation src/strands/strands_api.js:446:50 ❯ eval src/strands/strands_transpiler.js:1078:39 ❯ src/strands/strands_transpiler.js:1087:20 ❯ p5.Shader.modify src/strands/p5.strands.js:114:9 ❯ test/unit/visual/cases/webgl.js:1003:48 ❯ test/unit/visual/visualTest.js:432:13

Check failure on line 446 in src/strands/strands_api.js

View workflow job for this annotation

GitHub Actions / test (ubuntu-latest, chrome)

test/unit/visual/cases/webgl.js > WebGL > p5.strands > auto-return for shader hooks > auto-return works with getCameraInputs > matches expected screenshots

TypeError: Cannot read properties of undefined (reading 'position') ❯ p5.hookImplementation src/strands/strands_api.js:446:50 ❯ eval src/strands/strands_transpiler.js:1078:39 ❯ src/strands/strands_transpiler.js:1087:20 ❯ p5.Shader.modify src/strands/p5.strands.js:114:9 ❯ test/unit/visual/cases/webgl.js:984:48 ❯ test/unit/visual/visualTest.js:432:13

Check failure on line 446 in src/strands/strands_api.js

View workflow job for this annotation

GitHub Actions / test (ubuntu-latest, chrome)

test/unit/visual/cases/webgl.js > WebGL > p5.strands > auto-return for shader hooks > auto-return works with getObjectInputs > matches expected screenshots

TypeError: Cannot read properties of undefined (reading 'position') ❯ p5.hookImplementation src/strands/strands_api.js:446:50 ❯ eval src/strands/strands_transpiler.js:1078:39 ❯ src/strands/strands_transpiler.js:1087:20 ❯ p5.Shader.modify src/strands/p5.strands.js:114:9 ❯ test/unit/visual/cases/webgl.js:965:48 ❯ test/unit/visual/visualTest.js:432:13

Check failure on line 446 in src/strands/strands_api.js

View workflow job for this annotation

GitHub Actions / test (ubuntu-latest, chrome)

test/unit/visual/cases/webgl.js > WebGL > p5.strands > auto-return for shader hooks > auto-returns input struct when return is omitted > matches expected screenshots

TypeError: Cannot read properties of undefined (reading 'position') ❯ p5.hookImplementation src/strands/strands_api.js:446:50 ❯ eval src/strands/strands_transpiler.js:1078:39 ❯ src/strands/strands_transpiler.js:1087:20 ❯ p5.Shader.modify src/strands/p5.strands.js:114:9 ❯ test/unit/visual/cases/webgl.js:935:48 ❯ test/unit/visual/visualTest.js:432:13
if (receivedValue === undefined) {
FES.userError('type error', `You've returned an incomplete struct from ${hookType.name}.\n` +
`Expected: { ${expectedReturnType.properties.map(p => p.name).join(', ')} }\n` +
`Received: { ${Object.keys(userReturned).join(', ')} }\n` +
`Received: { ${Object.keys(effectiveReturn).join(', ')} }\n` +
`All of the properties are required!`);
}
const expectedTypeInfo = expectedProp.dataType;
Expand All @@ -448,7 +463,7 @@
throw new Error(`Missing dataType for return type ${expectedReturnType.typeName}`);
}
const expectedTypeInfo = expectedReturnType.dataType;
rootNodeID = enforceReturnTypeMatch(strandsContext, expectedTypeInfo, userReturned, hookType.name);
rootNodeID = enforceReturnTypeMatch(strandsContext, expectedTypeInfo, effectiveReturn, hookType.name);
}
const fullHookName = `${hookType.returnType.typeName} ${hookType.name}`;
const hookInfo = availableHooks[fullHookName];
Expand Down
105 changes: 105 additions & 0 deletions test/unit/visual/cases/webgl.js
Original file line number Diff line number Diff line change
Expand Up @@ -928,6 +928,111 @@ visualSuite('WebGL', function() {
p5.circle(p5.noise(0), p5.noise(0), 20);
screenshot();
});

visualSuite('auto-return for shader hooks', () => {
visualTest('auto-returns input struct when return is omitted', (p5, screenshot) => {
p5.createCanvas(50, 50, p5.WEBGL);
const shader = p5.baseMaterialShader().modify(() => {
p5.getWorldInputs((inputs) => {
inputs.position.x += 10;
// No explicit return - should auto-return inputs
});
}, { p5 });
p5.background(255);
p5.noStroke();
p5.shader(shader);
p5.sphere(20);
screenshot();
});

visualTest('explicit return still works', (p5, screenshot) => {
p5.createCanvas(50, 50, p5.WEBGL);
const shader = p5.baseMaterialShader().modify(() => {
p5.getWorldInputs((inputs) => {
inputs.position.x += 10;
return inputs; // Explicit return should still work
});
}, { p5 });
p5.background(255);
p5.noStroke();
p5.shader(shader);
p5.sphere(20);
screenshot();
});

visualTest('auto-return works with getObjectInputs', (p5, screenshot) => {
p5.createCanvas(50, 50, p5.WEBGL);
const shader = p5.baseMaterialShader().modify(() => {
p5.getObjectInputs((inputs) => {
inputs.position.x += 0.25;
// No explicit return
});
}, { p5 });
p5.background(255);
p5.lights();
p5.fill('red');
p5.noStroke();
p5.rotateY(p5.PI / 2);
p5.camera(-800, 0, 0, 0, 0, 0);
p5.shader(shader);
p5.sphere(20);
screenshot();
});

visualTest('auto-return works with getCameraInputs', (p5, screenshot) => {
p5.createCanvas(50, 50, p5.WEBGL);
const shader = p5.baseMaterialShader().modify(() => {
p5.getCameraInputs((inputs) => {
inputs.position.x += 10;
// No explicit return
});
}, { p5 });
p5.background(255);
p5.lights();
p5.fill('red');
p5.noStroke();
p5.rotateY(p5.PI / 2);
p5.camera(-800, 0, 0, 0, 0, 0);
p5.shader(shader);
p5.sphere(20);
screenshot();
});

visualTest('auto-return preserves multiple property modifications', (p5, screenshot) => {
p5.createCanvas(50, 50, p5.WEBGL);
const shader = p5.baseMaterialShader().modify(() => {
p5.getWorldInputs((inputs) => {
inputs.position.x += 5;
inputs.position.y += 5;
inputs.normal.x += 0.5;
inputs.normal = p5.normalize(inputs.normal);
// No explicit return - all modifications should be preserved
});
}, { p5 });
p5.background(255);
p5.lights();
p5.fill('red');
p5.noStroke();
p5.shader(shader);
p5.sphere(20);
screenshot();
});

visualTest('auto-return works with getPixelInputs', (p5, screenshot) => {
p5.createCanvas(50, 50, p5.WEBGL);
const shader = p5.baseMaterialShader().modify(() => {
p5.getPixelInputs((inputs) => {
inputs.color = p5.vec4(1.0, 0.0, 0.0, 1.0); // Red
// No explicit return
});
}, { p5 });
p5.background(255);
p5.noStroke();
p5.shader(shader);
p5.circle(0, 0, 40);
screenshot();
});
});
});

visualSuite('background()', function () {
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"numScreenshots": 1
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"numScreenshots": 1
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"numScreenshots": 1
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"numScreenshots": 1
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"numScreenshots": 1
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"numScreenshots": 1
}
Loading