1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
|
--[[
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.rmdir(texture_dir, true)
minetest.mkdir(texture_dir)
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({filepath = 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
}
|