From d956c87dbcf055675fa69e94c988b2b5c10f8edd Mon Sep 17 00:00:00 2001 From: Isidor Zeuner Date: Thu, 12 Nov 2020 06:02:56 +0100 Subject: [PATCH] support for non-ascii characters --- api.lua | 84 ++++++++++++++++++++++++++++++++++++++++++++++++---- encoding.lua | 55 +++++++++++++++++++++++----------- init.lua | 2 +- 3 files changed, 117 insertions(+), 24 deletions(-) diff --git a/api.lua b/api.lua index aad4d36..a3a0985 100644 --- a/api.lua +++ b/api.lua @@ -153,6 +153,7 @@ signs_lib.flip_walldir = { -- Initialize character texture cache local ctexcache = {} +local ctexcache_wide = {} -- entity handling @@ -328,8 +329,10 @@ end local TP = signs_lib.path .. "/textures" -- Font file formatter local CHAR_FILE = "%s_%02x.png" +local CHAR_FILE_WIDE = "%s_%s.png" -- Fonts path local CHAR_PATH = TP .. "/" .. CHAR_FILE +local CHAR_PATH_WIDE = TP .. "/" .. CHAR_FILE_WIDE -- Lots of overkill here. KISS advocates, go away, shoo! ;) -- kaeza @@ -389,6 +392,7 @@ end local function build_char_db(font_size) local cw = {} + local cw_wide = {} -- To calculate average char width. local total_width = 0 @@ -404,20 +408,32 @@ local function build_char_db(font_size) end end + for i = 1, #signs_lib.wide_character_codes do + local ch = signs_lib.wide_character_codes[i] + local w, h = signs_lib.read_image_size(CHAR_PATH_WIDE:format("signs_lib_font_"..font_size.."px", ch)) + if w and h then + cw_wide[ch] = w + total_width = total_width + w + char_count = char_count + 1 + end + end + local cbw, cbh = signs_lib.read_image_size(TP.."/signs_lib_color_"..font_size.."px_n.png") assert(cbw and cbh, "error reading bg dimensions") - return cw, cbw, cbh, (total_width / char_count) + return cw, cbw, cbh, (total_width / char_count), cw_wide end signs_lib.charwidth15, signs_lib.colorbgw15, signs_lib.lineheight15, -signs_lib.avgwidth15 = build_char_db(15) +signs_lib.avgwidth15, +signs_lib.charwidth_wide15 = build_char_db(15) signs_lib.charwidth31, signs_lib.colorbgw31, signs_lib.lineheight31, -signs_lib.avgwidth31 = build_char_db(31) +signs_lib.avgwidth31, +signs_lib.charwidth_wide31 = build_char_db(31) local sign_groups = {choppy=2, dig_immediate=2} local fences_with_sign = { } @@ -453,7 +469,22 @@ local function char_tex(font_name, ch) end end -local function make_line_texture(line, lineno, pos, line_width, line_height, cwidth_tab, font_size, colorbgw) +local function char_tex_wide(font_name, ch) + if ctexcache_wide[font_name..ch] then + return ctexcache_wide[font_name..ch], true + else + local exists, tex = file_exists(CHAR_PATH_WIDE:format(font_name, ch)) + if exists then + tex = CHAR_FILE_WIDE:format(font_name, ch) + else + tex = CHAR_FILE:format(font_name, 0x5f) + end + ctexcache_wide[font_name..ch] = tex + return tex, exists + end +end + +local function make_line_texture(line, lineno, pos, line_width, line_height, cwidth_tab, font_size, colorbgw, cwidth_tab_wide) local width = 0 local maxw = 0 local font_name = "signs_lib_font_"..font_size.."px" @@ -490,6 +521,27 @@ local function make_line_texture(line, lineno, pos, line_width, line_height, cwi local word_l = #word local i = 1 while i <= word_l do + local wide_c + if "&#x" == word:sub(i, i + 2) then + local j = i + 3 + local collected = "" + while j <= word_l do + local c = word:sub(j, j) + if c == ";" then + wide_c = collected + break + elseif c < "0" then + break + elseif "f" < c then + break + elseif ("9" < c) and (c < "a") then + break + else + collected = collected .. c + j = j + 1 + end + end + end local c = word:sub(i, i) if c == "#" then local cc = tonumber(word:sub(i+1, i+1), 16) @@ -497,6 +549,25 @@ local function make_line_texture(line, lineno, pos, line_width, line_height, cwi i = i + 1 cur_color = cc end + elseif wide_c then + local w = cwidth_tab_wide[wide_c] + if w then + width = width + w + 1 + if width >= (line_width - cwidth_tab[" "]) then + width = 0 + else + maxw = math_max(width, maxw) + end + if #chars < MAX_INPUT_CHARS then + table.insert(chars, { + off = ch_offs, + tex = char_tex_wide(font_name, wide_c), + col = ("%X"):format(cur_color), + }) + end + ch_offs = ch_offs + w + end + i = i + #wide_c + 3 else local w = cwidth_tab[c] if w then @@ -576,6 +647,7 @@ function signs_lib.make_sign_texture(lines, pos) local line_width local line_height local char_width + local char_width_wide local colorbgw local widemult = 1 @@ -588,12 +660,14 @@ function signs_lib.make_sign_texture(lines, pos) line_width = math.floor(signs_lib.avgwidth31 * def.chars_per_line) * (def.horiz_scaling * widemult) line_height = signs_lib.lineheight31 char_width = signs_lib.charwidth31 + char_width_wide = signs_lib.charwidth_wide31 colorbgw = signs_lib.colorbgw31 else font_size = 15 line_width = math.floor(signs_lib.avgwidth15 * def.chars_per_line) * (def.horiz_scaling * widemult) line_height = signs_lib.lineheight15 char_width = signs_lib.charwidth15 + char_width_wide = signs_lib.charwidth_wide15 colorbgw = signs_lib.colorbgw15 end @@ -602,7 +676,7 @@ function signs_lib.make_sign_texture(lines, pos) local lineno = 0 for i = 1, #lines do if lineno >= def.number_of_lines then break end - local linetex, ln = make_line_texture(lines[i], lineno, pos, line_width, line_height, char_width, font_size, colorbgw) + local linetex, ln = make_line_texture(lines[i], lineno, pos, line_width, line_height, char_width, font_size, colorbgw, char_width_wide) table.insert(texture, linetex) lineno = ln + 1 end diff --git a/encoding.lua b/encoding.lua index b398c46..df39590 100644 --- a/encoding.lua +++ b/encoding.lua @@ -203,6 +203,28 @@ local utf8_decode = { [210] = {[144] = "\165", [145] = "\180"} } +local wide_character_codes = { +} + +local unicode_install = function( + numbers +) + local scope = utf8_decode + for i = 1,#numbers-2 do + if not scope[numbers[i]] then + scope[numbers[i]] = {} + end + scope = scope[numbers[i]] + end + scope[numbers[#numbers-1]] = "&#x" .. numbers[#numbers] .. ";" + table.insert( + wide_character_codes, + numbers[#numbers] + ) +end + +unicode_install({38,"26"}) + local nmdc = { [36] = "$", [124] = "|" @@ -230,36 +252,33 @@ function AnsiToUtf8(s) end function Utf8ToAnsi(s) - local a, j, r, b = 0, 0, "" + local a, j, r, b, scope = 0, 0, "" for i = 1, s and s:len() or 0 do b = s:byte(i) - if b < 128 then + if b == 0x26 then + r = r .. "&" + elseif b < 128 then if nmdc[b] then r = r .. nmdc[b] else r = r .. string.char(b) end - elseif a == 2 then - a, j = a - 1, b - elseif a == 1 then - --if j == nil or b == nil then return r end - --print(j) - --print(b) - --local ansi = utf8_decode[j] - --if ansi == nil then return r end - --if ansi[b] == nil then return r end - if utf8_decode[j] then - if utf8_decode[j][b] then - a, r = a - 1, r .. utf8_decode[j][b] + elseif scope then + if scope[b] then + scope = scope[b] + if "string" == type(scope) then + r, scope = r .. scope end + else + r, scope = r .. "_" end - elseif b == 226 then - a = 2 - elseif b == 194 or b == 208 or b == 209 or b == 210 then - j, a = b, 1 + elseif utf8_decode[b] then + scope = utf8_decode[b] else r = r .. "_" end end return r end + +signs_lib.wide_character_codes = wide_character_codes diff --git a/init.lua b/init.lua index fd6c8e7..e0ff3d1 100644 --- a/init.lua +++ b/init.lua @@ -10,7 +10,7 @@ signs_lib.path = minetest.get_modpath(minetest.get_current_modname()) local S, NS = dofile(signs_lib.path .. "/intllib.lua") signs_lib.gettext = S -dofile(signs_lib.path.."/api.lua") dofile(signs_lib.path.."/encoding.lua") +dofile(signs_lib.path.."/api.lua") dofile(signs_lib.path.."/standard_signs.lua") dofile(signs_lib.path.."/compat.lua")