Changing font-size on the go

Hello,

I’m having a small issue. I’m trying to do a quick countdown with number showing on the screen and increasing size before disappearing.

The issue I have is that, since FontImageMap.size is a val I can’t find a way to change it without reloading the font everytime :

  import org.openrndr.draw.FontImageMap

 ...
 if (countdownAnimation.fontSize == maxFontSize) {    
     font = loadFont("data/fonts/default.otf", countdownAnimation.fontSize)
 } else {
     countdownAnimation.apply {
         ::fontSize.animate(maxFontSize, 2000)
    }
}

So my question would be, is there another, more efficient way to do this?

Hi :slight_smile: Welcome to the forum!

Approach 1

If you only have a limited number of sizes, you could create a list of fonts like this:

import org.openrndr.application
import org.openrndr.draw.loadFont

fun main() = application {
    program {
        val fonts = List(10) {
            loadFont(
                "data/fonts/SourceCodePro-Regular.ttf",
                4.0 + 5 * it * it,
                "0123456789".toSet() // limited character set to use less memory
            )
        }

        extend {
            drawer.fontMap = fonts.random()
            drawer.text(frameCount.toString(), 50.0, height - 50.0)
        }
    }
}

Approach 2

If you want to animate the scale you could create a high resolution font map and scale the text when drawing:

import org.openrndr.application
import org.openrndr.draw.loadFont
import org.openrndr.math.Vector2

fun main() = application {
    program {
        val font = loadFont(
            "data/fonts/SourceCodePro-Regular.ttf",
            600.0, // max size for text
            "moz".toSet() // to avoid creating a huge texture full of unused chars
        )

        extend {
            drawer.fontMap = font
            drawer.translate(50.0, height / 2.0)
            drawer.scale(0.01 + (frameCount * 0.001))
            drawer.text("zoom", Vector2.ZERO)
        }
    }
}

Maybe some day there will be an alternative font rendering approach which is not based on font maps but on curves. Then one could write any size with the same font.

Do one of the above solutions help you? Cheers!

1 Like

Hi!
Yes, the second approach worked perfectely, I had to put it in a drawer.isolated { } to not impact the scales of other element, but it worked :wink:

Thank you!

For my own culture may I ask why just changing the font size isn’t an option? Is the way the letters are drawn based on the font size?

For performance reasons, when you load a font it creates a texture (the font map) with a set of characters. Later, when you draw text, it copies rectangles from this texture to the screen. This is much faster than drawing a lot of antialiased curves.

Some limitations with this approach: getting contours of letters, rotating or deforming text, exporting svg text or pen plotting text.

I asked about this is Slack:

edwin: it is actually not that hard to extract the glyphs using stb-truetype and convert them to shapes but to set proper texts with those glyphs is a different story

so maybe something to experiment with :slight_smile: Here a link to a related class, C example.