diff options
Diffstat (limited to 'advtrains/unifont.lua')
-rw-r--r-- | advtrains/unifont.lua | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/advtrains/unifont.lua b/advtrains/unifont.lua new file mode 100644 index 0000000..18d0ed5 --- /dev/null +++ b/advtrains/unifont.lua @@ -0,0 +1,209 @@ +--[[ +Note on copyright: +The Unifont website (http://unifoundry.com/unifont/index.html) says that +the font files are licensed "under the GNU General Public License, +either version 2 or (at your option) a later version". Section 13 of the +GNU GPLv3 gives the "permission to link or combine any covered work with +a work licensed under version 3 of the GNU Affero General Public License +into a single combined work". The use of Unifont here should fall under +this case considering that +- Unifont is licensed under GNU GPLv2+, and, in this case, the terms of +the GNU GPLv3 is used here +- We are combining Unifont into advtrains, and the latter is licensed +under the GNU AGPLv3. +However, as I am not a lawyer, I can not be sure whether this +interpretation is legally accepted. +- Y.W. +]] + +local tonumber, unpack = tonumber, unpack +local sbyte, schar, sformat, smatch, ssub = string.byte, string.char, string.format, string.match, string.sub +local tconcat = table.concat + +local texture_dir = tconcat({advtrains.modpath, "textures", "unifont"}, DIR_DELIM) +minetest.mkdir(texture_dir) +for _, i in pairs(minetest.get_dir_list(texture_dir)) do + -- FIXME: remove this workaround eventually when MT 5.5.0 becomes common + os.remove(texture_dir .. DIR_DELIM .. i) +end + +local function texture_file(cp) + return sformat(cp < 65536 and "%s_%04x.bmp" or "%s_%06x.bmp", "advtrains_unifont", cp) +end +local function texture_path(cp) + return texture_dir .. DIR_DELIM .. texture_file(cp) +end + +local _cpwidth = {} +local cpdata = {} + +-- Generate texture files +local bmp_headers = {} +for _, v in pairs {8, 16} do + bmp_headers[v] = tconcat{ + "BM", -- starting bytes + "\125\0\0\0", -- file size + "\0\0\0\0", -- reserved fields + "\62\0\0\0", -- offset of the pixel array + "\40\0\0\0", -- BITMAPINFOHEADER + schar(v, 0, 0, 0), -- image width + "\16\0\0\0", -- image height + "\1\0", -- number of color planes (must be 1, apparently) + "\1\0", -- bits per pixel + "\0\0\0\0", -- no compression + "\64\0\0\0", -- size of the raw bitmap data + "\0\0\0\0\0\0\0\0", -- image resolution (irrelevant here) + "\2\0\0\0", -- number of colors in the palette + "\0\0\0\0", -- "important" colors + -- palette + "\0\0\0\0", + "\255\255\255\0", + } +end + +local f = io.open(advtrains.modpath .. DIR_DELIM .. "unifont.hex", "rb") or error("Cannot open unifont.hex") +for l in f:lines() do + local cp, raw = smatch(l, "^(%x+):(%x+)$") + cpdata[tonumber(cp, 16)] = raw +end +f:close() +f = nil + +local mods_loaded = false +local function cpwidth(cp) + if _cpwidth[cp] then + return _cpwidth[cp] + end + if cpdata[cp] then + local raw = cpdata[cp] + local rowsize = #raw/16 + local width = rowsize*4 + _cpwidth[cp] = width + local rowbytes = rowsize/2 + local bytes = {bmp_headers[width]} + for i = 0, 15 do + local row = {} + local offset = i*rowsize + for j = 1, rowbytes do + local offset = offset+2*j-1 + local data = ssub(raw, offset, offset+1) + row[j] = tonumber(data, 16) + end + for j = rowbytes+1, 4 do + row[j] = 0 + end + bytes[17-i] = schar(unpack(row)) + end + local path = texture_path(cp) + minetest.safe_file_write(path, tconcat(bytes)) + if mods_loaded then + minetest.dynamic_add_media(path) + end + return width + end +end +minetest.register_on_mods_loaded(function() mods_loaded = true end) + +local function mbstocps(str) + local t = {} + local i = 1 + while i <= #str do + local c = sbyte(str, i) + local bt = {} + i = i+1 + if c < 128 then + -- nop + elseif c < 192 then + c = 0 + elseif c < 224 then + bt = {sbyte(str, i, i)} + c = c%32 + elseif c < 240 then + bt = {sbyte(str, i, i+1)} + c = c%16 + elseif c < 248 then + bt = {sbyte(str, i, i+2)} + c = c%8 + else + c = 0 + end + for i = 1, #bt do + c = c*64+(bt[i]%64) + end + i = i + #bt + t[#t+1] = c + end + return t +end + +local function renderer(opts) + local opts = opts or {} + local x0, y0 = (opts.x or 0), (opts.y or 0) + local width, height = opts.width, opts.height + local minwidth, minheight = opts.minwidth, opts.minheight + local halign, valign = (opts.halign or 0.5), (opts.valign or 0.5) + local textcolor = opts.textcolor or "black" + local bgcolor = opts.bgcolor + local function break_lines(cps) + local lastline = {width = 0} + local lines = {lastline} + local maxwidth = 0 + local i = 1 + while i <= #cps do + local char = cps[i] + if char == 10 then + lastline = {width = 0} + lines[#lines+1] = lastline + elseif cpwidth(char) then + local newwidth = lastline.width + cpwidth(char) + lastline.width = newwidth + maxwidth = math.max(newwidth, maxwidth) + lastline[#lastline+1] = char + end + i = i+1 + end + return lines, maxwidth, 16*#lines + end + return function(str) + local lines, textwidth, textheight = break_lines(mbstocps(str)) + local width = math.max(minwidth or 0, width or 0, textwidth) + local height = math.max(minheight or 0, height or 0, textheight) + local y = y0 + (height-textheight)*valign + local st = { + "[combine", + sformat("%dx%d", x0+width, y0+height) + } + for i = 1, #lines do + local line = lines[i] + local x = x0 + (width - line.width)*halign + local spacing = 0 + if minwidth and line.width < minwidth then + x = x0 + (width - minwidth)*halign + spacing = (minwidth - line.width) / (#line - 1) + end + for j = 1, #line do + local cp = line[j] + st[#st+1] = sformat("%d,%d=%s", x, y, texture_file(cp)) + x = x + cpwidth(cp) + spacing + end + y = y + 16 + end + local prefix = "" + if bgcolor then + prefix = sformat("[combine:%dx%d:%d,%d=\\(advtrains_hud_bg.png\\^[resize\\:%dx%d\\^[colorize\\:%s\\:alpha\\)^", + x0+width, y0+height, x0, y0, width, height, bgcolor) + end + return sformat("(%s(%s^[makealpha:000000^[multiply:%s))", prefix, tconcat(st, ":"), textcolor), width, height + end +end + +local function render(str, opts) + return renderer(opts)(str) +end + +return { + texture_dir = texture_dir, + mbstocps = mbstocps, + renderer = renderer, + render = render +} |