Glyph atlas
Shows the whole sheet natiny.font.get_atlas bakes glyphs into. Press 1, 2 or
3 to add a code point range with natiny.font.preload_range and watch it
fill; F switches the atlas filter.
local natiny = require("natiny")
natiny.backend.init()
local win = natiny.window.create("Glyph atlas", 900, 600)
natiny.window.set_scale_mode(win, natiny.window.SCALE_MODE_STRETCH)
local res = natiny.resource.load("data/common/fonts/roboto.ttf")
local font = natiny.font.create(res, 44)
local small = natiny.font.create(res, 18)
local BG = { 21 / 255, 30 / 255, 44 / 255 } -- #151E2C
local PANEL = { 15 / 255, 22 / 255, 33 / 255 } -- #0F1621
local OBJECT = { 169 / 255, 179 / 255, 197 / 255 } -- #A9B3C5
local ACCENT = { 168 / 255, 194 / 255, 56 / 255 } -- #A8C238
local LIGHT_TEXT = { 243 / 255, 245 / 255, 250 / 255 } -- #F3F5FA
-- A font bakes a glyph the first time something asks for it. preload_range
-- asks for a whole block at once, so the cost is paid here instead of mid-scene.
local RANGES = {
{ key = natiny.input.KEY_1, name = "1 Latin U+0020..U+007E",
first = 0x20, last = 0x7E, sample = "Sphinx of black quartz" },
{ key = natiny.input.KEY_2, name = "2 Cyrillic U+0410..U+044F",
first = 0x0410, last = 0x044F, sample = "Съешь ещё этих булок" },
{ key = natiny.input.KEY_3, name = "3 Greek U+0391..U+03C9",
first = 0x0391, last = 0x03C9, sample = "Ταχίστη αλώπηξ" },
}
local ATLAS_X, ATLAS_Y, ATLAS_SIZE = 60, 110, 420
local nearest = false
natiny.backend.loop(function()
natiny.window.bind(win, function()
for _, range in ipairs(RANGES) do
if natiny.input.get_key_pressed(range.key) and not range.loaded then
natiny.font.preload_range(font, range.first, range.last)
range.loaded = true
end
end
if natiny.input.get_key_pressed(natiny.input.KEY_F) then
nearest = not nearest
natiny.font.set_filter(font, nearest and natiny.font.FILTER_NEAREST
or natiny.font.FILTER_LINEAR)
end
local atlas = natiny.font.get_atlas(font)
natiny.render.clear(BG[1], BG[2], BG[3], 1)
natiny.render.set_color(LIGHT_TEXT[1], LIGHT_TEXT[2], LIGHT_TEXT[3], 1)
natiny.render.text(small, ATLAS_X, 50,
"press 1, 2, 3 to bake a range into the atlas - F switches its filter")
local sheet = natiny.texture.get_width(atlas)
natiny.render.set_color(PANEL[1], PANEL[2], PANEL[3], 1)
natiny.render.rectangle(ATLAS_X, ATLAS_Y, ATLAS_SIZE, ATLAS_SIZE)
-- The whole sheet, scaled down to the panel: the empty part below the
-- baked rows is the room the next range will be packed into.
natiny.render.set_color(1, 1, 1, 1)
natiny.render.texture(atlas, ATLAS_X, ATLAS_Y, ATLAS_SIZE, ATLAS_SIZE)
natiny.render.set_color(OBJECT[1], OBJECT[2], OBJECT[3], 0.4)
natiny.render.rectangle_outline(ATLAS_X, ATLAS_Y, ATLAS_SIZE, ATLAS_SIZE, 2)
natiny.render.set_color(OBJECT[1], OBJECT[2], OBJECT[3], 1)
natiny.render.text(small, ATLAS_X, ATLAS_Y + ATLAS_SIZE + 10, string.format(
"the whole %d x %d sheet, %s",
sheet, natiny.texture.get_height(atlas),
nearest and "nearest" or "linear"))
local x, y = ATLAS_X + ATLAS_SIZE + 50, ATLAS_Y
for _, range in ipairs(RANGES) do
local ink = range.loaded and ACCENT or OBJECT
natiny.render.set_color(ink[1], ink[2], ink[3], 1)
natiny.render.text(small, x, y, range.name)
-- has_glyph answers without baking anything, fallbacks included.
local ok = natiny.font.has_glyph(font, range.first + 1)
natiny.render.set_color(OBJECT[1], OBJECT[2], OBJECT[3], 0.7)
natiny.render.text(small, x, y + 24,
ok and (range.loaded and range.sample or "in the font, not yet baked")
or "this font has no such glyphs")
y = y + 74
end
end)
end)
natiny.backend.shutdown()