Worked on FontManager
This commit is contained in:
parent
d5b5f93ed6
commit
93c73b1911
145
src/font.cpp
145
src/font.cpp
@ -1,11 +1,24 @@
|
||||
#include "font.hpp"
|
||||
#include "texture_atlas.hpp"
|
||||
#include "vulkan_allocator.hpp"
|
||||
#include "vulkan_instance.hpp"
|
||||
|
||||
#include <glm/exponential.hpp>
|
||||
#include <gz-util/exceptions.hpp>
|
||||
#include <gz-util/log.hpp>
|
||||
#include <gz-util/string/conversion.hpp>
|
||||
|
||||
namespace gz {
|
||||
namespace gz::vlk {
|
||||
|
||||
FontManager::FontManager(const std::string&& fontDir)
|
||||
: fontDir(fontDir) {
|
||||
FontManager::FontManager(VulkanInstance& instance, const std::string&& fontDir)
|
||||
: vk(instance), fontDir(fontDir)
|
||||
{
|
||||
fLog = Log(LogCreateInfo {
|
||||
.showLog = true,
|
||||
.storeLog = false,
|
||||
.prefix = "FontManager",
|
||||
.prefixColor = Color::BO_GREEN,
|
||||
});
|
||||
FT_Error error = FT_Init_FreeType(&freetype);
|
||||
if (error != FT_Err_Ok) {
|
||||
throw Exception("Could not load freetype library", "FontManager");
|
||||
@ -13,16 +26,132 @@ namespace gz {
|
||||
|
||||
}
|
||||
|
||||
FontManager::~FontManager() {
|
||||
FT_Error error = FT_Done_FreeType(freetype);
|
||||
if (error != FT_Err_Ok) {
|
||||
fLog.error("~FontManager: FT_Done_FreeType returned", error);
|
||||
}
|
||||
}
|
||||
|
||||
void FontManager::loadFont(const std::string& font) {
|
||||
FT_Error error = FT_New_Face(freetype, (fontDir + "/" + font).c_str(), 0, &faces[font]);
|
||||
|
||||
Font FontManager::getFont(const std::string& fontname) {
|
||||
if (fonts.contains(fontname)) {
|
||||
return fonts.at(fontname);
|
||||
}
|
||||
else {
|
||||
return loadFont(fontname);
|
||||
}
|
||||
}
|
||||
|
||||
Font FontManager::loadFont(const std::string& fontname) {
|
||||
static constexpr FT_Long faceIndex = 0;
|
||||
Font font = fontInfos.size();
|
||||
|
||||
fontInfos.emplace_back(FontInfo(TextureAtlas(vk, 48, 48, 16, 16, vk::Format::eR8Uint)));
|
||||
FT_Face& face = fontInfos.back().face;
|
||||
|
||||
FT_Error error = FT_New_Face(freetype, (fontDir + "/" + fontname).c_str(), faceIndex, &face);
|
||||
if (error != FT_Err_Ok) {
|
||||
throw Exception("Could not load font.", "FontManager::loadFont");
|
||||
}
|
||||
FT_Set_Pixel_Sizes(faces[font], 0, 48);
|
||||
if (FT_Load_Char(faces[font], 'X', FT_LOAD_RENDER)) {
|
||||
throw Exception("Could not load char.", "FontManager::loadFont");
|
||||
for (FT_Int i = 0; i < face->num_charmaps; i++) {
|
||||
if (face->charmaps[i]->encoding == ft_encoding_unicode) {
|
||||
face->charmap = face->charmaps[i];
|
||||
fLog("loadFont: loading", font, "with unicode charmap index", i);
|
||||
goto foundUnicodeMap;
|
||||
}
|
||||
fLog.log0("loadFont: Charmap", i, face->charmaps[i]->platform_id, face->charmaps[i]->encoding);
|
||||
}
|
||||
throw Exception("Could not find unicode char map for font '" + fontname + "'.", "FontManager::loadFont");
|
||||
foundUnicodeMap:
|
||||
/* FT_Set_Pixel_Sizes(fonts[font], 0, 48); */
|
||||
/* fonts[font]->charmap->encoding_idk */
|
||||
fLog("Font num_glyphs:", face->num_glyphs);
|
||||
addChars(font, "abcdefghijklmnopqrstuvxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789üß");
|
||||
return font;
|
||||
}
|
||||
|
||||
void FontManager::addChars(Font font, const std::string& chars) {
|
||||
FT_Face& face = fontInfos.at(font).face;
|
||||
TextureAtlas& atlas = fontInfos.at(font).atlas;
|
||||
auto& charInfoMap = fontInfos.at(font).charInfos;
|
||||
for (char c : chars) {
|
||||
if (charInfoMap.contains(c)) { continue; }
|
||||
FT_UInt charIndex = FT_Get_Char_Index(face, c);
|
||||
fLog("Char:", c, "index:", charIndex, "glyph index:", face->glyph->glyph_index, "bitmap rows/width:", face->glyph->bitmap.rows, face->glyph->bitmap.width, "bitmap ptr:", reinterpret_cast<uint64_t>(face->glyph->bitmap.buffer), "(before load char)");
|
||||
if (FT_Load_Char(face, c, FT_LOAD_RENDER)) {
|
||||
throw Exception(std::string("Could not load char.") + c, "FontManager::loadFont");
|
||||
}
|
||||
if (FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL)) {
|
||||
throw Exception(std::string("Could not render char.") + c, "FontManager::loadFont");
|
||||
}
|
||||
/* for (size_t i = 0; i < face->glyph->bitmap_left) */
|
||||
FT_Bitmap& bitmap = face->glyph->bitmap;
|
||||
fLog("Char:", c,
|
||||
"index:", charIndex,
|
||||
"glyph index:", face->glyph->glyph_index,
|
||||
"bitmap rows/width:", bitmap.rows, bitmap.width,
|
||||
"bitmap pitch:", bitmap.pitch,
|
||||
"bitmap ptr:", gz::toHexString(reinterpret_cast<uint64_t>(bitmap.buffer)));
|
||||
assert(bitmap.pitch > 0);
|
||||
CharInfo& charInfo = charInfoMap[c];
|
||||
charInfo.atlas = font;
|
||||
uint8_t bytesPerPixel = bitmap.width / bitmap.pitch;
|
||||
std::tie(charInfo.texCoordTopLeft, charInfo.texCoordBottomRight) = atlas.addTexture(bitmap.buffer, bitmap.rows, bitmap.width, bytesPerPixel);
|
||||
}
|
||||
}
|
||||
|
||||
void FontManager::createDescriptorResources() {
|
||||
// 1) layout
|
||||
// combined image sampler
|
||||
std::vector<vk::DescriptorSetLayoutBinding> samplerLayoutBindings(fontInfos.size(), {
|
||||
.binding = 0,
|
||||
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = vk::ShaderStageFlagBits::eFragment,
|
||||
/* .pImmutableSamplers = nullptr, */
|
||||
}
|
||||
);
|
||||
vk.createDescriptorSetLayout(samplerLayoutBindings, descriptorSetLayout);
|
||||
|
||||
// 2) pool
|
||||
vk::DescriptorPoolSize poolSize {
|
||||
.type = vk::DescriptorType::eCombinedImageSampler,
|
||||
.descriptorCount = vk.getMaxFramesInFlight(),
|
||||
};
|
||||
vk.createDescriptorPool({ poolSize }, vk.getMaxFramesInFlight(), descriptorPool);
|
||||
|
||||
// 3) Set
|
||||
vk.createDescriptorSet(descriptorSetLayout, descriptorPool, descriptorSet);
|
||||
|
||||
// 4) configure sets
|
||||
std::vector<vk::DescriptorImageInfo> imageInfos;
|
||||
for (auto it = fontInfos.cbegin(); it != fontInfos.cend(); it++) {
|
||||
imageInfos.emplace_back();
|
||||
imageInfos.back().imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
|
||||
imageInfos.back().imageView = it->atlas.getTextureImageView();
|
||||
imageInfos.back().sampler = it->atlas.getTextureSampler();
|
||||
}
|
||||
|
||||
vk::WriteDescriptorSet descriptorW {
|
||||
.dstSet = descriptorSet,
|
||||
.dstBinding = 0,
|
||||
.dstArrayElement = 0,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
|
||||
};
|
||||
descriptorW.setImageInfo(imageInfos);
|
||||
|
||||
// 1 write, no copies
|
||||
vk.getDevice().updateDescriptorSets(descriptorW, nullptr);
|
||||
fLog.log0("createDescriptorSets: Created descriptor sets.");
|
||||
}
|
||||
|
||||
|
||||
void FontManager::getTexCoords(Font font, char c, glm::vec2& texCoords) {
|
||||
CharInfo& charI = fontInfos.at(font).charInfos.at(c);
|
||||
fLog.log0("getTexCoords", texCoords, "textureInfo: topleft", charI.texCoordTopLeft, "botright", charI.texCoordBottomRight);
|
||||
texCoords = charI.texCoordTopLeft + texCoords * (charI.texCoordBottomRight - charI.texCoordTopLeft);
|
||||
}
|
||||
|
||||
}
|
||||
|
70
src/font.hpp
70
src/font.hpp
@ -1,20 +1,80 @@
|
||||
#pragma once
|
||||
|
||||
#include "texture_atlas.hpp"
|
||||
#include "vulkan_allocator.hpp"
|
||||
|
||||
#include <gz-util/string/utility.hpp>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
|
||||
namespace gz {
|
||||
#include <gz-util/log.hpp>
|
||||
|
||||
namespace gz::vlk {
|
||||
struct CharInfo {
|
||||
// TODO is atlas member needed?
|
||||
uint32_t atlas;
|
||||
glm::vec2 texCoordTopLeft;
|
||||
glm::vec2 texCoordBottomRight;
|
||||
};
|
||||
/// Handle
|
||||
using Font = uint16_t;
|
||||
struct FontInfo {
|
||||
FontInfo(TextureAtlas&& atlas) : atlas(atlas) {};
|
||||
FT_Face face;
|
||||
TextureAtlas atlas;
|
||||
using CharInfos = std::unordered_map<char, CharInfo>;
|
||||
CharInfos charInfos;
|
||||
};
|
||||
|
||||
|
||||
class FontManager {
|
||||
public:
|
||||
FontManager(const std::string&& fontDir);
|
||||
void loadFont(const std::string& font);
|
||||
const std::unordered_map<std::string, FT_Face>& getFaces() const { return faces; }
|
||||
FontManager(VulkanInstance& instance, const std::string&& fontDir);
|
||||
/**
|
||||
* @brief Load a font
|
||||
* @details
|
||||
* -# load face
|
||||
* -# set the charmap to unicode (throw if not found)
|
||||
*/
|
||||
~FontManager();
|
||||
FontManager(const FontManager& other) = delete;
|
||||
FontManager(FontManager&& other) = delete;
|
||||
Font getFont(const std::string& fontname);
|
||||
const std::unordered_map<std::string, Font>& getFonts() const { return fonts; }
|
||||
|
||||
void getTexCoords(Font font, const char c, glm::vec2& texCoords);
|
||||
const vk::DescriptorSet& getDescriptorSet() const { return descriptorSet; }
|
||||
const vk::DescriptorSetLayout& getDescriptorSetLayout() const { return descriptorSetLayout; }
|
||||
private:
|
||||
Font loadFont(const std::string& fontname);
|
||||
VulkanInstance& vk;
|
||||
FT_Library freetype;
|
||||
std::string fontDir;
|
||||
std::unordered_map<std::string, FT_Face> faces;
|
||||
Log fLog;
|
||||
|
||||
void addChars(Font font, const std::string& chars);
|
||||
/**
|
||||
* @name Font management
|
||||
*/
|
||||
/// @{
|
||||
/// Font name to handle
|
||||
std::unordered_map<std::string, Font> fonts;
|
||||
/// Font handle as index
|
||||
std::vector<FontInfo> fontInfos;
|
||||
/// @}
|
||||
/**
|
||||
* @name Create desciptors
|
||||
* @todo Currently the same as in TextureManager -> merge?
|
||||
* @see fm_descriptors
|
||||
*/
|
||||
/// @{
|
||||
vk::DescriptorSetLayout descriptorSetLayout;
|
||||
vk::DescriptorPool descriptorPool;
|
||||
vk::DescriptorSet descriptorSet;
|
||||
void createDescriptorResources();
|
||||
/// @}
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user