Skip to content

Commit

Permalink
Replaced all mipmap stuff with more generic glyph alignment functiona…
Browse files Browse the repository at this point in the history
…lity. Added transparentColorFix.
  • Loading branch information
ReFreezed committed Apr 9, 2021
1 parent a5f6e74 commit 0b0ccb6
Show file tree
Hide file tree
Showing 3 changed files with 212 additions and 109 deletions.
69 changes: 44 additions & 25 deletions build/README.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Website: https://github.com/ReFreezed/ReFreezedBitmapFontConverter
4. Font image
5. Font descriptor
6. Icons
7. Notes



Expand Down Expand Up @@ -181,7 +182,7 @@ File structure:
# around each character, which may be useful for custom shaders). Also
# note that padding does not affect the distance between characters when
# rendered - that's what renderSpacing and kerning is for. Setting this to
# a positive number may remove black fringe around glyphs when text is
# a positive number may remove fringe around glyphs when text is
# rendered rotated/scaled or at non-integer coordinates if linear
# interpolation is used. The parameter has multiple formats.
# (Default: 0 0 0 0)
Expand All @@ -190,8 +191,9 @@ File structure:
glyphPadding=up horizontal down
glyphPadding=up right down left

# Extra space between glyphs. The parameter has multiple formats.
# (Default: 0 0)
# Extra space between glyphs. It might be relevant to increase this if the
# font will be subject to mipmapping at a later point. The parameter has
# multiple formats. (Default: 0 0)
glyphSpacing=spacing
glyphSpacing=vertival horizontal

Expand All @@ -200,11 +202,33 @@ File structure:
imagePadding=padding
imagePadding=vertival horizontal

# Cell size in pixels for the grid that glyphs will be aligned on. It
# might be relevant to increase this if the font will be subject to
# mipmapping at a later point. (Default: 1)
glyphAlignment=alignment

# Specify whether glyphPadding should be seen as part of each glyph during
# alignment. (Default: false)
glyphAlignmentIncludesPadding=bool

# Control what RGB color transparent pixels should have. Possible values
# are 'full', 'border' or 'none'. 'full' will color all transparent pixels
# the same as the closest non-transparent pixel, 'border' will do the same
# but only one pixel around non-transparent pixels leaving the remaining
# pixels black, and 'none' will color all transparent pixels black.
# Setting this to 'full' or 'border' is likely to remove black fringe
# around glyphs when text is rendered rotated/scaled or at non-integer
# coordinates if linear interpolation is used. It might be relevant to set
# this to 'full' if the font will be subject to mipmapping at a later
# point. This parameter is only relevant for colored fonts, and only if no
# outline is added. (Default: border)
transparentColorFix=mode

# Set the distance between glyphs when rendered (in addition to any
# kerning). (Default: 1)
renderSpacing=spacing

# Specify whether the padding should affect the distance between glyphs
# Specify whether glyphPadding should affect the distance between glyphs
# when rendered. Possible values are 'true' or 'false'. (Default: false)
paddingAffectsRenderSpacing=bool

Expand All @@ -217,32 +241,15 @@ File structure:
# 'smallest', 'poweroftwo' or 'poweroftwosquare'. 'smallest' creates the
# smallest possible image, 'poweroftwo' forces the width and height to be
# power-of-two, and 'poweroftwosquare' forces the width and height to be
# both power-of-two and the same length. (Default: smallest)
# both power-of-two and the same length. Some hardware only supports
# power-of-two textures. (Default: smallest)
imageBounds=rule

# Set the image encoding. Possible values are 'png' or 'tga'.
# (Default: png)
imageEncoding=encoding

# If the font will be subject to mipmapping at a later point, this
# specifies how many mipmap levels are expected/relevant. Setting this to
# a value above 1 will align glyphs in such a way so that bleeding will be
# minimized when the image is downscaled 50% at a time until a certain
# point. (Default: 1, i.e. no additional levels for mipmapping are
# assumed)
#
# Note: Cannot be combined with glyphSpacing or imagePadding (but
# glyphPadding works fine).
#
# Note: glyphPadding is multiplied by this so that the most downscaled
# image will have the visible padding of the unmultiplied glyphPadding.
#
# Note: This parameter should not be needed if the program creating the
# mipmaps is smart enough.
#
alignForMipmapLevels=levels

# You can embed multiple custom values in the outputted BMFont file using
# You can embed multiple custom values in the outputted BMFont files using
# this format.
custom.someName=someValue
# Examples:
Expand Down Expand Up @@ -345,7 +352,7 @@ File structure, in addition to the above:
# TrueType hinting mode (for anti-aliasing). Possible values are 'normal',
# 'light', 'none' or 'mono'. 'mono' disables anti-aliasing while the
# others control the level of hinting. (Default: normal)
fontHinting=hintingMode
fontHinting=mode

# Filename of a text file containing characters you want to rasterize. You
# can use this instead of, or in conjunction with, numbered sections.
Expand Down Expand Up @@ -396,4 +403,16 @@ this:



