Multiple fonts and UTF chars support

This commit is contained in:
Pierre-Yves Rollo 2017-12-19 21:52:49 +01:00
parent ce8e214400
commit 46d2ce085e
163 changed files with 291 additions and 81 deletions

@ -13,6 +13,16 @@ For more information, see the [forum topic](https://forum.minetest.net/viewtopic
## Changelog
### 2017-12-19
This change is a preparation to merge Andrzej Pieńkowski fork (apienk) : new font and support of UTF chars.
- Font\_lib support for multiple fonts (nothing yet visible in mods) ;
- Font\_lib support for Unicode characters (limited to Unicode Plane 0: 0000-FFFF, see [Wikipedia](https://en.wikipedia.org/wiki/Unicode)) ;
- New "default" font with original textures from Vanessa Ezekowitz (VanessaE) ;
### 2017-12-10
- Compatibility of signs mod with signs_lib (thanks to gpcf) ;

@ -2,19 +2,24 @@
This document describes Font Lib API. Font Lib creates textures for font display on entities.
## Provided methods
### get\_line\_width
**font\_lib.get\_line\_width(text)**
### get\_text\_size
**font\_lib.get\_text\_size(font\_name, text)**
Computes size for a given font and text
**font\_name**: Font name of registered font to use
Computes line width for a given font height and text
**text**: Text to be rendered
**Returns**: rendered text width
**Returns**: rendered text width, height
### make\_line\_texture
**font\_lib.make\_line\_texture(text, texturew, x, y)**
**font\_lib.make\_line\_texture(font\_name, text, width, x, y)**
Builds texture part for a text line
**font\_name**: Font name of registered font to use
**text**: Text to be rendered
**texturew**: Width of the texture (extra text is not rendered)
@ -26,10 +31,12 @@ Builds texture part for a text line
**Returns**: Texture string
### make\_multiline\_texture
**font\_lib.make\_multiline\_texture(text, texturew, textureh, maxlines, valign, color)**
**font\_lib.make\_multiline\_texture(font\_name, text, width, height, maxlines, valign, color)**
Builds texture for a multiline colored text
**font\_name**: Font name of registered font to use
**text**: Text to be rendered
**texturew**: Width of the texture (extra text will be truncated)
@ -38,10 +45,46 @@ Builds texture for a multiline colored text
**maxlines**: Maximum number of lines
**valign**: Vertical text align ("top" or "center")
**valign**: Vertical text align ("top", "bottom" or "center")
**color**: Color of the text
**Returns**: Texture string
### register\_font
**font\_lib.register_font(font\_name, height, widths)**
Registers a new font in font_lib.
**font\_name**: Name of the font to register (this name will be used to address the font later)
**height**: Height of the font in pixels (all font textures should have the same height)
**widths** : An array containing the width of each font texture, indexed by its UTF code
All textures corresponding to the indexes in **widths** array should be present in textures directory with a name matching the pattern :
**font\_<font\_name>_<utf\_code>.png**
<font\_name>: Name of the font as given in the first argument
<utf\_code>: UTF code of the char in 4 hexadecimal digits
To ease that declaration, a shell is provided to build a <font\_name>.lua file from the texture files (see provided tools).
### set\_fallback\_font
**function font\_lib.set\_fallback\_font(font\_name)**
Defines the fallback font to be used instead of given font if not registered.
**font\_name**: Name of the font to be used as fallback font (has to be registered)
## Provided tools
### make_font_lua.sh
Still in early stage of development.
This script analyses textures in textures directory and creates a font\_<font\_name>.lua files with a call to register_font with images information.

@ -6,9 +6,9 @@ This library for font display on entities (to be used with display_lib for sign
**License**: LGPL
(Font taken from VanessaE's homedecor/signs_lib, originally under WTFPL)
(Default font taken from VanessaE's homedecor/signs_lib, originally under WTFPL)
**API**: See [API.md](https://github.com/pyrollo/display_modpack/blob/master/font_lib/API.md) document please.
For more information, see the [forum topic](https://forum.minetest.net/viewtopic.php?f=11&t=13563) at the Minetest forums.
For more information, see the [forum topic](https://forum.minetest.net/viewtopic.php?t=13563) at the Minetest forums.

12
font_lib/font_default.lua Normal file

@ -0,0 +1,12 @@
--[[
generated by ./make_font_mod.sh Sun Dec 17 21:23:59 CET 2017
--]]
font_lib.register_font(
'default',
12,
{ [0]=6, [32]=4, [33]=3, [34]=4, [35]=7, [36]=6, [37]=8, [38]=8, [39]=3, [40]=4, [41]=4, [42]=4, [43]=7, [44]=3, [45]=5, [46]=3, [47]=5, [48]=6, [49]=4, [50]=6, [51]=6, [52]=7, [53]=6, [54]=6, [55]=6, [56]=6, [57]=6, [58]=3, [59]=3, [60]=5, [61]=6, [62]=5, [63]=6, [64]=11, [65]=8, [66]=7, [67]=8, [68]=7, [69]=6, [70]=6, [71]=8, [72]=7, [73]=3, [74]=6, [75]=8, [76]=6, [77]=10, [78]=8, [79]=8, [80]=7, [81]=8, [82]=7, [83]=7, [84]=7, [85]=7, [86]=8, [87]=11, [88]=8, [89]=9, [90]=7, [91]=4, [92]=5, [93]=4, [94]=5, [95]=7, [96]=3, [97]=7, [98]=6, [99]=5, [100]=6, [101]=6, [102]=5, [103]=6, [104]=6, [105]=3, [106]=3, [107]=7, [108]=3, [109]=9, [110]=6, [111]=6, [112]=6, [113]=6, [114]=5, [115]=6, [116]=4, [117]=6, [118]=6, [119]=8, [120]=7, [121]=6, [122]=6, [123]=5, [124]=3, [125]=5, [126]=6, [138]=6, [141]=3, [161]=3, [177]=6, [191]=6, [193]=8, [194]=8, [195]=8, [196]=8, [197]=8, [198]=10, [199]=8, [200]=6, [201]=6, [202]=6, [203]=6, [204]=3, [205]=3, [206]=3, [207]=3, [208]=8, [209]=8, [210]=8, [211]=8, [212]=8, [213]=8, [214]=8, [215]=6, [216]=8, [217]=7, [218]=7, [219]=7, [220]=7, [221]=9, [224]=7, [225]=7, [226]=7, [227]=7, [228]=7, [229]=7, [230]=9, [231]=5, [232]=6, [233]=6, [234]=6, [235]=6, [236]=3, [237]=3, [238]=3, [239]=3, [242]=6, [244]=6, [245]=6, [246]=6, [247]=6, [249]=6, [250]=6, [251]=6, [252]=6, [253]=6, [255]=6 }
);

@ -21,26 +21,12 @@
font_lib = {}
font_lib.path = minetest.get_modpath("font_lib")
font_lib.font_height = 12
font_lib.font = {}
font_lib.registered_fonts = {}
-- Local functions
------------------
local function get_next_char(text, pos)
pos = pos + 1
local char = text:sub(pos, pos):byte()
if char >= 0x80 then
if char == 0xc2 or char == 0xc3 then
pos = pos + 1
char = (char - 0xc2) * 0x40 + text:sub(pos, pos):byte()
else
char = 0
end
end
if font_lib.font[char] == nil then char=0 end
return char, pos
end
-- Split multiline text into array of lines, with <maxlines> maximum lines.
local function split_lines(text, maxlines)
local splits = text:split("\n")
@ -55,49 +41,125 @@ local function split_lines(text, maxlines)
end
end
-- Computes line width for a given font height and text
-- @param text Text to be rendered
-- @return Rendered text width
-- Returns next char, managing ascii and unicode plane 0 (0000-FFFF).
function font_lib.get_line_width(text)
local char
local width = 0
local p=0
local function get_next_char(text, pos)
pos = pos + 1
local char = text:sub(pos, pos):byte()
while p < #text do
char, p = get_next_char(text, p)
width = width + font_lib.font[char].width
-- 4 bytes char not managed
if char >= 0xF0 then
pos = pos + 3
return 0, pos
end
return width
-- 3 bytes char not managed
if char >= 0xE0 then
pos = pos + 2
return 0, pos
end
-- 2 bytes char (little endian)
if char >= 0x80 then
pos = pos + 1
return char * 0x100 + text:sub(pos, pos):byte(), pos
end
-- 1 byte char
return char, pos
end
-- Returns font properties to be used according to font_name
local function get_font(font_name)
local font = font_lib.registered_fonts[font_name]
if font == nil then
local message
if font_name == nil then
message = "No font given"
else
message = "Font \""..font_name.."\" unregistered"
end
if font_lib.fallback_font == nil then
minetest.log("error", message.." and no other font registered.")
else
minetest.log("info", message..", using font \""..font_lib.fallback_font.."\".")
font = font_lib.registered_fonts[font_lib.fallback_font]
end
end
return font
end
-- API functions
----------------
-- Computes text size for a given font and text (ignores new lines)
-- @param font_name Font to be used
-- @param text Text to be rendered
-- @return Rendered text (width, height)
function font_lib.get_text_size(font_name, text)
local char
local width = 0
local pos = 0
local font = get_font(font_name)
if font == nil then
return 0, 0
else
while pos < #text do
char, pos = get_next_char(text, pos)
-- Ignore chars with no texture
if font.widths[char] ~= nil then
width = width + font.widths[char]
end
end
end
return width, font.height
end
--- Builds texture part for a text line
-- @param font_name Font to be used
-- @param text Text to be rendered
-- @param texturew Width of the texture (extra text is not rendered)
-- @param width Width of the texture (extra text is not rendered)
-- @param x Starting x position in texture
-- @param y Vertical position of the line in texture
-- @return Texture string
function font_lib.make_line_texture(text, texturew, x, y)
local char
--> ADD ALIGN
function font_lib.make_line_texture(font_name, text, width, x, y)
local texture = ""
local p=0
local char
local pos = 0
local font = get_font(font_name)
while p < #text do
char, p = get_next_char(text, p)
if font ~= nil then
while pos < #text do
char, pos = get_next_char(text, pos)
-- Ignore chars with no texture
if font.widths[char] ~= nil then
-- Add image only if it is visible (at least partly)
if x + font_lib.font[char].width >= 0 and x <= texturew then
texture = texture..string.format(":%d,%d=%s", x, y, font_lib.font[char].filename)
if x + font.widths[char] >= 0 and x <= width then
texture = texture..
string.format(":%d,%d=font_%s_%04x.png",
x, y, font.name, char)
end
x = x + font.widths[char]
end
end
end
x = x + font_lib.font[char].width
end
return texture
end
--- Builds texture for a multiline colored text
-- @param font_name Font to be used
-- @param text Text to be rendered
-- @param texturew Width of the texture (extra text will be truncated)
-- @param textureh Height of the texture
@ -106,29 +168,78 @@ end
-- @param color Color of the text
-- @return Texture string
function font_lib.make_multiline_texture(text, texturew, textureh, maxlines, valign, color)
function font_lib.make_multiline_texture(font_name, text, width, height,
maxlines, valign, color)
local texture = ""
local lines = split_lines(text, maxlines)
local y
local lines = {}
local textheight = 0
local y, w, h
for num, line in pairs(split_lines(text, maxlines)) do
w, h = font_lib.get_text_size(font_name, line)
lines[num] = { text = line, width = w, height = h, }
textheight = textheight + h
end
if #lines then
if valign == "top" then
y = font_lib.font_height / 2 - 1
y = 0
elseif valign == "bottom" then
y = height - textheight
else
y = (textureh - font_lib.font_height * #lines) / 2
y = (height - textheight) / 2
end
end
for _, line in pairs(lines) do
texture = texture..font_lib.make_line_texture(line, texturew,
(texturew - font_lib.get_line_width(line)) / 2, y)
y = y + font_lib.font_height
texture = texture..
font_lib.make_line_texture(font_name, line.text, width,
(width - line.width) / 2, y)
y = y + line.height
end
texture = string.format("[combine:%dx%d", texturew, textureh)..texture
texture = string.format("[combine:%dx%d", width, height)..texture
if color then texture = texture.."^[colorize:"..color end
return texture
end
--- Register a new font
-- Textures corresponding to the font should be named after following patern :
-- font_<name>_<code>.png
-- <name> : name of the font
-- <code> : 4 digit hexadecimal unicode of the char
-- If registering different sizes, add size in the font name (e.g. times_10, times_12...)
-- @param height Font height in pixels
-- @param widths Array of character widths in pixel, indexed by unicode number.
function font_lib.register_font(font_name, height, widths)
if font_lib.registered_fonts[font_name] ~= nil then
minetest.log("error", "Font \""..font_name.."\" already registered.")
return
end
font_lib.registered_fonts[font_name] =
{ name = font_name, height = height, widths = widths }
-- If no fallback font, set it (so, first font registered will be the default fallback font)
if font_lib.fallback_font == nil then
font_lib.fallback_font = font_name
end
end
--- Define the fallback font
-- This font will be used instead of given font if not registered.
-- @param font_name Name of the font to be used as fallback font (has to be registered).
function font_lib.set_fallback_font(font_name)
if font_lib.registered_fonts[font_name] == nil then
minetest.log("error", "Fallback font \""..font_name.."\" not registered.")
else
font_lib.fallback_font = font_name
end
end
--- Standard on_display_update entity callback.
-- Node should have a corresponding display_entity with size, resolution and maxlines fields and
-- optionally valign and color fields
@ -146,26 +257,12 @@ function font_lib.on_display_update(pos, objref)
objref:set_properties({
textures={font_lib.make_multiline_texture(
text, def.size.x*def.resolution.x, def.size.y*def.resolution.y,
def.font_name, text, def.size.x*def.resolution.x, def.size.y*def.resolution.y,
def.maxlines, def.valign, def.color)},
visual_size = def.size
})
end
end
-- Populate fonts table
local filename
for char = 0,255 do
filename = string.format("font_lib_%02x.png", char)
local file=io.open(font_lib.path.."/textures/"..filename,"rb")
if file~=nil then
-- Get png width, suposing png width is less than 256 (it is the case for all font textures)
-- All font png are smaller than 256x256 --> read only last byte
file:seek("set",19)
local w = file:read(1)
file:close()
font_lib.font[char] = {filename=filename, width=w:byte()}
end
end
dofile(font_lib.path.."/font_default.lua")

Before

Width:  |  Height:  |  Size: 145 B

After

Width:  |  Height:  |  Size: 145 B

Before

Width:  |  Height:  |  Size: 281 B

After

Width:  |  Height:  |  Size: 281 B

Before

Width:  |  Height:  |  Size: 299 B

After

Width:  |  Height:  |  Size: 299 B

Before

Width:  |  Height:  |  Size: 290 B

After

Width:  |  Height:  |  Size: 290 B

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 304 B

Before

Width:  |  Height:  |  Size: 314 B

After

Width:  |  Height:  |  Size: 314 B

Before

Width:  |  Height:  |  Size: 312 B

After

Width:  |  Height:  |  Size: 312 B

Before

Width:  |  Height:  |  Size: 319 B

After

Width:  |  Height:  |  Size: 319 B

Before

Width:  |  Height:  |  Size: 290 B

After

Width:  |  Height:  |  Size: 290 B

Before

Width:  |  Height:  |  Size: 303 B

After

Width:  |  Height:  |  Size: 303 B

Before

Width:  |  Height:  |  Size: 301 B

After

Width:  |  Height:  |  Size: 301 B

Before

Width:  |  Height:  |  Size: 289 B

After

Width:  |  Height:  |  Size: 289 B

Before

Width:  |  Height:  |  Size: 297 B

After

Width:  |  Height:  |  Size: 297 B

Before

Width:  |  Height:  |  Size: 290 B

After

Width:  |  Height:  |  Size: 290 B

Before

Width:  |  Height:  |  Size: 287 B

After

Width:  |  Height:  |  Size: 287 B

Before

Width:  |  Height:  |  Size: 289 B

After

Width:  |  Height:  |  Size: 289 B

Before

Width:  |  Height:  |  Size: 299 B

After

Width:  |  Height:  |  Size: 299 B

Before

Width:  |  Height:  |  Size: 302 B

After

Width:  |  Height:  |  Size: 302 B

Before

Width:  |  Height:  |  Size: 300 B

After

Width:  |  Height:  |  Size: 300 B

Before

Width:  |  Height:  |  Size: 312 B

After

Width:  |  Height:  |  Size: 312 B

Before

Width:  |  Height:  |  Size: 313 B

After

Width:  |  Height:  |  Size: 313 B

Before

Width:  |  Height:  |  Size: 314 B

After

Width:  |  Height:  |  Size: 314 B

Before

Width:  |  Height:  |  Size: 317 B

After

Width:  |  Height:  |  Size: 317 B

Before

Width:  |  Height:  |  Size: 312 B

After

Width:  |  Height:  |  Size: 312 B

Before

Width:  |  Height:  |  Size: 308 B

After

Width:  |  Height:  |  Size: 308 B

Before

Width:  |  Height:  |  Size: 300 B

After

Width:  |  Height:  |  Size: 300 B

Before

Width:  |  Height:  |  Size: 315 B

After

Width:  |  Height:  |  Size: 315 B

Before

Width:  |  Height:  |  Size: 289 B

After

Width:  |  Height:  |  Size: 289 B

Before

Width:  |  Height:  |  Size: 292 B

After

Width:  |  Height:  |  Size: 292 B

Before

Width:  |  Height:  |  Size: 290 B

After

Width:  |  Height:  |  Size: 290 B

Before

Width:  |  Height:  |  Size: 290 B

After

Width:  |  Height:  |  Size: 290 B

Before

Width:  |  Height:  |  Size: 289 B

After

Width:  |  Height:  |  Size: 289 B

Before

Width:  |  Height:  |  Size: 310 B

After

Width:  |  Height:  |  Size: 310 B

Before

Width:  |  Height:  |  Size: 323 B

After

Width:  |  Height:  |  Size: 323 B

Before

Width:  |  Height:  |  Size: 313 B

After

Width:  |  Height:  |  Size: 313 B

Before

Width:  |  Height:  |  Size: 302 B

After

Width:  |  Height:  |  Size: 302 B

Before

Width:  |  Height:  |  Size: 320 B

After

Width:  |  Height:  |  Size: 320 B

Before

Width:  |  Height:  |  Size: 308 B

After

Width:  |  Height:  |  Size: 308 B

Before

Width:  |  Height:  |  Size: 302 B

After

Width:  |  Height:  |  Size: 302 B

Before

Width:  |  Height:  |  Size: 305 B

After

Width:  |  Height:  |  Size: 305 B

Before

Width:  |  Height:  |  Size: 327 B

After

Width:  |  Height:  |  Size: 327 B

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 304 B

Before

Width:  |  Height:  |  Size: 292 B

After

Width:  |  Height:  |  Size: 292 B

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 304 B

Before

Width:  |  Height:  |  Size: 320 B

After

Width:  |  Height:  |  Size: 320 B

Before

Width:  |  Height:  |  Size: 298 B

After

Width:  |  Height:  |  Size: 298 B

Before

Width:  |  Height:  |  Size: 317 B

After

Width:  |  Height:  |  Size: 317 B

Before

Width:  |  Height:  |  Size: 315 B

After

Width:  |  Height:  |  Size: 315 B

Before

Width:  |  Height:  |  Size: 314 B

After

Width:  |  Height:  |  Size: 314 B

Before

Width:  |  Height:  |  Size: 309 B

After

Width:  |  Height:  |  Size: 309 B

Before

Width:  |  Height:  |  Size: 322 B

After

Width:  |  Height:  |  Size: 322 B

Before

Width:  |  Height:  |  Size: 303 B

After

Width:  |  Height:  |  Size: 303 B

Before

Width:  |  Height:  |  Size: 316 B

After

Width:  |  Height:  |  Size: 316 B

Before

Width:  |  Height:  |  Size: 301 B

After

Width:  |  Height:  |  Size: 301 B

Before

Width:  |  Height:  |  Size: 299 B

After

Width:  |  Height:  |  Size: 299 B

Before

Width:  |  Height:  |  Size: 306 B

After

Width:  |  Height:  |  Size: 306 B

Before

Width:  |  Height:  |  Size: 313 B

After

Width:  |  Height:  |  Size: 313 B

Before

Width:  |  Height:  |  Size: 308 B

After

Width:  |  Height:  |  Size: 308 B

Before

Width:  |  Height:  |  Size: 306 B

After

Width:  |  Height:  |  Size: 306 B

Before

Width:  |  Height:  |  Size: 307 B

After

Width:  |  Height:  |  Size: 307 B

Before

Width:  |  Height:  |  Size: 297 B

After

Width:  |  Height:  |  Size: 297 B

Before

Width:  |  Height:  |  Size: 297 B

After

Width:  |  Height:  |  Size: 297 B

Before

Width:  |  Height:  |  Size: 298 B

After

Width:  |  Height:  |  Size: 298 B

Before

Width:  |  Height:  |  Size: 303 B

After

Width:  |  Height:  |  Size: 303 B

Before

Width:  |  Height:  |  Size: 286 B

After

Width:  |  Height:  |  Size: 286 B

Before

Width:  |  Height:  |  Size: 284 B

After

Width:  |  Height:  |  Size: 284 B

Before

Width:  |  Height:  |  Size: 316 B

After

Width:  |  Height:  |  Size: 316 B

Before

Width:  |  Height:  |  Size: 307 B

After

Width:  |  Height:  |  Size: 307 B

Before

Width:  |  Height:  |  Size: 307 B

After

Width:  |  Height:  |  Size: 307 B

Before

Width:  |  Height:  |  Size: 314 B

After

Width:  |  Height:  |  Size: 314 B

Before

Width:  |  Height:  |  Size: 313 B

After

Width:  |  Height:  |  Size: 313 B

Before

Width:  |  Height:  |  Size: 306 B

After

Width:  |  Height:  |  Size: 306 B

Before

Width:  |  Height:  |  Size: 314 B

After

Width:  |  Height:  |  Size: 314 B

Before

Width:  |  Height:  |  Size: 305 B

After

Width:  |  Height:  |  Size: 305 B

Before

Width:  |  Height:  |  Size: 292 B

After

Width:  |  Height:  |  Size: 292 B

Before

Width:  |  Height:  |  Size: 293 B

After

Width:  |  Height:  |  Size: 293 B

Before

Width:  |  Height:  |  Size: 311 B

After

Width:  |  Height:  |  Size: 311 B

Before

Width:  |  Height:  |  Size: 292 B

After

Width:  |  Height:  |  Size: 292 B

Before

Width:  |  Height:  |  Size: 306 B

After

Width:  |  Height:  |  Size: 306 B

Before

Width:  |  Height:  |  Size: 308 B

After

Width:  |  Height:  |  Size: 308 B

Before

Width:  |  Height:  |  Size: 302 B

After

Width:  |  Height:  |  Size: 302 B

Before

Width:  |  Height:  |  Size: 315 B

After

Width:  |  Height:  |  Size: 315 B

Before

Width:  |  Height:  |  Size: 314 B

After

Width:  |  Height:  |  Size: 314 B

Before

Width:  |  Height:  |  Size: 303 B

After

Width:  |  Height:  |  Size: 303 B

Before

Width:  |  Height:  |  Size: 306 B

After

Width:  |  Height:  |  Size: 306 B

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 304 B

Before

Width:  |  Height:  |  Size: 295 B

After

Width:  |  Height:  |  Size: 295 B

Before

Width:  |  Height:  |  Size: 300 B

After

Width:  |  Height:  |  Size: 300 B

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 304 B

Before

Width:  |  Height:  |  Size: 302 B

After

Width:  |  Height:  |  Size: 302 B

Before

Width:  |  Height:  |  Size: 306 B

After

Width:  |  Height:  |  Size: 306 B

Before

Width:  |  Height:  |  Size: 296 B

After

Width:  |  Height:  |  Size: 296 B

Before

Width:  |  Height:  |  Size: 297 B

After

Width:  |  Height:  |  Size: 297 B

Before

Width:  |  Height:  |  Size: 134 B

After

Width:  |  Height:  |  Size: 134 B

Before

Width:  |  Height:  |  Size: 297 B

After

Width:  |  Height:  |  Size: 297 B

Some files were not shown because too many files have changed in this diff Show More