Rendering text on a quad with Freetype + GLFW

Hello,

I am a beginner to OpenGL, and I am currently trying to add Font rendering support to my app. I have reduced my program to the bare minimum to demonstrate the issues I am having.
I can successfully load a font, and print it to the screen using the command prompt, so I know the FreeType code is ok.
I can also draw a quad onto the screen, and the colour appears to change depending on which letter I try to draw, so it seems that something is happening in the rendering code, but I can’t seem to figure out what.

Can anyone shed any light on this?




// Include standard headers
#include <stdio.h>
#include <stdlib.h>

// Include GLEW. Always include it before gl.h and glfw.h, since it's a bit magic.
#include <PhoenixEngineDependencies/glew/glew.h>
// Include GLFW
#include <PhoenixEngineDependencies/glfw/glfw3.h>

// Include GLM
#include <PhoenixEngineDependencies/glm/glm.hpp>
#include <PhoenixEngineDependencies/glm/gtc/matrix_transform.hpp>
using namespace glm;

#include <iostream>
#include <fstream>
using namespace std;

#include "model_obj.h"

#include <PhoenixEngineDependencies/ttmath/ttmath.h>

#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H
#include FT_OUTLINE_H
#include FT_TRIGONOMETRY_H

int windowWidth = 800;
int windowHeight = 800;

void controls(GLFWwindow* window, int key, int scancode, int action, int mods)
{
	if(action == GLFW_PRESS)
		if(key == GLFW_KEY_ESCAPE)
			glfwSetWindowShouldClose(window, GL_TRUE);
}


