PDA

View Full Version : Rendering text on a quad with Freetype + GLFW



ZeroSum
02-04-2015, 05:28 PM
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\n");
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.\n");
glfwTerminate();
return NULL;
}

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

// Get info of GPU and supported OpenGL version
printf("Renderer: %s\n", glGetString(GL_RENDERER));
printf("OpenGL version supported %s\n", 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\n"
"in vec4 coord;"
"out vec2 texcoord;"
"void main {"
" gl_Position = vec4(coord.xy, 0, 1);"
" texcoord = coord.zw;"
"}";

const char* textfragmentSource =
"version 150\n"
"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("\n");
}

}


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;
}

GClements
02-08-2015, 05:37 AM
FT_Load_Char(face, 'A', FT_LOAD_RENDER);



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
);

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:




" gl_FragColor = vec4(1, 1, 1, texture2D(tex, texcoord).a * color;"

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

ZeroSum
03-12-2015, 04:31 PM
I'm sorry, I thought I had replied to this! Thanks a lot, your solution worked!