// ---------------------------------------------------- texture_font_delete --- void texture_font_delete( texture_font_t *self ) { size_t i; texture_glyph_t *glyph; assert( self ); if(self->location == TEXTURE_FONT_FILE && self->filename) free( self->filename ); for( i=0; i<vector_size( self->glyphs ); ++i) { glyph = *(texture_glyph_t **) vector_get( self->glyphs, i ); texture_glyph_delete( glyph); } vector_delete( self->glyphs ); free( self ); }
// ---------------------------------------------------- texture_font_delete --- void texture_font_delete( texture_font_t *self ) { assert( self ); if( self->filename ) { free( self->filename ); } size_t i; texture_glyph_t *glyph; for( i=0; i<vector_size( self->glyphs ); ++i) { glyph = *(texture_glyph_t **) vector_get( self->glyphs, i ); texture_glyph_delete( glyph); } vector_delete( self->glyphs ); free( self ); }
/* ------------------------------------------------------------------------- */ size_t texture_font_cache_glyphs( TextureFont *self, wchar_t * charcodes ) { size_t i, x, y, width, height, depth, w, h; FT_Library library; FT_Error error; FT_Face face; FT_GlyphSlot slot; FT_UInt glyph_index; TextureGlyph *glyph; Region region; unsigned char c; size_t missed = 0; width = self->atlas->width; height = self->atlas->height; depth = self->atlas->depth; if( !texture_font_load_face( &library, self->filename, self->size, &face ) ) { return wcslen(charcodes); } /* Load each glyph */ for( i=0; i<wcslen(charcodes); ++i ) { glyph_index = FT_Get_Char_Index( face, charcodes[i] ); // WARNING: We use texture-atlas depth to guess if user wants // LCD subpixel rendering FT_Int32 flags = FT_LOAD_RENDER; if( !self->hinting ) { flags |= FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT; } else { flags |= FT_LOAD_FORCE_AUTOHINT; } if( depth == 3 ) { FT_Library_SetLcdFilter( library, FT_LCD_FILTER_LIGHT ); flags |= FT_LOAD_TARGET_LCD; if( self->lcd_filter ) { FT_Library_SetLcdFilterWeights( library, self->lcd_weights ); } } error = FT_Load_Glyph( face, glyph_index, 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_FreeType( library ); return wcslen(charcodes)-i; } slot = face->glyph; /* Gamma correction (sort of) */ for( x=0; x<slot->bitmap.width; ++x ) { for( y=0; y<slot->bitmap.rows; ++y ) { c = *(unsigned char *)(slot->bitmap.buffer + y*slot->bitmap.pitch + x ); c = (unsigned char) ( pow(c/255.0, self->gamma) * 255); *(unsigned char *)(slot->bitmap.buffer + y*slot->bitmap.pitch + x ) = c; } } // We want each glyph to be separated by at least one black pixel // (for example for shader used in demo-subpixel.c) w = slot->bitmap.width/depth + 1; h = slot->bitmap.rows + 1; region = texture_atlas_get_region( self->atlas, w, h ); if ( region.x < 0 ) { missed++; continue; } w = w - 1; h = h - 1; x = region.x; y = region.y; texture_atlas_set_region( self->atlas, x, y, w, h, slot->bitmap.buffer, slot->bitmap.pitch ); glyph = texture_glyph_new( ); glyph->font = self; glyph->charcode = charcodes[i]; glyph->kerning = 0; glyph->width = w; glyph->height = h; glyph->offset_x = slot->bitmap_left; glyph->offset_y = slot->bitmap_top; glyph->u0 = x/(float)width; glyph->v0 = y/(float)height; glyph->u1 = (x + glyph->width)/(float)width; glyph->v1 = (y + glyph->height)/(float)height; /* Discard hinting to get advance */ FT_Load_Glyph( face, glyph_index, FT_LOAD_RENDER | FT_LOAD_NO_HINTING); slot = face->glyph; glyph->advance_x = slot->advance.x/64.0; glyph->advance_y = slot->advance.y/64.0; vector_push_back( self->glyphs, glyph ); texture_glyph_delete( glyph ); } FT_Done_Face( face ); FT_Done_FreeType( library ); texture_atlas_upload( self->atlas ); texture_font_generate_kerning( self ); return missed; }
// ------------------------------------------------- texture_font_get_glyph --- texture_glyph_t * texture_font_get_glyph( texture_font_t * self, wchar_t charcode ) { assert( self ); size_t i; wchar_t buffer[2] = {0,0}; texture_glyph_t *glyph; assert( self ); assert( self->filename ); assert( self->atlas ); /* Check if charcode has been already loaded */ for( i=0; i<self->glyphs->size; ++i ) { glyph = *(texture_glyph_t **) vector_get( self->glyphs, i ); // If charcode is -1, we don't care about outline type or thickness if( (glyph->charcode == charcode) && ((charcode == (wchar_t)(-1) ) || ((glyph->outline_type == self->outline_type) && (glyph->outline_thickness == self->outline_thickness)) )) { return glyph; } } /* charcode -1 is special : it is used for line drawing (overline, * underline, strikethrough) and background. */ if( charcode == (wchar_t)(-1) ) { size_t width = self->atlas->width; size_t height = self->atlas->height; ivec4 region = texture_atlas_get_region( self->atlas, 5, 5 ); texture_glyph_t * glyph = texture_glyph_new( ); static unsigned char data[4*4*3] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}; if ( region.x < 0 ) { fprintf( stderr, "Texture atlas is full (line %d)\n", __LINE__ ); texture_glyph_delete(glyph); return NULL; } texture_atlas_set_region( self->atlas, region.x, region.y, 4, 4, data, 0 ); glyph->charcode = (wchar_t)(-1); glyph->s0 = (region.x+2)/(float)width; glyph->t0 = (region.y+2)/(float)height; glyph->s1 = (region.x+3)/(float)width; glyph->t1 = (region.y+3)/(float)height; vector_push_back( self->glyphs, &glyph ); return glyph; //*(texture_glyph_t **) vector_back( self->glyphs ); } /* Glyph has not been already loaded */ buffer[0] = charcode; if( texture_font_load_glyphs( self, buffer ) == 0 ) { return *(texture_glyph_t **) vector_back( self->glyphs ); } return NULL; }