结合来自ttf和背景纹理

时间:2018-01-10 18:28:55

标签: c++ opengl-es opengl-es-2.0 freetype

我遇到了Opengl和Opengl ES的问题。我想用png图像纹理制作正方形并在这些正方形前面渲染文本。

我可以使用png图像中的纹理制作正方形,我可以像this example一样从ttf渲染文本,但只有在不同时执行的情况下它才有效。我将尝试更好地解释(示例代码太脏了,因为我从一个软件获得的代码更结构化,更大,而且这个代码只是一个例子):

我有一个带有一个顶点着色器的GLProgram和一个用于纹理方块的片段着色器。我有另一个GLProgram与另一个顶点着色器和另一个片段着色器来制作渲染器文本。

如果我加载所有GL程序并且只绘制每一帧纹理方块,我可以完美地看到它。

如果我在纹理正方形之前或之后绘制渲染器文本(使用他的GL程序)(在绘制正方形之前执行他的glUseProgram)我只能看到屏幕上的纹理文本和用它创建的背景颜色( glClearColor(x.xf,x.xf,x.xf,x.xf)),我看不到纹理方块。

有谁知道代码中的错误在哪里?

现在我将发布着色器和示例源代码:

back.v.glsl:

attribute vec4 g_vPosition;
attribute vec3 g_vColor;
attribute vec2 g_vTexCoord;

varying   vec3 g_vVSColor;
varying   vec2 g_vVSTexCoord;

void main()                 
{                               
    gl_Position  = g_vPosition; 
    g_vVSColor = g_vColor;              
    g_vVSTexCoord = g_vTexCoord;            
}

back.f.glsl:

uniform sampler2D s_texture;
varying   vec3      g_vVSColor; 
varying   vec2 g_vVSTexCoord;

void main()                     
{                               
    gl_FragColor = texture2D(s_texture,g_vVSTexCoord);  
}

text.v.glsl:

attribute vec4 coord;
varying vec2 texpos;

void main(void) {
  gl_Position = vec4(coord.xy, 0, 1);
  texpos = coord.zw;
}

text.f.glsl:

varying vec2 texpos;
uniform sampler2D tex;
uniform vec4 color;

void main(void) {
  //gl_FragColor = vec4(1, 1, 1, texture2D(tex, texpos).a) * color;
  gl_FragColor = vec4(color.rgb, texture2D(tex, texpos).a);
}

源代码:

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <assert.h>

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <assert.h>
#include <math.h>
#include <signal.h>

#include <GLES2/gl2.h>
#include <EGL/egl.h>

#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>

#include <unistd.h>
#include <sys/time.h>

#include <png.h>

EGLDisplay          egldisplay;
EGLConfig           eglconfig;
EGLSurface          eglsurface;
EGLContext          eglcontext;
EGLNativeWindowType eglNativeWindow;
EGLNativeDisplayType eglNativeDisplayType;

#include <ft2build.h>
#include FT_FREETYPE_H

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

GLuint programBack;
GLint coordBack = 0;
GLint texBack = 2;
GLint colorBack = 1;

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

GLuint vbo;

FT_Library ft;
FT_Face face;

// Maximum texture width
#define MAXWIDTH 800

const char *fontfilename;

float VertexColors[] = {

    /* Red */
    1.0f, 0.0f, 0.0f, 1.0f,
    /* Red */
    1.0f, 0.0f, 0.0f, 1.0f,

    /* Green */
    0.0f, 1.0f, 0.0f, 1.0f,

    /* Green */
    0.0f, 1.0f, 0.0f, 1.0f,

};

float VertexTexCoords[] = {
    /* Front Face */
    0.0f,0.0f,
    1.0f,0.0f,
    0.0f,1.0f,
    1.0f,1.0f,
};

float fBackgroundPosition[12] = {
    /* Bottom Left Of The Quad (Front) */
    -1.0f,-1.0f,1.0f,
    /* Bottom Right Of The Quad (Front) */
    1.0f,-1.0f,1.0f,
    /* Top Left Of The Quad (Front) */
    -1.0f,1.0f,1.0f,
    /* Top Right Of The Quad (Front) */
    1.0f,1.0f,1.0f,
};

