const FontFace* Font::GetFaceTTF(int pointSize) { // Create & initialize FreeType library if it does not exist yet FreeTypeLibrary* freeType = GetSubsystem<FreeTypeLibrary>(); if (!freeType) context_->RegisterSubsystem(freeType = new FreeTypeLibrary(context_)); FT_Face face; FT_Error error; FT_Library library = freeType->GetLibrary(); if (pointSize <= 0) { LOGERROR("Zero or negative point size"); return 0; } if (!fontDataSize_) { LOGERROR("Font not loaded"); return 0; } error = FT_New_Memory_Face(library, &fontData_[0], fontDataSize_, 0, &face); if (error) { LOGERROR("Could not create font face"); return 0; } error = FT_Set_Char_Size(face, 0, pointSize * 64, FONT_DPI, FONT_DPI); if (error) { FT_Done_Face(face); LOGERROR("Could not set font point size " + String(pointSize)); return 0; } SharedPtr<FontFace> newFace(new FontFace()); FT_GlyphSlot slot = face->glyph; unsigned numGlyphs = 0; // Build glyph mapping FT_UInt glyphIndex; FT_ULong charCode = FT_Get_First_Char(face, &glyphIndex); while (glyphIndex != 0) { numGlyphs = Max((int)glyphIndex + 1, (int)numGlyphs); newFace->glyphMapping_[charCode] = glyphIndex; charCode = FT_Get_Next_Char(face, charCode, &glyphIndex); } LOGDEBUG("Font face has " + String(numGlyphs) + " glyphs"); // Load each of the glyphs to see the sizes & store other information int maxHeight = 0; FT_Pos ascender = face->size->metrics.ascender; newFace->glyphs_.Reserve(numGlyphs); for (unsigned i = 0; i < numGlyphs; ++i) { FontGlyph newGlyph; error = FT_Load_Glyph(face, i, FT_LOAD_DEFAULT); if (!error) { // Note: position within texture will be filled later newGlyph.width_ = (short)((slot->metrics.width) >> 6); newGlyph.height_ = (short)((slot->metrics.height) >> 6); newGlyph.offsetX_ = (short)((slot->metrics.horiBearingX) >> 6); newGlyph.offsetY_ = (short)((ascender - slot->metrics.horiBearingY) >> 6); newGlyph.advanceX_ = (short)((slot->metrics.horiAdvance) >> 6); maxHeight = Max(maxHeight, newGlyph.height_); } else {
// ------------------------------------------------------------------- init --- void init( void ) { size_t i, j; int ptSize = 50*64; int device_hdpi = 72; int device_vdpi = 72; texture_atlas_t * atlas = texture_atlas_new( 512, 512, 3 ); /* Init freetype */ FT_Library ft_library; assert(!FT_Init_FreeType(&ft_library)); /* Load our fonts */ FT_Face ft_face[NUM_EXAMPLES]; assert(!FT_New_Face( ft_library, fonts[ENGLISH], 0, &ft_face[ENGLISH]) ); assert(!FT_Set_Char_Size( ft_face[ENGLISH], 0, ptSize, device_hdpi, device_vdpi ) ); // ftfdump( ft_face[ENGLISH] ); // wonderful world of encodings ... force_ucs2_charmap( ft_face[ENGLISH] ); // which we ignore. assert( !FT_New_Face(ft_library, fonts[ARABIC], 0, &ft_face[ARABIC]) ); assert( !FT_Set_Char_Size(ft_face[ARABIC], 0, ptSize, device_hdpi, device_vdpi ) ); // ftfdump( ft_face[ARABIC] ); force_ucs2_charmap( ft_face[ARABIC] ); assert(!FT_New_Face( ft_library, fonts[CHINESE], 0, &ft_face[CHINESE]) ); assert(!FT_Set_Char_Size( ft_face[CHINESE], 0, ptSize, device_hdpi, device_vdpi ) ); // ftfdump( ft_face[CHINESE] ); force_ucs2_charmap( ft_face[CHINESE] ); /* Get our harfbuzz font structs */ hb_font_t *hb_ft_font[NUM_EXAMPLES]; hb_ft_font[ENGLISH] = hb_ft_font_create( ft_face[ENGLISH], NULL ); hb_ft_font[ARABIC] = hb_ft_font_create( ft_face[ARABIC] , NULL ); hb_ft_font[CHINESE] = hb_ft_font_create( ft_face[CHINESE], NULL ); /* Create a buffer for harfbuzz to use */ hb_buffer_t *buf = hb_buffer_create(); for (i=0; i < NUM_EXAMPLES; ++i) { hb_buffer_set_direction( buf, text_directions[i] ); /* or LTR */ hb_buffer_set_script( buf, scripts[i] ); /* see hb-unicode.h */ hb_buffer_set_language( buf, hb_language_from_string(languages[i], strlen(languages[i])) ); /* Layout the text */ hb_buffer_add_utf8( buf, texts[i], strlen(texts[i]), 0, strlen(texts[i]) ); hb_shape( hb_ft_font[i], buf, NULL, 0 ); unsigned int glyph_count; hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(buf, &glyph_count); hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &glyph_count); FT_GlyphSlot slot; FT_Bitmap ft_bitmap; float size = 24; size_t hres = 64; FT_Error error; FT_Int32 flags = 0; flags |= FT_LOAD_RENDER; flags |= FT_LOAD_TARGET_LCD; FT_Library_SetLcdFilter( ft_library, FT_LCD_FILTER_LIGHT ); FT_Matrix matrix = { (int)((1.0/hres) * 0x10000L), (int)((0.0) * 0x10000L), (int)((0.0) * 0x10000L), (int)((1.0) * 0x10000L) }; /* Set char size */ error = FT_Set_Char_Size( ft_face[i], (int)(ptSize), 0, 72*hres, 72 ); if( error ) { //fprintf( stderr, "FT_Error (line %d, code 0x%02x) : %s\n", // __LINE__, FT_Errors[error].code, FT_Errors[error].message ); FT_Done_Face( ft_face[i] ); break; } /* Set transform matrix */ FT_Set_Transform( ft_face[i], &matrix, NULL ); for (j = 0; j < glyph_count; ++j) { /* Load glyph */ error = FT_Load_Glyph( ft_face[i], glyph_info[j].codepoint, flags ); if( error ) { //fprintf( stderr, "FT_Error (line %d, code 0x%02x) : %s\n", // __LINE__, FT_Errors[error].code, FT_Errors[error].message ); FT_Done_Face( ft_face[i] ); break; } slot = ft_face[i]->glyph; ft_bitmap = slot->bitmap; int ft_bitmap_width = slot->bitmap.width; int ft_bitmap_rows = slot->bitmap.rows; int ft_bitmap_pitch = slot->bitmap.pitch; int ft_glyph_top = slot->bitmap_top; int ft_glyph_left = slot->bitmap_left; int w = ft_bitmap_width/3; // 3 because of LCD/RGB encoding int h = ft_bitmap_rows; ivec4 region = texture_atlas_get_region( atlas, w+1, h+1 ); if ( region.x < 0 ) { fprintf( stderr, "Texture atlas is full (line %d)\n", __LINE__ ); continue; } int x = region.x, y = region.y; texture_atlas_set_region( atlas, region.x, region.y, w, h, ft_bitmap.buffer, ft_bitmap.pitch ); printf("%d: %dx%d %f %f\n", glyph_info[j].codepoint, ft_bitmap_width, ft_bitmap_rows, glyph_pos[j].x_advance/64., glyph_pos[j].y_advance/64.); } /* clean up the buffer, but don't kill it just yet */ hb_buffer_reset(buf); } /* Cleanup */ hb_buffer_destroy( buf ); for( i=0; i < NUM_EXAMPLES; ++i ) hb_font_destroy( hb_ft_font[i] ); FT_Done_FreeType( ft_library ); glClearColor(1,1,1,1); glEnable( GL_BLEND ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); glEnable( GL_TEXTURE_2D ); glBindTexture( GL_TEXTURE_2D, atlas->id ); texture_atlas_upload( atlas ); typedef struct { float x,y,z, u,v, r,g,b,a, shift, gamma; } vertex_t; vertex_t vertices[4] = { { 0, 0,0, 0,1, 0,0,0,1, 0, 1}, { 0,512,0, 0,0, 0,0,0,1, 0, 1}, {512,512,0, 1,0, 0,0,0,1, 0, 1}, {512, 0,0, 1,1, 0,0,0,1, 0, 1} }; GLuint indices[6] = { 0, 1, 2, 0,2,3 }; buffer = vertex_buffer_new( "vertex:3f," "tex_coord:2f," "color:4f," "ashift:1f," "agamma:1f" ); vertex_buffer_push_back( buffer, vertices, 4, indices, 6 ); shader = shader_load("shaders/text.vert", "shaders/text.frag"); mat4_set_identity( &projection ); mat4_set_identity( &model ); mat4_set_identity( &view ); }