Skip to content

Commit

Permalink
update internal path handling to match webgl
Browse files Browse the repository at this point in the history
  • Loading branch information
dhowe committed Dec 2, 2024
1 parent b610249 commit bfe78c6
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 47 deletions.
33 changes: 15 additions & 18 deletions src/type/p5.Font.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,14 +109,11 @@ function font(p5, fn) {
textToPoints(str, x, y, width, height, options) {
({ width, height, options } = this._parseArgs(width, height, options));

// lineate and get the points for each line
// lineate and get the glyphs for each line
let glyphs = this.textToPaths(str, x, y, width, height, options);

// create a 2d array with path elements: [type, data[0], data[1], ...]
let cmds = glyphs.map(g => [g.type, ...g.data]); // TODO: rm

// convert paths to points with {sampleFactor, simplifyThreshold}
return pathToPoints(cmds, options);
// convert glyphs to points array with {sampleFactor, simplifyThreshold}
return pathToPoints(glyphs, options);
}

static async list(log = false) { // tmp
Expand Down Expand Up @@ -176,24 +173,25 @@ function font(p5, fn) {
let cmds = this.textToPaths(str, x, y, width, height, options);

// divide line-segments with intermediate points
const subdivide = (pts, pt1, pt2, maxDist) => {
if (fn.dist(pt1.x, pt1.y, pt2.x, pt2.y) > maxDist) {
const subdivide = (pts, pt1, pt2, md) => {
if (fn.dist(pt1.x, pt1.y, pt2.x, pt2.y) > md) {
let middle = { x: (pt1.x + pt2.x) / 2, y: (pt1.y + pt2.y) / 2 };
pts.push(middle);
subdivide(pts, pt1, middle, maxDist);
subdivide(pts, middle, pt2, maxDist);
subdivide(pts, pt1, middle, md);
subdivide(pts, middle, pt2, md);
}
}

// a point for each path-command plus line subdivisions
let pts = [];
let { textSize } = this._pInst._renderer.states;
let maxDist = textSize / this.data.head.unitsPerEm * 500;
let maxDist = (textSize / this.data.head.unitsPerEm) * 500;

for (let i = 0; i < cmds.length; i++) {
let { type, data: d } = cmds[i];
if (type !== 'Z') {
let pt = { x: d[d.length - 2], y: d[d.length - 1] }
if (type === 'L' && pts.length) {
if (type === 'L' && pts.length && !options?.nodivide > 0) {
subdivide(pts, pts[pts.length - 1], pt, maxDist);
}
pts.push(pt);
Expand Down Expand Up @@ -281,16 +279,16 @@ function font(p5, fn) {
let glyph = { g: line.text[i], /*points: [],*/ path: { commands: [] } };

for (let j = 0; j < cmds.length; j++) {
let type = cmds[j], command = { type, data: [] };
let type = cmds[j], command = [ type ];
if (type in pathArgCounts) {
let argCount = pathArgCounts[type];
for (let k = 0; k < argCount; k += 2) {
let gx = crds[k + crdIdx] + x + dx;
let gy = crds[k + crdIdx + 1] + y + dy;
let fx = line.x + gx * scale;
let fy = line.y + gy * -scale;
command.data.push(fx);
command.data.push(fy);
command.push(fx);
command.push(fy);
/*if (k === argCount - 2) {
glyph.points.push({ x: fx, y: fy });
}*/
Expand All @@ -317,7 +315,7 @@ function font(p5, fn) {
return metrics;
}

drawPaths(ctx, commands, opts) {
drawPaths(ctx, commands, opts) { // for debugging
ctx.strokeStyle = opts?.stroke || ctx.strokeStyle;
ctx.fillStyle = opts?.fill || ctx.strokeStyle;
ctx.beginPath();
Expand Down Expand Up @@ -422,7 +420,7 @@ function font(p5, fn) {
try {
// load the raw font bytes
let result = await fn.loadBytes(path);

// parse the font data
let fonts = Typr.parse(result);
if (fonts.length !== 1 || fonts[0]._data.length === 0) {
Expand Down Expand Up @@ -517,7 +515,6 @@ function font(p5, fn) {
};

function pathToPoints(cmds, options) {
//console.log('pathToPoints', cmds, options);

const parseOpts = (options, defaults) => {
if (typeof options !== 'object') {
Expand Down
2 changes: 1 addition & 1 deletion src/type/text2d.js
Original file line number Diff line number Diff line change
Expand Up @@ -1153,7 +1153,7 @@ function text2d(p5, fn) {
return; // don't render lines beyond minY/maxY
}

this._pInst.push(); // fix to v1 #803
this._pInst.push();

// no stroke unless specified by user
if (states.doStroke && states.strokeSet) {
Expand Down
48 changes: 20 additions & 28 deletions test/manual-test-examples/type/text-to-paths.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,16 @@
import p5 from '../../../src/app.js';

let sketch = function (p) {
let paths, f;

p.setup = async function () {
p.createCanvas(750, 350);
p.background(255);
p.textFont(f = await p.loadFont('./font/LiberationSans-Bold.ttf'), 300);
let f = await p.loadFont('./font/LiberationSans-Bold.ttf')
p.textFont(f, 300);
p.fill('#E92D55');

paths = f.textToPaths('p5*js', 5, 250);
// draw the paths
let paths = f.textToPaths('p5*js', 5, 250);

if (0) {
f.drawPaths(p.drawingContext, paths, { fill: '#E92D55' }); // DIRECT
Expand All @@ -44,23 +46,28 @@
drawPaths(paths, p); // USING P5: HANDLE INNER HOLES
}

f.textToPoints('p5*js', 5, 250, { sampleFactor: .1 }).forEach((pt, i) => {
// draw the points
f.textToPoints('p5*js', 5, 250).forEach((pt, i) => {
p.fill(0);
p.circle(pt.x, pt.y, 5);
});
}
}

function drawPaths(commands, p) {

p.beginShape();

// TODO: remove (dummy shape for now)
p.vertex(0,0);
p.vertex(0,0);
p.vertex(0,0);

for (let k = 0; k < commands.length; k++) {
let { type, data } = commands[k];
let data = commands[k];
let type = data.shift();
if (type === 'M') {
if (false) {
p.beginContour();
}
else {
p.beginShape();
}
p.beginContour();
p.vertex(...data);
} else if (type === 'L') {
p.vertex(...data);
Expand All @@ -69,25 +76,10 @@
} else if (type === 'Q') {
p.quadraticVertex(...data);
} else if (type === 'Z') {
if (false) {
p.endContour();
}
p.endShape(p.CLOSE);
}
}
}

function clockwise(vertices) {
function polygonArea() {
let area = 0;
for (let i = 0; i < vertices.length; i++) {
j = (i + 1) % vertices.length;
area += vertices[i].x * vertices[j].y;
area -= vertices[j].x * vertices[i].y;
p.endContour();
}
return area / 2;
}
return polygonArea() > 0;
p.endShape();
}

new p5(sketch);
Expand Down

0 comments on commit bfe78c6

Please sign in to comment.