Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 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
7 changes: 0 additions & 7 deletions lib/empty-example/sketch.js

This file was deleted.

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
Collaborator 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
Collaborator 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
Collaborator 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
22 changes: 22 additions & 0 deletions src/core/p5.Renderer2D.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,28 @@ class Renderer2D extends p5.Renderer{
this._pInst._setProperty('drawingContext', this.drawingContext);
}

getFilterGraphicsLayer() {
// create hidden webgl renderer if it doesn't exist
if (!this.filterGraphicsLayer) {
// the real _pInst is buried when this is a secondary p5.Graphics
const pInst =
this._pInst instanceof p5.Graphics ?
this._pInst._pInst :
this._pInst;

// create secondary layer
this.filterGraphicsLayer =
new p5.Graphics(
this.width,
this.height,
constants.WEBGL,
pInst
);
}

return this.filterGraphicsLayer;
Copy link
Contributor

Choose a reason for hiding this comment

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

Before this, we might want to do a similar size matching to what we do in RendererGL with its framebuffer so that we ensure this.filterGraphicsLayer matches width, height, and pixel density to this._pInst. Right now filters on 2D mode don't seem to work when resizing: https://editor.p5js.org/davepagurek/sketches/OOKkLOINp

Maybe we can also copy and paste the current unit test that checks that the framebuffer gets resized in WebGL mode, and adapt it to check the size of filterGraphicsLayer in 2D mode? It would definitely be helpful to leave behind as many tests as we can so that we don't have to rely so much on thinking of new things to test the next time we make changes to this system.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

okay, i will do the changes asap.

}

_applyDefaults() {
this._cachedFillStyle = this._cachedStrokeStyle = undefined;
this._cachedBlendMode = constants.BLEND;
Expand Down
42 changes: 18 additions & 24 deletions src/image/pixels.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import p5 from '../core/main';
import Filters from './filters';
import '../color/p5.Color';
import * as constants from '../core/constants';

/**
* An array containing the color of each pixel on the canvas. Colors are
Expand Down Expand Up @@ -544,6 +543,15 @@ p5.prototype._copyHelper = (
* </div>
*/

/**
* @method getFilterGraphicsLayer
* @private
* @returns {p5.Graphics}
*/
p5.prototype.getFilterGraphicsLayer = function() {
return this._renderer.getFilterGraphicsLayer();
};

/**
* @method filter
* @param {Constant} filterType
Expand All @@ -560,7 +568,7 @@ p5.prototype.filter = function(...args) {
let { shader, operation, value, useWebGL } = parseFilterArgs(...args);

// when passed a shader, use it directly
if (shader) {
if (this._renderer.isP3D && shader) {
p5.RendererGL.prototype.filter.call(this._renderer, shader);
return;
}
Expand All @@ -586,27 +594,11 @@ p5.prototype.filter = function(...args) {

// when this is P2D renderer, create/use hidden webgl renderer
else {
// create hidden webgl renderer if it doesn't exist
if (!this.filterGraphicsLayer) {
// the real _pInst is buried when this is a secondary p5.Graphics
const pInst =
this._renderer._pInst instanceof p5.Graphics ?
this._renderer._pInst._pInst :
this._renderer._pInst;

// create secondary layer
this.filterGraphicsLayer =
new p5.Graphics(
this.width,
this.height,
constants.WEBGL,
pInst
);
}
const filterGraphicsLayer = this.getFilterGraphicsLayer();

// copy p2d canvas contents to secondary webgl renderer
// dest
this.filterGraphicsLayer.copy(
filterGraphicsLayer.copy(
// src
this._renderer,
// src coods
Expand All @@ -616,12 +608,14 @@ p5.prototype.filter = function(...args) {
);
//clearing the main canvas
this._renderer.clear();

this._renderer.resetMatrix();
// filter it with shaders
this.filterGraphicsLayer.filter(operation, value);
filterGraphicsLayer.filter(...args);

// copy secondary webgl renderer back to original p2d canvas
this._renderer._pInst.image(this.filterGraphicsLayer, 0, 0);
this.filterGraphicsLayer.clear(); // prevent feedback effects on p2d canvas
this._renderer._pInst.image(filterGraphicsLayer, 0, 0);
filterGraphicsLayer.clear(); // prevent feedback effects on p2d canvas
}
};

Expand Down Expand Up @@ -925,4 +919,4 @@ p5.prototype.updatePixels = function(x, y, w, h) {
this._renderer.updatePixels(x, y, w, h);
};

export default p5;
export default p5;
Loading