GLuint glTextures[4];


/**
 * 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[256];       // 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);

        /* Find minimum size for a texture holding all visible ASCII characters */
        //for (int i = 32; i < 128; i++) {
        for (int i = 32; i < 254; i++) {
            if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {
                fprintf(stderr, "Loading character %c failed!\n", i);
                continue;
            }
            if (roww + g->bitmap.width + 1 >= MAXWIDTH) {
                w = std::max(w, roww);
                h += rowh;
                roww = 0;
                rowh = 0;
            }
            roww += g->bitmap.width + 1;
            rowh = std::max(rowh, g->bitmap.rows);
        }

        w = std::max(w, roww);
        h += rowh;

        /* Create a texture that will be used to hold all ASCII glyphs */
        glActiveTexture(GL_TEXTURE0);
        glGenTextures(1, &tex);
        glBindTexture(GL_TEXTURE_2D, tex);
        glUniform1i(uniform_tex, 0);

        glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_ALPHA, GL_UNSIGNED_BYTE, 0);

        /* We require 1 byte alignment when uploading texture data */
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

        /* Clamping to edges is important to prevent artifacts when scaling */
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

        /* Linear filtering usually looks best for text */
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        /* Paste all glyph bitmaps into the texture, remembering the offset */
        int ox = 0;
        int oy = 0;

        rowh = 0;

        //for (int i = 32; i < 128; i++) {
        for (int i = 32; i < 254; i++) {
            if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {
                fprintf(stderr, "Loading character %c failed!\n", i);
                continue;
            }

            if (ox + g->bitmap.width + 1 >= MAXWIDTH) {
                oy += rowh;
                rowh = 0;
                ox = 0;
            }

            glTexSubImage2D(GL_TEXTURE_2D, 0, ox, oy, g->bitmap.width, g->bitmap.rows, GL_ALPHA, GL_UNSIGNED_BYTE, g->bitmap.buffer);
            c[i].ax = g->advance.x >> 6;
            c[i].ay = g->advance.y >> 6;

            c[i].bw = g->bitmap.width;
            c[i].bh = g->bitmap.rows;

            c[i].bl = g->bitmap_left;
            c[i].bt = g->bitmap_top;

            c[i].tx = ox / (float)w;
            c[i].ty = oy / (float)h;

            rowh = std::max(rowh, g->bitmap.rows);
            ox += g->bitmap.width + 1;
        }

        fprintf(stderr, "Generated a %d x %d (%d kb) texture atlas\n", w, h, w * h / 1024);
    }

    ~atlas() {
        glDeleteTextures(1, &tex);
    }
};

atlas *a48;
atlas *a24;
atlas *a12;


//#define GL_ES_VERSION_2_0

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

