Cleanup unused freetype dependencies and old text rendering

This commit is contained in:
Dan Paulat 2023-11-17 21:21:37 -06:00
parent a98d978cc6
commit c2918daebf
16 changed files with 4 additions and 1044 deletions

3
.gitmodules vendored
View file

@ -10,9 +10,6 @@
[submodule "external/hsluv-c"]
path = external/hsluv-c
url = https://github.com/hsluv/hsluv-c.git
[submodule "external/freetype-gl"]
path = external/freetype-gl
url = https://github.com/rougier/freetype-gl.git
[submodule "external/stb"]
path = external/stb
url = https://github.com/nothings/stb.git

View file

@ -5,7 +5,6 @@ class SupercellWxConan(ConanFile):
requires = ("boost/1.83.0",
"cpr/1.10.5",
"fontconfig/2.14.2",
"freetype/2.13.0",
"geographiclib/2.3",
"glew/2.2.0",
"glm/cci.20230113",

View file

@ -6,7 +6,6 @@ set_property(DIRECTORY
PROPERTY CMAKE_CONFIGURE_DEPENDS
aws-sdk-cpp.cmake
date.cmake
freetype-gl.cmake
hsluv-c.cmake
imgui.cmake
mapbox-gl-native.cmake
@ -16,7 +15,6 @@ set_property(DIRECTORY
include(aws-sdk-cpp.cmake)
include(date.cmake)
include(freetype-gl.cmake)
include(hsluv-c.cmake)
include(imgui.cmake)
include(mapbox-gl-native.cmake)

@ -1 +0,0 @@
Subproject commit 65b746d300e1b67033795ebb794b093eeae3b4d0

View file

@ -1,121 +0,0 @@
cmake_minimum_required(VERSION 3.20)
set(PROJECT_NAME scwx-freetype-gl)
find_package(OpenGL REQUIRED)
find_package(Freetype REQUIRED)
find_package(GLEW REQUIRED)
set(freetype-gl_WITH_GLEW ON)
set(freetype-gl_WITH_GLAD OFF)
set(freetype-gl_USE_VAO ON)
set(freetype-gl_BUILD_DEMOS OFF)
set(freetype-gl_BUILD_APIDOC OFF)
set(freetype-gl_BUILD_HARFBUZZ OFF)
set(freetype-gl_BUILD_MAKEFONT ON)
set(freetype-gl_BUILD_TESTS OFF)
set(freetype-gl_BUILD_SHARED OFF)
set(freetype-gl_OFF_SCREEN OFF)
configure_file(freetype-gl/cmake/config.h.in
${CMAKE_CURRENT_BINARY_DIR}/freetype-gl/config.h)
set(FREETYPE_GL_HDR freetype-gl/distance-field.h
freetype-gl/edtaa3func.h
freetype-gl/font-manager.h
freetype-gl/freetype-gl.h
freetype-gl/markup.h
freetype-gl/opengl.h
freetype-gl/platform.h
freetype-gl/text-buffer.h
freetype-gl/texture-atlas.h
freetype-gl/texture-font.h
freetype-gl/utf8-utils.h
freetype-gl/ftgl-utils.h
freetype-gl/vec234.h
freetype-gl/vector.h
freetype-gl/vertex-attribute.h
freetype-gl/vertex-buffer.h
freetype-gl/freetype-gl-errdef.h
${CMAKE_CURRENT_BINARY_DIR}/freetype-gl/config.h)
set(FREETYPE_GL_SRC freetype-gl/distance-field.c
freetype-gl/edtaa3func.c
freetype-gl/font-manager.c
freetype-gl/platform.c
freetype-gl/text-buffer.c
freetype-gl/texture-atlas.c
freetype-gl/texture-font.c
freetype-gl/utf8-utils.c
freetype-gl/ftgl-utils.c
freetype-gl/vector.c
freetype-gl/vertex-attribute.c
freetype-gl/vertex-buffer.c)
include(CheckLibraryExists)
check_library_exists(m cos "" HAVE_MATH_LIBRARY)
if(HAVE_MATH_LIBRARY)
list(APPEND CMAKE_REQUIRED_LIBRARIES m)
set(MATH_LIBRARY m)
endif()
if(freetype-gl_BUILD_APIDOC)
add_subdirectory(freetype-gl/doc)
endif()
if(freetype-gl_BUILD_SHARED)
add_library(freetype-gl SHARED ${FREETYPE_GL_SRC}
${FREETYPE_GL_HDR})
set_target_properties(freetype-gl PROPERTIES VERSION 0.3.2 SOVERSION 0)
target_link_libraries(freetype-gl PRIVATE opengl::opengl
Freetype::Freetype
${MATH_LIBRARY}
GLEW::GLEW)
else()
add_library(freetype-gl STATIC ${FREETYPE_GL_SRC}
${FREETYPE_GL_HDR})
target_link_libraries(freetype-gl PUBLIC opengl::opengl
Freetype::Freetype
${MATH_LIBRARY}
GLEW::GLEW)
endif()
if(freetype-gl_BUILD_MAKEFONT)
add_executable(makefont freetype-gl/makefont.c)
target_link_libraries(makefont freetype-gl
GLEW::GLEW)
endif()
if(freetype-gl_USE_VAO)
target_compile_definitions(freetype-gl PRIVATE FREETYPE_GL_USE_VAO)
target_compile_definitions(makefont PRIVATE FREETYPE_GL_USE_VAO)
endif()
if(freetype-gl_USE_WITH_GLAD)
target_compile_definitions(freetype-gl PRIVATE GL_WITH_GLAD)
target_compile_definitions(makefont PRIVATE GL_WITH_GLAD)
endif()
if(freetype-gl_USE_WITH_GLEW)
target_compile_definitions(freetype-gl PRIVATE FREETYPE_GL_USE_GLEW)
target_compile_definitions(makefont PRIVATE FREETYPE_GL_USE_GLEW)
endif()
if(MSVC)
target_compile_definitions(freetype-gl PRIVATE _CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_DEPRECATE)
target_compile_definitions(makefont PRIVATE _CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_DEPRECATE)
endif(MSVC)
target_include_directories(freetype-gl PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/freetype-gl)
target_include_directories(makefont PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/freetype-gl)
set(FTGL_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/freetype-gl PARENT_SCOPE)
set_target_properties(makefont PROPERTIES EXCLUDE_FROM_ALL True)
set_target_properties(freetype-gl PROPERTIES FOLDER ftgl)
set_target_properties(makefont PROPERTIES FOLDER ftgl)
if(freetype-gl_BUILD_APIDOC)
set_target_properties(doc PROPERTIES EXCLUDE_FROM_ALL True)
set_target_properties(doc PROPERTIES FOLDER ftgl)
endif()

View file

@ -1,17 +0,0 @@
#version 330 core
in vec2 texCoords;
in vec4 textColor;
out vec4 color;
uniform sampler2D uTexture;
void main()
{
float dist = texture(uTexture, texCoords).r;
float width = fwidth(dist);
float alpha = smoothstep(0.5f - width, 0.5f + width, dist);
color = vec4(textColor.rgb, textColor.a * alpha);
}

View file

@ -1,17 +0,0 @@
#version 330 core
layout (location = 0) in vec3 aVertex;
layout (location = 1) in vec2 aTexCoords;
layout (location = 2) in vec4 aColor;
out vec2 texCoords;
out vec4 textColor;
uniform mat4 projection;
void main()
{
gl_Position = projection * vec4(aVertex, 1.0f);
texCoords = aTexCoords;
textColor = aColor;
}

View file

@ -13,8 +13,8 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Boost)
find_package(Fontconfig)
find_package(Freetype)
find_package(geographiclib)
find_package(GLEW)
find_package(glm)
find_package(Python COMPONENTS Interpreter)
find_package(SQLite3)
@ -51,11 +51,9 @@ set(SRC_EXTERNAL source/scwx/qt/external/stb_image.cpp
source/scwx/qt/external/stb_rect_pack.cpp)
set(HDR_GL source/scwx/qt/gl/gl.hpp
source/scwx/qt/gl/gl_context.hpp
source/scwx/qt/gl/shader_program.hpp
source/scwx/qt/gl/text_shader.hpp)
source/scwx/qt/gl/shader_program.hpp)
set(SRC_GL source/scwx/qt/gl/gl_context.cpp
source/scwx/qt/gl/shader_program.cpp
source/scwx/qt/gl/text_shader.cpp)
source/scwx/qt/gl/shader_program.cpp)
set(HDR_GL_DRAW source/scwx/qt/gl/draw/draw_item.hpp
source/scwx/qt/gl/draw/geo_line.hpp
source/scwx/qt/gl/draw/placefile_icons.hpp
@ -238,8 +236,6 @@ set(SRC_UI_SETUP source/scwx/qt/ui/setup/finish_page.cpp
source/scwx/qt/ui/setup/welcome_page.cpp)
set(HDR_UTIL source/scwx/qt/util/color.hpp
source/scwx/qt/util/file.hpp
source/scwx/qt/util/font.hpp
source/scwx/qt/util/font_buffer.hpp
source/scwx/qt/util/geographic_lib.hpp
source/scwx/qt/util/imgui.hpp
source/scwx/qt/util/json.hpp
@ -253,8 +249,6 @@ set(HDR_UTIL source/scwx/qt/util/color.hpp
source/scwx/qt/util/tooltip.hpp)
set(SRC_UTIL source/scwx/qt/util/color.cpp
source/scwx/qt/util/file.cpp
source/scwx/qt/util/font.cpp
source/scwx/qt/util/font_buffer.cpp
source/scwx/qt/util/geographic_lib.cpp
source/scwx/qt/util/imgui.cpp
source/scwx/qt/util/json.cpp
@ -287,8 +281,6 @@ set(SHADER_FILES gl/color.frag
gl/map_color.vert
gl/radar.frag
gl/radar.vert
gl/text.frag
gl/text.vert
gl/texture1d.frag
gl/texture1d.vert
gl/texture2d.frag
@ -504,8 +496,8 @@ target_link_libraries(scwx-qt PUBLIC Qt${QT_VERSION_MAJOR}::Widgets
qmaplibregl
$<$<CXX_COMPILER_ID:MSVC>:opengl32>
Fontconfig::Fontconfig
freetype-gl
GeographicLib::GeographicLib
GLEW::GLEW
glm::glm
imgui
SQLite::SQLite3

View file

@ -7,8 +7,6 @@
<file>gl/map_color.vert</file>
<file>gl/radar.frag</file>
<file>gl/radar.vert</file>
<file>gl/text.frag</file>
<file>gl/text.vert</file>
<file>gl/texture1d.frag</file>
<file>gl/texture1d.vert</file>
<file>gl/texture2d.frag</file>

View file

@ -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

View file

@ -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

View file

@ -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>

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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