From cec34c28c9630300eb013ba86a68a0709fe518fc Mon Sep 17 00:00:00 2001 From: ywang Date: Mon, 9 Aug 2021 10:10:02 +0200 Subject: Add support for combining diacritics for LGC scripts; reorganize files --- advtrains/textrender.lua | 140 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 114 insertions(+), 26 deletions(-) (limited to 'advtrains/textrender.lua') diff --git a/advtrains/textrender.lua b/advtrains/textrender.lua index de9deac..acba0d8 100644 --- a/advtrains/textrender.lua +++ b/advtrains/textrender.lua @@ -21,15 +21,19 @@ Exposed API: local characters = {} do -- prevent LUT creation code from polluting the local environment local function ensure_entry_exists(char) - if not characters[char] then - characters[char] = {} + local e = characters[char] + if not e then + e = {} + characters[char] = e end + return e end local charwidth_lut = {} local charwidth_ranges = { [8] = { 0x20,0x7e, -- Latin 0xa0,0x052f, -- LGC + 0x1e00,0x1fff, -- Latin, Greek }, } for k, v in pairs(charwidth_lut) do @@ -57,6 +61,36 @@ do -- prevent LUT creation code from polluting the local environment characters[char][k] = true end end + -- import "interesting" data from UnicodeData + local f = io.open(advtrains.modpath.."/UCD/UnicodeData.txt","r") or error("Failed to open UnicodeData") + for line in f:lines() do + local cp, decomp = string.match(line, "^(%x+);[^;]*;[^;]*;[^;]*;[^;]*;([^;]*);.+$") + if cp and decomp then + cp = tonumber(cp, 16) + decomp = string.split(decomp, " ") + end + if cp then + if decomp[1] then + local compatfmt = string.match(decomp[1], "^<([^>]+)>$") + if compatfmt then + table.remove(decomp, 1) + end + if not compatfmt then + if #decomp == 2 then + local base, modifier = tonumber(decomp[1], 16), tonumber(decomp[2], 16) + if base and modifier then + local bt = ensure_entry_exists(base) + if not bt.modifiers then + bt.modifiers = {} + end + bt.modifiers[modifier] = cp + end + end + end + end + end + end + f:close() end local function texture_escape(str) @@ -105,6 +139,39 @@ local function mbstoucs(str) return cps end +local function ucstombs(ucs) + local s = "" + for i = 1, #ucs do + local cp = math.floor(ucs[i]) + local len + if cp < 0 or cp > 0x10ffff then + return "" + end + if cp < 0x80 then + len = 1 + elseif cp < 0x0800 then + len = 2 + elseif cp < 0x010000 then + len = 3 + else + len = 4 + end + if len == 1 then + s = s .. string.char(cp) + else + local t = {} + for i = len, 2, -1 do + local rem = cp % 64 + cp = math.floor(cp/64) + t[i] = 128+rem + end + t[1] = cp + 256 - 2^(8-len) + s = s .. string.char(unpack(t)) + end + end + return s +end + local function basechar(char) if type(char) == "table" then return char[1] @@ -114,7 +181,7 @@ local function basechar(char) end local function charwidth(char) - return (characters[basechar(char)] or {}).width + return (characters[basechar(char)] or {}).width or 0 end -- Splits the text into segments @@ -222,7 +289,27 @@ local function split_lines(cs, width, height, options) end local function cpstocs(cps) - return cps -- TODO: at least implement support for combining diacritics + local cs = {} + local i = 1 + local lastchar + while i <= #cps do + local cp = cps[i] + local addchar = true + if lastchar then + local lcp = characters[lastchar] + if lcp and lcp.modifiers and lcp.modifiers[cp] then + lastchar = lcp.modifiers[cp] + cs[#cs] = lastchar + addchar = false + end + end + if addchar then + cs[#cs+1] = cp + lastchar = cp + end + i = i + 1 + end + return cs end local function check_options(width, height, options) @@ -252,9 +339,9 @@ end local function get_char_texture(char) if type(char) == "number" then - return string.format("(advtrains_unifont.png\\^[sheet\\:258x260\\:%d,%d)", - char%256+2, - math.floor(char/256+4) + return string.format("(advtrains_unifont_%04x.png\\^[sheet\\:256x1\\:%d,0)", + math.floor(char/256), + char%256 ) end end @@ -286,29 +373,30 @@ local function render(str, ...) return table.concat(tst,":")..string.format(")^[makealpha:0,0,0^[multiply:%s)", opts.color) end -if minetest then - local tilefmt = "advtrains_hud_bg.png^[resize:128x128^[colorize:#0000ff^(advtrains_hud_bg.png^[resize:128x64)^%s" - -- expected: Hello worldáéḯṍǘ - local sampletext = "Hello world\n\náe"..string.char(0xcc,0x81,0xc3,0xaf,0xcc,0x81,0x6f,0xcc,0x83,0xcc,0x81,0xc7,0x98) - minetest.register_node("advtrains:textrender_demo",{ - description = "Text rendering demo", - tiles = {string.format(tilefmt, render(sampletext, 128, 128, {color="#00ff00"}))}, - groups = {cracky=3, not_in_creative_inventory=1} - }) - minetest.register_on_mods_loaded(function() -- wait until the trainhud module is loaded - minetest.register_craft{ - output = "advtrains:textrender_demo", - recipe = { - {"default:paper","default:paper","default:paper"}, - {"default:paper","advtrains:hud_demo","default:paper"}, - {"default:paper","default:paper","default:paper"}, - } +local tilefmt = "advtrains_hud_bg.png^[resize:128x128^[colorize:#0000ff^(advtrains_hud_bg.png^[resize:128x64)^%s" +local sampletext = "Hello world\n\n".. + ucstombs{0xe1, 0x65, 0x0301, 0xef, 0x0301, 0x6f, 0x0303, 0x0301, 0x01d8, 0x20, -- Latin alphabet test + 0x03b1, 0x0301, 0x0345, 0x03b2, 0x03b3, 0x03b4, 0x03ad, 0x20, -- Greek alphabet test + 0x0430, 0x0308, 0x0431, 0x0432, 0x0433, 0x0301, 0x0434} +minetest.register_node("advtrains:textrender_demo",{ + description = "Text rendering demo", + tiles = {string.format(tilefmt, render(sampletext, 128, 128, {color="#00ff00"}))}, + groups = {cracky=3, not_in_creative_inventory=1} +}) +minetest.register_on_mods_loaded(function() -- wait until the trainhud module is loaded + minetest.register_craft{ + output = "advtrains:textrender_demo", + recipe = { + {"default:paper","default:paper","default:paper"}, + {"default:paper","advtrains:hud_demo","default:paper"}, + {"default:paper","default:paper","default:paper"}, } - end) -end + } +end) return { mbstoucs = mbstoucs, + ucstombs = ucstombs, render = render, texture_escape = texture_escape, } \ No newline at end of file -- cgit v1.2.3