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文件,看起来有点长,别担心,这些都是可以直接引用的代码:
先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类型如下:
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方面的知识还需要学习。