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

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