Glyph wrap keeps integer origin

This commit is contained in:
Chlumsky 2023-09-09 23:51:42 +02:00
parent f1ad23f7c4
commit 3e73a31618
4 changed files with 49 additions and 20 deletions

View File

@ -52,6 +52,31 @@ void GlyphGeometry::edgeColoring(void (*fn)(msdfgen::Shape &, double, unsigned l
} }
void GlyphGeometry::wrapBox(double scale, double range, double miterLimit) { void GlyphGeometry::wrapBox(double scale, double range, double miterLimit) {
scale *= geometryScale;
range /= geometryScale;
box.range = range;
box.scale = scale;
if (bounds.l < bounds.r && bounds.b < bounds.t) {
double l = bounds.l, b = bounds.b, r = bounds.r, t = bounds.t;
l -= .5*range, b -= .5*range;
r += .5*range, t += .5*range;
if (miterLimit > 0)
shape.boundMiters(l, b, r, t, .5*range, miterLimit, 1);
int sl = (int) floor(scale*l-.5);
int sb = (int) floor(scale*b-.5);
int sr = (int) ceil(scale*r+.5);
int st = (int) ceil(scale*t+.5);
box.rect.w = sr-sl;
box.rect.h = st-sb;
box.translate.x = -sl/scale;
box.translate.y = -sb/scale;
} else {
box.rect.w = 0, box.rect.h = 0;
box.translate = msdfgen::Vector2();
}
}
void GlyphGeometry::wrapBoxUnaligned(double scale, double range, double miterLimit) {
scale *= geometryScale; scale *= geometryScale;
range /= geometryScale; range /= geometryScale;
box.range = range; box.range = range;

View File

@ -21,6 +21,8 @@ public:
void edgeColoring(void (*fn)(msdfgen::Shape &, double, unsigned long long), double angleThreshold, unsigned long long seed); void edgeColoring(void (*fn)(msdfgen::Shape &, double, unsigned long long), double angleThreshold, unsigned long long seed);
/// Computes the dimensions of the glyph's box as well as the transformation for the generator function /// Computes the dimensions of the glyph's box as well as the transformation for the generator function
void wrapBox(double scale, double range, double miterLimit); void wrapBox(double scale, double range, double miterLimit);
/// Computes the dimensions of the glyph's box and the transformation for the generator function, allowing origin to be located at a non-integer coordinate
void wrapBoxUnaligned(double scale, double range, double miterLimit);
/// Sets the glyph's box's position in the atlas /// Sets the glyph's box's position in the atlas
void placeBox(int x, int y); void placeBox(int x, int y);
/// Sets the glyph's box's rectangle in the atlas /// Sets the glyph's box's rectangle in the atlas

View File

@ -8,7 +8,20 @@
namespace msdf_atlas { namespace msdf_atlas {
int TightAtlasPacker::tryPack(GlyphGeometry *glyphs, int count, DimensionsConstraint dimensionsConstraint, int &width, int &height, int padding, double scale, double range, double miterLimit) { TightAtlasPacker::TightAtlasPacker() :
width(-1), height(-1),
padding(0),
dimensionsConstraint(DimensionsConstraint::POWER_OF_TWO_SQUARE),
scale(-1),
minScale(1),
unitRange(0),
pxRange(0),
miterLimit(0),
scaleMaximizationTolerance(.001)
{ }
int TightAtlasPacker::tryPack(GlyphGeometry *glyphs, int count, DimensionsConstraint dimensionsConstraint, int &width, int &height, double scale) const {
double range = unitRange+pxRange/scale;
// Wrap glyphs into boxes // Wrap glyphs into boxes
std::vector<Rectangle> rectangles; std::vector<Rectangle> rectangles;
std::vector<GlyphGeometry *> rectangleGlyphs; std::vector<GlyphGeometry *> rectangleGlyphs;
@ -64,9 +77,10 @@ int TightAtlasPacker::tryPack(GlyphGeometry *glyphs, int count, DimensionsConstr
return 0; return 0;
} }
double TightAtlasPacker::packAndScale(GlyphGeometry *glyphs, int count, int width, int height, int padding, double unitRange, double pxRange, double miterLimit, double tolerance) { double TightAtlasPacker::packAndScale(GlyphGeometry *glyphs, int count) const {
bool lastResult = false; bool lastResult = false;
#define TRY_PACK(scale) (lastResult = !tryPack(glyphs, count, DimensionsConstraint(), width, height, padding, (scale), unitRange+pxRange/(scale), miterLimit)) int w = width, h = height;
#define TRY_PACK(scale) (lastResult = !tryPack(glyphs, count, DimensionsConstraint(), w, h, (scale)))
double minScale = 1, maxScale = 1; double minScale = 1, maxScale = 1;
if (TRY_PACK(1)) { if (TRY_PACK(1)) {
while (maxScale < 1e+32 && ((maxScale = 2*minScale), TRY_PACK(maxScale))) while (maxScale < 1e+32 && ((maxScale = 2*minScale), TRY_PACK(maxScale)))
@ -77,7 +91,7 @@ double TightAtlasPacker::packAndScale(GlyphGeometry *glyphs, int count, int widt
} }
if (minScale == maxScale) if (minScale == maxScale)
return 0; return 0;
while (minScale/maxScale < 1-tolerance) { while (minScale/maxScale < 1-scaleMaximizationTolerance) {
double midScale = .5*(minScale+maxScale); double midScale = .5*(minScale+maxScale);
if (TRY_PACK(midScale)) if (TRY_PACK(midScale))
minScale = midScale; minScale = midScale;
@ -89,27 +103,15 @@ double TightAtlasPacker::packAndScale(GlyphGeometry *glyphs, int count, int widt
return minScale; return minScale;
} }
TightAtlasPacker::TightAtlasPacker() :
width(-1), height(-1),
padding(0),
dimensionsConstraint(DimensionsConstraint::POWER_OF_TWO_SQUARE),
scale(-1),
minScale(1),
unitRange(0),
pxRange(0),
miterLimit(0),
scaleMaximizationTolerance(.001)
{ }
int TightAtlasPacker::pack(GlyphGeometry *glyphs, int count) { int TightAtlasPacker::pack(GlyphGeometry *glyphs, int count) {
double initialScale = scale > 0 ? scale : minScale; double initialScale = scale > 0 ? scale : minScale;
if (initialScale > 0) { if (initialScale > 0) {
if (int remaining = tryPack(glyphs, count, dimensionsConstraint, width, height, padding, initialScale, unitRange+pxRange/initialScale, miterLimit)) if (int remaining = tryPack(glyphs, count, dimensionsConstraint, width, height, initialScale))
return remaining; return remaining;
} else if (width < 0 || height < 0) } else if (width < 0 || height < 0)
return -1; return -1;
if (scale <= 0) if (scale <= 0)
scale = packAndScale(glyphs, count, width, height, padding, unitRange, pxRange, miterLimit, scaleMaximizationTolerance); scale = packAndScale(glyphs, count);
if (scale <= 0) if (scale <= 0)
return -1; return -1;
pxRange += scale*unitRange; pxRange += scale*unitRange;

View File

@ -63,8 +63,8 @@ private:
double miterLimit; double miterLimit;
double scaleMaximizationTolerance; double scaleMaximizationTolerance;
static int tryPack(GlyphGeometry *glyphs, int count, DimensionsConstraint dimensionsConstraint, int &width, int &height, int padding, double scale, double range, double miterLimit); int tryPack(GlyphGeometry *glyphs, int count, DimensionsConstraint dimensionsConstraint, int &width, int &height, double scale) const;
static double packAndScale(GlyphGeometry *glyphs, int count, int width, int height, int padding, double unitRange, double pxRange, double miterLimit, double tolerance); double packAndScale(GlyphGeometry *glyphs, int count) const;
}; };