aboutsummaryrefslogtreecommitdiffstats
path: root/src/text.cpp
blob: 8726b88e1c9973350c71080ec33cb398a3864e38 (plain)
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);
    }
}