CSCI441 OpenGL Library 6.0.1.1
CS@Mines CSCI441 Computer Graphics Course Library
Loading...
Searching...
No Matches
Font.hpp
1#ifndef CSCI441_FONT_HPP
2#define CSCI441_FONT_HPP
3
4#ifdef CSCI441_USE_GLEW
5 #include <GL/glew.h>
6#else
7 #include <glad/gl.h>
8#endif
9
10#include <ft2build.h>
11#include FT_FREETYPE_H
12
13#include <cstdlib>
14
15namespace CSCI441 {
19 class Font {
20 public:
25 Font() = delete;
30 explicit Font(const char* filename);
34 ~Font();
35
40 [[nodiscard]] GLboolean isLoaded() const { return _loaded; }
41
48 void setScale(GLfloat scaleX, GLfloat scaleY);
49
54 void bind() const;
55
64 void draw(const char* str, GLfloat x, GLfloat y) const;
65 private:
69 GLboolean _loaded;
70
74 GLuint _vao;
78 GLuint _vbo;
82 GLuint _texHandle;
83
87 GLfloat _scaleX;
91 GLfloat _scaleY;
92
96 FT_Library _ftLibrary;
100 FT_Face _fontFace;
104 GLint _atlasWidth;
108 GLint _atlasHeight;
109
114 struct CharacterInfo {
118 GLfloat ax = 0.f;
122 GLfloat ay = 0.f;
123
127 GLfloat bw = 0.f;
131 GLfloat bh = 0.f;
132
136 GLfloat bl = 0.f;
140 GLfloat bt = 0.f;
141
145 GLfloat tx = 0.f;
146 } _fontCharacters[128];
147 };
148}
149
150inline CSCI441::Font::Font(const char *filename) :
151 _loaded(GL_FALSE),
152 _vao(0),
153 _vbo(0),
154 _texHandle(0),
155 _scaleX(1.0f),
156 _scaleY(1.0f),
157 _ftLibrary(nullptr),
158 _fontFace(nullptr),
159 _atlasWidth(0),
160 _atlasHeight(0)
161{
162
163 if(FT_Init_FreeType(&_ftLibrary)) {
164 fprintf(stderr, "[font | ERROR]: Could not init freetype library\n");
165 return;
166 }
167
168 if(FT_New_Face(_ftLibrary, filename, 0, &_fontFace)) {
169 fprintf(stderr, "[font | ERROR]: Could not open font\n");
170 return;
171 }
172
173 FT_Set_Pixel_Sizes(_fontFace, 0, 20);
174
175 const auto g = _fontFace->glyph;
176 GLint w = 0;
177 GLint h = 0;
178
179 for(int i = 32; i < 128; i++) {
180 if(FT_Load_Char(_fontFace, i, FT_LOAD_RENDER)) {
181 fprintf(stderr, "[font | ERROR]: Loading character %c failed!\n", i);
182 continue;
183 }
184
185 w += g->bitmap.width;
186 h = (h > g->bitmap.rows ? h : g->bitmap.rows);
187 }
188
189 // save this value as it is needed later on
190 _atlasWidth = w;
191 _atlasHeight = h;
192
193 glActiveTexture(GL_TEXTURE0);
194 glGenTextures(1, &_texHandle);
195 glBindTexture(GL_TEXTURE_2D, _texHandle);
196 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
197 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
198 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
199 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
200 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
201 glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, 0);
202
203 GLint x = 0;
204
205 for(int i = 32; i < 128; i++) {
206 if(FT_Load_Char(_fontFace, i, FT_LOAD_RENDER))
207 continue;
208
209 _fontCharacters[i].ax = static_cast<GLfloat>( g->advance.x >> 6 );
210 _fontCharacters[i].ay = static_cast<GLfloat>( g->advance.y >> 6 );
211
212 _fontCharacters[i].bw = static_cast<GLfloat>( g->bitmap.width );
213 _fontCharacters[i].bh = static_cast<GLfloat>( g->bitmap.rows );
214
215 _fontCharacters[i].bl = static_cast<GLfloat>( g->bitmap_left );
216 _fontCharacters[i].bt = static_cast<GLfloat>( g->bitmap_top );
217
218 _fontCharacters[i].tx = static_cast<GLfloat>(x) / static_cast<GLfloat>(w);
219
220 glTexSubImage2D(GL_TEXTURE_2D, 0, x, 0, g->bitmap.width, g->bitmap.rows, GL_RED, GL_UNSIGNED_BYTE, g->bitmap.buffer);
221
222 x += g->bitmap.width;
223 }
224
225 glGenVertexArrays(1, &_vao);
226 glBindVertexArray(_vao);
227 glGenBuffers(1, &_vbo);
228 glBindBuffer(GL_ARRAY_BUFFER, _vbo);
229 glEnableVertexAttribArray(0);
230 glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, nullptr);
231
232 _loaded = GL_TRUE;
233}
234
236 glDeleteVertexArrays(1, &_vao);
237 glDeleteBuffers(1, &_vbo);
238 glDeleteTextures(1, &_texHandle);
239 FT_Done_Face(_fontFace);
240 FT_Done_FreeType(_ftLibrary);
241}
242
243inline void CSCI441::Font::setScale(const GLfloat scaleX, const GLfloat scaleY) {
244 if (_scaleX > 0 && _scaleY > 0) {
245 _scaleX = scaleX;
246 _scaleY = scaleY;
247 }
248}
249
250inline void CSCI441::Font::bind() const {
251 glBindVertexArray(_vao);
252 glBindBuffer(GL_ARRAY_BUFFER, _vbo);
253 glActiveTexture(GL_TEXTURE0);
254 glBindTexture(GL_TEXTURE_2D, _texHandle);
255}
256
257inline void CSCI441::Font::draw(const char* str, GLfloat x, GLfloat y) const {
258 struct FontPoint {
259 GLfloat x;
260 GLfloat y;
261 GLfloat s;
262 GLfloat t;
263 } coords[6 * strlen(str)];
264
265 GLint n = 0;
266
267 for(const char *p = str; *p; p++) {
268 const auto characterIndex = static_cast<int>(*p);
269 const auto character = _fontCharacters[characterIndex];
270 const auto x2 = x + character.bl * _scaleX;
271 const auto y2 = -y - character.bt * _scaleY;
272 const auto w = character.bw * _scaleX;
273 const auto h = character.bh * _scaleY;
274
275 // Advance the cursor to the start of the next character
276 x += character.ax * _scaleX;
277 y += character.ay * _scaleY;
278
279 // Skip glyphs that have no pixels
280 if(!w || !h)
281 continue;
282
283 coords[n++] = (FontPoint){x2, -y2 , character.tx, 0};
284 coords[n++] = (FontPoint){x2 + w, -y2 , character.tx + character.bw / _atlasWidth, 0};
285 coords[n++] = (FontPoint){x2, -y2 - h, character.tx, character.bh / _atlasHeight}; //remember: each glyph occupies a different amount of vertical space
286
287 coords[n++] = (FontPoint){x2 + w, -y2 , character.tx + character.bw / _atlasWidth, 0};
288 coords[n++] = (FontPoint){x2, -y2 - h, character.tx, character.bh / _atlasHeight};
289 coords[n++] = (FontPoint){x2 + w, -y2 - h, character.tx + character.bw / _atlasWidth, character.bh / _atlasHeight};
290 }
291 glBufferData(GL_ARRAY_BUFFER, sizeof( coords ), coords, GL_DYNAMIC_DRAW);
292 glDrawArrays(GL_TRIANGLES, 0, n);
293}
294
295#endif//CSCI441_FONT_HPP
Stores character glyphs corresponding to a ttf file and draws text to the screen.
Definition: Font.hpp:19
GLboolean isLoaded() const
tracks if font file was loaded successfully
Definition: Font.hpp:40
~Font()
cleanup CPU and GPU memory
Definition: Font.hpp:235
Font()=delete
do not allow default Font objects to be constructed
void draw(const char *str, GLfloat x, GLfloat y) const
draws a text string at a given (x,y) window coordinate with the currently set scale
Definition: Font.hpp:257
void bind() const
make this font active, binding its VAO, VBO, and 2D texture to GL_TEXTURE0
Definition: Font.hpp:250
void setScale(GLfloat scaleX, GLfloat scaleY)
set the amount to scale each glyph when drawing
Definition: Font.hpp:243
CSCI441 Helper Functions for OpenGL.
Definition: ArcballCam.hpp:17