7. Notes
==============================================================================

Mipmapping:

If a font will be subject to mipmapping at a later point it might be relevant
to tweak the glyphAlignment and glyphSpacing parameters to fix downsized
glyphs bleeding into each other. Setting transparentColorFix to 'full' may
improve the color of the downsized glyphs.



==============================================================================
51 changes: 39 additions & 12 deletions src/functions.lua2p
Original file line number Diff line number Diff line change
Expand Up @@ -578,9 +578,9 @@ end



function _G.outputImageFilenameBaseToFilename(filenameBase, imageIndex)
function _G.outputImageFilenameBaseToFilename(filenameBase, page)
local basename, ext = getBasenameAndExtensionWithDot(filenameBase)
return F("%s_%d%s", basename, imageIndex-1, ext)
return F("%s_%d%s", basename, page-1, ext)
end


Expand Down Expand Up @@ -626,25 +626,45 @@ end
-- Glyphs are expected to be sorted by height, when width.
-- Returns nil if pageCount exceeds maxPages.
function _G.makeGlyphLayout(outDescr, glyphs, maxPageW,maxPageH, maxPages, forReal)
local ceil = math.ceil
local max = math.max

local maxW = maxPageW - outDescr.imagePaddingH
local maxH = maxPageH - outDescr.imagePaddingV

local glyphSpacingH = outDescr.glyphSpacingH
local glyphSpacingV = outDescr.glyphSpacingV

local alignment = outDescr.glyphAlignment
local alignmentInv = 1 / alignment
local alignmentOffsetX = outDescr.glyphAlignmentIncludesPadding and 0 or outDescr.glyphPaddingL
local alignmentOffsetY = outDescr.glyphAlignmentIncludesPadding and 0 or outDescr.glyphPaddingU

!(
local function ALIGN_X(expr)
return templateToLua(
`(ceil((($expr) + alignmentOffsetX) * alignmentInv) * alignment - alignmentOffsetX)`,
{expr=expr}
)
end
local function ALIGN_Y(expr)
return templateToLua(
`(ceil((($expr) + alignmentOffsetY) * alignmentInv) * alignment - alignmentOffsetY)`,
{expr=expr}
)
end
)

local pageWidth = 2 -- @Hardcoded minimum page size.
local pageHeight = 2
local pageCount = 1

local x0 = outDescr.imagePaddingH
local y0 = outDescr.imagePaddingV
local x0 = !!(ALIGN_X `outDescr.imagePaddingH`)
local y0 = !!(ALIGN_Y `outDescr.imagePaddingV`)

local rowInfos = {{page=1, nextX=x0, y=y0, height=glyphs[1].outH}} -- Note: We never need to update any rowInfo.height because of how the glyphs are sorted.
local pageHeights = {[1]=glyphs[1].outH}

local ceil = math.ceil
local max = math.max

for _, glyphInfo in ipairs(glyphs) do
if glyphInfo.inW > 0 then
-- Note: Glyphs will automatically be mipmap-aligned because of their already-determined final size
Expand All @@ -653,16 +673,22 @@ function _G.makeGlyphLayout(outDescr, glyphs, maxPageW,maxPageH, maxPages, forRe
local hPadded = glyphInfo.outH
local rowInfo = nil

for _, _rowInfo in ipairs(rowInfos) do
if _rowInfo.nextX+wPadded <= maxW and _rowInfo.y+hPadded <= maxH then
rowInfo = _rowInfo
for _, existingRowInfo in ipairs(rowInfos) do
if existingRowInfo.nextX+wPadded <= maxW and existingRowInfo.y+hPadded <= maxH then
rowInfo = existingRowInfo
break
end
end

if not rowInfo then
local lastRowInfo = rowInfos[#rowInfos]
rowInfo = {page=lastRowInfo.page, nextX=x0, y=lastRowInfo.y+lastRowInfo.height+glyphSpacingV, height=hPadded}

rowInfo = {
page = lastRowInfo.page,
nextX = x0,
y = !!(ALIGN_Y `lastRowInfo.y + lastRowInfo.height + glyphSpacingV`),
height = hPadded,
}

if rowInfo.y+hPadded > maxH then
rowInfo.page = pageCount + 1 -- Fallback if the loop below doesn't find an existing page to fit the row in.
Expand Down Expand Up @@ -693,7 +719,8 @@ function _G.makeGlyphLayout(outDescr, glyphs, maxPageW,maxPageH, maxPages, forRe
pageWidth = max(pageWidth, rowInfo.nextX + wPadded)
pageHeight = max(pageHeight, rowInfo.y + hPadded)

rowInfo.nextX = rowInfo.nextX + wPadded + glyphSpacingH
rowInfo.nextX = !!(ALIGN_X `rowInfo.nextX + wPadded + glyphSpacingH`)

-- @Speed?: "Forget" row if there's literally no more space.
end
end--for glyphs
Expand Down
Loading

0 comments on commit 0b0ccb6

Please sign in to comment.