Support for multiple fonts in one atlas
This commit is contained in:
parent
e44853e47e
commit
690ae5fb16
|
|
@ -45,6 +45,8 @@ Use the following command line arguments for the standalone version of the atlas
|
|||
- `-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).
|
||||
- `-fontscale <scale>` – applies a scaling transformation to the font's glyphs. Mainly to be used to generate multiple sizes in a single atlas, otherwise use [`-size`](#glyph-configuration).
|
||||
- `-and` – separates multiple inputs to be combined into a single atlas.
|
||||
|
||||
### Bitmap atlas type
|
||||
|
||||
|
|
|
|||
|
|
@ -314,6 +314,7 @@
|
|||
<ClCompile Include="msdf-atlas-gen\charset-parser.cpp" />
|
||||
<ClCompile Include="msdf-atlas-gen\Charset.cpp" />
|
||||
<ClCompile Include="msdf-atlas-gen\csv-export.cpp" />
|
||||
<ClCompile Include="msdf-atlas-gen\FontGeometry.cpp" />
|
||||
<ClCompile Include="msdf-atlas-gen\glyph-generators.cpp" />
|
||||
<ClCompile Include="msdf-atlas-gen\GlyphGeometry.cpp" />
|
||||
<ClCompile Include="msdf-atlas-gen\image-encode.cpp" />
|
||||
|
|
@ -337,6 +338,7 @@
|
|||
<ClInclude Include="msdf-atlas-gen\csv-export.h" />
|
||||
<ClInclude Include="msdf-atlas-gen\DynamicAtlas.h" />
|
||||
<ClInclude Include="msdf-atlas-gen\DynamicAtlas.hpp" />
|
||||
<ClInclude Include="msdf-atlas-gen\FontGeometry.h" />
|
||||
<ClInclude Include="msdf-atlas-gen\glyph-generators.h" />
|
||||
<ClInclude Include="msdf-atlas-gen\image-encode.h" />
|
||||
<ClInclude Include="msdf-atlas-gen\Charset.h" />
|
||||
|
|
|
|||
|
|
@ -66,6 +66,9 @@
|
|||
<ClCompile Include="msdf-atlas-gen\Workload.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="msdf-atlas-gen\FontGeometry.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="resource.h">
|
||||
|
|
@ -164,6 +167,9 @@
|
|||
<ClInclude Include="msdf-atlas-gen\Workload.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="msdf-atlas-gen\FontGeometry.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="msdf-atlas-gen.rc">
|
||||
|
|
|
|||
|
|
@ -0,0 +1,172 @@
|
|||
|
||||
#include "FontGeometry.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
FontGeometry::GlyphRange::GlyphRange() : glyphs(), rangeStart(), rangeEnd() { }
|
||||
|
||||
FontGeometry::GlyphRange::GlyphRange(const std::vector<GlyphGeometry> *glyphs, size_t rangeStart, size_t rangeEnd) : glyphs(glyphs), rangeStart(rangeStart), rangeEnd(rangeEnd) { }
|
||||
|
||||
size_t FontGeometry::GlyphRange::size() const {
|
||||
return glyphs->size();
|
||||
}
|
||||
|
||||
bool FontGeometry::GlyphRange::empty() const {
|
||||
return glyphs->empty();
|
||||
}
|
||||
|
||||
const GlyphGeometry * FontGeometry::GlyphRange::begin() const {
|
||||
return glyphs->data()+rangeStart;
|
||||
}
|
||||
|
||||
const GlyphGeometry * FontGeometry::GlyphRange::end() const {
|
||||
return glyphs->data()+rangeEnd;
|
||||
}
|
||||
|
||||
FontGeometry::FontGeometry() : geometryScale(1), metrics(), preferredIdentifierType(GlyphIdentifierType::UNICODE_CODEPOINT), glyphs(&ownGlyphs), rangeStart(glyphs->size()), rangeEnd(glyphs->size()) { }
|
||||
|
||||
FontGeometry::FontGeometry(std::vector<GlyphGeometry> *glyphStorage) : geometryScale(1), metrics(), preferredIdentifierType(GlyphIdentifierType::UNICODE_CODEPOINT), glyphs(glyphStorage), rangeStart(glyphs->size()), rangeEnd(glyphs->size()) { }
|
||||
|
||||
int FontGeometry::loadGlyphset(msdfgen::FontHandle *font, double fontScale, const Charset &glyphset, bool preprocessGeometry, bool enableKerning) {
|
||||
if (!(glyphs->size() == rangeEnd && loadMetrics(font, fontScale)))
|
||||
return -1;
|
||||
glyphs->reserve(glyphs->size()+glyphset.size());
|
||||
int loaded = 0;
|
||||
for (unicode_t index : glyphset) {
|
||||
GlyphGeometry glyph;
|
||||
if (glyph.load(font, geometryScale, msdfgen::GlyphIndex(index), preprocessGeometry)) {
|
||||
addGlyph((GlyphGeometry &&) glyph);
|
||||
++loaded;
|
||||
}
|
||||
}
|
||||
if (enableKerning)
|
||||
loadKerning(font);
|
||||
preferredIdentifierType = GlyphIdentifierType::GLYPH_INDEX;
|
||||
return loaded;
|
||||
}
|
||||
|
||||
int FontGeometry::loadCharset(msdfgen::FontHandle *font, double fontScale, const Charset &charset, bool preprocessGeometry, bool enableKerning) {
|
||||
if (!(glyphs->size() == rangeEnd && loadMetrics(font, fontScale)))
|
||||
return -1;
|
||||
glyphs->reserve(glyphs->size()+charset.size());
|
||||
int loaded = 0;
|
||||
for (unicode_t cp : charset) {
|
||||
GlyphGeometry glyph;
|
||||
if (glyph.load(font, geometryScale, cp, preprocessGeometry)) {
|
||||
addGlyph((GlyphGeometry &&) glyph);
|
||||
++loaded;
|
||||
}
|
||||
}
|
||||
if (enableKerning)
|
||||
loadKerning(font);
|
||||
preferredIdentifierType = GlyphIdentifierType::UNICODE_CODEPOINT;
|
||||
return loaded;
|
||||
}
|
||||
|
||||
bool FontGeometry::loadMetrics(msdfgen::FontHandle *font, double fontScale) {
|
||||
if (!msdfgen::getFontMetrics(metrics, font))
|
||||
return false;
|
||||
if (metrics.emSize <= 0)
|
||||
metrics.emSize = MSDF_ATLAS_DEFAULT_EM_SIZE;
|
||||
geometryScale = fontScale/metrics.emSize;
|
||||
metrics.emSize *= geometryScale;
|
||||
metrics.ascenderY *= geometryScale;
|
||||
metrics.descenderY *= geometryScale;
|
||||
metrics.lineHeight *= geometryScale;
|
||||
metrics.underlineY *= geometryScale;
|
||||
metrics.underlineThickness *= geometryScale;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FontGeometry::addGlyph(const GlyphGeometry &glyph) {
|
||||
if (glyphs->size() != rangeEnd)
|
||||
return false;
|
||||
glyphsByIndex.insert(std::make_pair(glyph.getIndex(), rangeEnd));
|
||||
if (glyph.getCodepoint())
|
||||
glyphsByCodepoint.insert(std::make_pair(glyph.getCodepoint(), rangeEnd));
|
||||
glyphs->push_back(glyph);
|
||||
++rangeEnd;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FontGeometry::addGlyph(GlyphGeometry &&glyph) {
|
||||
if (glyphs->size() != rangeEnd)
|
||||
return false;
|
||||
glyphsByIndex.insert(std::make_pair(glyph.getIndex(), rangeEnd));
|
||||
if (glyph.getCodepoint())
|
||||
glyphsByCodepoint.insert(std::make_pair(glyph.getCodepoint(), rangeEnd));
|
||||
glyphs->push_back((GlyphGeometry &&) glyph);
|
||||
++rangeEnd;
|
||||
return true;
|
||||
}
|
||||
|
||||
int FontGeometry::loadKerning(msdfgen::FontHandle *font) {
|
||||
int loaded = 0;
|
||||
for (size_t i = rangeStart; i < rangeEnd; ++i)
|
||||
for (size_t j = rangeStart; j < rangeEnd; ++j) {
|
||||
double advance;
|
||||
if (msdfgen::getKerning(advance, font, (*glyphs)[i].getGlyphIndex(), (*glyphs)[j].getGlyphIndex()) && advance) {
|
||||
kerning[std::make_pair<int, int>((*glyphs)[i].getIndex(), (*glyphs)[j].getIndex())] = geometryScale*advance;
|
||||
++loaded;
|
||||
}
|
||||
}
|
||||
return loaded;
|
||||
}
|
||||
|
||||
double FontGeometry::getGeometryScale() const {
|
||||
return geometryScale;
|
||||
}
|
||||
|
||||
const msdfgen::FontMetrics & FontGeometry::getMetrics() const {
|
||||
return metrics;
|
||||
}
|
||||
|
||||
GlyphIdentifierType FontGeometry::getPreferredIdentifierType() const {
|
||||
return preferredIdentifierType;
|
||||
}
|
||||
|
||||
FontGeometry::GlyphRange FontGeometry::getGlyphs() const {
|
||||
return GlyphRange(glyphs, rangeStart, rangeEnd);
|
||||
}
|
||||
|
||||
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 {
|
||||
std::map<unicode_t, size_t>::const_iterator it = glyphsByCodepoint.find(codepoint);
|
||||
if (it != glyphsByCodepoint.end())
|
||||
return &(*glyphs)[it->second];
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool FontGeometry::getAdvance(double &advance, msdfgen::GlyphIndex index1, msdfgen::GlyphIndex index2) const {
|
||||
const GlyphGeometry *glyph1 = getGlyph(index1);
|
||||
if (!glyph1)
|
||||
return false;
|
||||
advance = glyph1->getAdvance();
|
||||
std::map<std::pair<int, int>, double>::const_iterator it = kerning.find(std::make_pair<int, int>(index1.getIndex(), index2.getIndex()));
|
||||
if (it != kerning.end())
|
||||
advance += it->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FontGeometry::getAdvance(double &advance, unicode_t codepoint1, unicode_t codepoint2) const {
|
||||
const GlyphGeometry *glyph1, *glyph2;
|
||||
if (!((glyph1 = getGlyph(codepoint1)) && (glyph2 = getGlyph(codepoint2))))
|
||||
return false;
|
||||
advance = glyph1->getAdvance();
|
||||
std::map<std::pair<int, int>, double>::const_iterator it = kerning.find(std::make_pair<int, int>(glyph1->getIndex(), glyph2->getIndex()));
|
||||
if (it != kerning.end())
|
||||
advance += it->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::map<std::pair<int, int>, double> & FontGeometry::getKerning() const {
|
||||
return kerning;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <msdfgen.h>
|
||||
#include <msdfgen-ext.h>
|
||||
#include "types.h"
|
||||
#include "GlyphGeometry.h"
|
||||
#include "Charset.h"
|
||||
|
||||
#define MSDF_ATLAS_DEFAULT_EM_SIZE 32.0
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
/// Represents the geometry of all glyphs of a given font or font variant
|
||||
class FontGeometry {
|
||||
|
||||
public:
|
||||
class GlyphRange {
|
||||
public:
|
||||
GlyphRange();
|
||||
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;
|
||||
private:
|
||||
const std::vector<GlyphGeometry> *glyphs;
|
||||
size_t rangeStart, rangeEnd;
|
||||
};
|
||||
|
||||
FontGeometry();
|
||||
explicit FontGeometry(std::vector<GlyphGeometry> *glyphStorage);
|
||||
|
||||
/// Loads all glyphs in a glyphset (Charset elements are glyph indices), returns the number of successfully loaded glyphs
|
||||
int loadGlyphset(msdfgen::FontHandle *font, double fontScale, const Charset &glyphset, bool preprocessGeometry = true, bool enableKerning = true);
|
||||
/// Loads all glyphs in a charset (Charset elements are Unicode codepoints), returns the number of successfully loaded glyphs
|
||||
int loadCharset(msdfgen::FontHandle *font, double fontScale, const Charset &charset, bool preprocessGeometry = true, bool enableKerning = true);
|
||||
|
||||
/// Only loads font metrics and geometry scale from font
|
||||
bool loadMetrics(msdfgen::FontHandle *font, double fontScale);
|
||||
/// Adds a loaded glyph
|
||||
bool addGlyph(const GlyphGeometry &glyph);
|
||||
bool addGlyph(GlyphGeometry &&glyph);
|
||||
/// Loads kerning pairs for all glyphs that are currently present, returns the number of loaded kerning pairs
|
||||
int loadKerning(msdfgen::FontHandle *font);
|
||||
|
||||
/// Returns the geometry scale to be used when loading glyphs
|
||||
double getGeometryScale() const;
|
||||
/// Returns the processed font metrics
|
||||
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;
|
||||
/// 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;
|
||||
|
||||
private:
|
||||
double geometryScale;
|
||||
msdfgen::FontMetrics metrics;
|
||||
GlyphIdentifierType preferredIdentifierType;
|
||||
std::vector<GlyphGeometry> *glyphs;
|
||||
size_t rangeStart, rangeEnd;
|
||||
std::map<int, size_t> glyphsByIndex;
|
||||
std::map<unicode_t, size_t> glyphsByCodepoint;
|
||||
std::map<std::pair<int, int>, double> kerning;
|
||||
std::vector<GlyphGeometry> ownGlyphs;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -6,12 +6,14 @@
|
|||
|
||||
namespace msdf_atlas {
|
||||
|
||||
GlyphGeometry::GlyphGeometry() : index(), codepoint(), bounds(), advance(), box() { }
|
||||
GlyphGeometry::GlyphGeometry() : index(), codepoint(), geometryScale(), bounds(), advance(), box() { }
|
||||
|
||||
bool GlyphGeometry::load(msdfgen::FontHandle *font, msdfgen::GlyphIndex index, bool preprocessGeometry) {
|
||||
bool GlyphGeometry::load(msdfgen::FontHandle *font, double geometryScale, msdfgen::GlyphIndex index, bool preprocessGeometry) {
|
||||
if (font && msdfgen::loadGlyph(shape, font, index, &advance) && shape.validate()) {
|
||||
this->index = index.getIndex();
|
||||
this->geometryScale = geometryScale;
|
||||
codepoint = 0;
|
||||
advance *= geometryScale;
|
||||
#ifdef MSDFGEN_USE_SKIA
|
||||
if (preprocessGeometry)
|
||||
msdfgen::resolveShapeGeometry(shape);
|
||||
|
|
@ -34,10 +36,10 @@ bool GlyphGeometry::load(msdfgen::FontHandle *font, msdfgen::GlyphIndex index, b
|
|||
return false;
|
||||
}
|
||||
|
||||
bool GlyphGeometry::load(msdfgen::FontHandle *font, unicode_t codepoint, bool preprocessGeometry) {
|
||||
bool GlyphGeometry::load(msdfgen::FontHandle *font, double geometryScale, unicode_t codepoint, bool preprocessGeometry) {
|
||||
msdfgen::GlyphIndex index;
|
||||
if (msdfgen::getGlyphIndex(index, font, codepoint)) {
|
||||
if (load(font, index, preprocessGeometry)) {
|
||||
if (load(font, geometryScale, index, preprocessGeometry)) {
|
||||
this->codepoint = codepoint;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -50,6 +52,8 @@ void GlyphGeometry::edgeColoring(double angleThreshold, unsigned long long seed)
|
|||
}
|
||||
|
||||
void GlyphGeometry::wrapBox(double scale, double range, double miterLimit) {
|
||||
scale *= geometryScale;
|
||||
range /= geometryScale;
|
||||
box.range = range;
|
||||
box.scale = scale;
|
||||
if (bounds.l < bounds.r && bounds.b < bounds.t) {
|
||||
|
|
@ -127,10 +131,11 @@ msdfgen::Vector2 GlyphGeometry::getBoxTranslate() const {
|
|||
|
||||
void GlyphGeometry::getQuadPlaneBounds(double &l, double &b, double &r, double &t) const {
|
||||
if (box.rect.w > 0 && box.rect.h > 0) {
|
||||
l = -box.translate.x+.5/box.scale;
|
||||
b = -box.translate.y+.5/box.scale;
|
||||
r = -box.translate.x+(box.rect.w-.5)/box.scale;
|
||||
t = -box.translate.y+(box.rect.h-.5)/box.scale;
|
||||
double invBoxScale = 1/box.scale;
|
||||
l = geometryScale*(-box.translate.x+.5*invBoxScale);
|
||||
b = geometryScale*(-box.translate.y+.5*invBoxScale);
|
||||
r = geometryScale*(-box.translate.x+(box.rect.w-.5)*invBoxScale);
|
||||
t = geometryScale*(-box.translate.y+(box.rect.h-.5)*invBoxScale);
|
||||
} else
|
||||
l = 0, b = 0, r = 0, t = 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,14 +8,14 @@
|
|||
|
||||
namespace msdf_atlas {
|
||||
|
||||
/// Represent's the shape geometry of a single glyph as well as its configuration
|
||||
/// Represents the shape geometry of a single glyph as well as its configuration
|
||||
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);
|
||||
bool load(msdfgen::FontHandle *font, double geometryScale, msdfgen::GlyphIndex index, bool preprocessGeometry = true);
|
||||
bool load(msdfgen::FontHandle *font, double geometryScale, unicode_t codepoint, bool preprocessGeometry = true);
|
||||
/// Applies edge coloring to glyph shape
|
||||
void edgeColoring(double angleThreshold, unsigned long long seed);
|
||||
/// Computes the dimensions of the glyph's box as well as the transformation for the generator function
|
||||
|
|
@ -56,6 +56,7 @@ public:
|
|||
private:
|
||||
int index;
|
||||
unicode_t codepoint;
|
||||
double geometryScale;
|
||||
msdfgen::Shape shape;
|
||||
msdfgen::Shape::Bounds bounds;
|
||||
double advance;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <artery-font/std-artery-font.h>
|
||||
#include <artery-font/stdio-serialization.h>
|
||||
#include "GlyphGeometry.h"
|
||||
#include "image-encode.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
|
@ -53,55 +54,69 @@ artery_font::PixelFormat getPixelFormat<float>() {
|
|||
}
|
||||
|
||||
template <typename REAL, typename T, int N>
|
||||
bool exportArteryFont(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, const msdfgen::BitmapConstRef<T, N> &atlas, const char *filename, const ArteryFontExportProperties &properties) {
|
||||
bool exportArteryFont(const FontGeometry *fonts, int fontCount, const msdfgen::BitmapConstRef<T, N> &atlas, const char *filename, const ArteryFontExportProperties &properties) {
|
||||
artery_font::StdArteryFont<REAL> arfont = { };
|
||||
arfont.metadataFormat = artery_font::METADATA_NONE;
|
||||
|
||||
if (glyphCount > 0) {
|
||||
msdfgen::FontMetrics fontMetrics;
|
||||
if (!msdfgen::getFontMetrics(fontMetrics, font))
|
||||
return false;
|
||||
double fsScale = 1/fontMetrics.emSize;
|
||||
for (int i = 0; i < fontCount; ++i) {
|
||||
const FontGeometry &font = fonts[i];
|
||||
GlyphIdentifierType identifierType = font.getPreferredIdentifierType();
|
||||
const msdfgen::FontMetrics &fontMetrics = font.getMetrics();
|
||||
artery_font::StdFontVariant<REAL> fontVariant = { };
|
||||
fontVariant.codepointType = convertCodepointType(properties.glyphIdentifierType);
|
||||
fontVariant.codepointType = convertCodepointType(identifierType);
|
||||
fontVariant.imageType = convertImageType(properties.imageType);
|
||||
fontVariant.metrics.fontSize = REAL(properties.fontSize);
|
||||
fontVariant.metrics.fontSize = REAL(properties.fontSize*fontMetrics.emSize);
|
||||
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);
|
||||
fontVariant.metrics.lineHeight = REAL(fsScale*fontMetrics.lineHeight);
|
||||
fontVariant.metrics.underlineY = REAL(fsScale*fontMetrics.underlineY);
|
||||
fontVariant.metrics.underlineThickness = REAL(fsScale*fontMetrics.underlineThickness);
|
||||
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].getIdentifier(properties.glyphIdentifierType);
|
||||
fontVariant.metrics.emSize = REAL(fontMetrics.emSize);
|
||||
fontVariant.metrics.ascender = REAL(fontMetrics.ascenderY);
|
||||
fontVariant.metrics.descender = REAL(fontMetrics.descenderY);
|
||||
fontVariant.metrics.lineHeight = REAL(fontMetrics.lineHeight);
|
||||
fontVariant.metrics.underlineY = REAL(fontMetrics.underlineY);
|
||||
fontVariant.metrics.underlineThickness = REAL(fontMetrics.underlineThickness);
|
||||
fontVariant.glyphs = artery_font::StdList<artery_font::Glyph<REAL> >(font.getGlyphs().size());
|
||||
int j = 0;
|
||||
for (const GlyphGeometry &glyphGeom : font.getGlyphs()) {
|
||||
artery_font::Glyph<REAL> &glyph = fontVariant.glyphs[j++];
|
||||
glyph.codepoint = glyphGeom.getIdentifier(identifierType);
|
||||
glyph.image = 0;
|
||||
double l, b, r, t;
|
||||
glyphs[i].getQuadPlaneBounds(l, b, r, t);
|
||||
glyph.planeBounds.l = REAL(fsScale*l);
|
||||
glyph.planeBounds.b = REAL(fsScale*b);
|
||||
glyph.planeBounds.r = REAL(fsScale*r);
|
||||
glyph.planeBounds.t = REAL(fsScale*t);
|
||||
glyphs[i].getQuadAtlasBounds(l, b, r, t);
|
||||
glyphGeom.getQuadPlaneBounds(l, b, r, t);
|
||||
glyph.planeBounds.l = REAL(l);
|
||||
glyph.planeBounds.b = REAL(b);
|
||||
glyph.planeBounds.r = REAL(r);
|
||||
glyph.planeBounds.t = REAL(t);
|
||||
glyphGeom.getQuadAtlasBounds(l, b, r, t);
|
||||
glyph.imageBounds.l = REAL(l);
|
||||
glyph.imageBounds.b = REAL(b);
|
||||
glyph.imageBounds.r = REAL(r);
|
||||
glyph.imageBounds.t = REAL(t);
|
||||
glyph.advance.h = REAL(fsScale*glyphs[i].getAdvance());
|
||||
glyph.advance.h = REAL(glyphGeom.getAdvance());
|
||||
glyph.advance.v = REAL(0);
|
||||
for (int j = 0; j < glyphCount; ++j) {
|
||||
double kerning;
|
||||
if (msdfgen::getKerning(kerning, font, glyphs[i].getGlyphIndex(), glyphs[j].getGlyphIndex()) && kerning) {
|
||||
}
|
||||
switch (identifierType) {
|
||||
case GlyphIdentifierType::GLYPH_INDEX:
|
||||
for (const std::pair<std::pair<int, int>, double> &elem : font.getKerning()) {
|
||||
artery_font::KernPair<REAL> kernPair = { };
|
||||
kernPair.codepoint1 = glyphs[i].getIdentifier(properties.glyphIdentifierType);
|
||||
kernPair.codepoint2 = glyphs[j].getIdentifier(properties.glyphIdentifierType);
|
||||
kernPair.advance.h = REAL(fsScale*kerning);
|
||||
kernPair.codepoint1 = elem.first.first;
|
||||
kernPair.codepoint2 = elem.first.second;
|
||||
kernPair.advance.h = REAL(elem.second);
|
||||
fontVariant.kernPairs.vector.push_back((artery_font::KernPair<REAL> &&) kernPair);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GlyphIdentifierType::UNICODE_CODEPOINT:
|
||||
for (const std::pair<std::pair<int, int>, double> &elem : font.getKerning()) {
|
||||
const GlyphGeometry *glyph1 = font.getGlyph(msdfgen::GlyphIndex(elem.first.first));
|
||||
const GlyphGeometry *glyph2 = font.getGlyph(msdfgen::GlyphIndex(elem.first.second));
|
||||
if (glyph1 && glyph2 && glyph1->getCodepoint() && glyph2->getCodepoint()) {
|
||||
artery_font::KernPair<REAL> kernPair = { };
|
||||
kernPair.codepoint1 = glyph1->getCodepoint();
|
||||
kernPair.codepoint2 = glyph2->getCodepoint();
|
||||
kernPair.advance.h = REAL(elem.second);
|
||||
fontVariant.kernPairs.vector.push_back((artery_font::KernPair<REAL> &&) kernPair);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
arfont.variants.vector.push_back((artery_font::StdFontVariant<REAL> &&) fontVariant);
|
||||
}
|
||||
|
|
@ -149,11 +164,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, 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);
|
||||
template bool exportArteryFont<float>(const FontGeometry *fonts, int fontCount, const msdfgen::BitmapConstRef<byte, 1> &atlas, const char *filename, const ArteryFontExportProperties &properties);
|
||||
template bool exportArteryFont<float>(const FontGeometry *fonts, int fontCount, const msdfgen::BitmapConstRef<byte, 3> &atlas, const char *filename, const ArteryFontExportProperties &properties);
|
||||
template bool exportArteryFont<float>(const FontGeometry *fonts, int fontCount, const msdfgen::BitmapConstRef<byte, 4> &atlas, const char *filename, const ArteryFontExportProperties &properties);
|
||||
template bool exportArteryFont<float>(const FontGeometry *fonts, int fontCount, const msdfgen::BitmapConstRef<float, 1> &atlas, const char *filename, const ArteryFontExportProperties &properties);
|
||||
template bool exportArteryFont<float>(const FontGeometry *fonts, int fontCount, const msdfgen::BitmapConstRef<float, 3> &atlas, const char *filename, const ArteryFontExportProperties &properties);
|
||||
template bool exportArteryFont<float>(const FontGeometry *fonts, int fontCount, const msdfgen::BitmapConstRef<float, 4> &atlas, const char *filename, const ArteryFontExportProperties &properties);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,12 +4,11 @@
|
|||
#include <msdfgen.h>
|
||||
#include <msdfgen-ext.h>
|
||||
#include "types.h"
|
||||
#include "GlyphGeometry.h"
|
||||
#include "FontGeometry.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
struct ArteryFontExportProperties {
|
||||
GlyphIdentifierType glyphIdentifierType;
|
||||
double fontSize;
|
||||
double pxRange;
|
||||
ImageType imageType;
|
||||
|
|
@ -18,6 +17,6 @@ struct ArteryFontExportProperties {
|
|||
|
||||
/// 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, const msdfgen::BitmapConstRef<T, N> &atlas, const char *filename, const ArteryFontExportProperties &properties);
|
||||
bool exportArteryFont(const FontGeometry *fonts, int fontCount, const msdfgen::BitmapConstRef<T, N> &atlas, const char *filename, const ArteryFontExportProperties &properties);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,22 +2,26 @@
|
|||
#include "csv-export.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include "GlyphGeometry.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
bool exportCSV(const GlyphGeometry *glyphs, int glyphCount, GlyphIdentifierType glyphIdentifierType, double emSize, const char *filename) {
|
||||
bool exportCSV(const FontGeometry *fonts, int fontCount, const char *filename) {
|
||||
FILE *f = fopen(filename, "w");
|
||||
if (!f)
|
||||
return false;
|
||||
|
||||
double fsScale = 1/emSize;
|
||||
for (int i = 0; i < glyphCount; ++i) {
|
||||
double l, b, r, t;
|
||||
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);
|
||||
fprintf(f, "%.17g,%.17g,%.17g,%.17g\n", l, b, r, t);
|
||||
for (int i = 0; i < fontCount; ++i) {
|
||||
for (const GlyphGeometry &glyph : fonts[i].getGlyphs()) {
|
||||
double l, b, r, t;
|
||||
if (fontCount > 1)
|
||||
fprintf(f, "%d,", i);
|
||||
fprintf(f, "%d,%.17g,", glyph.getIdentifier(fonts[i].getPreferredIdentifierType()), glyph.getAdvance());
|
||||
glyph.getQuadPlaneBounds(l, b, r, t);
|
||||
fprintf(f, "%.17g,%.17g,%.17g,%.17g,", l, b, r, t);
|
||||
glyph.getQuadAtlasBounds(l, b, r, t);
|
||||
fprintf(f, "%.17g,%.17g,%.17g,%.17g\n", l, b, r, t);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
|
|
|||
|
|
@ -1,15 +1,14 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
#include "GlyphGeometry.h"
|
||||
#include "FontGeometry.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
/**
|
||||
* Writes the positioning data and atlas layout of the glyphs into a CSV file
|
||||
* The columns are: glyph identifier (index or Unicode), horizontal advance, plane bounds (l, b, r, t), atlas bounds (l, b, r, t)
|
||||
* The columns are: font variant index (if fontCount > 1), 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, GlyphIdentifierType glyphIdentifierType, double emSize, const char *filename);
|
||||
bool exportCSV(const FontGeometry *fonts, int fontCount, const char *filename);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
|
||||
#include "json-export.h"
|
||||
|
||||
#include "GlyphGeometry.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
static const char * imageTypeString(ImageType type) {
|
||||
|
|
@ -21,12 +23,7 @@ static const char * imageTypeString(ImageType type) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
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;
|
||||
double fsScale = 1/fontMetrics.emSize;
|
||||
|
||||
bool exportJSON(const FontGeometry *fonts, int fontCount, double fontSize, double pxRange, int atlasWidth, int atlasHeight, ImageType imageType, const char *filename, bool kerning) {
|
||||
FILE *f = fopen(filename, "w");
|
||||
if (!f)
|
||||
return false;
|
||||
|
|
@ -43,56 +40,86 @@ bool exportJSON(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyp
|
|||
fputs("\"yOrigin\":\"bottom\"", f);
|
||||
} fputs("},", f);
|
||||
|
||||
// Font metrics
|
||||
fputs("\"metrics\":{", f); {
|
||||
fprintf(f, "\"lineHeight\":%.17g,", fsScale*fontMetrics.lineHeight);
|
||||
fprintf(f, "\"ascender\":%.17g,", fsScale*fontMetrics.ascenderY);
|
||||
fprintf(f, "\"descender\":%.17g,", fsScale*fontMetrics.descenderY);
|
||||
fprintf(f, "\"underlineY\":%.17g,", fsScale*fontMetrics.underlineY);
|
||||
fprintf(f, "\"underlineThickness\":%.17g", fsScale*fontMetrics.underlineThickness);
|
||||
} fputs("},", f);
|
||||
if (fontCount > 1)
|
||||
fputs("\"variants\":[", f);
|
||||
for (int i = 0; i < fontCount; ++i) {
|
||||
const FontGeometry &font = fonts[i];
|
||||
if (fontCount > 1)
|
||||
fputs(i == 0 ? "{" : ",{", f);
|
||||
|
||||
// Glyph mapping
|
||||
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);
|
||||
if (l || b || r || t)
|
||||
fprintf(f, ",\"planeBounds\":{\"left\":%.17g,\"bottom\":%.17g,\"right\":%.17g,\"top\":%.17g}", fsScale*l, fsScale*b, fsScale*r, fsScale*t);
|
||||
glyphs[i].getQuadAtlasBounds(l, b, r, t);
|
||||
if (l || b || r || t)
|
||||
fprintf(f, ",\"atlasBounds\":{\"left\":%.17g,\"bottom\":%.17g,\"right\":%.17g,\"top\":%.17g}", l, b, r, t);
|
||||
fputs("}", f);
|
||||
}
|
||||
fputs("],", f);
|
||||
// Font metrics
|
||||
fputs("\"metrics\":{", f); {
|
||||
const msdfgen::FontMetrics &metrics = font.getMetrics();
|
||||
fprintf(f, "\"emSize\":%.17g,", metrics.emSize);
|
||||
fprintf(f, "\"lineHeight\":%.17g,", metrics.lineHeight);
|
||||
fprintf(f, "\"ascender\":%.17g,", metrics.ascenderY);
|
||||
fprintf(f, "\"descender\":%.17g,", metrics.descenderY);
|
||||
fprintf(f, "\"underlineY\":%.17g,", metrics.underlineY);
|
||||
fprintf(f, "\"underlineThickness\":%.17g", metrics.underlineThickness);
|
||||
} fputs("},", f);
|
||||
|
||||
// Kerning pairs
|
||||
fputs("\"kerning\":[", f);
|
||||
bool firstPair = true;
|
||||
for (int i = 0; i < glyphCount; ++i) {
|
||||
for (int j = 0; j < glyphCount; ++j) {
|
||||
double kerning;
|
||||
if (msdfgen::getKerning(kerning, font, glyphs[i].getCodepoint(), glyphs[j].getCodepoint()) && kerning) {
|
||||
fputs(firstPair ? "{" : ",{", f);
|
||||
fprintf(f, "\"unicode1\":%u,", glyphs[i].getCodepoint());
|
||||
fprintf(f, "\"unicode2\":%u,", glyphs[j].getCodepoint());
|
||||
fprintf(f, "\"advance\":%.17g", fsScale*kerning);
|
||||
fputs("}", f);
|
||||
firstPair = false;
|
||||
// Glyph mapping
|
||||
fputs("\"glyphs\":[", f);
|
||||
bool firstGlyph = true;
|
||||
for (const GlyphGeometry &glyph : font.getGlyphs()) {
|
||||
fputs(firstGlyph ? "{" : ",{", f);
|
||||
switch (font.getPreferredIdentifierType()) {
|
||||
case GlyphIdentifierType::GLYPH_INDEX:
|
||||
fprintf(f, "\"index\":%d,", glyph.getIndex());
|
||||
break;
|
||||
case GlyphIdentifierType::UNICODE_CODEPOINT:
|
||||
fprintf(f, "\"unicode\":%u,", glyph.getCodepoint());
|
||||
break;
|
||||
}
|
||||
fprintf(f, "\"advance\":%.17g", glyph.getAdvance());
|
||||
double l, b, r, t;
|
||||
glyph.getQuadPlaneBounds(l, b, r, t);
|
||||
if (l || b || r || t)
|
||||
fprintf(f, ",\"planeBounds\":{\"left\":%.17g,\"bottom\":%.17g,\"right\":%.17g,\"top\":%.17g}", l, b, r, t);
|
||||
glyph.getQuadAtlasBounds(l, b, r, t);
|
||||
if (l || b || r || t)
|
||||
fprintf(f, ",\"atlasBounds\":{\"left\":%.17g,\"bottom\":%.17g,\"right\":%.17g,\"top\":%.17g}", l, b, r, t);
|
||||
fputs("}", f);
|
||||
firstGlyph = false;
|
||||
} fputs("]", f);
|
||||
|
||||
// Kerning pairs
|
||||
if (kerning) {
|
||||
fputs(",\"kerning\":[", f);
|
||||
bool firstPair = true;
|
||||
switch (font.getPreferredIdentifierType()) {
|
||||
case GlyphIdentifierType::GLYPH_INDEX:
|
||||
for (const std::pair<std::pair<int, int>, double> &kernPair : font.getKerning()) {
|
||||
fputs(firstPair ? "{" : ",{", f);
|
||||
fprintf(f, "\"index1\":%d,", kernPair.first.first);
|
||||
fprintf(f, "\"index2\":%d,", kernPair.first.second);
|
||||
fprintf(f, "\"advance\":%.17g", kernPair.second);
|
||||
fputs("}", f);
|
||||
firstPair = false;
|
||||
}
|
||||
break;
|
||||
case GlyphIdentifierType::UNICODE_CODEPOINT:
|
||||
for (const std::pair<std::pair<int, int>, double> &kernPair : font.getKerning()) {
|
||||
const GlyphGeometry *glyph1 = font.getGlyph(msdfgen::GlyphIndex(kernPair.first.first));
|
||||
const GlyphGeometry *glyph2 = font.getGlyph(msdfgen::GlyphIndex(kernPair.first.second));
|
||||
if (glyph1 && glyph2 && glyph1->getCodepoint() && glyph2->getCodepoint()) {
|
||||
fputs(firstPair ? "{" : ",{", f);
|
||||
fprintf(f, "\"unicode1\":%u,", glyph1->getCodepoint());
|
||||
fprintf(f, "\"unicode2\":%u,", glyph2->getCodepoint());
|
||||
fprintf(f, "\"advance\":%.17g", kernPair.second);
|
||||
fputs("}", f);
|
||||
firstPair = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
} fputs("]", f);
|
||||
}
|
||||
|
||||
if (fontCount > 1)
|
||||
fputs("}", f);
|
||||
}
|
||||
fputs("]", f);
|
||||
if (fontCount > 1)
|
||||
fputs("]", f);
|
||||
|
||||
fputs("}\n", f);
|
||||
fclose(f);
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@
|
|||
#include <msdfgen.h>
|
||||
#include <msdfgen-ext.h>
|
||||
#include "types.h"
|
||||
#include "GlyphGeometry.h"
|
||||
#include "FontGeometry.h"
|
||||
|
||||
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, GlyphIdentifierType glyphIdentifierType, double fontSize, double pxRange, int atlasWidth, int atlasHeight, ImageType imageType, const char *filename);
|
||||
bool exportJSON(const FontGeometry *fonts, int fontCount, double fontSize, double pxRange, int atlasWidth, int atlasHeight, ImageType imageType, const char *filename, bool kerning);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,9 @@
|
|||
#define _USE_MATH_DEFINES
|
||||
#include <cstdio>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <thread>
|
||||
|
||||
|
|
@ -21,7 +23,6 @@ using namespace msdf_atlas;
|
|||
|
||||
#define DEFAULT_ANGLE_THRESHOLD 3.0
|
||||
#define DEFAULT_MITER_LIMIT 1.0
|
||||
#define DEFAULT_EM_SIZE 32.0
|
||||
#define DEFAULT_PIXEL_RANGE 2.0
|
||||
#define SDF_ERROR_ESTIMATE_PRECISION 19
|
||||
#define GLYPH_FILL_RULE msdfgen::FILL_NONZERO
|
||||
|
|
@ -46,6 +47,10 @@ INPUT SPECIFICATION
|
|||
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.
|
||||
-fontscale <scale>
|
||||
Specifies the scale to be applied to the glyph geometry of the font.
|
||||
-and
|
||||
Separates multiple inputs to be combined into a single atlas.
|
||||
|
||||
ATLAS CONFIGURATION
|
||||
-type <hardmask / softmask / sdf / psdf / msdf / mtsdf>
|
||||
|
|
@ -79,6 +84,8 @@ GLYPH CONFIGURATION
|
|||
Specifies the SDF distance range in EM's.
|
||||
-pxrange <pixel range>
|
||||
Specifies the SDF distance range in output pixels. The default value is 2.
|
||||
-nokerning
|
||||
Disables inclusion of kerning pair table in output files.
|
||||
|
||||
DISTANCE FIELD GENERATOR SETTINGS
|
||||
-angle <angle>
|
||||
|
|
@ -147,32 +154,14 @@ static bool cmpExtension(const char *path, const char *ext) {
|
|||
return true;
|
||||
}
|
||||
|
||||
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) {
|
||||
GlyphGeometry glyph;
|
||||
if (glyph.load(font, cp, preprocessGeometry))
|
||||
glyphs.push_back((GlyphGeometry &&) glyph);
|
||||
else
|
||||
printf("Glyph for codepoint 0x%X missing\n", cp);
|
||||
}
|
||||
}
|
||||
struct FontInput {
|
||||
const char *fontFilename;
|
||||
GlyphIdentifierType glyphIdentifierType;
|
||||
const char *charsetFilename;
|
||||
double fontScale;
|
||||
};
|
||||
|
||||
struct Configuration {
|
||||
GlyphIdentifierType glyphIdentifierType;
|
||||
ImageType imageType;
|
||||
ImageFormat imageFormat;
|
||||
int width, height;
|
||||
|
|
@ -183,6 +172,7 @@ struct Configuration {
|
|||
unsigned long long coloringSeed;
|
||||
GeneratorAttributes generatorAttributes;
|
||||
bool preprocessGeometry;
|
||||
bool kerning;
|
||||
int threadCount;
|
||||
const char *arteryFontFilename;
|
||||
const char *imageFilename;
|
||||
|
|
@ -193,7 +183,7 @@ struct Configuration {
|
|||
};
|
||||
|
||||
template <typename T, typename S, int N, GeneratorFunction<S, N> GEN_FN>
|
||||
static bool makeAtlas(const std::vector<GlyphGeometry> &glyphs, msdfgen::FontHandle *font, const Configuration &config) {
|
||||
static bool makeAtlas(const std::vector<GlyphGeometry> &glyphs, const std::vector<FontGeometry> &fonts, const Configuration &config) {
|
||||
ImmediateAtlasGenerator<S, N, GEN_FN, BitmapAtlasStorage<T, N> > generator(config.width, config.height);
|
||||
generator.setAttributes(config.generatorAttributes);
|
||||
generator.setThreadCount(config.threadCount);
|
||||
|
|
@ -213,12 +203,11 @@ static bool makeAtlas(const std::vector<GlyphGeometry> &glyphs, msdfgen::FontHan
|
|||
|
||||
if (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))
|
||||
if (exportArteryFont<float>(fonts.data(), fonts.size(), bitmap, config.arteryFontFilename, arfontProps))
|
||||
puts("Artery Font file generated.");
|
||||
else {
|
||||
success = false;
|
||||
|
|
@ -233,10 +222,12 @@ int main(int argc, const char * const *argv) {
|
|||
#define ABORT(msg) { puts(msg); return 1; }
|
||||
|
||||
int result = 0;
|
||||
std::vector<FontInput> fontInputs;
|
||||
FontInput fontInput = { };
|
||||
Configuration config = { };
|
||||
const char *fontFilename = nullptr;
|
||||
const char *charsetFilename = nullptr;
|
||||
config.glyphIdentifierType = GlyphIdentifierType::UNICODE_CODEPOINT;
|
||||
fontInput.glyphIdentifierType = GlyphIdentifierType::UNICODE_CODEPOINT;
|
||||
fontInput.fontScale = -1;
|
||||
config.kerning = true;
|
||||
config.imageType = ImageType::MSDF;
|
||||
config.imageFormat = ImageFormat::UNSPECIFIED;
|
||||
const char *imageFormatName = nullptr;
|
||||
|
|
@ -315,19 +306,36 @@ int main(int argc, const char * const *argv) {
|
|||
continue;
|
||||
}
|
||||
ARG_CASE("-font", 1) {
|
||||
fontFilename = argv[++argPos];
|
||||
fontInput.fontFilename = argv[++argPos];
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-charset", 1) {
|
||||
charsetFilename = argv[++argPos];
|
||||
config.glyphIdentifierType = GlyphIdentifierType::UNICODE_CODEPOINT;
|
||||
fontInput.charsetFilename = argv[++argPos];
|
||||
fontInput.glyphIdentifierType = GlyphIdentifierType::UNICODE_CODEPOINT;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-glyphset", 1) {
|
||||
charsetFilename = argv[++argPos];
|
||||
config.glyphIdentifierType = GlyphIdentifierType::GLYPH_INDEX;
|
||||
fontInput.charsetFilename = argv[++argPos];
|
||||
fontInput.glyphIdentifierType = GlyphIdentifierType::GLYPH_INDEX;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-fontscale", 1) {
|
||||
double fs;
|
||||
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("-and", 0) {
|
||||
if (!fontInput.fontFilename && !fontInput.charsetFilename && fontInput.fontScale < 0)
|
||||
ABORT("No font, character set, or font scale specified before -and separator.");
|
||||
if (!fontInputs.empty() && !memcmp(&fontInputs.back(), &fontInput, sizeof(FontInput)))
|
||||
ABORT("No changes between subsequent inputs. A different font, character set, or font scale must be set inbetween -and separators.");
|
||||
fontInputs.push_back(fontInput);
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -453,34 +461,44 @@ int main(int argc, const char * const *argv) {
|
|||
++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 += 1;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-preprocess", 0) {
|
||||
config.preprocessGeometry = true;
|
||||
argPos += 1;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-nooverlap", 0) {
|
||||
config.generatorAttributes.overlapSupport = false;
|
||||
argPos += 1;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-overlap", 0) {
|
||||
config.generatorAttributes.overlapSupport = true;
|
||||
argPos += 1;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-noscanline", 0) {
|
||||
config.generatorAttributes.scanlinePass = false;
|
||||
argPos += 1;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-scanline", 0) {
|
||||
config.generatorAttributes.scanlinePass = true;
|
||||
argPos += 1;
|
||||
++argPos;
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-seed", 1) {
|
||||
|
|
@ -520,7 +538,7 @@ int main(int argc, const char * const *argv) {
|
|||
);
|
||||
return 0;
|
||||
}
|
||||
if (!fontFilename)
|
||||
if (!fontInput.fontFilename)
|
||||
ABORT("No font specified.");
|
||||
if (!(config.arteryFontFilename || config.imageFilename || config.jsonFilename || config.csvFilename || config.shadronPreviewFilename)) {
|
||||
puts("No output specified.");
|
||||
|
|
@ -528,6 +546,22 @@ int main(int argc, const char * const *argv) {
|
|||
}
|
||||
bool layoutOnly = !(config.arteryFontFilename || config.imageFilename);
|
||||
|
||||
// Finalize font inputs
|
||||
const FontInput *nextFontInput = &fontInput;
|
||||
for (std::vector<FontInput>::reverse_iterator it = fontInputs.rbegin(); it != fontInputs.rend(); ++it) {
|
||||
if (!it->fontFilename && nextFontInput->fontFilename)
|
||||
it->fontFilename = nextFontInput->fontFilename;
|
||||
if (!it->charsetFilename && nextFontInput->charsetFilename) {
|
||||
it->charsetFilename = nextFontInput->charsetFilename;
|
||||
it->glyphIdentifierType = nextFontInput->glyphIdentifierType;
|
||||
}
|
||||
if (it->fontScale < 0 && nextFontInput->fontScale >= 0)
|
||||
it->fontScale = nextFontInput->fontScale;
|
||||
nextFontInput = &*it;
|
||||
}
|
||||
if (fontInputs.empty() || memcmp(&fontInputs.back(), &fontInput, sizeof(FontInput)))
|
||||
fontInputs.push_back(fontInput);
|
||||
|
||||
// Fix up configuration based on related values
|
||||
if (!(config.imageType == ImageType::PSDF || config.imageType == ImageType::MSDF || config.imageType == ImageType::MTSDF))
|
||||
config.miterLimit = 0;
|
||||
|
|
@ -535,7 +569,7 @@ int main(int argc, const char * const *argv) {
|
|||
minEmSize = config.emSize;
|
||||
if (!(fixedWidth > 0 && fixedHeight > 0) && !(minEmSize > 0)) {
|
||||
puts("Neither atlas size nor glyph size selected, using default...");
|
||||
minEmSize = DEFAULT_EM_SIZE;
|
||||
minEmSize = MSDF_ATLAS_DEFAULT_EM_SIZE;
|
||||
}
|
||||
if (!(config.imageType == ImageType::SDF || config.imageType == ImageType::PSDF || config.imageType == ImageType::MSDF || config.imageType == ImageType::MTSDF)) {
|
||||
rangeMode = RANGE_PIXEL;
|
||||
|
|
@ -544,6 +578,8 @@ int main(int argc, const char * const *argv) {
|
|||
rangeMode = RANGE_PIXEL;
|
||||
rangeValue = DEFAULT_PIXEL_RANGE;
|
||||
}
|
||||
if (config.kerning && !(config.arteryFontFilename || config.jsonFilename || config.shadronPreviewFilename))
|
||||
config.kerning = false;
|
||||
if (config.threadCount <= 0)
|
||||
config.threadCount = std::max((int) std::thread::hardware_concurrency(), 1);
|
||||
|
||||
|
|
@ -598,61 +634,108 @@ int main(int argc, const char * const *argv) {
|
|||
config.imageFormat == ImageFormat::BINARY_FLOAT_BE
|
||||
);
|
||||
|
||||
// Load font
|
||||
class FontHolder {
|
||||
msdfgen::FreetypeHandle *ft;
|
||||
msdfgen::FontHandle *font;
|
||||
public:
|
||||
explicit FontHolder(const char *fontFilename) : ft(nullptr), font(nullptr) {
|
||||
if ((ft = msdfgen::initializeFreetype()))
|
||||
font = msdfgen::loadFont(ft, fontFilename);
|
||||
}
|
||||
~FontHolder() {
|
||||
if (ft) {
|
||||
if (font)
|
||||
msdfgen::destroyFont(font);
|
||||
msdfgen::deinitializeFreetype(ft);
|
||||
}
|
||||
}
|
||||
operator msdfgen::FontHandle *() const {
|
||||
return font;
|
||||
}
|
||||
} font(fontFilename);
|
||||
if (!font)
|
||||
ABORT("Failed to load specified font file.");
|
||||
msdfgen::FontMetrics fontMetrics = { };
|
||||
msdfgen::getFontMetrics(fontMetrics, font);
|
||||
if (fontMetrics.emSize <= 0)
|
||||
fontMetrics.emSize = DEFAULT_EM_SIZE;
|
||||
|
||||
// Load character set
|
||||
Charset charset;
|
||||
if (charsetFilename) {
|
||||
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;
|
||||
|
||||
// Load glyphs
|
||||
// Load fonts
|
||||
std::vector<GlyphGeometry> glyphs;
|
||||
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;
|
||||
std::vector<FontGeometry> fonts;
|
||||
bool anyCodepointsAvailable = false;
|
||||
{
|
||||
class FontHolder {
|
||||
msdfgen::FreetypeHandle *ft;
|
||||
msdfgen::FontHandle *font;
|
||||
const char *fontFilename;
|
||||
public:
|
||||
FontHolder() : ft(msdfgen::initializeFreetype()), font(nullptr), fontFilename(nullptr) { }
|
||||
~FontHolder() {
|
||||
if (ft) {
|
||||
if (font)
|
||||
msdfgen::destroyFont(font);
|
||||
msdfgen::deinitializeFreetype(ft);
|
||||
}
|
||||
}
|
||||
bool load(const char *fontFilename) {
|
||||
if (ft && fontFilename) {
|
||||
if (this->fontFilename && !strcmp(this->fontFilename, fontFilename))
|
||||
return true;
|
||||
if (font)
|
||||
msdfgen::destroyFont(font);
|
||||
if ((font = msdfgen::loadFont(ft, fontFilename))) {
|
||||
this->fontFilename = fontFilename;
|
||||
return true;
|
||||
}
|
||||
this->fontFilename = nullptr;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
operator msdfgen::FontHandle *() const {
|
||||
return font;
|
||||
}
|
||||
} font;
|
||||
|
||||
for (FontInput &fontInput : fontInputs) {
|
||||
if (!font.load(fontInput.fontFilename))
|
||||
ABORT("Failed to load specified font file.");
|
||||
if (fontInput.fontScale <= 0)
|
||||
fontInput.fontScale = 1;
|
||||
|
||||
// Load character set
|
||||
Charset charset;
|
||||
if (fontInput.charsetFilename) {
|
||||
if (!charset.load(fontInput.charsetFilename, fontInput.glyphIdentifierType != GlyphIdentifierType::UNICODE_CODEPOINT))
|
||||
ABORT(fontInput.glyphIdentifierType == GlyphIdentifierType::GLYPH_INDEX ? "Failed to load glyph set specification." : "Failed to load character set specification.");
|
||||
} else {
|
||||
charset = Charset::ASCII;
|
||||
fontInput.glyphIdentifierType = GlyphIdentifierType::UNICODE_CODEPOINT;
|
||||
}
|
||||
|
||||
// Load glyphs
|
||||
FontGeometry fontGeometry(&glyphs);
|
||||
int glyphsLoaded = -1;
|
||||
switch (fontInput.glyphIdentifierType) {
|
||||
case GlyphIdentifierType::GLYPH_INDEX:
|
||||
glyphsLoaded = fontGeometry.loadGlyphset(font, fontInput.fontScale, charset, config.preprocessGeometry, config.kerning);
|
||||
break;
|
||||
case GlyphIdentifierType::UNICODE_CODEPOINT:
|
||||
glyphsLoaded = fontGeometry.loadCharset(font, fontInput.fontScale, charset, config.preprocessGeometry, config.kerning);
|
||||
anyCodepointsAvailable |= glyphsLoaded > 0;
|
||||
break;
|
||||
}
|
||||
if (glyphsLoaded < 0)
|
||||
ABORT("Failed to load glyphs from font.");
|
||||
printf("Loaded geometry of %d out of %d glyphs", glyphsLoaded, (int) charset.size());
|
||||
if (fontInputs.size() > 1)
|
||||
printf(" from font \"%s\"", fontInput.fontFilename);
|
||||
printf(".\n");
|
||||
// List missing glyphs
|
||||
if (glyphsLoaded < (int) charset.size()) {
|
||||
printf("Missing %d %s", (int) charset.size()-glyphsLoaded, fontInput.glyphIdentifierType == GlyphIdentifierType::UNICODE_CODEPOINT ? "codepoints" : "glyphs");
|
||||
bool first = true;
|
||||
switch (fontInput.glyphIdentifierType) {
|
||||
case GlyphIdentifierType::GLYPH_INDEX:
|
||||
for (unicode_t cp : charset)
|
||||
if (!fontGeometry.getGlyph(msdfgen::GlyphIndex(cp)))
|
||||
printf("%c 0x%02X", first ? ((first = false), ':') : ',', cp);
|
||||
break;
|
||||
case GlyphIdentifierType::UNICODE_CODEPOINT:
|
||||
for (unicode_t cp : charset)
|
||||
if (!fontGeometry.getGlyph(cp))
|
||||
printf("%c 0x%02X", first ? ((first = false), ':') : ',', cp);
|
||||
break;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
fonts.push_back((FontGeometry &&) fontGeometry);
|
||||
}
|
||||
}
|
||||
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
|
||||
{
|
||||
double unitRange = 0, pxRange = 0;
|
||||
switch (rangeMode) {
|
||||
case RANGE_EM:
|
||||
unitRange = rangeValue*fontMetrics.emSize;
|
||||
unitRange = rangeValue;
|
||||
break;
|
||||
case RANGE_PIXEL:
|
||||
pxRange = rangeValue;
|
||||
|
|
@ -668,9 +751,9 @@ int main(int argc, const char * const *argv) {
|
|||
atlasPacker.setPadding(config.imageType == ImageType::MSDF || config.imageType == ImageType::MTSDF ? 0 : -1);
|
||||
// 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.
|
||||
if (fixedScale)
|
||||
atlasPacker.setScale(config.emSize/fontMetrics.emSize);
|
||||
atlasPacker.setScale(config.emSize);
|
||||
else
|
||||
atlasPacker.setMinimumScale(minEmSize/fontMetrics.emSize);
|
||||
atlasPacker.setMinimumScale(minEmSize);
|
||||
atlasPacker.setPixelRange(pxRange);
|
||||
atlasPacker.setUnitRange(unitRange);
|
||||
atlasPacker.setMiterLimit(config.miterLimit);
|
||||
|
|
@ -685,7 +768,7 @@ int main(int argc, const char * const *argv) {
|
|||
atlasPacker.getDimensions(config.width, config.height);
|
||||
if (!(config.width > 0 && config.height > 0))
|
||||
ABORT("Unable to determine atlas size.");
|
||||
config.emSize = atlasPacker.getScale()*fontMetrics.emSize;
|
||||
config.emSize = atlasPacker.getScale();
|
||||
config.pxRange = atlasPacker.getPixelRange();
|
||||
if (!fixedScale)
|
||||
printf("Glyph size: %.9g pixels/EM\n", config.emSize);
|
||||
|
|
@ -709,34 +792,34 @@ int main(int argc, const char * const *argv) {
|
|||
switch (config.imageType) {
|
||||
case ImageType::HARD_MASK:
|
||||
if (floatingPointFormat)
|
||||
success = makeAtlas<float, float, 1, scanlineGenerator>(glyphs, font, config);
|
||||
success = makeAtlas<float, float, 1, scanlineGenerator>(glyphs, fonts, config);
|
||||
else
|
||||
success = makeAtlas<byte, float, 1, scanlineGenerator>(glyphs, font, config);
|
||||
success = makeAtlas<byte, float, 1, scanlineGenerator>(glyphs, fonts, config);
|
||||
break;
|
||||
case ImageType::SOFT_MASK:
|
||||
case ImageType::SDF:
|
||||
if (floatingPointFormat)
|
||||
success = makeAtlas<float, float, 1, sdfGenerator>(glyphs, font, config);
|
||||
success = makeAtlas<float, float, 1, sdfGenerator>(glyphs, fonts, config);
|
||||
else
|
||||
success = makeAtlas<byte, float, 1, sdfGenerator>(glyphs, font, config);
|
||||
success = makeAtlas<byte, float, 1, sdfGenerator>(glyphs, fonts, config);
|
||||
break;
|
||||
case ImageType::PSDF:
|
||||
if (floatingPointFormat)
|
||||
success = makeAtlas<float, float, 1, psdfGenerator>(glyphs, font, config);
|
||||
success = makeAtlas<float, float, 1, psdfGenerator>(glyphs, fonts, config);
|
||||
else
|
||||
success = makeAtlas<byte, float, 1, psdfGenerator>(glyphs, font, config);
|
||||
success = makeAtlas<byte, float, 1, psdfGenerator>(glyphs, fonts, config);
|
||||
break;
|
||||
case ImageType::MSDF:
|
||||
if (floatingPointFormat)
|
||||
success = makeAtlas<float, float, 3, msdfGenerator>(glyphs, font, config);
|
||||
success = makeAtlas<float, float, 3, msdfGenerator>(glyphs, fonts, config);
|
||||
else
|
||||
success = makeAtlas<byte, float, 3, msdfGenerator>(glyphs, font, config);
|
||||
success = makeAtlas<byte, float, 3, msdfGenerator>(glyphs, fonts, config);
|
||||
break;
|
||||
case ImageType::MTSDF:
|
||||
if (floatingPointFormat)
|
||||
success = makeAtlas<float, float, 4, mtsdfGenerator>(glyphs, font, config);
|
||||
success = makeAtlas<float, float, 4, mtsdfGenerator>(glyphs, fonts, config);
|
||||
else
|
||||
success = makeAtlas<byte, float, 4, mtsdfGenerator>(glyphs, font, config);
|
||||
success = makeAtlas<byte, float, 4, mtsdfGenerator>(glyphs, fonts, config);
|
||||
break;
|
||||
}
|
||||
if (!success)
|
||||
|
|
@ -744,7 +827,7 @@ int main(int argc, const char * const *argv) {
|
|||
}
|
||||
|
||||
if (config.csvFilename) {
|
||||
if (exportCSV(glyphs.data(), glyphs.size(), config.glyphIdentifierType, fontMetrics.emSize, config.csvFilename))
|
||||
if (exportCSV(fonts.data(), fonts.size(), config.csvFilename))
|
||||
puts("Glyph layout written into CSV file.");
|
||||
else {
|
||||
result = 1;
|
||||
|
|
@ -752,7 +835,7 @@ int main(int argc, const char * const *argv) {
|
|||
}
|
||||
}
|
||||
if (config.jsonFilename) {
|
||||
if (exportJSON(font, glyphs.data(), glyphs.size(), config.glyphIdentifierType, config.emSize, config.pxRange, config.width, config.height, config.imageType, config.jsonFilename))
|
||||
if (exportJSON(fonts.data(), fonts.size(), config.emSize, config.pxRange, config.width, config.height, config.imageType, config.jsonFilename, config.kerning))
|
||||
puts("Glyph layout and metadata written into JSON file.");
|
||||
else {
|
||||
result = 1;
|
||||
|
|
@ -761,11 +844,11 @@ int main(int argc, const char * const *argv) {
|
|||
}
|
||||
|
||||
if (config.shadronPreviewFilename && config.shadronPreviewText) {
|
||||
if (config.glyphIdentifierType == GlyphIdentifierType::UNICODE_CODEPOINT) {
|
||||
if (anyCodepointsAvailable) {
|
||||
std::vector<unicode_t> previewText;
|
||||
utf8Decode(previewText, config.shadronPreviewText);
|
||||
previewText.push_back(0);
|
||||
if (generateShadronPreview(font, glyphs.data(), glyphs.size(), config.imageType, config.width, config.height, config.pxRange, previewText.data(), config.imageFilename, floatingPointFormat, config.shadronPreviewFilename))
|
||||
if (generateShadronPreview(fonts.data(), fonts.size(), config.imageType, config.width, config.height, config.pxRange, previewText.data(), config.imageFilename, floatingPointFormat, config.shadronPreviewFilename))
|
||||
puts("Shadron preview script generated.");
|
||||
else {
|
||||
result = 1;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#include "Charset.h"
|
||||
#include "GlyphBox.h"
|
||||
#include "GlyphGeometry.h"
|
||||
#include "FontGeometry.h"
|
||||
#include "RectanglePacker.h"
|
||||
#include "rectangle-packing.h"
|
||||
#include "Workload.h"
|
||||
|
|
|
|||
|
|
@ -77,9 +77,12 @@ static std::string relativizePath(const char *base, const char *target) {
|
|||
return output;
|
||||
}
|
||||
|
||||
bool generateShadronPreview(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, ImageType atlasType, int atlasWidth, int atlasHeight, double pxRange, const unicode_t *text, const char *imageFilename, bool fullRange, const char *outputFilename) {
|
||||
bool generateShadronPreview(const FontGeometry *fonts, int fontCount, ImageType atlasType, int atlasWidth, int atlasHeight, double pxRange, const unicode_t *text, const char *imageFilename, bool fullRange, const char *outputFilename) {
|
||||
if (fontCount <= 0)
|
||||
return false;
|
||||
double texelWidth = 1./atlasWidth;
|
||||
double texelHeight = 1./atlasHeight;
|
||||
bool anyGlyphs = false;
|
||||
FILE *file = fopen(outputFilename, "w");
|
||||
if (!file)
|
||||
return false;
|
||||
|
|
@ -91,9 +94,12 @@ bool generateShadronPreview(msdfgen::FontHandle *font, const GlyphGeometry *glyp
|
|||
fprintf(file, " : %sfilter(%s), map(repeat);\n", fullRange ? "full_range(true), " : "", atlasType == ImageType::HARD_MASK ? "nearest" : "linear");
|
||||
fprintf(file, "const vec2 txRange = vec2(%.9g, %.9g);\n\n", pxRange*texelWidth, pxRange*texelHeight);
|
||||
{
|
||||
msdfgen::FontMetrics fontMetrics;
|
||||
if (!msdfgen::getFontMetrics(fontMetrics, font))
|
||||
return false;
|
||||
msdfgen::FontMetrics fontMetrics = fonts->getMetrics();
|
||||
for (int i = 1; i < fontCount; ++i) {
|
||||
fontMetrics.lineHeight = std::max(fontMetrics.lineHeight, fonts[i].getMetrics().lineHeight);
|
||||
fontMetrics.ascenderY = std::max(fontMetrics.ascenderY, fonts[i].getMetrics().ascenderY);
|
||||
fontMetrics.descenderY = std::min(fontMetrics.descenderY, fonts[i].getMetrics().descenderY);
|
||||
}
|
||||
double fsScale = 1/(fontMetrics.ascenderY-fontMetrics.descenderY);
|
||||
fputs("vertex_list GlyphVertex textQuadVertices = {\n", file);
|
||||
double x = 0, y = -fsScale*fontMetrics.ascenderY;
|
||||
|
|
@ -107,13 +113,14 @@ bool generateShadronPreview(msdfgen::FontHandle *font, const GlyphGeometry *glyp
|
|||
y -= fsScale*fontMetrics.lineHeight;
|
||||
continue;
|
||||
}
|
||||
for (int i = 0; i < glyphCount; ++i) {
|
||||
if (glyphs[i].getCodepoint() == *cp) {
|
||||
if (!glyphs[i].isWhitespace()) {
|
||||
for (int i = 0; i < fontCount; ++i) {
|
||||
const GlyphGeometry *glyph = fonts[i].getGlyph(*cp);
|
||||
if (glyph) {
|
||||
if (!glyph->isWhitespace()) {
|
||||
double pl, pb, pr, pt;
|
||||
double il, ib, ir, it;
|
||||
glyphs[i].getQuadPlaneBounds(pl, pb, pr, pt);
|
||||
glyphs[i].getQuadAtlasBounds(il, ib, ir, it);
|
||||
glyph->getQuadPlaneBounds(pl, pb, pr, pt);
|
||||
glyph->getQuadAtlasBounds(il, ib, ir, it);
|
||||
pl *= fsScale, pb *= fsScale, pr *= fsScale, pt *= fsScale;
|
||||
pl += x, pb += y, pr += x, pt += y;
|
||||
il *= texelWidth, ib *= texelHeight, ir *= texelWidth, it *= texelHeight;
|
||||
|
|
@ -126,10 +133,10 @@ bool generateShadronPreview(msdfgen::FontHandle *font, const GlyphGeometry *glyp
|
|||
pr, pb, ir, ib
|
||||
);
|
||||
}
|
||||
x += fsScale*glyphs[i].getAdvance();
|
||||
double kerning;
|
||||
if (msdfgen::getKerning(kerning, font, cp[0], cp[1]))
|
||||
x += fsScale*kerning;
|
||||
double advance = glyph->getAdvance();
|
||||
fonts[i].getAdvance(advance, cp[0], cp[1]);
|
||||
x += fsScale*advance;
|
||||
anyGlyphs = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -142,7 +149,7 @@ bool generateShadronPreview(msdfgen::FontHandle *font, const GlyphGeometry *glyp
|
|||
fputs("PREVIEW_IMAGE(Preview, Atlas, txRange, vec3(1.0), textQuadVertices, textSize, ivec2(1200, 400));\n", file);
|
||||
fputs("export png(Preview, \"preview.png\");\n", file);
|
||||
fclose(file);
|
||||
return true;
|
||||
return anyGlyphs;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@
|
|||
#include <msdfgen.h>
|
||||
#include <msdfgen-ext.h>
|
||||
#include "types.h"
|
||||
#include "GlyphGeometry.h"
|
||||
#include "FontGeometry.h"
|
||||
|
||||
namespace msdf_atlas {
|
||||
|
||||
/// Generates a Shadron script that displays a string using the generated atlas
|
||||
bool generateShadronPreview(msdfgen::FontHandle *font, const GlyphGeometry *glyphs, int glyphCount, ImageType atlasType, int atlasWidth, int atlasHeight, double pxRange, const unicode_t *text, const char *imageFilename, bool fullRange, const char *outputFilename);
|
||||
bool generateShadronPreview(const FontGeometry *fonts, int fontCount, ImageType atlasType, int atlasWidth, int atlasHeight, double pxRange, const unicode_t *text, const char *imageFilename, bool fullRange, const char *outputFilename);
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue