1. Example

Before you render any text piece, you have to initialize the class:

if (!Graphics_Text::Initialize("Arial.png", "Arial.csv", 2))

{

glfwTerminate();

return 3;

}

The first argument is the file path to the font texture, the second the file path to the corresponding csv file, the third argument is the "texture unit" you want to bind the font texture to.

If you dont need to render text anymore, release the resources:

Graphics_Text::CleanUp();

To render all text entries you have, call:

Graphics_Text::Render(text_entries);

The first argument is a std::list of type "Text_Entry":

struct Text_Entry

{

std::string Text;

glm::vec2 UpperLeftBound, LowerRightBound;

glm::vec4 Color;

float Size;

};

Each entry has its own text (of course!), boundaries, color and font size.

UpperLeftBound and LowerRightBound range: [-1; +1] x [-1; +1]

Font Size range: from 0.01f to unlimited

This makes the text independent of the actual window size.

If the string contains a "\n", it will be interpreted as new line.

If the string contains a "\t", it will be interpreted space of 2 x Font Size.

Main.cpp

#include <GL/glew.h>

#include <GLFW/glfw3.h>

#include <glm/glm.hpp>

#include <list>

#include "Shader.h"

#include "Graphics_Text.h"

int main(int argc, char* argv[])

{

/* Initialize GLFW */

if (!glfwInit())

return 1;

/* Create a window and its OpenGL context */

GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL", NULL, NULL);

if (!window)

{

glfwTerminate();

return 1;

}

/* Make the window's context current */

glfwMakeContextCurrent(window);

if (glewInit() != GLEW_OK)

{

glfwTerminate();

return 2;

}

if (!Graphics_Text::Initialize("Arial.png", "Arial.csv", 2))

{

glfwTerminate();

return 3;

}

/* Loop until the user closes the window */

while (!glfwWindowShouldClose(window))

{

/* Render here */

glClearColor(0.3f, 0.4f, 0.9f, 0.0f);

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

/* list of every piece of text */

std::list<Text_Entry> text_entries = {

{ LoadTextFile("src/Main.cpp"), glm::vec2(-1, 1), glm::vec2(1, -1), glm::vec4(0, 1, 0, 1), 0.05f },

{ "Thats my main.cpp:", glm::vec2(-0.7f, 0.5f), glm::vec2(1, -1), glm::vec4(1, 0, 0, 1), 0.2f },

};

Graphics_Text::Render(text_entries);

/* Swap front and back buffers */

glfwSwapBuffers(window);

/* Poll for and process events */

glfwPollEvents();

}

Graphics_Text::CleanUp();

glfwTerminate();

return 0;

}

Shader.h

#ifndef SHADER_H

#define SHADER_H

#include <GL/glew.h>

#include <string>

#include <list>

std::string LoadTextFile(const std::string& filepath);

std::string ShaderTypeName(GLuint shader);

bool CompileShader(GLuint shader, const std::string& sourcecode);

std::string ShaderInfoLog(GLuint shader);

bool LinkProgram(GLuint program, const std::list<GLuint>& shaderlist);

std::string ProgramInfoLog(GLuint program);

#endif // SHADER_H

Shader.cpp

#include "Shader.h"

#include <iostream>

#include <fstream>

std::string LoadTextFile(const std::string & filepath)

{

std::string result(""), line;

std::fstream f(filepath.c_str(), std::ios::in);

while (f.good())

{

std::getline(f, line);

result += line + '\n';

}

return result;

}

std::string ShaderTypeName(GLuint shader)

{

if (glIsShader(shader))

{

GLint type = 0;

glGetShaderiv(shader, GL_SHADER_TYPE, &type);

if (type == GL_VERTEX_SHADER)

return "Vertex Shader";

if (type == GL_TESS_CONTROL_SHADER)

return "Tessellation Control Shader";

if (type == GL_TESS_EVALUATION_SHADER)

return "Tessellation Evaluation Shader";

if (type == GL_GEOMETRY_SHADER)

return "Geometry Shader";

if (type == GL_FRAGMENT_SHADER)

return "Fragment Shader";

if (type == GL_COMPUTE_SHADER)

return "Compute Shader";

}

return "invalid shader";

}

bool CompileShader(GLuint shader, const std::string& sourcecode)

{

if (!glIsShader(shader))

{

std::cout << "ERROR: shader compilation failed, no valid shader specified" << std::endl;

return false;

}

if (sourcecode.empty())

{

std::cout << "ERROR: shader compilation failed, no source code specified (" << ShaderTypeName(shader) << ")" << std::endl;

return false;

}

const char* sourcearray[] = { sourcecode.c_str() };

glShaderSource(shader, 1, sourcearray, NULL);

glCompileShader(shader);

// check compile status

GLint status = 0;

glGetShaderiv(shader, GL_COMPILE_STATUS, &status);

// successfully compiled shader

if (status == GL_TRUE)

return true;

// show compile errors

std::cout << "ERROR: shader compilation failed (" << ShaderTypeName(shader) << ")" << std::endl << ShaderInfoLog(shader) << std::endl;

return false;

}

std::string ShaderInfoLog(GLuint shader)

{

if (glIsShader(shader))

{

GLint logsize = 0;

GLchar infolog[1024] = { 0 };

glGetShaderInfoLog(shader, 1024, &logsize, infolog);

return std::string(infolog);

}

return "invalid shader";

}

bool LinkProgram(GLuint program, const std::list<GLuint>& shaderlist)

{

if (!glIsProgram(program))

{

std::cout << "ERROR: shader linking failed, no valid program specified" << std::endl;

return false;

}

// attach all shaders to the program

for (std::list<GLuint>::const_iterator it = shaderlist.begin(); it != shaderlist.end(); it++)

{

if (glIsShader(*it))

glAttachShader(program, *it);

}

// link program

glLinkProgram(program);

// detach all shaders again

for (std::list<GLuint>::const_iterator it = shaderlist.begin(); it != shaderlist.end(); it++)

{

if (glIsShader(*it))

glDetachShader(program, *it);

}

GLint status = 0;

glGetProgramiv(program, GL_LINK_STATUS, &status);

// successfully linked program

if (status == GL_TRUE)

return true;

// show link errors

std::cout << "ERROR: shader linking failed" << std::endl << ProgramInfoLog(program) << std::endl;

return false;

}

std::string ProgramInfoLog(GLuint program)

{

if (glIsProgram(program))

{

GLint logsize = 0;

GLchar infolog[1024] = { 0 };

glGetProgramInfoLog(program, 1024, &logsize, infolog);

return std::string(infolog);

}

return "invalid program";

}