示例#1
0
文件: texture-font.c 项目: hurry07/v8
// ------------------------------------------ texture_font_generate_kerning ---
void
texture_font_generate_kerning( texture_font_t *self )
{
    size_t i, j;
    FT_Library library;
    FT_Face face;
    FT_UInt glyph_index, prev_index;
    texture_glyph_t *glyph, *prev_glyph;
    FT_Vector kerning;
    
    assert( self );

    /* Load font */
//    if( !texture_font_load_face( &library, self->filename, self->size, &face ) )
//    {
//        return;
//    }
    if( !texture_font_load_face( self, &library, self->size, &face ) )// <----- changed
    {
        return;
    }

    /* For each glyph couple combination, check if kerning is necessary */
    /* Starts at index 1 since 0 is for the special backgroudn glyph */
    for( i=1; i<self->glyphs->size; ++i )
    {
        glyph = *(texture_glyph_t **) vector_get( self->glyphs, i );
        glyph_index = FT_Get_Char_Index( face, glyph->charcode );
        vector_clear( glyph->kerning );

        for( j=1; j<self->glyphs->size; ++j )
        {
            prev_glyph = *(texture_glyph_t **) vector_get( self->glyphs, j );
            prev_index = FT_Get_Char_Index( face, prev_glyph->charcode );
            FT_Get_Kerning( face, prev_index, glyph_index, FT_KERNING_UNFITTED, &kerning );
            // printf("%c(%d)-%c(%d): %ld\n",
            //       prev_glyph->charcode, prev_glyph->charcode,
            //       glyph_index, glyph_index, kerning.x);
            if( kerning.x )
            {
                // 64 * 64 because of 26.6 encoding AND the transform matrix used
                // in texture_font_load_face (hres = 64)
                kerning_t k = {prev_glyph->charcode, kerning.x / (float)(64.0f*64.0f)};
                vector_push_back( glyph->kerning, &k );
            }
        }
    }
    FT_Done_Face( face );
    FT_Done_FreeType( library );
}
示例#2
0
/* ------------------------------------------------------------------------- */
TextureFont *
texture_font_new( TextureAtlas *atlas,
                  const char *filename,
                  const float size )
{
    TextureFont *self = (TextureFont *) malloc( sizeof(TextureFont) );
    if( !self )
    {
        return NULL;
    }
    self->glyphs = vector_new( sizeof(TextureGlyph) );
    self->filename = strdup( filename );
    self->size = size;
    self->gamma = 1.;
    self->atlas = atlas;
    self->height = 0;
    self->ascender = 0;
    self->descender = 0;
    self->hinting = 1;
    self->lcd_filter = 0;
    self->lcd_weights[0] = 0;
    self->lcd_weights[1] = 0;
    self->lcd_weights[2] = 255;
    self->lcd_weights[3] = 0;
    self->lcd_weights[4] = 0;

    /* Get font metrics at high resolution */
    FT_Library library;
    FT_Face face;
    if( !texture_font_load_face( &library, self->filename, self->size*100, &face ) )
    {
        return self;
    }

    FT_Size_Metrics metrics = face->size->metrics; 
    self->ascender  = (metrics.ascender >> 6) / 100.0;
    self->descender = (metrics.descender >> 6) / 100.0;
    self->height    = (metrics.height >> 6) / 100.0;
    self->linegap   = self->height - self->ascender + self->descender;

    return self;
}
示例#3
0
// ----------------------------------------------- texture_font_load_glyphs ---
size_t
texture_font_load_glyphs( texture_font_t * self,
                          const wchar_t * charcodes )
{
    assert( self );
    assert( charcodes );

    size_t i, x, y, width, height, depth, w, h;
    FT_Library library;
    FT_Error error;
    FT_Face face;
    FT_Glyph ft_glyph;
    FT_GlyphSlot slot;
    FT_Bitmap ft_bitmap;

    FT_UInt glyph_index;
    texture_glyph_t *glyph;
    ivec4 region;
    size_t missed = 0;
    width  = self->atlas->width;
    height = self->atlas->height;
    depth  = self->atlas->depth;

    region.x=1;
    region.y=1;

#ifdef RENDERSTRING
    stringwidth=0;
    stringheight=0;
    stringshift=0;
#endif

    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 = 0;

        if( self->outline_type > 0 )
        {
            flags |= FT_LOAD_NO_BITMAP;
        }
        else
        {
            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->filtering )
            {
//                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;
        }

        int ft_bitmap_width = 0;
        int ft_bitmap_rows = 0;
        int ft_bitmap_pitch = 0;
        int ft_glyph_top = 0;
        int ft_glyph_left = 0;
        if( self->outline_type == 0 )
        {
            slot            = face->glyph;
            ft_bitmap       = slot->bitmap;
            ft_bitmap_width = slot->bitmap.width;
            ft_bitmap_rows  = slot->bitmap.rows;
            ft_bitmap_pitch = slot->bitmap.pitch;
            ft_glyph_top    = slot->bitmap_top;
            ft_glyph_left   = slot->bitmap_left;
        }
        else
        {
            FT_Stroker stroker;
            error = FT_Stroker_New( library, &stroker );
            if( error )
            {
                fprintf(stderr, "FT_Error (0x%02x) : %s\n",
                        FT_Errors[error].code, FT_Errors[error].message);
                return 0;
            }
            FT_Stroker_Set( stroker,
                            (int)(self->outline_thickness *64),
                            FT_STROKER_LINECAP_ROUND,
                            FT_STROKER_LINEJOIN_ROUND,
                            0);
            error = FT_Get_Glyph( face->glyph, &ft_glyph);
            if( error )
            {
                fprintf(stderr, "FT_Error (0x%02x) : %s\n",
                        FT_Errors[error].code, FT_Errors[error].message);
                return 0;
            }

            if( self->outline_type == 1 )
            {
                error = FT_Glyph_Stroke( &ft_glyph, stroker, 1 );
            }
            else if ( self->outline_type == 2 )
            {
                error = FT_Glyph_StrokeBorder( &ft_glyph, stroker, 0, 1 );
            }
            else if ( self->outline_type == 3 )
            {
                error = FT_Glyph_StrokeBorder( &ft_glyph, stroker, 1, 1 );
            }
            if( error )
            {
                fprintf(stderr, "FT_Error (0x%02x) : %s\n",
                        FT_Errors[error].code, FT_Errors[error].message);
                return 0;
            }
          
            if( depth == 1)
            {
                error = FT_Glyph_To_Bitmap( &ft_glyph, FT_RENDER_MODE_NORMAL, 0, 1);
                if( error )
                {
                    fprintf(stderr, "FT_Error (0x%02x) : %s\n",
                            FT_Errors[error].code, FT_Errors[error].message);
                    return 0;
                }
            }
            else
            {
                error = FT_Glyph_To_Bitmap( &ft_glyph, FT_RENDER_MODE_LCD, 0, 1);
                if( error )
                {
                    fprintf(stderr, "FT_Error (0x%02x) : %s\n",
                            FT_Errors[error].code, FT_Errors[error].message);
                    return 0;
                }
            }
            FT_BitmapGlyph ft_bitmap_glyph = (FT_BitmapGlyph) ft_glyph;
            ft_bitmap       = ft_bitmap_glyph->bitmap;
            ft_bitmap_width = ft_bitmap.width;
            ft_bitmap_rows  = ft_bitmap.rows;
            ft_bitmap_pitch = ft_bitmap.pitch;
            ft_glyph_top    = ft_bitmap_glyph->top;
            ft_glyph_left   = ft_bitmap_glyph->left;
            FT_Stroker_Done(stroker);
        }


        // We want each glyph to be separated by at least one black pixel
        // (for example for shader used in demo-subpixel.c)
        w = ft_bitmap_width/depth + 1;
        h = ft_bitmap_rows + 1;

#ifdef RENDERSTRING
        static size_t maxh=0;
        if (charcodes[i]==13) { stringshift+=maxh+1; region.x=1; }
        if (h>maxh) maxh=h;
        //region.y=stringshift+maxh-h+1+(h-ft_glyph_top);
        region.y=stringshift+maxh-ft_glyph_top+1;
       // if (stringshift+h+h-ft_glyph_top+1>stringheight) stringheight=stringshift+h+h-ft_glyph_top+1;
        if (region.y+h>stringheight) stringheight=region.y+h;
        if (region.x+w>stringwidth) stringwidth=region.x+w;
//        if (region.y>=height) { missed++; continue; }
//        if (region.x+w>=width) {missed++; continue; }
       // if (h+h-ft_glyph_top+1>=height) { missed++; continue; }
       // if (h+h-ft_glyph_top+2>=height) { missed++; continue; }
//        if (region.y+maxh>=height) { missed++; continue; }
#else
        region = texture_atlas_get_region( self->atlas, w, h );
        if ( region.x < 0 )
        {
            missed++;
        //    fprintf( stderr, "Texture atlas is full (line %d)\n",  __LINE__ );
            continue;
        }
#endif
        w = w - 1;
        h = h - 1;
        x = region.x;
        y = region.y;
        if (charcodes[i]!=13) {

#ifdef RENDERSTRING
     if (!(x<width)||!((x+w)<=width)||!(y<height)||!((y+h)<=height)) { missed++; continue; }
#endif

          texture_atlas_set_region( self->atlas, x, y, w, h,
                                  ft_bitmap.buffer, ft_bitmap.pitch );
}
        glyph = texture_glyph_new( );
        glyph->charcode = charcodes[i];
        glyph->width    = w;
        glyph->height   = h;
        glyph->outline_type = self->outline_type;
        glyph->outline_thickness = self->outline_thickness;
        glyph->offset_x = ft_glyph_left;
        glyph->offset_y = ft_glyph_top;
        glyph->s0       = x/(float)width;
        glyph->t0       = y/(float)height;
        glyph->s1       = (x + glyph->width)/(float)width;
        glyph->t1       = (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;

#ifdef RENDERSTRING
        if (charcodes[i]!=13) region.x+=(int)glyph->advance_x;
#endif

        vector_push_back( self->glyphs, &glyph );
    }
    if( self->outline_type > 0 )
    {
        FT_Done_Glyph( ft_glyph );
    }
    FT_Done_Face( face );
    FT_Done_FreeType( library );
 //   texture_atlas_upload( self->atlas );
    texture_font_generate_kerning( self );
    return missed;
}
示例#4
0
// ------------------------------------------------------- texture_font_new ---
texture_font_t *
texture_font_new( texture_atlas_t * atlas,
                  const char * filename,
                  const float size)
{
    assert( filename );
    assert( size );

    texture_font_t *self = (texture_font_t *) malloc( sizeof(texture_font_t) );
    if( self == NULL)
    {
        fprintf( stderr,
                 "line %d: No more memory for allocating data\n", __LINE__ );
        exit( EXIT_FAILURE );
    }
    self->glyphs = vector_new( sizeof(texture_glyph_t *) );
    self->atlas = atlas;
    self->height = 0;
    self->ascender = 0;
    self->descender = 0;
    self->filename = strdup( filename );
    self->size = size;
    self->outline_type = 0;
    self->outline_thickness = 0.0;
    self->hinting = 1;
    self->filtering = 1;
    // FT_LCD_FILTER_LIGHT   is (0x00, 0x55, 0x56, 0x55, 0x00)
    // FT_LCD_FILTER_DEFAULT is (0x10, 0x40, 0x70, 0x40, 0x10)
    self->lcd_weights[0] = 0x10;
    self->lcd_weights[1] = 0x40;
    self->lcd_weights[2] = 0x70;
    self->lcd_weights[3] = 0x40;
    self->lcd_weights[4] = 0x10;

    /* Get font metrics at high resolution */
    FT_Library library;
    FT_Face face;
    if( !texture_font_load_face( &library, self->filename, self->size*100, &face ) )
    {
        return self;
    }

    // 64 * 64 because of 26.6 encoding AND the transform matrix used
    // in texture_font_load_face (hres = 64)
    self->underline_position = face->underline_position / (float)(64.0f*64.0f) * self->size;
    self->underline_position = round( self->underline_position );
    if( self->underline_position > -2 )
    {
        self->underline_position = -2.0;
    }

    self->underline_thickness = face->underline_thickness / (float)(64.0f*64.0f) * self->size;
    self->underline_thickness = round( self->underline_thickness );
    if( self->underline_thickness < 1 )
    {
        self->underline_thickness = 1.0;
    }

    FT_Size_Metrics metrics = face->size->metrics; 
    self->ascender = (metrics.ascender >> 6) / 100.0;
    self->descender = (metrics.descender >> 6) / 100.0;
    self->height = (metrics.height >> 6) / 100.0;
    self->linegap = self->height - self->ascender + self->descender;
    FT_Done_Face( face );
    FT_Done_FreeType( library );

    /* -1 is a special glyph */
    texture_font_get_glyph( self, -1 );

    return self;
}
示例#5
0
/* ------------------------------------------------------------------------- */
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;
}
示例#6
0
/* ------------------------------------------------------------------------- */
void
texture_font_generate_kerning( TextureFont *self )
{
    size_t i, j, k, count;
    FT_Library   library;
    FT_Face      face;
    FT_UInt      glyph_index, prev_index;
    TextureGlyph *glyph, *prev_glyph;
    FT_Vector    kerning;

    /* Load font */
    if( !texture_font_load_face( &library, self->filename, self->size, &face ) )
    {
        return;
    }

    /* For each glyph couple combination, check if kerning is necessary */
    for( i=0; i<self->glyphs->size; ++i )
    {

        glyph = (TextureGlyph *) vector_get( self->glyphs, i );

        /* Remove any old kerning information */
        if( glyph->kerning )
        {
            free( glyph->kerning );
            glyph->kerning = 0;
            glyph->kerning_count = 0;
        }

        /* Count how many kerning pairs we need */
        count = 0;
        glyph_index = FT_Get_Char_Index( face, glyph->charcode );
        for( j=0; j<self->glyphs->size; ++j )
        {
            prev_glyph = (TextureGlyph *) vector_get( self->glyphs, j );
            prev_index = FT_Get_Char_Index( face, prev_glyph->charcode );
            FT_Get_Kerning( face, prev_index, glyph_index, FT_KERNING_UNFITTED, &kerning );
            if( kerning.x != 0.0 )
            {
                count++;
            }
        }
      
        /* No kerning at all */
        if( !count )
        {
            continue;
        }

        /* Store kerning pairs */
        glyph->kerning = (KerningPair *) malloc( count * sizeof(KerningPair) );
        glyph->kerning_count = count;
        k = 0;
        for( j=0; j<self->glyphs->size; ++j )
        {
            prev_glyph = (TextureGlyph *) vector_get( self->glyphs, j );
            prev_index = FT_Get_Char_Index( face, prev_glyph->charcode );
            FT_Get_Kerning( face, prev_index, glyph_index, FT_KERNING_UNFITTED, &kerning );
            if( kerning.x != 0.0 )
            {
                glyph->kerning[k].charcode = prev_glyph->charcode;
                // 64 * 64 because of 26.6 encoding AND the transform matrix used
                // in texture_font_load_face (hres = 64)
                glyph->kerning[k].kerning = kerning.x/ (float)(64.0f*64.0f);
                ++k;
            }
        }
    }

    FT_Done_Face( face );
    FT_Done_FreeType( library );
}
示例#7
0
 static int
 texture_font_get_face_with_size(texture_font_t *self, float size,
         FT_Library *library, FT_Face *face)
 {
     return texture_font_load_face(self, size, library, face);
 }