From 6039cb14121cd38fb330180fc21d474e1572134b Mon Sep 17 00:00:00 2001 From: Yukti Nandwana Date: Sun, 5 Apr 2026 15:38:49 +0530 Subject: [PATCH 1/3] feat(webgl): add texCoord parameter to getFinalColor hook --- src/webgl/p5.RendererGL.js | 8 ++++---- src/webgl/p5.Shader.js | 2 +- src/webgl/shaders/basic.frag | 5 +++-- src/webgl/shaders/line.frag | 2 +- src/webgl/shaders/normal.frag | 5 +++-- src/webgl/shaders/phong.frag | 2 +- src/webgpu/p5.RendererWebGPU.js | 6 +++--- src/webgpu/shaders/color.js | 2 +- src/webgpu/shaders/line.js | 2 +- src/webgpu/shaders/material.js | 2 +- 10 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/webgl/p5.RendererGL.js b/src/webgl/p5.RendererGL.js index b744baff19..edd4f9969b 100644 --- a/src/webgl/p5.RendererGL.js +++ b/src/webgl/p5.RendererGL.js @@ -723,7 +723,7 @@ class RendererGL extends Renderer3D { color.a = components.opacity; return color; }`, - "vec4 getFinalColor": "(vec4 color) { return color; }", + "vec4 getFinalColor": "(vec4 color, vec2 texCoord) { return color; }", "void afterFragment": "() {}", }, } @@ -760,7 +760,7 @@ class RendererGL extends Renderer3D { }, fragment: { "void beforeFragment": "() {}", - "vec4 getFinalColor": "(vec4 color) { return color; }", + "vec4 getFinalColor": "(vec4 color, vec2 texCoord) { return color; }", "void afterFragment": "() {}", }, } @@ -788,7 +788,7 @@ class RendererGL extends Renderer3D { }, fragment: { "void beforeFragment": "() {}", - "vec4 getFinalColor": "(vec4 color) { return color; }", + "vec4 getFinalColor": "(vec4 color, vec2 texCoord) { return color; }", "void afterFragment": "() {}", }, } @@ -820,7 +820,7 @@ class RendererGL extends Renderer3D { fragment: { "void beforeFragment": "() {}", "Inputs getPixelInputs": "(Inputs inputs) { return inputs; }", - "vec4 getFinalColor": "(vec4 color) { return color; }", + "vec4 getFinalColor": "(vec4 color, vec2 texCoord) { return color; }", "bool shouldDiscard": "(bool outside) { return outside; }", "void afterFragment": "() {}", }, diff --git a/src/webgl/p5.Shader.js b/src/webgl/p5.Shader.js index a881825948..753c5180bd 100644 --- a/src/webgl/p5.Shader.js +++ b/src/webgl/p5.Shader.js @@ -172,7 +172,7 @@ class Shader { * color.a = components.opacity; * return color; * } - * vec4 getFinalColor(vec4 color) { return color; } + * vec4 getFinalColor(vec4 color, vec2 texCoord) { return color; } * void afterFragment() {} * ``` * diff --git a/src/webgl/shaders/basic.frag b/src/webgl/shaders/basic.frag index 1406964ca9..b7db52b1ad 100644 --- a/src/webgl/shaders/basic.frag +++ b/src/webgl/shaders/basic.frag @@ -1,7 +1,8 @@ IN vec4 vColor; +IN highp vec2 vVertTexCoord; void main(void) { HOOK_beforeFragment(); - OUT_COLOR = HOOK_getFinalColor(vColor); + OUT_COLOR = HOOK_getFinalColor(vColor, vVertTexCoord); OUT_COLOR.rgb *= OUT_COLOR.a; // Premultiply alpha before rendering HOOK_afterFragment(); -} +} \ No newline at end of file diff --git a/src/webgl/shaders/line.frag b/src/webgl/shaders/line.frag index a0ca059040..b1ed298b0d 100644 --- a/src/webgl/shaders/line.frag +++ b/src/webgl/shaders/line.frag @@ -69,6 +69,6 @@ void main() { discard; } } - OUT_COLOR = HOOK_getFinalColor(vec4(inputs.color.rgb, 1.) * inputs.color.a); + OUT_COLOR = HOOK_getFinalColor(vec4(inputs.color.rgb, 1.) * inputs.color.a, vec2(0.0, 0.0)); HOOK_afterFragment(); } diff --git a/src/webgl/shaders/normal.frag b/src/webgl/shaders/normal.frag index 0cb362265a..fbb9258547 100644 --- a/src/webgl/shaders/normal.frag +++ b/src/webgl/shaders/normal.frag @@ -1,6 +1,7 @@ IN vec3 vVertexNormal; +IN highp vec2 vVertTexCoord; void main(void) { HOOK_beforeFragment(); - OUT_COLOR = HOOK_getFinalColor(vec4(vVertexNormal, 1.0)); + OUT_COLOR = HOOK_getFinalColor(vec4(vVertexNormal, 1.0), vVertTexCoord); HOOK_afterFragment(); -} +} \ No newline at end of file diff --git a/src/webgl/shaders/phong.frag b/src/webgl/shaders/phong.frag index 78cfb76163..47ec519d47 100644 --- a/src/webgl/shaders/phong.frag +++ b/src/webgl/shaders/phong.frag @@ -77,7 +77,7 @@ void main(void) { c.ambient = inputs.ambientLight; c.specular = specular; c.emissive = inputs.emissiveMaterial; - OUT_COLOR = HOOK_getFinalColor(HOOK_combineColors(c)); + OUT_COLOR = HOOK_getFinalColor(HOOK_combineColors(c), vTexCoord); OUT_COLOR.rgb *= OUT_COLOR.a; // Premultiply alpha before rendering HOOK_afterFragment(); } diff --git a/src/webgpu/p5.RendererWebGPU.js b/src/webgpu/p5.RendererWebGPU.js index 2b616e4a63..b52d0dc599 100644 --- a/src/webgpu/p5.RendererWebGPU.js +++ b/src/webgpu/p5.RendererWebGPU.js @@ -2345,7 +2345,7 @@ function rendererWebGPU(p5, fn) { rgb += components.emissive; return vec4(rgb, components.opacity); }`, - "vec4f getFinalColor": "(color: vec4) { return color; }", + "vec4f getFinalColor": "(color: vec4, texCoord: vec2) { return color; }", "void afterFragment": "() {}", }, } @@ -2370,7 +2370,7 @@ function rendererWebGPU(p5, fn) { }, fragment: { "void beforeFragment": "() {}", - "vec4 getFinalColor": "(color: vec4) { return color; }", + "vec4 getFinalColor": "(color: vec4, texCoord: vec2) { return color; }", "void afterFragment": "() {}", }, } @@ -2396,7 +2396,7 @@ function rendererWebGPU(p5, fn) { fragment: { "void beforeFragment": "() {}", "Inputs getPixelInputs": "(inputs: Inputs) { return inputs; }", - "vec4 getFinalColor": "(color: vec4) { return color; }", + "vec4 getFinalColor": "(color: vec4, texCoord: vec2) { return color; }", "bool shouldDiscard": "(outside: bool) { return outside; };", "void afterFragment": "() {}", }, diff --git a/src/webgpu/shaders/color.js b/src/webgpu/shaders/color.js index cea80efc9b..cf4ab00285 100644 --- a/src/webgpu/shaders/color.js +++ b/src/webgpu/shaders/color.js @@ -119,7 +119,7 @@ ${uniforms} @fragment fn main(input: FragmentInput) -> @location(0) vec4 { HOOK_beforeFragment(); - var outColor = HOOK_getFinalColor(input.vColor); + var outColor = HOOK_getFinalColor(input.vColor, input.vVertTexCoord); outColor = vec4(outColor.rgb * outColor.a, outColor.a); HOOK_afterFragment(); return outColor; diff --git a/src/webgpu/shaders/line.js b/src/webgpu/shaders/line.js index a46317cee6..2b58857286 100644 --- a/src/webgpu/shaders/line.js +++ b/src/webgpu/shaders/line.js @@ -362,7 +362,7 @@ fn main(input: StrokeFragmentInput) -> @location(0) vec4 { discard; } } - var col = HOOK_getFinalColor(inputs.color); + var col = HOOK_getFinalColor(inputs.color, vec2(0.0, 0.0)); col = vec4(col.rgb, 1.0) * col.a; HOOK_afterFragment(); return vec4(col); diff --git a/src/webgpu/shaders/material.js b/src/webgpu/shaders/material.js index a740e9d17a..9da60f4628 100644 --- a/src/webgpu/shaders/material.js +++ b/src/webgpu/shaders/material.js @@ -417,7 +417,7 @@ fn main(input: FragmentInput) -> @location(0) vec4 { ); var outColor = HOOK_getFinalColor( - HOOK_combineColors(components) + HOOK_combineColors(components), input.vTexCoord ); outColor = vec4(outColor.rgb * outColor.a, outColor.a); HOOK_afterFragment(); From 31ad84a617f2c6de4cf3fffb3fb98f3a897d09a3 Mon Sep 17 00:00:00 2001 From: Yukti Nandwana Date: Sun, 5 Apr 2026 17:09:45 +0530 Subject: [PATCH 2/3] feat(webgl): add texCoord parameter to getFinalColor hook --- test/unit/visual/cases/webgl.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/unit/visual/cases/webgl.js b/test/unit/visual/cases/webgl.js index 7e1889674e..41420ba3cd 100644 --- a/test/unit/visual/cases/webgl.js +++ b/test/unit/visual/cases/webgl.js @@ -1134,6 +1134,21 @@ visualSuite('WebGL', function() { screenshot(); }); + visualTest('texCoord is available in getFinalColor', (p5, screenshot) => { + p5.createCanvas(50, 50, p5.WEBGL); + const shader = p5.baseColorShader().modify(() => { + getFinalColor((color) => { + color = [texCoord[0], texCoord[1], 0, 1]; + return color; + }); + }); + p5.background(0); + p5.shader(shader); + p5.noStroke(); + p5.plane(50, 50); + screenshot(); +}); + visualSuite('auto-return for shader hooks', () => { visualTest('auto-returns input struct when return is omitted', (p5, screenshot) => { p5.createCanvas(50, 50, p5.WEBGL); From cd2e29fc0560ec92197ae3ebc43ec03c2101340e Mon Sep 17 00:00:00 2001 From: Yukti Nandwana Date: Fri, 10 Apr 2026 21:22:46 +0530 Subject: [PATCH 3/3] test: update hook signatures in framebuffer and missing frag files --- src/webgpu/shaders/material.js | 6 ++--- test/unit/visual/cases/webgl.js | 23 +++++++++--------- .../000.png | Bin 0 -> 390 bytes .../metadata.json | 3 +++ test/unit/webgl/p5.Shader.js | 2 +- 5 files changed, 18 insertions(+), 16 deletions(-) create mode 100644 test/unit/visual/screenshots/WebGL/p5.strands/texCoord is available in getFinalColor/000.png create mode 100644 test/unit/visual/screenshots/WebGL/p5.strands/texCoord is available in getFinalColor/metadata.json diff --git a/src/webgpu/shaders/material.js b/src/webgpu/shaders/material.js index 9da60f4628..751ec0ad3a 100644 --- a/src/webgpu/shaders/material.js +++ b/src/webgpu/shaders/material.js @@ -416,9 +416,9 @@ fn main(input: FragmentInput) -> @location(0) vec4 { inputs.emissiveMaterial ); - var outColor = HOOK_getFinalColor( - HOOK_combineColors(components), input.vTexCoord - ); + var outColor = HOOK_getFinalColor( + HOOK_combineColors(components), input.vTexCoord + ); outColor = vec4(outColor.rgb * outColor.a, outColor.a); HOOK_afterFragment(); return outColor; diff --git a/test/unit/visual/cases/webgl.js b/test/unit/visual/cases/webgl.js index 41420ba3cd..0941c769cf 100644 --- a/test/unit/visual/cases/webgl.js +++ b/test/unit/visual/cases/webgl.js @@ -1135,19 +1135,18 @@ visualSuite('WebGL', function() { }); visualTest('texCoord is available in getFinalColor', (p5, screenshot) => { - p5.createCanvas(50, 50, p5.WEBGL); - const shader = p5.baseColorShader().modify(() => { - getFinalColor((color) => { - color = [texCoord[0], texCoord[1], 0, 1]; - return color; + p5.createCanvas(50, 50, p5.WEBGL); + const shader = p5.baseColorShader().modify(() => { + p5.finalColor.begin(); + p5.finalColor.set([p5.finalColor.texCoord, 0, 1]); + p5.finalColor.end(); + }, { p5 }); + p5.background(0); + p5.shader(shader); + p5.noStroke(); + p5.plane(50, 50); + screenshot(); }); - }); - p5.background(0); - p5.shader(shader); - p5.noStroke(); - p5.plane(50, 50); - screenshot(); -}); visualSuite('auto-return for shader hooks', () => { visualTest('auto-returns input struct when return is omitted', (p5, screenshot) => { diff --git a/test/unit/visual/screenshots/WebGL/p5.strands/texCoord is available in getFinalColor/000.png b/test/unit/visual/screenshots/WebGL/p5.strands/texCoord is available in getFinalColor/000.png new file mode 100644 index 0000000000000000000000000000000000000000..460f144e680fdec5c424ba6a89b6d18b8220d1f3 GIT binary patch literal 390 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=1|;R|J2o;fFj{-MIEGX(zPY*3*fmh#_{X`Q z+X6*gfoLL_3>5Li$~8Rv{SR~gu{XDOT3he`;F*7J-|pYm#pm}H-_A(cZ#?6u%(IOR zt~!a5+7U;ku5E1e%}JEDzHwCUTVaE<%tHxvi=&d~3LCv+9!i<-I4b+@V}rZRLrMLL zqtf?2Hu~2*l(x?>OAT{eeZl3uWA7KultnH^OE0c>?F2G|G$v*mYcEK>B{wfSPF&M+_BY5C27^XSzbqs_rln%LYg1;-J9>nrMl=m z*R)r=y*}U3G+G;~JoD0v>x*1|i5O{4@i;g6@BR1xTZJy3%(J?w{H{!Q(F+07t0x44 z<-gDOO1V?g_Tw!-1H=FS>vsRD0fr_UC>WU;VlUMMu|JQ_1&T0uy85}Sb4q9e0JnOj A;s5{u literal 0 HcmV?d00001 diff --git a/test/unit/visual/screenshots/WebGL/p5.strands/texCoord is available in getFinalColor/metadata.json b/test/unit/visual/screenshots/WebGL/p5.strands/texCoord is available in getFinalColor/metadata.json new file mode 100644 index 0000000000..2d4bfe30da --- /dev/null +++ b/test/unit/visual/screenshots/WebGL/p5.strands/texCoord is available in getFinalColor/metadata.json @@ -0,0 +1,3 @@ +{ + "numScreenshots": 1 +} \ No newline at end of file diff --git a/test/unit/webgl/p5.Shader.js b/test/unit/webgl/p5.Shader.js index 24c23fe548..1e307f51cc 100644 --- a/test/unit/webgl/p5.Shader.js +++ b/test/unit/webgl/p5.Shader.js @@ -318,7 +318,7 @@ suite('p5.Shader', function() { uniforms: { 'sampler2D myTex': null }, - 'vec4 getFinalColor': `(vec4 c) { + 'vec4 getFinalColor': `(vec4 c, vec2 texCoord) { return getTexture(myTex, vec2(0.,0.)); }` });