diff --git a/src/core/constants.js b/src/core/constants.js
index 0885ab3e48..6c36301c70 100644
--- a/src/core/constants.js
+++ b/src/core/constants.js
@@ -1347,7 +1347,7 @@ export const FLOAT = 'float';
export const HALF_FLOAT = 'half-float';
/**
- * The `splineEnds` mode where splines curve through
+ * The `splineProperty('ends')` mode where splines curve through
* their first and last points.
* @typedef {unique symbol} INCLUDE
* @property {INCLUDE} INCLUDE
@@ -1356,7 +1356,7 @@ export const HALF_FLOAT = 'half-float';
export const INCLUDE = Symbol('include');
/**
- * The `splineEnds` mode where the first and last points in a spline
+ * The `splineProperty('ends')` mode where the first and last points in a spline
* affect the direction of the curve, but are not rendered.
* @typedef {unique symbol} EXCLUDE
* @property {EXCLUDE} EXCLUDE
@@ -1365,7 +1365,7 @@ export const INCLUDE = Symbol('include');
export const EXCLUDE = Symbol('exclude');
/**
- * The `splineEnds` mode where the spline loops back to its first point.
+ * The `splineProperty('ends')` mode where the spline loops back to its first point.
* Only used internally.
* @typedef {unique symbol} JOIN
* @property {JOIN} JOIN
diff --git a/src/core/p5.Renderer.js b/src/core/p5.Renderer.js
index bcc69ed086..e5ba194d63 100644
--- a/src/core/p5.Renderer.js
+++ b/src/core/p5.Renderer.js
@@ -10,6 +10,18 @@ import { Image } from '../image/p5.Image';
import { Vector } from '../math/p5.Vector';
import { Shape } from '../shape/custom_shapes';
+class ClonableObject {
+ constructor(obj = {}) {
+ for (const key in obj) {
+ this[key] = obj[key];
+ }
+ }
+
+ clone() {
+ return new ClonableObject(this);
+ }
+};
+
class Renderer {
static states = {
strokeColor: null,
@@ -30,7 +42,7 @@ class Renderer {
textAlign: constants.LEFT,
textBaseline: constants.BASELINE,
bezierOrder: 3,
- splineEnds: constants.INCLUDE,
+ splineProperties: new ClonableObject({ ends: constants.INCLUDE, tightness: 0 }),
textWrap: constants.WORD,
// added v2.0
@@ -77,7 +89,6 @@ class Renderer {
this._clipping = false;
this._clipInvert = false;
- this._curveTightness = 0;
this._currentShape = undefined; // Lazily generate current shape
}
@@ -150,11 +161,11 @@ class Renderer {
this.currentShape.bezierVertex(position, textureCoordinates);
}
- splineEnds(mode) {
- if (mode === undefined) {
- return this.states.splineEnds;
+ splineProperty(key, value) {
+ if (value === undefined) {
+ return this.states.splineProperties[key];
} else {
- this.states.splineEnds = mode;
+ this.states.splineProperties[key] = value;
}
this.updateShapeProperties();
}
@@ -305,7 +316,8 @@ class Renderer {
updateShapeProperties() {
this.currentShape.bezierOrder(this.states.bezierOrder);
- this.currentShape.splineEnds(this.states.splineEnds);
+ this.currentShape.splineProperty('ends', this.states.splineProperties.ends);
+ this.currentShape.splineProperty('tightness', this.states.splineProperties.tightness);
}
updateShapeVertexProperties() {
diff --git a/src/shape/curves.js b/src/shape/curves.js
index 93a19c1d38..370011152e 100644
--- a/src/shape/curves.js
+++ b/src/shape/curves.js
@@ -765,61 +765,6 @@ function curves(p5, fn){
return this;
};
- /**
- * Adjusts the way curve() and
- * splineVertex() draw.
- *
- * Spline curves are like cables that are attached to a set of points.
- * `curveTightness()` adjusts how tightly the cable is attached to the points.
- *
- * The parameter, `tightness`, determines how the curve fits to the vertex
- * points. By default, `tightness` is set to 0. Setting tightness to 1,
- * as in `curveTightness(1)`, connects the curve's points using straight
- * lines. Values in the range from –5 to 5 deform curves while leaving them
- * recognizable.
- *
- * @method curveTightness
- * @param {Number} amount amount of tightness.
- * @chainable
- *
- * @example
- *
- *
- * // Move the mouse left and right to see the curve change.
- *
- * function setup() {
- * createCanvas(100, 100);
- *
- * describe('A black curve forms a sideways U shape. The curve deforms as the user moves the mouse from left to right');
- * }
- *
- * function draw() {
- * background(200);
- *
- * // Set the curve's tightness using the mouse.
- * let t = map(mouseX, 0, 100, -5, 5, true);
- * curveTightness(t);
- *
- * // Draw the curve.
- * noFill();
- * beginShape();
- * splineVertex(10, 26);
- * splineVertex(10, 26);
- * splineVertex(83, 24);
- * splineVertex(83, 61);
- * splineVertex(25, 65);
- * splineVertex(25, 65);
- * endShape();
- * }
- *
- *
- */
- fn.curveTightness = function(t) {
- // p5._validateParameters('curveTightness', arguments);
- this._renderer._curveTightness = t;
- return this;
- };
-
/**
* Calculates coordinates along a spline curve using interpolation.
*
@@ -934,7 +879,7 @@ function curves(p5, fn){
*/
fn.curvePoint = function(a, b, c, d, t) {
// p5._validateParameters('curvePoint', arguments);
- const s = this._renderer._curveTightness,
+ const s = this._renderer.states.splineProperties.tightness,
t3 = t * t * t,
t2 = t * t,
f1 = (s - 1) / 2 * t3 + (1 - s) * t2 + (s - 1) / 2 * t,
@@ -1051,7 +996,7 @@ function curves(p5, fn){
fn.curveTangent = function(a, b, c, d, t) {
// p5._validateParameters('curveTangent', arguments);
- const s = this._renderer._curveTightness,
+ const s = this._renderer.states.splineProperties.tightness,
tt3 = t * t * 3,
t2 = t * 2,
f1 = (s - 1) / 2 * tt3 + (1 - s) * t2 + (s - 1) / 2,
diff --git a/src/shape/custom_shapes.js b/src/shape/custom_shapes.js
index 84724486c4..58465a2298 100644
--- a/src/shape/custom_shapes.js
+++ b/src/shape/custom_shapes.js
@@ -280,8 +280,10 @@ to interpolated endpoints (a breaking change)
*/
class SplineSegment extends Segment {
#vertexCapacity = Infinity;
- _splineEnds = constants.INCLUDE;
- _splineTightness = 0;
+ _splineProperties = {
+ ends: constants.INCLUDE,
+ tightness: 0
+ };
get vertexCapacity() {
return this.#vertexCapacity;
@@ -296,7 +298,7 @@ class SplineSegment extends Segment {
}
get canOverrideAnchor() {
- return this._splineEnds === constants.EXCLUDE;
+ return this._splineProperties.ends === constants.EXCLUDE;
}
// assuming for now that the first interpolated vertex is always
@@ -304,7 +306,7 @@ class SplineSegment extends Segment {
// if this spline segment doesn't follow another segment,
// the first vertex is in an anchor
get _firstInterpolatedVertex() {
- if (this._splineEnds === constants.EXCLUDE) {
+ if (this._splineProperties.ends === constants.EXCLUDE) {
return this._comesAfterSegment ?
this.vertices[1] :
this.vertices[0];
@@ -328,10 +330,10 @@ class SplineSegment extends Segment {
// doesn't line up with end of last segment
addToShape(shape) {
const added = super.addToShape(shape);
- this._splineEnds = shape._splineEnds;
- this._splineTightness = shape._splineTightness;
+ this._splineProperties.ends = shape._splineProperties.ends;
+ this._splineProperties.tightness = shape._splineProperties.tightness;
- if (this._splineEnds !== constants.EXCLUDE) return added;
+ if (this._splineProperties.ends !== constants.EXCLUDE) return added;
let verticesPushed = !this._belongsToShape;
let lastPrimitive = shape.at(-1, -1);
@@ -367,9 +369,9 @@ class SplineSegment extends Segment {
// override method on base class
getEndVertex() {
- if (this._splineEnds === constants.INCLUDE) {
+ if (this._splineProperties.ends === constants.INCLUDE) {
return super.getEndVertex();
- } else if (this._splineEnds === constants.EXCLUDE) {
+ } else if (this._splineProperties.ends === constants.EXCLUDE) {
return this.vertices.at(-2);
} else {
return this.getStartVertex();
@@ -389,10 +391,10 @@ class SplineSegment extends Segment {
}
const prevVertex = this.getStartVertex();
- if (this._splineEnds === constants.INCLUDE) {
+ if (this._splineProperties.ends === constants.INCLUDE) {
points.unshift(prevVertex);
points.push(this.vertices.at(-1));
- } else if (this._splineEnds === constants.JOIN) {
+ } else if (this._splineProperties.ends === constants.JOIN) {
points.unshift(this.vertices.at(-1), prevVertex);
points.push(prevVertex, this.vertices.at(0));
}
@@ -410,7 +412,7 @@ class SplineSegment extends Segment {
}
close() {
- this._splineEnds = constants.JOIN;
+ this._splineProperties.ends = constants.JOIN;
}
}
@@ -581,10 +583,12 @@ class Shape {
#initialVertexProperties;
#primitiveShapeCreators;
#bezierOrder = 3;
- _splineTightness = 0;
kind = null;
contours = [];
- _splineEnds = constants.INCLUDE;
+ _splineProperties = {
+ tightness: 0,
+ ends: constants.INCLUDE
+ };
userVertexProperties = null;
constructor(
@@ -828,12 +832,8 @@ class Shape {
this.#bezierOrder = order;
}
- splineEnds(mode) {
- this._splineEnds = mode;
- }
-
- splineTightness(tightness) {
- this._splineTightness = tightness;
+ splineProperty(key, value) {
+ this._splineProperties[key] = value;
}
/*
@@ -1076,7 +1076,7 @@ class PrimitiveToPath2DConverter extends PrimitiveVisitor {
const shape = splineSegment._shape;
if (
- splineSegment._splineEnds === constants.EXCLUDE &&
+ splineSegment._splineProperties.ends === constants.EXCLUDE &&
!splineSegment._comesAfterSegment
) {
let startVertex = splineSegment._firstInterpolatedVertex;
@@ -1088,7 +1088,7 @@ class PrimitiveToPath2DConverter extends PrimitiveVisitor {
);
let bezierArrays = shape.catmullRomToBezier(
arrayVertices,
- splineSegment._splineTightness
+ splineSegment._splineProperties.tightness
).map(arr => arr.map(vertArr => shape.arrayToVertex(vertArr)));
for (const array of bezierArrays) {
const points = array.flatMap(vert => [vert.position.x, vert.position.y]);
@@ -1217,7 +1217,7 @@ class PrimitiveToVerticesConverter extends PrimitiveVisitor {
);
let bezierArrays = shape.catmullRomToBezier(
arrayVertices,
- splineSegment._splineTightness
+ splineSegment._splineProperties.tightness
);
let startVertex = shape.vertexToArray(splineSegment._firstInterpolatedVertex);
for (const array of bezierArrays) {
@@ -1596,10 +1596,11 @@ function customShapes(p5, fn) {
/**
* TODO: documentation
- * @param {SHOW|HIDE} mode
+ * @param {String} key
+ * @param value
*/
- fn.splineEnds = function(mode) {
- return this._renderer.splineEnds(mode);
+ fn.splineProperty = function(key, value) {
+ return this._renderer.splineProperty(key, value);
};
/**
diff --git a/src/webgl/p5.RendererGL.js b/src/webgl/p5.RendererGL.js
index b6b90984af..b6ab38c9c3 100644
--- a/src/webgl/p5.RendererGL.js
+++ b/src/webgl/p5.RendererGL.js
@@ -407,8 +407,6 @@ class RendererGL extends Renderer {
this.filterLayerTemp = undefined;
this.defaultFilterShaders = {};
- this._curveTightness = 6;
-
this.fontInfos = {};
this._curShader = undefined;
@@ -2409,34 +2407,6 @@ class RendererGL extends Renderer {
_vToNArray(arr) {
return arr.flatMap((item) => [item.x, item.y, item.z]);
}
-
- // function to calculate BezierVertex Coefficients
- _bezierCoefficients(t) {
- const t2 = t * t;
- const t3 = t2 * t;
- const mt = 1 - t;
- const mt2 = mt * mt;
- const mt3 = mt2 * mt;
- return [mt3, 3 * mt2 * t, 3 * mt * t2, t3];
- }
-
- // function to calculate QuadraticVertex Coefficients
- _quadraticCoefficients(t) {
- const t2 = t * t;
- const mt = 1 - t;
- const mt2 = mt * mt;
- return [mt2, 2 * mt * t, t2];
- }
-
- // function to convert Bezier coordinates to Catmull Rom Splines
- _bezierToCatmull(w) {
- const p1 = w[1];
- const p2 = w[1] + (w[2] - w[0]) / this._curveTightness;
- const p3 = w[2] - (w[3] - w[1]) / this._curveTightness;
- const p4 = w[2];
- const p = [p1, p2, p3, p4];
- return p;
- }
}
function rendererGL(p5, fn) {
diff --git a/test/unit/core/curves.js b/test/unit/core/curves.js
index d389e0fb9d..4840e273b1 100644
--- a/test/unit/core/curves.js
+++ b/test/unit/core/curves.js
@@ -4,7 +4,11 @@ import curves from '../../../src/shape/curves';
suite('Curves', function() {
beforeAll(function() {
mockP5Prototype._renderer = {
- _curveTightness: 0
+ states: {
+ splineProperties: {
+ tightness: 0
+ }
+ }
};
curves(mockP5, mockP5Prototype);
});
diff --git a/test/unit/visual/cases/shapes.js b/test/unit/visual/cases/shapes.js
index 61f8c0d3d9..8e7835a604 100644
--- a/test/unit/visual/cases/shapes.js
+++ b/test/unit/visual/cases/shapes.js
@@ -128,7 +128,7 @@ visualSuite('Shape drawing', function() {
visualTest('Drawing with curves with hidden ends', function(p5, screenshot) {
setup(p5);
p5.beginShape();
- p5.splineEnds(p5.EXCLUDE);
+ p5.splineProperty('ends', p5.EXCLUDE);
p5.splineVertex(10, 10);
p5.splineVertex(15, 40);
p5.splineVertex(40, 35);
@@ -152,7 +152,7 @@ visualSuite('Shape drawing', function() {
visualTest('Drawing with curves with tightness', function(p5, screenshot) {
setup(p5);
- p5.curveTightness(0.5);
+ p5.splineProperty('tightness', -1);
p5.beginShape();
p5.splineVertex(10, 10);
p5.splineVertex(15, 40);
@@ -166,7 +166,7 @@ visualSuite('Shape drawing', function() {
visualTest('Drawing closed curve loops', function(p5, screenshot) {
setup(p5);
p5.beginShape();
- p5.splineEnds(p5.EXCLUDE);
+ p5.splineProperty('ends', p5.EXCLUDE);
p5.splineVertex(10, 10);
p5.splineVertex(15, 40);
p5.splineVertex(40, 35);
diff --git a/test/unit/visual/cases/typography.js b/test/unit/visual/cases/typography.js
index 3bf1332344..df0450f0b2 100644
--- a/test/unit/visual/cases/typography.js
+++ b/test/unit/visual/cases/typography.js
@@ -543,4 +543,4 @@ visualSuite("Typography", function () {
screenshot();
});
});
-});
+}, { shiftThreshold: 3 });
diff --git a/test/unit/visual/screenshots/Shape drawing/2D mode/Drawing with curves with tightness/000.png b/test/unit/visual/screenshots/Shape drawing/2D mode/Drawing with curves with tightness/000.png
index 593867d9c8..36ee10117a 100644
Binary files a/test/unit/visual/screenshots/Shape drawing/2D mode/Drawing with curves with tightness/000.png and b/test/unit/visual/screenshots/Shape drawing/2D mode/Drawing with curves with tightness/000.png differ
diff --git a/test/unit/visual/screenshots/Shape drawing/WebGL mode/Drawing with curves with tightness/000.png b/test/unit/visual/screenshots/Shape drawing/WebGL mode/Drawing with curves with tightness/000.png
index 8d123f745f..e9b6d00541 100644
Binary files a/test/unit/visual/screenshots/Shape drawing/WebGL mode/Drawing with curves with tightness/000.png and b/test/unit/visual/screenshots/Shape drawing/WebGL mode/Drawing with curves with tightness/000.png differ
diff --git a/test/unit/visual/visualTest.js b/test/unit/visual/visualTest.js
index 4e77574c6c..068e8c7247 100644
--- a/test/unit/visual/visualTest.js
+++ b/test/unit/visual/visualTest.js
@@ -8,11 +8,6 @@ const { readFile, writeFile } = server.commands
// based on antialiasing.
const COLOR_THRESHOLD = 25;
-// By how many pixels can the snapshot shift? This is
-// often useful to accommodate different text rendering
-// across environments.
-const SHIFT_THRESHOLD = 3;
-
// The max side length to shrink test images down to before
// comparing, for performance.
const MAX_SIDE = 50;
@@ -39,6 +34,11 @@ function escapeName(name) {
let namePrefix = '';
+// By how many pixels can the snapshot shift? This is
+// often useful to accommodate different text rendering
+// across environments.
+let shiftThreshold = 2;
+
/**
* A helper to define a category of visual tests.
*
@@ -51,7 +51,7 @@ let namePrefix = '';
export function visualSuite(
name,
callback,
- { focus = false, skip = false } = {}
+ { focus = false, skip = false, shiftThreshold: newShiftThreshold } = {}
) {
let suiteFn = describe;
if (focus) {
@@ -61,11 +61,16 @@ export function visualSuite(
suiteFn = suiteFn.skip;
}
suiteFn(name, () => {
+ let lastShiftThreshold
let lastPrefix;
let lastDeviceRatio = window.devicePixelRatio;
beforeAll(() => {
lastPrefix = namePrefix;
namePrefix += escapeName(name) + '/';
+ lastShiftThreshold = shiftThreshold;
+ if (newShiftThreshold !== undefined) {
+ shiftThreshold = newShiftThreshold
+ }
// Force everything to be 1x
window.devicePixelRatio = 1;
@@ -76,6 +81,7 @@ export function visualSuite(
afterAll(() => {
namePrefix = lastPrefix;
window.devicePixelRatio = lastDeviceRatio;
+ shiftThreshold = lastShiftThreshold;
});
});
}
@@ -109,7 +115,7 @@ export async function checkMatch(actual, expected, p5) {
cnv.image(actual, 0, 0);
cnv.blendMode(DIFFERENCE);
cnv.image(expectedWithBg, 0, 0);
- for (let i = 0; i < SHIFT_THRESHOLD; i++) {
+ for (let i = 0; i < shiftThreshold; i++) {
cnv.filter(ERODE, false);
}
const diff = cnv.get();