Help with FreeType or need another texture atlas tutorial

#include "EngineExperiments.h"

#include <cstdio>
#include <cstdlib>
#include <string>
#include <cmath>
#include <algorithm>

#include <Utilities\Include_Helpers\GL_Version.h>
#include <glload\gl_load.hpp>    // loads the functions declared in glload/gl_*version*.h"
#include <GL/freeglut.h>

#include <ft2build.h>
#include FT_FREETYPE_H

//#include "../common/shader_utils.h"



// BEGIN copy and past of FreeType's shader_utils.cpp

/**
* From the OpenGL Programming wikibook: http://en.wikibooks.org/wiki/OpenGL_Programming
* This file is in the public domain.
* Contributors: Sylvain Beucler
*/

//#include <stdio.h>
//#include <stdlib.h>
//#include <GL/glew.h>    // replaced with freeglut and gl_load

/**
* Store all the file's contents in memory, useful to pass shaders
* source code to OpenGL
*/
char* file_read(const char* filename)
{
    FILE* in = fopen(filename, "rb");
    if (in == NULL) return NULL;

    int res_size = BUFSIZ;
    char* res = (char*)malloc(res_size);
    int nb_read_total = 0;

    while (!feof(in) && !ferror(in)) {
        if (nb_read_total + BUFSIZ > res_size) {
            if (res_size > 10 * 1024 * 1024) break;
            res_size = res_size * 2;
            res = (char*)realloc(res, res_size);
        }
        char* p_res = res + nb_read_total;
        nb_read_total += fread(p_res, 1, BUFSIZ, in);
    }

    fclose(in);
    res = (char*)realloc(res, nb_read_total + 1);
    res[nb_read_total] = '\0';
    return res;
}

/**
* Display compilation errors from the OpenGL shader compiler
*/
void print_log(GLuint object)
{
    GLint log_length = 0;
    if (glIsShader(object))
        glGetShaderiv(object, GL_INFO_LOG_LENGTH, &log_length);
    else if (glIsProgram(object))
        glGetProgramiv(object, GL_INFO_LOG_LENGTH, &log_length);
    else {
        fprintf(stderr, "printlog: Not a shader or a program\n");
        return;
    }

    char* log = (char*)malloc(log_length);

    if (glIsShader(object))
        glGetShaderInfoLog(object, log_length, NULL, log);
    else if (glIsProgram(object))
        glGetProgramInfoLog(object, log_length, NULL, log);

    fprintf(stderr, "%s", log);
    free(log);
}

/**
* Compile the shader from file 'filename', with error handling
*/
GLuint create_shader(const char* filename, GLenum type)
{
    const GLchar* source = file_read(filename);
    if (source == NULL) {
        fprintf(stderr, "Error opening %s: ", filename); perror("");
        return 0;
    }
    GLuint res = glCreateShader(type);
    const GLchar* sources[] = {
        // Define GLSL version
#ifdef GL_ES_VERSION_2_0
        "#version 100\n"  // OpenGL ES 2.0
#else
        "#version 120\n"  // OpenGL 2.1
#endif
        ,
        // GLES2 precision specifiers
#ifdef GL_ES_VERSION_2_0
        // Define default float precision for fragment shaders:
        (type == GL_FRAGMENT_SHADER) ?
        "#ifdef GL_FRAGMENT_PRECISION_HIGH\n"
        "precision highp float;           \n"
        "#else                            \n"
        "precision mediump float;         \n"
        "#endif                           \n"
        : ""
        // Note: OpenGL ES automatically defines this:
        // #define GL_ES
#else
        // Ignore GLES 2 precision specifiers:
        "#define lowp   \n"
        "#define mediump\n"
        "#define highp  \n"
#endif
        ,
        source };
    glShaderSource(res, 3, sources, NULL);
    free((void*)source);

    glCompileShader(res);
    GLint compile_ok = GL_FALSE;
    glGetShaderiv(res, GL_COMPILE_STATUS, &compile_ok);
    if (compile_ok == GL_FALSE) {
        fprintf(stderr, "%s:", filename);
        print_log(res);
        glDeleteShader(res);
        return 0;
    }

    return res;
}

