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("common/fonts/roboto.ttf")
local font = natiny.font.create(res, 44)
local small = natiny.font.create(res, 18)
local BG = natiny.color.from_hex("#151E2C")
local PANEL = natiny.color.from_hex("#0F1621")
local OBJECT = natiny.color.from_hex("#A9B3C5")
local ACCENT = natiny.color.from_hex("#A8C238")
local LIGHT_TEXT = natiny.color.from_hex("#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(dt)
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)
natiny.render.set_color(LIGHT_TEXT)
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)
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(natiny.color.from_hex("#FFFFFF"))
natiny.render.texture(atlas, ATLAS_X, ATLAS_Y, ATLAS_SIZE, ATLAS_SIZE)
natiny.render.set_color(natiny.color.from_hex("#A9B3C566"))
natiny.render.rectangle_outline(ATLAS_X, ATLAS_Y, ATLAS_SIZE, ATLAS_SIZE, 2)
natiny.render.set_color(OBJECT)
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)
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(natiny.color.from_hex("#A9B3C5B3"))
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()