Skip to content

Commit

Permalink
Fix sneaky bug where emptyTexture() is changing the texture binding
Browse files Browse the repository at this point in the history
  • Loading branch information
davepagurek committed Nov 3, 2024
1 parent 2d10678 commit 3b2cac2
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 5 deletions.
6 changes: 6 additions & 0 deletions src/webgl/p5.RendererGL.js
Original file line number Diff line number Diff line change
Expand Up @@ -1974,6 +1974,12 @@ class RendererGL extends Renderer {
return code;
}

/**
* @private
* Note: DO NOT CALL THIS while in the middle of binding another texture,
* since it will change the texture binding in order to allocate the empty
* texture! Grab its value beforehand!
*/
_getEmptyTexture() {
if (!this._emptyTexture) {
// a plain white texture RGBA, full alpha, single pixel.
Expand Down
14 changes: 10 additions & 4 deletions src/webgl/p5.Shader.js
Original file line number Diff line number Diff line change
Expand Up @@ -755,13 +755,15 @@ class Shader {
bindTextures() {
const gl = this._renderer.GL;

const empty = this._renderer._getEmptyTexture();

for (const uniform of this.samplers) {
let tex = uniform.texture;
if (tex === undefined) {
// user hasn't yet supplied a texture for this slot.
// (or there may not be one--maybe just lighting),
// so we supply a default texture instead.
tex = this._renderer._getEmptyTexture();
uniform.texture = tex = empty;
}
gl.activeTexture(gl.TEXTURE0 + uniform.samplerIndex);
tex.bindTexture();
Expand All @@ -783,9 +785,11 @@ class Shader {
const gl = this._renderer.GL;
const empty = this._renderer._getEmptyTexture();
for (const uniform of this.samplers) {
gl.activeTexture(gl.TEXTURE0 + uniform.samplerIndex);
empty.bindTexture();
gl.uniform1i(uniform.location, uniform.samplerIndex);
if (uniform.texture?.isFramebufferTexture) {
gl.activeTexture(gl.TEXTURE0 + uniform.samplerIndex);
empty.bindTexture();
gl.uniform1i(uniform.location, uniform.samplerIndex);
}
}
}

Expand Down Expand Up @@ -1037,6 +1041,8 @@ class Shader {
* </div>
*/
setUniform(uniformName, data) {
this.init();

const uniform = this.uniforms[uniformName];
if (!uniform) {
return;
Expand Down
31 changes: 30 additions & 1 deletion test/unit/webgl/p5.RendererGL.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,36 @@ suite('p5.RendererGL', function() {
});

suite('texture binding', function() {
test('setting a custom texture works', function() {
myp5.createCanvas(10, 10, myp5.WEBGL);
myp5.background(255);

const myShader = myp5.baseMaterialShader().modify({
uniforms: {
'sampler2D myTex': undefined,
},
'Inputs getPixelInputs': `(Inputs inputs) {
inputs.color = texture(myTex, inputs.texCoord);
return inputs;
}`
})

// Make a red texture
const tex = myp5.createFramebuffer();
tex.draw(() => myp5.background('red'));
console.log(tex.get().canvas.toDataURL());

myp5.shader(myShader);
myp5.fill('red')
myp5.noStroke();
myShader.setUniform('myTex', tex);

myp5.rectMode(myp5.CENTER)
myp5.rect(0, 0, myp5.width, myp5.height);

// It should be red
assert.deepEqual(myp5.get(5, 5), [255, 0, 0, 255]);
})
test('textures remain bound after each draw call', function() {
myp5.createCanvas(20, 10, myp5.WEBGL);
myp5.background(255);
Expand All @@ -89,7 +119,6 @@ suite('p5.RendererGL', function() {
tex.draw(() => myp5.background('red'));

myp5.shader(myShader);
// myp5.fill('red');
myp5.noStroke();
myShader.setUniform('myTex', tex);

Expand Down

0 comments on commit 3b2cac2

Please sign in to comment.