/**
 * 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;
    }
    else {
        printf("Load shader correctly %s\n", filename);
    }
    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) {
    printf("Creating program\n");

    GLuint program = glCreateProgram();
    GLuint shader;

    printf("Loading program\n");

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

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

bool bLoadPngImage(char *name, int &outWidth, int &outHeight, bool &outHasAlpha, GLubyte **outData) {
    png_structp png_ptr;
    png_infop info_ptr;
    unsigned int sig_read = 0;
    int color_type, interlace_type;
    FILE *fp;

    if ((fp = fopen(name, "rb")) == NULL)
        return false;

    /* Create and initialize the png_struct
     * with the desired error handler
     * functions.  If you want to use the
     * default stderr and longjump method,
     * you can supply NULL for the last
     * three parameters.  We also supply the
     * the compiler header file version, so
     * that we know if the application
     * was compiled with a compatible version
     * of the library.  REQUIRED
     */
    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
        NULL, NULL, NULL);

    if (png_ptr == NULL) {
        fclose(fp);
        return false;
    }

    /* Allocate/initialize the memory
    * for image information.  REQUIRED. */
    info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == NULL) {
        fclose(fp);
        png_destroy_read_struct(&png_ptr, NULL, NULL);
        return false;
    }

    /* Set error handling if you are
     * using the setjmp/longjmp method
     * (this is the normal method of
     * doing things with libpng).
     * REQUIRED unless you  set up
     * your own error handlers in
     * the png_create_read_struct()
     * earlier.
     */
    if (setjmp(png_jmpbuf(png_ptr))) {
        /* Free all of the memory associated
         * with the png_ptr and info_ptr */
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
        fclose(fp);
        /* If we get here, we had a
         * problem reading the file */
        return false;
    }

    /* Set up the output control if
     * you are using standard C streams */
    png_init_io(png_ptr, fp);

    /* If we have already
     * read some of the signature */
    png_set_sig_bytes(png_ptr, sig_read);

    /*
     * If you have enough memory to read
     * in the entire image at once, and
     * you need to specify only
     * transforms that can be controlled
     * with one of the PNG_TRANSFORM_*
     * bits (this presently excludes
     * dithering, filling, setting
     * background, and doing gamma
     * adjustment), then you can read the
     * entire image (including pixels)
     * into the info structure with this
     * call
     *
     * PNG_TRANSFORM_STRIP_16 |
     * PNG_TRANSFORM_PACKING  forces 8 bit
     * PNG_TRANSFORM_EXPAND forces to
     *  expand a palette into RGB
     */
    png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND, NULL);

    png_uint_32 width, height;
    int bit_depth;
    png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
        &interlace_type, NULL, NULL);
    outWidth = width;
    outHeight = height;

    unsigned int row_bytes = png_get_rowbytes(png_ptr, info_ptr);
    *outData = (unsigned char*)malloc(row_bytes * outHeight);

    png_bytepp row_pointers = png_get_rows(png_ptr, info_ptr);

    for (int i = 0; i < outHeight; i++) {
        // note that png is ordered top to
        // bottom, but OpenGL expect it bottom to top
        // so the order or swapped
        memcpy(*outData + (row_bytes * (outHeight - 1 - i)), row_pointers[i], row_bytes);
    }

    /* Clean up after the read,
     * and free any memory allocated */
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);

    /* Close the file */
    fclose(fp);

    /* That's it */
    return true;
}

void vLoadPngToTexture(std::string sFilename, int iTexture) {
    GLubyte *glTextureImage;
    int iWidth, iHeight;
    bool bHasAlpha;
    //char filename[] = "/home/root/res/drawable/disclaimerantamina.png";
    //bool success = bLoadPngImage((char *)sFilename.c_str(), iWidth, iHeight, bHasAlpha, &glTextureImage);
    //if (!success) {
    if (!bLoadPngImage((char *)sFilename.c_str(), iWidth, iHeight, bHasAlpha, &glTextureImage)) {
        std::cout << "Unable to load png file" << std::endl;
        exit(0);
    }

    std::cout << "Image loaded " << sFilename << " " << iWidth << " " << iHeight << " alpha " << bHasAlpha << std::endl;

    glBindTexture(GL_TEXTURE_2D, glTextures[iTexture]);
    /* Generate The Texture */
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, iWidth,
        iHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
        glTextureImage);
    /* Linear Filtering */
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);


    std::cout << "Texture loaded " << iTexture << " - " << sFilename << std::endl;
}

