[orx-text-writer] Add glyphOutput for custom glyph processing and wavy text demo
This commit is contained in:
@@ -3,6 +3,7 @@ package org.openrndr.extra.textwriter
|
|||||||
import org.openrndr.draw.DrawStyle
|
import org.openrndr.draw.DrawStyle
|
||||||
import org.openrndr.draw.Drawer
|
import org.openrndr.draw.Drawer
|
||||||
import org.openrndr.draw.FontImageMap
|
import org.openrndr.draw.FontImageMap
|
||||||
|
import org.openrndr.internal.GlyphOutput
|
||||||
import org.openrndr.math.Vector2
|
import org.openrndr.math.Vector2
|
||||||
import org.openrndr.shape.Rectangle
|
import org.openrndr.shape.Rectangle
|
||||||
import kotlin.contracts.ExperimentalContracts
|
import kotlin.contracts.ExperimentalContracts
|
||||||
@@ -182,6 +183,20 @@ class TextWriter(val drawerRef: Drawer?) {
|
|||||||
var style = WriteStyle()
|
var style = WriteStyle()
|
||||||
val styleStack = ArrayDeque<WriteStyle>()
|
val styleStack = ArrayDeque<WriteStyle>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the output of glyph positioning and rendering processes within the text drawing operations.
|
||||||
|
*
|
||||||
|
* This variable is used internally to maintain a collection of calculated glyph positions and associated
|
||||||
|
* bounding rectangles. It consists of two mutable lists:
|
||||||
|
* - One for glyph characters, represented by their positions.
|
||||||
|
* - One for glyph bounding rectangles, which define the area occupied by each glyph.
|
||||||
|
*
|
||||||
|
* The `glyphOutput` is primarily utilized in text rendering pipelines to calculate, store, and later
|
||||||
|
* process glyph information for visual rendering or additional transformations such as custom effects.
|
||||||
|
*/
|
||||||
|
val glyphOutput = GlyphOutput(mutableListOf(), mutableListOf())
|
||||||
|
|
||||||
|
|
||||||
var leading
|
var leading
|
||||||
get() = style.leading
|
get() = style.leading
|
||||||
set(value) {
|
set(value) {
|
||||||
@@ -380,7 +395,7 @@ class TextWriter(val drawerRef: Drawer?) {
|
|||||||
val first = renderTokens.filter { it != TextToken.END_OF_LINE }.first()
|
val first = renderTokens.filter { it != TextToken.END_OF_LINE }.first()
|
||||||
val last = renderTokens.last()
|
val last = renderTokens.last()
|
||||||
renderTokens.split().flatMap {
|
renderTokens.split().flatMap {
|
||||||
val sy = first.y - (fontMap?.ascenderLength ?: 0.0)
|
val sy = first.y - (fontMap?.ascenderLength ?: 0.0)
|
||||||
val ey = last.y + (fontMap?.descenderLength ?: 0.0)
|
val ey = last.y + (fontMap?.descenderLength ?: 0.0)
|
||||||
|
|
||||||
val th = ey - sy
|
val th = ey - sy
|
||||||
@@ -390,9 +405,7 @@ class TextWriter(val drawerRef: Drawer?) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (visible) {
|
drawTextTokens(renderTokens, visible)
|
||||||
drawTextTokens(renderTokens)
|
|
||||||
}
|
|
||||||
return renderTokens
|
return renderTokens
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -401,7 +414,9 @@ class TextWriter(val drawerRef: Drawer?) {
|
|||||||
* @param tokens a list of [TextToken] instances
|
* @param tokens a list of [TextToken] instances
|
||||||
* @since 0.4.3
|
* @since 0.4.3
|
||||||
*/
|
*/
|
||||||
fun drawTextTokens(tokens: List<TextToken>) {
|
fun drawTextTokens(tokens: List<TextToken>, visible: Boolean) {
|
||||||
|
glyphOutput.characters.clear()
|
||||||
|
glyphOutput.rectangles.clear()
|
||||||
drawerRef?.let { d ->
|
drawerRef?.let { d ->
|
||||||
val renderer = d.fontImageMapDrawer
|
val renderer = d.fontImageMapDrawer
|
||||||
val queue = renderer.getQueue(tokens.sumOf { it.token.length })
|
val queue = renderer.getQueue(tokens.sumOf { it.token.length })
|
||||||
@@ -414,10 +429,14 @@ class TextWriter(val drawerRef: Drawer?) {
|
|||||||
tracking = style.tracking,
|
tracking = style.tracking,
|
||||||
kerning = drawStyle.kerning,
|
kerning = drawStyle.kerning,
|
||||||
textSetting = drawStyle.textSetting,
|
textSetting = drawStyle.textSetting,
|
||||||
queue
|
queue,
|
||||||
|
visible,
|
||||||
|
glyphOutput
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
renderer.flush(d.context, d.drawStyle, queue)
|
if (visible) {
|
||||||
|
renderer.flush(d.context, d.drawStyle, queue)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -496,8 +515,6 @@ class TextWriter(val drawerRef: Drawer?) {
|
|||||||
}
|
}
|
||||||
return emptyList()
|
return emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
68
orx-text-writer/src/jvmDemo/kotlin/DemoGlyphOutput01.kt
Normal file
68
orx-text-writer/src/jvmDemo/kotlin/DemoGlyphOutput01.kt
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
import org.openrndr.application
|
||||||
|
import org.openrndr.color.ColorRGBa
|
||||||
|
import org.openrndr.draw.FontImageMap
|
||||||
|
import org.openrndr.draw.TextSettingMode
|
||||||
|
import org.openrndr.draw.isolated
|
||||||
|
import org.openrndr.draw.loadFont
|
||||||
|
import org.openrndr.draw.shadeStyle
|
||||||
|
import org.openrndr.extra.textwriter.TextWriter
|
||||||
|
import org.openrndr.extra.textwriter.writer
|
||||||
|
import org.openrndr.math.Vector2
|
||||||
|
import org.openrndr.shape.Rectangle
|
||||||
|
import kotlin.math.cos
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This demo implements a drawing program utilizing custom text rendering with a wave-like animation effect.
|
||||||
|
* It allows for manipulating text position and scaling over time.
|
||||||
|
*
|
||||||
|
* Key elements of the program:
|
||||||
|
* - A centered rectangle on the drawing canvas.
|
||||||
|
* - Text rendering with properties such as horizontal alignment, vertical alignment, and tracking,
|
||||||
|
* dynamically changing over time.
|
||||||
|
* - Custom text animation implementing wave-like movement and scaling.
|
||||||
|
*/
|
||||||
|
fun main() = application {
|
||||||
|
configure {
|
||||||
|
width = 720
|
||||||
|
height = 720
|
||||||
|
}
|
||||||
|
program {
|
||||||
|
extend {
|
||||||
|
val r = Rectangle.fromCenter(drawer.bounds.center, 600.0, 600.0)
|
||||||
|
drawer.isolated {
|
||||||
|
drawer.fill = null
|
||||||
|
drawer.stroke = ColorRGBa.WHITE
|
||||||
|
drawer.rectangle(r)
|
||||||
|
}
|
||||||
|
drawer.fontMap = loadFont("demo-data/fonts/IBMPlexMono-Regular.ttf", 24.0)
|
||||||
|
|
||||||
|
|
||||||
|
fun TextWriter.wavyWrite(text: String) {
|
||||||
|
text(text, visible = false)
|
||||||
|
drawer.shadeStyle = shadeStyle {
|
||||||
|
fragmentTransform = """
|
||||||
|
float o = x_fill.r;
|
||||||
|
x_fill = u_fill;
|
||||||
|
x_fill.a *= o;
|
||||||
|
""".trimIndent()
|
||||||
|
}
|
||||||
|
|
||||||
|
drawer.image((drawer.fontMap as FontImageMap).texture, glyphOutput.rectangles.mapIndexed { index, it ->
|
||||||
|
Pair(
|
||||||
|
it.first, it.second
|
||||||
|
.movedBy(Vector2(0.0, 20.0 * cos(index * 0.5 + seconds * 10.0)))
|
||||||
|
.scaledBy(cos(index * 0.1 + seconds * 0.5) * 0.5 + 1.0)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
writer {
|
||||||
|
drawer.drawStyle.textSetting = TextSettingMode.SUBPIXEL
|
||||||
|
style.horizontalAlign = cos(seconds) * 0.5 + 0.5
|
||||||
|
style.verticalAlign = 0.5
|
||||||
|
style.tracking = (cos(seconds * 0.1) * 0.5 + 0.5) * 20.0
|
||||||
|
box = r.offsetEdges(-10.0)
|
||||||
|
wavyWrite("hello world\nthis is a test\ncentered")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user