diff --git a/src/math/Matrices/Matrix.js b/src/math/Matrices/Matrix.js index e7d9748904..18545759bb 100644 --- a/src/math/Matrices/Matrix.js +++ b/src/math/Matrices/Matrix.js @@ -23,6 +23,9 @@ if (typeof Float32Array !== 'undefined') { export class Matrix extends MatrixInterface { matrix; #sqDimention; + // Duck-typing flag (like isVector / isColor) so code such as + // p5.Shader.setUniform can recognize a p5.Matrix without instanceof + isMatrix = true; constructor(...args) { super(...args); diff --git a/src/strands/strands_api.js b/src/strands/strands_api.js index 2ebbde4168..efe4639b33 100644 --- a/src/strands/strands_api.js +++ b/src/strands/strands_api.js @@ -934,6 +934,9 @@ export function initGlobalStrandsAPI(p5, fn, strandsContext) { typeAliases.push('Texture'); } else if (/^vec/.test(typeInfo.fnName)) { typeAliases.push(pascalTypeName.replace('Vec', 'Vector')); + } else if (/^mat\dx\d$/.test(typeInfo.fnName)) { + // mat3x3 -> Mat3, so uniformMat3() works alongside uniformMat3x3() + typeAliases.push(pascalTypeName.slice(0, 4)); } } augmentFn( diff --git a/src/webgl/p5.Shader.js b/src/webgl/p5.Shader.js index 68dbba20bf..ef055744d4 100644 --- a/src/webgl/p5.Shader.js +++ b/src/webgl/p5.Shader.js @@ -1164,6 +1164,8 @@ class Shader { : data.values; } else if (data?.isColor) { data = data._getRGBA([1, 1, 1, 1]); + } else if (data?.isMatrix) { + data = data.matrix; } if (uniform.isArray) { diff --git a/test/unit/webgl/p5.Shader.js b/test/unit/webgl/p5.Shader.js index ec3c0c8d28..dce8456271 100644 --- a/test/unit/webgl/p5.Shader.js +++ b/test/unit/webgl/p5.Shader.js @@ -3815,6 +3815,60 @@ suite('p5.Shader', function () { ); }).not.toThrow(); }); + + + suite('matrix uniforms (#8992)', () => { + test('short aliases declare the same uniforms as the NxN names', () => { + myp5.createCanvas(5, 5, myp5.WEBGL); + const testShader = myp5.baseMaterialShader().modify( + () => { + myp5.uniformMat2('uShort2'); + myp5.uniformMat3('uShort3'); + myp5.uniformMat4('uShort4'); + myp5.uniformMat3x3('uLong3'); + }, + { myp5 } + ); + + expect(() => { + myp5.shader(testShader); + myp5.plane(myp5.width, myp5.height); + }).not.toThrowError(); + + const src = testShader.fragSrc(); + assert.include(src, 'uniform mat2x2 uShort2;'); + assert.include(src, 'uniform mat3x3 uShort3;'); + assert.include(src, 'uniform mat4x4 uShort4;'); + assert.include(src, 'uniform mat3x3 uLong3;'); + }); + + test('setUniform accepts a p5.Matrix', () => { + myp5.createCanvas(50, 50, myp5.WEBGL); + const testShader = myp5.createFilterShader(` + precision highp float; + uniform mat3 uM; + void main() { + gl_FragColor = vec4(uM[0][0], uM[1][0], uM[2][2], 1.0); + } + `); + + // Column-major: index 3 is column 1, row 0 -> uM[1][0] + const m = myp5.createMatrix([ + 1.0, 0.0, 0.0, + 0.5, 0.0, 0.0, + 0.0, 0.0, 0.25 + ]); + + myp5.background(0); + testShader.setUniform('uM', m); + myp5.filter(testShader); + + const pixelColor = myp5.get(25, 25); + assert.approximately(pixelColor[0], 255, 5); // uM[0][0] = 1.0 + assert.approximately(pixelColor[1], 128, 5); // uM[1][0] = 0.5 + assert.approximately(pixelColor[2], 64, 5); // uM[2][2] = 0.25 + }); + }); }); suite('p5.strands error messages', () => { diff --git a/test/unit/webgpu/p5.Shader.js b/test/unit/webgpu/p5.Shader.js index 4003152397..aaa86639ce 100644 --- a/test/unit/webgpu/p5.Shader.js +++ b/test/unit/webgpu/p5.Shader.js @@ -2145,5 +2145,26 @@ suite('WebGPU p5.Shader', function () { }).not.toThrow(); }); }); + + suite('matrix uniforms (#8992)', () => { + test('short aliases declare the same uniforms as the NxN names', async () => { + await myp5.createCanvas(5, 5, myp5.WEBGPU); + const testShader = myp5.baseMaterialShader().modify( + () => { + myp5.uniformMat2('uShort2'); + myp5.uniformMat3('uShort3'); + myp5.uniformMat4('uShort4'); + myp5.uniformMat3x3('uLong3'); + }, + { myp5 } + ); + + const src = testShader.vertSrc(); + assert.include(src, 'uShort2: mat2x2'); + assert.include(src, 'uShort3: mat3x3'); + assert.include(src, 'uShort4: mat4x4'); + assert.include(src, 'uLong3: mat3x3'); + }); + }); }); }); diff --git a/utils/typescript.mjs b/utils/typescript.mjs index e0a850e3d7..919d1f9a17 100644 --- a/utils/typescript.mjs +++ b/utils/typescript.mjs @@ -134,6 +134,9 @@ function processStrandsFunctions() { typeAliases.push('Texture'); } else if (/^vec/.test(typeInfo.fnName)) { typeAliases.push(pascalTypeName.replace('Vec', 'Vector')); + } else if (/^mat\dx\d$/.test(typeInfo.fnName)) { + // mat3x3 -> Mat3, so uniformMat3() works alongside uniformMat3x3() + typeAliases.push(pascalTypeName.slice(0, 4)); } }