Atlas padding polish

This commit is contained in:
Chlumsky 2024-05-01 23:15:13 +02:00
parent 37e031b2b5
commit 6716f27903
15 changed files with 90 additions and 107 deletions

View File

@ -120,7 +120,11 @@ Any non-empty subset of the following may be specified:
- `-minsize <em size>` &ndash; sets the minimum size. The largest possible size that fits the same atlas dimensions will be used
- `-emrange <em range>` &ndash; sets the distance field range in em's
- `-pxrange <pixel range>` (default = 2) &ndash; sets the distance field range in output pixels
- `-aemrange` / `-apxrange <outermost distance> <innermost distance>` &ndash; sets the distance field range asymmetrically by specifying the minimum and maximum representable signed distances (outside distances are negative!)
- `-pxalign <off / on / horizontal / vertical>` (default = vertical) &ndash; enables or disables alignment of glyph's origin point with the pixel grid
- `-empadding` / `-pxpadding <width>` &ndash; sets additional padding within each glyph's box (in em's / pixels)
- `-outerempadding` / `-outerpxpadding <width>` &ndash; sets additional padding around each glyph's box
- `-aempadding` / `-apxpadding` / `-aouterempadding` / `-aouterpxpadding <left> <bottom> <right> <top>` &ndash; sets additional padding (see above) asymmetrically with a separate width value for each side
### Distance field generator settings

@ -1 +1 @@
Subproject commit 34134bde3cea35a93c2ae5703fa8d3d463793400
Subproject commit 888674220216d1d326c6f29cf89165b545279c1f

View File

