Brenta Engine 1.2
Loading...
Searching...
No Matches
text.cpp
1// SPDX-License-Identifier: MIT
2// Author: Giovanni Santini
3// Mail: giovanni.santini@proton.me
4// Github: @San7o
5
6#include <brenta/logger.hpp>
7#include <brenta/window.hpp>
8#include <brenta/text.hpp>
9#include <brenta/texture.hpp>
10
11using namespace brenta;
12
13//
14// Static variables
15//
16
17types::shader_name_t text::shader;
18types::vao text::vao;
19types::buffer text::vbo;
20std::map<char, types::character> text::characters;
21const std::string text::subsystem_name = "text";
22const text::config text::default_config = {
23 "examples/assets/fonts/arial.ttf",
24 48,
25};
26text::config text::init_config = default_config;
27bool text::initialized = false;
28
29//
30// Subsystem interface
31//
32
33std::expected<void, subsystem::error> text::initialize()
34{
35 if (this->is_initialized()) return {};
36
37 text::vbo = types::buffer(GL_ARRAY_BUFFER);
38 text::vao.init();
39 text::vao.bind();
40 if (text::init_config.font_path != "")
41 load(text::init_config.font_path, text::init_config.font_size);
42
43 text::initialized = true;
44 INFO("{}: initialized", text::subsystem_name);
45 return {};
46}
47
48std::expected<void, subsystem::error> text::terminate()
49{
50 if (!this->is_initialized()) return {};
51
52 text::initialized = false;
53 INFO("{}: text terminated", text::subsystem_name);
54 return {};
55}
56
57std::string text::name()
58{
59 return text::subsystem_name;
60}
61
63{
64 return text::initialized;
65}
66
67//
68// Member functions
69//
70
71text &text::instance()
72{
73 static text _text;
74 return _text;
75}
76
77void text::load(std::string font_path, int font_size)
78{
79 if (text::vao.get_vao() == 0)
80 {
81 ERROR("{}: not initialized", text::subsystem_name);
82 return;
83 }
84 FT_Library ft;
85 if (FT_Init_FreeType(&ft))
86 {
87 ERROR("{}: could not init FreeType library", text::subsystem_name);
88 return;
89 }
90
91 shader::create("TextShader",
92 GL_VERTEX_SHADER, "src/shaders/text.vs",
93 GL_FRAGMENT_SHADER, "src/shaders/text.fs");
94 text::shader = "TextShader";
95 shader::use(text::shader);
96
97 // find path to font
98 std::string font_name = font_path;
99 if (font_name.empty())
100 {
101 ERROR("{}: could not find font", text::subsystem_name);
102 return;
103 }
104
105 FT_Face face;
106 if (FT_New_Face(ft, font_name.c_str(), 0, &face))
107 {
108 ERROR("{}: could not load font", text::subsystem_name);
109 return;
110 }
111 else
112 {
113 // set size to load glyphs as
114 FT_Set_Pixel_Sizes(face, 0, font_size);
115
116 // disable byte-alignment restriction
117 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
118
119 // load first 128 characters of ASCII set
120 for (unsigned char c = 0; c < 128; c++)
121 {
122 // Load character glyph
123 if (FT_Load_Char(face, c, FT_LOAD_RENDER))
124 {
125 ERROR("{}: could not load glyph", text::subsystem_name);
126 continue;
127 }
128 // generate texture
129 unsigned int texture;
130 glGenTextures(1, &texture);
131 texture::bind_texture(GL_TEXTURE_2D, texture);
132 glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, face->glyph->bitmap.width,
133 face->glyph->bitmap.rows, 0, GL_RED, GL_UNSIGNED_BYTE,
134 face->glyph->bitmap.buffer);
135 // set texture options
136 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
137 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
138 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
139 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
140 // now store character for later use
141 types::character character_ = {
142 texture,
143 glm::ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows),
144 glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top),
145 static_cast<unsigned int>(face->glyph->advance.x)};
146 characters.insert(std::pair<char, types::character>(c, character_));
147 }
148 texture::bind_texture(GL_TEXTURE_2D, 0);
149 }
150 // destroy FreeType once we're finished
151 FT_Done_Face(face);
152 FT_Done_FreeType(ft);
153
154 // configure VAO/VBO for texture quads
155 text::vao.bind();
156 text::vbo.bind();
157 glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 4, NULL, GL_DYNAMIC_DRAW);
158 glEnableVertexAttribArray(0);
159 glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
160 text::vbo.unbind();
161 text::vao.unbind();
162}
163
164void text::render_text(std::string text, float x, float y, float scale,
165 glm::vec3 color)
166{
167 if (text::vao.get_vao() == 0)
168 {
169 ERROR("{}: not initialized", text::subsystem_name);
170 return;
171 }
172
173 shader::use(text::shader);
174 unsigned int textShaderId = shader::get_id(text::shader);
175
176 glUniform3f(glGetUniformLocation(textShaderId, "textColor"), color.x, color.y,
177 color.z);
178
179 glm::mat4 projection =
180 glm::ortho(0.0f, static_cast<float>(window::get_width()), 0.0f,
181 static_cast<float>(window::get_height()));
182 glUniformMatrix4fv(glGetUniformLocation(textShaderId, "projection"), 1,
183 GL_FALSE, glm::value_ptr(projection));
184
185 glActiveTexture(GL_TEXTURE0);
186 text::vao.bind();
187
188 // iterate through all characters
189 std::string::const_iterator c;
190 for (c = text.begin(); c != text.end(); c++)
191 {
193
194 float xpos = x + ch.bearing.x * scale;
195 float ypos = y - (ch.size.y - ch.bearing.y) * scale;
196
197 float w = ch.size.x * scale;
198 float h = ch.size.y * scale;
199
200 // update VBO for each character
201
202 float vertices[6][4] = {
203 {xpos, ypos + h, 0.0, 0.0}, {xpos, ypos, 0.0, 1.0},
204 {xpos + w, ypos, 1.0, 1.0},
205
206 {xpos, ypos + h, 0.0, 0.0}, {xpos + w, ypos, 1.0, 1.0},
207 {xpos + w, ypos + h, 1.0, 0.0}};
208
209 // render glyph texture over quad
210 glBindTexture(GL_TEXTURE_2D, ch.texture_id);
211
212 // update content of VBO memory
213 glBindBuffer(GL_ARRAY_BUFFER, text::vbo.id);
214 glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
215
216 glBindBuffer(GL_ARRAY_BUFFER, 0);
217 // render quad
218 glDrawArrays(GL_TRIANGLES, 0, 6);
219 // now advance cursors for next glyph (note that advance is number
220 // of 1/64 pixels)
221 x += (ch.advance >> 6)
222 * scale; // bitshift by 6 to get value in pixels (2^6 = 64)
223 }
224 glBindVertexArray(0);
225 glBindTexture(GL_TEXTURE_2D, 0);
226}
227
228//
229// Builder
230//
231
232text::builder &text::builder::font(const std::string &font_path)
233{
234 this->conf.font_path = font_path;
235 return *this;
236}
237
238text::builder &text::builder::size(int font_size)
239{
240 this->conf.font_size = font_size;
241 return *this;
242}
243
244subsystem &text::builder::build()
245{
246 text::init_config = this->conf;
247 return text::instance();
248}
static bool create(std::string shader_name, GLenum type, std::string path, Args... args)
Create a new shader.
Definition shader.hpp:71
static unsigned int get_id(types::shader_name_t shader_name)
Get the ID of a shader.
Definition shader.cpp:14
static bool use(types::shader_name_t shader_name)
Use the shader.
Definition shader.cpp:24
Subsystem interface.
Definition subsystem.hpp:22
Text subsystem.
Definition text.hpp:55
std::expected< void, subsystem::error > terminate() override
Cleaup resources.
Definition text.cpp:48
bool is_initialized() override
Returns true if the subsystem is initialized.
Definition text.cpp:62
static void render_text(std::string text, float x, float y, float scale, glm::vec3 color)
Render text.
Definition text.cpp:164
std::string name() override
Returns the name of the sybsystem.
Definition text.cpp:57
static void load(std::string font_name, int font_size=48)
Load a font.
Definition text.cpp:77
static std::map< char, types::character > characters
Map of characters.
Definition text.hpp:63
std::expected< void, subsystem::error > initialize() override
Initialize the text subsystem.
Definition text.cpp:33
Texture class.
Definition texture.hpp:20
static void bind_texture(GLenum target, unsigned int texture, GLint wrapping=GL_REPEAT, GLint filtering_min=GL_NEAREST, GLint filtering_mag=GL_NEAREST, GLboolean hasMipmap=GL_TRUE, GLint mipmap_min=GL_LINEAR_MIPMAP_LINEAR, GLint mipmap_mag=GL_LINEAR)
Bind a texture.
Definition texture.cpp:29
Buffer wrapper around OpenGL buffer objects.
Definition buffer.hpp:30
void unbind()
Unbind the buffer object.
Definition buffer.cpp:49
void bind()
Bind the buffer object.
Definition buffer.cpp:39
Vertex Array Object (VAO)
Definition vao.hpp:23
void bind()
Bind the VAO.
Definition vao.cpp:26
void unbind()
Unbind the VAO.
Definition vao.cpp:36
void init()
Init Constructor.
Definition vao.cpp:11
Character struct.
Definition text.hpp:38