Skip to content

Instantly share code, notes, and snippets.

@usernameak
Created November 17, 2025 05:40
Show Gist options
  • Select an option

  • Save usernameak/bd12296574cf7ce0bd07446c8dc0c796 to your computer and use it in GitHub Desktop.

Select an option

Save usernameak/bd12296574cf7ce0bd07446c8dc0c796 to your computer and use it in GitHub Desktop.
diff --git a/old/msdf-atlas-gen/msdf-atlas-gen/FontGeometry.cpp b/msdf-atlas-gen/msdf-atlas-gen/FontGeometry.cpp
index 7d350c2..0bc0e1a 100644
--- a/old/msdf-atlas-gen/msdf-atlas-gen/FontGeometry.cpp
+++ b/msdf-atlas-gen/msdf-atlas-gen/FontGeometry.cpp
@@ -54,14 +54,14 @@ FontGeometry &FontGeometry::operator=(FontGeometry &&orig) {
return *this;
}
-int FontGeometry::loadGlyphRange(msdfgen::FontHandle *font, double fontScale, unsigned rangeStart, unsigned rangeEnd, bool preprocessGeometry, bool enableKerning) {
+int FontGeometry::loadGlyphRange(msdfgen::FontHandle *font, double fontScale, unsigned rangeStart, unsigned rangeEnd, bool preprocessGeometry, bool enableKerning, bool loadCompositeGlyphs) {
if (!(glyphs->size() == this->rangeEnd && loadMetrics(font, fontScale)))
return -1;
glyphs->reserve(glyphs->size()+(rangeEnd-rangeStart));
int loaded = 0;
for (unsigned index = rangeStart; index < rangeEnd; ++index) {
GlyphGeometry glyph;
- if (glyph.load(font, geometryScale, msdfgen::GlyphIndex(index), preprocessGeometry)) {
+ if (glyph.load(font, geometryScale, msdfgen::GlyphIndex(index), preprocessGeometry, loadCompositeGlyphs)) {
addGlyph((GlyphGeometry &&) glyph);
++loaded;
}
@@ -72,14 +72,14 @@ int FontGeometry::loadGlyphRange(msdfgen::FontHandle *font, double fontScale, un
return loaded;
}
-int FontGeometry::loadGlyphset(msdfgen::FontHandle *font, double fontScale, const Charset &glyphset, bool preprocessGeometry, bool enableKerning) {
+int FontGeometry::loadGlyphset(msdfgen::FontHandle *font, double fontScale, const Charset &glyphset, bool preprocessGeometry, bool enableKerning, bool loadCompositeGlyphs) {
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)) {
+ if (glyph.load(font, geometryScale, msdfgen::GlyphIndex(index), preprocessGeometry, loadCompositeGlyphs)) {
addGlyph((GlyphGeometry &&) glyph);
++loaded;
}
@@ -90,14 +90,14 @@ int FontGeometry::loadGlyphset(msdfgen::FontHandle *font, double fontScale, cons
return loaded;
}
-int FontGeometry::loadCharset(msdfgen::FontHandle *font, double fontScale, const Charset &charset, bool preprocessGeometry, bool enableKerning) {
+int FontGeometry::loadCharset(msdfgen::FontHandle *font, double fontScale, const Charset &charset, bool preprocessGeometry, bool enableKerning, bool loadCompositeGlyphs) {
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)) {
+ if (glyph.load(font, geometryScale, cp, preprocessGeometry, loadCompositeGlyphs)) {
addGlyph((GlyphGeometry &&) glyph);
++loaded;
}
diff --git a/old/msdf-atlas-gen/msdf-atlas-gen/FontGeometry.h b/msdf-atlas-gen/msdf-atlas-gen/FontGeometry.h
index 8dc758f..65d495e 100644
--- a/old/msdf-atlas-gen/msdf-atlas-gen/FontGeometry.h
+++ b/msdf-atlas-gen/msdf-atlas-gen/FontGeometry.h
@@ -36,11 +36,11 @@ public:
FontGeometry &operator=(FontGeometry &&orig);
/// Loads the consecutive range of glyphs between rangeStart (inclusive) and rangeEnd (exclusive), returns the number of successfully loaded glyphs
- int loadGlyphRange(msdfgen::FontHandle *font, double fontScale, unsigned rangeStart, unsigned rangeEnd, bool preprocessGeometry = true, bool enableKerning = true);
+ int loadGlyphRange(msdfgen::FontHandle *font, double fontScale, unsigned rangeStart, unsigned rangeEnd, bool preprocessGeometry = true, bool enableKerning = true, bool loadCompositeGlyphs = false);
/// 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);
+ int loadGlyphset(msdfgen::FontHandle *font, double fontScale, const Charset &glyphset, bool preprocessGeometry = true, bool enableKerning = true, bool loadCompositeGlyphs = false);
/// 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);
+ int loadCharset(msdfgen::FontHandle *font, double fontScale, const Charset &charset, bool preprocessGeometry = true, bool enableKerning = true, bool loadCompositeGlyphs = false);
/// Only loads font metrics and geometry scale from font
bool loadMetrics(msdfgen::FontHandle *font, double fontScale);
diff --git a/old/msdf-atlas-gen/msdf-atlas-gen/GlyphGeometry.cpp b/msdf-atlas-gen/msdf-atlas-gen/GlyphGeometry.cpp
index 1e30df7..0988f37 100644
--- a/old/msdf-atlas-gen/msdf-atlas-gen/GlyphGeometry.cpp
+++ b/msdf-atlas-gen/msdf-atlas-gen/GlyphGeometry.cpp
@@ -8,38 +8,47 @@ namespace msdf_atlas {
GlyphGeometry::GlyphGeometry() : index(), codepoint(), geometryScale(), bounds(), advance(), box() { }
-bool GlyphGeometry::load(msdfgen::FontHandle *font, double geometryScale, msdfgen::GlyphIndex index, bool preprocessGeometry) {
- if (font && msdfgen::loadGlyph(shape, font, index, msdfgen::FONT_SCALING_NONE, &advance) && shape.validate()) {
- this->index = index.getIndex();
- this->geometryScale = geometryScale;
- codepoint = 0;
- advance *= geometryScale;
- #ifdef MSDFGEN_USE_SKIA
- if (preprocessGeometry)
- msdfgen::resolveShapeGeometry(shape);
- #endif
- shape.normalize();
- bounds = shape.getBounds();
- #ifdef MSDFGEN_USE_SKIA
- if (!preprocessGeometry)
- #endif
- {
- // Determine if shape is winded incorrectly and reverse it in that case
- msdfgen::Point2 outerPoint(bounds.l-(bounds.r-bounds.l)-1, bounds.b-(bounds.t-bounds.b)-1);
- if (msdfgen::SimpleTrueShapeDistanceFinder::oneShotDistance(shape, outerPoint) > 0) {
- for (msdfgen::Contour &contour : shape.contours)
- contour.reverse();
- }
+bool GlyphGeometry::load(msdfgen::FontHandle *font, double geometryScale, msdfgen::GlyphIndex index, bool preprocessGeometry, bool loadCompositeGlyphs) {
+ if (!font)
+ return false;
+ if (loadCompositeGlyphs) {
+ if (!msdfgen::loadCompositeGlyph(shape, font, index, msdfgen::FONT_SCALING_NONE, subGlyphs, &advance))
+ return false;
+ } else {
+ if (!msdfgen::loadGlyph(shape, font, index, msdfgen::FONT_SCALING_NONE, &advance))
+ return false;
+ }
+ if (!shape.validate())
+ return false;
+
+ this->index = index.getIndex();
+ this->geometryScale = geometryScale;
+ codepoint = 0;
+ advance *= geometryScale;
+ #ifdef MSDFGEN_USE_SKIA
+ if (preprocessGeometry)
+ msdfgen::resolveShapeGeometry(shape);
+ #endif
+ shape.normalize();
+ bounds = shape.getBounds();
+ #ifdef MSDFGEN_USE_SKIA
+ if (!preprocessGeometry)
+ #endif
+ {
+ // Determine if shape is winded incorrectly and reverse it in that case
+ msdfgen::Point2 outerPoint(bounds.l-(bounds.r-bounds.l)-1, bounds.b-(bounds.t-bounds.b)-1);
+ if (msdfgen::SimpleTrueShapeDistanceFinder::oneShotDistance(shape, outerPoint) > 0) {
+ for (msdfgen::Contour &contour : shape.contours)
+ contour.reverse();
}
- return true;
}
- return false;
+ return true;
}
-bool GlyphGeometry::load(msdfgen::FontHandle *font, double geometryScale, unicode_t codepoint, bool preprocessGeometry) {
+bool GlyphGeometry::load(msdfgen::FontHandle *font, double geometryScale, unicode_t codepoint, bool preprocessGeometry, bool loadCompositeGlyphs) {
msdfgen::GlyphIndex index;
if (msdfgen::getGlyphIndex(index, font, codepoint)) {
- if (load(font, geometryScale, index, preprocessGeometry)) {
+ if (load(font, geometryScale, index, preprocessGeometry, loadCompositeGlyphs)) {
this->codepoint = codepoint;
return true;
}
diff --git a/old/msdf-atlas-gen/msdf-atlas-gen/GlyphGeometry.h b/msdf-atlas-gen/msdf-atlas-gen/GlyphGeometry.h
index 6e0c13a..2010d70 100644
--- a/old/msdf-atlas-gen/msdf-atlas-gen/GlyphGeometry.h
+++ b/msdf-atlas-gen/msdf-atlas-gen/GlyphGeometry.h
@@ -24,8 +24,8 @@ public:
GlyphGeometry();
/// Loads glyph geometry from font
- 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);
+ bool load(msdfgen::FontHandle *font, double geometryScale, msdfgen::GlyphIndex index, bool preprocessGeometry = true, bool loadCompositeGlyphs = false);
+ bool load(msdfgen::FontHandle *font, double geometryScale, unicode_t codepoint, bool preprocessGeometry = true, bool loadCompositeGlyphs = false);
/// Applies edge coloring to glyph shape
void edgeColoring(void (*fn)(msdfgen::Shape &, double, unsigned long long), double angleThreshold, unsigned long long seed);
/// Computes the dimensions of the glyph's box as well as the transformation for the generator function
@@ -79,6 +79,10 @@ public:
/// Simplifies to GlyphBox
operator GlyphBox() const;
+ /// Returns subGlyphs for composite glyphs
+ const std::vector<msdfgen::CompositeGlyphInfo> &getSubGlyphs() const {
+ return subGlyphs;
+ }
private:
int index;
unicode_t codepoint;
@@ -94,6 +98,8 @@ private:
Padding outerPadding;
} box;
+ std::vector<msdfgen::CompositeGlyphInfo> subGlyphs;
+
};
msdfgen::Range operator+(msdfgen::Range a, msdfgen::Range b);
diff --git a/msdf-atlas-gen/msdfgen/core/GlyphInfo.h b/msdf-atlas-gen/msdfgen/core/GlyphInfo.h
new file mode 100644
index 0000000..ee39ba8
--- /dev/null
+++ b/msdf-atlas-gen/msdfgen/core/GlyphInfo.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include "Vector2.hpp"
+
+namespace msdfgen {
+ class GlyphIndex {
+ public:
+ explicit GlyphIndex(unsigned index = 0);
+ unsigned getIndex() const;
+
+ private:
+ unsigned index;
+
+ };
+
+ struct CompositeGlyphInfo {
+ GlyphIndex glyphIndex;
+ Vector2 position;
+ double matrix[2][2] {{1, 0}, {0, 1}};
+ };
+}
diff --git a/old/msdf-atlas-gen/msdfgen/ext/import-font.cpp b/msdf-atlas-gen/msdfgen/ext/import-font.cpp
index bbaf805..da94c4e 100644
--- a/old/msdf-atlas-gen/msdfgen/ext/import-font.cpp
+++ b/msdf-atlas-gen/msdfgen/ext/import-font.cpp
@@ -38,6 +38,7 @@ class FontHandle {
friend bool getFontWhitespaceWidth(double &spaceAdvance, double &tabAdvance, FontHandle *font, FontCoordinateScaling coordinateScaling);
friend bool getGlyphCount(unsigned &output, FontHandle *font);
friend bool getGlyphIndex(GlyphIndex &glyphIndex, FontHandle *font, unicode_t unicode);
+ friend bool loadCompositeGlyph(Shape &output, FontHandle *font, GlyphIndex glyphIndex, FontCoordinateScaling coordinateScaling, std::vector<CompositeGlyphInfo> &outSubGlyphs, double *outAdvance);
friend bool loadGlyph(Shape &output, FontHandle *font, GlyphIndex glyphIndex, FontCoordinateScaling coordinateScaling, double *outAdvance);
friend bool loadGlyph(Shape &output, FontHandle *font, unicode_t unicode, FontCoordinateScaling coordinateScaling, double *outAdvance);
friend bool getKerning(double &output, FontHandle *font, GlyphIndex glyphIndex0, GlyphIndex glyphIndex1, FontCoordinateScaling coordinateScaling);
@@ -229,7 +230,7 @@ bool getGlyphIndex(GlyphIndex &glyphIndex, FontHandle *font, unicode_t unicode)
bool loadGlyph(Shape &output, FontHandle *font, GlyphIndex glyphIndex, FontCoordinateScaling coordinateScaling, double *outAdvance) {
if (!font)
return false;
- FT_Error error = FT_Load_Glyph(font->face, glyphIndex.getIndex(), FT_LOAD_NO_SCALE);
+ FT_Error error = FT_Load_Glyph(font->face, glyphIndex.getIndex(), FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_TRANSFORM);
if (error)
return false;
double scale = getFontCoordinateScale(font->face, coordinateScaling);
@@ -238,6 +239,45 @@ bool loadGlyph(Shape &output, FontHandle *font, GlyphIndex glyphIndex, FontCoord
return !readFreetypeOutline(output, &font->face->glyph->outline, scale);
}
+bool loadCompositeGlyph(Shape &output, FontHandle *font, GlyphIndex glyphIndex, FontCoordinateScaling coordinateScaling, std::vector<CompositeGlyphInfo> &outSubGlyphs, double *outAdvance) {
+ if (!font)
+ return false;
+ FT_Error error = FT_Load_Glyph(font->face, glyphIndex.getIndex(), FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_TRANSFORM | FT_LOAD_NO_RECURSE);
+ if (error)
+ return false;
+ double scale = getFontCoordinateScale(font->face, coordinateScaling);
+
+ if (outAdvance)
+ *outAdvance = scale*font->face->glyph->advance.x;
+ if (readFreetypeOutline(output, &font->face->glyph->outline, scale))
+ return false;
+
+ for (FT_UInt i = 0; i < font->face->glyph->num_subglyphs; i++) {
+ FT_Int index;
+ FT_UInt flags;
+ FT_Int arg1;
+ FT_Int arg2;
+ FT_Matrix matrix;
+ if (FT_Get_SubGlyph_Info(font->face->glyph, i, &index, &flags, &arg1, &arg2, &matrix))
+ return false;
+
+ if (flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES) {
+ CompositeGlyphInfo &info = outSubGlyphs.emplace_back();
+ info.glyphIndex = GlyphIndex(index);
+ info.position = Vector2(F16DOT16_TO_DOUBLE(arg1), F16DOT16_TO_DOUBLE(arg2)) * scale;
+ info.matrix[0][0] = F16DOT16_TO_DOUBLE(matrix.xx) * scale;
+ info.matrix[0][1] = F16DOT16_TO_DOUBLE(matrix.xy) * scale;
+ info.matrix[1][0] = F16DOT16_TO_DOUBLE(matrix.yx) * scale;
+ info.matrix[1][1] = F16DOT16_TO_DOUBLE(matrix.yy) * scale;
+ } else {
+ // TODO: figure point snapping out
+ return false;
+ }
+ }
+
+ return true;
+}
+
bool loadGlyph(Shape &output, FontHandle *font, unicode_t unicode, FontCoordinateScaling coordinateScaling, double *outAdvance) {
return loadGlyph(output, font, GlyphIndex(FT_Get_Char_Index(font->face, unicode)), coordinateScaling, outAdvance);
}
diff --git a/old/msdf-atlas-gen/msdfgen/ext/import-font.h b/msdf-atlas-gen/msdfgen/ext/import-font.h
index c2bd81a..5c05808 100644
--- a/old/msdf-atlas-gen/msdfgen/ext/import-font.h
+++ b/msdf-atlas-gen/msdfgen/ext/import-font.h
@@ -2,6 +2,7 @@
#pragma once
#include "../core/Shape.h"
+#include "../core/GlyphInfo.h"
namespace msdfgen {
@@ -12,17 +13,6 @@ typedef unsigned unicode_t;
class FreetypeHandle;
class FontHandle;
-class GlyphIndex {
-
-public:
- explicit GlyphIndex(unsigned index = 0);
- unsigned getIndex() const;
-
-private:
- unsigned index;
-
-};
-
/// Global metrics of a typeface (in font units).
struct FontMetrics {
/// The size of one EM.
@@ -86,6 +76,8 @@ bool getGlyphIndex(GlyphIndex &glyphIndex, FontHandle *font, unicode_t unicode);
/// Loads the geometry of a glyph from a font.
bool loadGlyph(Shape &output, FontHandle *font, GlyphIndex glyphIndex, FontCoordinateScaling coordinateScaling, double *outAdvance = NULL);
bool loadGlyph(Shape &output, FontHandle *font, unicode_t unicode, FontCoordinateScaling coordinateScaling, double *outAdvance = NULL);
+/// Loads the geometry of a glyph from a font, loading every composite part separately.
+bool loadCompositeGlyph(Shape &output, FontHandle *font, GlyphIndex glyphIndex, FontCoordinateScaling coordinateScaling, std::vector<CompositeGlyphInfo> &outSubGlyphs, double *outAdvance = NULL);
// Legacy API - FontCoordinateScaling is LEGACY
bool loadGlyph(Shape &output, FontHandle *font, GlyphIndex glyphIndex, double *outAdvance = NULL);
bool loadGlyph(Shape &output, FontHandle *font, unicode_t unicode, double *outAdvance = NULL);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment