From 172558e8df1a96381f6e269a5f9a0e0e8fccb461 Mon Sep 17 00:00:00 2001 From: Perminder Date: Mon, 3 Mar 2025 23:30:52 +0530 Subject: [PATCH 1/6] update-docs --- src/type/p5.Font.js | 181 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 180 insertions(+), 1 deletion(-) diff --git a/src/type/p5.Font.js b/src/type/p5.Font.js index 462c7d9695..0358ef213b 100644 --- a/src/type/p5.Font.js +++ b/src/type/p5.Font.js @@ -121,7 +121,186 @@ function font(p5, fn) { return cmdContours.map((commands) => pathToPoints(commands, options, this)); } - + /** + * Sets the p5.Shader object to apply while drawing. + * + * Shaders are programs that run on the graphics processing unit (GPU). They + * can process many pixels or vertices at the same time, making them fast for + * many graphics tasks. They’re written in a language called + * GLSL + * and run along with the rest of the code in a sketch. + * p5.Shader objects can be created using the + * createShader() and + * loadShader() functions. + * + * The parameter, `s`, is the p5.Shader object to + * apply. For example, calling `shader(myShader)` applies `myShader` to + * process each pixel on the canvas. This only changes the fill (the inner part of shapes), + * but does not affect the outlines (strokes) or any images drawn using the `image()` function. + * The source code from a p5.Shader object's + * fragment and vertex shaders will be compiled the first time it's passed to + * `shader()`. See + * MDN + * for more information about compiling shaders. + * + * Calling resetShader() restores a sketch’s + * default shaders. + * + * Note: Shaders can only be used in WebGL mode. + * + *
+ *

+ * + * If you want to apply shaders to strokes or images, use the following methods: + * - **[strokeShader()](#/p5/strokeShader)**: Applies a shader to the stroke (outline) of shapes, allowing independent control over the stroke rendering using shaders. + * - **[imageShader()](#/p5/imageShader)**: Applies a shader to images or textures, controlling how the shader modifies their appearance during rendering. + * + *

+ *
+ * + * + * @method shader + * @chainable + * @param {p5.Shader} s p5.Shader object + * to apply. + * + * @example + *
+ * + * let fillShader; + * + * let vertSrc = ` + * precision highp float; + * attribute vec3 aPosition; + * uniform mat4 uModelViewMatrix; + * uniform mat4 uProjectionMatrix; + * varying vec3 vPosition; + * + * void main() { + * vPosition = aPosition; + * gl_Position = uProjectionMatrix * uModelViewMatrix * vec4(aPosition, 1.0); + * } + * `; + * + * let fragSrc = ` + * precision highp float; + * uniform vec3 uLightDir; + * varying vec3 vPosition; + * + * void main() { + * vec3 lightDir = normalize(uLightDir); + * float brightness = dot(lightDir, normalize(vPosition)); + * brightness = clamp(brightness, 0.4, 1.0); + * vec3 color = vec3(0.3, 0.5, 1.0); + * color = color * brightness * 3.0; + * gl_FragColor = vec4(color, 1.0); + * } + * `; + * + * function setup() { + * createCanvas(100, 100, WEBGL); + * fillShader = createShader(vertSrc, fragSrc); + * noStroke(); + * describe('A rotating torus with simulated directional lighting.'); + * } + * + * function draw() { + * background(20, 20, 40); + * let lightDir = [0.5, 0.5, -1.0]; + * fillShader.setUniform('uLightDir', lightDir); + * shader(fillShader); + * rotateY(frameCount * 0.02); + * rotateX(frameCount * 0.02); + * //lights(); + * torus(25, 10, 30, 30); + * } + * + *
+ * + * @example + *
+ * + * let fillShader; + * + * let vertSrc = ` + * precision highp float; + * attribute vec3 aPosition; + * uniform mat4 uProjectionMatrix; + * uniform mat4 uModelViewMatrix; + * varying vec3 vPosition; + * void main() { + * vPosition = aPosition; + * gl_Position = uProjectionMatrix * uModelViewMatrix * vec4(aPosition, 1.0); + * } + * `; + * + * let fragSrc = ` + * precision highp float; + * uniform vec3 uLightPos; + * uniform vec3 uFillColor; + * varying vec3 vPosition; + * void main() { + * float brightness = dot(normalize(uLightPos), normalize(vPosition)); + * brightness = clamp(brightness, 0.0, 1.0); + * vec3 color = uFillColor * brightness; + * gl_FragColor = vec4(color, 1.0); + * } + * `; + * + * function setup() { + * createCanvas(100, 100, WEBGL); + * fillShader = createShader(vertSrc, fragSrc); + * shader(fillShader); + * noStroke(); + * describe('A square affected by both fill color and lighting, with lights controlled by mouse.'); + * } + * + * function draw() { + * let lightPos = [(mouseX - width / 2) / width, + * (mouseY - height / 2) / height, 1.0]; + * fillShader.setUniform('uLightPos', lightPos); + * let fillColor = [map(mouseX, 0, width, 0, 1), + * map(mouseY, 0, height, 0, 1), 0.5]; + * fillShader.setUniform('uFillColor', fillColor); + * plane(100, 100); + * } + * + *
+ * + * @example + *
+ * + * let myShader; + * + * function setup() { + * createCanvas(100, 100, WEBGL); + * + * myShader = baseMaterialShader().modify({ + * declarations: 'uniform float time;', + * 'vec4 getFinalColor': `(vec4 color) { + * float r = 0.2 + 0.5 * abs(sin(time + 0.0)); + * float g = 0.2 + 0.5 * abs(sin(time + 1.0)); + * float b = 0.2 + 0.5 * abs(sin(time + 2.0)); + * color.rgb = vec3(r, g, b); + * return color; + * }` + * }); + * + * noStroke(); + * describe('A 3D cube with dynamically changing colors on a beige background.'); + * } + * + * function draw() { + * background(245, 245, 220); + * shader(myShader); + * myShader.setUniform('time', millis() / 1000.0); + * + * box(50); + * } + * + *
+ * + */ textToModel(str, x, y, width, height, options) { ({ width, height, options } = this._parseArgs(width, height, options)); const extrude = options?.extrude || 0; From 310063e346300f93359bb07302e620c5717e26a0 Mon Sep 17 00:00:00 2001 From: Perminder Date: Mon, 3 Mar 2025 23:55:34 +0530 Subject: [PATCH 2/6] fixing --- src/type/p5.Font.js | 181 +------------------------------------------- 1 file changed, 1 insertion(+), 180 deletions(-) diff --git a/src/type/p5.Font.js b/src/type/p5.Font.js index 0358ef213b..462c7d9695 100644 --- a/src/type/p5.Font.js +++ b/src/type/p5.Font.js @@ -121,186 +121,7 @@ function font(p5, fn) { return cmdContours.map((commands) => pathToPoints(commands, options, this)); } - /** - * Sets the p5.Shader object to apply while drawing. - * - * Shaders are programs that run on the graphics processing unit (GPU). They - * can process many pixels or vertices at the same time, making them fast for - * many graphics tasks. They’re written in a language called - * GLSL - * and run along with the rest of the code in a sketch. - * p5.Shader objects can be created using the - * createShader() and - * loadShader() functions. - * - * The parameter, `s`, is the p5.Shader object to - * apply. For example, calling `shader(myShader)` applies `myShader` to - * process each pixel on the canvas. This only changes the fill (the inner part of shapes), - * but does not affect the outlines (strokes) or any images drawn using the `image()` function. - * The source code from a p5.Shader object's - * fragment and vertex shaders will be compiled the first time it's passed to - * `shader()`. See - * MDN - * for more information about compiling shaders. - * - * Calling resetShader() restores a sketch’s - * default shaders. - * - * Note: Shaders can only be used in WebGL mode. - * - *
- *

- * - * If you want to apply shaders to strokes or images, use the following methods: - * - **[strokeShader()](#/p5/strokeShader)**: Applies a shader to the stroke (outline) of shapes, allowing independent control over the stroke rendering using shaders. - * - **[imageShader()](#/p5/imageShader)**: Applies a shader to images or textures, controlling how the shader modifies their appearance during rendering. - * - *

- *
- * - * - * @method shader - * @chainable - * @param {p5.Shader} s p5.Shader object - * to apply. - * - * @example - *
- * - * let fillShader; - * - * let vertSrc = ` - * precision highp float; - * attribute vec3 aPosition; - * uniform mat4 uModelViewMatrix; - * uniform mat4 uProjectionMatrix; - * varying vec3 vPosition; - * - * void main() { - * vPosition = aPosition; - * gl_Position = uProjectionMatrix * uModelViewMatrix * vec4(aPosition, 1.0); - * } - * `; - * - * let fragSrc = ` - * precision highp float; - * uniform vec3 uLightDir; - * varying vec3 vPosition; - * - * void main() { - * vec3 lightDir = normalize(uLightDir); - * float brightness = dot(lightDir, normalize(vPosition)); - * brightness = clamp(brightness, 0.4, 1.0); - * vec3 color = vec3(0.3, 0.5, 1.0); - * color = color * brightness * 3.0; - * gl_FragColor = vec4(color, 1.0); - * } - * `; - * - * function setup() { - * createCanvas(100, 100, WEBGL); - * fillShader = createShader(vertSrc, fragSrc); - * noStroke(); - * describe('A rotating torus with simulated directional lighting.'); - * } - * - * function draw() { - * background(20, 20, 40); - * let lightDir = [0.5, 0.5, -1.0]; - * fillShader.setUniform('uLightDir', lightDir); - * shader(fillShader); - * rotateY(frameCount * 0.02); - * rotateX(frameCount * 0.02); - * //lights(); - * torus(25, 10, 30, 30); - * } - * - *
- * - * @example - *
- * - * let fillShader; - * - * let vertSrc = ` - * precision highp float; - * attribute vec3 aPosition; - * uniform mat4 uProjectionMatrix; - * uniform mat4 uModelViewMatrix; - * varying vec3 vPosition; - * void main() { - * vPosition = aPosition; - * gl_Position = uProjectionMatrix * uModelViewMatrix * vec4(aPosition, 1.0); - * } - * `; - * - * let fragSrc = ` - * precision highp float; - * uniform vec3 uLightPos; - * uniform vec3 uFillColor; - * varying vec3 vPosition; - * void main() { - * float brightness = dot(normalize(uLightPos), normalize(vPosition)); - * brightness = clamp(brightness, 0.0, 1.0); - * vec3 color = uFillColor * brightness; - * gl_FragColor = vec4(color, 1.0); - * } - * `; - * - * function setup() { - * createCanvas(100, 100, WEBGL); - * fillShader = createShader(vertSrc, fragSrc); - * shader(fillShader); - * noStroke(); - * describe('A square affected by both fill color and lighting, with lights controlled by mouse.'); - * } - * - * function draw() { - * let lightPos = [(mouseX - width / 2) / width, - * (mouseY - height / 2) / height, 1.0]; - * fillShader.setUniform('uLightPos', lightPos); - * let fillColor = [map(mouseX, 0, width, 0, 1), - * map(mouseY, 0, height, 0, 1), 0.5]; - * fillShader.setUniform('uFillColor', fillColor); - * plane(100, 100); - * } - * - *
- * - * @example - *
- * - * let myShader; - * - * function setup() { - * createCanvas(100, 100, WEBGL); - * - * myShader = baseMaterialShader().modify({ - * declarations: 'uniform float time;', - * 'vec4 getFinalColor': `(vec4 color) { - * float r = 0.2 + 0.5 * abs(sin(time + 0.0)); - * float g = 0.2 + 0.5 * abs(sin(time + 1.0)); - * float b = 0.2 + 0.5 * abs(sin(time + 2.0)); - * color.rgb = vec3(r, g, b); - * return color; - * }` - * }); - * - * noStroke(); - * describe('A 3D cube with dynamically changing colors on a beige background.'); - * } - * - * function draw() { - * background(245, 245, 220); - * shader(myShader); - * myShader.setUniform('time', millis() / 1000.0); - * - * box(50); - * } - * - *
- * - */ + textToModel(str, x, y, width, height, options) { ({ width, height, options } = this._parseArgs(width, height, options)); const extrude = options?.extrude || 0; From bf0bf877eb4307439f9bf0a73b7a1f572e512d23 Mon Sep 17 00:00:00 2001 From: Perminder Date: Tue, 4 Mar 2025 03:10:42 +0530 Subject: [PATCH 3/6] textToModel-docs-update --- src/type/p5.Font.js | 191 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 186 insertions(+), 5 deletions(-) diff --git a/src/type/p5.Font.js b/src/type/p5.Font.js index 462c7d9695..9aace6c0a4 100644 --- a/src/type/p5.Font.js +++ b/src/type/p5.Font.js @@ -122,6 +122,187 @@ function font(p5, fn) { return cmdContours.map((commands) => pathToPoints(commands, options, this)); } + /** + * + * 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. + * + * + * @method textToModel + * @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') + * } + * geom = fonts['Anton'].textToModel("Hello World!", 50, 0, { sampleFactor: 2 }); + * geom.clearColors(); + * geom.normalize(); + * } + * + * function draw() { + * background(255); + * fill("red"); + * strokeWeight(4); + * scale(min(width, height) / 300); + * model(geom); + * } + * + *
+ * + * 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, + * + * @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'), + * } + * geom = fonts['Anton'].textToModel("Hello World!", 50, 0, { sampleFactor: 2, extrude: 5 }); + * geom.clearColors(); + * geom.normalize(); + * } + * + * function draw() { + * background(255); + * orbitControl(); + * fill("red"); + * strokeWeight(4); + * scale(min(width, height) / 300); + * model(geom); + * } + * + *
+ * + * The generated model (a Geometry object) can be manipulated further—rotated, scaled, + * or styled with shaders—to create engaging, interactive visual art. + * + * @example + *
+ * + * let geom; + * let fonts; + * let artShader; + * let lineShader; + * + * // Define parameters as simple variables + * let words = 'Word Art!'; + * let font = 'Anton'; + * let warp = 1; + * let extrude = 5; + * let palette = ["#ffe03d", "#fe4830", "#d33033", "#6d358a", "#1c509e", "#00953c"]; + * + * async function setup() { + * createCanvas(windowWidth, windowHeight, 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) / 300); + * model(geom); + * } + * + *
+ */ + textToModel(str, x, y, width, height, options) { ({ width, height, options } = this._parseArgs(width, height, options)); const extrude = options?.extrude || 0; @@ -598,7 +779,7 @@ function font(p5, fn) { // make sure we have a valid name name = name || extractFontName(fonts[0], path); - + // create a FontFace object and pass it to the p5.Font constructor pfont = await create(this, name, path, descriptors, fonts[0]); @@ -625,7 +806,7 @@ function font(p5, fn) { } async function create(pInst, name, path, descriptors, rawFont) { - + let face = createFontFace(name, path, descriptors, rawFont); // load if we need to @@ -633,7 +814,7 @@ function font(p5, fn) { // add it to the document document.fonts.add(face); - + // return a new p5.Font return new p5.Font(pInst, face, name, path, rawFont); } @@ -673,7 +854,7 @@ function font(p5, fn) { let result, meta = font?.name; // use the metadata if we have it - if (meta) { + if (meta) { if (meta.fullName) { return meta.fullName; } @@ -694,7 +875,7 @@ function font(p5, fn) { result = path; } } - + // replace spaces with underscores if (result.includes(' ')) { result = result.replace(/ /g, '_'); From f6eb13b0c7490504ee3378a07f779c535b7e42eb Mon Sep 17 00:00:00 2001 From: Perminder Singh <127239756+perminder-17@users.noreply.github.com> Date: Tue, 18 Mar 2025 05:32:03 +0530 Subject: [PATCH 4/6] fixes textToModel docs --- src/type/p5.Font.js | 207 +++++++++++++++++++++++--------------------- 1 file changed, 108 insertions(+), 99 deletions(-) diff --git a/src/type/p5.Font.js b/src/type/p5.Font.js index 9aace6c0a4..a6af9f5acf 100644 --- a/src/type/p5.Font.js +++ b/src/type/p5.Font.js @@ -122,7 +122,7 @@ function font(p5, fn) { return cmdContours.map((commands) => pathToPoints(commands, options, this)); } - /** + /** * * Converts text into a 3D model that can be rendered in WebGL mode. * @@ -132,8 +132,20 @@ function font(p5, fn) { * 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. * * @method textToModel + * @memberof p5.Font * @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. @@ -153,34 +165,30 @@ function font(p5, fn) { * let geom; * * async function setup() { - * createCanvas(200, 200, WEBGL); - * fonts = { - * Anton: await loadFont('https://fonts.gstatic.com/s/anton/v25/1Ptgg87LROyAm0K08i4gS7lu.ttf') - * } - * geom = fonts['Anton'].textToModel("Hello World!", 50, 0, { sampleFactor: 2 }); - * geom.clearColors(); - * geom.normalize(); + * 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); - * fill("red"); - * strokeWeight(4); - * scale(min(width, height) / 300); - * model(geom); + * 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.'); * } * * * - * 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, - * * @example *
* @@ -188,31 +196,32 @@ function font(p5, fn) { * 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'), - * } - * geom = fonts['Anton'].textToModel("Hello World!", 50, 0, { sampleFactor: 2, extrude: 5 }); - * geom.clearColors(); - * geom.normalize(); + * 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(); - * fill("red"); - * strokeWeight(4); - * scale(min(width, height) / 300); - * model(geom); + * 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.'); * } * *
* - * The generated model (a Geometry object) can be manipulated further—rotated, scaled, - * or styled with shaders—to create engaging, interactive visual art. - * * @example *
* @@ -222,56 +231,56 @@ function font(p5, fn) { * let lineShader; * * // Define parameters as simple variables - * let words = 'Word Art!'; + * let words = 'HELLO'; * let font = 'Anton'; * let warp = 1; * let extrude = 5; * let palette = ["#ffe03d", "#fe4830", "#d33033", "#6d358a", "#1c509e", "#00953c"]; * * async function setup() { - * createCanvas(windowWidth, windowHeight, 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'), - * }; + * 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.); - * }` - * }); + * 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; - * }`, - * }); + * 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 = ''; @@ -279,30 +288,30 @@ function font(p5, fn) { * let prevExtrude = -1; * * function draw() { - * if (words !== prevWords || prevFont !== font || prevExtrude !== extrude) { - * if (geom) freeGeometry(geom); + * 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(); + * geom = fonts[font].textToModel(words, 0, 50, { sampleFactor: 2, extrude }); + * geom.clearColors(); + * geom.normalize(); * - * prevWords = words; - * prevFont = font; - * prevExtrude = extrude; - * } + * prevWords = words; + * prevFont = font; + * prevExtrude = extrude; + * } * - * background(255); - * orbitControl(); - * shader(artShader); - * strokeShader(lineShader); - * strokeWeight(4); - * scale(min(width, height) / 300); - * model(geom); + * 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; From 337e47e4c5ba274b53232b2f9e8f160d8721ae37 Mon Sep 17 00:00:00 2001 From: Perminder Singh <127239756+perminder-17@users.noreply.github.com> Date: Wed, 19 Mar 2025 02:14:16 +0530 Subject: [PATCH 5/6] some fixes --- src/type/p5.Font.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/type/p5.Font.js b/src/type/p5.Font.js index a6af9f5acf..7dd67e0913 100644 --- a/src/type/p5.Font.js +++ b/src/type/p5.Font.js @@ -144,8 +144,6 @@ function font(p5, fn) { * The generated model (a Geometry object) can be manipulated further—rotated, scaled, * or styled with shaders—to create engaging, interactive visual art. * - * @method textToModel - * @memberof p5.Font * @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. From 277c533358cab9235bd9c7e10507312c30720506 Mon Sep 17 00:00:00 2001 From: Perminder Singh <127239756+perminder-17@users.noreply.github.com> Date: Wed, 19 Mar 2025 02:19:44 +0530 Subject: [PATCH 6/6] resolving merge conflicts --- src/type/p5.Font.js | 160 +------------------------------------------- 1 file changed, 2 insertions(+), 158 deletions(-) diff --git a/src/type/p5.Font.js b/src/type/p5.Font.js index ebbb4f85cd..90b3d3968c 100644 --- a/src/type/p5.Font.js +++ b/src/type/p5.Font.js @@ -125,6 +125,8 @@ class Font { cmdContours[cmdContours.length - 1].push(cmd); } + return cmdContours.map((commands) => pathToPoints(commands, options, this)); + } /** * * Converts text into a 3D model that can be rendered in WebGL mode. @@ -971,164 +973,6 @@ function font(p5, fn) { return pfont; } - - async function create(pInst, name, path, descriptors, rawFont) { - - let face = createFontFace(name, path, descriptors, rawFont); - - // load if we need to - if (face.status !== 'loaded') await face.load(); - - // add it to the document - document.fonts.add(face); - - // return a new p5.Font - return new p5.Font(pInst, face, name, path, rawFont); - } - - function unquote(name) { - // Unquote name from CSS - if ((name.startsWith('"') || name.startsWith("'")) && name.at(0) === name.at(-1)) { - return name.slice(1, -1).replace(/\/(['"])/g, '$1'); - } - return name; - } - - function createFontFace(name, path, descriptors, rawFont) { - - if (name.includes(' ')) name = "'" + name + "'"; // NOTE: must be single-quotes - - let fontArg = rawFont?._data; - if (!fontArg) { - if (!validFontTypesRe.test(path)) { - throw Error(invalidFontError); - } - if (!path.startsWith('url(')) { - path = 'url(' + path + ')'; - } - fontArg = path; - } - - // create/return the FontFace object - let face = new FontFace(name, fontArg, descriptors); - if (face.status === 'error') { - throw Error('Failed to create FontFace for "' + name + '"'); - } - return face; - } - - function extractFontName(font, path) { - let result, meta = font?.name; - - // use the metadata if we have it - if (meta) { - if (meta.fullName) { - return meta.fullName; - } - if (meta.familyName) { - result = meta.familyName; - } - } - - if (!result) { - - // if not, try to extract the name from the path - let matches = extractFontNameRe.exec(path); - if (matches && matches.length >= 3) { - result = matches[1]; - } - else { - // give up and return the full path - result = path; - } - } - - // replace spaces with underscores - if (result.includes(' ')) { - result = result.replace(/ /g, '_'); - } - - return result; - }; - - function pathToPoints(cmds, options, font) { - - const parseOpts = (options, defaults) => { - if (typeof options !== 'object') { - options = defaults; - } else { - for (const key in defaults) { - if (typeof options[key] === 'undefined') { - options[key] = defaults[key]; - } - } - } - return options; - } - - const at = (v, i) => { - const s = v.length; - return v[i < 0 ? i % s + s : i % s]; - } - - const simplify = (pts, angle) => { - angle = angle || 0; - let num = 0; - for (let i = pts.length - 1; pts.length > 3 && i >= 0; --i) { - if (collinear(at(pts, i - 1), at(pts, i), at(pts, i + 1), angle)) { - pts.splice(i % pts.length, 1); // Remove middle point - num++; - } - } - return num; - } - - const path = createFromCommands(arrayCommandsToObjects(cmds)); - let opts = parseOpts(options, { - sampleFactor: 0.1, - simplifyThreshold: 0 - }); - - const totalPoints = Math.ceil(path.getTotalLength() * opts.sampleFactor); - let points = []; - - const mode = font._pInst.angleMode(); - const DEGREES = font._pInst.DEGREES; - for (let i = 0; i < totalPoints; i++) { - const length = path.getTotalLength() * (i / (totalPoints - 1)); - points.push({ - ...path.getPointAtLength(length), - get angle() { - const angle = path.getAngleAtLength(length); - if (mode === DEGREES) { - return angle * 180 / Math.PI; - } else { - return angle; - } - }, - // For backwards compatibility - get alpha() { - return this.angle; - } - }); - } - - if (opts.simplifyThreshold) { - simplify(points, opts.simplifyThreshold); - } - - return points; - } - - function unquote(name) { - // Unquote name from CSS - if ((name.startsWith('"') || name.startsWith("'")) && name.at(0) === name.at(-1)) { - return name.slice(1, -1).replace(/\/(['"])/g, '$1'); - } - return name; - } - - }; // Convert arrays to named objects