zoukankan      html  css  js  c++  java
  • 【OpenGL】使用FreeType库加载字体并在GL中绘制文字

    FreeType用起来比较麻烦,这里写了一份简单的示例代码,仅供参考。

    实现了FT库生成字符位图,并上传到GL纹理。

    实现了字符位图缓存功能,多个字符图像保存在同一个纹理中。

    实现了简单的字体管理框架。

    实现了简单的加粗和倾斜效果。

    实现了反锯齿开关,并且兼容加粗倾斜效果。

    代码如下:

      1 // OpenGL library
      2 #include <gl/glut.h>
      3 
      4 // Std misc
      5 #include <map>
      6 #include <vector>
      7 
      8 // FreeType library
      9 #include <ft2build.h>
     10 #include FT_FREETYPE_H
     11 #include FT_BITMAP_H
     12 #include FT_OUTLINE_H
     13 
     14 
     15 #ifdef CreateFont
     16 #undef CreateFont
     17 #endif
     18 
     19 typedef unsigned char byte;
     20 
     21 class CFontManager
     22 {
     23 public:
     24     CFontManager();
     25     ~CFontManager();
     26 
     27     bool initialize(void);
     28     void release(void);
     29     int createFont(const char *filename, int face, int tall, bool bold, bool italic, bool antialias);
     30     bool getCharInfo(int font_index, int code, int *wide, int *tall, int *horiBearingX, int *horiBearingY, int *horiAdvance, GLuint *texture, float coords[]);
     31     int getFontTall(int font_index);
     32 
     33 private:
     34     struct glyphMetrics
     35     {
     36         int    width;
     37         int    height;
     38         int    horiBearingX;
     39         int    horiBearingY;
     40         int    horiAdvance;
     41         //int    vertBearingX;
     42         //int    vertBearingY;
     43         //int    vertAdvance;
     44     };
     45 
     46     class CFont
     47     {
     48     public:
     49         CFont();
     50         ~CFont();
     51 
     52         bool create(FT_Library library, const char *filename, FT_Long face_index, int tall, bool bold, bool italic, bool antialias);
     53         void release(void);
     54         bool getCharInfo(int code, glyphMetrics *metrics, GLuint *texture, float coords[]);
     55         int getFontTall(void);
     56 
     57     private:
     58         bool loadChar(int code, glyphMetrics *metrics);
     59 
     60         class CChar
     61         {
     62         public:
     63             void setInfo(glyphMetrics *metrics);
     64             void getInfo(glyphMetrics *metrics, GLuint *texture, float coords[]);
     65 
     66         public:
     67             int                m_code;
     68             GLuint            m_texture;
     69             float            m_coords[4];    // left top right bottom
     70 
     71         private:
     72             glyphMetrics    m_metrics;
     73         };
     74 
     75         class CPage
     76         {
     77         public:
     78             CPage();
     79             ~CPage();
     80 
     81             bool append(int wide, int tall, byte *rgba, float coords[]);
     82             GLuint getTexture(void);
     83 
     84         private:
     85             GLuint    m_texture;
     86             int        m_wide;
     87             int        m_tall;
     88             int        m_posx;
     89             int        m_posy;
     90             int        m_maxCharTall;
     91         };
     92 
     93         typedef std::map<int, CChar *> TCharMap;
     94 
     95         FT_Library                m_library;
     96         FT_Face                    m_face;
     97         bool                    m_antialias;
     98         bool                    m_bold;
     99         int                        m_tall;
    100         int                        m_rgbaSize;
    101         GLubyte                    *m_rgba;
    102         TCharMap                m_chars;
    103         std::vector<CPage *>    m_pages;
    104     };
    105 
    106     FT_Library                m_library;
    107     std::vector<CFont *>    m_fonts;
    108 };
    109 
    110 
    111 
    112 //------------------------------------------------------------
    113 // CFont
    114 //------------------------------------------------------------
    115 CFontManager::CFont::CFont()
    116 {
    117     m_face = NULL;
    118     m_rgba = NULL;
    119     m_antialias = false;
    120     m_bold = false;
    121     m_tall = 0;
    122 }
    123 
    124 CFontManager::CFont::~CFont()
    125 {
    126     release();
    127 }
    128 
    129 bool CFontManager::CFont::create(FT_Library library, const char *filename, FT_Long face_index, int tall, bool bold, bool italic, bool antialias)
    130 {
    131     FT_Error err;
    132 
    133     if (tall > 256)
    134     {
    135         // Bigger than a page size
    136         return false;
    137     }
    138 
    139     if ((err = FT_New_Face(library, filename, face_index, &m_face)) != FT_Err_Ok)
    140     {
    141         printf("FT_New_Face() Error %d
    ", err);
    142         return false;
    143     }
    144 
    145     if ((err = FT_Set_Pixel_Sizes(m_face, 0, tall)) != FT_Err_Ok)
    146     {
    147         printf("FT_Set_Pixel_Sizes() Error %d
    ", err);
    148         return false;
    149     }
    150 
    151     m_rgbaSize = (tall * 2) * tall * 4;
    152 
    153     m_rgba = new GLubyte[m_rgbaSize];
    154 
    155     if (m_rgba == NULL)
    156     {
    157         return false;
    158     }
    159 
    160     m_library = library;
    161     m_antialias = antialias;
    162     m_bold = bold;
    163     m_tall = tall;
    164 
    165     if (italic)
    166     {
    167         FT_Matrix m;
    168         m.xx = 0x10000L;
    169         m.xy = 0.5f * 0x10000L;
    170         m.yx = 0;
    171         m.yy = 0x10000L;
    172         FT_Set_Transform(m_face, &m, NULL);
    173     }
    174 
    175     return true;
    176 }
    177 
    178 void CFontManager::CFont::release(void)
    179 {
    180     FT_Error err;
    181 
    182     if (m_face)
    183     {
    184         if ((err = FT_Done_Face(m_face)) != FT_Err_Ok)
    185         {
    186             printf("FT_Done_Face() Error %d
    ", err);
    187         }
    188         m_face = NULL;
    189     }
    190 
    191     if (m_rgba)
    192     {
    193         delete[] m_rgba;
    194         m_rgba = NULL;
    195     }
    196 
    197     for (TCharMap::iterator it = m_chars.begin(); it != m_chars.end(); it++)
    198     {
    199         delete it->second;
    200         it->second = NULL;
    201     }
    202 
    203     m_chars.clear();
    204 
    205     for (size_t i = 0; i < m_pages.size(); i++)
    206     {
    207         delete m_pages[i];
    208         m_pages[i] = NULL;
    209     }
    210 
    211     m_pages.clear();
    212 }
    213 
    214 bool CFontManager::CFont::getCharInfo(int code, glyphMetrics *metrics, GLuint *texture, float coords[])
    215 {
    216     // fast find it
    217     TCharMap::iterator it = m_chars.find(code);
    218 
    219     if (it != m_chars.end())
    220     {
    221         it->second->getInfo(metrics, texture, coords);
    222         return true;
    223     }
    224 
    225     glyphMetrics gm;
    226 
    227     if (loadChar(code, &gm) == false)
    228     {
    229         return false;
    230     }
    231 
    232     CChar *ch = new CChar();
    233 
    234     ch->m_code = code;
    235     ch->setInfo(&gm);
    236 
    237     for (size_t i = 0; i < m_pages.size(); i++)
    238     {
    239         CPage *page = m_pages[i];
    240 
    241         if (page->append(gm.width, gm.height, m_rgba, ch->m_coords))
    242         {
    243             ch->m_texture = page->getTexture();
    244             ch->getInfo(metrics, texture, coords);
    245             m_chars.insert(TCharMap::value_type(code, ch));
    246             return true;
    247         }
    248     }
    249 
    250     CPage *page = new CPage();
    251 
    252     if (page->append(gm.width, gm.height, m_rgba, ch->m_coords))
    253     {
    254         ch->m_texture = page->getTexture();
    255         ch->getInfo(metrics, texture, coords);
    256         m_chars.insert(TCharMap::value_type(code, ch));
    257         m_pages.push_back(page);
    258         return true;
    259     }
    260 
    261     delete ch;
    262     delete page;
    263 
    264     return false;
    265 }
    266 
    267 int CFontManager::CFont::getFontTall(void)
    268 {
    269     return m_tall;
    270 }
    271 
    272 // bitmap.width  位图宽度
    273 // bitmap.rows   位图行数(高度)
    274 // bitmap.pitch  位图一行占用的字节数
    275 
    276 //MONO模式每1个像素仅用1bit保存,只有黑和白。
    277 //1个byte可以保存8个像素,1个int可以保存8*4个像素。
    278 void ConvertMONOToRGBA(FT_Bitmap *source, GLubyte *rgba)
    279 {
    280     GLubyte *s = source->buffer;
    281     GLubyte *t = rgba;
    282 
    283     for (GLuint y = source->rows; y > 0; y--)
    284     {
    285         GLubyte *ss = s;
    286         GLubyte *tt = t;
    287 
    288         for (GLuint x = source->width >> 3; x > 0; x--)
    289         {
    290             GLuint val = *ss;
    291 
    292             for (GLuint i = 8; i > 0; i--)
    293             {
    294                 tt[0] = tt[1] = tt[2] = tt[3] = ( val & (1<<(i-1)) ) ? 0xFF : 0x00;
    295                 tt += 4;
    296             }
    297 
    298             ss += 1;
    299         }
    300 
    301         GLuint rem = source->width & 7;
    302 
    303         if (rem > 0)
    304         {
    305             GLuint val = *ss;
    306 
    307             for (GLuint x = rem; x > 0; x--)
    308             {
    309                 tt[0] = tt[1] = tt[2] = tt[3] = ( val & 0x80 ) ? 0xFF : 0x00;
    310                 tt += 4;
    311                 val <<= 1;
    312             }
    313         }
    314 
    315         s += source->pitch;
    316         t += source->width * 4;    //pitch
    317     }
    318 }
    319 
    320 //GRAY模式1个像素用1个字节保存。
    321 void ConvertGRAYToRGBA(FT_Bitmap *source, GLubyte *rgba)
    322 {
    323     for (GLuint y = 0; y < source->rows; y++)
    324     {
    325         for (GLuint x = 0; x < source->width; x++)
    326         {
    327             GLubyte *s = &source->buffer[(y * source->pitch) + x];
    328             GLubyte *t = &rgba[((y * source->pitch) + x) * 4];
    329 
    330             t[0] = t[1] = t[2] = 0xFF;
    331             t[3] = *s;
    332         }
    333     }
    334 }
    335 
    336 bool CFontManager::CFont::loadChar(int code, glyphMetrics *metrics)
    337 {
    338     FT_Error err;
    339 
    340     FT_UInt glyph_index = FT_Get_Char_Index(m_face, (FT_ULong)code);
    341 
    342     if (glyph_index > 0)
    343     {
    344         if ((err = FT_Load_Glyph(m_face, glyph_index, FT_LOAD_DEFAULT)) == FT_Err_Ok)
    345         {
    346             FT_GlyphSlot glyph = m_face->glyph;
    347 
    348             FT_Render_Mode render_mode = m_antialias ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO;
    349 
    350             if (m_antialias && m_bold)
    351             {
    352                 if ((err = FT_Outline_EmboldenXY(&glyph->outline, 60, 60)) != FT_Err_Ok)
    353                 {
    354                     printf("FT_Outline_EmboldenXY() Error %d
    ", err);
    355                 }
    356             }
    357 
    358             if ((err = FT_Render_Glyph(glyph, render_mode)) == FT_Err_Ok)
    359             {
    360                 FT_Bitmap *bitmap = &glyph->bitmap;
    361 
    362                 switch (bitmap->pixel_mode)
    363                 {
    364                 case FT_PIXEL_MODE_MONO:
    365                     {
    366                         if (!m_antialias && m_bold)
    367                         {
    368                             if ((err = FT_Bitmap_Embolden(m_library, bitmap, 60, 0)) != FT_Err_Ok)
    369                             {
    370                                 printf("FT_Bitmap_Embolden() Error %d
    ", err);
    371                             }
    372                         }
    373                         ConvertMONOToRGBA(bitmap, m_rgba);
    374                         break;
    375                     }
    376                 case FT_PIXEL_MODE_GRAY:
    377                     {
    378                         ConvertGRAYToRGBA(bitmap, m_rgba);
    379                         break;
    380                     }
    381                 default:
    382                     {
    383                         memset(m_rgba, 0xFF, m_rgbaSize);
    384                         break;
    385                     }
    386                 }
    387 
    388                 metrics->width = bitmap->width;
    389                 metrics->height = bitmap->rows;
    390                 metrics->horiBearingX = glyph->bitmap_left;
    391                 metrics->horiBearingY = glyph->bitmap_top;
    392                 metrics->horiAdvance = glyph->advance.x >> 6;
    393 
    394                 return true;
    395             }
    396             else
    397             {
    398                 printf("FT_Render_Glyph() Error %d
    ", err);
    399             }
    400         }
    401         else
    402         {
    403             printf("FT_Load_Glyph() Error %d
    ", err);
    404         }
    405     }
    406 
    407     memset(metrics, 0, sizeof(glyphMetrics));
    408 
    409     return false;
    410 }
    411 
    412 //------------------------------------------------------------
    413 // CChar
    414 //------------------------------------------------------------
    415 void CFontManager::CFont::CChar::setInfo(glyphMetrics *metrics)
    416 {
    417     memcpy(&m_metrics, metrics, sizeof(glyphMetrics));
    418 }
    419 
    420 void CFontManager::CFont::CChar::getInfo(glyphMetrics *metrics, GLuint *texture, float coords[])
    421 {
    422     memcpy(metrics, &m_metrics, sizeof(glyphMetrics));
    423 
    424     *texture = m_texture;
    425     memcpy(coords, m_coords, sizeof(float)*4);
    426 }
    427 
    428 //------------------------------------------------------------
    429 // CPage
    430 //------------------------------------------------------------
    431 CFontManager::CFont::CPage::CPage()
    432 {
    433     m_wide = m_tall = 256;
    434     m_posx = m_posy = 0;
    435 
    436     // In a line, for a max height character
    437     m_maxCharTall = 0;
    438 
    439     glGenTextures(1, &m_texture);    // Using your API here
    440     glBindTexture(GL_TEXTURE_2D, m_texture);
    441     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_wide, m_tall, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    442     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    443     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    444 }
    445 
    446 CFontManager::CFont::CPage::~CPage()
    447 {
    448     // free the texture
    449 }
    450 
    451 bool CFontManager::CFont::CPage::append(int wide, int tall, byte *rgba, float coords[])
    452 {
    453     if (m_posy + tall > m_tall)
    454     {
    455         // not enough line space in this page
    456         return false;
    457     }
    458 
    459     // If this line is full ...
    460     if (m_posx + wide > m_wide)
    461     {
    462         int newLineY = m_posy + m_maxCharTall;
    463 
    464         if (newLineY + tall > m_tall)
    465         {
    466             // No more space for new line in this page, should allocate a new one
    467             return false;
    468         }
    469 
    470         // Begin in new line
    471         m_posx = 0;
    472         m_posy = newLineY;
    473         // Reset
    474         m_maxCharTall = 0;
    475     }
    476 
    477     glBindTexture(GL_TEXTURE_2D, m_texture);
    478     glTexSubImage2D(GL_TEXTURE_2D, 0, m_posx, m_posy, wide, tall, GL_RGBA, GL_UNSIGNED_BYTE, rgba);
    479 
    480     coords[0] = m_posx / (float)m_wide;                // left
    481     coords[1] = m_posy / (float)m_tall;                // top
    482     coords[2] = (m_posx + wide) / (float)m_wide;    // right
    483     coords[3] = (m_posy + tall) / (float)m_tall;    // bottom
    484 
    485     m_posx += wide;
    486 
    487     if (tall > m_maxCharTall)
    488     {
    489         m_maxCharTall = tall;
    490     }
    491 
    492     return true;
    493 }
    494 
    495 GLuint CFontManager::CFont::CPage::getTexture(void)
    496 {
    497     return m_texture;
    498 }
    499 
    500 //------------------------------------------------------------
    501 // CFontManager
    502 //------------------------------------------------------------
    503 CFontManager::CFontManager()
    504 {
    505     m_library = NULL;
    506 }
    507 
    508 CFontManager::~CFontManager()
    509 {
    510     release();
    511 }
    512 
    513 bool CFontManager::initialize(void)
    514 {
    515     FT_Error err;
    516 
    517     if ((err = FT_Init_FreeType(&m_library)) != FT_Err_Ok)
    518     {
    519         printf("FT_Init_FreeType() Error %d
    ", err);
    520         return false;
    521     }
    522 
    523     return true;
    524 }
    525 
    526 void CFontManager::release(void)
    527 {
    528     FT_Error err;
    529 
    530     for (size_t i = 0; i < m_fonts.size(); i++)
    531     {
    532         delete m_fonts[i];
    533         m_fonts[i] = NULL;
    534     }
    535 
    536     m_fonts.clear();
    537 
    538     if ((err = FT_Done_FreeType(m_library)) != FT_Err_Ok)
    539     {
    540         printf("FT_Done_FreeType() Error %d
    ");
    541     }
    542 }
    543 
    544 int CFontManager::createFont(const char *filename, int face, int tall, bool bold, bool italic, bool antialias)
    545 {
    546     CFont *font = new CFont();
    547 
    548     if (font->create(m_library, filename, face, tall, bold, italic, antialias) != true)
    549     {
    550         delete font;
    551         return 0;
    552     }
    553 
    554     m_fonts.push_back(font);
    555 
    556     return m_fonts.size();
    557 }
    558 
    559 #define CONVERT_FONT_INDEX(x) (((x) < 1 || (x) > (int)m_fonts.size()) ? -1 : (x) - 1)
    560 
    561 bool CFontManager::getCharInfo(int font_index, int code, int *wide, int *tall, int *horiBearingX, int *horiBearingY, int *horiAdvance, GLuint *texture, float coords[])
    562 {
    563     int i = CONVERT_FONT_INDEX(font_index);
    564 
    565     if (i == -1)
    566     {
    567         return false;
    568     }
    569 
    570     CFont *font = m_fonts[i];
    571 
    572     glyphMetrics metrics;
    573 
    574     if (font->getCharInfo(code, &metrics, texture, coords) == false)
    575     {
    576         return false;
    577     }
    578 
    579     *wide = metrics.width;
    580     *tall = metrics.height;
    581     *horiBearingX = metrics.horiBearingX;
    582     *horiBearingY = metrics.horiBearingY;
    583     *horiAdvance = metrics.horiAdvance;
    584 
    585     return true;
    586 }
    587 
    588 int CFontManager::getFontTall(int font_index)
    589 {
    590     int i = CONVERT_FONT_INDEX(font_index);
    591 
    592     if (i == -1)
    593     {
    594         return false;
    595     }
    596 
    597     CFont *font = m_fonts[i];
    598 
    599     return font->getFontTall();
    600 }
    601 
    602 CFontManager g_FontManager;
    603 
    604 
    605 int char_font;
    606 
    607 
    608 void init(void)
    609 {
    610     glClearColor(0.0, 0.0, 0.0, 0.0);
    611 
    612     glEnable(GL_BLEND);
    613     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    614 
    615     g_FontManager.initialize();
    616 
    617     char_font = g_FontManager.createFont("FZDH_GBK.TTF", 0, 32, false, false, true);
    618 
    619     if (char_font == 0)
    620     {
    621         printf("createFont failed
    ");
    622     }
    623 }
    624 
    625 wchar_t ciphertext[] =
    626 {
    627     L"第一我做的是人气,不是他妈的信仰不是他妈的信任
    "
    628     L"我想信任来着,一群狼心的人就知道玩游戏。我投入的你们给我一分钱回报了么。
    "
    629     L"不懂少在那里嫌弃我,白花花的银子砸出来的东西免费给你们玩你们还这bb那bb
    "
    630     L"不管有没有人骂我我只在乎有没有人看我 懂么?
    "
    631     L"第二我你们尽管骂我
    "
    632     L"第三我的事情是我的自由
    "
    633     L"第四我一直很讨厌csol
    "
    634     L"第五世界上最失败的一次行动就是创建百度贴吧
    "
    635     L"第六 一群二逼骂个毛线管我屁事
    "
    636     L"http://tieba.baidu.com/p/3144980358"
    637 };
    638 
    639 //#define DRAW_PAGE
    640 
    641 void draw_string(int x, int y, int font, wchar_t *string)
    642 {
    643     if (!font)
    644         return;
    645 
    646     int tall = g_FontManager.getFontTall(font);
    647 
    648     int dx = x;
    649     int dy = y;
    650 
    651     GLuint sglt = 0;
    652 
    653     while (*string)
    654     {
    655         if (*string == L'
    ')
    656         {
    657             string++;
    658             dx = x;
    659             dy += tall + 2;    //row spacing
    660             continue;
    661         }
    662 
    663         int cw, ct, bx, by, av;
    664         GLuint glt;
    665         float crd[4];
    666 
    667         if (!g_FontManager.getCharInfo(font, *string, &cw, &ct, &bx, &by, &av, &glt, crd))
    668         {
    669             string++;
    670             continue;
    671         }
    672 
    673         //大多数情况下多个字符都在同一个纹理中,避免频繁绑定纹理,可以提高效率
    674         if (glt != sglt)
    675         {
    676             glBindTexture(GL_TEXTURE_2D, glt);
    677             sglt = glt;
    678         }
    679 
    680         int px = dx + bx;
    681         int py = dy - by;
    682 
    683         glBegin(GL_QUADS);
    684             glTexCoord2f(crd[0], crd[1]);
    685             glVertex3f(px, py, 0.0f);
    686             glTexCoord2f(crd[2], crd[1]);
    687             glVertex3f(px + cw, py, 0.0f);
    688             glTexCoord2f(crd[2], crd[3]);
    689             glVertex3f(px + cw, py + ct, 0.0f);
    690             glTexCoord2f(crd[0], crd[3]);
    691             glVertex3f(px, py + ct, 0.0f);
    692         glEnd();
    693 
    694         dx += av;
    695 
    696         string++;
    697     }
    698 }
    699 
    700 void draw_page_texture(int x, int y, GLuint glt)
    701 {
    702     if (!glt)
    703     {
    704         glDisable(GL_TEXTURE_2D);
    705         glColor4f(0.2, 0.2, 0.2, 1.0);
    706     }
    707     else
    708     {
    709         glEnable(GL_TEXTURE_2D);
    710         glBindTexture(GL_TEXTURE_2D, glt);
    711         glColor4f(1.0, 1.0, 1.0, 1.0);
    712     }
    713 
    714     int w = 256;
    715     int t = 256;
    716 
    717     glBegin(GL_QUADS);
    718         glTexCoord2f(0.0, 0.0);
    719         glVertex3f(x, y, 0.0f);
    720         glTexCoord2f(1.0, 0.0);
    721         glVertex3f(x + w, y, 0.0f);
    722         glTexCoord2f(1.0, 1.0);
    723         glVertex3f(x + w, y + t, 0.0f);
    724         glTexCoord2f(0.0, 1.0);
    725         glVertex3f(x, y + t, 0.0f);
    726     glEnd();
    727 }
    728 
    729 void display(void)
    730 {
    731     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    732 
    733     glEnable(GL_TEXTURE_2D);
    734     glColor4f(1.0, 1.0, 1.0, 1.0);
    735     draw_string(10, 30, char_font, ciphertext);
    736 
    737     draw_page_texture(10, 350, 0);    //background
    738     draw_page_texture(10, 350, 1);    //page1 texture
    739 
    740     draw_page_texture(276, 350, 0);    //background
    741     draw_page_texture(276, 350, 2);    //page2 texture
    742 
    743     glutSwapBuffers();
    744     glutPostRedisplay();
    745 }
    746 
    747 void reshape(int width, int height)
    748 {
    749     glViewport(0, 0, width, height);
    750 
    751     glMatrixMode(GL_PROJECTION);
    752     glLoadIdentity();
    753     gluOrtho2D(0, width, height, 0);
    754     glMatrixMode(GL_MODELVIEW);
    755 }
    756 
    757 void keyboard(unsigned char key, int x, int y)
    758 {
    759 }
    760 
    761 void main(int argc, char **argv)
    762 {
    763     glutInitWindowPosition(200, 200);
    764     glutInitWindowSize(1200, 680);
    765     glutInit(&argc, argv);
    766     glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL);
    767     glutCreateWindow("FreeType OpenGL");
    768     init();
    769     glutDisplayFunc(display);
    770     glutReshapeFunc(reshape);
    771     glutKeyboardFunc(keyboard);
    772     glutMainLoop();
    773 }

    例子中用到的GLUT和FreeType库请自行配置好。

    运行效果:

  • 相关阅读:
    抽奖概率算法
    thinkphp 6.0 结合 layuiadmin (iframe版)
    d2-admin 学习记录
    判断点是否在多边形区域内外
    PHP 优秀资源汇集
    前端学习路线
    限制sa 登录IP
    vs2013发布.net程序
    游标批 量删除数据表
    sql server2012 还原数据库
  • 原文地址:https://www.cnblogs.com/crsky/p/7261090.html
Copyright © 2011-2022 走看看