Skip to content

Commit dad50f5

Browse files
committed
Merge branch 'dev-2.0' into webgpu
2 parents 5adc648 + 809de6b commit dad50f5

96 files changed

Lines changed: 378 additions & 167 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

contributor_docs/es/steward_guidelines.md

Lines changed: 92 additions & 91 deletions
Large diffs are not rendered by default.

src/core/p5.Renderer.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,24 @@ class Renderer {
388388
// Override in specific renderers as needed
389389
}
390390

391+
///////////////////////////////
392+
//// TEXT SUPPORT METHODS
393+
//////////////////////////////
394+
395+
_middleAlignOffset = function() {
396+
const { textFont, textSize } = this.states;
397+
const font = textFont?.font;
398+
const ctx = this.textDrawingContext();
399+
const metrics = ctx.measureText('X');
400+
let sCapHeight = (font?.data || {})['OS/2']?.sCapHeight;
401+
if (sCapHeight) {
402+
const unitsPerEm = font.data.head.unitsPerEm;
403+
sCapHeight *= textSize / unitsPerEm;
404+
} else {
405+
sCapHeight = metrics.fontBoundingBoxAscent;
406+
}
407+
return metrics.alphabeticBaseline + sCapHeight / 2;
408+
};
391409
};
392410

393411
function renderer(p5, fn){

src/core/p5.Renderer2D.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1141,7 +1141,7 @@ class Renderer2D extends Renderer {
11411141
case constants.BASELINE:
11421142
break;
11431143
case textCoreConstants._CTX_MIDDLE:
1144-
yOff = ydiff / 2;
1144+
yOff = ydiff / 2 + this._middleAlignOffset();
11451145
break;
11461146
case constants.BOTTOM:
11471147
yOff = ydiff;

src/core/p5.Renderer3D.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1787,6 +1787,13 @@ export class Renderer3D extends Renderer {
17871787
return this._yAlignOffset(lineData, adjustedH);
17881788
}
17891789

1790+
_verticalAlignFont = function() {
1791+
const ctx = this.textDrawingContext();
1792+
const metrics = ctx.measureText('X');
1793+
return -metrics.alphabeticBaseline ||
1794+
(-metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent);
1795+
}
1796+
17901797
_yAlignOffset(dataArr, height) {
17911798
if (typeof height === 'undefined') {
17921799
throw Error('_yAlignOffset: height is required');
@@ -1798,12 +1805,12 @@ export class Renderer3D extends Renderer {
17981805
((textLeading - textSize) * (numLines - 1));
17991806
switch (textBaseline) { // drawingContext ?
18001807
case constants.TOP:
1801-
yOff = textSize;
1808+
yOff = this._verticalAlignFont();
18021809
break;
18031810
case constants.BASELINE:
18041811
break;
18051812
case textCoreConstants._CTX_MIDDLE:
1806-
yOff = -totalHeight / 2 + textSize + (height || 0) / 2;
1813+
yOff = (-totalHeight + textSize + (height || 0)) / 2 + this._verticalAlignFont() + this._middleAlignOffset();
18071814
break;
18081815
case constants.BOTTOM:
18091816
yOff = -(totalHeight - textSize) + (height || 0);
@@ -1812,7 +1819,6 @@ export class Renderer3D extends Renderer {
18121819
console.warn(`${textBaseline} is not supported in WebGL mode.`); // FES?
18131820
break;
18141821
}
1815-
yOff += this.states.textFont.font?._verticalAlign(textSize) || 0;
18161822
dataArr.forEach(ele => ele.y += yOff);
18171823
return dataArr;
18181824
}

src/strands/p5.strands.js

Lines changed: 44 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -74,54 +74,56 @@ function strands(p5, fn) {
7474
const oldModify = p5.Shader.prototype.modify;
7575

7676
p5.Shader.prototype.modify = function (shaderModifier, scope = {}) {
77-
if (shaderModifier instanceof Function) {
78-
// Reset the context object every time modify is called;
79-
// const backend = glslBackend;
80-
initStrandsContext(strandsContext, this._renderer.strandsBackend, {
81-
active: true,
82-
renderer: this._renderer,
83-
baseShader: this,
84-
});
85-
createShaderHooksFunctions(strandsContext, fn, this);
86-
// TODO: expose this, is internal for debugging for now.
87-
const options = { parser: true, srcLocations: false };
77+
try {
78+
if (shaderModifier instanceof Function) {
79+
// Reset the context object every time modify is called;
80+
// const backend = glslBackend;
81+
initStrandsContext(strandsContext, this._renderer.strandsBackend, {
82+
active: true,
83+
renderer: this._renderer,
84+
baseShader: this,
85+
});
86+
createShaderHooksFunctions(strandsContext, fn, this);
87+
// TODO: expose this, is internal for debugging for now.
88+
const options = { parser: true, srcLocations: false };
8889

89-
// 1. Transpile from strands DSL to JS
90-
let strandsCallback;
91-
if (options.parser) {
92-
// #7955 Wrap function declaration code in brackets so anonymous functions are not top level statements, which causes an error in acorn when parsing
93-
// https://github.com/acornjs/acorn/issues/1385
94-
const sourceString = `(${shaderModifier.toString()})`;
95-
strandsCallback = transpileStrandsToJS(
96-
p5,
97-
sourceString,
98-
options.srcLocations,
99-
scope,
100-
);
101-
} else {
102-
strandsCallback = shaderModifier;
103-
}
90+
// 1. Transpile from strands DSL to JS
91+
let strandsCallback;
92+
if (options.parser) {
93+
// #7955 Wrap function declaration code in brackets so anonymous functions are not top level statements, which causes an error in acorn when parsing
94+
// https://github.com/acornjs/acorn/issues/1385
95+
const sourceString = `(${shaderModifier.toString()})`;
96+
strandsCallback = transpileStrandsToJS(
97+
p5,
98+
sourceString,
99+
options.srcLocations,
100+
scope,
101+
);
102+
} else {
103+
strandsCallback = shaderModifier;
104+
}
104105

105-
// 2. Build the IR from JavaScript API
106-
const globalScope = createBasicBlock(
107-
strandsContext.cfg,
108-
BlockType.GLOBAL,
109-
);
110-
pushBlock(strandsContext.cfg, globalScope);
111-
strandsCallback();
112-
popBlock(strandsContext.cfg);
106+
// 2. Build the IR from JavaScript API
107+
const globalScope = createBasicBlock(
108+
strandsContext.cfg,
109+
BlockType.GLOBAL,
110+
);
111+
pushBlock(strandsContext.cfg, globalScope);
112+
strandsCallback();
113+
popBlock(strandsContext.cfg);
113114

114-
// 3. Generate shader code hooks object from the IR
115-
// .......
116-
const hooksObject = generateShaderCode(strandsContext);
115+
// 3. Generate shader code hooks object from the IR
116+
// .......
117+
const hooksObject = generateShaderCode(strandsContext);
117118

119+
// Call modify with the generated hooks object
120+
return oldModify.call(this, hooksObject);
121+
} else {
122+
return oldModify.call(this, shaderModifier);
123+
}
124+
} finally {
118125
// Reset the strands runtime context
119126
deinitStrandsContext(strandsContext);
120-
121-
// Call modify with the generated hooks object
122-
return oldModify.call(this, hooksObject);
123-
} else {
124-
return oldModify.call(this, shaderModifier);
125127
}
126128
};
127129
}

src/strands/strands_api.js

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -228,14 +228,24 @@ export function initGlobalStrandsAPI(p5, fn, strandsContext) {
228228
const originalp5Fn = fn[typeInfo.fnName];
229229
fn[typeInfo.fnName] = function(...args) {
230230
if (strandsContext.active) {
231-
// For vector types with a single argument, repeat it for each component
232-
if (typeInfo.dimension > 1 && args.length === 1 && !Array.isArray(args[0]) &&
233-
!(args[0] instanceof StrandsNode && args[0].dimension > 1) &&
234-
(typeInfo.baseType === BaseType.FLOAT || typeInfo.baseType === BaseType.INT || typeInfo.baseType === BaseType.BOOL)) {
235-
args = Array(typeInfo.dimension).fill(args[0]);
231+
if (args.length === 1 && args[0].dimension && args[0].dimension === typeInfo.dimension) {
232+
const { id, dimension } = build.functionCallNode(strandsContext, typeInfo.fnName, args, {
233+
overloads: [{
234+
params: [args[0].typeInfo()],
235+
returnType: typeInfo,
236+
}]
237+
});
238+
return createStrandsNode(id, dimension, strandsContext);
239+
} else {
240+
// For vector types with a single argument, repeat it for each component
241+
if (typeInfo.dimension > 1 && args.length === 1 && !Array.isArray(args[0]) &&
242+
!(args[0] instanceof StrandsNode && args[0].dimension > 1) &&
243+
(typeInfo.baseType === BaseType.FLOAT || typeInfo.baseType === BaseType.INT || typeInfo.baseType === BaseType.BOOL)) {
244+
args = Array(typeInfo.dimension).fill(args[0]);
245+
}
246+
const { id, dimension } = build.primitiveConstructorNode(strandsContext, typeInfo, args);
247+
return createStrandsNode(id, dimension, strandsContext);
236248
}
237-
const { id, dimension } = build.primitiveConstructorNode(strandsContext, typeInfo, args);
238-
return createStrandsNode(id, dimension, strandsContext);
239249
} else if (originalp5Fn) {
240250
return originalp5Fn.apply(this, args);
241251
} else {

src/strands/strands_node.js

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,21 @@ export class StrandsNode {
1313
const nodeData = getNodeDataFromID(dag, this.id);
1414
if (nodeData && nodeData.identifier) {
1515
this._originalIdentifier = nodeData.identifier;
16+
}
17+
if (nodeData) {
1618
this._originalBaseType = nodeData.baseType;
1719
this._originalDimension = nodeData.dimension;
1820
}
1921
}
2022
copy() {
2123
return createStrandsNode(this.id, this.dimension, this.strandsContext);
2224
}
25+
typeInfo() {
26+
return {
27+
baseType: this._originalBaseType || BaseType.FLOAT,
28+
dimension: this.dimension
29+
};
30+
}
2331
bridge(value) {
2432
const { dag, cfg } = this.strandsContext;
2533
const orig = getNodeDataFromID(dag, this.id);
@@ -30,8 +38,8 @@ export class StrandsNode {
3038
newValueID = value.id;
3139
} else {
3240
const newVal = primitiveConstructorNode(
33-
this.strandsContext,
34-
{ baseType, dimension: this.dimension },
41+
this.strandsContext,
42+
{ baseType, dimension: this.dimension },
3543
value
3644
);
3745
newValueID = newVal.id;
@@ -85,8 +93,8 @@ export class StrandsNode {
8593
newValueID = value.id;
8694
} else {
8795
const newVal = primitiveConstructorNode(
88-
this.strandsContext,
89-
{ baseType, dimension: this.dimension },
96+
this.strandsContext,
97+
{ baseType, dimension: this.dimension },
9098
value
9199
);
92100
newValueID = newVal.id;
@@ -159,4 +167,4 @@ export function createStrandsNode(id, dimension, strandsContext, onRebind) {
159167
new StrandsNode(id, dimension, strandsContext),
160168
swizzleTrap(id, dimension, strandsContext, onRebind)
161169
);
162-
}
170+
}

src/type/p5.Font.js

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -737,25 +737,14 @@ export class Font {
737737

738738
/////////////////////////////// HELPERS ////////////////////////////////
739739

740-
_verticalAlign(size) {
741-
const { sCapHeight } = this.data?.['OS/2'] || {};
742-
const { unitsPerEm = 1000 } = this.data?.head || {};
743-
const { ascender = 0, descender = 0 } = this.data?.hhea || {};
744-
const current = ascender / 2;
745-
const target = (sCapHeight || (ascender + descender)) / 2;
746-
const offset = target - current;
747-
return offset * size / unitsPerEm;
748-
}
749-
750740
/*
751741
Returns an array of line objects, each containing { text, x, y, glyphs: [ {g, path} ] }
752742
*/
753743
_lineateAndPathify(str, x, y, width, height, options = {}) {
754744

755745
let renderer = options?.graphics?._renderer || this._pInst._renderer;
756-
757-
// save the baseline
758-
let setBaseline = renderer.drawingContext.textBaseline;
746+
renderer.push();
747+
renderer.textFont(this);
759748

760749
// lineate and compute bounds for the text
761750
let { lines, bounds } = renderer._computeBounds
@@ -772,8 +761,7 @@ export class Font {
772761
const axs = this._currentAxes(renderer);
773762
let pathsForLine = lines.map(l => this._lineToGlyphs(l, { scale, axs }));
774763

775-
// restore the baseline
776-
renderer.drawingContext.textBaseline = setBaseline;
764+
renderer.pop();
777765

778766
return pathsForLine;
779767
}
@@ -857,7 +845,7 @@ export class Font {
857845

858846
_position(renderer, lines, bounds, width, height) {
859847

860-
let { textAlign, textLeading } = renderer.states;
848+
let { textAlign, textLeading, textSize } = renderer.states;
861849
let metrics = this._measureTextDefault(renderer, 'X');
862850
let ascent = metrics.fontBoundingBoxAscent;
863851

src/webgl/p5.Camera.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1856,6 +1856,8 @@ class Camera {
18561856
_cam.projMatrix = this.projMatrix.copy();
18571857
_cam.yScale = this.yScale;
18581858

1859+
_cam.cameraType = this.cameraType;
1860+
18591861
return _cam;
18601862
}
18611863

@@ -2957,15 +2959,18 @@ function camera(p5, fn){
29572959
p5.Camera = Camera;
29582960

29592961
Renderer3D.prototype.camera = function(...args) {
2962+
this.states.setValue('curCamera', this.states.curCamera.clone());
29602963
this.states.curCamera.camera(...args);
29612964
};
29622965

29632966
Renderer3D.prototype.perspective = function(...args) {
2967+
this.states.setValue('curCamera', this.states.curCamera.clone());
29642968
this.states.curCamera.perspective(...args);
29652969
};
29662970

29672971
Renderer3D.prototype.linePerspective = function(enable) {
29682972
if (enable !== undefined) {
2973+
this.states.setValue('curCamera', this.states.curCamera.clone());
29692974
// Set the line perspective if enable is provided
29702975
this.states.curCamera.useLinePerspective = enable;
29712976
} else {
@@ -2975,10 +2980,12 @@ function camera(p5, fn){
29752980
};
29762981

29772982
Renderer3D.prototype.ortho = function(...args) {
2983+
this.states.setValue('curCamera', this.states.curCamera.clone());
29782984
this.states.curCamera.ortho(...args);
29792985
};
29802986

29812987
Renderer3D.prototype.frustum = function(...args) {
2988+
this.states.setValue('curCamera', this.states.curCamera.clone());
29822989
this.states.curCamera.frustum(...args);
29832990
};
29842991

src/webgl/p5.Framebuffer.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ class FramebufferCamera extends Camera {
2525
this.defaultCameraFOV =
2626
2 * Math.atan(this.fbo.height / 2 / this.defaultEyeZ);
2727
}
28+
29+
copy() {
30+
const _cam = super.copy();
31+
_cam.fbo = this.fbo;
32+
return _cam;
33+
}
2834
}
2935

3036
class FramebufferTexture {

0 commit comments

Comments
 (0)