Отрисовка шрифтов (Freetype) с помощью openGL ES 2.0 в сочетании с другими функциями рисования линии не работает

Этот stream связан с https: //stackoverflow.com/questions/50955558/render-fonts-with-sdl2-opengl-es-2-0-glsl-1-0-freetype

У меня есть проблема, сочетающая рендеринг шрифтов и использование этой функции следующим образом:

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

Эта функция использует glDrawArrays () для рисования серии строк, соединяющих предоставленные вершины. Флаги CLEAR, RENDER & UPDATE используются, чтобы позволить мне сделать что-то вроде:

 drawVertices(window, vertices, sizeOfVertices, CLEAR | RENDER); drawVertices(window, vertices, sizeOfVertices, RENDER); drawVertices(window, vertices, sizeOfVertices, RENDER | UPDATE); 

Я сделал то же самое с функцией рендеринга шрифтов, что позволило мне рисовать несколько строк в разных координатах x, y. Следующие две функции выполняют рендеринг шрифтов на основе кода, представленного на первом месте, и, конечно же, ваших исправлений.

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

Поэтому я могу:

  glRenderText(tmp, 0, 0, Olive, CLEAR | RENDER | UPDATE); glRenderText(tmp, 0, 150, Yellow_Green, RENDER); glRenderText(tmp, 0, 300, Light_Coral, RENDER | UPDATE); 

Оказывается, я могу либо отображать шрифты в разных координатах x, y, либо использовать функцию drawVertices для визуализации строк, соединяющих эти вершины, но не обоих. То есть я не могу этого сделать:

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

Как вы можете сказать, логика заключается в том, что в обеих функциях вам нужно просто с помощью CLEAR | RENDER, тогда сделайте только RENDER, и при последнем вызове для обеих функций используйте RENDER | ОБНОВИТЬ.

ПРОБЛЕМЫ:

(1) В моей попытке сделать предыдущее, то есть, комбинация glRenderText () + drawVertices () я потерпел неудачу, потому что есть что-то, что нужно настроить, прежде чем вызывать их один за другим.

(2) Еще одна проблема, с которой я столкнулся, заключается в том, что запуск кода на моем raspi3 привел к тому, что drawVertices () отлично работает, когда дело доходит до шрифтов, я мог видеть только эффект glClearColor () и glClear (GL_COLOR_BUFFER_BIT), что означает, что дисплей был очищен установкой цвета с помощью glClearColor (), но визуализации шрифтов не было видно. Я попробовал оба режима драйвера GL. Существует один драйвер FULL KMS GL, а другой – драйвер FAKE KMS GL.

Кроме того, для работы drawVertices () я должен был прокомментировать приведенный ниже код:

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

Мне все еще нужно было сохранить следующий код:

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

Основная проблема заключается в том, что программа шейдеров, которая используется для визуализации текста, по-прежнему активна (текущее состояние отображения), когда линии рисуются drawVertices() . Для этой шейдерной программы требуются текстурные координаты и текстура.

Вы не создаете никаких текстурных координат при рисовании линий, и не имеет смысла использовать текстуру с глифами шрифта при рендеринге линий.

Создайте второй очень простой шейдер, который вы можете использовать для рисования линий:

Vertex shader: shader_line.vert

 #version 100 attribute vec2 coord; void main(void) { gl_Position = vec4(coord.xy, 0, 1); } 

Фрагментный шейдер: shader_line.frag

 #version 100 #ifdef GL_ES precision highp float; #endif uniform vec4 color; void main(void) { gl_FragColor = color; } 

Создайте шейдерную программу:

 GLuint shaderProg_line = shaderProgLoad("shader_line.vert", "shader_line.frag"); GLuint line_color_loc = glGetUniformLocation( shaderProg_line, "color" ); 

Переключите текущую программу из «текстовой» шейдерной программы, в «шейдерную» программу линии, после рендеринга текста и перед визуализацией строк:

 lUseProgram( shaderProg ); // "text" shader glRenderText(tmp, 0, 0, Olive, CLEAR | RENDER); ..... glUseProgram( shaderProg_line ); // "line" shader float col[4] = { 1.0f, 0.0f, 0.0f, 1.0f }; glUniform4fv( line_color_loc, 1, col ); // set uniform "color" of the "line" shader drawVertices(window, vertices, sizeOfVertices, RENDER); ..... 

я смог решить проблему, перепродав почти все, что не является общим для двух операций (glRenderText () & drawVertices ()). Следующий код остается таким же, как и до вызова любой из двух функций () glRenderText () & drawVertices ( )). Эти две функции были обновлены, чтобы выполнить правильный сброс до достижения точки, где выполняется glDrawArrays ()

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

Это обновленная функция, которая сбрасывает некоторые параметры, чтобы мы получили нужный нам результат. Например, glDisable (GL_BLEND); используется для отключения смешивания, когда дело доходит до линий рисования. Самое главное, что я использую glBindBuffer () для установки соответствующего буфера для использования opengl каждый раз, когда вызывается drawVertices (). glGenBuffers () используется только один раз, когда соответствующее имя объекта равно 0, что означает, что имя используемого объекта еще не было присвоено 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; } 

Вещи работают почти так же, как функция 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 eg 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; } 

Логика заключается в том, что 2 vbos (один для рисования линии через drawVertices и один для рисования шрифтов через glRenderText ()) определены в main () или в глобальной области и передаются в glRenderText () & drawVertices (). Эти две функции обновляют значения своих локальных копий и возвращают vbos, чтобы обновить vbo в основной или глобальной области. Этот курс можно было бы сделать, передав их полностью по ссылке вместо того, чтобы принять мой подход.

Тем не менее, я еще не тестировал функциональность в своем raspi3. Я скоро вернусь с обновлением. Во всяком случае, приведенные выше функции полностью функциональны.

Еще раз спасибо за ваше время.