OpenGL入门技巧——字体的渲染(引用黑莓样例源码)

OpenGL入门技巧——字体的渲染(引用黑莓样例源码)

《OpenGL编程精粹》是本很好的书,但是渲染字体的步骤让我头疼,要自己载入图片,自己写一个类,如果有以往开发的经验和源码,直接引用还可以。
但是对于新手来说,还是简单点好,这里介绍的例子是黑莓样例Hello World中的字体渲染技巧,能不能通用还有待检验啊。
        int dpi = bbutil_calculate_dpi(screen_cxt);
font = bbutil_load_font(
"/usr/fonts/font_repository/adobe/MyriadPro-Bold.otf", 10, dpi);
if (!font) {
fprintf(stderr, "cant open font\n");
}
先load一个font文件,可以看到,使用了adobe的字体库,在大多数电脑上都应该有这个字体库,类似的库当然也可以。
bbutil_load_font文件,看起来有点长,别担心,这些都是可以直接引用的代码:
font_t* bbutil_load_font(const char* path, int point_size, int dpi) {
    FT_Library library;
    FT_Face face;
    int c;
    int i, j;
    font_t* font;
    if (!initialized) {
    fprintf(stderr, "EGL has not been initialized\n");
    return NULL;
    }
    if (!path){
    fprintf(stderr, "Invalid path to font file\n");
return NULL;
}
    if(FT_Init_FreeType(&library)) {
    fprintf(stderr, "Error loading Freetype library\n");
    return NULL;
    }
    if (FT_New_Face(library, path,0,&face)) {
fprintf(stderr, "Error loading font %s\n", path);
return NULL;
    }
    if(FT_Set_Char_Size ( face, point_size * 64, point_size * 64, dpi, dpi)) {
fprintf(stderr, "Error initializing character parameters\n");
return NULL;
    }
    font = (font_t*) malloc(sizeof(font_t));
    font->initialized = false;
    glGenTextures(1, &(font->font_texture));
    //Let each glyph reside in 32x32 section of the font texture
    int segment_size_x = 0, segment_size_y = 0;
    int num_segments_x = 16;
    int num_segments_y = 8;
    FT_GlyphSlot slot;
    FT_Bitmap bmp;
    int glyph_width, glyph_height;
    //First calculate the max width and height of a character in a passed font
    for(c = 0; c < 128; c++) {
if(FT_Load_Char(face, c, FT_LOAD_RENDER)) {
fprintf(stderr, "FT_Load_Char failed\n");
free(font);
return NULL;
}
slot = face->glyph;
bmp = slot->bitmap;
//glyph_width = nextp2(bmp.width);
//glyph_height = nextp2(bmp.rows);
glyph_width = bmp.width;
glyph_height = bmp.rows;
if (glyph_width > segment_size_x) {
segment_size_x = glyph_width;
}
if (glyph_height > segment_size_y) {
segment_size_y = glyph_height;
}
    }
    int font_tex_width = nextp2(num_segments_x * segment_size_x);
    int font_tex_height = nextp2(num_segments_y * segment_size_y);
    int bitmap_offset_x = 0, bitmap_offset_y = 0;
    GLubyte* font_texture_data = (GLubyte*) malloc(sizeof(GLubyte) * 2 * font_tex_width * font_tex_height);
    if (!font_texture_data) {
fprintf(stderr, "Failed to allocate memory for font texture\n");
free(font);
return NULL;
}
    // Fill font texture bitmap with individual bmp data and record appropriate size, texture coordinates and offsets for every glyph
    for(c = 0; c < 128; c++) {
if(FT_Load_Char(face, c, FT_LOAD_RENDER)) {
fprintf(stderr, "FT_Load_Char failed\n");
free(font);
return NULL;
}
slot = face->glyph;
bmp = slot->bitmap;
glyph_width = nextp2(bmp.width);
glyph_height = nextp2(bmp.rows);
div_t temp = div(c, num_segments_x);
bitmap_offset_x = segment_size_x * temp.rem;
bitmap_offset_y = segment_size_y * temp.quot;
        for (j = 0; j < glyph_height; j++) {
        for (i = 0; i < glyph_width; i++) {
        font_texture_data[2 * ((bitmap_offset_x + i) + (j + bitmap_offset_y) * font_tex_width) + 0] =
        font_texture_data[2 * ((bitmap_offset_x + i) + (j + bitmap_offset_y) * font_tex_width) + 1] =
(i >= bmp.width || j >= bmp.rows)? 0 : bmp.buffer[i + bmp.width * j];
            }
        }
        font->advance[c] = (float)(slot->advance.x >> 6);
        font->tex_x1[c] = (float)bitmap_offset_x / (float) font_tex_width;
        font->tex_x2[c] = (float)(bitmap_offset_x + bmp.width) / (float)font_tex_width;
        font->tex_y1[c] = (float)bitmap_offset_y / (float) font_tex_height;
        font->tex_y2[c] = (float)(bitmap_offset_y + bmp.rows) / (float)font_tex_height;
        font->width[c] = bmp.width;
        font->height[c] = bmp.rows;
        font->offset_x[c] = (float)slot->bitmap_left;
        font->offset_y[c] =  (float)((slot->metrics.horiBearingY-face->glyph->metrics.height) >> 6);
    }
    glBindTexture(GL_TEXTURE_2D, font->font_texture);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, font_tex_width, font_tex_height, 0, GL_LUMINANCE_ALPHA , GL_UNSIGNED_BYTE, font_texture_data);
    int err = glGetError();
    free(font_texture_data);
    FT_Done_Face(face);
    FT_Done_FreeType(library);
    if (err != 0) {
    fprintf(stderr, "GL Error 0x%x", err);
    free(font);
    return NULL;
    }
    font->initialized = true;
    return font;
}
font_t类型如下:
typedef struct{
    unsigned int font_texture;
    float pt;
    float advance[128];
    float width[128];
    float height[128];
    float tex_x1[128];
    float tex_x2[128];
    float tex_y1[128];
    float tex_y2[128];
    float offset_x[128];
    float offset_y[128];
    int initialized;
} font_t;
这样就可以使用系统的字体了,字体大小和位置:
void bbutil_measure_text(font_t* font, char* msg, float *width, float* height) {
int i, c;
if (!msg) {
return;
}
if (width) {
//Width of a text rectangle is a sum advances for every glyph in a string
*width = 0.0f;
for(i = 0; i < strlen(msg); ++i) {
c = msg[i];
*width += font->advance[c];
}
}
if (height) {
//Height of a text rectangle is a high of a tallest glyph in a string
*height = 0.0f;
for(i = 0; i < strlen(msg); ++i) {
c = msg[i];
if (*height < font->height[c]) {
*height = font->height[c];
}
}
}
}
float text_width, text_height;
bbutil_measure_text(font, notice, &text_width, &text_height);
pos_x = (width - text_width) / 2;
pos_y = height / 2;
字体的渲染:
bbutil_render_text(font, notice, pos_x, pos_y);
bbutil_render_text(font, sscore, pos_x2, pos_y2);

这一篇不是原创,借鉴了很多黑莓样例的源码,主要是为了在开发中节省时间,OpenGL方面的知识还需要学习。

你可能感兴趣的:(OpenGL入门技巧——字体的渲染(引用黑莓样例源码))