Skip to content

Commit

Permalink
Merge pull request #7417 from processing/feat/webgl-fonts-2.0
Browse files Browse the repository at this point in the history
Refactor 2.0 Typography code to work with WebGL
  • Loading branch information
davepagurek authored Dec 11, 2024
2 parents 584504d + d918802 commit 8d5498d
Show file tree
Hide file tree
Showing 8 changed files with 436 additions and 293 deletions.
24 changes: 12 additions & 12 deletions preview/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,30 +20,30 @@
import p5 from '../src/app.js';

const sketch = function (p) {
let g, f;
let f;
const testWebgl = true

p.setup = function () {
p.createCanvas(200, 200);
g = p.createGraphics(200, 200);
f = p.createGraphics(200, 200, p.WEBGL);
p.setup = async function () {
// TODO: make this work without a name
f = await p.loadFont('font/Lato-Black.ttf', 'Lato')
p.createCanvas(200, 200, testWebgl ? p.WEBGL : undefined);
};

p.draw = function () {
p.background(0, 50, 50);
p.circle(100, 100, 50);
if (testWebgl) p.translate(-p.width/2, -p.height/2);

p.fill('white');
p.textSize(30);
p.text('hello', 10, 30);

// f.fill('red');
f.sphere();
p.image(f, 0, 0);
p.textSize(60);
p.textAlign(p.RIGHT, p.CENTER)
p.textFont(f)
p.text('hello, world!', 0, p.height/2, p.width);
};
};

new p5(sketch);
</script>
<p style="font-family: Lato">hello, world!</p>
</body>

</html>
8 changes: 4 additions & 4 deletions src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,6 @@ io(p5);
import math from './math';
math(p5);

// typography
import type from './type'
type(p5);

// utilities
import utilities from './utilities';
utilities(p5);
Expand All @@ -61,6 +57,10 @@ utilities(p5);
import webgl from './webgl';
webgl(p5);

// typography
import type from './type'
type(p5);

import './core/init';

export default p5;
6 changes: 3 additions & 3 deletions src/core/p5.Renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class Renderer {
rectMode: constants.CORNER,
ellipseMode: constants.CENTER,

textFont: 'sans-serif',
textFont: { family: 'sans-serif' },
textLeading: 15,
leadingSet: false,
textSize: 12,
Expand Down Expand Up @@ -485,8 +485,8 @@ class Renderer {
/**
* Helper function to check font type (system or otf)
*/
_isOpenType(f = this.states.textFont) {
return typeof f === 'object' && f.font && f.font.supported;
_isOpenType({ font: f } = this.states.textFont) {
return typeof f === 'object' && f.data;
}

_updateTextMetrics() {
Expand Down
4 changes: 2 additions & 2 deletions src/core/p5.Renderer2D.js
Original file line number Diff line number Diff line change
Expand Up @@ -1405,7 +1405,7 @@ class Renderer2D extends Renderer {
return p;
}

_applyTextProperties() {
/*_applyTextProperties() {
let font;
const p = this._pInst;
Expand Down Expand Up @@ -1435,7 +1435,7 @@ class Renderer2D extends Renderer {
}
return p;
}
}*/

//////////////////////////////////////////////
// STRUCTURE
Expand Down
113 changes: 74 additions & 39 deletions src/type/p5.Font.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
/**
/**
* API:
* loadFont("https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,[email protected],200..800&display=swap")
* loadFont("{ font-family: "Bricolage Grotesque", serif; font-optical-sizing: auto; font-weight: <weight> font-style: normal; font-variation-settings: "wdth" 100; });
* loadFont({
* fontFamily: '"Bricolage Grotesque", serif';
* loadFont({
* fontFamily: '"Bricolage Grotesque", serif';
* fontOpticalSizing: 'auto';
* fontWeight: '<weight>';
* fontStyle: 'normal';
* fontVariationSettings: '"wdth" 100';
* fontVariationSettings: '"wdth" 100';
* });
* loadFont("https://fonts.gstatic.com/s/bricolagegrotesque/v1/pxiAZBhjZQIdd8jGnEotWQ.woff2");
* loadFont("./path/to/localFont.ttf");
* loadFont("system-font-name");
*
*
*
*
* NEXT:
* extract axes from font file
*
* TEST:
*
* TEST:
* const font = new FontFace("Inter", "url(./fonts/inter-latin-variable-full-font.woff2)", {
style: "oblique 0deg 10deg",
weight: "100 900",
Expand Down Expand Up @@ -53,6 +53,16 @@ function font(p5, fn) {
this.face = fontFace;
}

verticalAlign(size) {
const { sCapHeight } = this.data?.['OS/2'] || {};
const { unitsPerEm = 1000 } = this.data?.head || {};
const { ascender = 0, descender = 0 } = this.data?.hhea || {};
const current = ascender / 2;
const target = (sCapHeight || (ascender + descender)) / 2;
const offset = target - current;
return offset * size / unitsPerEm;
}

variations() {
let vars = {};
if (this.data) {
Expand Down Expand Up @@ -254,20 +264,63 @@ function font(p5, fn) {
return lines.map(coordify);
}

_lineToGlyphs(line, scale) {
_lineToGlyphs(line, scale = 1) {

if (!this.data) {
throw Error('No font data available for "' + this.name
+ '"\nTry downloading a local copy of the font file');
}
let glyphShapes = Typr.U.shape(this.data, line.text);
line.glyphShapes = glyphShapes;
line.glyphs = this._shapeToPaths(glyphShapes, line, scale);

return line;
}

_shapeToPaths(glyphs, line, scale) {
_positionGlyphs(text) {
const glyphShapes = Typr.U.shape(this.data, text);
const positionedGlyphs = [];
let x = 0;
for (const glyph of glyphShapes) {
positionedGlyphs.push({ x, index: glyph.g, shape: glyph });
x += glyph.ax;
}
return positionedGlyphs;
}

_singleShapeToPath(shape, { scale = 1, x = 0, y = 0, lineX = 0, lineY = 0 } = {}) {
let font = this.data;
let crdIdx = 0;
let { g, ax, ay, dx, dy } = shape;
let { crds, cmds } = Typr.U.glyphToPath(font, g);

// can get simple points for each glyph here, but we don't need them ?
let glyph = { /*g: line.text[i], points: [],*/ path: { commands: [] } };

for (let j = 0; j < cmds.length; j++) {
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 = lineX + gx * scale;
let fy = lineY + gy * -scale;
command.push(fx);
command.push(fy);
/*if (k === argCount - 2) {
glyph.points.push({ x: fx, y: fy });
}*/
}
crdIdx += argCount;
}
glyph.path.commands.push(command);
}

return { glyph, ax, ay };
}

_shapeToPaths(glyphs, line, scale = 1) {
let x = 0, y = 0, paths = [];

if (glyphs.length !== line.text.length) {
Expand All @@ -277,32 +330,14 @@ function font(p5, fn) {
// iterate over the glyphs, converting each to a glyph object
// with a path property containing an array of commands
for (let i = 0; i < glyphs.length; i++) {
let crdIdx = 0;
let { g, ax, ay, dx, dy } = glyphs[i];
let { crds, cmds } = Typr.U.glyphToPath(font, g);

// can get simple points for each glyph here, but we don't need them ?
let glyph = { g: line.text[i], /*points: [],*/ path: { commands: [] } };

for (let j = 0; j < cmds.length; j++) {
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.push(fx);
command.push(fy);
/*if (k === argCount - 2) {
glyph.points.push({ x: fx, y: fy });
}*/
}
crdIdx += argCount;
}
glyph.path.commands.push(command);
}
const { glyph, ax, ay } = this._singleShapeToPath(glyphs[i], {
scale,
x,
y,
lineX: line.x,
lineY: line.y,
});

paths.push(glyph);
x += ax; y += ay;
}
Expand Down Expand Up @@ -411,7 +446,7 @@ function font(p5, fn) {

/**
* Load a font and returns a p5.Font instance. The font can be specified by its path or a url.
* Optional arguments include the font name, descriptors for the FontFace object,
* Optional arguments include the font name, descriptors for the FontFace object,
* and callbacks for success and error.
* @param {...any} args - path, name, onSuccess, onError, descriptors
* @returns a Promise that resolves with a p5.Font instance
Expand All @@ -430,7 +465,7 @@ function font(p5, fn) {

// parse the font data
let fonts = Typr.parse(result);

if (fonts.length !== 1 || fonts[0].cmap === undefined) {
throw Error(23);
}
Expand Down Expand Up @@ -1059,4 +1094,4 @@ export default font;

if (typeof p5 !== 'undefined') {
font(p5, p5.prototype);
}
}
Loading

0 comments on commit 8d5498d

Please sign in to comment.