OpenGL 将来自 ttf 的渲染器文本与背景纹理组合在一起时出错



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

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

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

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

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

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

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

返回.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 atlasn", 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] = '';
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 %sn", filename);
}
GLuint res = glCreateShader(type);
const GLchar* sources[] = {
// Define GLSL version
#ifdef GL_ES_VERSION_2_0
"#version 100n"  // OpenGL ES 2.0
#else
"#version 120n"  // 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_HIGHn"
"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 mediumpn"
"#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 programn");
GLuint program = glCreateProgram();
GLuint shader;
printf("Loading programn");
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 %sn", 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 %sn", 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 libraryn");
return 0;
}
/* Load a font */
if (FT_New_Face(ft, fontfilename, 0, &face)) {
fprintf(stderr, "Could not open font %sn", fontfilename);
return 0;
}
printf("Load Font Correctlyn");
program = create_program("text.v.glsl", "text.f.glsl");
if (program == 0)
return 0;
printf("Create program Correctlyn");
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 Correctlyn");
programBack = create_program("back.v.glsl", "back.f.glsl");
printf("Create program Background Correctlyn");
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 = %sn", glGetString(GL_VENDOR));
printf("RENDERER = %sn", glGetString(GL_RENDERER));
printf("VERSION = %sn", 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);注释线条,我可以完美地看到带纹理的正方形。

glUniform通过
  1. 调用glUseProgram对当前状态的一部分的程序对象进行操作。

正因为如此,函数atlas中对glUniform1i的调用是无用的,因为此时根本没有当前程序。您可以删除此调用,因为稍后会设置制服。


  1. 不会生成在函数vLoadPngToTexture中绑定的纹理glTextures[iTexture]

以某种方式更改您的代码,如下所示:

glGenTextures(1, glTextures+iTexture);
glBindTexture(GL_TEXTURE_2D, glTextures[iTexture]);

    绘制
  1. 背景时不使用数组缓冲区,但在绘制文本时使用数组缓冲区。在函数render_text中,您绑定glBindBuffer(GL_ARRAY_BUFFER, vbo);但从不释放它。这会导致数组缓冲区vbo在下一个周期中应绘制背景时仍处于绑定状态。正因为如此,glVertexAttribPointer,在函数display中,不会执行您希望它执行的操作。

您可以通过添加来解决此问题

glBindBuffer(GL_ARRAY_BUFFER, 0)

到函数末尾render_text.

最新更新