Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding framebuffer support for filter() + CreateFilterShader for 2D mode #6559

Merged
merged 27 commits into from
Nov 23, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
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
72 changes: 37 additions & 35 deletions src/core/p5.Renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class Renderer extends p5.Element {

// the renderer should return a 'style' object that it wishes to
// store on the push stack.
push () {
push() {
this._pushPopDepth++;
return {
properties: {
Expand All @@ -94,10 +94,10 @@ class Renderer extends p5.Element {
// a pop() operation is in progress
// the renderer is passed the 'style' object that it returned
// from its push() method.
pop (style) {
pop(style) {
this._pushPopDepth--;
if (style.properties) {
// copy the style properties back into the renderer
// copy the style properties back into the renderer
Object.assign(this, style.properties);
}
}
Expand All @@ -120,26 +120,28 @@ class Renderer extends p5.Element {
/**
* Resize our canvas element.
*/
resize (w, h) {
this.width = w;
this.height = h;
this.elt.width = w * this._pInst._pixelDensity;
this.elt.height = h * this._pInst._pixelDensity;
this.elt.style.width = `${w}px`;
this.elt.style.height = `${h}px`;
if (this._isMainCanvas) {
this._pInst._setProperty('width', this.width);
this._pInst._setProperty('height', this.height);
resize(w, h) {
if (this._pInst && this._pInst._pixelDensity) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was there a case where these conditions weren't met?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, during testing, there seems to be an issue where, after a resize operation, logging console.log(this._pInst) sometimes results in the value undefined. This occurrence leads to errors of the form "cannot read properties of undefined (reading _pixelDensity)". To address this, a check has been added to verify whether this._pInst is defined before attempting to access its properties. This check helps prevent the errors encountered during the testing process. It was actually failing the test given below. Am I doing the correct way....Or this still have limitations?

 test('secondary graphics layer matches main canvas size', function() {
      let g1 = myp5.createCanvas(5, 5, myp5.WEBGL);
      let s = myp5.createShader(vert, frag);
      myp5.filter(s);
      let g2 = g1.filterGraphicsLayer;
      assert.deepEqual([g1.width, g1.height], [g2.width, g2.height]);
      myp5.resizeCanvas(4, 4);
      assert.deepEqual([g1.width, g1.height], [g2.width, g2.height]);
    });

checkpass

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for pointing out the test case! I was asking because it seems like it might be indicative of a bigger problem if something is getting resized without having a _pInst, and maybe we want to see how it got into that state and maybe fix it at the source instead of here. I'll take a look at that test and get back to you soon!

Copy link
Contributor Author

@perminder-17 perminder-17 Nov 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for pointing out the test case! I was asking because it seems like it might be indicative of a bigger problem if something is getting resized without having a _pInst, and maybe we want to see how it got into that state and maybe fix it at the source instead of here. I'll take a look at that test and get back to you soon!

Sure

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's coming from these lines:

// resize filter graphics layer
if (this.filterGraphicsLayer) {
p5.Renderer.prototype.resize.call(this.filterGraphicsLayer, w, h);
}

These were added when filterGraphicsLayer was a graphic, but now it's a framebuffer. I think we don't need those lines at all any more since we handle the resizing when we call filter, so maybe we can take it out, and check instead that the size changes after calling filter:

    test('secondary graphics layer matches main canvas size', function() {
      let g1 = myp5.createCanvas(5, 5, myp5.WEBGL);
      let s = myp5.createShader(vert, frag);
      myp5.filter(s);
      let g2 = g1.filterGraphicsLayer;
      assert.deepEqual([g1.width, g1.height], [g2.width, g2.height]);
      myp5.resizeCanvas(4, 4);
+     myp5.filter(s);
      assert.deepEqual([g1.width, g1.height], [g2.width, g2.height]);
    });

Also as a side note, we should still rename filterGraphicsLayer and filterGraphicsLayerTemp in RendererGL to remove the word graphic (just filterLayer and filterLayerTemp probably)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, i have done a little testing myself, I think it's working now. I have made the required changes.

this.width = w;
this.height = h;
this.elt.width = w * this._pInst._pixelDensity;
this.elt.height = h * this._pInst._pixelDensity;
this.elt.style.width = `${w}px`;
this.elt.style.height = `${h}px`;
if (this._isMainCanvas) {
this._pInst._setProperty('width', this.width);
this._pInst._setProperty('height', this.height);
}
}
}

get (x, y, w, h) {
get(x, y, w, h) {
const pixelsState = this._pixelsState;
const pd = pixelsState._pixelDensity;
const canvas = this.canvas;

if (typeof x === 'undefined' && typeof y === 'undefined') {
// get()
// get()
x = y = 0;
w = pixelsState.width;
h = pixelsState.height;
Expand All @@ -148,26 +150,26 @@ class Renderer extends p5.Element {
y *= pd;

if (typeof w === 'undefined' && typeof h === 'undefined') {
// get(x,y)
// get(x,y)
if (x < 0 || y < 0 || x >= canvas.width || y >= canvas.height) {
return [0, 0, 0, 0];
}

return this._getPixel(x, y);
}
// get(x,y,w,h)
// get(x,y,w,h)
}

const region = new p5.Image(w*pd, h*pd);
const region = new p5.Image(w * pd, h * pd);
region._pixelDensity = pd;
region.canvas
.getContext('2d')
.drawImage(canvas, x, y, w * pd, h * pd, 0, 0, w*pd, h*pd);
.drawImage(canvas, x, y, w * pd, h * pd, 0, 0, w * pd, h * pd);

return region;
}

textLeading (l) {
textLeading(l) {
if (typeof l === 'number') {
this._setProperty('_leadingSet', true);
this._setProperty('_textLeading', l);
Expand All @@ -177,13 +179,13 @@ class Renderer extends p5.Element {
return this._textLeading;
}

textStyle (s) {
textStyle(s) {
if (s) {
if (
s === constants.NORMAL ||
s === constants.ITALIC ||
s === constants.BOLD ||
s === constants.BOLDITALIC
s === constants.ITALIC ||
s === constants.BOLD ||
s === constants.BOLDITALIC
) {
this._setProperty('_textStyle', s);
}
Expand All @@ -194,21 +196,21 @@ class Renderer extends p5.Element {
return this._textStyle;
}

textAscent () {
textAscent() {
if (this._textAscent === null) {
this._updateTextMetrics();
}
return this._textAscent;
}

textDescent () {
textDescent() {
if (this._textDescent === null) {
this._updateTextMetrics();
}
return this._textDescent;
}

textAlign (h, v) {
textAlign(h, v) {
if (typeof h !== 'undefined') {
this._setProperty('_textAlign', h);

Expand All @@ -225,7 +227,7 @@ class Renderer extends p5.Element {
}
}

textWrap (wrapStyle) {
textWrap(wrapStyle) {
this._setProperty('_textWrap', wrapStyle);
return this._textWrap;
}
Expand Down Expand Up @@ -306,10 +308,10 @@ class Renderer extends p5.Element {
finalMaxHeight = originalY + maxHeight - ascent / 2;
}
} else {
// no text-height specified, show warning for BOTTOM / CENTER
// no text-height specified, show warning for BOTTOM / CENTER
if (this._textBaseline === constants.BOTTOM ||
this._textBaseline === constants.CENTER) {
// use rectHeight as an approximation for text height
this._textBaseline === constants.CENTER) {
// use rectHeight as an approximation for text height
let rectHeight = p.textSize() * this._textLeading;
finalMinHeight = y - rectHeight / 2;
finalMaxHeight = y + rectHeight / 2;
Expand Down Expand Up @@ -435,8 +437,8 @@ class Renderer extends p5.Element {
y += p.textLeading();
}
} else {
// Offset to account for vertically centering multiple lines of text - no
// need to adjust anything for vertical align top or baseline
// Offset to account for vertically centering multiple lines of text - no
// need to adjust anything for vertical align top or baseline
let offset = 0;
if (this._textBaseline === constants.CENTER) {
offset = (lines.length - 1) * p.textLeading() / 2;
Expand Down Expand Up @@ -536,11 +538,11 @@ function calculateOffset(object) {
return [currentLeft, currentTop];
}
// This caused the test to failed.
Renderer.prototype.textSize = function(s) {
Renderer.prototype.textSize = function (s) {
if (typeof s === 'number') {
this._setProperty('_textSize', s);
if (!this._leadingSet) {
// only use a default value if not previously set (#5181)
// only use a default value if not previously set (#5181)
this._setProperty('_textLeading', s * constants._DEFAULT_LEADMULT);
}
return this._applyTextProperties();
Expand Down
2 changes: 2 additions & 0 deletions src/image/pixels.js
Original file line number Diff line number Diff line change
Expand Up @@ -616,6 +616,8 @@ p5.prototype.filter = function(...args) {
);
//clearing the main canvas
this._renderer.clear();
// Resetting the matrix of the canvas
this._renderer.resetMatrix();
// filter it with shaders
this.filterGraphicsLayer.filter(operation, value);

Expand Down
14 changes: 13 additions & 1 deletion src/webgl/material.js
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,12 @@ p5.prototype.createShader = function(vertSrc, fragSrc) {
* </div>
*/
p5.prototype.createFilterShader = function(fragSrc) {
let iswebgl;
if(this._renderer.GL){
iswebgl = true;
}else{
iswebgl = false;
}
this._assert3d('createFilterShader');
p5._validateParameters('createFilterShader', arguments);
let defaultVertV1 = `
Expand Down Expand Up @@ -322,7 +328,13 @@ p5.prototype.createFilterShader = function(fragSrc) {
`;
let vertSrc = fragSrc.includes('#version 300 es') ? defaultVertV2 : defaultVertV1;
const shader = new p5.Shader(this._renderer, vertSrc, fragSrc);
shader.ensureCompiledOnContext(this._renderer.getFilterGraphicsLayer());
let target;
if(!iswebgl){
target = this._renderer.getFilterGraphicsLayer();
}else{
target = this;
}
shader.ensureCompiledOnContext(target);
return shader;
};

Expand Down
Loading
Loading