@ -54,7 +54,7 @@ void GlyphGeometry::edgeColoring(void (*fn)(msdfgen::Shape &, double, unsigned l
void GlyphGeometry::wrapBox(const GlyphAttributes &glyphAttributes) {
double scale = glyphAttributes.scale*geometryScale;
msdfgen::Range range = glyphAttributes.range/geometryScale;
Padding fullPadding = 1/geometryScale*(glyphAttributes.innerPadding+glyphAttributes.outerPadding);
Padding fullPadding = (glyphAttributes.innerPadding+glyphAttributes.outerPadding)/geometryScale;
box.range = range;
box.scale = scale;
if (bounds.l < bounds.r && bounds.b < bounds.t) {
@ -115,7 +115,7 @@ void GlyphGeometry::wrapBox(double scale, double range, double miterLimit, bool
void GlyphGeometry::frameBox(const GlyphAttributes &glyphAttributes, int width, int height, const double *fixedX, const double *fixedY) {
double scale = glyphAttributes.scale*geometryScale;
msdfgen::Range range = glyphAttributes.range/geometryScale;
Padding fullPadding = 1/geometryScale*(glyphAttributes.innerPadding+glyphAttributes.outerPadding);
Padding fullPadding = (glyphAttributes.innerPadding+glyphAttributes.outerPadding)/geometryScale;
box.range = range;
box.scale = scale;
box.rect.w = width;
@ -288,22 +288,4 @@ msdfgen::Range operator+(msdfgen::Range a, msdfgen::Range b) {
return msdfgen::Range(a.lower+b.lower, a.upper+b.upper);
}
Padding operator+(const Padding &a, const Padding &b) {
Padding result;
result.l = a.l+b.l;
result.b = a.b+b.b;
result.r = a.r+b.r;
result.t = a.t+b.t;
return result;
}
Padding operator*(double a, const Padding &b) {
Padding result;
result.l = a*b.l;
result.b = a*b.b;
result.r = a*b.r;
result.t = a*b.t;
return result;
}
}

View File

@ -5,12 +5,11 @@
#include <msdfgen-ext.h>
#include "types.h"
#include "Rectangle.h"
#include "Padding.h"
#include "GlyphBox.h"
namespace msdf_atlas {
typedef msdfgen::Shape::Bounds Padding;
/// Represents the shape geometry of a single glyph as well as its configuration
class GlyphGeometry {
@ -99,7 +98,4 @@ private:
msdfgen::Range operator+(msdfgen::Range a, msdfgen::Range b);
Padding operator+(const Padding &a, const Padding &b);
Padding operator*(double a, const Padding &b);
}

View File

@ -102,8 +102,6 @@ GridAtlasPacker::GridAtlasPacker() :
pxRange(0),
miterLimit(0),
pxAlignOriginX(false), pxAlignOriginY(false),
innerUnitPadding(), outerUnitPadding(),
innerPxPadding(), outerPxPadding(),
scaleMaximizationTolerance(.001),
alignedColumnsBias(.125),
cutoff(false)
@ -136,8 +134,7 @@ msdfgen::Shape::Bounds GridAtlasPacker::getMaxBounds(double &maxWidth, double &m
if (maxBounds.l >= maxBounds.r || maxBounds.b >= maxBounds.t)
maxBounds = msdfgen::Shape::Bounds();
Padding fullPadding = scale*(innerUnitPadding+outerUnitPadding)+innerPxPadding+outerPxPadding;
maxBounds.l -= fullPadding.l, maxBounds.b -= fullPadding.b;
maxBounds.r += fullPadding.r, maxBounds.t += fullPadding.t;
pad(maxBounds, fullPadding);
maxWidth += fullPadding.l+fullPadding.r;
maxHeight += fullPadding.b+fullPadding.t;
// If origin is pixel-aligned but not fixed, one pixel has to be added to max dimensions to allow for aligning the origin by shifting by < 1 pixel
@ -326,8 +323,7 @@ int GridAtlasPacker::pack(GlyphGeometry *glyphs, int count) {
Padding pxPadding = innerPxPadding+outerPxPadding;
maxBounds = getMaxBounds(maxWidth, maxHeight, glyphs, count, 1, -unitRange.lower);
// Undo pxPadding added by getMaxBounds before pixel scale is known
maxBounds.l += pxPadding.l, maxBounds.b += pxPadding.b;
maxBounds.r -= pxPadding.r, maxBounds.t -= pxPadding.t;
pad(maxBounds, -pxPadding);
maxWidth -= pxPadding.l+pxPadding.r;
maxHeight -= pxPadding.b+pxPadding.t;
int hSlack = 0, vSlack = 0;
@ -419,8 +415,7 @@ int GridAtlasPacker::pack(GlyphGeometry *glyphs, int count) {
maxBounds.r *= scale, maxBounds.t *= scale;
maxWidth *= scale, maxHeight *= scale;
// Redo addition of pxPadding once scale is known
maxBounds.l -= pxPadding.l, maxBounds.b -= pxPadding.b;
maxBounds.r += pxPadding.r, maxBounds.t += pxPadding.t;
pad(maxBounds, pxPadding);
maxWidth += pxPadding.l+pxPadding.r;
maxHeight += pxPadding.b+pxPadding.t;
@ -602,44 +597,22 @@ void GridAtlasPacker::setOriginPixelAlignment(bool alignX, bool alignY) {
pxAlignOriginX = alignX, pxAlignOriginY = alignY;
}
static Padding makeUniformPadding(double width) {
Padding p;
p.l = width, p.b = width, p.r = width, p.t = width;
return p;
}
void GridAtlasPacker::setInnerUnitPadding(const Padding &padding) {
innerUnitPadding = padding;
}
void GridAtlasPacker::setInnerUnitPadding(double uniformPadding) {
innerUnitPadding = makeUniformPadding(uniformPadding);
}
void GridAtlasPacker::setOuterUnitPadding(const Padding &padding) {
outerUnitPadding = padding;
}
void GridAtlasPacker::setOuterUnitPadding(double uniformPadding) {
outerUnitPadding = makeUniformPadding(uniformPadding);
}
void GridAtlasPacker::setInnerPixelPadding(const Padding &padding) {
innerPxPadding = padding;
}
void GridAtlasPacker::setInnerPixelPadding(double uniformPadding) {
innerPxPadding = makeUniformPadding(uniformPadding);
}
void GridAtlasPacker::setOuterPixelPadding(const Padding &padding) {
outerPxPadding = padding;
}
void GridAtlasPacker::setOuterPixelPadding(double uniformPadding) {
outerPxPadding = makeUniformPadding(uniformPadding);
}
void GridAtlasPacker::getDimensions(int &width, int &height) const {
width = this->width, height = this->height;
}

View File

@ -1,6 +1,7 @@
#pragma once
#include "Padding.h"
#include "GlyphGeometry.h"
namespace msdf_atlas {
@ -50,16 +51,12 @@ public:
void setOriginPixelAlignment(bool alignX, bool alignY);
/// Sets the unit component of width of additional padding that is part of each glyph quad
void setInnerUnitPadding(const Padding &padding);
void setInnerUnitPadding(double uniformPadding);
/// Sets the unit component of width of additional padding around each glyph quad
void setOuterUnitPadding(const Padding &padding);
void setOuterUnitPadding(double uniformPadding);
/// Sets the pixel component of width of additional padding that is part of each glyph quad
void setInnerPixelPadding(const Padding &padding);
void setInnerPixelPadding(double uniformPadding);
/// Sets the pixel component of width of additional padding around each glyph quad
void setOuterPixelPadding(const Padding &padding);
void setOuterPixelPadding(double uniformPadding);
/// Outputs the atlas's final dimensions
void getDimensions(int &width, int &height) const;

View File

@ -0,0 +1,37 @@
#include "Padding.h"
namespace msdf_atlas {
void pad(msdfgen::Shape::Bounds &bounds, const Padding &padding) {
bounds.l -= padding.l;
bounds.b -= padding.b;
bounds.r += padding.r;
bounds.t += padding.t;
}
Padding operator-(const Padding &padding) {
return Padding(-padding.l, -padding.b, -padding.r, -padding.t);
}
Padding operator+(const Padding &a, const Padding &b) {
return Padding(a.l+b.l, a.b+b.b, a.r+b.r, a.t+b.t);
}
Padding operator-(const Padding &a, const Padding &b) {
return Padding(a.l-b.l, a.b-b.b, a.r-b.r, a.t-b.t);
}
Padding operator*(double factor, const Padding &padding) {
return Padding(factor*padding.l, factor*padding.b, factor*padding.r, factor*padding.t);
}
Padding operator*(const Padding &padding, double factor) {
return Padding(padding.l*factor, padding.b*factor, padding.r*factor, padding.t*factor);
}
Padding operator/(const Padding &padding, double divisor) {
return Padding(padding.l/divisor, padding.b/divisor, padding.r/divisor, padding.t/divisor);
}
}

24
msdf-atlas-gen/Padding.h Normal file
View File

@ -0,0 +1,24 @@
#pragma once
#include <msdfgen.h>
namespace msdf_atlas {
struct Padding {
double l, b, r, t;
inline Padding(double uniformPadding = 0) : l(uniformPadding), b(uniformPadding), r(uniformPadding), t(uniformPadding) { }
inline Padding(double l, double b, double r, double t) : l(l), b(b), r(r), t(t) { }
};
void pad(msdfgen::Shape::Bounds &bounds, const Padding &padding);
Padding operator-(const Padding &padding);
Padding operator+(const Padding &a, const Padding &b);
Padding operator-(const Padding &a, const Padding &b);
Padding operator*(double factor, const Padding &padding);
Padding operator*(const Padding &padding, double factor);
Padding operator/(const Padding &padding, double divisor);
}

View File

@ -18,8 +18,6 @@ TightAtlasPacker::TightAtlasPacker() :
pxRange(0),
miterLimit(0),
pxAlignOriginX(false), pxAlignOriginY(false),
innerUnitPadding(), outerUnitPadding(),
innerPxPadding(), outerPxPadding(),
scaleMaximizationTolerance(.001)
{ }
@ -32,8 +30,8 @@ int TightAtlasPacker::tryPack(GlyphGeometry *glyphs, int count, DimensionsConstr
GlyphGeometry::GlyphAttributes attribs = { };
attribs.scale = scale;
attribs.range = unitRange+pxRange/scale;
attribs.innerPadding = innerUnitPadding+1/scale*innerPxPadding;
attribs.outerPadding = outerUnitPadding+1/scale*outerPxPadding;
attribs.innerPadding = innerUnitPadding+innerPxPadding/scale;
attribs.outerPadding = outerUnitPadding+outerPxPadding/scale;
attribs.miterLimit = miterLimit;
attribs.pxAlignOriginX = pxAlignOriginX;
attribs.pxAlignOriginY = pxAlignOriginY;
@ -172,44 +170,22 @@ void TightAtlasPacker::setOriginPixelAlignment(bool alignX, bool alignY) {
pxAlignOriginX = alignX, pxAlignOriginY = alignY;
}
static Padding makeUniformPadding(double width) {
Padding p;
p.l = width, p.b = width, p.r = width, p.t = width;
return p;
}
void TightAtlasPacker::setInnerUnitPadding(const Padding &padding) {
innerUnitPadding = padding;
}
void TightAtlasPacker::setInnerUnitPadding(double uniformPadding) {
innerUnitPadding = makeUniformPadding(uniformPadding);
}
void TightAtlasPacker::setOuterUnitPadding(const Padding &padding) {
outerUnitPadding = padding;
}
void TightAtlasPacker::setOuterUnitPadding(double uniformPadding) {
outerUnitPadding = makeUniformPadding(uniformPadding);
}
void TightAtlasPacker::setInnerPixelPadding(const Padding &padding) {
innerPxPadding = padding;
}
void TightAtlasPacker::setInnerPixelPadding(double uniformPadding) {
innerPxPadding = makeUniformPadding(uniformPadding);
}
void TightAtlasPacker::setOuterPixelPadding(const Padding &padding) {
outerPxPadding = padding;
}
void TightAtlasPacker::setOuterPixelPadding(double uniformPadding) {
outerPxPadding = makeUniformPadding(uniformPadding);
}
void TightAtlasPacker::getDimensions(int &width, int &height) const {
width = this->width, height = this->height;
}

View File

@ -2,6 +2,7 @@
#pragma once
#include "types.h"
#include "Padding.h"
#include "GlyphGeometry.h"
namespace msdf_atlas {
@ -41,16 +42,12 @@ public:
void setOriginPixelAlignment(bool alignX, bool alignY);
/// Sets the unit component of width of additional padding that is part of each glyph quad
void setInnerUnitPadding(const Padding &padding);
void setInnerUnitPadding(double uniformPadding);
/// Sets the unit component of width of additional padding around each glyph quad
void setOuterUnitPadding(const Padding &padding);
void setOuterUnitPadding(double uniformPadding);
/// Sets the pixel component of width of additional padding that is part of each glyph quad
void setInnerPixelPadding(const Padding &padding);
void setInnerPixelPadding(double uniformPadding);
/// Sets the pixel component of width of additional padding around each glyph quad
void setOuterPixelPadding(const Padding &padding);
void setOuterPixelPadding(double uniformPadding);
/// Outputs the atlas's final dimensions
void getDimensions(int &width, int &height) const;

View File

@ -69,8 +69,10 @@ bool exportArteryFont(const FontGeometry *fonts, int fontCount, const msdfgen::B
fontVariant.codepointType = convertCodepointType(identifierType);
fontVariant.imageType = convertImageType(properties.imageType);
fontVariant.metrics.fontSize = REAL(properties.fontSize*fontMetrics.emSize);
if (properties.imageType != ImageType::HARD_MASK)
if (properties.imageType != ImageType::HARD_MASK) {
fontVariant.metrics.distanceRange = REAL(properties.pxRange.upper-properties.pxRange.lower);
fontVariant.metrics.distanceRangeMiddle = REAL(.5*(properties.pxRange.lower+properties.pxRange.upper));
}
fontVariant.metrics.emSize = REAL(fontMetrics.emSize);
fontVariant.metrics.ascender = REAL(fontMetrics.ascenderY);
fontVariant.metrics.descender = REAL(fontMetrics.descenderY);

View File

@ -69,7 +69,7 @@ bool exportJSON(const FontGeometry *fonts, int fontCount, ImageType imageType, c
fprintf(f, "\"type\":\"%s\",", imageTypeString(imageType));
if (imageType == ImageType::SDF || imageType == ImageType::PSDF || imageType == ImageType::MSDF || imageType == ImageType::MTSDF) {
fprintf(f, "\"distanceRange\":%.17g,", metrics.distanceRange.upper-metrics.distanceRange.lower);
fprintf(f, "\"zeroDistanceValue\":%.17g,", -metrics.distanceRange.lower/(metrics.distanceRange.upper-metrics.distanceRange.lower));
fprintf(f, "\"distanceRangeMiddle\":%.17g,", .5*(metrics.distanceRange.lower+metrics.distanceRange.upper));
}
fprintf(f, "\"size\":%.17g,", metrics.size);
fprintf(f, "\"width\":%d,", metrics.width);

View File

@ -253,12 +253,6 @@ static bool strStartsWith(const char *str, const char *prefix) {
return true;
}
static Padding makeUniformPadding(double width) {
Padding p;
p.l = width, p.b = width, p.r = width, p.t = width;
return p;
}
#ifndef MSDFGEN_DISABLE_VARIABLE_FONTS
static msdfgen::FontHandle *loadVarFont(msdfgen::FreetypeHandle *library, const char *filename) {
std::string buffer;
@ -399,8 +393,8 @@ int main(int argc, const char *const *argv) {
double minEmSize = 0;
Units rangeUnits = Units::PIXELS;
msdfgen::Range rangeValue = 0;
Padding innerPadding = { };
Padding outerPadding = { };
Padding innerPadding;
Padding outerPadding;
Units innerPaddingUnits = Units::EMS;
Units outerPaddingUnits = Units::EMS;
PackingStyle packingStyle = PackingStyle::TIGHT;
@ -656,7 +650,7 @@ int main(int argc, const char *const *argv) {
if (!parseDouble(p, argv[argPos++]))
ABORT("Invalid padding argument. Use -empadding <padding> with a real number.");
innerPaddingUnits = Units::EMS;
innerPadding = makeUniformPadding(p);
innerPadding = Padding(p);
continue;
}
ARG_CASE("-pxpadding", 1) {
@ -664,7 +658,7 @@ int main(int argc, const char *const *argv) {
if (!parseDouble(p, argv[argPos++]))
ABORT("Invalid padding argument. Use -pxpadding <padding> with a real number.");
innerPaddingUnits = Units::PIXELS;
innerPadding = makeUniformPadding(p);
innerPadding = Padding(p);
continue;
}
ARG_CASE("-outerempadding", 1) {
@ -672,7 +666,7 @@ int main(int argc, const char *const *argv) {
if (!parseDouble(p, argv[argPos++]))
ABORT("Invalid padding argument. Use -outerempadding <padding> with a real number.");
outerPaddingUnits = Units::EMS;
outerPadding = makeUniformPadding(p);
outerPadding = Padding(p);
continue;
}
ARG_CASE("-outerpxpadding", 1) {
@ -680,7 +674,7 @@ int main(int argc, const char *const *argv) {
if (!parseDouble(p, argv[argPos++]))
ABORT("Invalid padding argument. Use -outerpxpadding <padding> with a real number.");
outerPaddingUnits = Units::PIXELS;
outerPadding = makeUniformPadding(p);
outerPadding = Padding(p);
continue;
}
ARG_CASE("-aempadding", 4) {
@ -1171,8 +1165,8 @@ int main(int argc, const char *const *argv) {
pxRange = rangeValue;
break;
}
Padding innerEmPadding = { }, outerEmPadding = { };
Padding innerPxPadding = { }, outerPxPadding = { };
Padding innerEmPadding, outerEmPadding;
Padding innerPxPadding, outerPxPadding;
switch (innerPaddingUnits) {
case Units::EMS:
innerEmPadding = innerPadding;

View File

@ -14,6 +14,7 @@
#include "types.h"
#include "utf8.h"
#include "Rectangle.h"
#include "Padding.h"
#include "Charset.h"
#include "GlyphBox.h"
#include "GlyphGeometry.h"

@ -1 +1 @@
Subproject commit c7a724c17366db009a43514b90329519d792b51b
Subproject commit 5dc5f6260b85064c7972808daa8f544d76a73c17