diff --git a/src/type/p5.Font.js b/src/type/p5.Font.js index 52c6755f8b..90b3d3968c 100644 --- a/src/type/p5.Font.js +++ b/src/type/p5.Font.js @@ -127,10 +127,194 @@ class Font { return cmdContours.map((commands) => pathToPoints(commands, options, this)); } - /** - * Test - */ + * + * Converts text into a 3D model that can be rendered in WebGL mode. + * + * This method transforms flat text into extruded 3D geometry, allowing + * for dynamic effects like depth, warping, and custom shading. + * + * It works by taking the outlines (contours) of each character in the + * provided text string and constructing a 3D shape from them. + * + * Once your 3D text is ready, you can rotate it in 3D space using orbitControl() + * — just click and drag with your mouse to see it from all angles! + * + * Use the extrude slider to give your letters depth: slide it up, and your + * flat text turns into a solid, multi-dimensional object. + * + * You can also choose from various fonts such as "Anton", "Montserrat", or "Source Serif", + * much like selecting fancy fonts in a word processor, + * + * The generated model (a Geometry object) can be manipulated further—rotated, scaled, + * or styled with shaders—to create engaging, interactive visual art. + * + * @param {String} str The text string to convert into a 3D model. + * @param {Number} x The x-coordinate for the starting position of the text. + * @param {Number} y The y-coordinate for the starting position of the text. + * @param {Number} width Maximum width of the text block (wraps text if exceeded). + * @param {Number} height Maximum height of the text block. + * @param {Object} [options] Configuration options for the 3D text: + * @param {Number} [options.extrude=0] The depth to extrude the text. A value of 0 produces + * flat text; higher values create thicker, 3D models. + * @param {Number} [options.sampleFactor=1] A factor controlling the level of detail for the text contours. + * Higher values result in smoother curves. + * @return {p5.Geometry} A geometry object representing the 3D model of the text. + * + * @example + *
+ * + * let font; + * let geom; + * + * async function setup() { + * createCanvas(200, 200, WEBGL); + * fonts = { + * Anton: await loadFont('https://fonts.gstatic.com/s/anton/v25/1Ptgg87LROyAm0K08i4gS7lu.ttf') + * }; + * + * // Create 3D geometry from text using the Anton font + * geom = fonts['Anton'].textToModel("Hello", 50, 0, { sampleFactor: 2 }); + * geom.clearColors(); + * geom.normalize(); + * } + * + * function draw() { + * background(255); + * orbitControl(); // Enables mouse control to rotate the 3D text + * fill("red"); + * strokeWeight(4); + * scale(min(width, height) / 300); + * model(geom); + * + * describe('A red non-extruded "Hello" in Anton on white canvas, rotatable via mouse.'); + * } + * + *
+ * + * @example + *
+ * + * let font; + * let geom; + * + * async function setup() { + * createCanvas(200, 200, WEBGL); + * fonts = { + * Anton: await loadFont('https://fonts.gstatic.com/s/anton/v25/1Ptgg87LROyAm0K08i4gS7lu.ttf'), + * Montserrat: await loadFont('https://fonts.gstatic.com/s/montserrat/v29/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCtr6Ew-Y3tcoqK5.ttf'), + * 'Source Serif': await loadFont('https://fonts.gstatic.com/s/sourceserif4/v8/vEFy2_tTDB4M7-auWDN0ahZJW3IX2ih5nk3AucvUHf6OAVIJmeUDygwjihdqrhxXD-wGvjU.ttf'), + * }; + * + * // You can change fonts from here. + * geom = fonts['Source Serif'].textToModel("Hello", 50, 0, { sampleFactor: 2, extrude: 5 }); + * geom.clearColors(); + * geom.normalize(); + * } + * + * function draw() { + * background(255); + * orbitControl(); // Enables mouse control to rotate the 3D text. + * fill("red"); + * strokeWeight(4); + * scale(min(width, height) / 300); + * model(geom); + * + * describe('3D red extruded "Hello" in Source Serif on white, rotatable via mouse.'); + * } + * + *
+ * + * @example + *
+ * + * let geom; + * let fonts; + * let artShader; + * let lineShader; + * + * // Define parameters as simple variables + * let words = 'HELLO'; + * let font = 'Anton'; + * let warp = 1; + * let extrude = 5; + * let palette = ["#ffe03d", "#fe4830", "#d33033", "#6d358a", "#1c509e", "#00953c"]; + * + * async function setup() { + * createCanvas(200, 200, WEBGL); + * fonts = { + * Anton: await loadFont('https://fonts.gstatic.com/s/anton/v25/1Ptgg87LROyAm0K08i4gS7lu.ttf'), + * Montserrat: await loadFont('https://fonts.gstatic.com/s/montserrat/v29/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCtr6Ew-Y3tcoqK5.ttf'), + * 'Source Serif': await loadFont('https://fonts.gstatic.com/s/sourceserif4/v8/vEFy2_tTDB4M7-auWDN0ahZJW3IX2ih5nk3AucvUHf6OAVIJmeUDygwjihdqrhxXD-wGvjU.ttf'), + * }; + * + * artShader = baseMaterialShader().modify({ + * uniforms: { + * 'float time': () => millis(), + * 'float warp': () => warp, + * 'float numColors': () => palette.length, + * 'vec3[6] colors': () => palette.flatMap((c) => [red(c)/255, green(c)/255, blue(c)/255]), + * }, + * vertexDeclarations: 'out vec3 vPos;', + * fragmentDeclarations: 'in vec3 vPos;', + * 'Vertex getObjectInputs': `(Vertex inputs) { + * vPos = inputs.position; + * inputs.position.x += 5. * warp * sin(inputs.position.y * 0.1 + time * 0.001) / (1. + warp); + * inputs.position.y += 5. * warp * sin(inputs.position.x * 0.1 + time * 0.0009) / (1. + warp); + * return inputs; + * }`, + * 'vec4 getFinalColor': `(vec4 _c) { + * float x = vPos.x * 0.005; + * float a = floor(fract(x) * numColors); + * float b = a == numColors - 1. ? 0. : a + 1.; + * float t = fract(x * numColors); + * vec3 c = mix(colors[int(a)], colors[int(b)], t); + * return vec4(c, 1.); + * }` + * }); + * + * lineShader = baseStrokeShader().modify({ + * uniforms: { + * 'float time': () => millis(), + * 'float warp': () => warp, + * }, + * 'StrokeVertex getObjectInputs': `(StrokeVertex inputs) { + * inputs.position.x += 5. * warp * sin(inputs.position.y * 0.1 + time * 0.001) / (1. + warp); + * inputs.position.y += 5. * warp * sin(inputs.position.x * 0.1 + time * 0.0009) / (1. + warp); + * return inputs; + * }`, + * }); + * } + * + * let prevWords = ''; + * let prevFont = ''; + * let prevExtrude = -1; + * + * function draw() { + * if (words !== prevWords || prevFont !== font || prevExtrude !== extrude) { + * if (geom) freeGeometry(geom); + * + * geom = fonts[font].textToModel(words, 0, 50, { sampleFactor: 2, extrude }); + * geom.clearColors(); + * geom.normalize(); + * + * prevWords = words; + * prevFont = font; + * prevExtrude = extrude; + * } + * + * background(255); + * orbitControl(); + * shader(artShader); + * strokeShader(lineShader); + * strokeWeight(4); + * scale(min(width, height) / 210); + * model(geom); + * describe('3D wavy with different color sets "Hello" in Anton on white canvas, rotatable via mouse.'); + * } + * + *
+ */ textToModel(str, x, y, width, height, options) { ({ width, height, options } = this._parseArgs(width, height, options)); const extrude = options?.extrude || 0;