add Font and Glyph classes
This commit is contained in:
parent
33bf113f26
commit
d776f1a209
91
src/Font.cc
Normal file
91
src/Font.cc
Normal file
@ -0,0 +1,91 @@
|
||||
#include "Font.h"
|
||||
|
||||
#define round_up_26_6(val) (((val) + 63) >> 6u)
|
||||
|
||||
static FT_Library ft_library_handle;
|
||||
static bool ft_initialized;
|
||||
|
||||
bool Initialize_FreeType()
|
||||
{
|
||||
if (ft_initialized)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (FT_Init_FreeType(&ft_library_handle) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ft_initialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Font::load(const char * fname, int size)
|
||||
{
|
||||
if (!Initialize_FreeType())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (FT_New_Face(ft_library_handle, fname, 0, &m_face) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
FT_Set_Pixel_Sizes(m_face, 0, size);
|
||||
|
||||
return preload_glyphs();
|
||||
}
|
||||
|
||||
bool Font::preload_glyphs()
|
||||
{
|
||||
static const char preload_glyph_list[] = "HMgjqxy_|^";
|
||||
|
||||
int max_top = -9999;
|
||||
int min_bottom = 9999;
|
||||
m_advance = 0;
|
||||
|
||||
for (size_t i = 0u; i < sizeof(preload_glyph_list) - 1u; i++)
|
||||
{
|
||||
std::shared_ptr<Glyph> g = get_glyph(preload_glyph_list[i]);
|
||||
if (g == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (m_face->glyph->bitmap_top > max_top)
|
||||
{
|
||||
max_top = m_face->glyph->bitmap_top;
|
||||
}
|
||||
int bitmap_bottom = m_face->glyph->bitmap_top - m_face->glyph->bitmap.rows;
|
||||
if (bitmap_bottom < min_bottom)
|
||||
{
|
||||
min_bottom = bitmap_bottom;
|
||||
}
|
||||
if (g->get_advance() > m_advance)
|
||||
{
|
||||
m_advance = g->get_advance();
|
||||
}
|
||||
}
|
||||
|
||||
m_line_height = round_up_26_6(m_face->size->metrics.height);
|
||||
m_baseline_offset = (m_line_height - (max_top - min_bottom)) / 2 - min_bottom;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::shared_ptr<Glyph> Font::get_glyph(FT_ULong character)
|
||||
{
|
||||
auto it = m_glyphs.find(character);
|
||||
if (it != m_glyphs.end())
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
std::shared_ptr<Glyph> glyph = std::make_shared<Glyph>();
|
||||
if (!glyph->load(m_face, character))
|
||||
{
|
||||
glyph = nullptr;
|
||||
}
|
||||
m_glyphs[character] = glyph;
|
||||
return glyph;
|
||||
}
|
27
src/Font.h
Normal file
27
src/Font.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef FONT_H
|
||||
#define FONT_H
|
||||
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
#include "Glyph.h"
|
||||
|
||||
class Font
|
||||
{
|
||||
public:
|
||||
bool load(const char * fname, int size);
|
||||
std::shared_ptr<Glyph> get_glyph(FT_ULong character);
|
||||
int get_advance() { return m_advance; }
|
||||
int get_line_height() { return m_line_height; }
|
||||
int get_baseline_offset() { return m_baseline_offset; }
|
||||
|
||||
protected:
|
||||
bool preload_glyphs();
|
||||
|
||||
FT_Face m_face;
|
||||
std::unordered_map<FT_ULong, std::shared_ptr<Glyph>> m_glyphs;
|
||||
int m_advance;
|
||||
int m_line_height;
|
||||
int m_baseline_offset;
|
||||
};
|
||||
|
||||
#endif
|
52
src/Glyph.cc
Normal file
52
src/Glyph.cc
Normal file
@ -0,0 +1,52 @@
|
||||
#include "Glyph.h"
|
||||
|
||||
#define round_up_26_6(val) (((val) + 63) >> 6u)
|
||||
|
||||
bool Glyph::load(FT_Face face, FT_ULong char_code)
|
||||
{
|
||||
if (FT_Load_Char(face, char_code, FT_LOAD_RENDER) != 0)
|
||||
return false;
|
||||
|
||||
m_texture = glcxx::Texture::create();
|
||||
m_texture->bind(GL_TEXTURE_2D);
|
||||
int width = face->glyph->bitmap.width;
|
||||
int rounded_width = glcxx::Texture::next_power_of_2(width);
|
||||
int height = face->glyph->bitmap.rows;
|
||||
int rounded_height = glcxx::Texture::next_power_of_2(height);
|
||||
m_advance = round_up_26_6(face->glyph->advance.x);
|
||||
uint8_t * texture = new uint8_t[rounded_width * rounded_height];
|
||||
memset(texture, 0, rounded_width * rounded_height);
|
||||
for (int i = 0; i < height; i++)
|
||||
{
|
||||
memcpy(&texture[rounded_width * i],
|
||||
&face->glyph->bitmap.buffer[width * (height - i - 1)],
|
||||
width);
|
||||
}
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, rounded_width, rounded_height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, texture);
|
||||
delete[] texture;
|
||||
|
||||
m_array = glcxx::Array::create();
|
||||
m_array->bind();
|
||||
|
||||
int left = face->glyph->bitmap_left;
|
||||
int top = face->glyph->bitmap_top;
|
||||
float s_max = width / (float)rounded_width;
|
||||
float t_max = height / (float)rounded_height;
|
||||
m_buffer = glcxx::Buffer::create(GL_ARRAY_BUFFER, GL_STATIC_DRAW, {
|
||||
(GLfloat)left, (GLfloat)(top - height), 0.0, 0.0,
|
||||
(GLfloat)(left + width), (GLfloat)(top - height), s_max, 0.0,
|
||||
(GLfloat)left, (GLfloat)top, 0.0, t_max,
|
||||
(GLfloat)(left + width), (GLfloat)top, s_max, t_max,
|
||||
});
|
||||
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
|
||||
|
||||
return true;
|
||||
}
|
27
src/Glyph.h
Normal file
27
src/Glyph.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef GLYPH_H
|
||||
#define GLYPH_H
|
||||
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include "glcxx.hpp"
|
||||
|
||||
class Glyph
|
||||
{
|
||||
public:
|
||||
bool load(FT_Face face, FT_ULong char_code);
|
||||
int get_advance() { return m_advance; }
|
||||
void render()
|
||||
{
|
||||
m_array->bind();
|
||||
m_texture->bind(GL_TEXTURE_2D);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
|
||||
protected:
|
||||
int m_advance;
|
||||
std::shared_ptr<glcxx::Texture> m_texture;
|
||||
std::shared_ptr<glcxx::Buffer> m_buffer;
|
||||
std::shared_ptr<glcxx::Array> m_array;
|
||||
};
|
||||
|
||||
#endif
|
3
wscript
3
wscript
@ -12,6 +12,7 @@ def configure(conf):
|
||||
conf.env.CXXFLAGS += ["-Wall"]
|
||||
conf.env.CXXFLAGS += ["-std=gnu++14"]
|
||||
conf.check_cfg(package = "sdl2", args = "--cflags --libs")
|
||||
conf.check_cfg(package = "freetype2", uselib_store = "FreeType2", args = "--cflags --libs")
|
||||
if "MINGW" in os.popen("uname").read():
|
||||
# TODO: set CXX to mingw32-g++
|
||||
pass
|
||||
@ -34,7 +35,7 @@ def build(bld):
|
||||
bld.program(
|
||||
source = sources,
|
||||
target = "app",
|
||||
uselib = "SDL2",
|
||||
uselib = ["SDL2", "FreeType2"],
|
||||
lib = libs,
|
||||
linkflags = ["-Wl,-rpath,$ORIGIN"],
|
||||
install_path = None)
|
||||
|
Loading…
x
Reference in New Issue
Block a user