int init_resources() {
    /* Initialize the FreeType2 library */
    if (FT_Init_FreeType(&ft)) {
        fprintf(stderr, "Could not init freetype library\n");
        return 0;
    }

    /* Load a font */
    if (FT_New_Face(ft, fontfilename, 0, &face)) {
        fprintf(stderr, "Could not open font %s\n", fontfilename);
        return 0;
    }

    printf("Load Font Correctly\n");

    program = create_program("text.v.glsl", "text.f.glsl");
    if (program == 0)
        return 0;

    printf("Create program Correctly\n");

    attribute_coord = get_attrib(program, "coord");
    uniform_tex = get_uniform(program, "tex");
    uniform_color = get_uniform(program, "color");

    if (attribute_coord == -1 || uniform_tex == -1 || uniform_color == -1)
        return 0;

    printf("Create attributes Correctly\n");

    programBack = create_program("back.v.glsl", "back.f.glsl");

    printf("Create program Background Correctly\n");

    coordBack = get_attrib(programBack, "g_vPosition");
    //colorBack = get_attrib(programBack, "g_vColor");
    texBack = get_attrib(programBack, "g_vTexCoord");

    if (coordBack == -1 || colorBack == -1 || texBack == -1)
        return 0;

    // Create the vertex buffer object
    glGenBuffers(1, &vbo);

    ///* Create texture atlasses for several font sizes */
    a48 = new atlas(face, 48);
    a24 = new atlas(face, 24);
    a12 = new atlas(face, 12);

    return 1;
}

/**
 * Render text using the currently loaded font and currently set font size.
 * Rendering starts at coordinates (x, y), z is always 0.
 * The pixel coordinates that the FreeType2 library uses are scaled by (sx, sy).
 */
void render_text(const char *text, atlas * a, float x, float y, float sx, float sy) {
    const uint8_t *p;

    /* Use the texture containing the atlas */
    glBindTexture(GL_TEXTURE_2D, a->tex);
    glUniform1i(uniform_tex, 0);

    /* Set up the VBO for our vertex data */
    glEnableVertexAttribArray(attribute_coord);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glVertexAttribPointer(attribute_coord, 4, GL_FLOAT, GL_FALSE, 0, 0);

    point coords[6 * strlen(text)];
    int c = 0;

    /* Loop through all characters */
    for (p = (const uint8_t *)text; *p; p++) {
        /* Calculate the vertex and texture coordinates */
        float x2 = x + a->c[*p].bl * sx;
        float y2 = -y - a->c[*p].bt * sy;
        float w = a->c[*p].bw * sx;
        float h = a->c[*p].bh * sy;

        /* Advance the cursor to the start of the next character */
        x += a->c[*p].ax * sx;
        y += a->c[*p].ay * sy;

        /* Skip glyphs that have no pixels */
        if (!w || !h)
            continue;

        coords[c++] = (point) {
            x2, -y2, a->c[*p].tx, a->c[*p].ty
        };
        coords[c++] = (point) {
            x2 + w, -y2, a->c[*p].tx + a->c[*p].bw / a->w, a->c[*p].ty
        };
        coords[c++] = (point) {
            x2, -y2 - h, a->c[*p].tx, a->c[*p].ty + a->c[*p].bh / a->h
        };
        coords[c++] = (point) {
            x2 + w, -y2, a->c[*p].tx + a->c[*p].bw / a->w, a->c[*p].ty
        };
        coords[c++] = (point) {
            x2, -y2 - h, a->c[*p].tx, a->c[*p].ty + a->c[*p].bh / a->h
        };
        coords[c++] = (point) {
            x2 + w, -y2 - h, a->c[*p].tx + a->c[*p].bw / a->w, a->c[*p].ty + a->c[*p].bh / a->h
        };
    }

    /* Draw all the character on the screen in one go */
    glBufferData(GL_ARRAY_BUFFER, sizeof coords, coords, GL_DYNAMIC_DRAW);
    glDrawArrays(GL_TRIANGLES, 0, c);

    glDisableVertexAttribArray(attribute_coord);
}

