Loading glyphs by glyph index
This commit is contained in:
parent
c42964a9ec
commit
60789b8cf3
|
|
@ -0,0 +1,18 @@
|
|||
|
||||
## Version 1.1 (2020-10-18)
|
||||
|
||||
- Updated to MSDFgen 1.8.
|
||||
- Glyph geometry is now preprocessed by Skia to resolve irregularities which were previously unsupported and caused artifacts.
|
||||
- The scanline pass and overlapping contour mode is made obsolete by this step and has been disabled by default. The preprocess step can be disabled by the new `-nopreprocess` switch and the former enabled by `-scanline` and `-overlap` respectively.
|
||||
- The project can be built without the Skia library, forgoing the geometry preprocessing feature. This is controlled by the macro definition `MSDFGEN_USE_SKIA`.
|
||||
- Glyphs can now also be loaded by glyph index rather than Unicode values. In the standalone version, a set of glyphs can be passed by `-glyphset` in place of `-charset`.
|
||||
- Glyphs not present in the font should now be correctly skipped instead of producing a placeholder symbol.
|
||||
- Added `-threads` argument to set the number of concurrent threads used during distance field generation.
|
||||
|
||||
### Version 1.0.1 (2020-03-09)
|
||||
|
||||
- Updated to MSDFgen 1.7.1.
|
||||
|
||||
## Version 1.0 (2020-03-08)
|
||||
|
||||
- Initial release.
|
||||
23
README.md
23
README.md
|
|
@ -3,19 +3,17 @@
|
|||
|
||||
This is a utility for generating compact font atlases using [MSDFgen](https://github.com/Chlumsky/msdfgen).
|
||||
|
||||
It can read TTF and OTF font files, select a subset of characters, generate distance fields or bitmaps for each, and tightly pack them into an atlas bitmap, which can be e.g. used as a texture in video games. The atlas can be exported as an image file or an [Artery Font](https://github.com/Chlumsky/artery-font-format) file, and its layout written into a CSV or structured JSON file.
|
||||
The atlas generator loads a subset of glyphs from a TTF or OTF font file, generates a distance field for each of them, and tightly packs them into an atlas bitmap (example below). The finished atlas and/or its layout metadata can be exported as an [Artery Font](https://github.com/Chlumsky/artery-font-format) file, a plain image file, a CSV sheet or a structured JSON file.
|
||||
|
||||

|
||||
|
||||
## Getting started
|
||||
A font atlas is typically stored in texture memory and used to draw text in real-time rendering contexts such as video games.
|
||||
|
||||
This project can be used either as a library or as a console program.
|
||||
To start using the program immediately, there is a Windows binary available for download in the ["Releases" section](https://github.com/Chlumsky/msdf-atlas-gen/releases).
|
||||
To build the project, you may use the included [Visual Studio solution](msdf-atlas-gen.sln) or the [Unix Makefile](Makefile).
|
||||
- See what's new in the [changelog](CHANGELOG.md).
|
||||
|
||||
## Atlas types
|
||||
|
||||
The utility can generate the atlas bitmap in the following six ways:
|
||||
The atlas generator can generate the following six types of atlases.
|
||||
|
||||
| |Hard mask|Soft mask|SDF|PSDF|MSDF|MTSDF|
|
||||
|-|-|-|-|-|-|-|
|
||||
|
|
@ -32,12 +30,21 @@ Notes:
|
|||
- *Soft effects* refers to the support of effects that use true distance, such as glows, rounded borders, or simplified shadows.
|
||||
- *Hard effects* refers to the support of effects that use pseudo-distance, such as mitered borders or thickness adjustment.
|
||||
|
||||
## Getting started
|
||||
|
||||
This project can be used either as a library or as a standalone console program.
|
||||
To start using the program immediately, there is a Windows binary available for download in the ["Releases" section](https://github.com/Chlumsky/msdf-atlas-gen/releases).
|
||||
To build the project, you may use the included [Visual Studio solution](msdf-atlas-gen.sln) or the [Unix Makefile](Makefile).
|
||||
|
||||
## Command line arguments
|
||||
|
||||
Use the following command line arguments for the standalone version of the atlas generator.
|
||||
|
||||
### Input
|
||||
|
||||
- `-font <fontfile.ttf/otf>` – sets the input font file.
|
||||
- `-charset <charset.txt>` – sets the character set. The ASCII charset will be used if not specified. See [the syntax specification](#character-set-specification-syntax) of `charset.txt`.
|
||||
- `-glyphset <glyphset.txt>` – sets the set of input glyphs using their indices within the font file. See [the syntax specification](#glyph-set-specification).
|
||||
|
||||
### Bitmap atlas type
|
||||
|
||||
|
|
@ -123,3 +130,7 @@ Additionally, the include directive can be used to include other charset files a
|
|||
It must be written on a separate line:
|
||||
|
||||
`@include "base-charset.txt"`
|
||||
|
||||
### Glyph set specification
|
||||
|
||||
The syntax of the glyph set specification is mostly the same as that of a character set, but only numeric values (decimal and hexadecimal) are allowed.
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ public:
|
|||
std::set<unicode_t>::const_iterator end() const;
|
||||
|
||||
/// Load character set from a text file with the correct syntax
|
||||
bool load(const char *filename);
|
||||
bool load(const char *filename, bool disableCharLiterals = false);
|
||||
|
||||
private:
|
||||
std::set<unicode_t> codepoints;
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
/// The glyph box - its bounds in plane and atlas
|
||||
struct GlyphBox {
|
||||
unicode_t codepoint;
|
||||
int index;
|
||||
double advance;
|
||||
struct {
|
||||
double l, b, r, t;
|
||||
|
|
|
|||
|
|
@ -6,11 +6,12 @@
|
|||
|
||||
namespace msdf_atlas {
|
||||
|
||||
GlyphGeometry::GlyphGeometry() : codepoint(), bounds(), advance(), box() { }
|
||||
GlyphGeometry::GlyphGeometry() : index(), codepoint(), bounds(), advance(), box() { }
|
||||
|
||||
bool GlyphGeometry::load(msdfgen::FontHandle *font, unicode_t codepoint, bool preprocessGeometry) {
|
||||
if (font && msdfgen::loadGlyph(shape, font, codepoint, &advance) && shape.validate()) {
|
||||
this->codepoint = codepoint;
|
||||
bool GlyphGeometry::load(msdfgen::FontHandle *font, msdfgen::GlyphIndex index, bool preprocessGeometry) {
|
||||
if (font && msdfgen::loadGlyph(shape, font, index, &advance) && shape.validate()) {
|
||||
this->index = index.getIndex();
|
||||
codepoint = 0;
|
||||
#ifdef MSDFGEN_USE_SKIA
|
||||
if (preprocessGeometry)
|
||||
msdfgen::resolveShapeGeometry(shape);
|
||||
|
|
@ -33,6 +34,17 @@ bool GlyphGeometry::load(msdfgen::FontHandle *font, unicode_t codepoint, bool pr
|
|||
return false;
|
||||
}
|
||||
|
||||
bool GlyphGeometry::load(msdfgen::FontHandle *font, unicode_t codepoint, bool preprocessGeometry) {
|
||||
msdfgen::GlyphIndex index;
|
||||
if (msdfgen::getGlyphIndex(index, font, codepoint)) {
|
||||
if (load(font, index, preprocessGeometry)) {
|
||||
this->codepoint = codepoint;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GlyphGeometry::edgeColoring(double angleThreshold, unsigned long long seed) {
|
||||
msdfgen::edgeColoringInkTrap(shape, angleThreshold, seed);
|
||||
}
|
||||
|
|
@ -62,10 +74,28 @@ void GlyphGeometry::placeBox(int x, int y) {
|
|||
box.rect.x = x, box.rect.y = y;
|
||||
}
|
||||
|
||||
int GlyphGeometry::getIndex() const {
|
||||
return index;
|
||||
}
|
||||
|
||||
msdfgen::GlyphIndex GlyphGeometry::getGlyphIndex() const {
|
||||
return msdfgen::GlyphIndex(index);
|
||||
}
|
||||
|
||||
unicode_t GlyphGeometry::getCodepoint() const {
|
||||
return codepoint;
|
||||
}
|
||||
|
||||
int GlyphGeometry::getIdentifier(GlyphIdentifierType type) const {
|
||||
switch (type) {
|
||||
case GlyphIdentifierType::GLYPH_INDEX:
|
||||
return index;
|
||||
case GlyphIdentifierType::UNICODE_CODEPOINT:
|
||||
return (int) codepoint;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const msdfgen::Shape & GlyphGeometry::getShape() const {
|
||||
return shape;
|
||||
}
|
||||
|
|
@ -121,7 +151,7 @@ bool GlyphGeometry::isWhitespace() const {
|
|||
|
||||
GlyphGeometry::operator GlyphBox() const {
|
||||
GlyphBox box;
|
||||
box.codepoint = codepoint;
|
||||
box.index = index;
|
||||
box.advance = advance;
|
||||
getQuadPlaneBounds(box.bounds.l, box.bounds.b, box.bounds.r, box.bounds.t);
|
||||
box.rect.x = this->box.rect.x, box.rect.y = this->box.rect.y, box.rect.w = this->box.rect.w, box.rect.h = this->box.rect.h;
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ class GlyphGeometry {
|
|||
public:
|
||||
GlyphGeometry();
|
||||
/// Loads glyph geometry from font
|
||||
bool load(msdfgen::FontHandle *font, msdfgen::GlyphIndex index, bool preprocessGeometry = true);
|
||||
bool load(msdfgen::FontHandle *font, unicode_t codepoint, bool preprocessGeometry = true);
|
||||
/// Applies edge coloring to glyph shape
|
||||
void edgeColoring(double angleThreshold, unsigned long long seed);
|
||||
|
|
@ -21,8 +22,14 @@ public:
|
|||
void wrapBox(double scale, double range, double miterLimit);
|
||||
/// Sets the glyph's box's position in the atlas
|
||||
void placeBox(int x, int y);
|
||||
/// Returns the glyph's Unicode index
|
||||
/// Returns the glyph's index within the font
|
||||
int getIndex() const;
|
||||
/// Returns the glyph's index as a msdfgen::GlyphIndex
|
||||
msdfgen::GlyphIndex getGlyphIndex() const;
|
||||
/// Returns the Unicode codepoint represented by the glyph or 0 if unknown
|
||||
unicode_t getCodepoint() const;
|
||||
/// Returns the glyph's identifier specified by the supplied identifier type
|
||||
int getIdentifier(GlyphIdentifierType type) const;
|
||||
/// Returns the glyph's shape
|
||||
const msdfgen::Shape & getShape() const;
|
||||
/// Returns the glyph's advance
|
||||
|
|
@ -47,6 +54,7 @@ public:
|
|||
operator GlyphBox() const;
|
||||
|
||||
private:
|
||||
int index;
|
||||
unicode_t codepoint;
|
||||
msdfgen::Shape shape;
|
||||
msdfgen::Shape::Bounds bounds;
|
||||
|
|
|
|||
|
|
@ -24,6 +24,16 @@ static artery_font::ImageType convertImageType(ImageType imageType) {
|
|||
return artery_font::IMAGE_NONE;
|
||||
}
|
||||
|
||||
static artery_font::CodepointType convertCodepointType(GlyphIdentifierType glyphIdentifierType) {
|
||||
switch (glyphIdentifierType) {
|
||||
case GlyphIdentifierType::GLYPH_INDEX:
|
||||
return artery_font::CP_INDEXED;
|
||||
case GlyphIdentifierType::UNICODE_CODEPOINT:
|
||||
return artery_font::CP_UNICODE;
|
||||
}
|
||||
return artery_font::CP_UNSPECIFIED;
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
static bool encodeTiff(std::vector<byte> &output, const msdfgen::BitmapConstRef<T, N> &atlas) {
|
||||
// TODO
|
||||
|
|
@ -43,7 +53,7 @@ artery_font::PixelFormat getPixelFormat<float>() {
|
|||
}
|
||||
|
||||
template <typename REAL, typename T, int N>
|
||||
bool exportArteryFont(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, double fontSize, double pxRange, const msdfgen::BitmapConstRef<T, N> &atlas, ImageType imageType, ImageFormat imageFormat, const char *filename) {
|
||||
bool exportArteryFont(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, const msdfgen::BitmapConstRef<T, N> &atlas, const char *filename, const ArteryFontExportProperties &properties) {
|
||||
artery_font::StdArteryFont<REAL> arfont = { };
|
||||
arfont.metadataFormat = artery_font::METADATA_NONE;
|
||||
|
||||
|
|
@ -53,11 +63,11 @@ bool exportArteryFont(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, in
|
|||
return false;
|
||||
double fsScale = 1/fontMetrics.emSize;
|
||||
artery_font::StdFontVariant<REAL> fontVariant = { };
|
||||
fontVariant.codepointType = artery_font::CP_UNICODE;
|
||||
fontVariant.imageType = convertImageType(imageType);
|
||||
fontVariant.metrics.fontSize = REAL(fontSize);
|
||||
if (imageType != ImageType::HARD_MASK)
|
||||
fontVariant.metrics.distanceRange = REAL(pxRange);
|
||||
fontVariant.codepointType = convertCodepointType(properties.glyphIdentifierType);
|
||||
fontVariant.imageType = convertImageType(properties.imageType);
|
||||
fontVariant.metrics.fontSize = REAL(properties.fontSize);
|
||||
if (properties.imageType != ImageType::HARD_MASK)
|
||||
fontVariant.metrics.distanceRange = REAL(properties.pxRange);
|
||||
fontVariant.metrics.emSize = REAL(fsScale*fontMetrics.emSize);
|
||||
fontVariant.metrics.ascender = REAL(fsScale*fontMetrics.ascenderY);
|
||||
fontVariant.metrics.descender = REAL(fsScale*fontMetrics.descenderY);
|
||||
|
|
@ -67,7 +77,7 @@ bool exportArteryFont(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, in
|
|||
fontVariant.glyphs = artery_font::StdList<artery_font::Glyph<REAL> >(glyphCount);
|
||||
for (int i = 0; i < glyphCount; ++i) {
|
||||
artery_font::Glyph<REAL> &glyph = fontVariant.glyphs[i];
|
||||
glyph.codepoint = glyphs[i].getCodepoint();
|
||||
glyph.codepoint = glyphs[i].getIdentifier(properties.glyphIdentifierType);
|
||||
glyph.image = 0;
|
||||
double l, b, r, t;
|
||||
glyphs[i].getQuadPlaneBounds(l, b, r, t);
|
||||
|
|
@ -84,10 +94,10 @@ bool exportArteryFont(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, in
|
|||
glyph.advance.v = REAL(0);
|
||||
for (int j = 0; j < glyphCount; ++j) {
|
||||
double kerning;
|
||||
if (msdfgen::getKerning(kerning, font, glyphs[i].getCodepoint(), glyphs[j].getCodepoint()) && kerning) {
|
||||
if (msdfgen::getKerning(kerning, font, glyphs[i].getGlyphIndex(), glyphs[j].getGlyphIndex()) && kerning) {
|
||||
artery_font::KernPair<REAL> kernPair = { };
|
||||
kernPair.codepoint1 = glyphs[i].getCodepoint();
|
||||
kernPair.codepoint2 = glyphs[j].getCodepoint();
|
||||
kernPair.codepoint1 = glyphs[i].getIdentifier(properties.glyphIdentifierType);
|
||||
kernPair.codepoint2 = glyphs[j].getIdentifier(properties.glyphIdentifierType);
|
||||
kernPair.advance.h = REAL(fsScale*kerning);
|
||||
fontVariant.kernPairs.vector.push_back((artery_font::KernPair<REAL> &&) kernPair);
|
||||
}
|
||||
|
|
@ -101,8 +111,8 @@ bool exportArteryFont(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, in
|
|||
image.width = atlas.width;
|
||||
image.height = atlas.height;
|
||||
image.channels = N;
|
||||
image.imageType = convertImageType(imageType);
|
||||
switch (imageFormat) {
|
||||
image.imageType = convertImageType(properties.imageType);
|
||||
switch (properties.imageFormat) {
|
||||
case ImageFormat::PNG:
|
||||
image.encoding = artery_font::IMAGE_PNG;
|
||||
image.pixelFormat = artery_font::PIXEL_UNSIGNED8;
|
||||
|
|
@ -139,11 +149,11 @@ bool exportArteryFont(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, in
|
|||
return artery_font::writeFile(arfont, filename);
|
||||
}
|
||||
|
||||
template bool exportArteryFont<float>(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, double fontSize, double pxRange, const msdfgen::BitmapConstRef<byte, 1> &atlas, ImageType imageType, ImageFormat imageFormat, const char *filename);
|
||||
template bool exportArteryFont<float>(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, double fontSize, double pxRange, const msdfgen::BitmapConstRef<byte, 3> &atlas, ImageType imageType, ImageFormat imageFormat, const char *filename);
|
||||
template bool exportArteryFont<float>(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, double fontSize, double pxRange, const msdfgen::BitmapConstRef<byte, 4> &atlas, ImageType imageType, ImageFormat imageFormat, const char *filename);
|
||||
template bool exportArteryFont<float>(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, double fontSize, double pxRange, const msdfgen::BitmapConstRef<float, 1> &atlas, ImageType imageType, ImageFormat imageFormat, const char *filename);
|
||||
template bool exportArteryFont<float>(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, double fontSize, double pxRange, const msdfgen::BitmapConstRef<float, 3> &atlas, ImageType imageType, ImageFormat imageFormat, const char *filename);
|
||||
template bool exportArteryFont<float>(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, double fontSize, double pxRange, const msdfgen::BitmapConstRef<float, 4> &atlas, ImageType imageType, ImageFormat imageFormat, const char *filename);
|
||||
template bool exportArteryFont<float>(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, const msdfgen::BitmapConstRef<byte, 1> &atlas, const char *filename, const ArteryFontExportProperties &properties);
|
||||
template bool exportArteryFont<float>(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, const msdfgen::BitmapConstRef<byte, 3> &atlas, const char *filename, const ArteryFontExportProperties &properties);
|
||||
template bool exportArteryFont<float>(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, const msdfgen::BitmapConstRef<byte, 4> &atlas, const char *filename, const ArteryFontExportProperties &properties);
|
||||
template bool exportArteryFont<float>(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, const msdfgen::BitmapConstRef<float, 1> &atlas, const char *filename, const ArteryFontExportProperties &properties);
|
||||
template bool exportArteryFont<float>(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, const msdfgen::BitmapConstRef<float, 3> &atlas, const char *filename, const ArteryFontExportProperties &properties);
|
||||
template bool exportArteryFont<float>(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, const msdfgen::BitmapConstRef<float, 4> &atlas, const char *filename, const ArteryFontExportProperties &properties);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,8 +8,16 @@
|
|||
|
||||
namespace msdf_atlas {
|
||||
|
||||
struct ArteryFontExportProperties {
|
||||
GlyphIdentifierType glyphIdentifierType;
|
||||
double fontSize;
|
||||
double pxRange;
|
||||
ImageType imageType;
|
||||
ImageFormat imageFormat;
|
||||
};
|
||||
|
||||
/// Encodes the atlas bitmap and its layout into an Artery Atlas Font file
|
||||
template <typename REAL, typename T, int N>
|
||||
bool exportArteryFont(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, double fontSize, double pxRange, const msdfgen::BitmapConstRef<T, N> &atlas, ImageType imageType, ImageFormat imageFormat, const char *filename);
|
||||
bool exportArteryFont(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, const msdfgen::BitmapConstRef<T, N> &atlas, const char *filename, const ArteryFontExportProperties &properties);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ static std::string combinePath(const char *basePath, const char *relPath) {
|
|||
return std::string(basePath, lastSlash+1)+relPath;
|
||||
}
|
||||
|
||||
bool Charset::load(const char *filename) {
|
||||
bool Charset::load(const char *filename, bool disableCharLiterals) {
|
||||
|
||||
if (FILE *f = fopen(filename, "rb")) {
|
||||
|
||||
|
|
@ -125,7 +125,7 @@ bool Charset::load(const char *filename) {
|
|||
goto FAIL;
|
||||
switch (state) {
|
||||
case CLEAR:
|
||||
if (cp > 0)
|
||||
if (cp >= 0)
|
||||
add((unicode_t) cp);
|
||||
state = TIGHT;
|
||||
break;
|
||||
|
|
@ -144,7 +144,7 @@ bool Charset::load(const char *filename) {
|
|||
buffer.clear();
|
||||
continue; // next character already read
|
||||
case '\'': // single UTF-8 character
|
||||
if (!(state == CLEAR || state == RANGE_BRACKET || state == RANGE_SEPARATOR))
|
||||
if (!(state == CLEAR || state == RANGE_BRACKET || state == RANGE_SEPARATOR) || disableCharLiterals)
|
||||
goto FAIL;
|
||||
if (!readString(buffer, f, '\''))
|
||||
goto FAIL;
|
||||
|
|
@ -173,7 +173,7 @@ bool Charset::load(const char *filename) {
|
|||
buffer.clear();
|
||||
break;
|
||||
case '"': // string of UTF-8 characters
|
||||
if (state != CLEAR)
|
||||
if (state != CLEAR || disableCharLiterals)
|
||||
goto FAIL;
|
||||
if (!readString(buffer, f, '"'))
|
||||
goto FAIL;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
namespace msdf_atlas {
|
||||
|
||||
bool exportCSV(const GlyphGeometry *glyphs, int glyphCount, double emSize, const char *filename) {
|
||||
bool exportCSV(const GlyphGeometry *glyphs, int glyphCount, GlyphIdentifierType glyphIdentifierType, double emSize, const char *filename) {
|
||||
FILE *f = fopen(filename, "w");
|
||||
if (!f)
|
||||
return false;
|
||||
|
|
@ -13,7 +13,7 @@ bool exportCSV(const GlyphGeometry *glyphs, int glyphCount, double emSize, const
|
|||
double fsScale = 1/emSize;
|
||||
for (int i = 0; i < glyphCount; ++i) {
|
||||
double l, b, r, t;
|
||||
fprintf(f, "%u,%.17g,", glyphs[i].getCodepoint(), fsScale*glyphs[i].getAdvance());
|
||||
fprintf(f, "%d,%.17g,", glyphs[i].getIdentifier(glyphIdentifierType), fsScale*glyphs[i].getAdvance());
|
||||
glyphs[i].getQuadPlaneBounds(l, b, r, t);
|
||||
fprintf(f, "%.17g,%.17g,%.17g,%.17g,", fsScale*l, fsScale*b, fsScale*r, fsScale*t);
|
||||
glyphs[i].getQuadAtlasBounds(l, b, r, t);
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
#include "GlyphGeometry.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
/**
|
||||
* Writes the positioning data and atlas layout of the glyphs into a CSV file
|
||||
* The columns are: Unicode index, horizontal advance, plane bounds (l, b, r, t), atlas bounds (l, b, r, t)
|
||||
* The columns are: glyph identifier (index or Unicode), horizontal advance, plane bounds (l, b, r, t), atlas bounds (l, b, r, t)
|
||||
*/
|
||||
bool exportCSV(const GlyphGeometry *glyphs, int glyphCount, double emSize, const char *filename);
|
||||
bool exportCSV(const GlyphGeometry *glyphs, int glyphCount, GlyphIdentifierType glyphIdentifierType, double emSize, const char *filename);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ static const char * imageTypeString(ImageType type) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
bool exportJSON(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, double fontSize, double pxRange, int atlasWidth, int atlasHeight, ImageType imageType, const char *filename) {
|
||||
bool exportJSON(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, GlyphIdentifierType glyphIdentifierType, double fontSize, double pxRange, int atlasWidth, int atlasHeight, ImageType imageType, const char *filename) {
|
||||
msdfgen::FontMetrics fontMetrics;
|
||||
if (!msdfgen::getFontMetrics(fontMetrics, font))
|
||||
return false;
|
||||
|
|
@ -56,7 +56,14 @@ bool exportJSON(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyp
|
|||
fputs("\"glyphs\":[", f);
|
||||
for (int i = 0; i < glyphCount; ++i) {
|
||||
fputs(i == 0 ? "{" : ",{", f);
|
||||
switch (glyphIdentifierType) {
|
||||
case GlyphIdentifierType::GLYPH_INDEX:
|
||||
fprintf(f, "\"index\":%d,", glyphs[i].getIndex());
|
||||
break;
|
||||
case GlyphIdentifierType::UNICODE_CODEPOINT:
|
||||
fprintf(f, "\"unicode\":%u,", glyphs[i].getCodepoint());
|
||||
break;
|
||||
}
|
||||
fprintf(f, "\"advance\":%.17g", fsScale*glyphs[i].getAdvance());
|
||||
double l, b, r, t;
|
||||
glyphs[i].getQuadPlaneBounds(l, b, r, t);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,6 @@
|
|||
namespace msdf_atlas {
|
||||
|
||||
/// Writes the font and glyph metrics and atlas layout data into a comprehensive JSON file
|
||||
bool exportJSON(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, double fontSize, double pxRange, int atlasWidth, int atlasHeight, ImageType imageType, const char *filename);
|
||||
bool exportJSON(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, GlyphIdentifierType glyphIdentifierType, double fontSize, double pxRange, int atlasWidth, int atlasHeight, ImageType imageType, const char *filename);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@ INPUT SPECIFICATION
|
|||
Specifies the input TrueType / OpenType font file. This is required.
|
||||
-charset <filename>
|
||||
Specifies the input character set. Refer to the documentation for format of charset specification. Defaults to ASCII.
|
||||
-glyphset <filename>
|
||||
Specifies the set of input glyphs as glyph indices within the font file.
|
||||
|
||||
ATLAS CONFIGURATION
|
||||
-type <hardmask / softmask / sdf / psdf / msdf / mtsdf>
|
||||
|
|
@ -145,7 +147,19 @@ static bool cmpExtension(const char *path, const char *ext) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static void loadGlyphs(std::vector<GlyphGeometry> &glyphs, msdfgen::FontHandle *font, const Charset &charset, bool preprocessGeometry) {
|
||||
static void loadGlyphsByIndex(std::vector<GlyphGeometry> &glyphs, msdfgen::FontHandle *font, const Charset &charset, bool preprocessGeometry) {
|
||||
glyphs.clear();
|
||||
glyphs.reserve(charset.size());
|
||||
for (unicode_t cp : charset) {
|
||||
GlyphGeometry glyph;
|
||||
if (glyph.load(font, msdfgen::GlyphIndex(cp), preprocessGeometry))
|
||||
glyphs.push_back((GlyphGeometry &&) glyph);
|
||||
else
|
||||
printf("Glyph # 0x%X missing\n", cp);
|
||||
}
|
||||
}
|
||||
|
||||
static void loadGlyphsByUnicode(std::vector<GlyphGeometry> &glyphs, msdfgen::FontHandle *font, const Charset &charset, bool preprocessGeometry) {
|
||||
glyphs.clear();
|
||||
glyphs.reserve(charset.size());
|
||||
for (unicode_t cp : charset) {
|
||||
|
|
@ -158,6 +172,7 @@ static void loadGlyphs(std::vector<GlyphGeometry> &glyphs, msdfgen::FontHandle *
|
|||
}
|
||||
|
||||
struct Configuration {
|
||||
GlyphIdentifierType glyphIdentifierType;
|
||||
ImageType imageType;
|
||||
ImageFormat imageFormat;
|
||||
int width, height;
|
||||
|
|
@ -197,7 +212,13 @@ static bool makeAtlas(const std::vector<GlyphGeometry> &glyphs, msdfgen::FontHan
|
|||
}
|
||||
|
||||
if (config.arteryFontFilename) {
|
||||
if (exportArteryFont<float>(font, glyphs.data(), glyphs.size(), config.emSize, config.pxRange, bitmap, config.imageType, config.imageFormat, config.arteryFontFilename))
|
||||
ArteryFontExportProperties arfontProps;
|
||||
arfontProps.glyphIdentifierType = config.glyphIdentifierType;
|
||||
arfontProps.fontSize = config.emSize;
|
||||
arfontProps.pxRange = config.pxRange;
|
||||
arfontProps.imageType = config.imageType;
|
||||
arfontProps.imageFormat = config.imageFormat;
|
||||
if (exportArteryFont<float>(font, glyphs.data(), glyphs.size(), bitmap, config.arteryFontFilename, arfontProps))
|
||||
puts("Artery Font file generated.");
|
||||
else {
|
||||
success = false;
|
||||
|
|
@ -215,6 +236,7 @@ int main(int argc, const char * const *argv) {
|
|||
Configuration config = { };
|
||||
const char *fontFilename = nullptr;
|
||||
const char *charsetFilename = nullptr;
|
||||
config.glyphIdentifierType = GlyphIdentifierType::UNICODE_CODEPOINT;
|
||||
config.imageType = ImageType::MSDF;
|
||||
config.imageFormat = ImageFormat::UNSPECIFIED;
|
||||
const char *imageFormatName = nullptr;
|
||||
|
|
@ -299,6 +321,13 @@ int main(int argc, const char * const *argv) {
|
|||
}
|
||||
ARG_CASE("-charset", 1) {
|
||||
charsetFilename = argv[++argPos];
|
||||
config.glyphIdentifierType = GlyphIdentifierType::UNICODE_CODEPOINT;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-glyphset", 1) {
|
||||
charsetFilename = argv[++argPos];
|
||||
config.glyphIdentifierType = GlyphIdentifierType::GLYPH_INDEX;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -593,17 +622,24 @@ int main(int argc, const char * const *argv) {
|
|||
// Load character set
|
||||
Charset charset;
|
||||
if (charsetFilename) {
|
||||
if (!charset.load(charsetFilename))
|
||||
ABORT("Failed to load character set specification.");
|
||||
if (!charset.load(charsetFilename, config.glyphIdentifierType != GlyphIdentifierType::UNICODE_CODEPOINT))
|
||||
ABORT(config.glyphIdentifierType == GlyphIdentifierType::GLYPH_INDEX ? "Failed to load glyph set specification." : "Failed to load character set specification.");
|
||||
} else
|
||||
charset = Charset::ASCII;
|
||||
if (charset.empty())
|
||||
ABORT("No character set loaded.");
|
||||
|
||||
// Load glyphs
|
||||
std::vector<GlyphGeometry> glyphs;
|
||||
loadGlyphs(glyphs, font, charset, config.preprocessGeometry);
|
||||
printf("Loaded geometry of %d out of %d characters.\n", (int) glyphs.size(), (int) charset.size());
|
||||
switch (config.glyphIdentifierType) {
|
||||
case GlyphIdentifierType::GLYPH_INDEX:
|
||||
loadGlyphsByIndex(glyphs, font, charset, config.preprocessGeometry);
|
||||
break;
|
||||
case GlyphIdentifierType::UNICODE_CODEPOINT:
|
||||
loadGlyphsByUnicode(glyphs, font, charset, config.preprocessGeometry);
|
||||
break;
|
||||
}
|
||||
if (glyphs.empty())
|
||||
ABORT("No glyphs loaded.");
|
||||
printf("Loaded geometry of %d out of %d %s.\n", (int) glyphs.size(), (int) charset.size(), config.glyphIdentifierType == GlyphIdentifierType::GLYPH_INDEX ? "glyphs" : "characters");
|
||||
|
||||
// Determine final atlas dimensions, scale and range, pack glyphs
|
||||
{
|
||||
|
|
@ -709,7 +745,7 @@ int main(int argc, const char * const *argv) {
|
|||
}
|
||||
|
||||
if (config.csvFilename) {
|
||||
if (exportCSV(glyphs.data(), glyphs.size(), fontMetrics.emSize, config.csvFilename))
|
||||
if (exportCSV(glyphs.data(), glyphs.size(), config.glyphIdentifierType, fontMetrics.emSize, config.csvFilename))
|
||||
puts("Glyph layout written into CSV file.");
|
||||
else {
|
||||
result = 1;
|
||||
|
|
@ -717,7 +753,7 @@ int main(int argc, const char * const *argv) {
|
|||
}
|
||||
}
|
||||
if (config.jsonFilename) {
|
||||
if (exportJSON(font, glyphs.data(), glyphs.size(), config.emSize, config.pxRange, config.width, config.height, config.imageType, config.jsonFilename))
|
||||
if (exportJSON(font, glyphs.data(), glyphs.size(), config.glyphIdentifierType, config.emSize, config.pxRange, config.width, config.height, config.imageType, config.jsonFilename))
|
||||
puts("Glyph layout and metadata written into JSON file.");
|
||||
else {
|
||||
result = 1;
|
||||
|
|
@ -726,6 +762,7 @@ int main(int argc, const char * const *argv) {
|
|||
}
|
||||
|
||||
if (config.shadronPreviewFilename && config.shadronPreviewText) {
|
||||
if (config.glyphIdentifierType == GlyphIdentifierType::UNICODE_CODEPOINT) {
|
||||
std::vector<unicode_t> previewText;
|
||||
utf8Decode(previewText, config.shadronPreviewText);
|
||||
previewText.push_back(0);
|
||||
|
|
@ -735,6 +772,10 @@ int main(int argc, const char * const *argv) {
|
|||
result = 1;
|
||||
puts("Failed to generate Shadron preview file.");
|
||||
}
|
||||
} else {
|
||||
result = 1;
|
||||
puts("Shadron preview not supported in -glyphset mode.");
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
|||
|
|
@ -37,4 +37,10 @@ enum class ImageFormat {
|
|||
BINARY_FLOAT_BE
|
||||
};
|
||||
|
||||
/// Glyph identification
|
||||
enum class GlyphIdentifierType {
|
||||
GLYPH_INDEX,
|
||||
UNICODE_CODEPOINT
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue