1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
#include "text.hpp"
#include <iostream>
void TextSystem::configure([[maybe_unused]] entityx::EntityManager& entities,
[[maybe_unused]] entityx::EventManager& events)
{
if (FT_Init_FreeType(&freetype) != 0) {
// TODO handle error
}
}
/**
* Draws the text for all entities.
*/
void TextSystem::update([[maybe_unused]] entityx::EntityManager& entites,
[[maybe_unused]] entityx::EventManager& events,
[[maybe_unused]] entityx::TimeDelta dt)
{
// TODO render each Text component's text
}
void TextSystem::loadFont(const std::string& name,
const std::string& file,
int size)
{
// Find or load font at given size
//
if (fonts.find(file) == fonts.end()) {
FT_Face face;
if (FT_New_Face(freetype, file.c_str(), 0, &face)) {
// TODO handle this error
}
fonts.emplace(file, face);
}
auto& face = fonts[file];
FT_Set_Pixel_Sizes(face, 0, size);
fontData.try_emplace(name);
// Calculate dimensions of final texture
//
float width = 0, height = 0;
for (int c = 32; c < 128; c++) {
FT_Load_Char(face, c, FT_LOAD_RENDER);
width += face->glyph->bitmap.width + 1;
height = std::max(height, static_cast<float>(face->glyph->bitmap.rows));
}
// Generate texture to hold entire font
//
auto& font = fontData[name];
glGenTextures(1, &font.tex);
glGenBuffers(1, &font.vbo);
glBindTexture(GL_TEXTURE_2D, font.tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width, height,
0, GL_RED, GL_UNSIGNED_BYTE, 0);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// // convert red-on-black to RGBA
// auto& g = face->glyph;
// std::vector<uint32_t> buf (g->bitmap.width * g->bitmap.rows, 0xFFFFFF);
// for (auto j = buf.size(); j--;)
// buf[j] |= g->bitmap.buffer[j] << 24;
// Load each character and add it to the texture
//
float offsetX = 0, offsetY = 0;
for (int c = 32; c < 128; c++) {
FT_Load_Char(face, c, FT_LOAD_RENDER);
auto* g = face->glyph;
glTexSubImage2D(GL_TEXTURE_2D, 0, offsetX, offsetY,
g->bitmap.width, g->bitmap.rows,
GL_RED, GL_UNSIGNED_BYTE,
g->bitmap.buffer);
auto& d = font.data[c - 32];
d.dim = { g->bitmap.width, g->bitmap.rows };
d.bitmap = { g->bitmap_left, g->bitmap_top };
d.advance = { g->advance.x >> 6, g->advance.y >> 6 };
d.offset = { offsetX / width, offsetY / height };
offsetX += g->bitmap.width;
// Keep offsetY at zero?
}
std::cout << "Loaded font: " << file << " (size: " << size << ", tex: "
<< font.tex << ")" << std::endl;
}
void TextSystem::updateVBOs(void)
{
for (auto& data : fontData) {
auto& d = data.second;
d.buffer.clear();
for (auto& text : d.text) {
for (char c : text.text) {
if (c < 32)
continue;
d.buffer += {
text.x, text.y, text.z,
d.data[c].offset.first, d.data[c].offset.second,
1.0f
};
}
}
glBindBuffer(GL_ARRAY_BUFFER, d.vbo);
glBufferData(GL_ARRAY_BUFFER,
d.text.size() * sizeof(TextMeshData), d.text.data(),
GL_STREAM_DRAW);
}
}
|