aboutsummaryrefslogtreecommitdiff
path: root/advtrains/unifont.lua
diff options
context:
space:
mode:
Diffstat (limited to 'advtrains/unifont.lua')
-rw-r--r--advtrains/unifont.lua209
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
+}