diff options
Diffstat (limited to 'scene/resources/dynamic_font.cpp')
-rw-r--r-- | scene/resources/dynamic_font.cpp | 301 |
1 files changed, 180 insertions, 121 deletions
diff --git a/scene/resources/dynamic_font.cpp b/scene/resources/dynamic_font.cpp index 19aa0e79cc..c76b5f3d3a 100644 --- a/scene/resources/dynamic_font.cpp +++ b/scene/resources/dynamic_font.cpp @@ -1,65 +1,11 @@ +#ifdef FREETYPE_ENABLED #include "dynamic_font.h" -#define STB_TRUETYPE_IMPLEMENTATION -#include "stb_truetype.h" #include "os/file_access.h" -void DynamicFontData::lock() { - fr=font_data.read(); - - if (fr.ptr()!=last_data_ptr) { - - last_data_ptr=fr.ptr(); - - if (!stbtt_InitFont(&info, last_data_ptr, 0)) { - valid=false; - } else { - valid=true; - } - - last_data_ptr=fr.ptr(); - } -} - -void DynamicFontData::unlock() { - - fr = DVector<uint8_t>::Read(); -} - -void DynamicFontData::set_font_data(const DVector<uint8_t>& p_font) { - //clear caches and stuff - ERR_FAIL_COND(font_data.size()) ; - font_data=p_font; - - lock(); - - if (valid) { - stbtt_GetFontVMetrics(&info, &ascent, &descent, &linegap); - descent=-descent + linegap; - - for(int i=32;i<1024;i++) { - for(int j=32;j<1024;j++) { - - int kern = stbtt_GetCodepointKernAdvance(&info, i,j); - if (kern!=0) { - KerningPairKey kpk; - kpk.A=i; - kpk.B=j; - kerning_map[kpk]=kern; - } - } - } - } - - unlock(); - //clear existing stuff - - ERR_FAIL_COND(!valid); -} Ref<DynamicFontAtSize> DynamicFontData::_get_dynamic_font_at_size(int p_size) { - ERR_FAIL_COND_V(!valid,Ref<DynamicFontAtSize>()); if (size_cache.has(p_size)) { return Ref<DynamicFontAtSize>( size_cache[p_size] ); @@ -67,6 +13,7 @@ Ref<DynamicFontAtSize> DynamicFontData::_get_dynamic_font_at_size(int p_size) { Ref<DynamicFontAtSize> dfas; + dfas.instance(); dfas->font=Ref<DynamicFontData>( this ); @@ -74,21 +21,34 @@ Ref<DynamicFontAtSize> DynamicFontData::_get_dynamic_font_at_size(int p_size) { size_cache[p_size]=dfas.ptr(); dfas->size=p_size; + dfas->_load(); + + return dfas; - lock(); +} - dfas->scale = stbtt_ScaleForPixelHeight(&info, p_size); +void DynamicFontData::set_font_ptr(const uint8_t* p_font_mem,int p_font_mem_size) { - unlock(); + font_mem=p_font_mem; + font_mem_size=p_font_mem_size; +} - return dfas; +void DynamicFontData::set_font_path(const String& p_path) { + + font_path=p_path; +} + +void DynamicFontData::set_force_autohinter(bool p_force) { + force_autohinter=p_force; } DynamicFontData::DynamicFontData() { - last_data_ptr=NULL; - valid=false; + + force_autohinter=false; + font_mem=NULL; + font_mem_size=0; } DynamicFontData::~DynamicFontData() @@ -100,22 +60,106 @@ DynamicFontData::~DynamicFontData() //////////////////// +Error DynamicFontAtSize::_load() { + + + int error = FT_Init_FreeType( &library ); + + ERR_EXPLAIN(TTR("Error initializing FreeType.")); + ERR_FAIL_COND_V( error !=0, ERR_CANT_CREATE ); + + if (font->font_path!=String()) { + + FileAccess *f=FileAccess::open(font->font_path,FileAccess::READ); + ERR_FAIL_COND_V(!f,ERR_CANT_OPEN); + + memset(&stream,0,sizeof(FT_StreamRec)); + stream.base=NULL; + stream.size=f->get_len(); + stream.pos=0; + stream.descriptor.pointer=f; + stream.read=_ft_stream_io; + stream.close=_ft_stream_close; + + FT_Open_Args fargs; + memset(&fargs,0,sizeof(FT_Open_Args)); + fargs.flags=FT_OPEN_STREAM; + fargs.stream=&stream; + error = FT_Open_Face( library,&fargs,0,&face); + } else if (font->font_mem) { + + memset(&stream,0,sizeof(FT_StreamRec)); + stream.base=(unsigned char*)font->font_mem; + stream.size=font->font_mem_size; + stream.pos=0; + + FT_Open_Args fargs; + memset(&fargs,0,sizeof(FT_Open_Args)); + fargs.memory_base=(unsigned char*)font->font_mem; + fargs.memory_size=font->font_mem_size; + fargs.flags= FT_OPEN_MEMORY; + fargs.stream=&stream; + error = FT_Open_Face( library,&fargs,0,&face); + + } else { + ERR_EXPLAIN("DynamicFont uninitialized"); + ERR_FAIL_V(ERR_UNCONFIGURED); + } + + //error = FT_New_Face( library, src_path.utf8().get_data(),0,&face ); + + if ( error == FT_Err_Unknown_File_Format ) { + ERR_EXPLAIN(TTR("Unknown font format.")); + FT_Done_FreeType( library ); + + } else if ( error ) { + + ERR_EXPLAIN(TTR("Error loading font.")); + FT_Done_FreeType( library ); + + } + + ERR_FAIL_COND_V(error,ERR_FILE_CANT_OPEN); + + + /*error = FT_Set_Char_Size(face,0,64*size,512,512); + + if ( error ) { + FT_Done_FreeType( library ); + ERR_EXPLAIN(TTR("Invalid font size.")); + ERR_FAIL_COND_V( error, ERR_INVALID_PARAMETER ); + }*/ + + error = FT_Set_Pixel_Sizes(face,0,size); + + ascent=face->size->metrics.ascender>>6; + descent=-face->size->metrics.descender>>6; + linegap=0; + + //print_line("ASCENT: "+itos(ascent)+" descent "+itos(descent)+" hinted: "+itos(face->face_flags&FT_FACE_FLAG_HINTER)); + + valid=true; + return OK; +} + float DynamicFontAtSize::get_height() const { - return (font->ascent+font->descent)*scale; + return ascent+descent; } float DynamicFontAtSize::get_ascent() const { - return font->ascent*scale; + return ascent; } float DynamicFontAtSize::get_descent() const { - return font->descent*scale; + return descent; } Size2 DynamicFontAtSize::get_char_size(CharType p_char,CharType p_next) const { + if (!valid) + return Size2(1,1); const_cast<DynamicFontAtSize*>(this)->_update_char(p_char); const Character *c = char_map.getptr(p_char); @@ -124,14 +168,9 @@ Size2 DynamicFontAtSize::get_char_size(CharType p_char,CharType p_next) const { Size2 ret( c->advance, get_height()); if (p_next) { - DynamicFontData::KerningPairKey kpk; - kpk.A=p_char; - kpk.B=p_next; - - const Map<DynamicFontData::KerningPairKey,int>::Element *K=font->kerning_map.find(kpk); - if (K) { - ret.x+=K->get()*scale; - } + FT_Vector delta; + FT_Get_Kerning( face, p_char,p_next, FT_KERNING_DEFAULT, &delta ); + ret.x+=delta.x>>6; } @@ -141,6 +180,9 @@ Size2 DynamicFontAtSize::get_char_size(CharType p_char,CharType p_next) const { float DynamicFontAtSize::draw_char(RID p_canvas_item, const Point2& p_pos, const CharType& p_char,const CharType& p_next,const Color& p_modulate) const { + if (!valid) + return 0; + const_cast<DynamicFontAtSize*>(this)->_update_char(p_char); const Character * c = char_map.getptr(p_char); @@ -161,58 +203,84 @@ float DynamicFontAtSize::draw_char(RID p_canvas_item, const Point2& p_pos, const float ret = c->advance; if (p_next) { - DynamicFontData::KerningPairKey kpk; - kpk.A=p_char; - kpk.B=p_next; - const Map<DynamicFontData::KerningPairKey,int>::Element *K=font->kerning_map.find(kpk); - if (K) { - ret+=K->get()*scale; - } + FT_Vector delta; + FT_Get_Kerning( face, p_char,p_next, FT_KERNING_DEFAULT, &delta ); + ret+=delta.x>>6; } return ret; } +unsigned long DynamicFontAtSize::_ft_stream_io(FT_Stream stream, unsigned long offset, unsigned char* buffer, unsigned long count ) { + + + FileAccess *f=(FileAccess*)stream->descriptor.pointer; + + if (f->get_pos()!=offset) { + f->seek(offset); + + } + + if (count==0) + return 0; + + return f->get_buffer(buffer,count); +} +void DynamicFontAtSize::_ft_stream_close(FT_Stream stream) { + + FileAccess *f=(FileAccess*)stream->descriptor.pointer; + f->close(); + memdelete(f); +} + void DynamicFontAtSize::_update_char(CharType p_char) { if (char_map.has(p_char)) return; - font->lock(); - + _THREAD_SAFE_METHOD_ - int w,h,xofs,yofs; - unsigned char * cpbitmap = stbtt_GetCodepointBitmap(&font->info, scale, scale, p_char, &w, &h, &xofs, &yofs ); + FT_GlyphSlot slot = face->glyph; - if (!cpbitmap) { - //no glyph + int error = FT_Load_Char( face, p_char, FT_LOAD_RENDER|(font->force_autohinter?FT_LOAD_FORCE_AUTOHINT:0) ); + if (!error) { + error = FT_Render_Glyph( face->glyph, ft_render_mode_normal ); + } + if (error) { - int advance; - stbtt_GetCodepointHMetrics(&font->info, p_char, &advance, 0); + int advance=0; + //stbtt_GetCodepointHMetrics(&font->info, p_char, &advance, 0); //print_line("char has no bitmap: "+itos(p_char)+" but advance is "+itos(advance*scale)); Character ch; ch.texture_idx=-1; - ch.advance=advance*scale; + ch.advance=advance; ch.h_align=0; ch.v_align=0; char_map[p_char]=ch; - font->unlock(); return; } + + + int w = slot->bitmap.width; + int h = slot->bitmap.rows; + int p = slot->bitmap.pitch; + int yofs=slot->bitmap_top; + int xofs=slot->bitmap_left; + int advance=slot->advance.x>>6; + + int mw=w+rect_margin*2; int mh=h+rect_margin*2; if (mw>4096 || mh>4096) { - stbtt_FreeBitmap(cpbitmap,NULL); - font->unlock(); ERR_FAIL_COND(mw>4096); ERR_FAIL_COND(mh>4096); } @@ -304,13 +372,14 @@ void DynamicFontAtSize::_update_char(CharType p_char) { { DVector<uint8_t>::Write wr = tex.imgdata.write(); + for(int i=0;i<h;i++) { for(int j=0;j<w;j++) { int ofs = ( (i+tex_y+rect_margin)*tex.texture_size+j+tex_x+rect_margin)*2; ERR_FAIL_COND(ofs >= tex.imgdata.size()); wr[ofs+0]=255; //grayscale as 1 - wr[ofs+1]=cpbitmap[i*w+j]; //alpha as 0 + wr[ofs+1]=slot->bitmap.buffer[i*slot->bitmap.width+j]; } } } @@ -322,7 +391,7 @@ void DynamicFontAtSize::_update_char(CharType p_char) { if (tex.texture.is_null()) { tex.texture.instance(); - tex.texture->create_from_image(img,Texture::FLAG_FILTER); + tex.texture->create_from_image(img,0/*Texture::FLAG_FILTER*/); } else { tex.texture->set_data(img); //update } @@ -337,13 +406,11 @@ void DynamicFontAtSize::_update_char(CharType p_char) { tex.offsets[k]=tex_y+mh; } - int advance; - stbtt_GetCodepointHMetrics(&font->info, p_char, &advance, 0); Character chr; chr.h_align=xofs; - chr.v_align=yofs + get_ascent(); - chr.advance=advance*scale; + chr.v_align=ascent-yofs;// + ascent - descent; + chr.advance=advance; chr.texture_idx=tex_index; @@ -353,21 +420,24 @@ void DynamicFontAtSize::_update_char(CharType p_char) { char_map[p_char]=chr; - stbtt_FreeBitmap(cpbitmap,NULL); - - font->unlock(); } DynamicFontAtSize::DynamicFontAtSize() { + valid=false; rect_margin=1; + ascent=1; + descent=1; + linegap=1; } DynamicFontAtSize::~DynamicFontAtSize(){ - ERR_FAIL_COND(!font.ptr()); - font->size_cache.erase(size); + if (valid) { + FT_Done_FreeType( library ); + font->size_cache.erase(size); + } } ///////////////////////// @@ -478,34 +548,21 @@ RES ResourceFormatLoaderDynamicFont::load(const String &p_path, const String& p_ if (r_error) *r_error=ERR_FILE_CANT_OPEN; + Ref<DynamicFontData> dfont; + dfont.instance();; + dfont->set_font_path(p_path); - FileAccess *f = FileAccess::open(p_path,FileAccess::READ); - ERR_FAIL_COND_V(!f,RES()); - - DVector<uint8_t> data; - - data.resize(f->get_len()); - - ERR_FAIL_COND_V(data.size()==0,RES()); - - { - DVector<uint8_t>::Write w = data.write(); - f->get_buffer(w.ptr(),data.size()); - } - - Ref<DynamicFontData> dfd; - dfd.instance(); - dfd->set_font_data(data); if (r_error) *r_error=OK; - return dfd; + return dfont; } void ResourceFormatLoaderDynamicFont::get_recognized_extensions(List<String> *p_extensions) const { p_extensions->push_back("ttf"); + p_extensions->push_back("otf"); } bool ResourceFormatLoaderDynamicFont::handles_type(const String& p_type) const { @@ -516,8 +573,10 @@ bool ResourceFormatLoaderDynamicFont::handles_type(const String& p_type) const { String ResourceFormatLoaderDynamicFont::get_resource_type(const String &p_path) const { String el = p_path.extension().to_lower(); - if (el=="ttf") + if (el=="ttf" || el=="otf") return "DynamicFontData"; return ""; } + +#endif |