mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-10-31 07:20:04 +00:00 
			
		
		
		
	Create a text shader and font utility
This commit is contained in:
		
							parent
							
								
									817a59f741
								
							
						
					
					
						commit
						82b265b6d4
					
				
					 11 changed files with 473 additions and 5 deletions
				
			
		|  | @ -13,6 +13,7 @@ set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) | ||||||
| include(${PROJECT_SOURCE_DIR}/external/cmake-conan/conan.cmake) | include(${PROJECT_SOURCE_DIR}/external/cmake-conan/conan.cmake) | ||||||
| 
 | 
 | ||||||
| conan_cmake_configure(REQUIRES boost/1.76.0 | conan_cmake_configure(REQUIRES boost/1.76.0 | ||||||
|  |                                freetype/2.10.4 | ||||||
|                                geographiclib/1.52 |                                geographiclib/1.52 | ||||||
|                                glm/0.9.9.8 |                                glm/0.9.9.8 | ||||||
|                                gtest/cci.20210126 |                                gtest/cci.20210126 | ||||||
|  |  | ||||||
							
								
								
									
										12
									
								
								scwx-qt/gl/text.frag
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								scwx-qt/gl/text.frag
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | ||||||
|  | #version 330 core | ||||||
|  | in vec2 texCoords; | ||||||
|  | out vec4 color; | ||||||
|  | 
 | ||||||
|  | uniform sampler2D text; | ||||||
|  | uniform vec4 textColor; | ||||||
|  | 
 | ||||||
|  | void main() | ||||||
|  | { | ||||||
|  |    vec4 sampled = vec4(1.0f, 1.0f, 1.0f, texture(text, texCoords).r); | ||||||
|  |    color        = textColor * sampled; | ||||||
|  | } | ||||||
							
								
								
									
										11
									
								
								scwx-qt/gl/text.vert
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								scwx-qt/gl/text.vert
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,11 @@ | ||||||
|  | #version 330 core | ||||||
|  | layout (location = 0) in vec4 vertex; | ||||||
|  | out vec2 texCoords; | ||||||
|  | 
 | ||||||
|  | uniform mat4 projection; | ||||||
|  | 
 | ||||||
|  | void main() | ||||||
|  | { | ||||||
|  |    gl_Position = projection * vec4(vertex.xy, 0.0f, 1.0f); | ||||||
|  |    texCoords   = vertex.zw; | ||||||
|  | } | ||||||
|  | @ -12,6 +12,7 @@ set(CMAKE_CXX_STANDARD 17) | ||||||
| set(CMAKE_CXX_STANDARD_REQUIRED ON) | set(CMAKE_CXX_STANDARD_REQUIRED ON) | ||||||
| 
 | 
 | ||||||
| find_package(Boost) | find_package(Boost) | ||||||
|  | find_package(Freetype) | ||||||
| find_package(geographiclib) | find_package(geographiclib) | ||||||
| find_package(glm) | find_package(glm) | ||||||
| 
 | 
 | ||||||
|  | @ -51,6 +52,8 @@ set(HDR_MAIN source/scwx/qt/main/main_window.hpp) | ||||||
| set(SRC_MAIN source/scwx/qt/main/main.cpp | set(SRC_MAIN source/scwx/qt/main/main.cpp | ||||||
|              source/scwx/qt/main/main_window.cpp) |              source/scwx/qt/main/main_window.cpp) | ||||||
| set(UI_MAIN  source/scwx/qt/main/main_window.ui) | set(UI_MAIN  source/scwx/qt/main/main_window.ui) | ||||||
|  | set(HDR_GL source/scwx/qt/gl/text_shader.hpp) | ||||||
|  | set(SRC_GL source/scwx/qt/gl/text_shader.cpp) | ||||||
| set(HDR_MANAGER source/scwx/qt/manager/radar_manager.hpp) | set(HDR_MANAGER source/scwx/qt/manager/radar_manager.hpp) | ||||||
| set(SRC_MANAGER source/scwx/qt/manager/radar_manager.cpp) | set(SRC_MANAGER source/scwx/qt/manager/radar_manager.cpp) | ||||||
| set(HDR_MAP source/scwx/qt/map/map_widget.hpp | set(HDR_MAP source/scwx/qt/map/map_widget.hpp | ||||||
|  | @ -61,16 +64,20 @@ set(SRC_MAP source/scwx/qt/map/map_widget.cpp | ||||||
|             source/scwx/qt/map/radar_layer.cpp |             source/scwx/qt/map/radar_layer.cpp | ||||||
|             source/scwx/qt/map/radar_range_layer.cpp |             source/scwx/qt/map/radar_range_layer.cpp | ||||||
|             source/scwx/qt/map/triangle_layer.cpp) |             source/scwx/qt/map/triangle_layer.cpp) | ||||||
| set(HDR_UTIL source/scwx/qt/util/gl.hpp | set(HDR_UTIL source/scwx/qt/util/font.hpp | ||||||
|  |              source/scwx/qt/util/gl.hpp | ||||||
|              source/scwx/qt/util/shader_program.hpp) |              source/scwx/qt/util/shader_program.hpp) | ||||||
| set(SRC_UTIL source/scwx/qt/util/shader_program.cpp) | set(SRC_UTIL source/scwx/qt/util/font.cpp | ||||||
|  |              source/scwx/qt/util/shader_program.cpp) | ||||||
| set(HDR_VIEW source/scwx/qt/view/radar_view.hpp) | set(HDR_VIEW source/scwx/qt/view/radar_view.hpp) | ||||||
| set(SRC_VIEW source/scwx/qt/view/radar_view.cpp) | set(SRC_VIEW source/scwx/qt/view/radar_view.cpp) | ||||||
| 
 | 
 | ||||||
| set(RESOURCE_FILES scwx-qt.qrc) | set(RESOURCE_FILES scwx-qt.qrc) | ||||||
| 
 | 
 | ||||||
| set(SHADER_FILES gl/radar.frag | set(SHADER_FILES gl/radar.frag | ||||||
|                  gl/radar.vert) |                  gl/radar.vert | ||||||
|  |                  gl/text.frag | ||||||
|  |                  gl/text.vert) | ||||||
| 
 | 
 | ||||||
| set(TS_FILES ts/scwx_en_US.ts) | set(TS_FILES ts/scwx_en_US.ts) | ||||||
| 
 | 
 | ||||||
|  | @ -122,6 +129,7 @@ target_link_libraries(scwx-qt PRIVATE Qt${QT_VERSION_MAJOR}::Widgets | ||||||
|                                       Boost::timer |                                       Boost::timer | ||||||
|                                       qmapboxgl |                                       qmapboxgl | ||||||
|                                       opengl32 |                                       opengl32 | ||||||
|  |                                       Freetype::Freetype | ||||||
|                                       GeographicLib::GeographicLib |                                       GeographicLib::GeographicLib | ||||||
|                                       glm::glm |                                       glm::glm | ||||||
|                                       wxdata) |                                       wxdata) | ||||||
|  |  | ||||||
|  | @ -2,5 +2,7 @@ | ||||||
|     <qresource prefix="/"> |     <qresource prefix="/"> | ||||||
|         <file>gl/radar.frag</file> |         <file>gl/radar.frag</file> | ||||||
|         <file>gl/radar.vert</file> |         <file>gl/radar.vert</file> | ||||||
|  |         <file>gl/text.frag</file> | ||||||
|  |         <file>gl/text.vert</file> | ||||||
|     </qresource> |     </qresource> | ||||||
| </RCC> | </RCC> | ||||||
|  |  | ||||||
							
								
								
									
										155
									
								
								scwx-qt/source/scwx/qt/gl/text_shader.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								scwx-qt/source/scwx/qt/gl/text_shader.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,155 @@ | ||||||
|  | #include <scwx/qt/gl/text_shader.hpp> | ||||||
|  | 
 | ||||||
|  | #include <boost/log/trivial.hpp> | ||||||
|  | #include <glm/gtc/type_ptr.hpp> | ||||||
|  | 
 | ||||||
|  | namespace scwx | ||||||
|  | { | ||||||
|  | namespace qt | ||||||
|  | { | ||||||
|  | namespace gl | ||||||
|  | { | ||||||
|  | 
 | ||||||
|  | static const std::string logPrefix_ = "[scwx::qt::gl::text_shader] "; | ||||||
|  | 
 | ||||||
|  | class TextShaderImpl | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |    explicit TextShaderImpl(OpenGLFunctions& gl) : | ||||||
|  |        gl_ {gl}, | ||||||
|  |        projectionLocation_(GL_INVALID_INDEX), | ||||||
|  |        textColorLocation_(GL_INVALID_INDEX), | ||||||
|  |        vao_ {GL_INVALID_INDEX}, | ||||||
|  |        vbo_ {GL_INVALID_INDEX} | ||||||
|  |    { | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    ~TextShaderImpl() {} | ||||||
|  | 
 | ||||||
|  |    OpenGLFunctions& gl_; | ||||||
|  | 
 | ||||||
|  |    GLint projectionLocation_; | ||||||
|  |    GLint textColorLocation_; | ||||||
|  | 
 | ||||||
|  |    GLuint vao_; | ||||||
|  |    GLuint vbo_; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | TextShader::TextShader(OpenGLFunctions& gl) : | ||||||
|  |     ShaderProgram(gl), p(std::make_unique<TextShaderImpl>(gl)) | ||||||
|  | { | ||||||
|  | } | ||||||
|  | TextShader::~TextShader() = default; | ||||||
|  | 
 | ||||||
|  | TextShader::TextShader(TextShader&&) noexcept = default; | ||||||
|  | TextShader& TextShader::operator=(TextShader&&) noexcept = default; | ||||||
|  | 
 | ||||||
|  | bool TextShader::Initialize() | ||||||
|  | { | ||||||
|  |    OpenGLFunctions& gl = p->gl_; | ||||||
|  | 
 | ||||||
|  |    // Load and configure shader
 | ||||||
|  |    bool success = Load(":/gl/text.vert", ":/gl/text.frag"); | ||||||
|  | 
 | ||||||
|  |    p->projectionLocation_ = gl.glGetUniformLocation(id(), "projection"); | ||||||
|  |    if (p->projectionLocation_ == -1) | ||||||
|  |    { | ||||||
|  |       BOOST_LOG_TRIVIAL(warning) << logPrefix_ << "Could not find projection"; | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    p->textColorLocation_ = gl.glGetUniformLocation(id(), "textColor"); | ||||||
|  |    if (p->textColorLocation_ == -1) | ||||||
|  |    { | ||||||
|  |       BOOST_LOG_TRIVIAL(warning) << logPrefix_ << "Could not find textColor"; | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    gl.glGenVertexArrays(1, &p->vao_); | ||||||
|  |    gl.glGenBuffers(1, &p->vbo_); | ||||||
|  |    gl.glBindVertexArray(p->vao_); | ||||||
|  |    gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_); | ||||||
|  |    gl.glBufferData( | ||||||
|  |       GL_ARRAY_BUFFER, sizeof(float) * 6 * 4, nullptr, GL_DYNAMIC_DRAW); | ||||||
|  |    gl.glEnableVertexAttribArray(0); | ||||||
|  |    gl.glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0); | ||||||
|  |    gl.glBindBuffer(GL_ARRAY_BUFFER, 0); | ||||||
|  |    gl.glBindVertexArray(0); | ||||||
|  | 
 | ||||||
|  |    return success; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void TextShader::RenderText(const std::string&               text, | ||||||
|  |                             float                            x, | ||||||
|  |                             float                            y, | ||||||
|  |                             float                            scale, | ||||||
|  |                             const glm::mat4&                 projection, | ||||||
|  |                             const boost::gil::rgba8_pixel_t& color, | ||||||
|  |                             const std::unordered_map<char, util::Glyph>& glyphs) | ||||||
|  | { | ||||||
|  |    OpenGLFunctions& gl = p->gl_; | ||||||
|  | 
 | ||||||
|  |    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.glUniform4f( | ||||||
|  |       p->textColorLocation_, color[0], color[1], color[2], color[3]); | ||||||
|  | 
 | ||||||
|  |    gl.glActiveTexture(GL_TEXTURE0); | ||||||
|  |    gl.glBindVertexArray(p->vao_); | ||||||
|  | 
 | ||||||
|  |    for (auto c = text.cbegin(); c != text.cend(); c++) | ||||||
|  |    { | ||||||
|  |       if (glyphs.find(*c) == glyphs.end()) | ||||||
|  |       { | ||||||
|  |          continue; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       const util::Glyph& g = glyphs.at(*c); | ||||||
|  | 
 | ||||||
|  |       float xpos = x + g.bearing.x * scale; | ||||||
|  |       float ypos = y - (g.size.y - g.bearing.y) * scale; | ||||||
|  | 
 | ||||||
|  |       float w = g.size.x * scale; | ||||||
|  |       float h = g.size.y * scale; | ||||||
|  | 
 | ||||||
|  |       // Glyph vertices
 | ||||||
|  |       float vertices[6][4] = {{xpos, ypos + h, 0.0f, 0.0f}, | ||||||
|  |                               {xpos, ypos, 0.0f, 1.0f}, | ||||||
|  |                               {xpos + w, ypos, 1.0f, 1.0f}, //
 | ||||||
|  |                                                             //
 | ||||||
|  |                               {xpos, ypos + h, 0.0f, 0.0f}, | ||||||
|  |                               {xpos + w, ypos, 1.0f, 1.0f}, | ||||||
|  |                               {xpos + w, ypos + h, 1.0f, 0.0f}}; | ||||||
|  | 
 | ||||||
|  |       // Render glyph texture
 | ||||||
|  |       gl.glBindTexture(GL_TEXTURE_2D, g.textureId); | ||||||
|  | 
 | ||||||
|  |       gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_); | ||||||
|  |       gl.glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); | ||||||
|  |       gl.glBindBuffer(GL_ARRAY_BUFFER, 0); | ||||||
|  | 
 | ||||||
|  |       gl.glDrawArrays(GL_TRIANGLES, 0, 6); | ||||||
|  | 
 | ||||||
|  |       // Advance to the next glyph
 | ||||||
|  |       x += (g.advance >> 6) * scale; | ||||||
|  |    } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void TextShader::SetProjection(const glm::mat4& projection) | ||||||
|  | { | ||||||
|  |    p->gl_.glUniformMatrix4fv( | ||||||
|  |       p->projectionLocation_, 1, GL_FALSE, glm::value_ptr(projection)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void TextShader::SetTextColor(const boost::gil::rgba8_pixel_t color) | ||||||
|  | { | ||||||
|  |    p->gl_.glUniform4f( | ||||||
|  |       p->textColorLocation_, color[0], color[1], color[2], color[3]); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace gl
 | ||||||
|  | } // namespace qt
 | ||||||
|  | } // namespace scwx
 | ||||||
							
								
								
									
										49
									
								
								scwx-qt/source/scwx/qt/gl/text_shader.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								scwx-qt/source/scwx/qt/gl/text_shader.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,49 @@ | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <scwx/qt/util/shader_program.hpp> | ||||||
|  | #include <scwx/qt/util/font.hpp> | ||||||
|  | 
 | ||||||
|  | #include <memory> | ||||||
|  | 
 | ||||||
|  | #include <boost/gil.hpp> | ||||||
|  | #include <glm/glm.hpp> | ||||||
|  | 
 | ||||||
|  | namespace scwx | ||||||
|  | { | ||||||
|  | namespace qt | ||||||
|  | { | ||||||
|  | namespace gl | ||||||
|  | { | ||||||
|  | 
 | ||||||
|  | class TextShaderImpl; | ||||||
|  | 
 | ||||||
|  | class TextShader : public ShaderProgram | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |    explicit TextShader(OpenGLFunctions& gl); | ||||||
|  |    ~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, | ||||||
|  |                    const std::unordered_map<char, util::Glyph>& glyphs); | ||||||
|  |    void SetProjection(const glm::mat4& projection); | ||||||
|  |    void SetTextColor(const boost::gil::rgba8_pixel_t color); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |    std::unique_ptr<TextShaderImpl> p; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } // namespace gl
 | ||||||
|  | } // namespace qt
 | ||||||
|  | } // namespace scwx
 | ||||||
							
								
								
									
										179
									
								
								scwx-qt/source/scwx/qt/util/font.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										179
									
								
								scwx-qt/source/scwx/qt/util/font.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,179 @@ | ||||||
|  | #include <scwx/qt/util/font.hpp> | ||||||
|  | 
 | ||||||
|  | #include <mutex> | ||||||
|  | #include <unordered_map> | ||||||
|  | 
 | ||||||
|  | #include <boost/log/trivial.hpp> | ||||||
|  | #include <ft2build.h> | ||||||
|  | #include <QFile> | ||||||
|  | 
 | ||||||
|  | #include FT_FREETYPE_H | ||||||
|  | 
 | ||||||
|  | namespace scwx | ||||||
|  | { | ||||||
|  | namespace qt | ||||||
|  | { | ||||||
|  | namespace util | ||||||
|  | { | ||||||
|  | 
 | ||||||
|  | static const std::string logPrefix_ = "[scwx::qt::util::font] "; | ||||||
|  | 
 | ||||||
|  | static std::unordered_map<std::string, std::shared_ptr<Font>> fontMap_; | ||||||
|  | 
 | ||||||
|  | static FT_Library ft_ {nullptr}; | ||||||
|  | static std::mutex ftMutex_; | ||||||
|  | 
 | ||||||
|  | static bool InitializeFreeType(); | ||||||
|  | 
 | ||||||
|  | class FontImpl | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |    explicit FontImpl(const std::string& resource) : | ||||||
|  |        resource_(resource), fontData_(), face_ {nullptr} | ||||||
|  |    { | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    ~FontImpl() {} | ||||||
|  | 
 | ||||||
|  |    const std::string resource_; | ||||||
|  | 
 | ||||||
|  |    QByteArray fontData_; | ||||||
|  |    FT_Face    face_; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | Font::Font(const std::string& resource) : | ||||||
|  |     p(std::make_unique<FontImpl>(resource)) | ||||||
|  | { | ||||||
|  | } | ||||||
|  | Font::~Font() | ||||||
|  | { | ||||||
|  |    FT_Done_Face(p->face_); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void Font::GenerateGlyphs(OpenGLFunctions&                 gl, | ||||||
|  |                           std::unordered_map<char, Glyph>& glyphs, | ||||||
|  |                           unsigned int                     height) | ||||||
|  | { | ||||||
|  |    FT_Error error; | ||||||
|  |    FT_Face& face = p->face_; | ||||||
|  | 
 | ||||||
|  |    // Allow single-byte texture colors
 | ||||||
|  |    gl.glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | ||||||
|  | 
 | ||||||
|  |    FT_Set_Pixel_Sizes(p->face_, 0, 48); | ||||||
|  | 
 | ||||||
|  |    for (unsigned char c = 0; c < 128; c++) | ||||||
|  |    { | ||||||
|  |       if (glyphs.find(c) != glyphs.end()) | ||||||
|  |       { | ||||||
|  |          BOOST_LOG_TRIVIAL(warning) << logPrefix_ << "Found glyph " | ||||||
|  |                                     << static_cast<uint16_t>(c) << ", skipping"; | ||||||
|  |          continue; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       if ((error = FT_Load_Char(face, c, FT_LOAD_RENDER)) != 0) | ||||||
|  |       { | ||||||
|  |          BOOST_LOG_TRIVIAL(error) << logPrefix_ << "Failed to load glyph " | ||||||
|  |                                   << static_cast<uint16_t>(c) << ": " << error; | ||||||
|  |          continue; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       GLuint texture; | ||||||
|  |       gl.glGenTextures(1, &texture); | ||||||
|  |       gl.glBindTexture(GL_TEXTURE_2D, texture); | ||||||
|  | 
 | ||||||
|  |       gl.glTexImage2D(GL_TEXTURE_2D, | ||||||
|  |                       0, | ||||||
|  |                       GL_RED, | ||||||
|  |                       face->glyph->bitmap.width, | ||||||
|  |                       face->glyph->bitmap.rows, | ||||||
|  |                       0, | ||||||
|  |                       GL_RED, | ||||||
|  |                       GL_UNSIGNED_BYTE, | ||||||
|  |                       face->glyph->bitmap.buffer); | ||||||
|  | 
 | ||||||
|  |       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); | ||||||
|  | 
 | ||||||
|  |       glyphs.insert( | ||||||
|  |          {c, | ||||||
|  |           Glyph { | ||||||
|  |              texture, | ||||||
|  |              glm::ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows), | ||||||
|  |              glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top), | ||||||
|  |              face->glyph->advance.x}}); | ||||||
|  |    } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | std::shared_ptr<Font> Font::Create(const std::string& resource) | ||||||
|  | { | ||||||
|  |    std::shared_ptr<Font> font = nullptr; | ||||||
|  |    FT_Error              error; | ||||||
|  | 
 | ||||||
|  |    if (!InitializeFreeType()) | ||||||
|  |    { | ||||||
|  |       return font; | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    auto it = fontMap_.find(resource); | ||||||
|  |    if (it != fontMap_.end()) | ||||||
|  |    { | ||||||
|  |       return it->second; | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    QFile fontFile(resource.c_str()); | ||||||
|  |    fontFile.open(QIODevice::ReadOnly); | ||||||
|  |    if (!fontFile.isOpen()) | ||||||
|  |    { | ||||||
|  |       BOOST_LOG_TRIVIAL(error) | ||||||
|  |          << logPrefix_ << "Could not read font file: " << resource; | ||||||
|  |       return font; | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    font               = std::make_shared<Font>(resource); | ||||||
|  |    font->p->fontData_ = fontFile.readAll(); | ||||||
|  | 
 | ||||||
|  |    { | ||||||
|  |       std::scoped_lock(ftMutex_); | ||||||
|  |       if ((error = FT_New_Memory_Face( | ||||||
|  |               ft_, | ||||||
|  |               reinterpret_cast<const FT_Byte*>(font->p->fontData_.data()), | ||||||
|  |               font->p->fontData_.size(), | ||||||
|  |               0, | ||||||
|  |               &font->p->face_)) != 0) | ||||||
|  |       { | ||||||
|  |          BOOST_LOG_TRIVIAL(error) | ||||||
|  |             << logPrefix_ << "Failed to load font: " << error; | ||||||
|  |          font.reset(); | ||||||
|  |       } | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    if (font != nullptr) | ||||||
|  |    { | ||||||
|  |       fontMap_.insert({resource, font}); | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    return font; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool InitializeFreeType() | ||||||
|  | { | ||||||
|  |    std::scoped_lock(ftMutex_); | ||||||
|  | 
 | ||||||
|  |    FT_Error error; | ||||||
|  | 
 | ||||||
|  |    if (ft_ == nullptr && (error = FT_Init_FreeType(&ft_)) != 0) | ||||||
|  |    { | ||||||
|  |       BOOST_LOG_TRIVIAL(error) | ||||||
|  |          << logPrefix_ << "Could not init FreeType library: " << error; | ||||||
|  |       ft_ = nullptr; | ||||||
|  |    } | ||||||
|  | 
 | ||||||
|  |    return (ft_ != nullptr); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace util
 | ||||||
|  | } // namespace qt
 | ||||||
|  | } // namespace scwx
 | ||||||
							
								
								
									
										51
									
								
								scwx-qt/source/scwx/qt/util/font.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								scwx-qt/source/scwx/qt/util/font.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,51 @@ | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <scwx/qt/util/gl.hpp> | ||||||
|  | 
 | ||||||
|  | #include <memory> | ||||||
|  | #include <string> | ||||||
|  | 
 | ||||||
|  | #include <glm/glm.hpp> | ||||||
|  | 
 | ||||||
|  | namespace scwx | ||||||
|  | { | ||||||
|  | namespace qt | ||||||
|  | { | ||||||
|  | namespace util | ||||||
|  | { | ||||||
|  | 
 | ||||||
|  | struct Glyph | ||||||
|  | { | ||||||
|  |    GLuint     textureId; | ||||||
|  |    glm::ivec2 size;    // pixels
 | ||||||
|  |    glm::ivec2 bearing; // pixels
 | ||||||
|  |    GLint      advance; // 1/64 pixels
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 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; | ||||||
|  | 
 | ||||||
|  |    void GenerateGlyphs(OpenGLFunctions&                 gl, | ||||||
|  |                        std::unordered_map<char, Glyph>& glyphs, | ||||||
|  |                        unsigned int                     height); | ||||||
|  | 
 | ||||||
|  |    static std::shared_ptr<Font> Create(const std::string& resource); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |    std::unique_ptr<FontImpl> p; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } // namespace util
 | ||||||
|  | } // namespace qt
 | ||||||
|  | } // namespace scwx
 | ||||||
|  | @ -147,7 +147,7 @@ bool ShaderProgram::Load(const std::string& vertexPath, | ||||||
|    gl.glDeleteShader(vertexShader); |    gl.glDeleteShader(vertexShader); | ||||||
|    gl.glDeleteShader(fragmentShader); |    gl.glDeleteShader(fragmentShader); | ||||||
| 
 | 
 | ||||||
|    return false; |    return success; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ShaderProgram::Use() const | void ShaderProgram::Use() const | ||||||
|  |  | ||||||
|  | @ -20,7 +20,7 @@ class ShaderProgram | ||||||
| { | { | ||||||
| public: | public: | ||||||
|    explicit ShaderProgram(OpenGLFunctions& gl); |    explicit ShaderProgram(OpenGLFunctions& gl); | ||||||
|    ~ShaderProgram(); |    virtual ~ShaderProgram(); | ||||||
| 
 | 
 | ||||||
|    ShaderProgram(const ShaderProgram&) = delete; |    ShaderProgram(const ShaderProgram&) = delete; | ||||||
|    ShaderProgram& operator=(const ShaderProgram&) = delete; |    ShaderProgram& operator=(const ShaderProgram&) = delete; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Dan Paulat
						Dan Paulat