Compare commits
3 Commits
37d185878d
...
bed35b13b0
| Author | SHA1 | Date |
|---|---|---|
|
|
bed35b13b0 | |
|
|
3a4f181674 | |
|
|
b716311880 |
|
|
@ -32,12 +32,12 @@ public:
|
|||
/// Adds a batch of glyphs. Adding more than one glyph at a time may improve packing efficiency
|
||||
ChangeFlags add(GlyphGeometry *glyphs, int count, bool allowRearrange = false);
|
||||
/// Allows access to generator. Do not add glyphs to the generator directly!
|
||||
AtlasGenerator & atlasGenerator();
|
||||
const AtlasGenerator & atlasGenerator() const;
|
||||
AtlasGenerator &atlasGenerator();
|
||||
const AtlasGenerator &atlasGenerator() const;
|
||||
|
||||
private:
|
||||
int side;
|
||||
int padding;
|
||||
int spacing;
|
||||
int glyphCount;
|
||||
int totalArea;
|
||||
RectanglePacker packer;
|
||||
|
|
|
|||
|
|
@ -14,14 +14,14 @@ static int ceilPOT(int x) {
|
|||
}
|
||||
|
||||
template <class AtlasGenerator>
|
||||
DynamicAtlas<AtlasGenerator>::DynamicAtlas() : side(0), padding(0), glyphCount(0), totalArea(0) { }
|
||||
DynamicAtlas<AtlasGenerator>::DynamicAtlas() : side(0), spacing(0), glyphCount(0), totalArea(0) { }
|
||||
|
||||
template <class AtlasGenerator>
|
||||
template <typename... ARGS>
|
||||
DynamicAtlas<AtlasGenerator>::DynamicAtlas(int minSide, ARGS... args) : side(ceilPOT(minSide)), padding(0), glyphCount(0), totalArea(0), packer(side+padding, side+padding), generator(side, side, args...) { }
|
||||
DynamicAtlas<AtlasGenerator>::DynamicAtlas(int minSide, ARGS... args) : side(ceilPOT(minSide)), spacing(0), glyphCount(0), totalArea(0), packer(side+spacing, side+spacing), generator(side, side, args...) { }
|
||||
|
||||
template <class AtlasGenerator>
|
||||
DynamicAtlas<AtlasGenerator>::DynamicAtlas(AtlasGenerator &&generator) : side(0), padding(0), glyphCount(0), totalArea(0), generator((AtlasGenerator &&) generator) { }
|
||||
DynamicAtlas<AtlasGenerator>::DynamicAtlas(AtlasGenerator &&generator) : side(0), spacing(0), glyphCount(0), totalArea(0), generator((AtlasGenerator &&) generator) { }
|
||||
|
||||
template <class AtlasGenerator>
|
||||
typename DynamicAtlas<AtlasGenerator>::ChangeFlags DynamicAtlas<AtlasGenerator>::add(GlyphGeometry *glyphs, int count, bool allowRearrange) {
|
||||
|
|
@ -31,14 +31,14 @@ typename DynamicAtlas<AtlasGenerator>::ChangeFlags DynamicAtlas<AtlasGenerator>:
|
|||
if (!glyphs[i].isWhitespace()) {
|
||||
int w, h;
|
||||
glyphs[i].getBoxSize(w, h);
|
||||
Rectangle rect = { 0, 0, w+padding, h+padding };
|
||||
Rectangle rect = { 0, 0, w+spacing, h+spacing };
|
||||
rectangles.push_back(rect);
|
||||
Remap remapEntry = { };
|
||||
remapEntry.index = glyphCount+i;
|
||||
remapEntry.width = w;
|
||||
remapEntry.height = h;
|
||||
remapBuffer.push_back(remapEntry);
|
||||
totalArea += (w+padding)*(h+padding);
|
||||
totalArea += (w+spacing)*(h+spacing);
|
||||
}
|
||||
}
|
||||
if ((int) rectangles.size() > start) {
|
||||
|
|
@ -49,10 +49,10 @@ typename DynamicAtlas<AtlasGenerator>::ChangeFlags DynamicAtlas<AtlasGenerator>:
|
|||
while (side*side < totalArea)
|
||||
side <<= 1;
|
||||
if (allowRearrange) {
|
||||
packer = RectanglePacker(side+padding, side+padding);
|
||||
packer = RectanglePacker(side+spacing, side+spacing);
|
||||
packerStart = 0;
|
||||
} else {
|
||||
packer.expand(side+padding, side+padding);
|
||||
packer.expand(side+spacing, side+spacing);
|
||||
packerStart = rectangles.size()-remaining;
|
||||
}
|
||||
changeFlags |= RESIZED;
|
||||
|
|
@ -80,12 +80,12 @@ typename DynamicAtlas<AtlasGenerator>::ChangeFlags DynamicAtlas<AtlasGenerator>:
|
|||
}
|
||||
|
||||
template <class AtlasGenerator>
|
||||
AtlasGenerator & DynamicAtlas<AtlasGenerator>::atlasGenerator() {
|
||||
AtlasGenerator &DynamicAtlas<AtlasGenerator>::atlasGenerator() {
|
||||
return generator;
|
||||
}
|
||||
|
||||
template <class AtlasGenerator>
|
||||
const AtlasGenerator & DynamicAtlas<AtlasGenerator>::atlasGenerator() const {
|
||||
const AtlasGenerator &DynamicAtlas<AtlasGenerator>::atlasGenerator() const {
|
||||
return generator;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,11 +15,11 @@ bool FontGeometry::GlyphRange::empty() const {
|
|||
return glyphs->empty();
|
||||
}
|
||||
|
||||
const GlyphGeometry * FontGeometry::GlyphRange::begin() const {
|
||||
const GlyphGeometry *FontGeometry::GlyphRange::begin() const {
|
||||
return glyphs->data()+rangeStart;
|
||||
}
|
||||
|
||||
const GlyphGeometry * FontGeometry::GlyphRange::end() const {
|
||||
const GlyphGeometry *FontGeometry::GlyphRange::end() const {
|
||||
return glyphs->data()+rangeEnd;
|
||||
}
|
||||
|
||||
|
|
@ -142,7 +142,7 @@ double FontGeometry::getGeometryScale() const {
|
|||
return geometryScale;
|
||||
}
|
||||
|
||||
const msdfgen::FontMetrics & FontGeometry::getMetrics() const {
|
||||
const msdfgen::FontMetrics &FontGeometry::getMetrics() const {
|
||||
return metrics;
|
||||
}
|
||||
|
||||
|
|
@ -154,14 +154,14 @@ FontGeometry::GlyphRange FontGeometry::getGlyphs() const {
|
|||
return GlyphRange(glyphs, rangeStart, rangeEnd);
|
||||
}
|
||||
|
||||
const GlyphGeometry * FontGeometry::getGlyph(msdfgen::GlyphIndex index) const {
|
||||
const GlyphGeometry *FontGeometry::getGlyph(msdfgen::GlyphIndex index) const {
|
||||
std::map<int, size_t>::const_iterator it = glyphsByIndex.find(index.getIndex());
|
||||
if (it != glyphsByIndex.end())
|
||||
return &(*glyphs)[it->second];
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const GlyphGeometry * FontGeometry::getGlyph(unicode_t codepoint) const {
|
||||
const GlyphGeometry *FontGeometry::getGlyph(unicode_t codepoint) const {
|
||||
std::map<unicode_t, size_t>::const_iterator it = glyphsByCodepoint.find(codepoint);
|
||||
if (it != glyphsByCodepoint.end())
|
||||
return &(*glyphs)[it->second];
|
||||
|
|
@ -190,11 +190,11 @@ bool FontGeometry::getAdvance(double &advance, unicode_t codepoint1, unicode_t c
|
|||
return true;
|
||||
}
|
||||
|
||||
const std::map<std::pair<int, int>, double> & FontGeometry::getKerning() const {
|
||||
const std::map<std::pair<int, int>, double> &FontGeometry::getKerning() const {
|
||||
return kerning;
|
||||
}
|
||||
|
||||
const char * FontGeometry::getName() const {
|
||||
const char *FontGeometry::getName() const {
|
||||
if (name.empty())
|
||||
return nullptr;
|
||||
return name.c_str();
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ public:
|
|||
GlyphRange(const std::vector<GlyphGeometry> *glyphs, size_t rangeStart, size_t rangeEnd);
|
||||
size_t size() const;
|
||||
bool empty() const;
|
||||
const GlyphGeometry * begin() const;
|
||||
const GlyphGeometry * end() const;
|
||||
const GlyphGeometry *begin() const;
|
||||
const GlyphGeometry *end() const;
|
||||
private:
|
||||
const std::vector<GlyphGeometry> *glyphs;
|
||||
size_t rangeStart, rangeEnd;
|
||||
|
|
@ -55,21 +55,21 @@ public:
|
|||
/// Returns the geometry scale to be used when loading glyphs
|
||||
double getGeometryScale() const;
|
||||
/// Returns the processed font metrics
|
||||
const msdfgen::FontMetrics & getMetrics() const;
|
||||
const msdfgen::FontMetrics &getMetrics() const;
|
||||
/// Returns the type of identifier that was used to load glyphs
|
||||
GlyphIdentifierType getPreferredIdentifierType() const;
|
||||
/// Returns the list of all glyphs
|
||||
GlyphRange getGlyphs() const;
|
||||
/// Finds a glyph by glyph index or Unicode codepoint, returns null if not found
|
||||
const GlyphGeometry * getGlyph(msdfgen::GlyphIndex index) const;
|
||||
const GlyphGeometry * getGlyph(unicode_t codepoint) const;
|
||||
const GlyphGeometry *getGlyph(msdfgen::GlyphIndex index) const;
|
||||
const GlyphGeometry *getGlyph(unicode_t codepoint) const;
|
||||
/// Outputs the advance between two glyphs with kerning taken into consideration, returns false on failure
|
||||
bool getAdvance(double &advance, msdfgen::GlyphIndex index1, msdfgen::GlyphIndex index2) const;
|
||||
bool getAdvance(double &advance, unicode_t codepoint1, unicode_t codepoint2) const;
|
||||
/// Returns the complete mapping of kerning pairs (by glyph indices) and their respective advance values
|
||||
const std::map<std::pair<int, int>, double> & getKerning() const;
|
||||
const std::map<std::pair<int, int>, double> &getKerning() const;
|
||||
/// Returns the name associated with the font or null if not set
|
||||
const char * getName() const;
|
||||
const char *getName() const;
|
||||
|
||||
private:
|
||||
double geometryScale;
|
||||
|
|
|
|||
|
|
@ -169,11 +169,11 @@ double GlyphGeometry::getGeometryScale() const {
|
|||
return geometryScale;
|
||||
}
|
||||
|
||||
const msdfgen::Shape & GlyphGeometry::getShape() const {
|
||||
const msdfgen::Shape &GlyphGeometry::getShape() const {
|
||||
return shape;
|
||||
}
|
||||
|
||||
const msdfgen::Shape::Bounds & GlyphGeometry::getShapeBounds() const {
|
||||
const msdfgen::Shape::Bounds &GlyphGeometry::getShapeBounds() const {
|
||||
return bounds;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,9 +40,9 @@ public:
|
|||
/// Returns the glyph's geometry scale
|
||||
double getGeometryScale() const;
|
||||
/// Returns the glyph's shape
|
||||
const msdfgen::Shape & getShape() const;
|
||||
const msdfgen::Shape &getShape() const;
|
||||
/// Returns the glyph's shape's raw bounds
|
||||
const msdfgen::Shape::Bounds & getShapeBounds() const;
|
||||
const msdfgen::Shape::Bounds &getShapeBounds() const;
|
||||
/// Returns the glyph's advance
|
||||
double getAdvance() const;
|
||||
/// Returns the glyph's box in the atlas
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ GridAtlasPacker::GridAtlasPacker() :
|
|||
columns(-1), rows(-1),
|
||||
width(-1), height(-1),
|
||||
cellWidth(-1), cellHeight(-1),
|
||||
padding(0),
|
||||
spacing(0),
|
||||
dimensionsConstraint(DimensionsConstraint::NONE),
|
||||
cellDimensionsConstraint(DimensionsConstraint::NONE),
|
||||
hFixed(false), vFixed(false),
|
||||
|
|
@ -152,7 +152,7 @@ double GridAtlasPacker::scaleToFit(GlyphGeometry *glyphs, int count, int cellWid
|
|||
if (cellHeight <= 0)
|
||||
cellHeight = BIG_VALUE;
|
||||
--cellWidth, --cellHeight; // Implicit half-pixel padding from each side to make sure that no representable values are beyond outermost pixel centers
|
||||
cellWidth -= padding, cellHeight -= padding;
|
||||
cellWidth -= spacing, cellHeight -= spacing;
|
||||
bool lastResult = false;
|
||||
#define TRY_FIT(scale) (maxWidth = 0, maxHeight = 0, maxBounds = getMaxBounds(maxWidth, maxHeight, glyphs, count, (scale), unitRange+pxRange/(scale)), lastResult = maxWidth <= cellWidth && maxHeight <= cellHeight)
|
||||
double minScale = 1, maxScale = 1;
|
||||
|
|
@ -197,7 +197,7 @@ int GridAtlasPacker::pack(GlyphGeometry *glyphs, int count) {
|
|||
else if (rows > 0)
|
||||
columns = (cellCount+rows-1)/rows;
|
||||
else if (width > 0 && cellWidth > 0) {
|
||||
columns = (width+padding)/cellWidth;
|
||||
columns = (width+spacing)/cellWidth;
|
||||
rows = (cellCount+columns-1)/columns;
|
||||
}
|
||||
}
|
||||
|
|
@ -210,9 +210,9 @@ int GridAtlasPacker::pack(GlyphGeometry *glyphs, int count) {
|
|||
raiseToConstraint(width, height, dimensionsConstraint);
|
||||
|
||||
if (cellWidth < 0 && width > 0 && columns > 0)
|
||||
cellWidth = (width+padding)/columns;
|
||||
cellWidth = (width+spacing)/columns;
|
||||
if (cellHeight < 0 && height > 0 && rows > 0)
|
||||
cellHeight = (height+padding)/rows;
|
||||
cellHeight = (height+spacing)/rows;
|
||||
if (cellWidth != initial.cellWidth || cellHeight != initial.cellHeight) {
|
||||
bool positiveCellWidth = cellWidth > 0, positiveCellHeight = cellHeight > 0;
|
||||
lowerToConstraint(cellWidth, cellHeight, cellDimensionsConstraint);
|
||||
|
|
@ -220,7 +220,7 @@ int GridAtlasPacker::pack(GlyphGeometry *glyphs, int count) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
if ((cellWidth > 0 && cellWidth-padding-1 <= pxRange) || (cellHeight > 0 && cellHeight-padding-1 <= pxRange)) // cells definitely too small
|
||||
if ((cellWidth > 0 && cellWidth-spacing-1 <= pxRange) || (cellHeight > 0 && cellHeight-spacing-1 <= pxRange)) // cells definitely too small
|
||||
return -1;
|
||||
|
||||
msdfgen::Shape::Bounds maxBounds = { };
|
||||
|
|
@ -246,8 +246,8 @@ int GridAtlasPacker::pack(GlyphGeometry *glyphs, int count) {
|
|||
for (int q = (int) sqrt(cellCount)+1; q > 0; --q) {
|
||||
int cols = q;
|
||||
int rows = (cellCount+cols-1)/cols;
|
||||
int tWidth = (width+padding)/cols;
|
||||
int tHeight = (height+padding)/rows;
|
||||
int tWidth = (width+spacing)/cols;
|
||||
int tHeight = (height+spacing)/rows;
|
||||
lowerToConstraint(tWidth, tHeight, cellDimensionsConstraint);
|
||||
if (tWidth > 0 && tHeight > 0) {
|
||||
double curScale = scaleToFit(glyphs, count, tWidth, tHeight, maxBounds, maxWidth, maxHeight);
|
||||
|
|
@ -262,8 +262,8 @@ int GridAtlasPacker::pack(GlyphGeometry *glyphs, int count) {
|
|||
}
|
||||
cols = (cellCount+q-1)/q;
|
||||
rows = (cellCount+cols-1)/cols;
|
||||
tWidth = (width+padding)/cols;
|
||||
tHeight = (height+padding)/rows;
|
||||
tWidth = (width+spacing)/cols;
|
||||
tHeight = (height+spacing)/rows;
|
||||
lowerToConstraint(tWidth, tHeight, cellDimensionsConstraint);
|
||||
if (tWidth > 0 && tHeight > 0) {
|
||||
double curScale = scaleToFit(glyphs, count, tWidth, tHeight, maxBounds, maxWidth, maxHeight);
|
||||
|
|
@ -287,8 +287,8 @@ int GridAtlasPacker::pack(GlyphGeometry *glyphs, int count) {
|
|||
|
||||
columns = bestCols;
|
||||
rows = (cellCount+columns-1)/columns;
|
||||
cellWidth = (width+padding)/columns;
|
||||
cellHeight = (height+padding)/rows;
|
||||
cellWidth = (width+spacing)/columns;
|
||||
cellHeight = (height+spacing)/rows;
|
||||
lowerToConstraint(cellWidth, cellHeight, cellDimensionsConstraint);
|
||||
scale = scaleToFit(glyphs, count, cellWidth, cellHeight, maxBounds, maxWidth, maxHeight);
|
||||
if (scale < minScale)
|
||||
|
|
@ -297,8 +297,8 @@ int GridAtlasPacker::pack(GlyphGeometry *glyphs, int count) {
|
|||
|
||||
if (scale <= 0) {
|
||||
maxBounds = getMaxBounds(maxWidth, maxHeight, glyphs, count, minScale, unitRange+pxRange/minScale);
|
||||
cellWidth = (int) ceil(maxWidth)+padding+1;
|
||||
cellHeight = (int) ceil(maxHeight)+padding+1;
|
||||
cellWidth = (int) ceil(maxWidth)+spacing+1;
|
||||
cellHeight = (int) ceil(maxHeight)+spacing+1;
|
||||
raiseToConstraint(cellWidth, cellHeight, cellDimensionsConstraint);
|
||||
scale = scaleToFit(glyphs, count, cellWidth, cellHeight, maxBounds, maxWidth, maxHeight);
|
||||
if (scale < minScale)
|
||||
|
|
@ -306,7 +306,7 @@ int GridAtlasPacker::pack(GlyphGeometry *glyphs, int count) {
|
|||
}
|
||||
|
||||
if (initial.rows < 0 && initial.cellHeight < 0) {
|
||||
int optimalCellWidth = cellWidth, optimalCellHeight = (int) ceil(maxHeight)+padding+1;
|
||||
int optimalCellWidth = cellWidth, optimalCellHeight = (int) ceil(maxHeight)+spacing+1;
|
||||
raiseToConstraint(optimalCellWidth, optimalCellHeight, cellDimensionsConstraint);
|
||||
if (optimalCellHeight < cellHeight && optimalCellWidth <= cellWidth) {
|
||||
cellWidth = optimalCellWidth;
|
||||
|
|
@ -329,9 +329,9 @@ int GridAtlasPacker::pack(GlyphGeometry *glyphs, int count) {
|
|||
|
||||
double hScale = 0, vScale = 0;
|
||||
if (cellWidth > 0)
|
||||
hScale = (cellWidth-hSlack-padding-1-pxRange)/maxWidth;
|
||||
hScale = (cellWidth-hSlack-spacing-1-pxRange)/maxWidth;
|
||||
if (cellHeight > 0)
|
||||
vScale = (cellHeight-vSlack-padding-1-pxRange)/maxHeight;
|
||||
vScale = (cellHeight-vSlack-spacing-1-pxRange)/maxHeight;
|
||||
if (hScale || vScale) {
|
||||
if (hScale && vScale)
|
||||
scale = std::min(hScale, vScale);
|
||||
|
|
@ -349,12 +349,12 @@ int GridAtlasPacker::pack(GlyphGeometry *glyphs, int count) {
|
|||
// TODO optimize to only test up to sqrt(cellCount) cols and rows like in the above branch (for (int q = (int) sqrt(cellCount)+1; ...)
|
||||
for (int cols = 1; cols < width; ++cols) {
|
||||
int rows = (cellCount+cols-1)/cols;
|
||||
int tWidth = (width+padding)/cols;
|
||||
int tHeight = (height+padding)/rows;
|
||||
int tWidth = (width+spacing)/cols;
|
||||
int tHeight = (height+spacing)/rows;
|
||||
lowerToConstraint(tWidth, tHeight, cellDimensionsConstraint);
|
||||
if (tWidth > 0 && tHeight > 0) {
|
||||
hScale = (tWidth-hSlack-padding-1-pxRange)/maxWidth;
|
||||
vScale = (tHeight-vSlack-padding-1-pxRange)/maxHeight;
|
||||
hScale = (tWidth-hSlack-spacing-1-pxRange)/maxWidth;
|
||||
vScale = (tHeight-vSlack-spacing-1-pxRange)/maxHeight;
|
||||
double curScale = std::min(hScale, vScale);
|
||||
if (curScale > scale) {
|
||||
scale = curScale;
|
||||
|
|
@ -376,24 +376,24 @@ int GridAtlasPacker::pack(GlyphGeometry *glyphs, int count) {
|
|||
|
||||
columns = bestCols;
|
||||
rows = (cellCount+columns-1)/columns;
|
||||
cellWidth = (width+padding)/columns;
|
||||
cellHeight = (height+padding)/rows;
|
||||
cellWidth = (width+spacing)/columns;
|
||||
cellHeight = (height+spacing)/rows;
|
||||
lowerToConstraint(cellWidth, cellHeight, cellDimensionsConstraint);
|
||||
if (scale < minScale)
|
||||
scale = -1;
|
||||
}
|
||||
|
||||
if (scale <= 0) {
|
||||
cellWidth = (int) ceil(minScale*maxWidth+pxRange)+hSlack+padding+1;
|
||||
cellHeight = (int) ceil(minScale*maxHeight+pxRange)+vSlack+padding+1;
|
||||
cellWidth = (int) ceil(minScale*maxWidth+pxRange)+hSlack+spacing+1;
|
||||
cellHeight = (int) ceil(minScale*maxHeight+pxRange)+vSlack+spacing+1;
|
||||
raiseToConstraint(cellWidth, cellHeight, cellDimensionsConstraint);
|
||||
hScale = (cellWidth-hSlack-padding-1-pxRange)/maxWidth;
|
||||
vScale = (cellHeight-vSlack-padding-1-pxRange)/maxHeight;
|
||||
hScale = (cellWidth-hSlack-spacing-1-pxRange)/maxWidth;
|
||||
vScale = (cellHeight-vSlack-spacing-1-pxRange)/maxHeight;
|
||||
scale = std::min(hScale, vScale);
|
||||
}
|
||||
|
||||
if (initial.rows < 0 && initial.cellHeight < 0) {
|
||||
int optimalCellWidth = cellWidth, optimalCellHeight = (int) ceil(scale*maxHeight+pxRange)+vSlack+padding+1;
|
||||
int optimalCellWidth = cellWidth, optimalCellHeight = (int) ceil(scale*maxHeight+pxRange)+vSlack+spacing+1;
|
||||
raiseToConstraint(optimalCellWidth, optimalCellHeight, cellDimensionsConstraint);
|
||||
if (optimalCellHeight < cellHeight && optimalCellWidth <= cellWidth) {
|
||||
cellWidth = optimalCellWidth;
|
||||
|
|
@ -408,8 +408,8 @@ int GridAtlasPacker::pack(GlyphGeometry *glyphs, int count) {
|
|||
|
||||
} else {
|
||||
maxBounds = getMaxBounds(maxWidth, maxHeight, glyphs, count, scale, unitRange+pxRange/scale);
|
||||
int optimalCellWidth = (int) ceil(maxWidth)+padding+1;
|
||||
int optimalCellHeight = (int) ceil(maxHeight)+padding+1;
|
||||
int optimalCellWidth = (int) ceil(maxWidth)+spacing+1;
|
||||
int optimalCellHeight = (int) ceil(maxHeight)+spacing+1;
|
||||
if (cellWidth < 0 || cellHeight < 0) {
|
||||
cellWidth = optimalCellWidth;
|
||||
cellHeight = optimalCellHeight;
|
||||
|
|
@ -423,17 +423,17 @@ int GridAtlasPacker::pack(GlyphGeometry *glyphs, int count) {
|
|||
if (pxAlignOriginX) {
|
||||
int sl = (int) floor(maxBounds.l-.5);
|
||||
int sr = (int) ceil(maxBounds.r+.5);
|
||||
fixedX = (-sl+(cellWidth-padding-(sr-sl))/2)/scale;
|
||||
fixedX = (-sl+(cellWidth-spacing-(sr-sl))/2)/scale;
|
||||
} else
|
||||
fixedX = (-maxBounds.l+.5*(cellWidth-padding-maxWidth))/scale;
|
||||
fixedX = (-maxBounds.l+.5*(cellWidth-spacing-maxWidth))/scale;
|
||||
}
|
||||
if (vFixed) {
|
||||
if (pxAlignOriginY) {
|
||||
int sb = (int) floor(maxBounds.b-.5);
|
||||
int st = (int) ceil(maxBounds.t+.5);
|
||||
fixedY = (-sb+(cellHeight-padding-(st-sb))/2)/scale;
|
||||
fixedY = (-sb+(cellHeight-spacing-(st-sb))/2)/scale;
|
||||
} else
|
||||
fixedY = (-maxBounds.b+.5*(cellHeight-padding-maxHeight))/scale;
|
||||
fixedY = (-maxBounds.b+.5*(cellHeight-spacing-maxHeight))/scale;
|
||||
}
|
||||
|
||||
if (width < 0 || height < 0) {
|
||||
|
|
@ -475,7 +475,7 @@ int GridAtlasPacker::pack(GlyphGeometry *glyphs, int count) {
|
|||
}
|
||||
|
||||
if (columns < 0) {
|
||||
columns = (width+padding)/cellWidth;
|
||||
columns = (width+spacing)/cellWidth;
|
||||
rows = (cellCount+columns-1)/columns;
|
||||
}
|
||||
if (rows*cellHeight > height)
|
||||
|
|
@ -484,7 +484,7 @@ int GridAtlasPacker::pack(GlyphGeometry *glyphs, int count) {
|
|||
int col = 0, row = 0;
|
||||
for (GlyphGeometry *glyph = glyphs, *end = glyphs+count; glyph < end; ++glyph) {
|
||||
if (!glyph->isWhitespace()) {
|
||||
glyph->frameBox(scale, unitRange+pxRange/scale, miterLimit, cellWidth-padding, cellHeight-padding, hFixed ? &fixedX : nullptr, vFixed ? &fixedY : nullptr, pxAlignOriginX, pxAlignOriginY);
|
||||
glyph->frameBox(scale, unitRange+pxRange/scale, miterLimit, cellWidth-spacing, cellHeight-spacing, hFixed ? &fixedX : nullptr, vFixed ? &fixedY : nullptr, pxAlignOriginX, pxAlignOriginY);
|
||||
glyph->placeBox(col*cellWidth, height-(row+1)*cellHeight);
|
||||
if (++col >= columns) {
|
||||
if (++row >= rows) {
|
||||
|
|
@ -542,8 +542,8 @@ void GridAtlasPacker::setDimensionsConstraint(DimensionsConstraint dimensionsCon
|
|||
this->dimensionsConstraint = dimensionsConstraint;
|
||||
}
|
||||
|
||||
void GridAtlasPacker::setPadding(int padding) {
|
||||
this->padding = padding;
|
||||
void GridAtlasPacker::setSpacing(int spacing) {
|
||||
this->spacing = spacing;
|
||||
}
|
||||
|
||||
void GridAtlasPacker::setScale(double scale) {
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ public:
|
|||
void unsetDimensions();
|
||||
/// Sets the constraint to be used when determining dimensions
|
||||
void setDimensionsConstraint(DimensionsConstraint dimensionsConstraint);
|
||||
/// Sets the padding between glyph boxes
|
||||
void setPadding(int padding);
|
||||
/// Sets the spacing between glyph boxes
|
||||
void setSpacing(int spacing);
|
||||
/// Sets fixed glyph scale
|
||||
void setScale(double scale);
|
||||
/// Sets the minimum glyph scale
|
||||
|
|
@ -70,7 +70,7 @@ private:
|
|||
int columns, rows;
|
||||
int width, height;
|
||||
int cellWidth, cellHeight;
|
||||
int padding;
|
||||
int spacing;
|
||||
DimensionsConstraint dimensionsConstraint;
|
||||
DimensionsConstraint cellDimensionsConstraint;
|
||||
bool hFixed, vFixed;
|
||||
|
|
|
|||
|
|
@ -30,9 +30,9 @@ public:
|
|||
/// Sets the number of threads to be run by generate
|
||||
void setThreadCount(int threadCount);
|
||||
/// Allows access to the underlying AtlasStorage
|
||||
const AtlasStorage & atlasStorage() const;
|
||||
const AtlasStorage &atlasStorage() const;
|
||||
/// Returns the layout of the contained glyphs as a list of GlyphBoxes
|
||||
const std::vector<GlyphBox> & getLayout() const;
|
||||
const std::vector<GlyphBox> &getLayout() const;
|
||||
|
||||
private:
|
||||
AtlasStorage storage;
|
||||
|
|
|
|||
|
|
@ -74,12 +74,12 @@ void ImmediateAtlasGenerator<T, N, GEN_FN, AtlasStorage>::setThreadCount(int thr
|
|||
}
|
||||
|
||||
template <typename T, int N, GeneratorFunction<T, N> GEN_FN, class AtlasStorage>
|
||||
const AtlasStorage & ImmediateAtlasGenerator<T, N, GEN_FN, AtlasStorage>::atlasStorage() const {
|
||||
const AtlasStorage &ImmediateAtlasGenerator<T, N, GEN_FN, AtlasStorage>::atlasStorage() const {
|
||||
return storage;
|
||||
}
|
||||
|
||||
template <typename T, int N, GeneratorFunction<T, N> GEN_FN, class AtlasStorage>
|
||||
const std::vector<GlyphBox> & ImmediateAtlasGenerator<T, N, GEN_FN, AtlasStorage>::getLayout() const {
|
||||
const std::vector<GlyphBox> &ImmediateAtlasGenerator<T, N, GEN_FN, AtlasStorage>::getLayout() const {
|
||||
return layout;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ namespace msdf_atlas {
|
|||
|
||||
TightAtlasPacker::TightAtlasPacker() :
|
||||
width(-1), height(-1),
|
||||
padding(0),
|
||||
spacing(0),
|
||||
dimensionsConstraint(DimensionsConstraint::POWER_OF_TWO_SQUARE),
|
||||
scale(-1),
|
||||
minScale(1),
|
||||
|
|
@ -50,27 +50,27 @@ int TightAtlasPacker::tryPack(GlyphGeometry *glyphs, int count, DimensionsConstr
|
|||
std::pair<int, int> dimensions = std::make_pair(width, height);
|
||||
switch (dimensionsConstraint) {
|
||||
case DimensionsConstraint::POWER_OF_TWO_SQUARE:
|
||||
dimensions = packRectangles<SquarePowerOfTwoSizeSelector>(rectangles.data(), rectangles.size(), padding);
|
||||
dimensions = packRectangles<SquarePowerOfTwoSizeSelector>(rectangles.data(), rectangles.size(), spacing);
|
||||
break;
|
||||
case DimensionsConstraint::POWER_OF_TWO_RECTANGLE:
|
||||
dimensions = packRectangles<PowerOfTwoSizeSelector>(rectangles.data(), rectangles.size(), padding);
|
||||
dimensions = packRectangles<PowerOfTwoSizeSelector>(rectangles.data(), rectangles.size(), spacing);
|
||||
break;
|
||||
case DimensionsConstraint::MULTIPLE_OF_FOUR_SQUARE:
|
||||
dimensions = packRectangles<SquareSizeSelector<4> >(rectangles.data(), rectangles.size(), padding);
|
||||
dimensions = packRectangles<SquareSizeSelector<4> >(rectangles.data(), rectangles.size(), spacing);
|
||||
break;
|
||||
case DimensionsConstraint::EVEN_SQUARE:
|
||||
dimensions = packRectangles<SquareSizeSelector<2> >(rectangles.data(), rectangles.size(), padding);
|
||||
dimensions = packRectangles<SquareSizeSelector<2> >(rectangles.data(), rectangles.size(), spacing);
|
||||
break;
|
||||
case DimensionsConstraint::SQUARE:
|
||||
default:
|
||||
dimensions = packRectangles<SquareSizeSelector<> >(rectangles.data(), rectangles.size(), padding);
|
||||
dimensions = packRectangles<SquareSizeSelector<> >(rectangles.data(), rectangles.size(), spacing);
|
||||
break;
|
||||
}
|
||||
if (!(dimensions.first > 0 && dimensions.second > 0))
|
||||
return -1;
|
||||
width = dimensions.first, height = dimensions.second;
|
||||
} else {
|
||||
if (int result = packRectangles(rectangles.data(), rectangles.size(), width, height, padding))
|
||||
if (int result = packRectangles(rectangles.data(), rectangles.size(), width, height, spacing))
|
||||
return result;
|
||||
}
|
||||
// Set glyph box placement
|
||||
|
|
@ -131,8 +131,8 @@ void TightAtlasPacker::setDimensionsConstraint(DimensionsConstraint dimensionsCo
|
|||
this->dimensionsConstraint = dimensionsConstraint;
|
||||
}
|
||||
|
||||
void TightAtlasPacker::setPadding(int padding) {
|
||||
this->padding = padding;
|
||||
void TightAtlasPacker::setSpacing(int spacing) {
|
||||
this->spacing = spacing;
|
||||
}
|
||||
|
||||
void TightAtlasPacker::setScale(double scale) {
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@ public:
|
|||
void unsetDimensions();
|
||||
/// Sets the constraint to be used when determining dimensions
|
||||
void setDimensionsConstraint(DimensionsConstraint dimensionsConstraint);
|
||||
/// Sets the padding between glyph boxes
|
||||
void setPadding(int padding);
|
||||
/// Sets the spacing between glyph boxes
|
||||
void setSpacing(int spacing);
|
||||
/// Sets fixed glyph scale
|
||||
void setScale(double scale);
|
||||
/// Sets the minimum glyph scale
|
||||
|
|
@ -49,7 +49,7 @@ public:
|
|||
|
||||
private:
|
||||
int width, height;
|
||||
int padding;
|
||||
int spacing;
|
||||
DimensionsConstraint dimensionsConstraint;
|
||||
double scale;
|
||||
double minScale;
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ static std::string escapeJsonString(const char *str) {
|
|||
return outStr;
|
||||
}
|
||||
|
||||
static const char * imageTypeString(ImageType type) {
|
||||
static const char *imageTypeString(ImageType type) {
|
||||
switch (type) {
|
||||
case ImageType::HARD_MASK:
|
||||
return "hardmask";
|
||||
|
|
@ -87,7 +87,7 @@ bool exportJSON(const FontGeometry *fonts, int fontCount, ImageType imageType, c
|
|||
fprintf(f, ",\"originY\":%.17g", *metrics.grid->originY);
|
||||
break;
|
||||
case YDirection::TOP_DOWN:
|
||||
fprintf(f, ",\"originY\":%.17g", (metrics.grid->cellHeight-metrics.grid->padding-1)/metrics.size-*metrics.grid->originY);
|
||||
fprintf(f, ",\"originY\":%.17g", (metrics.grid->cellHeight-metrics.grid->spacing-1)/metrics.size-*metrics.grid->originY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ struct JsonAtlasMetrics {
|
|||
int cellWidth, cellHeight;
|
||||
int columns, rows;
|
||||
const double *originX, *originY;
|
||||
int padding;
|
||||
int spacing;
|
||||
};
|
||||
double distanceRange;
|
||||
double size;
|
||||
|
|
|
|||
|
|
@ -46,12 +46,12 @@ using namespace msdf_atlas;
|
|||
#define EXTRA_UNDERLINE
|
||||
#endif
|
||||
|
||||
static const char * const versionText =
|
||||
static const char *const versionText =
|
||||
"MSDF-Atlas-Gen v" MSDF_ATLAS_VERSION_STRING "\n"
|
||||
" with MSDFgen v" MSDFGEN_VERSION_STRING TITLE_SUFFIX "\n"
|
||||
"(c) 2020 - " STRINGIZE(MSDF_ATLAS_COPYRIGHT_YEAR) " Viktor Chlumsky";
|
||||
|
||||
static const char * const helpText = R"(
|
||||
static const char *const helpText = R"(
|
||||
MSDF Atlas Generator by Viktor Chlumsky v)" MSDF_ATLAS_VERSION_STRING R"( (with MSDFgen v)" MSDFGEN_VERSION_STRING TITLE_SUFFIX R"()
|
||||
----------------------------------------------------------------)" VERSION_UNDERLINE EXTRA_UNDERLINE R"(
|
||||
|
||||
|
|
@ -221,7 +221,14 @@ static bool cmpExtension(const char *path, const char *ext) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static msdfgen::FontHandle * loadVarFont(msdfgen::FreetypeHandle *library, const char *filename) {
|
||||
static bool strStartsWith(const char *str, const char *prefix) {
|
||||
while (*prefix)
|
||||
if (*str++ != *prefix++)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static msdfgen::FontHandle *loadVarFont(msdfgen::FreetypeHandle *library, const char *filename) {
|
||||
std::string buffer;
|
||||
while (*filename && *filename != '?')
|
||||
buffer.push_back(*filename++);
|
||||
|
|
@ -322,7 +329,7 @@ static bool makeAtlas(const std::vector<GlyphGeometry> &glyphs, const std::vecto
|
|||
return success;
|
||||
}
|
||||
|
||||
int main(int argc, const char * const *argv) {
|
||||
int main(int argc, const char *const *argv) {
|
||||
#define ABORT(msg) do { fputs(msg "\n", stderr); return 1; } while (false)
|
||||
|
||||
int result = 0;
|
||||
|
|
@ -371,25 +378,27 @@ int main(int argc, const char * const *argv) {
|
|||
bool explicitErrorCorrectionMode = false;
|
||||
while (argPos < argc) {
|
||||
const char *arg = argv[argPos];
|
||||
#define ARG_CASE(s, p) if (!strcmp(arg, s) && argPos+(p) < argc)
|
||||
#define ARG_CASE(s, p) if ((!strcmp(arg, s)) && argPos+(p) < argc && (++argPos, true))
|
||||
#define ARG_CASE_OR ) || !strcmp(arg,
|
||||
#define ARG_IS(s) (!strcmp(argv[argPos], s))
|
||||
#define ARG_PREFIX(s) strStartsWith(argv[argPos], s)
|
||||
|
||||
// Accept arguments prefixed with -- instead of -
|
||||
if (arg[0] == '-' && arg[1] == '-')
|
||||
++arg;
|
||||
|
||||
ARG_CASE("-type", 1) {
|
||||
arg = argv[++argPos];
|
||||
if (!strcmp(arg, "hardmask"))
|
||||
if (ARG_IS("hardmask"))
|
||||
config.imageType = ImageType::HARD_MASK;
|
||||
else if (!strcmp(arg, "softmask"))
|
||||
else if (ARG_IS("softmask"))
|
||||
config.imageType = ImageType::SOFT_MASK;
|
||||
else if (!strcmp(arg, "sdf"))
|
||||
else if (ARG_IS("sdf"))
|
||||
config.imageType = ImageType::SDF;
|
||||
else if (!strcmp(arg, "psdf"))
|
||||
else if (ARG_IS("psdf"))
|
||||
config.imageType = ImageType::PSDF;
|
||||
else if (!strcmp(arg, "msdf"))
|
||||
else if (ARG_IS("msdf"))
|
||||
config.imageType = ImageType::MSDF;
|
||||
else if (!strcmp(arg, "mtsdf"))
|
||||
else if (ARG_IS("mtsdf"))
|
||||
config.imageType = ImageType::MTSDF;
|
||||
else
|
||||
ABORT("Invalid atlas type. Valid types are: hardmask, softmask, sdf, psdf, msdf, mtsdf");
|
||||
|
|
@ -397,22 +406,21 @@ int main(int argc, const char * const *argv) {
|
|||
continue;
|
||||
}
|
||||
ARG_CASE("-format", 1) {
|
||||
arg = argv[++argPos];
|
||||
if (!strcmp(arg, "png"))
|
||||
if (ARG_IS("png"))
|
||||
config.imageFormat = ImageFormat::PNG;
|
||||
else if (!strcmp(arg, "bmp"))
|
||||
else if (ARG_IS("bmp"))
|
||||
config.imageFormat = ImageFormat::BMP;
|
||||
else if (!strcmp(arg, "tiff"))
|
||||
else if (ARG_IS("tiff"))
|
||||
config.imageFormat = ImageFormat::TIFF;
|
||||
else if (!strcmp(arg, "text"))
|
||||
else if (ARG_IS("text"))
|
||||
config.imageFormat = ImageFormat::TEXT;
|
||||
else if (!strcmp(arg, "textfloat"))
|
||||
else if (ARG_IS("textfloat"))
|
||||
config.imageFormat = ImageFormat::TEXT_FLOAT;
|
||||
else if (!strcmp(arg, "bin"))
|
||||
else if (ARG_IS("bin"))
|
||||
config.imageFormat = ImageFormat::BINARY;
|
||||
else if (!strcmp(arg, "binfloat"))
|
||||
else if (ARG_IS("binfloat"))
|
||||
config.imageFormat = ImageFormat::BINARY_FLOAT;
|
||||
else if (!strcmp(arg, "binfloatbe"))
|
||||
else if (ARG_IS("binfloatbe"))
|
||||
config.imageFormat = ImageFormat::BINARY_FLOAT_BE;
|
||||
else
|
||||
ABORT("Invalid image format. Valid formats are: png, bmp, tiff, text, textfloat, bin, binfloat");
|
||||
|
|
@ -421,46 +429,39 @@ int main(int argc, const char * const *argv) {
|
|||
continue;
|
||||
}
|
||||
ARG_CASE("-font", 1) {
|
||||
fontInput.fontFilename = argv[++argPos];
|
||||
fontInput.fontFilename = argv[argPos++];
|
||||
fontInput.variableFont = false;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-varfont", 1) {
|
||||
fontInput.fontFilename = argv[++argPos];
|
||||
fontInput.fontFilename = argv[argPos++];
|
||||
fontInput.variableFont = true;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-charset", 1) {
|
||||
fontInput.charsetFilename = argv[++argPos];
|
||||
fontInput.charsetFilename = argv[argPos++];
|
||||
fontInput.glyphIdentifierType = GlyphIdentifierType::UNICODE_CODEPOINT;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-glyphset", 1) {
|
||||
fontInput.charsetFilename = argv[++argPos];
|
||||
fontInput.charsetFilename = argv[argPos++];
|
||||
fontInput.glyphIdentifierType = GlyphIdentifierType::GLYPH_INDEX;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-allglyphs", 0) {
|
||||
fontInput.charsetFilename = nullptr;
|
||||
fontInput.glyphIdentifierType = GlyphIdentifierType::GLYPH_INDEX;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-fontscale", 1) {
|
||||
double fs;
|
||||
if (!(parseDouble(fs, argv[++argPos]) && fs > 0))
|
||||
if (!(parseDouble(fs, argv[argPos++]) && fs > 0))
|
||||
ABORT("Invalid font scale argument. Use -fontscale <font scale> with a positive real number.");
|
||||
fontInput.fontScale = fs;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-fontname", 1) {
|
||||
fontInput.fontName = argv[++argPos];
|
||||
++argPos;
|
||||
fontInput.fontName = argv[argPos++];
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-and", 0) {
|
||||
|
|
@ -470,80 +471,67 @@ int main(int argc, const char * const *argv) {
|
|||
ABORT("No changes between subsequent inputs. A different font, character set, or font scale must be set inbetween -and separators.");
|
||||
fontInputs.push_back(fontInput);
|
||||
fontInput.fontName = nullptr;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
#ifndef MSDF_ATLAS_NO_ARTERY_FONT
|
||||
ARG_CASE("-arfont", 1) {
|
||||
config.arteryFontFilename = argv[++argPos];
|
||||
++argPos;
|
||||
config.arteryFontFilename = argv[argPos++];
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
ARG_CASE("-imageout", 1) {
|
||||
config.imageFilename = argv[++argPos];
|
||||
++argPos;
|
||||
config.imageFilename = argv[argPos++];
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-json", 1) {
|
||||
config.jsonFilename = argv[++argPos];
|
||||
++argPos;
|
||||
config.jsonFilename = argv[argPos++];
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-csv", 1) {
|
||||
config.csvFilename = argv[++argPos];
|
||||
++argPos;
|
||||
config.csvFilename = argv[argPos++];
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-shadronpreview", 2) {
|
||||
config.shadronPreviewFilename = argv[++argPos];
|
||||
config.shadronPreviewText = argv[++argPos];
|
||||
++argPos;
|
||||
config.shadronPreviewFilename = argv[argPos++];
|
||||
config.shadronPreviewText = argv[argPos++];
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-dimensions", 2) {
|
||||
unsigned w, h;
|
||||
if (!(parseUnsigned(w, argv[argPos+1]) && parseUnsigned(h, argv[argPos+2]) && w && h))
|
||||
if (!(parseUnsigned(w, argv[argPos++]) && parseUnsigned(h, argv[argPos++]) && w && h))
|
||||
ABORT("Invalid atlas dimensions. Use -dimensions <width> <height> with two positive integers.");
|
||||
fixedWidth = w, fixedHeight = h;
|
||||
argPos += 3;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-pots", 0) {
|
||||
atlasSizeConstraint = DimensionsConstraint::POWER_OF_TWO_SQUARE;
|
||||
fixedWidth = -1, fixedHeight = -1;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-potr", 0) {
|
||||
atlasSizeConstraint = DimensionsConstraint::POWER_OF_TWO_RECTANGLE;
|
||||
fixedWidth = -1, fixedHeight = -1;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-square", 0) {
|
||||
atlasSizeConstraint = DimensionsConstraint::SQUARE;
|
||||
fixedWidth = -1, fixedHeight = -1;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-square2", 0) {
|
||||
atlasSizeConstraint = DimensionsConstraint::EVEN_SQUARE;
|
||||
fixedWidth = -1, fixedHeight = -1;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-square4", 0) {
|
||||
atlasSizeConstraint = DimensionsConstraint::MULTIPLE_OF_FOUR_SQUARE;
|
||||
fixedWidth = -1, fixedHeight = -1;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-yorigin", 1) {
|
||||
arg = argv[++argPos];
|
||||
if (!strcmp(arg, "bottom"))
|
||||
if (ARG_IS("bottom"))
|
||||
config.yDirection = YDirection::BOTTOM_UP;
|
||||
else if (!strcmp(arg, "top"))
|
||||
else if (ARG_IS("top"))
|
||||
config.yDirection = YDirection::TOP_DOWN;
|
||||
else
|
||||
ABORT("Invalid Y-axis origin. Use bottom or top.");
|
||||
|
|
@ -552,237 +540,219 @@ int main(int argc, const char * const *argv) {
|
|||
}
|
||||
ARG_CASE("-size", 1) {
|
||||
double s;
|
||||
if (!(parseDouble(s, argv[++argPos]) && s > 0))
|
||||
if (!(parseDouble(s, argv[argPos++]) && s > 0))
|
||||
ABORT("Invalid em size argument. Use -size <em size> with a positive real number.");
|
||||
config.emSize = s;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-minsize", 1) {
|
||||
double s;
|
||||
if (!(parseDouble(s, argv[++argPos]) && s > 0))
|
||||
if (!(parseDouble(s, argv[argPos++]) && s > 0))
|
||||
ABORT("Invalid minimum em size argument. Use -minsize <em size> with a positive real number.");
|
||||
minEmSize = s;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-emrange", 1) {
|
||||
double r;
|
||||
if (!(parseDouble(r, argv[++argPos]) && r >= 0))
|
||||
if (!(parseDouble(r, argv[argPos++]) && r >= 0))
|
||||
ABORT("Invalid range argument. Use -emrange <em range> with a positive real number.");
|
||||
rangeMode = RANGE_EM;
|
||||
rangeValue = r;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-pxrange", 1) {
|
||||
double r;
|
||||
if (!(parseDouble(r, argv[++argPos]) && r >= 0))
|
||||
if (!(parseDouble(r, argv[argPos++]) && r >= 0))
|
||||
ABORT("Invalid range argument. Use -pxrange <pixel range> with a positive real number.");
|
||||
rangeMode = RANGE_PIXEL;
|
||||
rangeValue = r;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-pxalign", 1) {
|
||||
if (!strcmp(argv[argPos+1], "off") || !memcmp(argv[argPos+1], "disable", 7) || !strcmp(argv[argPos+1], "0") || !strcmp(argv[argPos+1], "false") || argv[argPos+1][0] == 'n')
|
||||
if (ARG_IS("off") || ARG_PREFIX("disable") || ARG_IS("0") || ARG_IS("false") || ARG_PREFIX("n"))
|
||||
config.pxAlignOriginX = false, config.pxAlignOriginY = false;
|
||||
else if (!strcmp(argv[argPos+1], "on") || !memcmp(argv[argPos+1], "enable", 6) || !strcmp(argv[argPos+1], "1") || !strcmp(argv[argPos+1], "true") || !strcmp(argv[argPos+1], "hv") || argv[argPos+1][0] == 'y')
|
||||
else if (ARG_IS("on") || ARG_PREFIX("enable") || ARG_IS("1") || ARG_IS("true") || ARG_IS("hv") || ARG_PREFIX("y"))
|
||||
config.pxAlignOriginX = true, config.pxAlignOriginY = true;
|
||||
else if (argv[argPos+1][0] == 'h')
|
||||
else if (ARG_PREFIX("h"))
|
||||
config.pxAlignOriginX = true, config.pxAlignOriginY = false;
|
||||
else if (argv[argPos+1][0] == 'v' || !strcmp(argv[argPos+1], "baseline") || !strcmp(argv[argPos+1], "default"))
|
||||
else if (ARG_PREFIX("v") || ARG_IS("baseline") || ARG_IS("default"))
|
||||
config.pxAlignOriginX = false, config.pxAlignOriginY = true;
|
||||
else
|
||||
ABORT("Unknown -pxalign setting. Use one of: off, on, horizontal, vertical.");
|
||||
argPos += 2;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-angle", 1) {
|
||||
double at;
|
||||
if (!parseAngle(at, argv[argPos+1]))
|
||||
if (!parseAngle(at, argv[argPos++]))
|
||||
ABORT("Invalid angle threshold. Use -angle <min angle> with a positive real number less than PI or a value in degrees followed by 'd' below 180d.");
|
||||
config.angleThreshold = at;
|
||||
argPos += 2;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-uniformgrid", 0) {
|
||||
packingStyle = PackingStyle::GRID;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-uniformcols", 1) {
|
||||
packingStyle = PackingStyle::GRID;
|
||||
unsigned c;
|
||||
if (!(parseUnsigned(c, argv[argPos+1]) && c))
|
||||
if (!(parseUnsigned(c, argv[argPos++]) && c))
|
||||
ABORT("Invalid number of grid columns. Use -uniformcols <N> with a positive integer.");
|
||||
config.grid.cols = c;
|
||||
argPos += 2;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-uniformcell", 2) {
|
||||
packingStyle = PackingStyle::GRID;
|
||||
unsigned w, h;
|
||||
if (!(parseUnsigned(w, argv[argPos+1]) && parseUnsigned(h, argv[argPos+2]) && w && h))
|
||||
if (!(parseUnsigned(w, argv[argPos++]) && parseUnsigned(h, argv[argPos++]) && w && h))
|
||||
ABORT("Invalid cell dimensions. Use -uniformcell <width> <height> with two positive integers.");
|
||||
fixedCellWidth = w, fixedCellHeight = h;
|
||||
argPos += 3;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-uniformcellconstraint", 1) {
|
||||
packingStyle = PackingStyle::GRID;
|
||||
if (!strcmp(argv[argPos+1], "none") || !strcmp(argv[argPos+1], "rect"))
|
||||
if (ARG_IS("none") || ARG_IS("rect"))
|
||||
cellSizeConstraint = DimensionsConstraint::NONE;
|
||||
else if (!strcmp(argv[argPos+1], "pots"))
|
||||
else if (ARG_IS("pots"))
|
||||
cellSizeConstraint = DimensionsConstraint::POWER_OF_TWO_SQUARE;
|
||||
else if (!strcmp(argv[argPos+1], "potr"))
|
||||
else if (ARG_IS("potr"))
|
||||
cellSizeConstraint = DimensionsConstraint::POWER_OF_TWO_RECTANGLE;
|
||||
else if (!strcmp(argv[argPos+1], "square"))
|
||||
else if (ARG_IS("square"))
|
||||
cellSizeConstraint = DimensionsConstraint::SQUARE;
|
||||
else if (!strcmp(argv[argPos+1], "square2"))
|
||||
else if (ARG_IS("square2"))
|
||||
cellSizeConstraint = DimensionsConstraint::EVEN_SQUARE;
|
||||
else if (!strcmp(argv[argPos+1], "square4"))
|
||||
else if (ARG_IS("square4"))
|
||||
cellSizeConstraint = DimensionsConstraint::MULTIPLE_OF_FOUR_SQUARE;
|
||||
else
|
||||
ABORT("Unknown dimensions constaint. Use -uniformcellconstraint with one of: none, pots, potr, square, square2, or square4.");
|
||||
argPos += 2;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-uniformorigin", 1) {
|
||||
packingStyle = PackingStyle::GRID;
|
||||
if (!strcmp(argv[argPos+1], "off") || !memcmp(argv[argPos+1], "disable", 7) || !strcmp(argv[argPos+1], "0") || !strcmp(argv[argPos+1], "false") || argv[argPos+1][0] == 'n')
|
||||
if (ARG_IS("off") || ARG_PREFIX("disable") || ARG_IS("0") || ARG_IS("false") || ARG_PREFIX("n"))
|
||||
config.grid.fixedOriginX = false, config.grid.fixedOriginY = false;
|
||||
else if (!strcmp(argv[argPos+1], "on") || !memcmp(argv[argPos+1], "enable", 6) || !strcmp(argv[argPos+1], "1") || !strcmp(argv[argPos+1], "true") || !strcmp(argv[argPos+1], "hv") || argv[argPos+1][0] == 'y')
|
||||
else if (ARG_IS("on") || ARG_PREFIX("enable") || ARG_IS("1") || ARG_IS("true") || ARG_IS("hv") || ARG_PREFIX("y"))
|
||||
config.grid.fixedOriginX = true, config.grid.fixedOriginY = true;
|
||||
else if (argv[argPos+1][0] == 'h')
|
||||
else if (ARG_PREFIX("h"))
|
||||
config.grid.fixedOriginX = true, config.grid.fixedOriginY = false;
|
||||
else if (argv[argPos+1][0] == 'v' || !strcmp(argv[argPos+1], "baseline") || !strcmp(argv[argPos+1], "default"))
|
||||
else if (ARG_PREFIX("v") || ARG_IS("baseline") || ARG_IS("default"))
|
||||
config.grid.fixedOriginX = false, config.grid.fixedOriginY = true;
|
||||
else
|
||||
ABORT("Unknown -uniformorigin setting. Use one of: off, on, horizontal, vertical.");
|
||||
argPos += 2;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-errorcorrection", 1) {
|
||||
msdfgen::ErrorCorrectionConfig &ec = config.generatorAttributes.config.errorCorrection;
|
||||
if (!memcmp(argv[argPos+1], "disable", 7) || !strcmp(argv[argPos+1], "0") || !strcmp(argv[argPos+1], "none")) {
|
||||
if (ARG_PREFIX("disable") || ARG_IS("0") || ARG_IS("none")) {
|
||||
ec.mode = msdfgen::ErrorCorrectionConfig::DISABLED;
|
||||
ec.distanceCheckMode = msdfgen::ErrorCorrectionConfig::DO_NOT_CHECK_DISTANCE;
|
||||
} else if (!strcmp(argv[argPos+1], "default") || !strcmp(argv[argPos+1], "auto") || !strcmp(argv[argPos+1], "auto-mixed") || !strcmp(argv[argPos+1], "mixed")) {
|
||||
} else if (ARG_IS("default") || ARG_IS("auto") || ARG_IS("auto-mixed") || ARG_IS("mixed")) {
|
||||
ec.mode = msdfgen::ErrorCorrectionConfig::EDGE_PRIORITY;
|
||||
ec.distanceCheckMode = msdfgen::ErrorCorrectionConfig::CHECK_DISTANCE_AT_EDGE;
|
||||
} else if (!strcmp(argv[argPos+1], "auto-fast") || !strcmp(argv[argPos+1], "fast")) {
|
||||
} else if (ARG_IS("auto-fast") || ARG_IS("fast")) {
|
||||
ec.mode = msdfgen::ErrorCorrectionConfig::EDGE_PRIORITY;
|
||||
ec.distanceCheckMode = msdfgen::ErrorCorrectionConfig::DO_NOT_CHECK_DISTANCE;
|
||||
} else if (!strcmp(argv[argPos+1], "auto-full") || !strcmp(argv[argPos+1], "full")) {
|
||||
} else if (ARG_IS("auto-full") || ARG_IS("full")) {
|
||||
ec.mode = msdfgen::ErrorCorrectionConfig::EDGE_PRIORITY;
|
||||
ec.distanceCheckMode = msdfgen::ErrorCorrectionConfig::ALWAYS_CHECK_DISTANCE;
|
||||
} else if (!strcmp(argv[argPos+1], "distance") || !strcmp(argv[argPos+1], "distance-fast") || !strcmp(argv[argPos+1], "indiscriminate") || !strcmp(argv[argPos+1], "indiscriminate-fast")) {
|
||||
} else if (ARG_IS("distance") || ARG_IS("distance-fast") || ARG_IS("indiscriminate") || ARG_IS("indiscriminate-fast")) {
|
||||
ec.mode = msdfgen::ErrorCorrectionConfig::INDISCRIMINATE;
|
||||
ec.distanceCheckMode = msdfgen::ErrorCorrectionConfig::DO_NOT_CHECK_DISTANCE;
|
||||
} else if (!strcmp(argv[argPos+1], "distance-full") || !strcmp(argv[argPos+1], "indiscriminate-full")) {
|
||||
} else if (ARG_IS("distance-full") || ARG_IS("indiscriminate-full")) {
|
||||
ec.mode = msdfgen::ErrorCorrectionConfig::INDISCRIMINATE;
|
||||
ec.distanceCheckMode = msdfgen::ErrorCorrectionConfig::ALWAYS_CHECK_DISTANCE;
|
||||
} else if (!strcmp(argv[argPos+1], "edge-fast")) {
|
||||
} else if (ARG_IS("edge-fast")) {
|
||||
ec.mode = msdfgen::ErrorCorrectionConfig::EDGE_ONLY;
|
||||
ec.distanceCheckMode = msdfgen::ErrorCorrectionConfig::DO_NOT_CHECK_DISTANCE;
|
||||
} else if (!strcmp(argv[argPos+1], "edge") || !strcmp(argv[argPos+1], "edge-full")) {
|
||||
} else if (ARG_IS("edge") || ARG_IS("edge-full")) {
|
||||
ec.mode = msdfgen::ErrorCorrectionConfig::EDGE_ONLY;
|
||||
ec.distanceCheckMode = msdfgen::ErrorCorrectionConfig::ALWAYS_CHECK_DISTANCE;
|
||||
} else if (!strcmp(argv[argPos+1], "help")) {
|
||||
} else if (ARG_IS("help")) {
|
||||
puts(errorCorrectionHelpText);
|
||||
return 0;
|
||||
} else
|
||||
ABORT("Unknown error correction mode. Use -errorcorrection help for more information.");
|
||||
++argPos;
|
||||
explicitErrorCorrectionMode = true;
|
||||
argPos += 2;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-errordeviationratio", 1) {
|
||||
double edr;
|
||||
if (!(parseDouble(edr, argv[argPos+1]) && edr > 0))
|
||||
if (!(parseDouble(edr, argv[argPos++]) && edr > 0))
|
||||
ABORT("Invalid error deviation ratio. Use -errordeviationratio <ratio> with a positive real number.");
|
||||
config.generatorAttributes.config.errorCorrection.minDeviationRatio = edr;
|
||||
argPos += 2;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-errorimproveratio", 1) {
|
||||
double eir;
|
||||
if (!(parseDouble(eir, argv[argPos+1]) && eir > 0))
|
||||
if (!(parseDouble(eir, argv[argPos++]) && eir > 0))
|
||||
ABORT("Invalid error improvement ratio. Use -errorimproveratio <ratio> with a positive real number.");
|
||||
config.generatorAttributes.config.errorCorrection.minImproveRatio = eir;
|
||||
argPos += 2;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-coloringstrategy", 1) {
|
||||
if (!strcmp(argv[argPos+1], "simple")) config.edgeColoring = msdfgen::edgeColoringSimple, config.expensiveColoring = false;
|
||||
else if (!strcmp(argv[argPos+1], "inktrap")) config.edgeColoring = msdfgen::edgeColoringInkTrap, config.expensiveColoring = false;
|
||||
else if (!strcmp(argv[argPos+1], "distance")) config.edgeColoring = msdfgen::edgeColoringByDistance, config.expensiveColoring = true;
|
||||
ARG_CASE("-coloringstrategy" ARG_CASE_OR "-edgecoloring", 1) {
|
||||
if (ARG_IS("simple"))
|
||||
config.edgeColoring = &msdfgen::edgeColoringSimple, config.expensiveColoring = false;
|
||||
else if (ARG_IS("inktrap"))
|
||||
config.edgeColoring = &msdfgen::edgeColoringInkTrap, config.expensiveColoring = false;
|
||||
else if (ARG_IS("distance"))
|
||||
config.edgeColoring = &msdfgen::edgeColoringByDistance, config.expensiveColoring = true;
|
||||
else
|
||||
fputs("Unknown coloring strategy specified.\n", stderr);
|
||||
argPos += 2;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-miterlimit", 1) {
|
||||
double m;
|
||||
if (!(parseDouble(m, argv[++argPos]) && m >= 0))
|
||||
if (!(parseDouble(m, argv[argPos++]) && m >= 0))
|
||||
ABORT("Invalid miter limit argument. Use -miterlimit <limit> with a positive real number.");
|
||||
config.miterLimit = m;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-nokerning", 0) {
|
||||
config.kerning = false;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-kerning", 0) {
|
||||
config.kerning = true;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-nopreprocess", 0) {
|
||||
config.preprocessGeometry = false;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-preprocess", 0) {
|
||||
config.preprocessGeometry = true;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-nooverlap", 0) {
|
||||
config.generatorAttributes.config.overlapSupport = false;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-overlap", 0) {
|
||||
config.generatorAttributes.config.overlapSupport = true;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-noscanline", 0) {
|
||||
config.generatorAttributes.scanlinePass = false;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-scanline", 0) {
|
||||
config.generatorAttributes.scanlinePass = true;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-seed", 1) {
|
||||
if (!parseUnsignedLL(config.coloringSeed, argv[argPos+1]))
|
||||
if (!parseUnsignedLL(config.coloringSeed, argv[argPos++]))
|
||||
ABORT("Invalid seed. Use -seed <N> with N being a non-negative integer.");
|
||||
argPos += 2;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-threads", 1) {
|
||||
unsigned tc;
|
||||
if (!parseUnsigned(tc, argv[argPos+1]) || (int) tc < 0)
|
||||
if (!(parseUnsigned(tc, argv[argPos++]) && (int) tc >= 0))
|
||||
ABORT("Invalid thread count. Use -threads <N> with N being a non-negative integer.");
|
||||
config.threadCount = (int) tc;
|
||||
argPos += 2;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-version", 0) {
|
||||
|
|
@ -793,9 +763,8 @@ int main(int argc, const char * const *argv) {
|
|||
puts(helpText);
|
||||
return 0;
|
||||
}
|
||||
fprintf(stderr, "Unknown setting or insufficient parameters: %s\n", argv[argPos]);
|
||||
fprintf(stderr, "Unknown setting or insufficient parameters: %s\n", argv[argPos++]);
|
||||
suggestHelp = true;
|
||||
++argPos;
|
||||
}
|
||||
if (suggestHelp)
|
||||
fputs("Use -help for more information.\n", stderr);
|
||||
|
|
@ -929,8 +898,8 @@ int main(int argc, const char * const *argv) {
|
|||
config.imageFormat == ImageFormat::BINARY_FLOAT ||
|
||||
config.imageFormat == ImageFormat::BINARY_FLOAT_BE
|
||||
);
|
||||
// TODO: In this case (if padding is -1), the border pixels of each glyph are black, but still computed. For floating-point output, this may play a role.
|
||||
int padding = config.imageType == ImageType::MSDF || config.imageType == ImageType::MTSDF ? 0 : -1;
|
||||
// TODO: In this case (if spacing is -1), the border pixels of each glyph are black, but still computed. For floating-point output, this may play a role.
|
||||
int spacing = config.imageType == ImageType::MSDF || config.imageType == ImageType::MTSDF ? 0 : -1;
|
||||
double uniformOriginX, uniformOriginY;
|
||||
|
||||
// Load fonts
|
||||
|
|
@ -1064,7 +1033,7 @@ int main(int argc, const char * const *argv) {
|
|||
atlasPacker.setDimensions(fixedWidth, fixedHeight);
|
||||
else
|
||||
atlasPacker.setDimensionsConstraint(atlasSizeConstraint);
|
||||
atlasPacker.setPadding(padding);
|
||||
atlasPacker.setSpacing(spacing);
|
||||
if (fixedScale)
|
||||
atlasPacker.setScale(config.emSize);
|
||||
else
|
||||
|
|
@ -1106,7 +1075,7 @@ int main(int argc, const char * const *argv) {
|
|||
atlasPacker.setDimensions(fixedWidth, fixedHeight);
|
||||
else
|
||||
atlasPacker.setDimensionsConstraint(atlasSizeConstraint);
|
||||
atlasPacker.setPadding(padding);
|
||||
atlasPacker.setSpacing(spacing);
|
||||
if (fixedScale)
|
||||
atlasPacker.setScale(config.emSize);
|
||||
else
|
||||
|
|
@ -1148,7 +1117,7 @@ int main(int argc, const char * const *argv) {
|
|||
printf("Y = %.9g", uniformOriginY);
|
||||
break;
|
||||
case YDirection::TOP_DOWN:
|
||||
printf("Y = %.9g", (config.grid.cellHeight-padding-1)/config.emSize-uniformOriginY);
|
||||
printf("Y = %.9g", (config.grid.cellHeight-spacing-1)/config.emSize-uniformOriginY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -1243,7 +1212,7 @@ int main(int argc, const char * const *argv) {
|
|||
gridMetrics.originX = &uniformOriginX;
|
||||
if (config.grid.fixedOriginY)
|
||||
gridMetrics.originY = &uniformOriginY;
|
||||
gridMetrics.padding = padding;
|
||||
gridMetrics.spacing = spacing;
|
||||
jsonMetrics.grid = &gridMetrics;
|
||||
}
|
||||
if (exportJSON(fonts.data(), fonts.size(), config.imageType, jsonMetrics, config.jsonFilename, config.kerning))
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@ namespace msdf_atlas {
|
|||
|
||||
/// Packs the rectangle array into an atlas with fixed dimensions, returns how many didn't fit (0 on success)
|
||||
template <typename RectangleType>
|
||||
int packRectangles(RectangleType *rectangles, int count, int width, int height, int padding = 0);
|
||||
int packRectangles(RectangleType *rectangles, int count, int width, int height, int spacing = 0);
|
||||
|
||||
/// Packs the rectangle array into an atlas of unknown size, returns the minimum required dimensions constrained by SizeSelector
|
||||
template <class SizeSelector, typename RectangleType>
|
||||
std::pair<int, int> packRectangles(RectangleType *rectangles, int count, int padding = 0);
|
||||
std::pair<int, int> packRectangles(RectangleType *rectangles, int count, int spacing = 0);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,35 +18,35 @@ static void copyRectanglePlacement(OrientedRectangle &dst, const OrientedRectang
|
|||
}
|
||||
|
||||
template <typename RectangleType>
|
||||
int packRectangles(RectangleType *rectangles, int count, int width, int height, int padding) {
|
||||
if (padding)
|
||||
int packRectangles(RectangleType *rectangles, int count, int width, int height, int spacing) {
|
||||
if (spacing)
|
||||
for (int i = 0; i < count; ++i) {
|
||||
rectangles[i].w += padding;
|
||||
rectangles[i].h += padding;
|
||||
rectangles[i].w += spacing;
|
||||
rectangles[i].h += spacing;
|
||||
}
|
||||
int result = RectanglePacker(width+padding, height+padding).pack(rectangles, count);
|
||||
if (padding)
|
||||
int result = RectanglePacker(width+spacing, height+spacing).pack(rectangles, count);
|
||||
if (spacing)
|
||||
for (int i = 0; i < count; ++i) {
|
||||
rectangles[i].w -= padding;
|
||||
rectangles[i].h -= padding;
|
||||
rectangles[i].w -= spacing;
|
||||
rectangles[i].h -= spacing;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class SizeSelector, typename RectangleType>
|
||||
std::pair<int, int> packRectangles(RectangleType *rectangles, int count, int padding) {
|
||||
std::pair<int, int> packRectangles(RectangleType *rectangles, int count, int spacing) {
|
||||
std::vector<RectangleType> rectanglesCopy(count);
|
||||
int totalArea = 0;
|
||||
for (int i = 0; i < count; ++i) {
|
||||
rectanglesCopy[i].w = rectangles[i].w+padding;
|
||||
rectanglesCopy[i].h = rectangles[i].h+padding;
|
||||
rectanglesCopy[i].w = rectangles[i].w+spacing;
|
||||
rectanglesCopy[i].h = rectangles[i].h+spacing;
|
||||
totalArea += rectangles[i].w*rectangles[i].h;
|
||||
}
|
||||
std::pair<int, int> dimensions;
|
||||
SizeSelector sizeSelector(totalArea);
|
||||
int width, height;
|
||||
while (sizeSelector(width, height)) {
|
||||
if (!RectanglePacker(width+padding, height+padding).pack(rectanglesCopy.data(), count)) {
|
||||
if (!RectanglePacker(width+spacing, height+spacing).pack(rectanglesCopy.data(), count)) {
|
||||
dimensions.first = width;
|
||||
dimensions.second = height;
|
||||
for (int i = 0; i < count; ++i)
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
namespace msdf_atlas {
|
||||
|
||||
static const char * const shadronFillGlyphMask = R"(
|
||||
static const char *const shadronFillGlyphMask = R"(
|
||||
template <ATLAS, RANGE, COLOR>
|
||||
glsl vec4 fillGlyph(vec2 texCoord) {
|
||||
float fill = texture((ATLAS), texCoord).r;
|
||||
|
|
@ -14,7 +14,7 @@ glsl vec4 fillGlyph(vec2 texCoord) {
|
|||
}
|
||||
)";
|
||||
|
||||
static const char * const shadronFillGlyphSdf = R"(
|
||||
static const char *const shadronFillGlyphSdf = R"(
|
||||
template <ATLAS, RANGE, COLOR>
|
||||
glsl vec4 fillGlyph(vec2 texCoord) {
|
||||
vec3 s = texture((ATLAS), texCoord).rgb;
|
||||
|
|
@ -24,7 +24,7 @@ glsl vec4 fillGlyph(vec2 texCoord) {
|
|||
}
|
||||
)";
|
||||
|
||||
static const char * const shadronPreviewPreamble = R"(
|
||||
static const char *const shadronPreviewPreamble = R"(
|
||||
#include <median>
|
||||
|
||||
glsl struct GlyphVertex {
|
||||
|
|
|
|||
|
|
@ -27,14 +27,14 @@ bool SquareSizeSelector<MULTIPLE>::operator()(int &width, int &height) const {
|
|||
}
|
||||
|
||||
template <int MULTIPLE>
|
||||
SquareSizeSelector<MULTIPLE> & SquareSizeSelector<MULTIPLE>::operator++() {
|
||||
SquareSizeSelector<MULTIPLE> &SquareSizeSelector<MULTIPLE>::operator++() {
|
||||
lowerBound = current+1;
|
||||
updateCurrent();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <int MULTIPLE>
|
||||
SquareSizeSelector<MULTIPLE> & SquareSizeSelector<MULTIPLE>::operator--() {
|
||||
SquareSizeSelector<MULTIPLE> &SquareSizeSelector<MULTIPLE>::operator--() {
|
||||
upperBound = current;
|
||||
updateCurrent();
|
||||
return *this;
|
||||
|
|
@ -54,12 +54,12 @@ bool SquarePowerOfTwoSizeSelector::operator()(int &width, int &height) const {
|
|||
return side > 0;
|
||||
}
|
||||
|
||||
SquarePowerOfTwoSizeSelector & SquarePowerOfTwoSizeSelector::operator++() {
|
||||
SquarePowerOfTwoSizeSelector &SquarePowerOfTwoSizeSelector::operator++() {
|
||||
side <<= 1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
SquarePowerOfTwoSizeSelector & SquarePowerOfTwoSizeSelector::operator--() {
|
||||
SquarePowerOfTwoSizeSelector &SquarePowerOfTwoSizeSelector::operator--() {
|
||||
side = 0;
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -74,7 +74,7 @@ bool PowerOfTwoSizeSelector::operator()(int &width, int &height) const {
|
|||
return w > 0 && h > 0;
|
||||
}
|
||||
|
||||
PowerOfTwoSizeSelector & PowerOfTwoSizeSelector::operator++() {
|
||||
PowerOfTwoSizeSelector &PowerOfTwoSizeSelector::operator++() {
|
||||
if (w == h)
|
||||
w <<= 1;
|
||||
else
|
||||
|
|
@ -82,7 +82,7 @@ PowerOfTwoSizeSelector & PowerOfTwoSizeSelector::operator++() {
|
|||
return *this;
|
||||
}
|
||||
|
||||
PowerOfTwoSizeSelector & PowerOfTwoSizeSelector::operator--() {
|
||||
PowerOfTwoSizeSelector &PowerOfTwoSizeSelector::operator--() {
|
||||
w = 0, h = 0;
|
||||
return *this;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ class SquareSizeSelector {
|
|||
public:
|
||||
explicit SquareSizeSelector(int minArea = 0);
|
||||
bool operator()(int &width, int &height) const;
|
||||
SquareSizeSelector<MULTIPLE> & operator++();
|
||||
SquareSizeSelector<MULTIPLE> & operator--();
|
||||
SquareSizeSelector<MULTIPLE> &operator++();
|
||||
SquareSizeSelector<MULTIPLE> &operator--();
|
||||
|
||||
private:
|
||||
int lowerBound, upperBound;
|
||||
|
|
@ -29,8 +29,8 @@ class SquarePowerOfTwoSizeSelector {
|
|||
public:
|
||||
explicit SquarePowerOfTwoSizeSelector(int minArea = 0);
|
||||
bool operator()(int &width, int &height) const;
|
||||
SquarePowerOfTwoSizeSelector & operator++();
|
||||
SquarePowerOfTwoSizeSelector & operator--();
|
||||
SquarePowerOfTwoSizeSelector &operator++();
|
||||
SquarePowerOfTwoSizeSelector &operator--();
|
||||
|
||||
private:
|
||||
int side;
|
||||
|
|
@ -43,8 +43,8 @@ class PowerOfTwoSizeSelector {
|
|||
public:
|
||||
explicit PowerOfTwoSizeSelector(int minArea = 0);
|
||||
bool operator()(int &width, int &height) const;
|
||||
PowerOfTwoSizeSelector & operator++();
|
||||
PowerOfTwoSizeSelector & operator--();
|
||||
PowerOfTwoSizeSelector &operator++();
|
||||
PowerOfTwoSizeSelector &operator--();
|
||||
|
||||
private:
|
||||
int w, h;
|
||||
|
|
|
|||
Loading…
Reference in New Issue