Brenta Engine 1.2
Loading...
Searching...
No Matches
font.cpp
1// SPDX-License-Identifier: MIT
2// Author: Giovanni Santini
3// Mail: giovanni.santini@proton.me
4// Github: @San7o
5
6#include <brenta/asset.hpp>
7#include <brenta/logger.hpp>
8#include <brenta/font.hpp>
9#include <brenta/renderer/opengl/shader.hpp>
10#include <brenta/renderer/opengl/texture.hpp>
11
12#include <ft2build.h>
13#include FT_FREETYPE_H
14
15#include "renderer/shaders/c/text_fs.c"
16#include "renderer/shaders/c/text_vs.c"
17
18using namespace brenta;
19
20Font::Font(const std::filesystem::path &path, int size)
21{
22 this->vao.init();
23 this->vao.bind();
24 this->vbo.init(Buffer::Target::Array);
25
26 FT_Library ft;
27 if (FT_Init_FreeType(&ft))
28 {
29 ERROR("Font: could not init FreeType library");
30 return;
31 }
32
33 auto text_shader = AssetManager::get<Shader>("TextShader");
34 if (!text_shader)
35 {
36 text_shader =
37 AssetManager::new_asset<Shader>("TextShader",
39 .object({ Shader::Type::Vertex, text_vs })
40 .object({ Shader::Type::Fragment, text_fs }));
41 }
42 if (!text_shader) return;
43
44 this->shader = text_shader;
45 this->shader->use();
46
47 // find path to font
48 if (path.empty())
49 {
50 ERROR("Font: could not find font at path {}", path.string());
51 return;
52 }
53
54 FT_Face face;
55 if (FT_New_Face(ft, path.string().c_str(), 0, &face))
56 {
57 ERROR("Font: could not load font at path {}", path.string());
58 return;
59 }
60 else
61 {
62 // set size to load glyphs as
63 FT_Set_Pixel_Sizes(face, 0, size);
64
65 // disable byte-alignment restriction
66 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
67
68 // load first 128 characters of ASCII set
69 for (unsigned char c = 0; c < 128; c++)
70 {
71 // Load character glyph
72 if (FT_Load_Char(face, c, FT_LOAD_RENDER))
73 {
74 ERROR("Font: could not load glyph for font at path {}",
75 path.string());
76 continue;
77 }
78 // generate texture
79 unsigned int texture;
80 glGenTextures(1, &texture);
81 Texture::bind_id(Texture::Target::Texture2D, texture);
82 glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, face->glyph->bitmap.width,
83 face->glyph->bitmap.rows, 0, GL_RED, GL_UNSIGNED_BYTE,
84 face->glyph->bitmap.buffer);
85 // set texture options
86 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
87 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
88 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
89 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
90 // now store character for later use
91 Font::Character character = {
92 texture,
93 glm::ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows),
94 glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top),
95 static_cast<unsigned int>(face->glyph->advance.x)};
96 characters.insert(std::pair<char, Font::Character>(c, character));
97 }
98 Texture::bind_id(Texture::Target::Texture2D, 0);
99 }
100 // destroy FreeType once we're finished
101 FT_Done_Face(face);
102 FT_Done_FreeType(ft);
103
104 // configure VAO/VBO for texture quads
105 this->vao.bind();
106 this->vbo.bind();
107 glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 4, NULL, GL_DYNAMIC_DRAW);
108 glEnableVertexAttribArray(0);
109 glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
110 this->vbo.unbind();
111 this->vao.unbind();
112
113 EVENT(Logger::Event::Lifetime, "Font: initialized");
114}
115
116Font::~Font()
117{
118 this->shader = nullptr;
119 this->vao.destroy();
120 this->vbo.destroy();
121
122 EVENT(Logger::Event::Lifetime, "Font: destoyed");
123}
124
125Font::Builder& Font::Builder::path(const std::filesystem::path& path)
126{
127 this->_path = path;
128 this->watch_paths.push_back(path);
129 return *this;
130}
131
132Font::Builder& Font::Builder::size(int size)
133{
134 this->_size = size;
135 return *this;
136}
137
138Font::Builder& Font::Builder::watch(const std::filesystem::path& path)
139{
140 this->watch_paths.push_back(path);
141 return *this;
142}
143
144Font Font::Builder::build()
145{
146 return Font(this->_path, this->_size);
147}
148
149tenno::vector<std::filesystem::path> Font::Builder::get_watch_paths() const
150{
151 return this->watch_paths;
152}