Last active
October 5, 2021 00:53
-
-
Save Shaptic/4705286 to your computer and use it in GitHub Desktop.
CFont::RenderText() - Renders a line of text at the given position in OpenGL.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
rect_t CFont::RenderText(const std::string& text, const vector2_t& Pos) | |
{ | |
// VAO and buffers that will contain our text vertex data. | |
uint32_t vao = 0, vbo = 0, ibo = 0; | |
// Track total text size. | |
rect_t Size(Pos.x, Pos.y, 0, 0); | |
if(!m_loaded || !CFont::s_loaded || text.empty()) return Size; | |
// Vertex buffer size, index buffer size. | |
uint16_t vlen = text.length() << 2; | |
uint16_t ilen = text.length() * ((1 << 2) + 2); | |
// Create buffers and zero them. | |
vertex2_t* verts = new vertex2_t[vlen]; | |
uint16_t* inds = new uint16_t[ilen]; | |
memset(inds, NULL, sizeof(uint16_t) * ilen); | |
memset(verts, NULL, sizeof(vertex2_t) * vlen); | |
// Track width and max height. | |
int max_w = 0, max_h = 0; | |
// The x-position to start the next character at. | |
int32_t last_w = Pos.x; | |
// The y-position of the starting character, for new-lines. | |
float y = Pos.y; | |
// Fill up buffers. Each character needs 4 vertices, so | |
// we increment by 4 each iteration then compensate for | |
// that throughout the loop. | |
for(size_t i = 0; i < vlen; i += 4) | |
{ | |
// Shortcut. | |
char c = text[i >> 2]; | |
// Handle new-lines by starting from the x position | |
// again and increasing Y by the height of an arbitrary | |
// large letter (here H). | |
if(c == '\n') | |
{ | |
last_w = Pos.x; | |
y += mp_glyphTextures['H'].dim.y + mp_glyphTextures['H'].dim.h; | |
} | |
// We want to make sure the letters are in the range | |
// that we've loaded (ASCII printables). | |
char letter = (c > '~' || c < ' ') ? ' ' : c; | |
// Retrieve dimensions from the dictionary. | |
// Since we're doing i += 4, the index in the text string | |
// would be text[i / 4]. | |
rect_t Dim = mp_glyphTextures[letter].dim; | |
float w = last_w; | |
float h = Dim.y; | |
last_w = w + Dim.w; // Increase until next char by the | |
// bitmap's horizontal advance value. | |
// [i] : top left | |
// [i + 1] : top right | |
// [i + 2] : bottom right | |
// [i + 3] : bottom left | |
verts[i].Position = math::vector2_t(w, y- Dim.h); | |
verts[i+1].Position = math::vector2_t(last_w, y - Dim.h); | |
verts[i+2].Position = math::vector2_t(last_w, y - Dim.h + h); | |
verts[i+3].Position = math::vector2_t(w, y - Dim.h + h); | |
// Load up the bitmap texture coordinates moving counter-clockwise | |
// from the origin. | |
verts[i].TexCoord = math::vector2_t(0, 0); | |
verts[i+1].TexCoord = math::vector2_t(1, 0); | |
verts[i+2].TexCoord = math::vector2_t(1, 1); | |
verts[i+3].TexCoord = math::vector2_t(0, 1); | |
// The vertices all use the font color. | |
// See CFont::SetColor() | |
for(size_t j = i; j < i + 4; ++j) | |
verts[j].Color = m_Color; | |
// A basic textured quad uses the indices [0, 1, 3, 3, 2, 1] | |
// assuming that verts[0] is the top-left, and the rest are | |
// calculated going clock-wise. | |
// The index in the buffer that we need is i / 4 * 6, since | |
// i / 4 gives us the current character, and each character | |
// needs 6 indices. | |
int x = (i >> 2) * 6; | |
// Assign the values. | |
inds[x] = i; | |
inds[x+1] = i + 1; | |
inds[x+2] = i + 3; | |
inds[x+3] = i + 3; | |
inds[x+4] = i + 2; | |
inds[x+5] = i + 1; | |
// Keep track of the overall dimensions. | |
max_w += Dim.w; | |
max_h = (max_h > Dim.h + h) ? max_h : Dim.h + h; | |
} | |
// Tally up dimensions. | |
Size.w = max_w; | |
Size.h = max_h; | |
// Enable font-rendering shader. | |
m_FontRender.Bind(); | |
// Create GPU buffers for vertex/index data | |
glGenBuffers(1, &vao); | |
glGenBuffers(1, &vbo); | |
glGenBuffers(1, &ibo); | |
glBindVertexArray(vao); | |
glBindBuffer(GL_ARRAY_BUFFER, vbo); | |
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); | |
// Enable the vertex attributes for position, texcoord, and color. | |
// See the shader for details. | |
glEnableVertexAttribArray(0); | |
glEnableVertexAttribArray(1); | |
glEnableVertexAttribArray(2); | |
// Give data to GPU. | |
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex2_t) * vlen, verts, GL_STATIC_DRAW); | |
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint16_t) * ilen, inds, GL_STATIC_DRAW); | |
// Vertices are arranged in memory like so: | |
// [ p0, p1, t0, t1, c0, c1, c2, c3 ] | |
// Specify vertex position arrangement. | |
// According to the diagram shown above, the vertex position | |
// would start at index 0. | |
// See the VBO_OFFSET macro in CFont.hpp. | |
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, | |
sizeof(vertex2_t), | |
VBO_OFFSET(0, vertex2_t, Position)); | |
// Specify texture coordinate position arrangement. | |
// According to the diagram, texture coordinates | |
// start at index 2. | |
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, | |
sizeof(vertex2_t), VBO_OFFSET(0, vertex2_t, TexCoord)); | |
// Specify the color arrangement. | |
// Starting at index 4. | |
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, | |
sizeof(vertex2_t), VBO_OFFSET(0, vertex2_t, Color)); | |
// Enable blending so that the text doesn't have a black background. | |
glEnable(GL_BLEND); | |
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
// Draw each character with its texture enabled. | |
for(size_t i = 0; i < text.length(); ++i) | |
{ | |
// Make invalid characters just spaces (' ') | |
char c = (text[i] > '~' || text[i] < ' ') ? ' ' : text[i]; | |
glBindTexture(GL_TEXTURE_2D, mp_glyphTextures[c]); | |
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, | |
(void*)(sizeof(uint16_t) * i * 6)); | |
} | |
// Delete GPU buffers. | |
glBufferData(GL_ARRAY_BUFFER, 0, NULL, GL_STATIC_DRAW); | |
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 0, NULL, GL_STATIC_DRAW); | |
// Unbind all the things. | |
glBindTexture(GL_TEXTURE_2D, 0); | |
glDisableVertexAttribArray(0); | |
glDisableVertexAttribArray(1); | |
glDisableVertexAttribArray(2); | |
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); | |
glBindBuffer(GL_ARRAY_BUFFER, 0); | |
glBindVertexArray(0); | |
m_FontRender.Unbind(); | |
// Delete all buffers. | |
glDeleteVertexArrays(1, &vao); | |
glDeleteBuffers(1, &vbo); | |
glDeleteBuffers(1, &ibo); | |
// Delete old buffers in RAM. | |
delete[] verts; | |
delete[] inds; | |
// Give back the total dimensions of the text rendered. | |
return Size; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment