Skip to content

Commit 266756c

Browse files
authored
Merge branch 'dev-2.0' into fix-buildGeometry-docs-links
2 parents f393f04 + 46eac76 commit 266756c

12 files changed

Lines changed: 451 additions & 79 deletions

File tree

src/core/p5.Renderer3D.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ export class Renderer3D extends Renderer {
160160

161161
// clipping
162162
this._clipDepths = [];
163+
this._textContextSavedStack = [];
163164
this._isClipApplied = false;
164165
this._stencilTestOn = false;
165166

@@ -221,6 +222,8 @@ export class Renderer3D extends Renderer {
221222
// Used by beginShape/endShape functions to construct a p5.Geometry
222223
this.shapeBuilder = new ShapeBuilder(this);
223224

225+
this._largeTessellationAcknowledged = false;
226+
224227
this.geometryBufferCache = new GeometryBufferCache(this);
225228

226229
this.curStrokeCap = constants.ROUND;
@@ -1323,13 +1326,25 @@ export class Renderer3D extends Renderer {
13231326
return this;
13241327
}
13251328

1329+
push() {
1330+
super.push()
1331+
const saved = !!(this.states.textFont?.font);
1332+
if (saved) {
1333+
this.textDrawingContext().save()
1334+
}
1335+
this._textContextSavedStack.push(saved);
1336+
}
1337+
13261338
pop(...args) {
13271339
if (
13281340
this._clipDepths.length > 0 &&
13291341
this._pushPopDepth === this._clipDepths[this._clipDepths.length - 1]
13301342
) {
13311343
this._clearClip();
13321344
}
1345+
if (this._textContextSavedStack.pop()) {
1346+
this.textDrawingContext().restore()
1347+
}
13331348
super.pop(...args);
13341349
this._applyStencilTestIfClipping();
13351350
}
@@ -1991,6 +2006,10 @@ const webGPUAddonMessage = 'Add the WebGPU add-on to your project and pass WEBGP
19912006
function renderer3D(p5, fn) {
19922007
p5.Renderer3D = Renderer3D;
19932008

2009+
ShapeBuilder.prototype.friendlyErrorsDisabled = function() {
2010+
return Boolean(p5.disableFriendlyErrors);
2011+
};
2012+
19942013
/**
19952014
* Creates a <a href="#/p5/p5.StorageBuffer">`p5.StorageBuffer`</a>, which is
19962015
* a block of data that shaders can read from, and compute shaders

src/strands/strands_transpiler.js

Lines changed: 33 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,35 @@ function replaceReferences(node, tempVarMap) {
235235
internalReplaceReferences(node);
236236
}
237237

238+
// Shared handler for both BinaryExpression and LogicalExpression —
239+
// both follow the same operator-to-method-call transformation pattern.
240+
function transformBinaryOrLogical(node, state, ancestors) {
241+
if (ancestors.some(a => nodeIsUniform(a) || nodeIsUniformCallbackFn(a, state.uniformCallbackNames))) {
242+
return;
243+
}
244+
const unsafeTypes = ['Literal', 'ArrayExpression', 'Identifier'];
245+
if (unsafeTypes.includes(node.left.type)) {
246+
node.left = {
247+
type: 'CallExpression',
248+
callee: {
249+
type: 'Identifier',
250+
name: '__p5.strandsNode',
251+
},
252+
arguments: [node.left]
253+
};
254+
}
255+
node.type = 'CallExpression';
256+
node.callee = {
257+
type: 'MemberExpression',
258+
object: node.left,
259+
property: {
260+
type: 'Identifier',
261+
name: replaceBinaryOperator(node.operator),
262+
},
263+
};
264+
node.arguments = [node.right];
265+
}
266+
238267
const ASTCallbacks = {
239268
UnaryExpression(node, state, ancestors) {
240269
if (ancestors.some(a => nodeIsUniform(a) || nodeIsUniformCallbackFn(a, state.uniformCallbackNames))) {
@@ -509,72 +538,10 @@ const ASTCallbacks = {
509538
}
510539
}
511540
},
512-
BinaryExpression(node, state, ancestors) {
513-
// Don't convert uniform default values to node methods, as
514-
// they should be evaluated at runtime, not compiled.
515-
if (ancestors.some(a => nodeIsUniform(a) || nodeIsUniformCallbackFn(a, state.uniformCallbackNames))) {
516-
return;
517-
}
518-
// If the left hand side of an expression is one of these types,
519-
// we should construct a node from it.
520-
const unsafeTypes = ['Literal', 'ArrayExpression', 'Identifier'];
521-
if (unsafeTypes.includes(node.left.type)) {
522-
const leftReplacementNode = {
523-
type: 'CallExpression',
524-
callee: {
525-
type: 'Identifier',
526-
name: '__p5.strandsNode',
527-
},
528-
arguments: [node.left]
529-
}
530-
node.left = leftReplacementNode;
531-
}
532-
// Replace the binary operator with a call expression
533-
// in other words a call to BaseNode.mult(), .div() etc.
534-
node.type = 'CallExpression';
535-
node.callee = {
536-
type: 'MemberExpression',
537-
object: node.left,
538-
property: {
539-
type: 'Identifier',
540-
name: replaceBinaryOperator(node.operator),
541-
},
542-
};
543-
node.arguments = [node.right];
544-
},
545-
LogicalExpression(node, state, ancestors) {
546-
// Don't convert uniform default values to node methods, as
547-
// they should be evaluated at runtime, not compiled.
548-
if (ancestors.some(a => nodeIsUniform(a) || nodeIsUniformCallbackFn(a, state.uniformCallbackNames))) {
549-
return;
550-
}
551-
// If the left hand side of an expression is one of these types,
552-
// we should construct a node from it.
553-
const unsafeTypes = ['Literal', 'ArrayExpression', 'Identifier'];
554-
if (unsafeTypes.includes(node.left.type)) {
555-
const leftReplacementNode = {
556-
type: 'CallExpression',
557-
callee: {
558-
type: 'Identifier',
559-
name: '__p5.strandsNode',
560-
},
561-
arguments: [node.left]
562-
}
563-
node.left = leftReplacementNode;
564-
}
565-
// Replace the logical operator with a call expression
566-
// in other words a call to BaseNode.or(), .and() etc.
567-
node.type = 'CallExpression';
568-
node.callee = {
569-
type: 'MemberExpression',
570-
object: node.left,
571-
property: {
572-
type: 'Identifier',
573-
name: replaceBinaryOperator(node.operator),
574-
},
575-
};
576-
node.arguments = [node.right];
577-
},
541+
BinaryExpression: transformBinaryOrLogical,
542+
LogicalExpression: transformBinaryOrLogical,
543+
544+
578545
ConditionalExpression(node, state, ancestors) {
579546
if (ancestors.some(a => nodeIsUniform(a) || nodeIsUniformCallbackFn(a, state.uniformCallbackNames))) {
580547
return;

src/type/textCore.js

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1587,13 +1587,6 @@ function textCore(p5, fn) {
15871587
if (typeof weight === 'number') {
15881588
this.states.setValue('fontWeight', weight);
15891589
this._applyTextProperties();
1590-
1591-
// Safari works without weight set in the canvas style attribute, and actually
1592-
// has buggy behavior if it is present, using the wrong weight when drawing
1593-
// multiple times with different weights
1594-
if (!p5.prototype._isSafari()) {
1595-
this._setCanvasStyleProperty('font-variation-settings', `"wght" ${weight}`);
1596-
}
15971590
return;
15981591
}
15991592
// the getter

src/webgl/3d_primitives.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1792,33 +1792,38 @@ function primitives3D(p5, fn){
17921792
const prevMode = this.states.textureMode;
17931793
this.states.setValue('textureMode', constants.NORMAL);
17941794
const prevOrder = this.bezierOrder();
1795-
this.bezierOrder(2);
1795+
this.bezierOrder(3);
17961796
this.beginShape();
17971797
const addUVs = (x, y) => [x, y, 0, (x - x1)/width, (y - y1)/height];
1798+
const rr = 0.5523; // kappa: 4*(sqrt(2)-1)/3, handle ratio for cubic bezier circle approximation
17981799
if (tr !== 0) {
17991800
this.vertex(...addUVs(x2 - tr, y1));
1800-
this.bezierVertex(...addUVs(x2, y1));
1801+
this.bezierVertex(...addUVs(x2 - tr + tr * rr, y1));
1802+
this.bezierVertex(...addUVs(x2, y1 + tr - tr * rr));
18011803
this.bezierVertex(...addUVs(x2, y1 + tr));
18021804
} else {
18031805
this.vertex(...addUVs(x2, y1));
18041806
}
18051807
if (br !== 0) {
18061808
this.vertex(...addUVs(x2, y2 - br));
1807-
this.bezierVertex(...addUVs(x2, y2));
1809+
this.bezierVertex(...addUVs(x2, y2 - br + br * rr));
1810+
this.bezierVertex(...addUVs(x2 - br + rr * br, y2));
18081811
this.bezierVertex(...addUVs(x2 - br, y2));
18091812
} else {
18101813
this.vertex(...addUVs(x2, y2));
18111814
}
18121815
if (bl !== 0) {
18131816
this.vertex(...addUVs(x1 + bl, y2));
1814-
this.bezierVertex(...addUVs(x1, y2));
1817+
this.bezierVertex(...addUVs(x1 + bl - bl * rr, y2));
1818+
this.bezierVertex(...addUVs(x1, y2 - bl + bl * rr));
18151819
this.bezierVertex(...addUVs(x1, y2 - bl));
18161820
} else {
18171821
this.vertex(...addUVs(x1, y2));
18181822
}
18191823
if (tl !== 0) {
18201824
this.vertex(...addUVs(x1, y1 + tl));
1821-
this.bezierVertex(...addUVs(x1, y1));
1825+
this.bezierVertex(...addUVs(x1, y1 + tl - tl * rr));
1826+
this.bezierVertex(...addUVs(x1 + tl - tl * rr, y1));
18221827
this.bezierVertex(...addUVs(x1 + tl, y1));
18231828
} else {
18241829
this.vertex(...addUVs(x1, y1));

src/webgl/ShapeBuilder.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ export class ShapeBuilder {
4545
this.bufferStrides = { ...INITIAL_BUFFER_STRIDES };
4646
}
4747

48+
friendlyErrorsDisabled() {
49+
return false;
50+
}
51+
4852
constructFromContours(shape, contours) {
4953
if (this._useUserVertexProperties){
5054
this._resetUserVertexProperties();
@@ -148,6 +152,27 @@ export class ShapeBuilder {
148152
}
149153

150154
if (this.shapeMode === constants.PATH) {
155+
const vertexCount = this.geometry.vertices.length;
156+
const MAX_SAFE_TESSELLATION_VERTICES = 50000;
157+
158+
if (
159+
vertexCount > MAX_SAFE_TESSELLATION_VERTICES &&
160+
!this.friendlyErrorsDisabled() &&
161+
!this.renderer._largeTessellationAcknowledged
162+
) {
163+
const proceed = window.confirm(
164+
'🌸 p5.js says:\n\n' +
165+
`This shape has ${vertexCount} vertices. Tessellating shapes with this ` +
166+
'many vertices can be very slow and may cause your browser to become ' +
167+
'unresponsive.\n\n' +
168+
'Do you want to continue tessellating this shape?'
169+
);
170+
if (!proceed) {
171+
return;
172+
}
173+
this.renderer._largeTessellationAcknowledged = true;
174+
}
175+
151176
this.isProcessingVertices = true;
152177
this._tesselateShape();
153178
this.isProcessingVertices = false;

0 commit comments

Comments
 (0)