I'm trying to display some simple text in OpenGL, but all I get is a black screen. I'm using cglm (glm for c), glad, and glfw. Here is my code:
#include <iostream>
#include <map>
#include <string>
#include <vendor/glad/glad.h>
#include <vendor/GLFW/glfw3.h>
#include <vendor/cglm/cglm.h>
#include <ft2build.h>
#include FT_FREETYPE_H
// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
const char *vertexShaderSource =
"#version 330 core\n"
"layout (location = 0) in vec4 vertex; // <vec2 pos, vec2 tex>\n"
"out vec2 TexCoords;\n"
"uniform mat4 projection;\n"
"void main()\n"
"{\n"
" gl_Position = projection * vec4(vertex.xy, 0.0, 1.0);\n"
" TexCoords = vertex.zw;\n"
"};\n";
const char *fragmentShaderSource =
"#version 330 core\n"
"in vec2 TexCoords;\n"
"out vec4 color;\n"
"uniform sampler2D text;\n"
"uniform vec3 textColor;\n"
"void main()\n"
"{ \n"
" vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r);\n"
" color = vec4(textColor, 1.0) * sampled;\n"
"};\n";
typedef struct my_vec3
{
float x;
float y;
float z;
} my_vec3;
typedef struct my_vec2
{
int x;
int y;
} my_vec2;
typedef struct Character
{
unsigned int TextureID; // ID handle of the glyph texture
my_vec2 Size; // Size of glyph
my_vec2 Bearing; // Offset from baseline to left/top of glyph
unsigned int Advance; // Horizontal offset to advance to next glyph
} Character;
void framebuffer_size_callback(GLFWwindow *window, int width, int height);
void processInput(GLFWwindow *window);
void RenderText(GLuint shader, std::string text, float x, float y, float scale, my_vec3 color);
unsigned int VAO, VBO;
std::map<GLchar, Character> Characters;
int main()
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow *window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
if (window == NULL)
{
printf("Failed to create GLFW window");
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
printf("Failed to initialize GLAD");
return -1;
}
glEnable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
int success;
char infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
printf("ERROR::SHADER::VERTEX::COMPILATION_FAILED %s\n", infoLog);
}
unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
printf("ERROR::SHADER::FRAGMENT::COMPILATION_FAILED %s\n", infoLog);
}
unsigned int shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
printf("ERROR::SHADER::PROGRAM::LINKING_FAILED %s\n", infoLog);
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
mat4 projection;
glm_mat4_identity(projection);
glm_ortho(0.0, static_cast<float>(SCR_WIDTH), 0.0f, static_cast<float>(SCR_HEIGHT), 0.01, 100.0, projection);
// glm_perspective(4.8, (float)SCR_WIDTH/(float)SCR_WIDTH, 0.01, 100.0, projection);
glUseProgram(shaderProgram);
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "projection"), 1, GL_FALSE, &projection[0][0]);
FT_Library ft;
if (FT_Init_FreeType(&ft))
{
std::cout << "ERROR::FREETYPE: Could not init FreeType Library" << std::endl;
return -1;
}
std::string font_name = "/home/filip/Downloads/arial/arial.ttf";
FT_Face face;
if (FT_New_Face(ft, font_name.c_str(), 0, &face))
{
std::cout << "ERROR::FREETYPE: Failed to load font" << std::endl;
return -1;
}
else
{
FT_Set_Pixel_Sizes(face, 0, 48);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
for (unsigned char c = 0; c < 128; c++)
{
if (FT_Load_Char(face, c, FT_LOAD_RENDER))
{
std::cout << "ERROR::FREETYTPE: Failed to load Glyph" << std::endl;
continue;
}
unsigned int texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RED,
face->glyph->bitmap.width,
face->glyph->bitmap.rows,
0,
GL_RED,
GL_UNSIGNED_BYTE,
face->glyph->bitmap.buffer);
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);
my_vec2 size;
size.x = face->glyph->bitmap.width;
size.y = face->glyph->bitmap.rows;
my_vec2 bearing;
bearing.x = face->glyph->bitmap_left;
bearing.y = face->glyph->bitmap_top;
Character character = {
texture,
size,
bearing,
static_cast<unsigned int>(face->glyph->advance.x)};
Characters.insert(std::pair<char, Character>(c, character));
}
glBindTexture(GL_TEXTURE_2D, 0);
}
FT_Done_Face(face);
FT_Done_FreeType(ft);
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 4, NULL, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
while (!glfwWindowShouldClose(window))
{
processInput(window);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
my_vec3 color1;
color1.x = 0.5;
color1.y = 0.8;
color1.z = 0.2;
my_vec3 color2;
color2.x = 0.3;
color2.y = 0.7;
color2.z = 0.9;
RenderText(shaderProgram, "This is sample text", 125.0f, 125.0f, 1.0f, color1);
RenderText(shaderProgram, "(C) LearnOpenGL123.com", 370.0f, 370.0f, 0.5f, color2);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
}
void processInput(GLFWwindow *window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
}
void framebuffer_size_callback(GLFWwindow *window, int width, int height)
{
glViewport(0, 0, width, height);
}
void RenderText(GLuint shader, std::string text, float x, float y, float scale, my_vec3 color)
{
glUseProgram(shader);
glUniform3f(glGetUniformLocation(shader, "textColor"), color.x, color.y, color.z);
glActiveTexture(GL_TEXTURE0);
glBindVertexArray(VAO);
std::string::const_iterator c;
for (c = text.begin(); c != text.end(); c++)
{
Character ch = Characters[*c];
float xpos = x + ch.Bearing.x * scale;
float ypos = y - (ch.Size.y - ch.Bearing.y) * scale;
float w = ch.Size.x * scale;
float h = ch.Size.y * scale;
float vertices[6][4] = {
{xpos, ypos + h, 0.0f, 0.0f},
{xpos, ypos, 0.0f, 1.0f},
{xpos + w, ypos, 1.0f, 1.0f},
{xpos, ypos + h, 0.0f, 0.0f},
{xpos + w, ypos, 1.0f, 1.0f},
{xpos + w, ypos + h, 1.0f, 0.0f}};
glBindTexture(GL_TEXTURE_2D, ch.TextureID);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); // be sure to use glBufferSubData and not glBufferData
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDrawArrays(GL_TRIANGLES, 0, 6);
x += (ch.Advance >> 6) * scale; // bitshift by 6 to get value in pixels (2^6 = 64 (divide amount of 1/64th pixels by 64 to get amount of pixels))
}
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
}
I've been following this tutorial. The program compiles and runs without any errors, except that it does not render anything and I can not seem to figure out why.
It seems that you are placing your text on plane z=0
But your camera is looking to -Z (standard camera) from -0.01 to -100.0f.
You can solve it just moving your text a little bit to the -Z axis. A value between the range you have specified in the Zmin, Zmax parameters of the glm_ortho function. Just to be inside the box that ortho is defining.
It doesn't mind because it is an orthographic projection. Objects have the same size no matter how depth they are.
More details about projection can be found here http://www.songho.ca/opengl/gl_transform.html