diff options
Diffstat (limited to 'editor/io_plugins/editor_font_import_plugin.cpp')
| -rw-r--r-- | editor/io_plugins/editor_font_import_plugin.cpp | 1704 |
1 files changed, 1704 insertions, 0 deletions
diff --git a/editor/io_plugins/editor_font_import_plugin.cpp b/editor/io_plugins/editor_font_import_plugin.cpp new file mode 100644 index 000000000..c792ad717 --- /dev/null +++ b/editor/io_plugins/editor_font_import_plugin.cpp @@ -0,0 +1,1704 @@ +/*************************************************************************/ +/* editor_font_import_plugin.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "editor_font_import_plugin.h" +#if 0 +#include "scene/gui/dialogs.h" +#include "editor/editor_file_dialog.h" +#include "editor/editor_node.h" +#include "os/file_access.h" +#include "editor_atlas.h" +#include "io/image_loader.h" +#include "io/resource_saver.h" + +#ifdef FREETYPE_ENABLED +#include <ft2build.h> +#include FT_FREETYPE_H +#endif + + +class _EditorFontImportOptions : public Object { + + GDCLASS(_EditorFontImportOptions,Object); +public: + + enum FontMode { + + FONT_BITMAP, + FONT_DISTANCE_FIELD + }; + + enum ColorType { + COLOR_WHITE, + COLOR_CUSTOM, + COLOR_GRADIENT_RANGE, + COLOR_GRADIENT_IMAGE + }; + + + int char_extra_spacing; + int top_extra_spacing; + int bottom_extra_spacing; + int space_extra_spacing; + + enum CharacterSet { + + CHARSET_ASCII, + CHARSET_LATIN, + CHARSET_UNICODE, + CHARSET_CUSTOM, + CHARSET_CUSTOM_LATIN + }; + + + FontMode font_mode; + + CharacterSet character_set; + String custom_file; + + bool shadow; + Vector2 shadow_offset; + int shadow_radius; + Color shadow_color; + float shadow_transition; + + bool shadow2; + Vector2 shadow2_offset; + int shadow2_radius; + Color shadow2_color; + float shadow2_transition; + + ColorType color_type; + Color color; + Color gradient_begin; + Color gradient_end; + bool color_use_monochrome; + String gradient_image; + + bool enable_filter; + bool round_advance; + bool premultiply_alpha; + + + + bool _set(const StringName& p_name, const Variant& p_value) { + + String n = p_name; + if (n=="mode/mode") { + font_mode=FontMode(int(p_value)); + _change_notify(); + } else if (n=="extra_space/char") + char_extra_spacing=p_value; + else if (n=="extra_space/space") + space_extra_spacing=p_value; + else if (n=="extra_space/top") + top_extra_spacing=p_value; + else if (n=="extra_space/bottom") + bottom_extra_spacing=p_value; + + else if (n=="character_set/mode") { + character_set=CharacterSet(int(p_value)); + _change_notify(); + } else if (n=="character_set/custom") + custom_file=p_value; + + else if (n=="shadow/enabled") { + shadow=p_value; + _change_notify(); + }else if (n=="shadow/radius") + shadow_radius=p_value; + else if (n=="shadow/offset") + shadow_offset=p_value; + else if (n=="shadow/color") + shadow_color=p_value; + else if (n=="shadow/transition") + shadow_transition=p_value; + + else if (n=="shadow2/enabled") { + shadow2=p_value; + _change_notify(); + }else if (n=="shadow2/radius") + shadow2_radius=p_value; + else if (n=="shadow2/offset") + shadow2_offset=p_value; + else if (n=="shadow2/color") + shadow2_color=p_value; + else if (n=="shadow2/transition") + shadow2_transition=p_value; + + else if (n=="color/mode") { + color_type=ColorType(int(p_value)); + _change_notify(); + }else if (n=="color/color") + color=p_value; + else if (n=="color/begin") + gradient_begin=p_value; + else if (n=="color/end") + gradient_end=p_value; + else if (n=="color/image") + gradient_image=p_value; + else if (n=="color/monochrome") + color_use_monochrome=p_value; + else if (n=="advanced/round_advance") + round_advance=p_value; + else if (n=="advanced/enable_filter") + enable_filter=p_value; + else if (n=="advanced/premultiply_alpha") + premultiply_alpha=p_value; + else + return false; + + emit_signal("changed"); + + + return true; + + } + + bool _get(const StringName& p_name,Variant &r_ret) const{ + + String n = p_name; + if (n=="mode/mode") + r_ret=font_mode; + else if (n=="extra_space/char") + r_ret=char_extra_spacing; + else if (n=="extra_space/space") + r_ret=space_extra_spacing; + else if (n=="extra_space/top") + r_ret=top_extra_spacing; + else if (n=="extra_space/bottom") + r_ret=bottom_extra_spacing; + + else if (n=="character_set/mode") + r_ret=character_set; + else if (n=="character_set/custom") + r_ret=custom_file; + + else if (n=="shadow/enabled") + r_ret=shadow; + else if (n=="shadow/radius") + r_ret=shadow_radius; + else if (n=="shadow/offset") + r_ret=shadow_offset; + else if (n=="shadow/color") + r_ret=shadow_color; + else if (n=="shadow/transition") + r_ret=shadow_transition; + + else if (n=="shadow2/enabled") + r_ret=shadow2; + else if (n=="shadow2/radius") + r_ret=shadow2_radius; + else if (n=="shadow2/offset") + r_ret=shadow2_offset; + else if (n=="shadow2/color") + r_ret=shadow2_color; + else if (n=="shadow2/transition") + r_ret=shadow2_transition; + + + else if (n=="color/mode") + r_ret=color_type; + else if (n=="color/color") + r_ret=color; + else if (n=="color/begin") + r_ret=gradient_begin; + else if (n=="color/end") + r_ret=gradient_end; + else if (n=="color/image") + r_ret=gradient_image; + else if (n=="color/monochrome") + r_ret=color_use_monochrome; + else if (n=="advanced/round_advance") + r_ret=round_advance; + else if (n=="advanced/enable_filter") + r_ret=enable_filter; + else if (n=="advanced/premultiply_alpha") + r_ret=premultiply_alpha; + else + return false; + + return true; + + } + + void _get_property_list( List<PropertyInfo> *p_list) const{ + + + p_list->push_back(PropertyInfo(Variant::INT,"mode/mode",PROPERTY_HINT_ENUM,"Bitmap,Distance Field")); + + p_list->push_back(PropertyInfo(Variant::INT,"extra_space/char",PROPERTY_HINT_RANGE,"-64,64,1")); + p_list->push_back(PropertyInfo(Variant::INT,"extra_space/space",PROPERTY_HINT_RANGE,"-64,64,1")); + p_list->push_back(PropertyInfo(Variant::INT,"extra_space/top",PROPERTY_HINT_RANGE,"-64,64,1")); + p_list->push_back(PropertyInfo(Variant::INT,"extra_space/bottom",PROPERTY_HINT_RANGE,"-64,64,1")); + p_list->push_back(PropertyInfo(Variant::INT,"character_set/mode",PROPERTY_HINT_ENUM,"Ascii,Latin,Unicode,Custom,Custom&Latin")); + + if (character_set>=CHARSET_CUSTOM) + p_list->push_back(PropertyInfo(Variant::STRING,"character_set/custom",PROPERTY_HINT_GLOBAL_FILE)); + + int usage = PROPERTY_USAGE_DEFAULT; + + if (font_mode==FONT_DISTANCE_FIELD) { + usage = PROPERTY_USAGE_NOEDITOR; + } + + { + + p_list->push_back(PropertyInfo(Variant::BOOL,"shadow/enabled",PROPERTY_HINT_NONE,"",usage)); + if (shadow) { + p_list->push_back(PropertyInfo(Variant::INT,"shadow/radius",PROPERTY_HINT_RANGE,"-64,64,1",usage)); + p_list->push_back(PropertyInfo(Variant::VECTOR2,"shadow/offset",PROPERTY_HINT_NONE,"",usage)); + p_list->push_back(PropertyInfo(Variant::COLOR,"shadow/color",PROPERTY_HINT_NONE,"",usage)); + p_list->push_back(PropertyInfo(Variant::REAL,"shadow/transition",PROPERTY_HINT_EXP_EASING,"",usage)); + } + + p_list->push_back(PropertyInfo(Variant::BOOL,"shadow2/enabled",PROPERTY_HINT_NONE,"",usage)); + if (shadow2) { + p_list->push_back(PropertyInfo(Variant::INT,"shadow2/radius",PROPERTY_HINT_RANGE,"-64,64,1",usage)); + p_list->push_back(PropertyInfo(Variant::VECTOR2,"shadow2/offset",PROPERTY_HINT_NONE,"",usage)); + p_list->push_back(PropertyInfo(Variant::COLOR,"shadow2/color",PROPERTY_HINT_NONE,"",usage)); + p_list->push_back(PropertyInfo(Variant::REAL,"shadow2/transition",PROPERTY_HINT_EXP_EASING,"",usage)); + } + + p_list->push_back(PropertyInfo(Variant::INT,"color/mode",PROPERTY_HINT_ENUM,"White,Color,Gradient,Gradient Image",usage)); + if (color_type==COLOR_CUSTOM) { + p_list->push_back(PropertyInfo(Variant::COLOR,"color/color",PROPERTY_HINT_NONE,"",usage)); + + } + if (color_type==COLOR_GRADIENT_RANGE) { + p_list->push_back(PropertyInfo(Variant::COLOR,"color/begin",PROPERTY_HINT_NONE,"",usage)); + p_list->push_back(PropertyInfo(Variant::COLOR,"color/end",PROPERTY_HINT_NONE,"",usage)); + } + if (color_type==COLOR_GRADIENT_IMAGE) { + p_list->push_back(PropertyInfo(Variant::STRING,"color/image",PROPERTY_HINT_GLOBAL_FILE,"",usage)); + } + p_list->push_back(PropertyInfo(Variant::BOOL,"color/monochrome",PROPERTY_HINT_NONE,"",usage)); + } + + p_list->push_back(PropertyInfo(Variant::BOOL,"advanced/round_advance")); + p_list->push_back(PropertyInfo(Variant::BOOL,"advanced/enable_filter")); + p_list->push_back(PropertyInfo(Variant::BOOL,"advanced/premultiply_alpha")); + + } + + + static void _bind_methods() { + + + ADD_SIGNAL( MethodInfo("changed")); + } + + + void reset() { + + char_extra_spacing=0; + top_extra_spacing=0; + bottom_extra_spacing=0; + space_extra_spacing=0; + + character_set=CHARSET_LATIN; + + shadow=false; + shadow_radius=2; + shadow_color=Color(0,0,0,0.3); + shadow_transition=1.0; + + shadow2=false; + shadow2_radius=2; + shadow2_color=Color(0,0,0,0.3); + shadow2_transition=1.0; + + color_type=COLOR_WHITE; + color=Color(1,1,1,1); + gradient_begin=Color(1,1,1,1); + gradient_end=Color(0.5,0.5,0.5,1); + color_use_monochrome=false; + + font_mode=FONT_BITMAP; + round_advance=true; + enable_filter=true; + premultiply_alpha=false; + + } + + _EditorFontImportOptions() { + + font_mode=FONT_BITMAP; + + char_extra_spacing=0; + top_extra_spacing=0; + bottom_extra_spacing=0; + space_extra_spacing=0; + + character_set=CHARSET_LATIN; + + shadow=false; + shadow_radius=2; + shadow_color=Color(0,0,0,0.3); + shadow_transition=1.0; + + shadow2=false; + shadow2_radius=2; + shadow2_color=Color(0,0,0,0.3); + shadow2_transition=1.0; + + color_type=COLOR_WHITE; + color=Color(1,1,1,1); + gradient_begin=Color(1,1,1,1); + gradient_end=Color(0.5,0.5,0.5,1); + color_use_monochrome=false; + + round_advance=true; + enable_filter=true; + premultiply_alpha=false; + } + + +}; + + +class EditorFontImportDialog : public ConfirmationDialog { + + GDCLASS(EditorFontImportDialog, ConfirmationDialog); + + + EditorLineEditFileChooser *source; + EditorLineEditFileChooser *dest; + SpinBox *font_size; + LineEdit *test_string; + ColorPickerButton *test_color; + Label *test_label; + PropertyEditor *prop_edit; + Timer *timer; + ConfirmationDialog *error_dialog; + + + Ref<ResourceImportMetadata> get_rimd() { + + Ref<ResourceImportMetadata> imd = memnew( ResourceImportMetadata ); + List<PropertyInfo> pl; + options->_get_property_list(&pl); + for(List<PropertyInfo>::Element *E=pl.front();E;E=E->next()) { + + Variant v; + String opt=E->get().name; + options->_get(opt,v); + if (opt=="color/image" || opt=="character_set/custom") { + v = EditorImportPlugin::validate_source_path(v); + } + imd->set_option(opt,v); + } + + String src_path = EditorImportPlugin::validate_source_path(source->get_line_edit()->get_text()); + //print_line("pre src path "+source->get_line_edit()->get_text()); + //print_line("src path "+src_path); + imd->add_source(src_path); + imd->set_option("font/size",font_size->get_value()); + + return imd; + + } + + void _src_changed(String) { + _prop_changed(); + } + + void _update_text2(String) { + _update_text(); + } + void _update_text3(Color) { + _update_text(); + } + + void _update_text() { + + test_label->set_text(""); + test_label->set_text(test_string->get_text()); + test_label->add_color_override("font_color",test_color->get_pick_color()); + } + + void _update() { + + Ref<ResourceImportMetadata> imd = get_rimd(); + Ref<BitmapFont> font = plugin->generate_font(imd); + test_label->add_font_override("font",font); + _update_text(); + } + + void _font_size_changed(double) { + + _prop_changed(); + } + + void _prop_changed() { + + timer->start(); + } + + void _import_inc(String p_font) { + + Ref<BitmapFont> font = ResourceLoader::load(p_font); + if (!font.is_valid()) + return; + Ref<ImageTexture> tex = font->get_texture(0); + if (tex.is_null()) + return; + FileAccessRef f=FileAccess::open(p_font.get_basename()+".inc",FileAccess::WRITE); + Vector<CharType> ck = font->get_char_keys(); + + f->store_line("static const int _builtin_font_height="+itos(font->get_height())+";"); + f->store_line("static const int _builtin_font_ascent="+itos(font->get_ascent())+";"); + f->store_line("static const int _builtin_font_charcount="+itos(ck.size())+";"); + f->store_line("static const int _builtin_font_charrects["+itos(ck.size())+"][8]={"); + f->store_line("/* charidx , ofs_x, ofs_y, size_x, size_y, valign, halign, advance */"); + + for(int i=0;i<ck.size();i++) { + CharType k=ck[i]; + BitmapFont::Character c=font->get_character(k); + f->store_line("{"+itos(k)+","+rtos(c.rect.pos.x)+","+rtos(c.rect.pos.y)+","+rtos(c.rect.size.x)+","+rtos(c.rect.size.y)+","+rtos(c.v_align)+","+rtos(c.h_align)+","+rtos(c.advance)+"},"); + } + f->store_line("};"); + + Vector<BitmapFont::KerningPairKey> kp=font->get_kerning_pair_keys(); + f->store_line("static const int _builtin_font_kerning_pair_count="+itos(kp.size())+";"); + f->store_line("static const int _builtin_font_kerning_pairs["+itos(kp.size())+"][3]={"); + for(int i=0;i<kp.size();i++) { + + int d = font->get_kerning_pair(kp[i].A,kp[i].B); + f->store_line("{"+itos(kp[i].A)+","+itos(kp[i].B)+","+itos(d)+"},"); + } + + f->store_line("};"); + Image img = tex->get_data(); + + f->store_line("static const int _builtin_font_img_width="+itos(img.get_width())+";"); + f->store_line("static const int _builtin_font_img_height="+itos(img.get_height())+";"); + + String fname = p_font.get_basename()+".sv.png"; + ResourceSaver::save(fname,tex); + Vector<uint8_t> data=FileAccess::get_file_as_array(fname); + + + f->store_line("static const int _builtin_font_img_data_size="+itos(data.size())+";"); + f->store_line("static const unsigned char _builtin_font_img_data["+itos(data.size())+"]={"); + + + + for(int i=0;i<data.size();i++) { + + f->store_line(itos(data[i])+","); + + } + f->store_line("};"); + + } + + void _import() { + + if (source->get_line_edit()->get_text()=="") { + error_dialog->set_text(TTR("No source font file!")); + error_dialog->popup_centered(Size2(200,100)*EDSCALE); + return; + } + + if (dest->get_line_edit()->get_text()=="") { + error_dialog->set_text(TTR("No target font resource!")); + error_dialog->popup_centered(Size2(200,100)*EDSCALE); + return; + } + + if (dest->get_line_edit()->get_text().get_file()==".fnt") { + dest->get_line_edit()->set_text(dest->get_line_edit()->get_text().get_base_dir() + "/" + source->get_line_edit()->get_text().get_file().get_basename() + ".fnt" ); + } + + if (dest->get_line_edit()->get_text().get_extension() == dest->get_line_edit()->get_text()) { + dest->get_line_edit()->set_text(dest->get_line_edit()->get_text() + ".fnt"); + } + + if (dest->get_line_edit()->get_text().get_extension().to_lower() != "fnt") { + error_dialog->set_text(TTR("Invalid file extension.\nPlease use .fnt.")); + error_dialog->popup_centered(Size2(200,100)); + return; + } + + Ref<ResourceImportMetadata> rimd = get_rimd(); + + if (rimd.is_null()) { + error_dialog->set_text(TTR("Can't load/process source font.")); + error_dialog->popup_centered(Size2(200,100)*EDSCALE); + return; + } + + Error err = plugin->import(dest->get_line_edit()->get_text(),rimd); + + if (err!=OK) { + error_dialog->set_text(TTR("Couldn't save font.")); + error_dialog->popup_centered(Size2(200,100)*EDSCALE); + return; + } + + _import_inc(dest->get_line_edit()->get_text()); + + hide(); + } + + EditorFontImportPlugin *plugin; + _EditorFontImportOptions *options; + + static void _bind_methods() { + + ClassDB::bind_method("_update",&EditorFontImportDialog::_update); + ClassDB::bind_method("_update_text",&EditorFontImportDialog::_update_text); + ClassDB::bind_method("_update_text2",&EditorFontImportDialog::_update_text2); + ClassDB::bind_method("_update_text3",&EditorFontImportDialog::_update_text3); + ClassDB::bind_method("_prop_changed",&EditorFontImportDialog::_prop_changed); + ClassDB::bind_method("_src_changed",&EditorFontImportDialog::_src_changed); + ClassDB::bind_method("_font_size_changed",&EditorFontImportDialog::_font_size_changed); + ClassDB::bind_method("_import",&EditorFontImportDialog::_import); + + } + +public: + + void _notification(int p_what) { + + if (p_what==NOTIFICATION_ENTER_TREE) { + prop_edit->edit(options); + _update_text(); + } + } + + void popup_import(const String& p_path) { + + popup_centered(Size2(600,500)*EDSCALE); + + if (p_path!="") { + + Ref<ResourceImportMetadata> rimd = ResourceLoader::load_import_metadata(p_path); + ERR_FAIL_COND(!rimd.is_valid()); + + dest->get_line_edit()->set_text(p_path); + List<String> opts; + rimd->get_options(&opts); + options->reset(); + for(List<String>::Element *E=opts.front();E;E=E->next()) { + + options->_set(E->get(),rimd->get_option(E->get())); + } + + String src = ""; + for(int i=0;i<rimd->get_source_count();i++) { + if (i>0) + src+=","; + src+=EditorImportPlugin::expand_source_path(rimd->get_source_path(i)); + } + source->get_line_edit()->set_text(src); + + font_size->set_value(rimd->get_option("font/size")); + } + } + + + void set_source_and_dest(const String& p_font,const String& p_dest) { + source->get_line_edit()->set_text(p_font); + dest->get_line_edit()->set_text(p_dest); + _prop_changed(); + } + + EditorFontImportDialog(EditorFontImportPlugin *p_plugin) { + plugin=p_plugin; + VBoxContainer *vbc = memnew( VBoxContainer ); + add_child(vbc); + //set_child_rect(vbc); + HBoxContainer *hbc = memnew( HBoxContainer); + vbc->add_child(hbc); + VBoxContainer *vbl = memnew( VBoxContainer ); + hbc->add_child(vbl); + hbc->set_v_size_flags(SIZE_EXPAND_FILL); + vbl->set_h_size_flags(SIZE_EXPAND_FILL); + VBoxContainer *vbr = memnew( VBoxContainer ); + hbc->add_child(vbr); + vbr->set_h_size_flags(SIZE_EXPAND_FILL); + + source = memnew( EditorLineEditFileChooser ); + source->get_file_dialog()->set_access(EditorFileDialog::ACCESS_FILESYSTEM); + source->get_file_dialog()->set_mode(EditorFileDialog::MODE_OPEN_FILE); + source->get_file_dialog()->add_filter("*.ttf;TrueType"); + source->get_file_dialog()->add_filter("*.otf;OpenType"); + source->get_file_dialog()->add_filter("*.fnt;BMFont"); + source->get_line_edit()->connect("text_entered",this,"_src_changed"); + + vbl->add_margin_child(TTR("Source Font:"),source); + font_size = memnew( SpinBox ); + vbl->add_margin_child(TTR("Source Font Size:"),font_size); + font_size->set_min(3); + font_size->set_max(256); + font_size->set_value(16); + font_size->connect("value_changed",this,"_font_size_changed"); + dest = memnew( EditorLineEditFileChooser ); + // + List<String> fl; + Ref<BitmapFont> font= memnew(BitmapFont); + dest->get_file_dialog()->add_filter("*.fnt ; Font" ); + /* + ResourceSaver::get_recognized_extensions(font,&fl); + for(List<String>::Element *E=fl.front();E;E=E->next()) { + dest->get_file_dialog()->add_filter("*."+E->get()); + } + */ + + vbl->add_margin_child(TTR("Dest Resource:"),dest); + HBoxContainer *testhb = memnew( HBoxContainer ); + test_string = memnew( LineEdit ); + test_string->set_text(TTR("The quick brown fox jumps over the lazy dog.")); + test_string->set_h_size_flags(SIZE_EXPAND_FILL); + test_string->set_stretch_ratio(5); + + testhb->add_child(test_string); + test_color = memnew( ColorPickerButton ); + test_color->set_pick_color(get_color("font_color","Label")); + test_color->set_h_size_flags(SIZE_EXPAND_FILL); + test_color->set_stretch_ratio(1); + test_color->connect("color_changed",this,"_update_text3"); + testhb->add_child(test_color); + + vbl->add_spacer(); + vbl->add_margin_child(TTR("Test:")+" ",testhb); + /* + HBoxContainer *upd_hb = memnew( HBoxContainer ); + //vbl->add_child(upd_hb); + upd_hb->add_spacer(); + Button *update = memnew( Button); + upd_hb->add_child(update); + update->set_text("Update"); + update->connect("pressed",this,"_update"); +*/ + options = memnew( _EditorFontImportOptions ); + prop_edit = memnew( PropertyEditor() ); + vbr->add_margin_child(TTR("Options:"),prop_edit,true); + options->connect("changed",this,"_prop_changed"); + + prop_edit->hide_top_label(); + + Panel *panel = memnew( Panel ); + vbc->add_child(panel); + test_label = memnew( Label ); + test_label->set_autowrap(true); + panel->add_child(test_label); + test_label->set_area_as_parent_rect(); + panel->set_v_size_flags(SIZE_EXPAND_FILL); + test_string->connect("text_changed",this,"_update_text2"); + set_title(TTR("Font Import")); + timer = memnew( Timer ); + add_child(timer); + timer->connect("timeout",this,"_update"); + timer->set_wait_time(0.4); + timer->set_one_shot(true); + + get_ok()->connect("pressed", this,"_import"); + get_ok()->set_text(TTR("Import")); + + error_dialog = memnew ( ConfirmationDialog ); + add_child(error_dialog); + error_dialog->get_ok()->set_text(TTR("Accept")); + set_hide_on_ok(false); + + + } + + ~EditorFontImportDialog() { + memdelete(options); + } +}; + + +/////////////////////////////////////// + + + +struct _EditorFontData { + + Vector<uint8_t> bitmap; + int width,height; + int ofs_x; //ofset to center, from ABOVE + int ofs_y; //ofset to begining, from LEFT + int valign; //vertical alignment + int halign; + float advance; + int character; + int glyph; + + int texture; + Image blit; + Point2i blit_ofs; + //bool printable; + +}; + + +struct _EditorFontDataSort { + + bool operator()(const _EditorFontData *p_A,const _EditorFontData *p_B) const { + return p_A->height > p_B->height; + }; +}; + +struct _EditorKerningKey { + + CharType A,B; + bool operator<(const _EditorKerningKey& p_k) const { return (A==p_k.A)?(B<p_k.B):(A<p_k.A); } + +}; + + +static unsigned char get_SDF_radial( + unsigned char *fontmap, + int w, int h, + int x, int y, + int max_radius ) +{ + //hideous brute force method + float d2 = max_radius*max_radius+1.0; + unsigned char v = fontmap[x+y*w]; + for( int radius = 1; (radius <= max_radius) && (radius*radius < d2); ++radius ) + { + int line, lo, hi; + //north + line = y - radius; + if( (line >= 0) && (line < h) ) + { + lo = x - radius; + hi = x + radius; + if( lo < 0 ) { lo = 0; } + if( hi >= w ) { hi = w-1; } + int idx = line * w + lo; + for( int i = lo; i <= hi; ++i ) + { + //check this pixel + if( fontmap[idx] != v ) + { + float nx = i - x; + float ny = line - y; + float nd2 = nx*nx+ny*ny; + if( nd2 < d2 ) + { + d2 = nd2; + } + } + //move on + ++idx; + } + } + //south + line = y + radius; + if( (line >= 0) && (line < h) ) + { + lo = x - radius; + hi = x + radius; + if( lo < 0 ) { lo = 0; } + if( hi >= w ) { hi = w-1; } + int idx = line * w + lo; + for( int i = lo; i <= hi; ++i ) + { + //check this pixel + if( fontmap[idx] != v ) + { + float nx = i - x; + float ny = line - y; + float nd2 = nx*nx+ny*ny; + if( nd2 < d2 ) + { + d2 = nd2; + } + } + //move on + ++idx; + } + } + //west + line = x - radius; + if( (line >= 0) && (line < w) ) + { + lo = y - radius + 1; + hi = y + radius - 1; + if( lo < 0 ) { lo = 0; } + if( hi >= h ) { hi = h-1; } + int idx = lo * w + line; + for( int i = lo; i <= hi; ++i ) + { + //check this pixel + if( fontmap[idx] != v ) + { + float nx = line - x; + float ny = i - y; + float nd2 = nx*nx+ny*ny; + if( nd2 < d2 ) + { + d2 = nd2; + } + } + //move on + idx += w; + } + } + //east + line = x + radius; + if( (line >= 0) && (line < w) ) + { + lo = y - radius + 1; + hi = y + radius - 1; + if( lo < 0 ) { lo = 0; } + if( hi >= h ) { hi = h-1; } + int idx = lo * w + line; + for( int i = lo; i <= hi; ++i ) + { + //check this pixel + if( fontmap[idx] != v ) + { + float nx = line - x; + float ny = i - y; + float nd2 = nx*nx+ny*ny; + if( nd2 < d2 ) + { + d2 = nd2; + } + } + //move on + idx += w; + } + } + } + d2 = sqrtf( d2 ); + if( v==0 ) + { + d2 = -d2; + } + d2 *= 127.5 / max_radius; + d2 += 127.5; + if( d2 < 0.0 ) d2 = 0.0; + if( d2 > 255.0 ) d2 = 255.0; + return (unsigned char)(d2 + 0.5); +} + + +Ref<BitmapFont> EditorFontImportPlugin::generate_font(const Ref<ResourceImportMetadata>& p_from, const String &p_existing) { + + + + Ref<ResourceImportMetadata> from = p_from; + ERR_FAIL_COND_V(from->get_source_count()!=1,Ref<BitmapFont>()); + + String src_path = EditorImportPlugin::expand_source_path(from->get_source_path(0)); + + if (src_path.get_extension().to_lower()=="fnt") { + + if (ResourceLoader::load(src_path).is_valid()) { + EditorNode::get_singleton()->show_warning(TTR("Path:")+" "+src_path+"\n"+TTR("This file is already a Godot font file, please supply a BMFont type file instead.")); + return Ref<BitmapFont>(); + } + + Ref<BitmapFont> font; + font.instance(); + Error err = font->create_from_fnt(src_path); + if (err) { + EditorNode::get_singleton()->show_warning(TTR("Path:")+" "+src_path+"\n"+TTR("Failed opening as BMFont file.")); + return Ref<BitmapFont>(); + } + + return font; + } + + int size = from->get_option("font/size"); + +#ifdef FREETYPE_ENABLED + FT_Library library; /* handle to library */ + FT_Face face; /* handle to face object */ + + Vector<_EditorFontData*> font_data_list; + + int error = FT_Init_FreeType( &library ); + + ERR_EXPLAIN(TTR("Error initializing FreeType.")); + ERR_FAIL_COND_V( error !=0, Ref<BitmapFont>() ); + + print_line("loadfrom: "+src_path); + 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,Ref<BitmapFont>()); + + + int height=0; + int ascent=0; + int font_spacing=0; + + 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,Ref<BitmapFont>() ); + + } + + int font_mode = from->get_option("mode/mode"); + + int scaler=(font_mode==_EditorFontImportOptions::FONT_DISTANCE_FIELD)?16:1; + + error = FT_Set_Pixel_Sizes(face,0,size*scaler); + + FT_GlyphSlot slot = face->glyph; + + //error = FT_Set_Charmap(face,ft_encoding_unicode ); /* encoding.. */ + + + /* PRINT CHARACTERS TO INDIVIDUAL BITMAPS */ + + + //int space_size=5; //size for space, if none found.. 5! + //int min_valign=500; //some ridiculous number + + FT_ULong charcode; + FT_UInt gindex; + + int max_up=-1324345; ///gibberish + int max_down=124232; + + Map<_EditorKerningKey,int> kerning_map; + + charcode = FT_Get_First_Char( face, &gindex ); + + Set<CharType> import_chars; + + int import_mode = from->get_option("character_set/mode"); + bool round_advance = from->get_option("advanced/round_advance"); + + if (import_mode>=_EditorFontImportOptions::CHARSET_CUSTOM) { + + //load from custom text + String path = from->get_option("character_set/custom"); + + FileAccess *fa = FileAccess::open(EditorImportPlugin::expand_source_path(path),FileAccess::READ); + + if ( !fa ) { + + FT_Done_FreeType( library ); + ERR_EXPLAIN(TTR("Invalid font custom source.")); + ERR_FAIL_COND_V( !fa,Ref<BitmapFont>() ); + + } + + + while(!fa->eof_reached()) { + + String line = fa->get_line(); + for(int i=0;i<line.length();i++) { + import_chars.insert(line[i]); + } + } + + if (import_mode==_EditorFontImportOptions::CHARSET_CUSTOM_LATIN) { + + for(int i=32;i<128;i++) + import_chars.insert(i); + } + + memdelete(fa); + } + + int xsize=0; + while ( gindex != 0 ) + { + + bool skip=false; + error = FT_Load_Char( face, charcode, font_mode==_EditorFontImportOptions::FONT_BITMAP?FT_LOAD_RENDER:FT_LOAD_MONOCHROME ); + if (error) skip=true; + else error = FT_Render_Glyph( face->glyph, font_mode==_EditorFontImportOptions::FONT_BITMAP?ft_render_mode_normal:ft_render_mode_mono ); + if (error) { + skip=true; + } else if (!skip) { + + switch(import_mode) { + + case _EditorFontImportOptions::CHARSET_ASCII: skip = charcode>127; break; + case _EditorFontImportOptions::CHARSET_LATIN: skip = charcode>255 ;break; + case _EditorFontImportOptions::CHARSET_UNICODE: break; //none + case _EditorFontImportOptions::CHARSET_CUSTOM: + case _EditorFontImportOptions::CHARSET_CUSTOM_LATIN: skip = !import_chars.has(charcode); break; + + } + } + + if (charcode<=32) //?? + skip=true; + + if (skip) { + charcode=FT_Get_Next_Char(face,charcode,&gindex); + continue; + } + + _EditorFontData * fdata = memnew( _EditorFontData ); + + + int w = slot->bitmap.width; + int h = slot->bitmap.rows; + int p = slot->bitmap.pitch; + + //print_line("W: "+itos(w)+" P: "+itos(slot->bitmap.pitch)); + + if (font_mode==_EditorFontImportOptions::FONT_DISTANCE_FIELD) { + + //oversize the holding buffer so I can smooth it! + int sw = w + scaler * 4; + int sh = h + scaler * 4; + //do the SDF + int sdfw = sw / scaler; + int sdfh = sh / scaler; + + fdata->width=sdfw; + fdata->height=sdfh; + } else { + fdata->width=w; + fdata->height=h; + } + + fdata->character=charcode; + fdata->glyph=FT_Get_Char_Index(face,charcode); + if (charcode=='x') + xsize=w/scaler; + + + + fdata->valign=slot->bitmap_top; + fdata->halign=slot->bitmap_left; + + if (round_advance) + fdata->advance=(slot->advance.x+(1<<5))>>6; + else + fdata->advance=slot->advance.x/float(1<<6); + + if (font_mode==_EditorFontImportOptions::FONT_DISTANCE_FIELD) { + + fdata->halign = fdata->halign / scaler - 1.5; + fdata->valign = fdata->valign / scaler + 1.5; + fdata->advance/=scaler; + + } + + fdata->advance+=font_spacing; + + + if (charcode<127) { + int top = fdata->valign; + int hmax = h/scaler; + + if (top>max_up) { + + max_up=top; + } + + + if ( (top - hmax)<max_down ) { + + max_down=top - hmax; + } + } + + if (font_mode==_EditorFontImportOptions::FONT_DISTANCE_FIELD) { + + + //oversize the holding buffer so I can smooth it! + int sw = w + scaler * 4; + int sh = h + scaler * 4; + + unsigned char *smooth_buf = new unsigned char[sw*sh]; + + for( int i = 0; i < sw*sh; ++i ) { + smooth_buf[i] = 0; + } + + // copy the glyph into the buffer to be smoothed + unsigned char *buf = slot->bitmap.buffer; + for( int j = 0; j < h; ++j ) { + for( int i = 0; i < w; ++i ) { + smooth_buf[scaler*2+i+(j+scaler*2)*sw] = 255 * ((buf[j*p+(i>>3)] >> (7 - (i & 7))) & 1); + } + } + + // do the SDF + int sdfw = fdata->width; + int sdfh = fdata->height; + + fdata->bitmap.resize( sdfw*sdfh ); + + for( int j = 0; j < sdfh; ++j ) { + for( int i = 0; i < sdfw; ++i ) { + int pd_idx = j*sdfw+i; + + //fdata->bitmap[j*slot->bitmap.width+i]=slot->bitmap.buffer[j*slot->bitmap.width+i]; + + fdata->bitmap[pd_idx] = + //get_SDF + get_SDF_radial + ( smooth_buf, sw, sh, + i*scaler + (scaler >>1), j*scaler + (scaler >>1), + 2*scaler ); + + } + } + + delete [] smooth_buf; + + } else { + fdata->bitmap.resize( slot->bitmap.width*slot->bitmap.rows ); + for (int i=0;i<slot->bitmap.width;i++) { + for (int j=0;j<slot->bitmap.rows;j++) { + + fdata->bitmap[j*slot->bitmap.width+i]=slot->bitmap.buffer[j*slot->bitmap.width+i]; + } + } + } + + font_data_list.push_back(fdata); + charcode=FT_Get_Next_Char(face,charcode,&gindex); +// printf("reading char %i\n",charcode); + } + + /* SPACE */ + + _EditorFontData *spd = memnew( _EditorFontData ); + spd->advance=0; + spd->character=' '; + spd->halign=0; + spd->valign=0; + spd->width=0; + spd->height=0; + spd->ofs_x=0; + spd->ofs_y=0; + + if (!FT_Load_Char( face, ' ', FT_LOAD_RENDER ) && !FT_Render_Glyph( face->glyph, font_mode==_EditorFontImportOptions::FONT_BITMAP?ft_render_mode_normal:ft_render_mode_mono )) { + + spd->advance = slot->advance.x>>6; //round to nearest or store as float + spd->advance/=scaler; + spd->advance+=font_spacing; + } else { + + spd->advance=xsize; + spd->advance+=font_spacing; + } + + font_data_list.push_back(spd); + + Set<CharType> exported; + for (int i=0; i<font_data_list.size(); i++) { + exported.insert(font_data_list[i]->character); + }; + int missing = 0; + for(Set<CharType>::Element *E=import_chars.front();E;E=E->next()) { + CharType c = E->get(); + if (!exported.has(c)) { + CharType str[2] = {c, 0}; + printf("** Warning: character %i (%ls) not exported\n", (int)c, str); + ++missing; + }; + }; + print_line("total_chars: "+itos(font_data_list.size())); + + /* KERNING */ + + + for(int i=0;i<font_data_list.size();i++) { + + if (font_data_list[i]->character>512) + continue; + for(int j=0;j<font_data_list.size();j++) { + + if (font_data_list[j]->character>512) + continue; + + FT_Vector delta; + FT_Get_Kerning( face, font_data_list[i]->glyph,font_data_list[j]->glyph, FT_KERNING_DEFAULT, &delta ); + + if (delta.x!=0) { + + _EditorKerningKey kpk; + kpk.A = font_data_list[i]->character; + kpk.B = font_data_list[j]->character; + int kern = ((-delta.x)+(1<<5))>>6; + + if (kern==0) + continue; + kerning_map[kpk]=kern/scaler; + } + } + } + + height=max_up-max_down; + ascent=max_up; + + /* FIND OUT WHAT THE FONT HEIGHT FOR THIS IS */ + + /* ADJUST THE VALIGN FOR EACH CHARACTER */ + + for (int i=0;i<(int)font_data_list.size();i++) { + + font_data_list[i]->valign=max_up-font_data_list[i]->valign; + } + + + + /* ADD THE SPACEBAR CHARACTER */ +/* + _EditorFontData * fdata = new _EditorFontData; + + fdata->character=32; + fdata->bitmap=0; + fdata->width=xsize; + fdata->height=1; + fdata->valign=0; + + font_data_list.push_back(fdata); +*/ + /* SORT BY HEIGHT, SO THEY FIT BETTER ON THE TEXTURE */ + + font_data_list.sort_custom<_EditorFontDataSort>(); + Color *color=memnew_arr(Color,height); + + int gradient_type=from->get_option("color/mode"); + switch(gradient_type) { + case _EditorFontImportOptions::COLOR_WHITE: { + + for(int i=0;i<height;i++){ + color[i]=Color(1,1,1,1); + } + + } break; + case _EditorFontImportOptions::COLOR_CUSTOM: { + + Color cc = from->get_option("color/color"); + for(int i=0;i<height;i++){ + color[i]=cc; + } + + } break; + case _EditorFontImportOptions::COLOR_GRADIENT_RANGE: { + + Color src=from->get_option("color/begin"); + Color to=from->get_option("color/end"); + for(int i=0;i<height;i++){ + color[i]=src.linear_interpolate(to,i/float(height)); + } + + } break; + case _EditorFontImportOptions::COLOR_GRADIENT_IMAGE: { + + String fp = EditorImportPlugin::expand_source_path(from->get_option("color/image")); + Image img; + Error err = ImageLoader::load_image(fp,&img); + if (err==OK) { + + for(int i=0;i<height;i++){ + //color[i]=img.get_pixel(0,i*img.get_height()/height); + } + } else { + + for(int i=0;i<height;i++){ + color[i]=Color(1,1,1,1); + } + } + + } break; + } + + + for(int i=0;i<font_data_list.size();i++) { + + if (font_data_list[i]->bitmap.size()==0) + continue; + + int margin[4]={0,0,0,0}; + + if (from->get_option("shadow/enabled").operator bool()) { + int r=from->get_option("shadow/radius"); + Point2i ofs=Point2(from->get_option("shadow/offset")); + margin[ MARGIN_LEFT ] = MAX( r - ofs.x, 0); + margin[ MARGIN_RIGHT ] = MAX( r + ofs.x, 0); + margin[ MARGIN_TOP ] = MAX( r - ofs.y, 0); + margin[ MARGIN_BOTTOM ] = MAX( r + ofs.y, 0); + + } + + if (from->get_option("shadow2/enabled").operator bool()) { + int r=from->get_option("shadow2/radius"); + Point2i ofs=Point2(from->get_option("shadow2/offset")); + margin[ MARGIN_LEFT ] = MAX( r - ofs.x, margin[ MARGIN_LEFT ]); + margin[ MARGIN_RIGHT ] = MAX( r + ofs.x, margin[ MARGIN_RIGHT ]); + margin[ MARGIN_TOP ] = MAX( r - ofs.y, margin[ MARGIN_TOP ]); + margin[ MARGIN_BOTTOM ] = MAX( r + ofs.y, margin[ MARGIN_BOTTOM ]); + + } + + Size2i s; + s.width=font_data_list[i]->width+margin[MARGIN_LEFT]+margin[MARGIN_RIGHT]; + s.height=font_data_list[i]->height+margin[MARGIN_TOP]+margin[MARGIN_BOTTOM]; + Point2i o; + o.x=margin[MARGIN_LEFT]; + o.y=margin[MARGIN_TOP]; + + int ow=font_data_list[i]->width; + int oh=font_data_list[i]->height; + + PoolVector<uint8_t> pixels; + pixels.resize(s.x*s.y*4); + + PoolVector<uint8_t>::Write w = pixels.write(); + //print_line("val: "+itos(font_data_list[i]->valign)); + for(int y=0;y<s.height;y++) { + + int yc=CLAMP(y-o.y+font_data_list[i]->valign,0,height-1); + Color c=color[yc]; + c.a=0; + + for(int x=0;x<s.width;x++) { + + int ofs=y*s.x+x; + w[ofs*4+0]=c.r*255.0; + w[ofs*4+1]=c.g*255.0; + w[ofs*4+2]=c.b*255.0; + w[ofs*4+3]=c.a*255.0; + } + } + + + for(int si=0;si<2;si++) { + +#define S_VAR(m_v) (String(si==0?"shadow/":"shadow2/")+m_v) + if (from->get_option(S_VAR("enabled")).operator bool()) { + int r = from->get_option(S_VAR("radius")); + + Color sc = from->get_option(S_VAR("color")); + Point2i so=Point2(from->get_option(S_VAR("offset"))); + + float tr = from->get_option(S_VAR("transition")); + print_line("shadow enabled: "+itos(si)); + + Vector<uint8_t> s2buf; + s2buf.resize(s.x*s.y); + uint8_t *wa=s2buf.ptr(); + + for(int j=0;j<s.x*s.y;j++){ + + wa[j]=0; + } + + // blit shadowa + for(int x=0;x<ow;x++) { + for(int y=0;y<oh;y++) { + int ofs = (o.y+y+so.y)*s.x+x+o.x+so.x; + wa[ofs]=font_data_list[i]->bitmap[y*ow+x]; + } + } + //blur shadow2 with separatable convolution + + if (r>0) { + + Vector<uint8_t> pixels2; + pixels2.resize(s2buf.size()); + uint8_t *w2=pixels2.ptr(); + //vert + for(int x=0;x<s.width;x++) { + for(int y=0;y<s.height;y++) { + + int ofs = y*s.width+x; + int sum=wa[ofs]; + + for(int k=1;k<=r;k++) { + + int ofs_d=MIN(y+k,s.height-1)*s.width+x; + int ofs_u=MAX(y-k,0)*s.width+x; + sum+=wa[ofs_d]; + sum+=wa[ofs_u]; + } + + w2[ofs]=sum/(r*2+1); + + } + } + //horiz + for(int x=0;x<s.width;x++) { + for(int y=0;y<s.height;y++) { + + int ofs = y*s.width+x; + int sum=w2[ofs]; + + for(int k=1;k<=r;k++) { + + int ofs_r=MIN(x+k,s.width-1)+s.width*y; + int ofs_l=MAX(x-k,0)+s.width*y; + sum+=w2[ofs_r]; + sum+=w2[ofs_l]; + } + + wa[ofs]=Math::pow(float(sum/(r*2+1))/255.0f,tr)*255.0f; + + } + } + + } + + //blend back + + for(int j=0;j<s.x*s.y;j++){ + Color wd(w[j*4+0]/255.0,w[j*4+1]/255.0,w[j*4+2]/255.0,w[j*4+3]/255.0); + Color ws(sc.r,sc.g,sc.b,sc.a*(wa[j]/255.0)); + Color b = wd.blend(ws); + + w[j*4+0]=b.r*255.0; + w[j*4+1]=b.g*255.0; + w[j*4+2]=b.b*255.0; + w[j*4+3]=b.a*255.0; + + } + } + } + + for(int y=0;y<oh;y++) { + int yc=CLAMP(y+font_data_list[i]->valign,0,height-1); + Color sc=color[yc]; + for(int x=0;x<ow;x++) { + int ofs = (o.y+y)*s.x+x+o.x; + float c = font_data_list[i]->bitmap[y*ow+x]/255.0; + Color src_col=sc; + src_col.a*=c; + Color dst_col(w[ofs*4+0]/255.0,w[ofs*4+1]/255.0,w[ofs*4+2]/255.0,w[ofs*4+3]/255.0); + dst_col = dst_col.blend(src_col); + w[ofs*4+0]=dst_col.r*255.0; + w[ofs*4+1]=dst_col.g*255.0; + w[ofs*4+2]=dst_col.b*255.0; + w[ofs*4+3]=dst_col.a*255.0; + } + } + + + w=PoolVector<uint8_t>::Write(); + + Image img(s.width,s.height,0,Image::FORMAT_RGBA8,pixels); + + font_data_list[i]->blit=img; + font_data_list[i]->blit_ofs=o; + + } + + //make atlas + int spacing=2; + Vector<Size2i> sizes; + sizes.resize(font_data_list.size()); + for(int i=0;i<font_data_list.size();i++) { + + sizes[i]=Size2(font_data_list[i]->blit.get_width()+spacing*2,font_data_list[i]->blit.get_height()+spacing*2); + + } + Vector<Point2i> res; + Size2i res_size; + EditorAtlas::fit(sizes,res,res_size); + res_size.x=nearest_power_of_2(res_size.x); + res_size.y=nearest_power_of_2(res_size.y); + print_line("Atlas size: "+res_size); + + Image atlas(res_size.x,res_size.y,0,Image::FORMAT_RGBA8); + + for(int i=0;i<font_data_list.size();i++) { + + if (font_data_list[i]->bitmap.size()==0) + continue; + atlas.blit_rect(font_data_list[i]->blit,Rect2(0,0,font_data_list[i]->blit.get_width(),font_data_list[i]->blit.get_height()),res[i]+Size2(spacing,spacing)); + font_data_list[i]->ofs_x=res[i].x+spacing; + font_data_list[i]->ofs_y=res[i].y+spacing; + + + } + + if (from->has_option("advanced/premultiply_alpha") && bool(from->get_option("advanced/premultiply_alpha"))) { + + PoolVector<uint8_t> data = atlas.get_data(); + int dl = data.size(); + { + PoolVector<uint8_t>::Write w = data.write(); + + for(int i=0;i<dl;i+=4) { + + w[i+0]= uint8_t(int(w[i+0])*int(w[i+3])/255); + w[i+1]= uint8_t(int(w[i+1])*int(w[i+3])/255); + w[i+2]= uint8_t(int(w[i+2])*int(w[i+3])/255); + } + } + + atlas=Image(res_size.x,res_size.y,0,Image::FORMAT_RGBA8,data); + } + + if (from->has_option("color/monochrome") && bool(from->get_option("color/monochrome"))) { + + atlas.convert(Image::FORMAT_LA8); + } + + + if (0) { + //debug the texture + Ref<ImageTexture> atlast = memnew( ImageTexture ); + atlast->create_from_image(atlas); + //atlast->create_from_image(font_data_list[5]->blit); + TextureRect *tf = memnew( TextureRect ); + tf->set_texture(atlast); + dialog->add_child(tf); + } + + + /* CREATE FONT */ + + int char_space = from->get_option("extra_space/char"); + int space_space = from->get_option("extra_space/space"); + int top_space = from->get_option("extra_space/top"); + int bottom_space = from->get_option("extra_space/bottom"); + bool enable_filter = from->get_option("advanced/enable_filter"); + if (from->has_option("advanced/disable_filter")){ // this is a compatibility check for a deprecated option + enable_filter = !from->get_option("advanced/disable_filter"); + } + + Ref<BitmapFont> font; + + if (p_existing!=String() && ResourceCache::has(p_existing)) { + + font = Ref<BitmapFont>( ResourceCache::get(p_existing)->cast_to<BitmapFont>()); + } + + if (font.is_null()) { + font = Ref<BitmapFont>( memnew( BitmapFont ) ); + } + + font->clear(); + font->set_height(height+bottom_space+top_space); + font->set_ascent(ascent+top_space); + font->set_distance_field_hint(font_mode==_EditorFontImportOptions::FONT_DISTANCE_FIELD); + + //register texures + { + Ref<ImageTexture> t = memnew(ImageTexture); + int flags; + if (!enable_filter) + flags=0; + else + flags=Texture::FLAG_FILTER; + t->create_from_image(atlas,flags); + t->set_storage( ImageTexture::STORAGE_COMPRESS_LOSSLESS ); + font->add_texture(t); + + } + //register characters + + + for(int i=0;i<font_data_list.size();i++) { + _EditorFontData *fd=font_data_list[i]; + int tex_idx=0; + + font->add_char(fd->character,tex_idx,Rect2( fd->ofs_x, fd->ofs_y, fd->blit.get_width(), fd->blit.get_height()),Point2(fd->halign-fd->blit_ofs.x,fd->valign-fd->blit_ofs.y+top_space), fd->advance+char_space+(fd->character==' '?space_space:0)); + memdelete(fd); + } + + for(Map<_EditorKerningKey,int>::Element *E=kerning_map.front();E;E=E->next()) { + + font->add_kerning_pair(E->key().A,E->key().B,E->get()); + } + + FT_Done_FreeType( library ); + + return font; +#else + + return Ref<BitmapFont>(); +#endif +} + + +String EditorFontImportPlugin::get_name() const { + + return "font"; +} +String EditorFontImportPlugin::get_visible_name() const{ + + return TTR("Font"); +} +void EditorFontImportPlugin::import_dialog(const String& p_from){ + + dialog->popup_import(p_from); +} +Error EditorFontImportPlugin::import(const String& p_path, const Ref<ResourceImportMetadata>& p_from){ + + + Ref<BitmapFont> font = EditorFontImportPlugin::generate_font(p_from,p_path); + if (!font.is_valid()) + return ERR_CANT_CREATE; + + Ref<ResourceImportMetadata> from=p_from; + from->set_source_md5(0,FileAccess::get_md5(EditorImportPlugin::expand_source_path(from->get_source_path(0)))); + from->set_editor(get_name()); + font->set_import_metadata(from); + + return ResourceSaver::save(p_path,font); + +} + +void EditorFontImportPlugin::import_from_drop(const Vector<String>& p_drop, const String &p_dest_path) { + + for(int i=0;i<p_drop.size();i++) { + String ext = p_drop[i].get_extension().to_lower(); + String file = p_drop[i].get_file(); + if (ext=="ttf" || ext=="otf" || ext=="fnt") { + + import_dialog(); + dialog->set_source_and_dest(p_drop[i],p_dest_path.plus_file(file.get_basename()+".fnt")); + break; + } + } +} + + +EditorFontImportPlugin::EditorFontImportPlugin(EditorNode* p_editor) { + + dialog = memnew( EditorFontImportDialog(this) ); + p_editor->get_gui_base()->add_child(dialog); +} +#endif |
