9 std::shared_ptr<Font>
Font::Create(
const std::filesystem::path& path,
const std::vector<CharsetRange>& charsets,
const float minimalScale ,
const float miterLimit ) {
11 std::shared_ptr<Font> coriFont = std::make_shared<Font>();
14 msdfgen::FreetypeHandle* ft = msdfgen::initializeFreetype();
16 msdfgen::FontHandle* font = msdfgen::loadFont(ft, path.string().c_str());
18 coriFont->Load(
static_cast<void*
>(font), charsets, path, minimalScale, miterLimit);
20 msdfgen::destroyFont(font);
31 msdfgen::deinitializeFreetype(ft);
36 std::shared_ptr<Font>
Font::Create(
const Descriptor& descriptor) {
37 return Create(descriptor.m_FontPath, descriptor.m_CharsetRanges, descriptor.m_MinimalScale, descriptor.m_MiterLimit);
44 void Font::Load(
void* font,
const std::vector<CharsetRange>& charsets,
const std::filesystem::path& fontPath,
const float minimalScale,
const float miterLimit) {
46 auto font_ =
static_cast<msdfgen::FontHandle*
>(font);
50 msdf_atlas::Charset charset;
52 for (
const auto& [m_Start, m_End] : charsets) {
53 for (uint32_t c = m_Start; c <= m_End; ++c) {
60 int32_t loadedCount = m_Data->m_FontGeometry.loadCharset(font_, 1.0f, charset);
61 if (loadedCount > 0) {
67 constexpr float angleThreshold = 3.0f;
68 for (msdf_atlas::GlyphGeometry& glyph : m_Data->m_Glyphs) {
69 glyph.edgeColoring(&msdfgen::edgeColoringInkTrap, angleThreshold, 0);
72 msdf_atlas::TightAtlasPacker packer;
73 packer.setDimensionsConstraint(msdf_atlas::DimensionsConstraint::SQUARE);
74 packer.setMinimumScale(minimalScale);
76 packer.setPixelRange(2.0);
77 packer.setMiterLimit(miterLimit);
79 int32_t notPackedCount = packer.pack(m_Data->m_Glyphs.data(), m_Data->m_Glyphs.size());
80 if (notPackedCount > 0) {
84 m_Data->m_FinalScale = packer.getScale();
86 std::filesystem::path target = std::filesystem::path(
"cache") /
"fonts" / (fontPath.stem().
string() +
"Cache.bin");
88 std::filesystem::create_directories(target.parent_path());
90 size_t fontFileSize = std::filesystem::file_size(fontPath);
92 static auto CheckCached = [&]() ->
bool {
93 std::ifstream f(target, std::ios::in | std::ios::binary);
106 f.seekg(0, std::ios::end);
107 size_t fileSize = f.tellg();
108 f.seekg(0, std::ios::beg);
110 std::vector<unsigned char> buffer(fileSize);
112 f.read(
reinterpret_cast<char*
>(buffer.data()), fileSize);
116 auto widthLoaded = *
reinterpret_cast<int32_t*
>(&buffer[0]);
117 auto heightLoaded = *
reinterpret_cast<int32_t*
>(&buffer[4]);
118 auto finalSizeLoaded = *
reinterpret_cast<double*
>(&buffer[8]);
119 auto miterLimitLoaded = *
reinterpret_cast<float*
>(&buffer[16]);
120 auto cachedFontFileSize = *
reinterpret_cast<size_t*
>(&buffer[20]);
122 if (finalSizeLoaded != m_Data->m_FinalScale) {
127 if (miterLimitLoaded != miterLimit) {
132 if (cachedFontFileSize != fontFileSize) {
137 for (
const auto& [m_Start, m_End] : charsets) {
139 for (uint32_t i = 0; i < static_cast<uint32_t>(buffer[28]); ++i) {
140 size_t startPos = 32 + i * 8;
141 auto start = *
reinterpret_cast<uint32_t*
>(&buffer[startPos]);
142 auto end = *
reinterpret_cast<uint32_t*
>(&buffer[startPos + 4]);
144 if (start == m_Start && end == m_End) {
156 size_t assumedAtlasSize = widthLoaded * 3 * heightLoaded;
157 size_t pixelsOffset = 32 +
static_cast<uint32_t
>(buffer[28]) * 8;
158 size_t actualAtlasSize = fileSize - pixelsOffset;
160 if (assumedAtlasSize != actualAtlasSize) {
167 void* pixels = &buffer[pixelsOffset];
171 void* data = malloc(assumedAtlasSize);
172 memcpy(data, pixels, assumedAtlasSize);
174 std::shared_ptr<Font> subject = shared_from_this();
177 subject->m_Data->m_Atlas =
Texture2D::Create(data, widthLoaded, heightLoaded, params2);
186 bool regenerate = CheckCached();
191 packer.getDimensions(width, height);
192 msdf_atlas::ImmediateAtlasGenerator<float, 3, msdf_atlas::msdfGenerator, msdf_atlas::BitmapAtlasStorage<msdf_atlas::byte, 3>> generator(width, height);
193 msdf_atlas::GeneratorAttributes attributes;
194 attributes.scanlinePass =
true;
195 generator.setAttributes(attributes);
196 int32_t n = std::thread::hardware_concurrency();
198 generator.setThreadCount(n);
202 generator.setThreadCount(n - 4);
204 generator.setThreadCount(n / 2);
208 generator.generate(m_Data->m_Glyphs.data(), m_Data->m_Glyphs.size());
209 msdfgen::BitmapConstRef<msdf_atlas::byte, 3> storage = generator.atlasStorage();
211 std::ofstream out(target, std::ios::out | std::ios::binary);
213 uint32_t charsetSize = charsets.size();
226 out.write(
reinterpret_cast<const char*
>(&storage.width),
sizeof(storage.width));
227 out.write(
reinterpret_cast<const char*
>(&storage.height),
sizeof(storage.height));
228 out.write(
reinterpret_cast<const char*
>(&m_Data->m_FinalScale),
sizeof(m_Data->m_FinalScale));
229 out.write(
reinterpret_cast<const char*
>(&miterLimit),
sizeof(miterLimit));
230 out.write(
reinterpret_cast<const char*
>(&fontFileSize),
sizeof(fontFileSize));
231 out.write(
reinterpret_cast<const char*
>(&charsetSize),
sizeof(charsetSize));
233 for (
const auto& [m_Start, m_End] : charsets) {
234 out.write(
reinterpret_cast<const char*
>(&m_Start),
sizeof(m_Start));
235 out.write(
reinterpret_cast<const char*
>(&m_End),
sizeof(m_End));
238 out.write(
reinterpret_cast<const char*
>(storage.pixels), storage.width * 3 * storage.height);
242 void* data = malloc(storage.width * 3 * storage.height);
243 memcpy(data, storage.pixels, storage.width * 3 * storage.height);
247 std::shared_ptr<Font> subject = shared_from_this();
248 int32_t w = storage.width;
249 int32_t h = storage.height;
#define CORI_CLEAN_TYPE_NAME(tn)
#define CORI_CORE_DEBUG_TAGGED(...)
#define CORI_CORE_FATAL_TAGGED(...)
#define CORI_CORE_ASSERT(x,...)
#define CORI_CORE_ERROR_TAGGED(...)
#define CORI_CORE_WARN_TAGGED(...)
#define CORI_CORE_INFO_TAGGED(...)
#define CORI_PROFILE_FUNCTION()
static bool HasPlaceholder()
Checks if an asset type have placeholder registered.
static std::future< std::invoke_result_t< F, Args... > > SubmitMainTask(F &&f, Args &&... args)
Submits a task to be executed on the main thread.
static std::future< std::invoke_result_t< F, Args... > > SubmitWorkerTask(F &&f, Args &&... args)
Submits a task to be executed on the worker thread.
AssetStatus GetStatus() const
static std::shared_ptr< Font > Create(const std::filesystem::path &path, const std::vector< CharsetRange > &charsets, const float minimalScale=48.0f, const float miterLimit=1.0f)
Creates a Font object.
static std::shared_ptr< Texture2D > Create(const std::shared_ptr< Image > &image)
Creates a Texture2D from the Image.
Almost everything connected to graphics is in this namespace.