freetype 2 et opengl écrire du texte

Il est temps que je trouve freetype2. Maintenant, je veux mettre mon code à la disposition de ceux qui en ont besoin. Parce que comment penser à la façon de travailler avec la bibliothèque, il n'y a pas toujours le temps. Je veux montrer le code de travail avec freetype et un peu avec opengl. Un peu sur le code. Je ne peux pas créer de code complexe. Tout se révèle en quelque sorte simple pour moi. J'ai vu plusieurs morceaux de code travailler avec freetype2 et je ne pouvais pas comprendre comment cela fonctionnait réellement. Déjà un code très complexe a été créé par les auteurs. J'espère que vous aimez mon code simple. Après avoir lu cet article, vous pouvez créer du texte sur plusieurs lignes et l'afficher comme une seule texture à l'écran.

Commençons donc.

La première chose que je voudrais écrire ici est le shader que j'ai écrit à partir du livre. Il impose une texture bidimensionnelle sur plusieurs triangles.

Pour créer des shaders, j'ai une classe séparée. Je lui écris le shader à compiler et il me rend le programme. Il ajoute également un programme par nom au conteneur std :: map, afin que je puisse obtenir le programme de ce shader particulier dans une autre section du code.

GLuint ShaderManager::createProgram ( const char *param ) { if ( !strncmp ( param, "sprite\0",7 ) ) { const char *vshader = "#version 300 es\n" "layout(location = 0) in vec2 position;\n" "layout(location = 1) in vec2 texCoord;\n" "uniform mat4 transform;\n" "out vec2 v_texCoord;\n" "void main ( )\n" "{\n" " gl_Position = transform * vec4 ( position, 0.0, 1.0 );\n" " v_texCoord = texCoord;\n" "}"; const char *fshader = "#version 300 es\n" "precision mediump float;\n" "in vec2 v_texCoord;\n" "layout(location = 0) out vec4 outColor;\n" "uniform sampler2D s_texture;\n" "void main ( )\n" "{\n" " outColor = texture ( s_texture, v_texCoord );\n" "}"; /*   */ GLuint program = loadProgram ( vshader, fshader ); /*     */ global.programs["sprite"] = program; return program; 

Ensuite, j'ai créé une classe de polices. Un objet de cette classe initialisera le texte, indiquera une position sur l'écran et dessinera une texture.

 #ifndef H_FONT_H #define H_FONT_H #include <stdint.h> #include <ft2build.h> #include <string> #include <vector> #include <SDL2/SDL_opengl.h> #include <SDL2/SDL_opengles2.h> #include "gl_mat.hpp" #include "global.hpp" #include <wchar.h> #include FT_FREETYPE_H #include FT_GLYPH_H class Font { public: Font ( ) { } /*   freetype   ttf . */ Font ( const char *ttf_file ); /*     */ void setPos ( int x, int y ); /*    .   *\1     . *\2  . *\3       . *\4       . *\5    . *\6   . *\7   . *\8   . *          */ void init ( wchar_t *text, int fontSize, int align, int valign, int space, uint8_t r, uint8_t g, uint8_t b ); /*    */ void setSize ( int w, int h ); /*   */ void draw ( ); private: FT_Face face = 0; /*    */ float *texture; /*    */ float *vertices; /*    :  */ int width; /*    :  */ int height; /*     */ int sampler; /* id  */ GLuint textureid; /*  x */ int x; /*  y */ int y; /*    glOrtho */ float ortho[4][4]; /*      */ float translate[4][4]; /*    */ float result[4][4]; /*   */ unsigned int program; FT_Library ft_library; FT_Face ttf; }; #endif 

Eh bien, le cours est prêt. Commençons maintenant. Je fais un jeu sur android avec sdl2 et je teste sur pc. Par conséquent, je connais une seule façon d'afficher des données à l'écran en utilisant gles2 et opengl.

Commençons donc.

 #include "font.hpp" Font::Font ( const char *ttf_file ) { /*        *       android,    cpp  glm. *   ,           *        */ glm::clearMatrix4x4 ( &ortho[0] ); glm::clearMatrix4x4 ( &translate[0] ); glm::clearMatrix4x4 ( &result[0] ); /*       */ program = global.programs["sprite"]; /*       ,     */ int width = global.width; int height = global.height; /*     ,       *  2d  */ glm::ortho ( &ortho[0], 0.0f, width, 0.0f, height, 0.0f, 1.0f ); /*     */ setPos ( 0, 0 ); /*   freetype2. */ FT_Init_FreeType( &ft_library ); /*     */ #ifdef __ANDROID__ FT_NewFace ( ft_library, ttf_file, 0, &face ); #else char *path = (char *) new char[255]; sprintf ( path, "assets/%s", ttf_file ); FT_New_Face ( ft_library, path, 0, &face ); delete[] path; #endif } /*      */ void Font::init ( wchar_t *es, int fontSize, int align, int vert, int space, uint8_t r, uint8_t g, uint8_t b ) { /*      */ FT_Set_Pixel_Sizes ( face, 0, fontSize ); FT_Glyph glyph; int w = 0; unsigned int h = 0; unsigned int maxh = 0; unsigned int toprow = 0; /*        ,     *    i,     . */ int len = wcslen ( es ); /*           ,    *         .     .  *    */ for ( int i = 0; i < len; i++ ) { /*    */ wchar_t charcode = es[i]; /*       bitmap  */ FT_Load_Char ( face, charcode, FT_LOAD_RENDER ); FT_UInt glyph_index = FT_Get_Char_Index ( face, charcode ) FT_Load_Glyph ( face, glyph_index, FT_LOAD_DEFAULT ); FT_Render_Glyph ( face->glyph, FT_RENDER_MODE_NORMAL ); FT_Get_Glyph ( face->glyph, &glyph ); FT_Glyph_To_Bitmap ( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 ); FT_BitmapGlyph bitmap_glyph = (FT_BitmapGlyph) glyph; FT_Bitmap bitmap = bitmap_glyph->bitmap; /*      */ w += bitmap.width; /*        . */ int resize = bitmap.rows > bitmap_glyph->top ? bitmap.rows - bitmap_glyph->top : bitmap_glyph->top - bitmap.rows; /*         */ if ( h < bitmap.rows + resize ) h = bitmap.rows + resize; /*        */ if ( toprow < bitmap.rows ) toprow = bitmap.rows; if ( maxh < bitmap.rows + bitmap_glyph->top ) maxh = bitmap.rows + bitmap_glyph->top; /*    ,   w   ,    *  */ if ( charcode == ' ' ) w += space; /*    ' ' *           */ if ( charcode == '\n' ) { h += vert + maxh; FT_Done_Glyph ( glyph ); continue; } /*    ,  align   ,     */ w += align; FT_Done_Glyph ( glyph ); } /*      , *        */ if ( h <= 0 ) h = maxh; uint8_t im[h][w]; /*    */ memset ( &im[0][0], 0, w * h * sizeof ( uint8_t ) ); int ih = 0; int iw = 0; int posy = 0; int topy = 0; int maxwidth = 0; for ( int i = 0; i < len; i++ ) { wchar_t charcode = es[i]; FT_Load_Char ( face, charcode, FT_LOAD_RENDER ); FT_UInt glyph_index = FT_Get_Char_Index ( face, charcode ); FT_Load_Glyph ( face, glyph_index, FT_LOAD_DEFAULT ); FT_Render_Glyph ( face->glyph, FT_RENDER_MODE_NORMAL ); FT_Get_Glyph ( face->glyph, &glyph ); FT_Glyph_To_Bitmap ( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 ); FT_BitmapGlyph bitmap_glyph = (FT_BitmapGlyph) glyph; FT_Bitmap bitmap = bitmap_glyph->bitmap; /*      */ posy = bitmap_glyph->top; /*   ,       */ posy = bitmap.rows - posy; topy = toprow - bitmap.rows; /*   ,  ih -    ,     , *   */ if ( charcode == '\n' ) { ih += maxh; iw = 0; FT_Done_Glyph ( glyph ); continue; } for ( unsigned int y = 0, i = 0; y < bitmap.rows; y++ ) { for ( unsigned int x = 0; x < bitmap.width; x++, i++ ) { if ( ( ih + posy + y + topy ) > h ) { if ( posy < 0 ) posy = abs ( posy ); } /*         *      gray,       */ im [ ih + posy + y + topy ] [ iw + x ] = bitmap.buffer[i]; } } /*   */ iw += bitmap.width; /*     */ iw += align; if ( maxwidth < iw ) maxwidth = iw; if ( charcode == ' ' ) { iw += space; } FT_Done_Glyph ( glyph ); } iw = maxwidth; width = iw; height = h; unsigned int size = width * height; /*       */ uint8_t *image_data = new uint8_t [ size * 4 ]; /*      */ memset ( image_data, 255, size * 4 * sizeof ( uint8_t ) ); for ( unsigned int i = 0, y = 0; i < size; y++ ) { for ( int x = 0; x < width; x++, i++ ) { /*          */ image_data[ 4 * i + 3] = im [ y ][ x ]; /*    */ image_data[ 4 * i + 0] = r; image_data[ 4 * i + 1] = g; image_data[ 4 * i + 2] = b; } } /*      */ glGenTextures ( 1, &textureid ); glBindTexture ( GL_TEXTURE_2D, textureid ); glTexImage2D ( GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data ); 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); /*      */ setSize ( width, height ); /*   ,       image_data   . */ delete[] image_data; } void Font::setSize ( int w, int h ) { /*   ,       ,     */ if ( vertices ) delete[] vertices; if ( texture ) delete[] texture; vertices = new float [ 12 ]; vertices[0] = 0; vertices[1] = 0; vertices[2] = 0; vertices[3] = h; vertices[4] = w; vertices[5] = 0; vertices[6] = w; vertices[7] = 0; vertices[8] = w; vertices[9] = h; vertices[10] = 0; vertices[11] = h; /*        ,       *  */ texture = new float [ 12 ]; texture[0] = 0; texture[1] = 1; texture[2] = 0; texture[3] = 0; texture[4] = 1; texture[5] = 1; texture[6] = 1; texture[7] = 1; texture[8] = 1; texture[9] = 0; texture[10] = 0; texture[11] = 0; } void Font::setPos ( int x, int y ) { /*    ,    */ this->x = x; this->y = y; glm::translate ( &translate[0], x, y, 0 ); glm::sumMatrix ( &result[0], &translate[0], &ortho[0] ); } void Font::draw ( ) { /*      */ glUseProgram ( program ); sampler = glGetUniformLocation ( program, "s_texture" ); glActiveTexture ( GL_TEXTURE0 ); glBindTexture ( GL_TEXTURE_2D, textureid ); glUniform1i ( sampler, 0 ); GLint projection_location = glGetUniformLocation ( program, "transform" ); glUniformMatrix4fv ( projection_location, 1, GL_FALSE, &result[0][0] ); glEnableVertexAttribArray ( 0 ); glEnableVertexAttribArray ( 1 ); /*     */ glVertexAttribPointer ( 0, 2, GL_FLOAT, GL_FALSE, 0, vertices ); /*     */ glVertexAttribPointer ( 1, 2, GL_FLOAT, GL_FALSE, 0, texture ); /*    */ glDrawArrays ( GL_TRIANGLES, 0, 12 ); glDisableVertexAttribArray ( 0 ); glDisableVertexAttribArray ( 1 ); } 

A partir du code, vous pouvez appeler cette fonction comme ceci.

  Font *font = new Font ("anonymous.ttf"); wchar_t * text = L" habr.    .   freetype  opengl.\n" "  freetype   .\n" "    ,       "; font->init ( text, 21, 1, 4, 4, 0, 0, 0 ); font->setPos ( 100, 100 ); 

image

Source: https://habr.com/ru/post/fr441986/


All Articles