问题
This thread is related to https: //stackoverflow.com/questions/50955558/render-fonts-with-sdl2-opengl-es-2-0-glsl-1-0-freetype
I have a problem combining font rendering and using this function as follows:
// Create VBO (Vertex Buffer Object) based on the vertices provided, render the vertices on the
// background buffer and eventually swap buffers to update the display.
// Return index of VBO buffer
GLuint drawVertices(SDL_Window *window, Vertex *vertices, GLsizei numVertices, int mode){
// Number of vertices elements must be provided as a param (see numVertices) because
// sizeof() cannot calculate the size of the type a pointer points to
//GLsizei vertSize = sizeof(vertices[0]);
//SDL_Log("Vertices size is %d, no of vertices is %d", vertSize, numVertices);
// Create a VBO (Vertex Buffer Object)
GLuint VBO = vboCreate(vertices, numVertices);
if (!VBO) {
// Failed. Error message has already been printed, so just quit
return (GLuint)NULL;
}
// Set up for rendering the triangle (activate the VBO)
GLuint positionIdx = 0; // Position is vertex attribute 0
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glVertexAttribPointer(positionIdx, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*)0);
glEnableVertexAttribArray(positionIdx);
if (mode & CLEAR){
// Set color of the clear operation
glClearColor(0.0, 0.0, 0.0, 1.0);
// Clears the invisible buffer
glClear(GL_COLOR_BUFFER_BIT);
}
// Now draw!
// GL_POINTS = Draw only the pixels that correspond to the vertices coordinates
// GL_LINE_STRIP = Draw line that connects the vertices coordinates
// GL_LINE_LOOP = Draw line that connects the vertices coordinates plus a line that re-connects the last coordinate with the first
if (mode & RENDER){ glDrawArrays(GL_LINE_STRIP, 0, numVertices); }
// Don’t forget to flip the buffers as well, to display the final image:
// Update the window
if (mode & UPDATE){ SDL_GL_SwapWindow(window); }
return VBO;
}
This function uses glDrawArrays() to draw a series of lines connecting the provided vertices. Flags CLEAR, RENDER & UPDATE are being used to let me do something like:
drawVertices(window, vertices, sizeOfVertices, CLEAR | RENDER);
drawVertices(window, vertices, sizeOfVertices, RENDER);
drawVertices(window, vertices, sizeOfVertices, RENDER | UPDATE);
I did the same thing with the font rendering function thus enabling me to draw multiple strings in various x,y coordinates. The next two functions do the font rendering based on the code i submitted at the first place and off course your corrections.
void render_text(const char *text, float x, float y, float sx, float sy) {
const char *p;
FT_GlyphSlot g = face->glyph;
SDL_Log("Debug info: glyph w: %d, glyph rows: %d", g->bitmap.width, g->bitmap.rows);
for(p = text; *p; p++) {
// If FT_Load_Char() returns a non-zero value then the glyph in *p could not be loaded
if(FT_Load_Char(face, *p, FT_LOAD_RENDER)){ continue; }
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RED,
g->bitmap.width,
g->bitmap.rows,
0,
GL_RED,
GL_UNSIGNED_BYTE,
g->bitmap.buffer
);
float x2 = x + g->bitmap_left * sx;
float y2 = -y - g->bitmap_top * sy;
float w = g->bitmap.width * sx;
float h = g->bitmap.rows * sy;
GLfloat box[4][4] = {
{x2, -y2 , 0, 0},
{x2 + w, -y2 , 1, 0},
{x2, -y2 - h, 0, 1},
{x2 + w, -y2 - h, 1, 1},
};
glBufferData(GL_ARRAY_BUFFER, sizeof box, box, GL_DYNAMIC_DRAW);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
x += (g->advance.x>>6) * sx;
y += (g->advance.y>>6) * sy;
}
}
void glRenderText(char *text, int _x, int _y, SDL_Color rgb, int mode) {
float x = _x;
float y = _y;
int w=0, h=0;
SDL_GetWindowSize(SDLmain.window, &w, &h);
float xMax = 2.0 / (float)w;
float yMax = 2.0 / (float)h;
GLuint color_loc = glGetUniformLocation( shaderProg, "color" );
float col[4] = { (float)rgb.r/255, (float)rgb.g/255, (float)rgb.b/255, 1 }; // red and opaque
glUniform4fv( color_loc, 1, col);
// Clear invisible buffer
if (mode & CLEAR){ glClearColor(0.0, 0.0, 0.0, 1); glClear(GL_COLOR_BUFFER_BIT); }
// If coordinate system required is:
// COORD_SYS_CONVENTIONAL = (1) left bottom corner is 0,0 and moving towards right and top sides we reach max screen size in pixels e.g 1024 * 768 pixels
// COORD_SYS_CARTECIAN = (2) left bottom corner is -1,-1 and moving towards right and top sides we reach +1,+1 . The center of the display is always 0,0
if (mode & ~COORD_SYS_CARTECIAN){
x = (_x * xMax)-1;
y = (_y * yMax)-1;
}
// Draw the text on the invisible buffer
if (mode & RENDER){ render_text(text, x, y, xMax, yMax); }
// Update display
if (mode & UPDATE){ SDL_GL_SwapWindow(SDLmain.window); }
}
I therefore can do:
glRenderText(tmp, 0, 0, Olive, CLEAR | RENDER | UPDATE);
glRenderText(tmp, 0, 150, Yellow_Green, RENDER);
glRenderText(tmp, 0, 300, Light_Coral, RENDER | UPDATE);
It turns out that i can either render fonts at various x,y coordinates or use the function drawVertices to render lines connecting those vertices BUT not both. That is, i cannot do this:
glRenderText(tmp, 0, 0, Olive, CLEAR | RENDER);
glRenderText(tmp, 0, 150, Yellow_Green, RENDER);
glRenderText(tmp, 0, 300, Light_Coral, RENDER);
drawVertices(window, vertices, sizeOfVertices, RENDER);
drawVertices(window, vertices, sizeOfVertices, RENDER);
drawVertices(window, vertices, sizeOfVertices, RENDER | UPDATE);
As you can tell the logic is that in either functions you have to just with a CLEAR | RENDER flag, then do only RENDER and on your last call to either functions use RENDER | UPDATE.
ISSUES:
(1) In my attempt to do the previous, that is, combinning glRenderText() + drawVertices() i failed because there is clearly something to be setup prior calling them one after the other.
(2) Another issue that i am facing is that running the code on my raspi3 resulted in drawVertices() working fine back when it comes to fonts i could only see the effect of glClearColor() & glClear(GL_COLOR_BUFFER_BIT) which means that the display was cleared with the color setup by glClearColor() but there was no font rendering to be seen. I tried both GL driver mode. There is one called FULL KMS GL driver and another called FAKE KMS GL driver.
Also, in order for the drawVertices() to work i had to comment the code provided below:
FT_Set_Pixel_Sizes(face, 0, 200);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
GLuint vbo;
GLuint attribute_coord=0;
glGenBuffers(1, &vbo);
glEnableVertexAttribArray(attribute_coord);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(attribute_coord, 4, GL_FLOAT, GL_FALSE, 0, 0);
I still had to keep the following code active:
// Load the shader program and set it for use
shaderProg = shaderProgLoad("shaderV1.vert", "shaderV1.frag");
GLuint tex_loc = glGetUniformLocation( shaderProg, "tex" );
GLuint color_loc = glGetUniformLocation( shaderProg, "color" );
// Activate the resulting shaders program
glUseProgram(shaderProg);
glUniform1i( tex_loc, 0 ); // 0, because the texture is bound to of texture unit 0
// Define RGB color + Alpha
float col[4] = { 0.0f, 1.0f, 1.0, 1.0f };
glUniform4fv( color_loc, 1, col);
回答1:
i was able to resolve the issue by reseting pretty much everything that is not common to the two operations (glRenderText() & drawVertices()) The following code stays as is before calling any of the two functions ()glRenderText() & drawVertices()). These two functions have been updated so that a proper reset is done before reaching the point where glDrawArrays() is executed
// Load the shader program and set it for use
shaderProg = shaderProgLoad("shaderV1.vert", "shaderV1.frag");
// Activate the resulting shaders program
glUseProgram(shaderProg);
// After the shaders (vertex & fragment) have been compiled & linked into a program
// we can query the location index value of a uniform variable existing in the program.
// In this case we are querying uniform variables "tex" that exist in the fragment shader
GLuint tex_loc = glGetUniformLocation( shaderProg, "tex" );
// Set the value of the uniform variable "tex_loc" to 0, because the texture is bound to of texture unit 0
glUniform1i( tex_loc, 0 );
This is the updated function that resets some options so that we get the result we need. For example, glDisable(GL_BLEND); is used to disable blending when it comes to drawing lines. The most important off course is that i use glBindBuffer() to set the appropriate buffer for use by opengl every time drawVertices() is called. glGenBuffers() is used only once when the corresponding object name is 0 meaning that an used object name has not yet been assigned to the vbo.
GLuint drawVertices(SDL_Window *window, GLuint vbo, Vertex *vertices, GLsizei numVertices, SDL_Color rgb, int mode){
float col[4] = { (float)rgb.r/255, (float)rgb.g/255, (float)rgb.b/255, 1.0 };
// Get an available object name for glBindBuffer() when object name is ZERO
if (!vbo){ glGenBuffers(1, &vbo); }
// Check for problems
GLenum err = glGetError();
// Deal with errors
if (err != GL_NO_ERROR) {
// Failed
glDeleteBuffers(1, &vbo);
SDL_Log("Creating VBO failed, code %u\n", err);
vbo = 0;
}
else if (!vbo) {
// Failed. Error message has already been printed, so just quit
return (GLuint)NULL;
}
if (mode & CLEAR){
// Set color of the clear operation
glClearColor(0.0, 0.0, 0.0, 1.0);
// Clears the invisible buffer
glClear(GL_COLOR_BUFFER_BIT);
}
if (mode & RENDER){
// Dissable blending when drawing lines
glDisable(GL_BLEND);
// Set up for rendering the triangle (activate the vbo)
// Position is vertex attribute 0
GLuint attribute_coord = 0;
// Specifies the index of the generic vertex attribute and enables it
glEnableVertexAttribArray(attribute_coord);
// Set the buffer to be used from now on
glBindBuffer(GL_ARRAY_BUFFER, vbo);
// Define an array of generic vertex attribute data
glVertexAttribPointer(attribute_coord, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*)0);
// Get the location of the uniform variable "color_loc"
GLuint color_loc = glGetUniformLocation( shaderProg, "color" );
// Set the value of the uniform variable "color_loc" to array "col"
glUniform4fv( color_loc, 1, col);
// Copy vertices into buffer
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * numVertices, vertices, GL_STATIC_DRAW);
// Now draw!
// GL_POINTS = Draw only the pixels that correspond to the vertices coordinates
// GL_LINE_STRIP = Draw line that connects the vertices coordinates
// GL_LINE_LOOP = Draw line that connects the vertices coordinates plus a line that re-connects the last coordinate with the first
// GL_TRIANGLE_FAN =
glDrawArrays(GL_LINE_STRIP, 0, numVertices);
}
// Don’t forget to flip the buffers as well, to display the final image:
// Update the window
if (mode & UPDATE){ SDL_GL_SwapWindow(window); }
return vbo;
}
Things work pretty much the same way for function glRenderText()
// render_text is called by glRenderText()
void render_text(const char *text, float x, float y, float sx, float sy) {
const char *p;
FT_GlyphSlot g = face->glyph;
//SDL_Log("Debug info: glyph w: %d, glyph rows: %d", g->bitmap.width, g->bitmap.rows);
for(p = text; *p; p++) {
// If FT_Load_Char() returns a non-zero value then the glyph in *p could not be loaded
if(FT_Load_Char(face, *p, FT_LOAD_RENDER)){ continue; }
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RED,
g->bitmap.width,
g->bitmap.rows,
0,
GL_RED,
GL_UNSIGNED_BYTE,
g->bitmap.buffer
);
float x2 = x + g->bitmap_left * sx;
float y2 = -y - g->bitmap_top * sy;
float w = g->bitmap.width * sx;
float h = g->bitmap.rows * sy;
GLfloat box[4][4] = {
{x2, -y2 , 0, 0},
{x2 + w, -y2 , 1, 0},
{x2, -y2 - h, 0, 1},
{x2 + w, -y2 - h, 1, 1},
};
glBufferData(GL_ARRAY_BUFFER, sizeof box, box, GL_DYNAMIC_DRAW);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
x += (g->advance.x>>6) * sx;
y += (g->advance.y>>6) * sy;
}
}
GLuint glRenderText(char *text, int fontSize, GLuint vbo, int _x, int _y, SDL_Color rgb, int mode) {
float x = _x;
float y = _y;
float xMax = 2.0 / (float)getWindowWidth();
float yMax = 2.0 / (float)getWindowHeight();
GLuint attribute_coord=0;
float col[4] = { (float)rgb.r/255, (float)rgb.g/255, (float)rgb.b/255, 1 };
// Enable blending when drawing fonts
glEnable(GL_BLEND);
// Set the W & H of the font loaded
FT_Set_Pixel_Sizes(face, 0, fontSize);
// If vbo is ZERO setup and get an object name
if (!vbo){
// Enables blending operations
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// Set texture parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Specifies the alignment requirements for the start of each pixel row in memory
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// Save into vbo one unused buffer name (index) for use with glBindBuffer
glGenBuffers(1, &vbo);
// Specifies the index of the generic vertex attribute and enables it
glEnableVertexAttribArray(attribute_coord);
}
// Set the buffer to be used from now on to the one indicated by vbo
glBindBuffer(GL_ARRAY_BUFFER, vbo);
// Define an array of generic vertex attribute data
glVertexAttribPointer(attribute_coord, 4, GL_FLOAT, GL_FALSE, 0, 0);
GLuint color_loc = glGetUniformLocation( shaderProg, "color" );
// Set the value of the uniform variable "color_loc" from array "col"
glUniform4fv( color_loc, 1, col);
// Clear invisible buffer
if (mode & CLEAR){
glClearColor(0.0, 0.0, 0.0, 1);
glClear(GL_COLOR_BUFFER_BIT);
}
// If coordinate system required is:
// COORD_SYS_CONVENTIONAL = (1) left bottom corner is 0,0 and moving towards right and top sides we reach max screen size in pixels e.g 1024 * 768 pixels
// COORD_SYS_CARTECIAN = (2) left bottom corner is -1,-1 and moving towards right and top sides we reach +1,+1 . The center of the display is always 0,0
if (mode & ~COORD_SYS_CARTECIAN){
x = (_x * xMax)-1;
y = (_y * yMax)-1;
}
// Draw the text on the invisible buffer
if (mode & RENDER){ render_text(text, x, y, xMax, yMax); }
// Update display
if (mode & UPDATE){ SDL_GL_SwapWindow(SDLmain.window); }
return vbo;
}
The logic is that 2 vbos (one for drawing line through drawVertices and one for drawing fonts through glRenderText()) are defined in main() or in the global scope and are passed to glRenderText() & drawVertices() . These two functions update the values of their local copies and return the vbos so that the vbo in main or in the global scope get updated. That off course could be done by passing them entirely by reference instead of adopting my approach.
I have not yet tested the functionality in my raspi3 though. I will get back real soon with an update. Anyway, the functions given above are fully functional.
Thanks again for your time.
来源:https://stackoverflow.com/questions/50982640/font-rendering-freetype-with-opengl-es-2-0-combined-with-other-line-drawing-fu