1414#include < nbl/builtin/hlsl/cpp_compat/vector.hlsl>
1515#include FT_FREETYPE_H
1616#include FT_OUTLINE_H
17+ #include FT_TRUETYPE_TABLES_H
18+ #include FT_SFNT_NAMES_H
19+ #include FT_MULTIPLE_MASTERS_H
1720
1821using namespace nbl ;
1922using namespace nbl ::core;
@@ -67,16 +70,6 @@ class TextRenderer : public nbl::core::IReferenceCounted
6770
6871class FontFace : public nbl ::core::IReferenceCounted
6972{
70-
71- protected:
72-
73- FontFace (core::smart_refctd_ptr<TextRenderer>&& textRenderer, FT_Face face, size_t hash)
74- {
75- m_textRenderer = std::move (textRenderer);
76- m_ftFace = face;
77- m_hash = hash;
78- }
79-
8073public:
8174
8275 // Face Global Metrics/Settings
@@ -100,14 +93,14 @@ class FontFace : public nbl::core::IReferenceCounted
10093 float64_t2 size;
10194 };
10295
103- static core::smart_refctd_ptr<FontFace> create (core::smart_refctd_ptr<TextRenderer>&& textRenderer, const std::string& path)
96+ static core::smart_refctd_ptr<FontFace> create (core::smart_refctd_ptr<TextRenderer>&& textRenderer, const std::string& path, int faceIdx = 0 )
10497 {
10598 FT_Face face;
106- FT_Error res = FT_New_Face (textRenderer->m_ftLibrary , path.c_str (), 0 , &face);
99+ FT_Error res = FT_New_Face (textRenderer->m_ftLibrary , path.c_str (), faceIdx , &face);
107100 if (res != 0 )
108101 return nullptr ;
109- size_t hash = std::hash<std::string>{}(path);
110- return core::smart_refctd_ptr<FontFace>(new FontFace (std::move (textRenderer), face, hash ), core::dont_grab);
102+
103+ return core::smart_refctd_ptr<FontFace>(new FontFace (std::move (textRenderer), face, path ), core::dont_grab);
111104 }
112105
113106 ~FontFace ()
@@ -141,7 +134,7 @@ class FontFace : public nbl::core::IReferenceCounted
141134 // transforms uv in glyph space to uv in the actual texture
142135 float32_t2 getUV (float32_t2 uv, float32_t2 glyphSize, uint32_t2 textureExtents, uint32_t msdfPixelRange);
143136
144- size_t getHash () { return m_hash; }
137+ core:: blake3_hash_t getHash () { return m_hash; }
145138
146139 // TODO: make these protected, it's only used for customized tests such as building shapes for hatches
147140 FT_GlyphSlot getGlyphSlot (uint32_t glyphId)
@@ -150,13 +143,88 @@ class FontFace : public nbl::core::IReferenceCounted
150143 assert (!error);
151144 return m_ftFace->glyph ;
152145 }
146+
153147 FT_Face getFreetypeFace () { return m_ftFace; }
148+
154149 msdfgen::Shape generateGlyphShape (uint32_t glyphId);
150+
151+ // Functions to Set and Query Masters:
152+
153+ bool hasMultipleMasters () const
154+ {
155+ return FT_HAS_MULTIPLE_MASTERS (m_ftFace);
156+ }
157+
158+ uint32_t getMastersCount () const
159+ {
160+ uint32_t numMasters = 0u ;
161+ if (hasMultipleMasters ())
162+ {
163+ FT_MM_Var* multipleMasterData;
164+ FT_Error res = FT_Get_MM_Var (m_ftFace, &multipleMasterData);
165+ if (res == 0 )
166+ {
167+ numMasters = multipleMasterData->num_namedstyles ;
168+ FT_Done_MM_Var (m_textRenderer->m_ftLibrary , multipleMasterData);
169+ }
170+ }
171+ return numMasters;
172+ }
173+
174+ bool setMasterIndex (uint32_t index)
175+ {
176+ FT_Error res = FT_Set_Named_Instance (m_ftFace, index);
177+ if (res == 0 )
178+ {
179+ calculateFaceHash ();
180+ return true ;
181+ }
182+ return false ;
183+ }
184+
185+ // bits [0,15] are for faceIndex given to create function / constructor
186+ // bits [16,30] are for masterIndex given to `setMasterIndex` if it was ever called successfully
187+ // bit 31 is always 0
188+ // See FreeType documentation: https://freetype.org/freetype2/docs/reference/ft2-face_creation.html#ft_face
189+ int32_t getFaceIndex () const
190+ {
191+ return static_cast <int32_t >(m_ftFace->face_index );
192+ }
193+
194+ // Each face may have multiple masters. to change face index you need to recreate your face and use `int faceIdx` param
195+ uint32_t getNumFaces () const { return m_ftFace->num_faces ; }
196+
197+ // Names:
198+ const char * getFontFamilyName () const { return m_ftFace->family_name ; }
199+ const char * getStyleName () const { return m_ftFace->style_name ; }
155200
156201protected:
202+
203+ void calculateFaceHash ()
204+ {
205+ core::blake3_hasher hasher;
206+ hasher.update (&m_ftFace->face_index , sizeof (FT_Long));
207+ hasher.update (&m_pathHash, sizeof (core::blake3_hash_t ));
208+ m_hash = static_cast <blake3_hash_t >(hasher);
209+ }
210+
211+ FontFace (core::smart_refctd_ptr<TextRenderer>&& textRenderer, FT_Face face, const std::string& path)
212+ {
213+ m_textRenderer = std::move (textRenderer);
214+ m_ftFace = face;
215+
216+ // calculate hash path and store it
217+ core::blake3_hasher hasher;
218+ hasher.update (path.data (), path.size ());
219+ m_pathHash = static_cast <blake3_hash_t >(hasher);
220+ // calculate final hash with faceIdx
221+ calculateFaceHash ();
222+ }
223+
157224 core::smart_refctd_ptr<TextRenderer> m_textRenderer;
158225 FT_Face m_ftFace;
159- size_t m_hash;
226+ core::blake3_hash_t m_pathHash;
227+ core::blake3_hash_t m_hash;
160228};
161229
162230// Helper class for building an msdfgen shape from a glyph
0 commit comments