GLFWwindow* initWindow(const int resX, const int resY)
{
	if(!glfwInit())
	{
		fprintf(stderr, "Failed to initialize GLFW
");
		return NULL;
	}
	glfwWindowHint(GLFW_SAMPLES, 4); // 4x antialiasing

	// Open a window and create its OpenGL context
	GLFWwindow* window = glfwCreateWindow(resX, resY, "TEST", NULL, NULL);

	if(window == NULL)
	{
		fprintf(stderr, "Failed to open GLFW window.
");
		glfwTerminate();
		return NULL;
	}

	glfwMakeContextCurrent(window);
	glfwSetKeyCallback(window, controls);

	// Get info of GPU and supported OpenGL version
	printf("Renderer: %s
", glGetString(GL_RENDERER));
	printf("OpenGL version supported %s
", glGetString(GL_VERSION));

	glEnable(GL_DEPTH_TEST); // Depth Testing
	glDepthFunc(GL_LEQUAL);
	glDisable(GL_CULL_FACE);
	glCullFace(GL_BACK);
	return window;
}

const char* textvertexSource =
	"version 150
"
	"in vec4 coord;"
	"out vec2 texcoord;"
	"void main {"
	"       gl_Position = vec4(coord.xy, 0, 1);"
	"       texcoord = coord.zw;"
	"}";

const char* textfragmentSource =
	"version  150
"
	"in vec2 texcoord;"
	"uniform sampler2D tex;"
	"uniform vec4 color;"
	"void main() {"
	"       gl_FragColor = vec4(1, 1, 1, texture2D(tex, texcoord).a * color;"
	"}";

FT_Library ft;
FT_Face face;

char* fontName = "tr.ttf";

unsigned char Image[800][800];

bool run = false;
void my_draw_bitmap( FT_Bitmap* bitmap, FT_Int x, FT_Int y)
{

	if(run == true)
		return;

	run = true;

	FT_Int  i, j, p, q;
	FT_Int  x_max = x + bitmap->width;
	FT_Int  y_max = y + bitmap->rows;
	for ( j = y, q = 0; j < y_max; j++, q++ )
	{
		for ( i = x, p = 0; i < x_max; i++, p++ )
		{
			if ( i<0 || j<0 || i>=800 || j>=800 )  continue;
			Image[j][i] |= bitmap->buffer[q * bitmap->width + p];

			if(Image[j][i]==0) {
				printf("-");
			}
			else{
				printf("0");
			}
		}
		printf("
");
	}

}


GLuint textureID;

int main(int argc, char** argv)
{

	GLFWwindow* window = initWindow(windowWidth, windowHeight);

	GLenum err = glewInit();


	if(FT_Init_FreeType(&ft))
		printf("Could not initiate freetype library.");


	if(FT_New_Face(ft, fontName, 0, &face))
	{
		printf("Could not load font: ");
		printf(fontName);
	}


	if( NULL != window )
	{

		glViewport(0, 0, windowWidth, windowHeight);

		glClearColor(0.5, 0.8, 0.3, 1.0);


		float points[] = {
			-0.5f, -0.5f, 0,
			-0.5f, 0.5f, 0,
			0.5f, -0.5f, 0,

			0.5f, -0.5f, 0,
			-0.5f, 0.5f, 0,
			0.5f, 0.5f, 0
		};

		GLuint vbo = 0;
		glGenBuffers (1, &vbo);
		glBindBuffer (GL_ARRAY_BUFFER, vbo);
		glBufferData (GL_ARRAY_BUFFER, 18 * sizeof (float), points, GL_STATIC_DRAW);


		GLuint vao = 0;
		glGenVertexArrays (1, &vao);
		glBindVertexArray (vao);
		glEnableVertexAttribArray (0);
		glBindBuffer (GL_ARRAY_BUFFER, vbo);
		glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, 0, NULL);




		const char* vertex_shader =
			"#version 330 core"
			"layout(location=0) in vec4 vVertex; //object space vertex"
			"out vec2 vUV;   // texture coordinates for texture lookup in the fragment shader"

			"void main()"
			"{"
			"    gl_Position = vec4(vVertex.xy,0,1);"
			"    vUV = vVertex.zw; // texture coordinate"
			"}"
			;

		const char* fragment_shader =
			"#version 330 core"
			"layout (location=0) out vec4 vFragColor;"
			"smooth in vec2 vUV;"
			"uniform sampler2D textureMap;"

			"void main()"
			"{"                                              
			"   vFragColor = texture(textureMap, vUV);"
			"}"
			;



		GLuint vs = glCreateShader (GL_VERTEX_SHADER);
		glShaderSource (vs, 1, &vertex_shader, NULL);
		glCompileShader (vs);
		GLuint fs = glCreateShader (GL_FRAGMENT_SHADER);
		glShaderSource (fs, 1, &fragment_shader, NULL);
		glCompileShader (fs);

		GLuint shader_programme = glCreateProgram ();
		glAttachShader (shader_programme, fs);
		glAttachShader (shader_programme, vs);
		glLinkProgram (shader_programme);



		err = FT_Set_Char_Size(
			face,    /* handle to face object           */
			0,       /* char_width in 1/64th of points  */
			16*64,   /* char_height in 1/64th of points */
			300,     /* horizontal device resolution    */
			300 );   /* vertical device resolution      */

		if(err){printf("FAIL1");}
		err = FT_Set_Pixel_Sizes(
			face,   /* handle to face object */
			0,      /* pixel_width           */
			16 );   /* pixel_height          */
		if(err){printf("FAIL2");}



		FT_GlyphSlot  slot;
		while(!glfwWindowShouldClose(window))
		{



			glClearColor( 1.0f, 1.0f, 1.0f, 1.0f );

			glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

			slot = face->glyph;
			FT_Load_Char(face, 'A', FT_LOAD_RENDER);


			my_draw_bitmap( &slot->bitmap,
				300 + slot->bitmap_left,
				200 - slot->bitmap_top );

			glGenTextures( 1, &textureID );
			glActiveTexture( GL_TEXTURE0 );

			glBindTexture(GL_TEXTURE_2D, 0);

			glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
			glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
			glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
			glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

			glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);


			glEnable (GL_TEXTURE_2D);
			glEnable(GL_BLEND);
			glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);


			glUseProgram (shader_programme);
			glBindVertexArray (vao);



			glTexImage2D( GL_TEXTURE_2D,
				0,
				GL_RGB,
				face->glyph->bitmap.width,
				face->glyph->bitmap.rows,
				0,
				GL_RGB,
				GL_UNSIGNED_BYTE,
				face->glyph->bitmap.buffer
				);


			glDrawArrays (GL_TRIANGLES, 0, 6);


			glfwSwapBuffers(window);


			glfwPollEvents();

		}

	}
	glfwDestroyWindow(window);
	glfwTerminate();
	return 0;
}





FreeType will render the bitmap as greyscale, but you’re telling glTexImage2D that the data is RGB. Use GL_RED instead (in the compatibility profile, you could use GL_LUMINANCE or GL_ALPHA, but those are deprecated).

Also:

This shouldn’t even compile (two open parentheses and only one close).

I’m sorry, I thought I had replied to this! Thanks a lot, your solution worked!