source: trunk/src/gfx/texture_font.cc @ 487

Last change on this file since 487 was 487, checked in by epyon, 9 years ago
File size: 5.7 KB
RevLine 
[395]1// Copyright (C) 2012-2015 ChaosForge Ltd
[21]2// http://chaosforge.org/
3//
[395]4// This file is part of Nova libraries.
5// For conditions of distribution and use, see copying.txt file in root folder.
6
[95]7#include "nv/gfx/texture_font.hh"
8
[21]9#include "nv/lib/freetype2.hh"
[365]10#include "nv/core/logging.hh"
[21]11
12using namespace nv;
13
[403]14#define NV_CHECK_FREETYPE_ERROR( error, ... ) \
15if ( error != 0 ) { \
16        NV_LOG_CRITICAL( "freetype : ", __VA_ARGS__ ); \
17        NV_ABORT( "freetype : freetype library error!" ); \
18}
19
[24]20texture_glyph::texture_glyph()
[21]21        : charcode(0), size(0,0), offset(0,0), advance(0.f,0.f), tl(0.f,0.f), br(0.f,0.f)
22{
23}
24
[121]25float texture_glyph::get_kerning( const uint16 other )
[21]26{
[121]27        auto i = kerning.find( other );
[21]28        return i != kerning.end() ? i->second : 0.0f;
29}
30
[438]31texture_font::texture_font( texture_atlas* atlas, const string_view& filename, float size )
32        : m_atlas( atlas ), m_filename( filename ), m_size( size ),
[21]33        m_height(0), m_linegap(0), m_ascender(0), m_descender(0),
[28]34        m_hinting( true ), m_filtering( true ), m_rlibrary( nullptr ), m_rface( nullptr )
[21]35{
[114]36        load_freetype_library();
[21]37        size_t hres = 64;
38        FT_Error error;
39        FT_Matrix matrix = {
[405]40                static_cast<int>((1.0/hres) * 0x10000L),
41                static_cast<int>((0.0)      * 0x10000L),
42                static_cast<int>((0.0)      * 0x10000L),
43                static_cast<int>((1.0)      * 0x10000L)
[21]44        };
45
46        m_lcd_weights[0] = 0x10;
47        m_lcd_weights[1] = 0x40;
48        m_lcd_weights[2] = 0x70;
49        m_lcd_weights[3] = 0x40;
50        m_lcd_weights[4] = 0x10;
51         
[405]52        error = FT_Init_FreeType( reinterpret_cast<FT_Library*>(&m_rlibrary) );
[403]53        NV_CHECK_FREETYPE_ERROR( error, "error on FT_Init_FreeType, code - ", error );
[21]54
[438]55        error = FT_New_Face( reinterpret_cast<FT_Library>(m_rlibrary), filename.data(), 0, reinterpret_cast<FT_Face*>(&m_rface) );
[403]56        NV_CHECK_FREETYPE_ERROR( error, "error on FT_New_Face, code - ", error );
[21]57
[405]58        error = FT_Set_Char_Size( reinterpret_cast<FT_Face>(m_rface), int(size*64), 0, 72*64, 72 );
[403]59        NV_CHECK_FREETYPE_ERROR( error, "error on FT_Set_Char_Size, code - ", error );
[21]60
[405]61    FT_Set_Transform( reinterpret_cast<FT_Face>(m_rface), &matrix, NULL );
[21]62
[405]63    FT_Size_Metrics metrics = reinterpret_cast<FT_Face>(m_rface)->size->metrics;
64    m_ascender  = static_cast<float>(metrics.ascender >> 6) / 100.0f;
65    m_descender = static_cast<float>(metrics.descender >> 6) / 100.0f;
66    m_height    = static_cast<float>(metrics.height >> 6) / 100.0f;
[45]67    m_linegap   = m_height - m_ascender + m_descender;
[21]68}
69
[24]70const texture_glyph* texture_font::get_glyph( uint16 charcode ) const
[21]71{
[24]72        auto i = m_glyphs.find( charcode );
73        if ( i == m_glyphs.end() )
[21]74        {
75                return nullptr;
76        }
77        return &(i->second);
78}
79
[103]80static uint8* convert_to_rgba(uint8* rgb, const int lines, const int line_count, const int line_bpitch )
81{
[487]82        uint8* result = new uint8[ static_cast< uint32 >( lines * line_count * 4 ) ];
[103]83        uint8* rgba   = result;
84        for(int l=0; l<lines; ++l)
85        {
86                for(int c=0; c<line_count; ++c)
87                {
88                        for(int j=0; j<3; ++j) {
89                                rgba[j]  = rgb[j];
90                        }
91                        rgba[3] = uint8( uint16( rgb[0] + rgb[1] + rgb[2] ) / 3 );
92                        rgba += 4;
93                        rgb  += 3;
94                }
95                rgb += line_bpitch - ( 3 * line_count );
96        }
97        return result;
98}
99
[399]100bool texture_font::load_glyphs( string_view codes )
[21]101{
[405]102        FT_Face face = reinterpret_cast<FT_Face>( m_rface );
[398]103        size_t depth = m_atlas->get_depth();
[405]104        vec2 asize   = vec2( m_atlas->get_size() );
[21]105        FT_Int32 flags = 0;
106        flags |= FT_LOAD_RENDER;
107        if( !m_hinting )
108        {
109                flags |= FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT;
110        }
111        else
112        {
113                flags |= FT_LOAD_FORCE_AUTOHINT;
114        }
115
[103]116        if( m_atlas->get_depth() >= 3 )
[21]117        {
[405]118                FT_Library_SetLcdFilter( reinterpret_cast<FT_Library>( m_rlibrary ), FT_LCD_FILTER_LIGHT );
[21]119                flags |= FT_LOAD_TARGET_LCD;
120                if ( m_filtering )
121                {
[405]122                        FT_Library_SetLcdFilterWeights( reinterpret_cast<FT_Library>( m_rlibrary ), m_lcd_weights );
[21]123                }
124        }
125
[121]126        for ( char ch : codes )
[21]127        {
[121]128                uint16 c = static_cast<uint16>( ch );
[21]129                FT_UInt glyph_index = FT_Get_Char_Index( face, c );
130                FT_Error error = FT_Load_Glyph( face, glyph_index, flags );
[403]131                NV_CHECK_FREETYPE_ERROR( error, "error on FT_Load_Glyph, gylph '", c ,"' code - ", error );
[21]132
133                FT_GlyphSlot slot   = face->glyph;
134                FT_Bitmap ft_bitmap = slot->bitmap;
135                int ft_bitmap_width = slot->bitmap.width;
136                int ft_bitmap_rows  = slot->bitmap.rows;
137                int ft_glyph_top    = slot->bitmap_top;
138                int ft_glyph_left   = slot->bitmap_left;
[405]139                int reg_width       = ft_bitmap_width / (depth > 3 ? 3 : int( depth ) );
[21]140
[398]141                ivec2 gsize( reg_width + 1, ft_bitmap_rows + 1 );
[21]142                region r = m_atlas->get_region( gsize );
143                if ( r.pos.x < 0 )
144                {
[403]145                        NV_LOG_CRITICAL( "texture_font : atlas full while loading glyphs, gylph '", c, "' r.pos.x = ", r.pos.x );
146                        NV_ABORT( "texture_font : atlas full while loading gylphs!" );
[21]147                }
[103]148                if (depth == 4)
149                {
150                        r.size.x -= 1;
151                        r.size.y -= 1;
152                        uint8* data = convert_to_rgba(ft_bitmap.buffer, r.size.y, r.size.x, ft_bitmap.pitch );
153                        m_atlas->set_region( r, data );
154                        delete data;
155                }
156                else
157                {
158                        r.size.x -= 1;
159                        r.size.y -= 1;
160                        m_atlas->set_region( r, ft_bitmap.buffer, ft_bitmap.pitch );
161                }
[21]162
[405]163                texture_glyph* g = &( m_glyphs[c] );
[21]164
165                g->charcode = c;
166                g->size     = gsize;
[398]167                g->offset   = ivec2( ft_glyph_left, ft_glyph_top );
[405]168                g->tl       = vec2( r.pos ) / asize;
169                g->br       = vec2( r.pos + gsize ) / asize;
[21]170
171                // Discard hinting to get advance
172                FT_Load_Glyph( face, glyph_index, FT_LOAD_RENDER | FT_LOAD_NO_HINTING);
173                slot = face->glyph;
[471]174                g->advance = vec2( slot->advance.x/64.0f, slot->advance.y/64.0f );
[21]175        }
176        generate_kerning();
177        return true;
178}
179
180texture_font::~texture_font()
181{
[405]182        if ( m_rface )    FT_Done_Face( reinterpret_cast<FT_Face>( m_rface ) );
183        if ( m_rlibrary ) FT_Done_FreeType( reinterpret_cast<FT_Library>( m_rlibrary ) );
[21]184}
185
186void texture_font::generate_kerning()
187{
188
189}
190
Note: See TracBrowser for help on using the repository browser.