aboutsummaryrefslogtreecommitdiff
path: root/advtrains/textrender.lua
diff options
context:
space:
mode:
Diffstat (limited to 'advtrains/textrender.lua')
-rw-r--r--advtrains/textrender.lua140
1 files changed, 114 insertions, 26 deletions
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<one empty line>áéḯṍǘ
- 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