void display() {
    //float sx = 2.0 / glutGet(GLUT_WINDOW_WIDTH);
    //float sy = 2.0 / glutGet(GLUT_WINDOW_HEIGHT);

    float sx = 2.0 / 800;
    float sy = 2.0 / 480;

    glViewport(0, 0, 800, 480);

    glUseProgram(programBack);

    /* White background */
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    /* Enable blending, necessary for our alpha texture */
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    glVertexAttribPointer(coordBack, 3, GL_FLOAT, 0, 0, fBackgroundPosition);
    glEnableVertexAttribArray(coordBack);

    //glVertexAttribPointer(colorBack, 4, GL_FLOAT, 0, 0, VertexColors);
    //glEnableVertexAttribArray(colorBack);

    glVertexAttribPointer(texBack, 2, GL_FLOAT, 0, 0, VertexTexCoords);
    glEnableVertexAttribArray(texBack);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, glTextures[0]);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    // Cleanup
    glDisableVertexAttribArray(coordBack);
    glDisableVertexAttribArray(colorBack);
    glDisableVertexAttribArray(texBack);

    glUseProgram(program);

    GLfloat black[4] = { 0, 0, 0, 1 };
    GLfloat red[4] = { 1, 0, 0, 1 };
    GLfloat transparent_green[4] = { 0, 1, 0, 0.5 };

    /* Set color to black */
    //glUniform4fv(uniform_color, 1, black);

    /* Effects of alignment */
    render_text("The ñ Ñ Quick Brown Fox Jumps Over The Lazy Dog", a48, -1 + 8 * sx, 1 - 50 * sy, sx, sy);
    //render_text("The , . - + { } & % Misaligned Fox Jumps Over The Lazy Dog", a48, -1 + 8.5 * sx, 1 - 100.5 * sy, sx, sy);

    ///* Scaling the texture versus changing the font size */
    //render_text("The ç ó Small Texture Scaled Fox Jumps Over The Lazy Dog", a48, -1 + 8 * sx, 1 - 175 * sy, sx * 0.5, sy * 0.5);
    //render_text("The Small Font Sized Fox Jumps Over The Lazy Dog", a24, -1 + 8 * sx, 1 - 200 * sy, sx, sy);
    //render_text("The Tiny Texture Scaled Fox Jumps Over The Lazy Dog", a48, -1 + 8 * sx, 1 - 235 * sy, sx * 0.25, sy * 0.25);
    //render_text("The Tiny Font Sized Fox Jumps Over The Lazy Dog", a12, -1 + 8 * sx, 1 - 250 * sy, sx, sy);

    ///* Colors and transparency */
    //render_text("The Solid Black Fox Jumps Over The Lazy Dog", a48, -1 + 8 * sx, 1 - 430 * sy, sx, sy);

    //glUniform4fv(uniform_color, 1, red);
    //render_text("The Solid Red Fox Jumps Over The Lazy Dog", a48, -1 + 8 * sx, 1 - 330 * sy, sx, sy);
    //render_text("The Solid Red Fox Jumps Over The Lazy Dog", a48, -1 + 28 * sx, 1 - 450 * sy, sx, sy);

    //glUniform4fv(uniform_color, 1, transparent_green);
    //render_text("The Transparent Green Fox Jumps Over The Lazy Dog", a48, -1 + 8 * sx, 1 - 380 * sy, sx, sy);
    //render_text("The Transparent Green Fox Jumps Over The Lazy Dog", a48, -1 + 18 * sx, 1 - 440 * sy, sx, sy);

    eglSwapBuffers(egldisplay, eglsurface);
}

void free_resources() {
    glDeleteProgram(program);
}

