mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-10-31 01:30:05 +00:00 
			
		
		
		
	Cleanup unused freetype dependencies and old text rendering
This commit is contained in:
		
							parent
							
								
									a98d978cc6
								
							
						
					
					
						commit
						c2918daebf
					
				
					 16 changed files with 4 additions and 1044 deletions
				
			
		|  | @ -1,124 +0,0 @@ | |||
| #include <scwx/qt/gl/text_shader.hpp> | ||||
| #include <scwx/qt/gl/shader_program.hpp> | ||||
| #include <scwx/util/logger.hpp> | ||||
| 
 | ||||
| #if defined(_MSC_VER) | ||||
| #   pragma warning(push, 0) | ||||
| #endif | ||||
| 
 | ||||
| #include <glm/gtc/type_ptr.hpp> | ||||
| 
 | ||||
| #if defined(_MSC_VER) | ||||
| #   pragma warning(pop) | ||||
| #endif | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
| { | ||||
| namespace gl | ||||
| { | ||||
| 
 | ||||
| static const std::string logPrefix_ = "scwx::qt::gl::text_shader"; | ||||
| static const auto        logger_    = scwx::util::Logger::Create(logPrefix_); | ||||
| 
 | ||||
| class TextShaderImpl | ||||
| { | ||||
| public: | ||||
|    explicit TextShaderImpl(std::shared_ptr<GlContext> context) : | ||||
|        context_ {context}, | ||||
|        shaderProgram_ {nullptr}, | ||||
|        projectionLocation_(GL_INVALID_INDEX) | ||||
|    { | ||||
|    } | ||||
| 
 | ||||
|    ~TextShaderImpl() {} | ||||
| 
 | ||||
|    std::shared_ptr<GlContext>     context_; | ||||
|    std::shared_ptr<ShaderProgram> shaderProgram_; | ||||
| 
 | ||||
|    GLint projectionLocation_; | ||||
| }; | ||||
| 
 | ||||
| TextShader::TextShader(std::shared_ptr<GlContext> context) : | ||||
|     p(std::make_unique<TextShaderImpl>(context)) | ||||
| { | ||||
| } | ||||
| TextShader::~TextShader() = default; | ||||
| 
 | ||||
| TextShader::TextShader(TextShader&&) noexcept            = default; | ||||
| TextShader& TextShader::operator=(TextShader&&) noexcept = default; | ||||
| 
 | ||||
| bool TextShader::Initialize() | ||||
| { | ||||
|    OpenGLFunctions& gl = p->context_->gl(); | ||||
| 
 | ||||
|    // Load and configure shader
 | ||||
|    p->shaderProgram_ = | ||||
|       p->context_->GetShaderProgram(":/gl/text.vert", ":/gl/text.frag"); | ||||
| 
 | ||||
|    p->projectionLocation_ = | ||||
|       gl.glGetUniformLocation(p->shaderProgram_->id(), "projection"); | ||||
|    if (p->projectionLocation_ == -1) | ||||
|    { | ||||
|       logger_->warn("Could not find projection"); | ||||
|    } | ||||
| 
 | ||||
|    return true; | ||||
| } | ||||
| 
 | ||||
| void TextShader::RenderText(const std::string&               text, | ||||
|                             float                            x, | ||||
|                             float                            y, | ||||
|                             float                            pointSize, | ||||
|                             const glm::mat4&                 projection, | ||||
|                             const boost::gil::rgba8_pixel_t& color, | ||||
|                             std::shared_ptr<util::Font>      font, | ||||
|                             GLuint                           textureId, | ||||
|                             TextAlign                        align) | ||||
| { | ||||
|    OpenGLFunctions& gl = p->context_->gl(); | ||||
| 
 | ||||
|    p->shaderProgram_->Use(); | ||||
| 
 | ||||
|    gl.glEnable(GL_BLEND); | ||||
|    gl.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | ||||
| 
 | ||||
|    gl.glUniformMatrix4fv( | ||||
|       p->projectionLocation_, 1, GL_FALSE, glm::value_ptr(projection)); | ||||
| 
 | ||||
|    gl.glActiveTexture(GL_TEXTURE0); | ||||
|    gl.glBindTexture(GL_TEXTURE_2D, textureId); | ||||
| 
 | ||||
|    switch (align) | ||||
|    { | ||||
|    case TextAlign::Left: | ||||
|       // Do nothing
 | ||||
|       break; | ||||
| 
 | ||||
|    case TextAlign::Center: | ||||
|       // X position is the center of text, subtract half length
 | ||||
|       x -= font->TextLength(text, pointSize) * 0.5f; | ||||
|       break; | ||||
| 
 | ||||
|    case TextAlign::Right: | ||||
|       // X position is the end of text, subtract length
 | ||||
|       x -= font->TextLength(text, pointSize); | ||||
|       break; | ||||
|    } | ||||
| 
 | ||||
|    std::shared_ptr<util::FontBuffer> buffer = | ||||
|       std::make_shared<util::FontBuffer>(); | ||||
|    font->BufferText(buffer, text, x, y, pointSize, color); | ||||
|    buffer->Render(gl); | ||||
| } | ||||
| 
 | ||||
| void TextShader::SetProjection(const glm::mat4& projection) | ||||
| { | ||||
|    p->context_->gl().glUniformMatrix4fv( | ||||
|       p->projectionLocation_, 1, GL_FALSE, glm::value_ptr(projection)); | ||||
| } | ||||
| 
 | ||||
| } // namespace gl
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
|  | @ -1,57 +0,0 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <scwx/qt/gl/gl_context.hpp> | ||||
| #include <scwx/qt/util/font.hpp> | ||||
| 
 | ||||
| #include <memory> | ||||
| 
 | ||||
| #include <boost/gil.hpp> | ||||
| #include <glm/glm.hpp> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
| { | ||||
| namespace gl | ||||
| { | ||||
| 
 | ||||
| enum class TextAlign | ||||
| { | ||||
|    Left, | ||||
|    Center, | ||||
|    Right | ||||
| }; | ||||
| 
 | ||||
| class TextShaderImpl; | ||||
| 
 | ||||
| class TextShader | ||||
| { | ||||
| public: | ||||
|    explicit TextShader(std::shared_ptr<GlContext> context); | ||||
|    ~TextShader(); | ||||
| 
 | ||||
|    TextShader(const TextShader&)            = delete; | ||||
|    TextShader& operator=(const TextShader&) = delete; | ||||
| 
 | ||||
|    TextShader(TextShader&&) noexcept; | ||||
|    TextShader& operator=(TextShader&&) noexcept; | ||||
| 
 | ||||
|    bool Initialize(); | ||||
|    void RenderText(const std::string&               text, | ||||
|                    float                            x, | ||||
|                    float                            y, | ||||
|                    float                            scale, | ||||
|                    const glm::mat4&                 projection, | ||||
|                    const boost::gil::rgba8_pixel_t& color, | ||||
|                    std::shared_ptr<util::Font>      font, | ||||
|                    GLuint                           textureId, | ||||
|                    TextAlign                        align = TextAlign::Left); | ||||
|    void SetProjection(const glm::mat4& projection); | ||||
| 
 | ||||
| private: | ||||
|    std::unique_ptr<TextShaderImpl> p; | ||||
| }; | ||||
| 
 | ||||
| } // namespace gl
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
|  | @ -1,7 +1,6 @@ | |||
| #include <scwx/qt/map/overlay_layer.hpp> | ||||
| #include <scwx/qt/gl/draw/rectangle.hpp> | ||||
| #include <scwx/qt/gl/shader_program.hpp> | ||||
| #include <scwx/qt/gl/text_shader.hpp> | ||||
| #include <scwx/util/logger.hpp> | ||||
| #include <scwx/util/time.hpp> | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,408 +0,0 @@ | |||
| // No suitable standard C++ replacement
 | ||||
| #define _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING | ||||
| 
 | ||||
| // Disable strncpy warning
 | ||||
| #define _CRT_SECURE_NO_WARNINGS | ||||
| 
 | ||||
| #include <scwx/qt/util/font.hpp> | ||||
| #include <scwx/qt/model/imgui_context_model.hpp> | ||||
| #include <scwx/qt/settings/general_settings.hpp> | ||||
| #include <scwx/util/logger.hpp> | ||||
| 
 | ||||
| #include <codecvt> | ||||
| #include <unordered_map> | ||||
| 
 | ||||
| #include <boost/timer/timer.hpp> | ||||
| #include <fmt/format.h> | ||||
| #include <imgui.h> | ||||
| #include <QFile> | ||||
| #include <QFileInfo> | ||||
| 
 | ||||
| #include <ft2build.h> | ||||
| #include FT_FREETYPE_H | ||||
| #include FT_SFNT_NAMES_H | ||||
| #include FT_TRUETYPE_IDS_H | ||||
| 
 | ||||
| #if defined(_MSC_VER) | ||||
| #   pragma warning(push, 0) | ||||
| #endif | ||||
| 
 | ||||
| #if defined(__GNUC__) | ||||
| #   pragma GCC diagnostic push | ||||
| #   pragma GCC diagnostic ignored "-Wpedantic" | ||||
| #endif | ||||
| 
 | ||||
| // #include <freetype-gl.h> (exclude opengl.h)
 | ||||
| #include <platform.h> | ||||
| #include <vec234.h> | ||||
| #include <vector.h> | ||||
| #include <texture-atlas.h> | ||||
| #include <texture-font.h> | ||||
| #include <ftgl-utils.h> | ||||
| 
 | ||||
| #if defined(__GNUC__) | ||||
| #   pragma GCC diagnostic pop | ||||
| #endif | ||||
| 
 | ||||
| #if defined(_MSC_VER) | ||||
| #   pragma warning(pop) | ||||
| #endif | ||||
| 
 | ||||
| #ifdef WIN32 | ||||
| #   include <WinSock2.h> | ||||
| #else | ||||
| #   include <arpa/inet.h> | ||||
| #endif | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
| { | ||||
| namespace util | ||||
| { | ||||
| 
 | ||||
| struct TextureGlyph | ||||
| { | ||||
|    int   offsetX_; | ||||
|    int   offsetY_; | ||||
|    int   width_; | ||||
|    int   height_; | ||||
|    float s0_; | ||||
|    float t0_; | ||||
|    float s1_; | ||||
|    float t1_; | ||||
|    float advanceX_; | ||||
| 
 | ||||
|    TextureGlyph(int   offsetX, | ||||
|                 int   offsetY, | ||||
|                 int   width, | ||||
|                 int   height, | ||||
|                 float s0, | ||||
|                 float t0, | ||||
|                 float s1, | ||||
|                 float t1, | ||||
|                 float advanceX) : | ||||
|        offsetX_ {offsetX}, | ||||
|        offsetY_ {offsetY}, | ||||
|        width_ {width}, | ||||
|        height_ {height}, | ||||
|        s0_ {s0}, | ||||
|        t0_ {t0}, | ||||
|        s1_ {s1}, | ||||
|        t1_ {t1}, | ||||
|        advanceX_ {advanceX} | ||||
|    { | ||||
|    } | ||||
| }; | ||||
| 
 | ||||
| static const std::string CODEPOINTS = | ||||
|    " !\"#$%&'()*+,-./0123456789:;<=>?" | ||||
|    "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" | ||||
|    "`abcdefghijklmnopqrstuvwxyz{|}~"; | ||||
| 
 | ||||
| static const std::string logPrefix_ = "scwx::qt::util::font"; | ||||
| static const auto        logger_    = scwx::util::Logger::Create(logPrefix_); | ||||
| 
 | ||||
| static constexpr float BASE_POINT_SIZE = 72.0f; | ||||
| static constexpr float POINT_SCALE     = 1.0f / BASE_POINT_SIZE; | ||||
| 
 | ||||
| static std::unordered_map<std::string, std::shared_ptr<Font>> fontMap_; | ||||
| 
 | ||||
| static void ParseSfntName(const FT_SfntName& sfntName, std::string& str); | ||||
| 
 | ||||
| class FontImpl | ||||
| { | ||||
| public: | ||||
|    explicit FontImpl(const std::string& resource) : | ||||
|        resource_(resource), atlas_ {nullptr} | ||||
|    { | ||||
|    } | ||||
| 
 | ||||
|    ~FontImpl() | ||||
|    { | ||||
|       if (atlas_ != nullptr) | ||||
|       { | ||||
|          ftgl::texture_atlas_delete(atlas_); | ||||
|       } | ||||
|    } | ||||
| 
 | ||||
|    void ParseNames(FT_Face face); | ||||
| 
 | ||||
|    const std::string resource_; | ||||
| 
 | ||||
|    struct | ||||
|    { | ||||
|       std::string fontFamily_; | ||||
|       std::string fontSubfamily_; | ||||
|    } fontData_; | ||||
| 
 | ||||
|    ftgl::texture_atlas_t*                 atlas_; | ||||
|    std::unordered_map<char, TextureGlyph> glyphs_; | ||||
|    std::unordered_map<size_t, ImFont*>    imGuiFonts_; | ||||
| }; | ||||
| 
 | ||||
| Font::Font(const std::string& resource) : | ||||
|     p(std::make_unique<FontImpl>(resource)) | ||||
| { | ||||
| } | ||||
| Font::~Font() = default; | ||||
| 
 | ||||
| float Font::BufferText(std::shared_ptr<FontBuffer> buffer, | ||||
|                        const std::string&          text, | ||||
|                        float                       x, | ||||
|                        float                       y, | ||||
|                        float                       pointSize, | ||||
|                        boost::gil::rgba8_pixel_t   color) const | ||||
| { | ||||
|    static constexpr float colorScale = 1.0f / 255.0f; | ||||
| 
 | ||||
|    const float scale = pointSize * POINT_SCALE; | ||||
| 
 | ||||
|    float r = color[0] * colorScale; | ||||
|    float g = color[1] * colorScale; | ||||
|    float b = color[2] * colorScale; | ||||
|    float a = color[3] * colorScale; | ||||
| 
 | ||||
|    for (size_t i = 0; i < text.length(); ++i) | ||||
|    { | ||||
|       const char& c = text[i]; | ||||
| 
 | ||||
|       auto it = p->glyphs_.find(c); | ||||
|       if (it == p->glyphs_.end()) | ||||
|       { | ||||
|          logger_->info("Could not draw character: {}", | ||||
|                        static_cast<uint32_t>(c)); | ||||
|          continue; | ||||
|       } | ||||
| 
 | ||||
|       TextureGlyph& glyph = it->second; | ||||
| 
 | ||||
|       if (i > 0) | ||||
|       { | ||||
|          x += Kerning(text[i - 1], c) * scale; | ||||
|       } | ||||
| 
 | ||||
|       float x0 = x + glyph.offsetX_ * scale; | ||||
|       float y0 = y + glyph.offsetY_ * scale; | ||||
|       float x1 = x0 + glyph.width_ * scale; | ||||
|       float y1 = y0 - glyph.height_ * scale; | ||||
| 
 | ||||
|       float s0 = glyph.s0_; | ||||
|       float t0 = glyph.t0_; | ||||
|       float s1 = glyph.s1_; | ||||
|       float t1 = glyph.t1_; | ||||
| 
 | ||||
|       buffer->Push(/* Indices  */ {0, 1, 2, 0, 2, 3},             //
 | ||||
|                    /* Vertices */ {x0, y0, 0, s0, t0, r, g, b, a, //
 | ||||
|                                    x0, y1, 0, s0, t1, r, g, b, a, //
 | ||||
|                                    x1, y1, 0, s1, t1, r, g, b, a, //
 | ||||
|                                    x1, y0, 0, s1, t0, r, g, b, a}); | ||||
| 
 | ||||
|       x += glyph.advanceX_ * scale; | ||||
|    } | ||||
| 
 | ||||
|    return x; | ||||
| } | ||||
| 
 | ||||
| float Font::Kerning(char /*c1*/, char /*c2*/) const | ||||
| { | ||||
|    // TODO
 | ||||
|    return 0.0f; | ||||
| } | ||||
| 
 | ||||
| float Font::TextLength(const std::string& text, float pointSize) const | ||||
| { | ||||
|    const float scale = pointSize * POINT_SCALE; | ||||
| 
 | ||||
|    float x = 0.0f; | ||||
| 
 | ||||
|    for (size_t i = 0; i < text.length(); ++i) | ||||
|    { | ||||
|       const char& c = text[i]; | ||||
| 
 | ||||
|       auto it = p->glyphs_.find(c); | ||||
|       if (it == p->glyphs_.end()) | ||||
|       { | ||||
|          logger_->info("Character not found: {}", static_cast<uint32_t>(c)); | ||||
|          continue; | ||||
|       } | ||||
| 
 | ||||
|       TextureGlyph& glyph = it->second; | ||||
| 
 | ||||
|       if (i > 0) | ||||
|       { | ||||
|          x += Kerning(text[i - 1], c) * scale; | ||||
|       } | ||||
| 
 | ||||
|       x += glyph.advanceX_ * scale; | ||||
|    } | ||||
| 
 | ||||
|    return x; | ||||
| } | ||||
| 
 | ||||
| GLuint Font::GenerateTexture(gl::OpenGLFunctions& gl) | ||||
| { | ||||
|    gl.glGenTextures(1, &p->atlas_->id); | ||||
|    gl.glBindTexture(GL_TEXTURE_2D, p->atlas_->id); | ||||
| 
 | ||||
|    gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | ||||
|    gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | ||||
|    gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | ||||
|    gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | ||||
| 
 | ||||
|    gl.glTexImage2D(GL_TEXTURE_2D, | ||||
|                    0, | ||||
|                    GL_RED, | ||||
|                    static_cast<GLsizei>(p->atlas_->width), | ||||
|                    static_cast<GLsizei>(p->atlas_->height), | ||||
|                    0, | ||||
|                    GL_RED, | ||||
|                    GL_UNSIGNED_BYTE, | ||||
|                    p->atlas_->data); | ||||
| 
 | ||||
|    return p->atlas_->id; | ||||
| } | ||||
| 
 | ||||
| ImFont* Font::ImGuiFont(std::size_t fontPixelSize) | ||||
| { | ||||
|    auto it = p->imGuiFonts_.find(fontPixelSize); | ||||
|    if (it != p->imGuiFonts_.cend()) | ||||
|    { | ||||
|       return it->second; | ||||
|    } | ||||
|    return nullptr; | ||||
| } | ||||
| 
 | ||||
| std::shared_ptr<Font> Font::Create(const std::string& resource) | ||||
| { | ||||
|    logger_->debug("Loading font file: {}", resource); | ||||
| 
 | ||||
|    std::shared_ptr<Font>   font = nullptr; | ||||
|    boost::timer::cpu_timer timer; | ||||
| 
 | ||||
|    auto it = fontMap_.find(resource); | ||||
|    if (it != fontMap_.end()) | ||||
|    { | ||||
|       logger_->debug("Font already created"); | ||||
|       return it->second; | ||||
|    } | ||||
| 
 | ||||
|    QFile fontFile(resource.c_str()); | ||||
|    fontFile.open(QIODevice::ReadOnly); | ||||
|    if (!fontFile.isOpen()) | ||||
|    { | ||||
|       logger_->error("Could not read font file"); | ||||
|       return font; | ||||
|    } | ||||
| 
 | ||||
|    font                = std::make_shared<Font>(resource); | ||||
|    QByteArray fontData = fontFile.readAll(); | ||||
| 
 | ||||
|    font->p->atlas_                   = ftgl::texture_atlas_new(512, 512, 1); | ||||
|    ftgl::texture_font_t* textureFont = ftgl::texture_font_new_from_memory( | ||||
|       font->p->atlas_, BASE_POINT_SIZE, fontData.constData(), fontData.size()); | ||||
| 
 | ||||
|    font->p->ParseNames(textureFont->face); | ||||
| 
 | ||||
|    textureFont->rendermode = ftgl::RENDER_SIGNED_DISTANCE_FIELD; | ||||
| 
 | ||||
|    timer.start(); | ||||
|    texture_font_load_glyphs(textureFont, CODEPOINTS.c_str()); | ||||
|    timer.stop(); | ||||
| 
 | ||||
|    // Single-byte UTF-8 characters
 | ||||
|    for (const char& c : CODEPOINTS) | ||||
|    { | ||||
|       const ftgl::texture_glyph_t* glyph = | ||||
|          ftgl::texture_font_get_glyph(textureFont, &c); | ||||
| 
 | ||||
|       if (glyph != nullptr) | ||||
|       { | ||||
|          font->p->glyphs_.emplace(c, | ||||
|                                   TextureGlyph(glyph->offset_x, | ||||
|                                                glyph->offset_y, | ||||
|                                                static_cast<int>(glyph->width), | ||||
|                                                static_cast<int>(glyph->height), | ||||
|                                                glyph->s0, | ||||
|                                                glyph->t0, | ||||
|                                                glyph->s1, | ||||
|                                                glyph->t1, | ||||
|                                                glyph->advance_x)); | ||||
|       } | ||||
|    } | ||||
| 
 | ||||
|    logger_->debug("Font loaded in {}", timer.format(6, "%ws")); | ||||
| 
 | ||||
|    texture_font_delete(textureFont); | ||||
| 
 | ||||
|    if (font != nullptr) | ||||
|    { | ||||
|       fontMap_.insert({resource, font}); | ||||
|    } | ||||
| 
 | ||||
|    return font; | ||||
| } | ||||
| 
 | ||||
| void FontImpl::ParseNames(FT_Face face) | ||||
| { | ||||
|    FT_SfntName sfntName; | ||||
|    FT_Error    error; | ||||
| 
 | ||||
|    FT_UInt nameCount = FT_Get_Sfnt_Name_Count(face); | ||||
| 
 | ||||
|    for (FT_UInt i = 0; i < nameCount; i++) | ||||
|    { | ||||
|       error = FT_Get_Sfnt_Name(face, i, &sfntName); | ||||
| 
 | ||||
|       if (error == 0) | ||||
|       { | ||||
|          switch (sfntName.name_id) | ||||
|          { | ||||
|          case TT_NAME_ID_FONT_FAMILY: | ||||
|             ParseSfntName(sfntName, fontData_.fontFamily_); | ||||
|             break; | ||||
| 
 | ||||
|          case TT_NAME_ID_FONT_SUBFAMILY: | ||||
|             ParseSfntName(sfntName, fontData_.fontSubfamily_); | ||||
|             break; | ||||
|          } | ||||
|       } | ||||
|    } | ||||
| 
 | ||||
|    logger_->debug( | ||||
|       "Font family: {} ({})", fontData_.fontFamily_, fontData_.fontSubfamily_); | ||||
| } | ||||
| 
 | ||||
| static void ParseSfntName(const FT_SfntName& sfntName, std::string& str) | ||||
| { | ||||
|    if (str.empty()) | ||||
|    { | ||||
|       if (sfntName.platform_id == TT_PLATFORM_MICROSOFT && | ||||
|           sfntName.encoding_id == TT_MS_ID_UNICODE_CS) | ||||
|       { | ||||
|          char16_t* tempString = new char16_t[sfntName.string_len / 2]; | ||||
|          memcpy(tempString, sfntName.string, sfntName.string_len); | ||||
| 
 | ||||
|          for (size_t j = 0; j < sfntName.string_len / 2; j++) | ||||
|          { | ||||
|             tempString[j] = ntohs(tempString[j]); | ||||
|          } | ||||
| 
 | ||||
|          str = | ||||
|             std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> {} | ||||
|                .to_bytes(tempString, tempString + sfntName.string_len / 2); | ||||
| 
 | ||||
|          delete[] tempString; | ||||
|       } | ||||
|       else if (sfntName.platform_id == TT_PLATFORM_MACINTOSH && | ||||
|                sfntName.encoding_id == TT_MAC_ID_ROMAN) | ||||
|       { | ||||
|          str = std::string(reinterpret_cast<char*>(sfntName.string), | ||||
|                            sfntName.string_len); | ||||
|       } | ||||
|    } | ||||
| } | ||||
| 
 | ||||
| } // namespace util
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
|  | @ -1,55 +0,0 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <scwx/qt/gl/gl.hpp> | ||||
| #include <scwx/qt/util/font_buffer.hpp> | ||||
| 
 | ||||
| #include <memory> | ||||
| #include <string> | ||||
| 
 | ||||
| #include <boost/gil/typedefs.hpp> | ||||
| 
 | ||||
| struct ImFont; | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
| { | ||||
| namespace util | ||||
| { | ||||
| 
 | ||||
| class FontImpl; | ||||
| 
 | ||||
| class Font | ||||
| { | ||||
| public: | ||||
|    explicit Font(const std::string& resource); | ||||
|    ~Font(); | ||||
| 
 | ||||
|    Font(const Font&)            = delete; | ||||
|    Font& operator=(const Font&) = delete; | ||||
| 
 | ||||
|    Font(Font&&)            = delete; | ||||
|    Font& operator=(Font&&) = delete; | ||||
| 
 | ||||
|    float BufferText(std::shared_ptr<FontBuffer> buffer, | ||||
|                     const std::string&          text, | ||||
|                     float                       x, | ||||
|                     float                       y, | ||||
|                     float                       pointSize, | ||||
|                     boost::gil::rgba8_pixel_t   color) const; | ||||
|    float Kerning(char c1, char c2) const; | ||||
|    float TextLength(const std::string& text, float pointSize) const; | ||||
| 
 | ||||
|    ImFont* ImGuiFont(std::size_t fontPixelSize); | ||||
| 
 | ||||
|    GLuint GenerateTexture(gl::OpenGLFunctions& gl); | ||||
| 
 | ||||
|    static std::shared_ptr<Font> Create(const std::string& resource); | ||||
| 
 | ||||
| private: | ||||
|    std::unique_ptr<FontImpl> p; | ||||
| }; | ||||
| 
 | ||||
| } // namespace util
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
|  | @ -1,184 +0,0 @@ | |||
| #include <scwx/qt/util/font_buffer.hpp> | ||||
| #include <scwx/util/logger.hpp> | ||||
| 
 | ||||
| #include <mutex> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
| { | ||||
| namespace util | ||||
| { | ||||
| 
 | ||||
| static const std::string logPrefix_ = "scwx::qt::util::font_buffer"; | ||||
| static const auto        logger_    = scwx::util::Logger::Create(logPrefix_); | ||||
| 
 | ||||
| class FontBufferImpl | ||||
| { | ||||
| public: | ||||
|    explicit FontBufferImpl() : | ||||
|        vaoId_ {GL_INVALID_INDEX}, | ||||
|        verticesId_ {GL_INVALID_INDEX}, | ||||
|        indicesId_ {GL_INVALID_INDEX}, | ||||
|        gpuISize_ {0}, | ||||
|        gpuVSize_ {0}, | ||||
|        dirty_ {true} | ||||
|    { | ||||
|    } | ||||
| 
 | ||||
|    ~FontBufferImpl() {} | ||||
| 
 | ||||
|    void RenderSetup(gl::OpenGLFunctions& gl) | ||||
|    { | ||||
|       // Generate and setup VAO
 | ||||
|       gl.glGenVertexArrays(1, &vaoId_); | ||||
|       gl.glBindVertexArray(vaoId_); | ||||
| 
 | ||||
|       gl.glBindBuffer(GL_ARRAY_BUFFER, verticesId_); | ||||
| 
 | ||||
|       // vec3 aVertex
 | ||||
|       gl.glEnableVertexAttribArray(0); | ||||
|       gl.glVertexAttribPointer( | ||||
|          0, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(float), nullptr); | ||||
| 
 | ||||
|       // vec2 aTexCoords
 | ||||
|       gl.glEnableVertexAttribArray(1); | ||||
|       gl.glVertexAttribPointer( | ||||
|          1, | ||||
|          2, | ||||
|          GL_FLOAT, | ||||
|          GL_FALSE, | ||||
|          9 * sizeof(float), | ||||
|          reinterpret_cast<const GLvoid*>(3 * sizeof(float))); | ||||
| 
 | ||||
|       // vec4 aColor
 | ||||
|       gl.glEnableVertexAttribArray(2); | ||||
|       gl.glVertexAttribPointer( | ||||
|          2, | ||||
|          4, | ||||
|          GL_FLOAT, | ||||
|          GL_FALSE, | ||||
|          9 * sizeof(float), | ||||
|          reinterpret_cast<const GLvoid*>(5 * sizeof(float))); | ||||
| 
 | ||||
|       gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indicesId_); | ||||
|    } | ||||
| 
 | ||||
|    void Upload(gl::OpenGLFunctions& gl) | ||||
|    { | ||||
|       if (verticesId_ == GL_INVALID_INDEX) | ||||
|       { | ||||
|          gl.glGenBuffers(1, &verticesId_); | ||||
|       } | ||||
|       if (indicesId_ == GL_INVALID_INDEX) | ||||
|       { | ||||
|          gl.glGenBuffers(1, &indicesId_); | ||||
|       } | ||||
| 
 | ||||
|       GLsizei vSize = static_cast<GLsizei>(vertices_.size() * sizeof(GLfloat)); | ||||
|       GLsizei iSize = static_cast<GLsizei>(indices_.size() * sizeof(GLuint)); | ||||
| 
 | ||||
|       // Always upload vertices first to avoid rendering non-existent data
 | ||||
| 
 | ||||
|       // Upload vertices
 | ||||
|       gl.glBindBuffer(GL_ARRAY_BUFFER, verticesId_); | ||||
|       if (vSize != gpuVSize_) | ||||
|       { | ||||
|          gl.glBufferData( | ||||
|             GL_ARRAY_BUFFER, vSize, vertices_.data(), GL_DYNAMIC_DRAW); | ||||
|          gpuVSize_ = vSize; | ||||
|       } | ||||
|       else | ||||
|       { | ||||
|          gl.glBufferSubData(GL_ARRAY_BUFFER, 0, vSize, vertices_.data()); | ||||
|       } | ||||
| 
 | ||||
|       // Upload indices
 | ||||
|       gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indicesId_); | ||||
|       if (iSize != gpuISize_) | ||||
|       { | ||||
|          gl.glBufferData( | ||||
|             GL_ELEMENT_ARRAY_BUFFER, iSize, indices_.data(), GL_DYNAMIC_DRAW); | ||||
|       } | ||||
|       else | ||||
|       { | ||||
|          gl.glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, iSize, indices_.data()); | ||||
|       } | ||||
| 
 | ||||
|       dirty_ = false; | ||||
|    } | ||||
| 
 | ||||
|    GLuint  vaoId_; | ||||
|    GLuint  verticesId_; | ||||
|    GLuint  indicesId_; | ||||
|    GLsizei gpuISize_; | ||||
|    GLsizei gpuVSize_; | ||||
|    bool    dirty_; | ||||
| 
 | ||||
|    std::vector<GLfloat> vertices_; | ||||
|    std::vector<GLuint>  indices_; | ||||
| 
 | ||||
|    std::mutex mutex_; | ||||
| }; | ||||
| 
 | ||||
| FontBuffer::FontBuffer() : p(std::make_unique<FontBufferImpl>()) {} | ||||
| FontBuffer::~FontBuffer() = default; | ||||
| 
 | ||||
| void FontBuffer::Clear() | ||||
| { | ||||
|    if (!p->indices_.empty() || !p->vertices_.empty()) | ||||
|    { | ||||
|       std::scoped_lock lock(p->mutex_); | ||||
|       p->indices_.clear(); | ||||
|       p->vertices_.clear(); | ||||
|       p->dirty_ = true; | ||||
|    } | ||||
| } | ||||
| 
 | ||||
| void FontBuffer::Push(std::initializer_list<GLuint>  indices, | ||||
|                       std::initializer_list<GLfloat> vertices) | ||||
| { | ||||
|    if (indices.size() % 3 != 0 || vertices.size() % 9 != 0) | ||||
|    { | ||||
|       logger_->warn("Invalid push arguments, ignoring"); | ||||
|       return; | ||||
|    } | ||||
| 
 | ||||
|    std::scoped_lock lock(p->mutex_); | ||||
| 
 | ||||
|    GLuint indexStart = static_cast<GLuint>(p->vertices_.size() / 9); | ||||
| 
 | ||||
|    for (GLuint index : indices) | ||||
|    { | ||||
|       p->indices_.push_back(index + indexStart); | ||||
|    } | ||||
| 
 | ||||
|    p->vertices_.insert(p->vertices_.end(), vertices); | ||||
| } | ||||
| 
 | ||||
| void FontBuffer::Render(gl::OpenGLFunctions& gl) | ||||
| { | ||||
|    std::scoped_lock lock(p->mutex_); | ||||
| 
 | ||||
|    if (p->dirty_) | ||||
|    { | ||||
|       p->Upload(gl); | ||||
|    } | ||||
| 
 | ||||
|    if (p->vaoId_ == GL_INVALID_INDEX) | ||||
|    { | ||||
|       p->RenderSetup(gl); | ||||
|    } | ||||
| 
 | ||||
|    // Bind VAO for drawing
 | ||||
|    gl.glBindVertexArray(p->vaoId_); | ||||
| 
 | ||||
|    gl.glDrawElements(GL_TRIANGLES, | ||||
|                      static_cast<GLsizei>(p->indices_.size()), | ||||
|                      GL_UNSIGNED_INT, | ||||
|                      0); | ||||
| } | ||||
| 
 | ||||
| } // namespace util
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
|  | @ -1,39 +0,0 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <scwx/qt/gl/gl.hpp> | ||||
| 
 | ||||
| #include <memory> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
| { | ||||
| namespace util | ||||
| { | ||||
| 
 | ||||
| class FontBufferImpl; | ||||
| 
 | ||||
| class FontBuffer | ||||
| { | ||||
| public: | ||||
|    explicit FontBuffer(); | ||||
|    ~FontBuffer(); | ||||
| 
 | ||||
|    FontBuffer(const FontBuffer&) = delete; | ||||
|    FontBuffer& operator=(const FontBuffer&) = delete; | ||||
| 
 | ||||
|    FontBuffer(FontBuffer&&) = delete; | ||||
|    FontBuffer& operator=(FontBuffer&&) = delete; | ||||
| 
 | ||||
|    void Clear(); | ||||
|    void Push(std::initializer_list<GLuint>  indices, | ||||
|              std::initializer_list<GLfloat> vertices); | ||||
|    void Render(gl::OpenGLFunctions& gl); | ||||
| 
 | ||||
| private: | ||||
|    std::unique_ptr<FontBufferImpl> p; | ||||
| }; | ||||
| 
 | ||||
| } // namespace util
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Dan Paulat
						Dan Paulat