I’m writing a text rendering class based on this guide. For some reason it does not render the text and I am completely stumped.
Here’s my code:
TextRenderer.hpp
#ifndef TEXTRENDERER_HPP
#include <iostream>
#include <GL/glew.h>
#include <ft2build.h>
#include FT_FREETYPE_H
struct point
{
GLfloat x;
GLfloat y;
GLfloat s;
GLfloat t;
};
class TextRenderer
{
public:
void renderText(const char *text, int x, int y, int scaleX, int scaleY);
void setColor(int r, int g, int b, int a);
TextRenderer(FT_Face face, int fontSize);
GLfloat color[4];
private:
void setup();
void shutdown();
int fontSize;
GLint coordIndex, texIndex, colorIndex;
GLuint program;
GLuint vbo;
FT_Face face;
};
#define TEXTRENDERER_HPP
#endif
TextRenderer.cpp
#include "TextRenderer.hpp"
#include "ShaderHandler.hpp"
#include <iostream>
#include <GL/glew.h>
#include <ft2build.h>
#include FT_FREETYPE_H
TextRenderer::TextRenderer(FT_Face face, int fontSize = 10)
{
this->face = face;
this->program = ShaderHandler::loadShader("TextShader.vglsl", "TextShader.fglsl");
this->fontSize = fontSize;
this->setColor(1, 1, 1, 0);
}
void TextRenderer::setColor(int r, int g, int b, int a)
{
this->color[0] = r;
this->color[1] = g;
this->color[2] = b;
this->color[3] = a;
}
void TextRenderer::setup()
{
glUseProgram(this->program);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
FT_Set_Pixel_Sizes(this->face, 0, this->fontSize);
this->coordIndex = ShaderHandler::getAttribIndex(this->program, "coord");
this->texIndex = ShaderHandler::getUniformIndex(this->program, "tex");
this->colorIndex = ShaderHandler::getUniformIndex(this->program, "color");
glGenBuffers(1, &this->vbo);
glUniform4fv(this->colorIndex, 1, this->color);
}
void TextRenderer::shutdown()
{
}
void TextRenderer::renderText(const char *text, int x, int y, int scaleX, int scaleY)
{
this->setup();
FT_GlyphSlot glyph = this->face->glyph;
const char *c;
GLuint tex;
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glUniform1i(this->texIndex, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glGenBuffers(1, &vbo);
glEnableVertexAttribArray(this->coordIndex);
glBindBuffer(GL_ARRAY_BUFFER, this->vbo);
glVertexAttribPointer(this->coordIndex, 4, GL_FLOAT, GL_FALSE, 0, 0);
for (c = text; *c; c++)
{
//std::cout << c << std::endl;
if (FT_Load_Char(this->face, *c, FT_LOAD_RENDER))
{
continue;
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, glyph->bitmap.width, glyph->bitmap.rows, 0, GL_RED, GL_UNSIGNED_BYTE, glyph->bitmap.buffer);
float x2 = x + glyph->bitmap_left * scaleX;
float y2 = -y - glyph->bitmap_top * scaleY;
float width = glyph->bitmap.width * scaleX;
float height = glyph->bitmap.rows * scaleY;
point box[4][4] =
{
{ x2, -y2, 0, 0 },
{ x2 + width, -y2, 1, 0 },
{ x2, -y2 - height, 0, 1 },
{ x2 + width, -y2 - height, 1, 1 },
};
glBufferData(GL_ARRAY_BUFFER, sizeof box, box, GL_DYNAMIC_DRAW);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
x += (glyph->advance.x >> 6) * scaleX;
y += (glyph->advance.y >> 6) * scaleY;
}
glDisableVertexAttribArray(this->coordIndex);
glDeleteTextures(1, &tex);
}
TextShader.fglsl (Fragment shader)
#version 330
varying vec2 texpos;
uniform sampler2D tex;
uniform vec4 color;
out vec4 outColor;
void main(void)
{
outColor = vec4( 1, 1, 1, texture( tex, texpos ).r) * color;
}
TextShader.vglsl (Vertex shader)
#version 330
attribute vec4 coord;
varying vec2 texpos;
out vec4 pos;
void main(void)
{
pos = vec4(coord.xy, 0, 1);
texpos = coord.zw;
}
Then I just call this to init the TextRenderer:
TextRenderer tRenderer = TextRenderer(sans, 10);
Then this in the game loop:
int sx = width / 2.0;
int sy = height / 2.0;
tRenderer.renderText("hi there", -1 + 8 * sx, 1 - 50 * sy, sx, sy);