int init(void)
{
    Display    *x_display;
    Window      win;

    x_display = XOpenDisplay(":0");   // open the standard display (the primary screen)
    if (x_display == NULL) {
        std::cout << "cannot connect to X server" << std::endl;
        return 1;
    }

    Window root = DefaultRootWindow(x_display);   // get the root window (usually the whole screen)

    XSetWindowAttributes  swa;
    swa.event_mask = ExposureMask | PointerMotionMask | KeyPressMask;

    win = XCreateWindow(   // create a window with the provided parameters
        x_display, root,
        0, 0, 800, 480, 0,
        CopyFromParent, InputOutput,
        CopyFromParent, CWEventMask,
        &swa);

    XMapWindow(x_display, win);             // make the window visible on the screen
    XStoreName(x_display, win, "GL test"); // give the window a name

    static const EGLint s_configAttribs[] =
    {
        EGL_RENDERABLE_TYPE,    4,
        EGL_RED_SIZE,           5,
        EGL_GREEN_SIZE,         6,
        EGL_BLUE_SIZE,          5,
        EGL_ALPHA_SIZE,         0,
        EGL_SAMPLES,            0,
        EGL_SAMPLE_BUFFERS,     1,
        EGL_SAMPLES,            4,  // This is for 4x MSAA.
        EGL_NONE
    };


    EGLint numconfigs;

    egldisplay = eglGetDisplay((EGLNativeDisplayType)x_display);
    eglInitialize(egldisplay, NULL, NULL);
    assert(eglGetError() == EGL_SUCCESS);
    eglBindAPI(EGL_OPENGL_ES_API);

    eglChooseConfig(egldisplay, s_configAttribs, &eglconfig, 1, &numconfigs);
    assert(eglGetError() == EGL_SUCCESS);
    assert(numconfigs == 1);

    eglsurface = eglCreateWindowSurface(egldisplay, eglconfig, win, NULL);

    assert(eglGetError() == EGL_SUCCESS);
    EGLint ContextAttribList[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
    eglcontext = eglCreateContext(egldisplay, eglconfig, EGL_NO_CONTEXT, ContextAttribList);
    assert(eglGetError() == EGL_SUCCESS);
    eglMakeCurrent(egldisplay, eglsurface, eglsurface, eglcontext);
    assert(eglGetError() == EGL_SUCCESS);

    printf("VENDOR = %s\n", glGetString(GL_VENDOR));
    printf("RENDERER = %s\n", glGetString(GL_RENDERER));
    printf("VERSION = %s\n", glGetString(GL_VERSION));
}

int main(int argc, char *argv[]) {
    if (argc > 1)
        fontfilename = argv[1];
    else
        fontfilename = "FreeSans.ttf";

    init();

    init_resources();

    std::string sBackground = "back2.png";

    vLoadPngToTexture(sBackground, 0);

    //// this is needed for time measuring  -->  frames per second
    struct  timezone  tz;
    timeval  t1, t2;
    gettimeofday(&t1, &tz);
    int  num_frames = 0;

    while (1) {
        display();
        if (++num_frames % 30 == 0) {
        //if (++num_frames % 100 == 0) {
            gettimeofday(&t2, &tz);
            float dt = t2.tv_sec - t1.tv_sec + (t2.tv_usec - t1.tv_usec) * 1e-6;
            std::cout << "fps: " << num_frames / dt << std::endl;
            num_frames = 0;
            t1 = t2;
        }
        usleep(32000);
    }

    return 0;
}

如果我对render_text("The ñ Ñ Quick Brown Fox Jumps Over The Lazy Dog", a48, -1 + 8 * sx, 1 - 50 * sy, sx, sy);行进行评论,我可以完美地看到纹理正方形。

1 个答案:

答案 0 :(得分:1)

  1. glUniform通过调用glUseProgram对作为当前状态一部分的程序对象进行操作。
  2. 因此,函数glUniform1iatlas的调用是无用的,因为此时根本没有当前的程序。您可以删除此通话,因为您稍后会设置制服。

    1. 未生成在函数glTextures[iTexture]中绑定的纹理vLoadPngToTexture
    2. 以某种方式改变你的代码:

      glGenTextures(1, glTextures+iTexture);
      glBindTexture(GL_TEXTURE_2D, glTextures[iTexture]);
      
      1. 绘制背景时不使用数组缓冲区,但在绘制文本时使用数组缓冲区。在函数render_text中绑定glBindBuffer(GL_ARRAY_BUFFER, vbo);但您永远不会释放它。这会导致在下一个周期中绘制背景时仍然绑定数组缓冲区vbo。因此,glVertexAttribPointer在函数display中不会按照您的预期执行。
      2. 您可以通过添加

        来解决此问题
        glBindBuffer(GL_ARRAY_BUFFER, 0)
        

        到函数render_text的末尾。