From 73c0924ef6f5a1ac215f44f21d8011842324d91e Mon Sep 17 00:00:00 2001 From: Pierre-Yves Rollo Date: Wed, 15 Oct 2025 08:33:05 +0200 Subject: [PATCH] wip --- extra_fonts/init.lua | 116 +++++++++++++++++++++++- extra_fonts/params_test.lua | 70 +++++++++++++- extra_fonts/sources/OldWizard.ttf | Bin 0 -> 49068 bytes extra_fonts/textures/font_botic.png | Bin 1623 -> 1623 bytes extra_fonts/textures/font_oldwizard.png | Bin 0 -> 26193 bytes font_api/API.md | 4 + font_api/tools/make_font.lua | 88 ++++++++++++++++-- font_api/tools/make_font/params.example | 22 ++++- signs/nodes.lua | 2 +- 9 files changed, 281 insertions(+), 21 deletions(-) create mode 100644 extra_fonts/sources/OldWizard.ttf create mode 100644 extra_fonts/textures/font_oldwizard.png diff --git a/extra_fonts/init.lua b/extra_fonts/init.lua index dc7bef8..2a623ed 100644 --- a/extra_fonts/init.lua +++ b/extra_fonts/init.lua @@ -1,7 +1,7 @@ -- -- fonts_extra: A font mod for font_api -- --- This file was generated by `../font_api/tools/make_font.lua` on 2025-10-11 at 11:57. +-- This file was generated by `../font_api/tools/make_font.lua` on 2025-10-12 at 10:26. -- -- Font generated from file sources/pixeldroidBoticRegular.otf with pointsize 16 @@ -10,8 +10,8 @@ font_api.register_font( { version = 2, default = true, - margintop = 3, - linespacing = -2, + margintop = 0, + linespacing = 0, charspacing = 2, texture_height = 39, glyphs_height = 13, @@ -76,3 +76,113 @@ font_api.register_font( }, } ) +-- Font generated from file sources/OldWizard.ttf with pointsize 16 +font_api.register_font( + 'oldwizard', + { + version = 2, + default = true, + margintop = 0, + linespacing = 0, + charspacing = 2, + texture_height = 25674, + glyphs_height = 389, + glyphs = { + [32] = { 18 }, [33] = { 3, 90, 0, 0 }, [34] = { 5, 60, 2, 0 }, + [35] = { 8, 40, 6, 0 }, [36] = { 10, 30, 8, 0 }, + [37] = { 14, 24, 8, 0 }, [38] = { 12, 24, 9, 0 }, + [39] = { 3, 90, 1, 0 }, [40] = { 8, 40, 7, 0 }, + [41] = { 9, 36, 8, 0 }, [42] = { 10, 30, 9, 0 }, + [43] = { 16, 20, 11, 0 }, [44] = { 7, 45, 4, 0 }, + [45] = { 14, 24, 10, 0 }, [46] = { 7, 45, 5, 0 }, + [47] = { 15, 20, 12, 0 }, [48] = { 18, 18, 13, 0 }, + [49] = { 17, 20, 13, 0 }, [50] = { 26, 12, 0, 1 }, + [51] = { 18, 18, 14, 0 }, [52] = { 22, 15, 13, 0 }, + [53] = { 23, 15, 14, 0 }, [54] = { 24, 12, 1, 1 }, + [55] = { 25, 12, 2, 1 }, [56] = { 25, 12, 3, 1 }, + [57] = { 26, 12, 4, 1 }, [58] = { 12, 24, 11, 0 }, + [59] = { 12, 24, 12, 0 }, [60] = { 33, 10, 8, 1 }, + [61] = { 30, 10, 9, 1 }, [62] = { 35, 10, 0, 2 }, + [63] = { 27, 12, 5, 1 }, [64] = { 60, 5, 0, 7 }, + [65] = { 43, 8, 4, 2 }, [66] = { 39, 9, 2, 2 }, + [67] = { 45, 6, 1, 3 }, [68] = { 52, 6, 2, 3 }, + [69] = { 42, 8, 5, 2 }, [70] = { 54, 6, 3, 3 }, + [71] = { 49, 6, 4, 3 }, [72] = { 51, 6, 5, 3 }, + [73] = { 52, 6, 0, 4 }, [74] = { 65, 5, 1, 7 }, + [75] = { 60, 5, 2, 7 }, [76] = { 62, 5, 3, 7 }, + [77] = { 88, 4, 0, 10 }, [78] = { 77, 4, 1, 10 }, + [79] = { 58, 6, 1, 4 }, [80] = { 67, 5, 4, 7 }, + [81] = { 67, 5, 0, 8 }, [82] = { 76, 4, 2, 10 }, + [83] = { 70, 5, 1, 8 }, [84] = { 72, 4, 3, 10 }, + [85] = { 73, 4, 0, 11 }, [86] = { 74, 4, 1, 11 }, + [87] = { 113, 3, 0, 16 }, [88] = { 84, 4, 2, 11 }, + [89] = { 85, 4, 3, 11 }, [90] = { 87, 4, 0, 12 }, + [91] = { 48, 6, 2, 4 }, [92] = { 49, 6, 3, 4 }, + [93] = { 50, 6, 4, 4 }, [94] = { 50, 6, 5, 4 }, + [95] = { 76, 4, 1, 12 }, [96] = { 26, 12, 6, 1 }, + [97] = { 61, 5, 2, 8 }, [98] = { 62, 5, 3, 8 }, + [99] = { 54, 6, 0, 5 }, [100] = { 55, 6, 1, 5 }, + [101] = { 56, 6, 2, 5 }, [102] = { 56, 6, 3, 5 }, + [103] = { 67, 5, 4, 8 }, [104] = { 77, 4, 2, 12 }, + [105] = { 40, 8, 6, 2 }, [106] = { 40, 8, 7, 2 }, + [107] = { 90, 3, 1, 16 }, [108] = { 42, 8, 0, 3 }, + [109] = { 124, 2, 1, 22 }, [110] = { 84, 4, 3, 12 }, + [111] = { 63, 5, 0, 9 }, [112] = { 74, 4, 0, 13 }, + [113] = { 75, 4, 1, 13 }, [114] = { 76, 4, 2, 13 }, + [115] = { 66, 5, 1, 9 }, [116] = { 46, 6, 4, 5 }, + [117] = { 102, 3, 2, 16 }, [118] = { 92, 3, 0, 17 }, + [119] = { 127, 2, 0, 23 }, [120] = { 105, 3, 1, 17 }, + [121] = { 83, 4, 3, 13 }, [122] = { 95, 3, 2, 17 }, + [123] = { 72, 4, 0, 14 }, [124] = { 25, 12, 7, 1 }, + [125] = { 74, 4, 1, 14 }, [126] = { 99, 3, 0, 18 }, + [161] = { 38, 9, 3, 2 }, [162] = { 88, 4, 2, 14 }, + [163] = { 128, 2, 1, 23 }, [164] = { 90, 3, 1, 18 }, + [165] = { 117, 3, 2, 18 }, [166] = { 27, 12, 8, 1 }, + [167] = { 93, 3, 0, 19 }, [168] = { 54, 6, 5, 5 }, + [169] = { 135, 2, 0, 24 }, [170] = { 55, 6, 0, 6 }, + [171] = { 110, 3, 1, 19 }, [172] = { 97, 3, 2, 19 }, + [174] = { 140, 2, 1, 24 }, [175] = { 113, 3, 0, 20 }, + [176] = { 71, 5, 2, 9 }, [177] = { 115, 3, 1, 20 }, + [178] = { 58, 6, 1, 6 }, [179] = { 59, 6, 2, 6 }, + [180] = { 45, 6, 3, 6 }, [181] = { 105, 3, 2, 20 }, + [182] = { 105, 3, 0, 21 }, [183] = { 46, 6, 4, 6 }, + [184] = { 61, 5, 3, 9 }, [185] = { 31, 10, 1, 2 }, + [186] = { 78, 4, 3, 14 }, [187] = { 125, 2, 0, 25 }, + [188] = { 142, 2, 1, 25 }, [189] = { 159, 2, 0, 26 }, + [190] = { 160, 2, 1, 26 }, [191] = { 113, 3, 1, 21 }, + [192] = { 146, 2, 0, 27 }, [193] = { 147, 2, 1, 27 }, + [194] = { 148, 2, 0, 28 }, [195] = { 150, 2, 1, 28 }, + [196] = { 151, 2, 0, 29 }, [197] = { 152, 2, 1, 29 }, + [198] = { 221, 1, 0, 49 }, [199] = { 154, 2, 0, 30 }, + [200] = { 138, 2, 1, 30 }, [201] = { 139, 2, 0, 31 }, + [202] = { 140, 2, 1, 31 }, [203] = { 141, 2, 0, 32 }, + [204] = { 160, 2, 1, 32 }, [205] = { 161, 2, 0, 33 }, + [206] = { 162, 2, 1, 33 }, [207] = { 164, 2, 0, 34 }, + [208] = { 183, 1, 0, 50 }, [209] = { 221, 1, 0, 51 }, + [210] = { 166, 2, 1, 34 }, [211] = { 168, 2, 0, 35 }, + [212] = { 169, 2, 1, 35 }, [213] = { 170, 2, 0, 36 }, + [214] = { 171, 2, 1, 36 }, [215] = { 115, 3, 2, 21 }, + [216] = { 192, 1, 0, 52 }, [217] = { 194, 1, 0, 53 }, + [218] = { 195, 1, 0, 54 }, [219] = { 197, 1, 0, 55 }, + [220] = { 198, 1, 0, 56 }, [221] = { 219, 1, 0, 57 }, + [222] = { 160, 2, 0, 37 }, [223] = { 161, 2, 1, 37 }, + [224] = { 142, 2, 0, 38 }, [225] = { 143, 2, 1, 38 }, + [226] = { 144, 2, 0, 39 }, [227] = { 144, 2, 1, 39 }, + [228] = { 145, 2, 0, 40 }, [229] = { 146, 2, 1, 40 }, + [230] = { 210, 1, 0, 58 }, [231] = { 127, 2, 0, 41 }, + [232] = { 128, 2, 1, 41 }, [233] = { 128, 2, 0, 42 }, + [234] = { 129, 2, 1, 42 }, [235] = { 130, 2, 0, 43 }, + [236] = { 88, 4, 0, 15 }, [237] = { 88, 4, 1, 15 }, + [238] = { 88, 4, 2, 15 }, [239] = { 90, 3, 0, 22 }, + [240] = { 156, 2, 1, 43 }, [241] = { 180, 1, 0, 59 }, + [242] = { 135, 2, 0, 44 }, [243] = { 136, 2, 1, 44 }, + [244] = { 137, 2, 0, 45 }, [245] = { 137, 2, 1, 45 }, + [246] = { 138, 2, 0, 46 }, [247] = { 185, 1, 0, 60 }, + [248] = { 163, 2, 1, 46 }, [249] = { 211, 1, 0, 61 }, + [250] = { 212, 1, 0, 62 }, [251] = { 213, 1, 0, 63 }, + [252] = { 214, 1, 0, 64 }, [253] = { 167, 2, 0, 47 }, + [254] = { 144, 2, 1, 47 }, [255] = { 170, 2, 0, 48 }, + [0] = { 8, 45, 3, 0 }, [8364] = { 243, 1, 0, 65 }, + }, + } +) diff --git a/extra_fonts/params_test.lua b/extra_fonts/params_test.lua index 7754752..d06c322 100644 --- a/extra_fonts/params_test.lua +++ b/extra_fonts/params_test.lua @@ -31,6 +31,13 @@ params = { -- True type font file to get glyphs from (required) file = "sources/pixeldroidBoticRegular.otf", + -- Author(s) of the original font (required) + author = "pixeldroid", + + -- License of the original font (required) + -- Join license text, as a text file, to your mod. + license = "Open Font License", + -- Render pointsize (integer, required) -- Try to find a proper value for a good rendering pointsize = 16, @@ -42,11 +49,11 @@ params = { trim = true, -- Margin added on top of text textures with this font (integer, optional, default 0) - margin_top = 3, + margin_top = 0, -- Space between consecutive lines (integer, optional, default 0) -- Space may be negative to make lines closer. - line_spacing = -2, + line_spacing = 0, -- Space between consecutive chars (integer, optional, default 0) char_spacing = 2, @@ -63,6 +70,63 @@ params = { -- 20a0-20cf Currency Symbols (Limited to Euro symbol) { from = 0x20ac, to = 0x20ac }, }, - } + }, { + -- Registered font name (required) + -- As this name will be use as texture prefix and so repeated many times, + -- avoid long names. A good name would be a single world all lowercase. + name = "oldwizard", + + -- Registered font label (optional, default capitalized name) + -- This is the display name for this font. No need to be concise. + label = "Old Wizard", + + -- True type font file to get glyphs from (required) + file = "sources/OldWizard.ttf", + + -- Author(s) of the original font (required) + author = "Angel", + + -- License of the original font (required) + -- Join license text, as a text file, to your mod. + license = "Public Domain", + + -- URL of the original font (optional) + -- This is an optional field but it is recommended to put an URL + -- if it exists. + url = "http://www.pentacom.jp/pentacom/bitfontmaker2/gallery/?id=168", + + -- Render pointsize (integer, required) + -- Try to find a proper value for a good rendering + pointsize = 16, + + -- Shoud chars be trimmed? (boolean, required) + -- Set it to true to reduce texture size + -- and increase `char_spacing` accordingly. + -- If results are weird, you may try to set it to false. + trim = true, + + -- Margin added on top of text textures with this font (integer, optional, default 0) + margin_top = 0, + + -- Space between consecutive lines (integer, optional, default 0) + -- Space may be negative to make lines closer. + line_spacing = 0, + + -- Space between consecutive chars (integer, optional, default 0) + char_spacing = 2, + + -- Extra codepoints to include to font mod (optional, default none) + -- Codepoints from 0x0020 to 0x007f (ASCII) are always included. + -- Codepoint 0x0020 is always considered as a space. + -- Codepoints not existing in font file will be ignored. + -- Refer to https://en.wikipedia.org/wiki/Unicode + codepoints = { + -- 00a0-00ff Latin-1 Supplement (full except nbsp) + { from = 0x00a1, to = 0x00ff }, + + -- 20a0-20cf Currency Symbols (Limited to Euro symbol) + { from = 0x20ac, to = 0x20ac }, + }, + }, } } diff --git a/extra_fonts/sources/OldWizard.ttf b/extra_fonts/sources/OldWizard.ttf new file mode 100644 index 0000000000000000000000000000000000000000..227c8c3bdc270c5f60fef1f86f726396fc236867 GIT binary patch literal 49068 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

DW=g{pN%HhRfOQuvII@m72?~ljx|7nkp_LY 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 C+9cZm delta 126 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 Q_6&4WRa>R-`kjaW0VuJfy8r+H literal 0 HcmV?d00001 diff --git a/font_api/API.md b/font_api/API.md index 80b1121..80595f7 100644 --- a/font_api/API.md +++ b/font_api/API.md @@ -1,3 +1,7 @@ +## TODO: +* Update documentation with new format +* add information about texture having to be escaped in formspecs with `:gsub("[\\^]", "\\%0")` + # Font API This document describes Font API. Font API creates textures for font display on entities. diff --git a/font_api/tools/make_font.lua b/font_api/tools/make_font.lua index 0f58df6..0d20a76 100644 --- a/font_api/tools/make_font.lua +++ b/font_api/tools/make_font.lua @@ -2,8 +2,8 @@ -- A font mod generator for font_api -- --- This files generates only code and textures - should not be translated - +-- This is an utility script for code and texture generator, +-- not intended to be tranlslated. -- TODO : detect and manage fixed width fonts @@ -192,7 +192,7 @@ local function make_final_texture(font) local glyph_y = 0 table.sort(font.tile_widths) - + print(" Computing positions") -- Compute positions for _, tile_width in ipairs(font.tile_widths) do for _, codepoint in ipairs(font.by_width[tile_width]) do @@ -211,6 +211,8 @@ local function make_final_texture(font) end end + print(" Composing texture") + -- Compose texture command(string.format( "convert -size %dx%d xc:transparent %s", @@ -218,6 +220,7 @@ local function make_final_texture(font) )) for codepoint, n in pairs(font.glyph_ns) do + print(codepoint) local w = math.floor(texture_width / n) local x = w * font.glyph_xs[codepoint] local y = font.glyphs_height * font.glyph_ys[codepoint] @@ -266,12 +269,12 @@ local function process_font(font) font.glyph_widths = {} -- Exact width of reach glyph font.glyphs_height = 0 -- Max height of all glyphs - print("Read available glyphs") + print(" Reading available glyphs") -- Available codepoints from file font.cp = read_available_codepoints(font.file) - print("Compute glyphs properties") + print(" Computing glyphs properties") -- Special char: unknown char -- We use size of glyph "0" (rounded) but it would be better to get size from ttx @@ -294,7 +297,7 @@ local function process_font(font) end end - print("Create final texture") + print(" Creating final texture") make_final_texture(font) @@ -338,15 +341,17 @@ font_api.register_font( { version = 2, default = true, - margintop = 3, - linespacing = -2, - charspacing = 2, + margintop = %d, + linespacing = %d, + charspacing = %d, texture_height = %d, glyphs_height = %d, glyphs = %s, } ) -]], font.file, font.pointsize, font.name, font.texture_height, font.glyphs_height, glyphs) +]], font.file, font.pointsize, font.name, + font.margin_top, font.line_spacing, font.char_spacing, + font.texture_height, font.glyphs_height, glyphs) end -- @@ -357,7 +362,14 @@ for _, font in ipairs(params.fonts) do process_font(font) end +print("All fonts processed, writing mod files") + +-- -- Write init.lua +-- + +print(" Writing init.lua") + local file = io.open(mod_dir .. "/init.lua", "w") file:write(string.format([[ @@ -379,6 +391,7 @@ file:close() -- -- Write mod.conf -- +print(" Writing mod.conf") local file = io.open(mod_dir .. "/mod.conf", "w") file:write(string.format([[ @@ -388,4 +401,59 @@ description = %s depends = font_api ]], params.mod_name, params.mod_title, params.mod_description)) +-- +-- Write README.md +-- +print(" Writing README.md") + +local function list(t) + return #t == 1 and t[1] or + table.concat(t, ", ", 1, #t - 1) .. " and " .. t[#t] +end + +local font_labels = {} +for _, font in ipairs(params.fonts) do + table.insert(font_name, font.label) +end + +local function font_description(font) + local orignal = string.format("%s by %s", font.label, font.author) + if font.url and font.url ~= "" then + original = string.format("[%s](%s)", original, font.url) + end + + return string.format([[ +![%s font preview](screenshot_%s.png) + +**Original font**: %s + +**License**: %s +]], font.label, font.name, orignal, font.license) +end + +local file = io.open(mod_dir .. "/README.md", "w") +file:write(string.format([[ +# %s minetest mod for font API + +This mod adds %s to Font API mod (from [display_modpack](https://github.com/pyrollo/display_modpack)). + +For more information, see the [forum topic](https://forum.minetest.net/viewtopic.php?t=13563) at the Minetest forums. +]], params.mod_title, list(font_labels))) + +file:write([[ +**Dependancies**: font_api + +**License**: code under LGPL v2.1 +]]) + +if #params.fonts > 1 then + for _, font in ipairs(params.fonts) do + file:write("## %s font\n", font.label) + file:write(font_description(font)) + end +else + file:write(font_description(params.font[1])) +end + +-- This font includes uppercase, lowercase and many accentuated latin letters, greek and cyrillic letters. diff --git a/font_api/tools/make_font/params.example b/font_api/tools/make_font/params.example index 954086d..0dc41a8 100644 --- a/font_api/tools/make_font/params.example +++ b/font_api/tools/make_font/params.example @@ -10,10 +10,10 @@ params = { -- please avoid long names but keep explicit anyway. mod_name = "", - -- If only one font, have font in title, like "xxx font" + -- If only one font, have font in title, like "xxx font" mod_title = "", - -- A good description would be "... fonts for font_api" + -- A good description would be "... fonts for font_api" mod_description = "", -- List of fons to include to the mod. @@ -31,6 +31,20 @@ params = { -- True type font file to get glyphs from (required) file = "", + -- Author(s) of the original font (required) + author = "", + + -- License of the original font (required) + -- Join license text, as a text file, to your mod. + license = "", + + -- URL of the original font (optional) + -- If there is an URL about this font, it is recommended to have it + -- here. It should be URL of font project if it exists or at least + -- an URL where to download the font with details about author and + -- license. + url = "", + -- Render pointsize (integer, required) -- Try to find a proper value for a good rendering pointsize = , @@ -54,7 +68,7 @@ params = { -- Extra codepoints to include to font mod (optional, default none) -- Codepoints from 0x0020 to 0x007f (ASCII) are always included. -- Codepoint 0x0020 is always considered as a space. - -- Codepoints not existing in font file will be ignored. + -- Codepoints not existing in font file will be ignored. -- Refer to https://en.wikipedia.org/wiki/Unicode codepoints = { -- 00a0-00ff Latin-1 Supplement (full except nbsp) @@ -78,6 +92,6 @@ params = { -- 20a0-20cf Currency Symbols (Limited to Euro symbol) { from = 0x20ac, to = 0x20ac }, }, - } + }, } } diff --git a/signs/nodes.lua b/signs/nodes.lua index 55135a4..f54ead4 100644 --- a/signs/nodes.lua +++ b/signs/nodes.lua @@ -42,7 +42,7 @@ local function display_poster(pos, node, player) image[0,-0.2;8.4,2;%s] style_type[textarea;textcolor=#111] textarea[0.3,1.5;7,8;;%s;]]=], - titletexture, + titletexture:gsub("[\\^]", "\\%0"), minetest.formspec_escape(meta:get_string("text"))) if minetest.is_protected(pos, player:get_player_name()) then