Smallcase folders part 1
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
#include "Display/UI/Text/Fonts.h"
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include <stdexcept>
|
||||
#include <iostream>
|
||||
#include <filesystem>
|
||||
#include "Helpers/Paths.h"
|
||||
|
||||
namespace display::ui::text
|
||||
{
|
||||
struct Fonts::Library
|
||||
{
|
||||
FT_Library library = nullptr;
|
||||
};
|
||||
struct Fonts::Face
|
||||
{
|
||||
FT_Face face = nullptr;
|
||||
};
|
||||
|
||||
Fonts::Fonts()
|
||||
: library(std::make_unique<Library>())
|
||||
{
|
||||
if (FT_Init_FreeType(&library->library))
|
||||
throw std::runtime_error("FT_Init_FreeType failed");
|
||||
|
||||
loadAllFonts();
|
||||
}
|
||||
|
||||
Fonts::~Fonts()
|
||||
{
|
||||
for (auto &[k, v] : fonts)
|
||||
if (v->face)
|
||||
FT_Done_Face(v->face);
|
||||
if (library->library)
|
||||
FT_Done_FreeType(library->library);
|
||||
}
|
||||
|
||||
void Fonts::loadAllFonts()
|
||||
{
|
||||
loadFonts("/usr/share/fonts/truetype");
|
||||
loadFonts(helpers::initPaths().exeDir);
|
||||
}
|
||||
|
||||
void Fonts::loadFonts(const std::string &path)
|
||||
{
|
||||
if (std::filesystem::exists(path))
|
||||
{
|
||||
for (auto &p : std::filesystem::recursive_directory_iterator(path))
|
||||
{
|
||||
if (p.path().extension() == ".ttf" || p.path().extension() == ".otf")
|
||||
{
|
||||
std::string path = p.path().string();
|
||||
std::string filename = p.path().stem().string();
|
||||
|
||||
// Можно сразу создавать Fonts для стандартных размеров, например: 10,12,14,16,18,24
|
||||
for (int sz : {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 24, 36, 72})
|
||||
{
|
||||
Font key{filename, sz};
|
||||
|
||||
std::unique_ptr<Face> face = std::make_unique<Face>();
|
||||
if (FT_New_Face(library->library, path.c_str(), 0, &face->face))
|
||||
throw std::runtime_error("FT_New_Face failed");
|
||||
FT_Set_Pixel_Sizes(face->face, 0, sz);
|
||||
|
||||
fonts.emplace(key, std::move(face));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const Glyph &Fonts::getGlyph(char ch, const Font &font)
|
||||
{
|
||||
|
||||
GlyphKey key{ch, font};
|
||||
|
||||
auto gph = glyphs.find(key);
|
||||
if (gph != glyphs.end())
|
||||
return gph->second;
|
||||
|
||||
auto fnt = fonts.find(font);
|
||||
if (fnt == fonts.end())
|
||||
{
|
||||
// Если нет, можно использовать какой-нибудь дефолтный шрифт
|
||||
fnt = fonts.begin();
|
||||
}
|
||||
|
||||
FT_Face face = fnt->second->face;
|
||||
|
||||
if (!face)
|
||||
throw std::runtime_error("Fonts not initialized!");
|
||||
if (FT_Load_Char(face, ch, FT_LOAD_RENDER | FT_LOAD_TARGET_MONO))
|
||||
throw std::runtime_error("FT_Load_Char failed");
|
||||
FT_GlyphSlot g = face->glyph;
|
||||
|
||||
Glyph glyph;
|
||||
glyph.width = g->bitmap.width;
|
||||
glyph.height = g->bitmap.rows;
|
||||
glyph.bearingX = g->bitmap_left;
|
||||
glyph.bearingY = g->bitmap_top;
|
||||
glyph.advance = g->advance.x >> 6;
|
||||
// glyph.buffer.assign(g->bitmap.buffer, g->bitmap.buffer + g->bitmap.width * g->bitmap.rows);
|
||||
|
||||
glyph.buffer.resize(glyph.width * glyph.height, 0);
|
||||
|
||||
const FT_Bitmap &bm = g->bitmap;
|
||||
for (int y = 0; y < bm.rows; ++y)
|
||||
{
|
||||
for (int x = 0; x < bm.width; ++x)
|
||||
{
|
||||
int byteIndex = y * bm.pitch + x / 8;
|
||||
int bitIndex = 7 - (x % 8);
|
||||
uint8_t bit = (bm.buffer[byteIndex] >> bitIndex) & 1;
|
||||
glyph.buffer[y * bm.width + x] = bit ? 255 : 0;
|
||||
}
|
||||
}
|
||||
return glyphs.emplace(key, std::move(glyph)).first->second;
|
||||
}
|
||||
} // namespace display::ui::text
|
||||
Reference in New Issue
Block a user