Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor 2.0 Typography code to work with WebGL #7417

Merged
merged 5 commits into from
Dec 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading