freetype 2 dan opengl menulis teks

Sudah saatnya saya menemukan freetype2. Sekarang saya ingin membuat kode saya tersedia untuk mereka yang membutuhkan. Karena cara berpikir tentang cara bekerja dengan perpustakaan, tidak selalu ada waktu. Saya ingin menunjukkan kode kerja dengan freetype dan sedikit dengan OpenGL. Sedikit tentang kodenya. Saya tidak dapat membuat kode yang rumit. Segalanya ternyata sederhana bagi saya. Saya melihat beberapa bagian kode bekerja dengan freetype2, dan tidak bisa mengerti bagaimana cara kerjanya. Sudah kode yang sangat kompleks dibuat oleh penulis. Saya harap Anda menyukai kode sederhana saya. Setelah membaca artikel ini, Anda dapat membuat teks multi-baris dan menampilkannya sebagai tekstur tunggal pada layar.

Jadi mari kita mulai.

Hal pertama yang ingin saya tulis di sini adalah shader yang saya tulis di buku. Ini memaksakan tekstur dua dimensi pada beberapa segitiga.

Untuk membuat shader, saya memiliki kelas yang terpisah. Saya menulis kepadanya mana shader untuk dikompilasi dan dia mengembalikan program kepada saya. Dia juga menambahkan program dengan nama ke wadah std :: map, sehingga saya bisa mendapatkan program shader khusus ini di bagian lain dari kode.

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; 

Selanjutnya, saya membuat kelas font. Objek kelas ini akan menginisialisasi teks, menunjukkan posisi di layar, dan menggambar tekstur.

 #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 

Nah, kelasnya sudah siap. Sekarang mari kita mulai. Saya membuat game di android dengan sdl2 dan pengujian di pc. Oleh karena itu, saya tahu satu cara tunggal untuk menampilkan data di layar menggunakan gles2 dan opengl.

Jadi mari kita mulai.

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

Dari kode, Anda dapat memanggil fungsi ini seperti ini.

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

gambar

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


All Articles