summaryrefslogtreecommitdiff
path: root/scene/resources/dynamic_font.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'scene/resources/dynamic_font.cpp')
-rw-r--r--scene/resources/dynamic_font.cpp301
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