GLuint create_program(const char *vertexfile, const char *fragmentfile) {
    GLuint program = glCreateProgram();
    GLuint shader;

    if (vertexfile) {
        shader = create_shader(vertexfile, GL_VERTEX_SHADER);
        if (!shader)
            return 0;
        glAttachShader(program, shader);
    }

    if (fragmentfile) {
        shader = create_shader(fragmentfile, GL_FRAGMENT_SHADER);
        if (!shader)
            return 0;
        glAttachShader(program, shader);
    }

    glLinkProgram(program);
    GLint link_ok = GL_FALSE;
    glGetProgramiv(program, GL_LINK_STATUS, &link_ok);
    if (!link_ok) {
        fprintf(stderr, "glLinkProgram:");
        print_log(program);
        glDeleteProgram(program);
        return 0;
    }

    return program;
}

#ifdef GL_GEOMETRY_SHADER
GLuint create_gs_program(const char *vertexfile, const char *geometryfile, const char *fragmentfile, GLint input, GLint output, GLint vertices) {
    GLuint program = glCreateProgram();
    GLuint shader;

    if (vertexfile) {
        shader = create_shader(vertexfile, GL_VERTEX_SHADER);
        if (!shader)
            return 0;
        glAttachShader(program, shader);
    }

    if (geometryfile) {
        shader = create_shader(geometryfile, GL_GEOMETRY_SHADER);
        if (!shader)
            return 0;
        glAttachShader(program, shader);

        glProgramParameteriEXT(program, GL_GEOMETRY_INPUT_TYPE_EXT, input);
        glProgramParameteriEXT(program, GL_GEOMETRY_OUTPUT_TYPE_EXT, output);
        glProgramParameteriEXT(program, GL_GEOMETRY_VERTICES_OUT_EXT, vertices);
    }

    if (fragmentfile) {
        shader = create_shader(fragmentfile, GL_FRAGMENT_SHADER);
        if (!shader)
            return 0;
        glAttachShader(program, shader);
    }

    glLinkProgram(program);
    GLint link_ok = GL_FALSE;
    glGetProgramiv(program, GL_LINK_STATUS, &link_ok);
    if (!link_ok) {
        fprintf(stderr, "glLinkProgram:");
        print_log(program);
        glDeleteProgram(program);
        return 0;
    }

    return program;
}
#else
GLuint create_gs_program(const char *vertexfile, const char *geometryfile, const char *fragmentfile, GLint input, GLint output, GLint vertices) {
    fprintf(stderr, "Missing support for geometry shaders.\n");
    return 0;
}
#endif

GLint get_attrib(GLuint program, const char *name) {
    GLint attribute = glGetAttribLocation(program, name);
    if (attribute == -1)
        fprintf(stderr, "Could not bind attribute %s\n", name);
    return attribute;
}

GLint get_uniform(GLuint program, const char *name) {
    GLint uniform = glGetUniformLocation(program, name);
    if (uniform == -1)
        fprintf(stderr, "Could not bind uniform %s\n", name);
    return uniform;
}

// END shader_utils.cpp



GLuint program;
GLint attribute_coord;
GLint uniform_tex;
GLint uniform_color;

struct point {
    GLfloat x;
    GLfloat y;
    GLfloat s;
    GLfloat t;
};

GLuint vbo;

FT_Library ft;
FT_Face face;

// Maximum texture width
#define MAXWIDTH 1024

const char *fontfilename;

/**
* The atlas struct holds a texture that contains the visible US-ASCII characters
* of a certain font rendered with a certain character height.
* It also contains an array that contains all the information necessary to
* generate the appropriate vertex and texture coordinates for each character.
*
* After the constructor is run, you don't need to use any FreeType functions anymore.
*/
struct atlas {
    GLuint tex;     // texture object

    unsigned int w;         // width of texture in pixels
    unsigned int h;         // height of texture in pixels

    struct {
        float ax;   // advance.x
        float ay;   // advance.y

        float bw;   // bitmap.width;
        float bh;   // bitmap.height;

        float bl;   // bitmap_left;
        float bt;   // bitmap_top;

        float tx;   // x offset of glyph in texture coordinates
        float ty;   // y offset of glyph in texture coordinates
    } c[128];       // character information

    atlas(FT_Face face, int height) {
        FT_Set_Pixel_Sizes(face, 0, height);
        FT_GlyphSlot g = face->glyph;

        unsigned int roww = 0;
        unsigned int rowh = 0;
        w = 0;
        h = 0;

        memset(c, 0, sizeof c);
/r/opengl Thread