freetype 2 و opengl كتابة النص

لقد حان الوقت وأنا أحسب freetype2. الآن أريد أن أجعل الكود متاحًا للمحتاجين. لأن كيفية التفكير في كيفية العمل مع المكتبة ، ليس هناك وقت دائمًا. أريد أن أعرض رمز العمل مع freetype وقليلا مع opengl. قليلا عن الرمز. لا أستطيع إنشاء رمز معقد. كل شيء اتضح بسيط نوعا ما بالنسبة لي. لقد رأيت عدة أجزاء من التعليمات البرمجية تعمل مع freetype2 ، ولم أستطع فهم كيف تعمل في الواقع. بالفعل تم إنشاء رمز معقد للغاية من قبل المؤلفين. آمل أن تكونوا مثل بلدي رمز بسيط. بعد قراءة هذه المقالة ، يمكنك إنشاء نص متعدد الأسطر وعرضه كنسيج واحد على الشاشة.

لذلك دعونا نبدأ.

أول شيء أود أن أكتب هنا هو التظليل الذي كتبته من الكتاب. يفرض نسيجًا ثنائي الأبعاد على عدة مثلثات.

لإنشاء تظليل ، لدي فصل منفصل. أنا أكتب إليه الذي تظليل لتجميعه ويعيد البرنامج لي. يضيف أيضًا برنامج بالاسم إلى حاوية std :: map ، حتى أتمكن من الحصول على برنامج التظليل المعين هذا في قسم آخر من الكود.

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; 

بعد ذلك ، قمت بإنشاء فئة الخط. سيقوم كائن من هذه الفئة بتهيئة النص ، والإشارة إلى موضع على الشاشة ، ورسم نسيج.

 #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 

حسنا ، الطبقة جاهزة. الآن لنبدأ. أنا صنع لعبة على الروبوت مع sdl2 واختبار على جهاز الكمبيوتر. لذلك ، أعرف طريقة واحدة لعرض البيانات على الشاشة باستخدام gles2 و opengl.

لذلك دعونا نبدأ.

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

من الرمز ، يمكنك استدعاء هذه الوظيفة مثل هذا.

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

الصورة

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


All Articles