Repository: processing/p5.js (JavaScript)

Issue:
Incorrect textureFiltering for Framebuffers
### Most appropriate sub-area of p5.js?

- [ ] Accessibility
- [ ] Color
- [X] Core/Environment/Rendering
- [ ] Data
- [ ] DOM
- [ ] Events
- [ ] Image
- [ ] IO
- [ ] Math
- [ ] Typography
- [ ] Utilities
- [X] WebGL
- [ ] Build Process
- [ ] Unit Testing
- [ ] Internalization
- [ ] Friendly Errors
- [ ] Other (specify if possible)

### p5.js version

1.7.0

### Web browser and version

Chrome 116.0.0.0

### Operating System

MacOS 13.3.1 (Ventura)

### Steps to reproduce this

### Steps:
The`textureFiltering` option of `createFramebuffer` is ignored by the renderer.

1. Create a Framebuffer smaller than the canvas, set `textureFiltering` to NEAREST.
2. Use a shader to sample the Framebuffer texture and draw it to the canvas. This will upscale it.
3. Note that the result is blurry around the outline of the circle, indicating that it was upscaled with LINEAR interpolation instead of NEAREST (see output image below)

![linear-filtering](https://github.com/processing/p5.js/assets/3796838/bb7026e9-a2e4-4b6b-83ff-ffb29bd91ee4)

### Snippet:
See [here](https://editor.p5js.org/KeyboardSounds/sketches/yff7JgZ4E) for the live sketch version.

<details>
<summary> Copy of the code in the sketch </summary>

```js

/*
p5 version: 1.7.0

This code renders a circle to a Framebuffer at a lower resolution, and then uses shaders to upscale it to a higher resolution canvas.

The texture filtering for the Framebuffer is set to NEAREST, but this seems to be ignored, and the LINEAR interpolation is used instead, as shown by the blurry output.
*/

const canvasSize = 512;
const framebufferSize = canvasSize/16;
let myShader;
let framebuffer;

let debug_log_framebuffer = true;

const vs = `
attribute vec3 aPosition;

// texture coordinates
attribute vec2 aTexCoord;

// the varying variable will pass the texture coordinate to our fragment shader
varying vec2 vTexCoord;

void main() {
  // assign attribute to varying, so it can be used in the fragment
  vTexCoord = aTexCoord;

  vec4 positionVec4 = vec4(aPosition, 1.0);
  positionVec4.xy = positionVec4.xy * 2.0 - 1.0;

  gl_Position = positionVec4;
}
  `;

// Sample the texture from the framebuffer
const fs = `
  precision mediump float;
  uniform sampler2D img;

varying vec2 vTexCoord;

void main() {
  // sample texture using coords from vertex shader
  gl_FragColor = texture2D(img, vTexCoord);
}
  `;

function setup() {
  createCanvas(canvasSize, canvasSize, WEBGL);
  // BUG: We set the texture filtering to NEAREST here, but this is is ignored at render time.
  // `noSmooth();` makes no difference, as noted in https://github.com/processing/p5.js/issues/6325
  framebuffer = createFramebuffer({
    width: framebufferSize,
    height: framebufferSize,
    textureFiltering: NEAREST,
    antialias: false
  });
  myShader = createShader(vs, fs);
  strokeWeight(2);
  stroke(0);
}

function draw() {
  // Draw the circle to the framebuffer
  resetShader();
  framebuffer.begin();
  background("cornflowerblue");
  circle(0, 0, framebufferSize / 2);
  framebuffer.end();
      
  shader(myShader);
  // BUG: inspecting the inner framebuffer color texture in the debugger shows that it's using LINEAR interpolation instead of NEAREST
  myShader.setUniform("img", framebuffer.color);
  
  // only log once, not every frame
  if(debug_log_framebuffer) {

    console.log(framebuffer.color.framebuffer.colorP5Texture)
    // The output shows that:
    //   glMinFilter: 9729
    //   glMagFilter: 9729
    // This is the WEBGL constant for Linear interpolation (hex 0x2601) 
    // (see https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Constants#textures)
    
    debug_log_framebuffer = false;
  }
  rect(0, 0, canvasSize, canvasSize);
}

```
</details>


### More Info

I took a look at the Framebuffer class, and it looks like `glMinFilter` and `glMagFilter` are being set correctly in here (but I haven't checked in a debugger yet): https://github.com/processing/p5.js/blob/f702842c3306131305df90d09cc386310e3c90eb/src/webgl/p5.Framebuffer.js#L528-L540
so I suspect they're being unexpectedly modified somewhere else.


Discussion:
If someone more familiar with the codebase could confirm this is a bug and my analysis isn't completely off-base, I'll try putting together a PR to fix it (I know it's probably very low priority because it won't affect many users, so I totally understand if this goes to the bottom of the Issue pile). 

The same bug could also be the root cause of https://github.com/processing/p5.js/issues/6325 but the comments there say otherwise, so I'm not sure.
Yep looks like you're right! I suspect the issue is that in `p5.Framebuffer.js`, it sets `gl(Min|Max)Filter` in the settings, but `p5.Texture` expects them to be called `(min|max)Filter`:
https://github.com/processing/p5.js/blob/efc4c73bb6d0a9a85f25cb12f00c6722629b6f9f/src/webgl/p5.Texture.js#L56-L59

> If someone more familiar with the codebase could confirm this is a bug and my analysis isn't completely off-base, I'll try putting together a PR to fix it 

Thanks! I'll assign this to you.
@KeyboardSounds @davepagurek where can i see the setup guide



Patch:
diff --git a/src/webgl/p5.Framebuffer.js b/src/webgl/p5.Framebuffer.js
index beb6109bc9..bbf1b8df23 100644
--- a/src/webgl/p5.Framebuffer.js
+++ b/src/webgl/p5.Framebuffer.js
@@ -533,8 +533,8 @@ class Framebuffer {
       this.target._renderer,
       this.color,
       {
-        glMinFilter: filter,
-        glMagFilter: filter
+        minFilter: filter,
+        magFilter: filter
       }
     );
     this.target._renderer.textures.set(this.color, this.colorP5Texture);


Test patch:
diff --git a/test/unit/webgl/p5.Framebuffer.js b/test/unit/webgl/p5.Framebuffer.js
index d343b5ad55..f2dbe0f622 100644
--- a/test/unit/webgl/p5.Framebuffer.js
+++ b/test/unit/webgl/p5.Framebuffer.js
@@ -541,4 +541,34 @@ suite('p5.Framebuffer', function() {
       });
     }
   });
+
+  suite('texture filtering', function() {
+    test('can create a framebuffer that uses NEAREST texture filtering',
+      function() {
+        myp5.createCanvas(10, 10, myp5.WEBGL);
+        const fbo = myp5.createFramebuffer({
+          textureFiltering: myp5.NEAREST
+        });
+
+        assert.equal(
+          fbo.color.framebuffer.colorP5Texture.glMinFilter, fbo.gl.NEAREST
+        );
+        assert.equal(
+          fbo.color.framebuffer.colorP5Texture.glMagFilter, fbo.gl.NEAREST
+        );
+      });
+    test('can create a framebuffer that uses LINEAR texture filtering',
+      function() {
+        myp5.createCanvas(10, 10, myp5.WEBGL);
+        // LINEAR should be the default
+        const fbo = myp5.createFramebuffer({});
+
+        assert.equal(
+          fbo.color.framebuffer.colorP5Texture.glMinFilter, fbo.gl.LINEAR
+        );
+        assert.equal(
+          fbo.color.framebuffer.colorP5Texture.glMagFilter, fbo.gl.LINEAR
+        );
+      });
+  });
 });