editor_font_import_plugin.cpp 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617
  1. /*************************************************************************/
  2. /* editor_font_import_plugin.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /*************************************************************************/
  30. #include "editor_font_import_plugin.h"
  31. #include "editor/editor_file_dialog.h"
  32. #include "editor/editor_node.h"
  33. #include "editor_atlas.h"
  34. #include "io/image_loader.h"
  35. #include "io/resource_saver.h"
  36. #include "os/file_access.h"
  37. #include "scene/gui/dialogs.h"
  38. #ifdef FREETYPE_ENABLED
  39. #include <ft2build.h>
  40. #include FT_FREETYPE_H
  41. #endif
  42. class _EditorFontImportOptions : public Object {
  43. OBJ_TYPE(_EditorFontImportOptions, Object);
  44. public:
  45. enum FontMode {
  46. FONT_BITMAP,
  47. FONT_DISTANCE_FIELD
  48. };
  49. enum ColorType {
  50. COLOR_WHITE,
  51. COLOR_CUSTOM,
  52. COLOR_GRADIENT_RANGE,
  53. COLOR_GRADIENT_IMAGE
  54. };
  55. int char_extra_spacing;
  56. int top_extra_spacing;
  57. int bottom_extra_spacing;
  58. int space_extra_spacing;
  59. enum CharacterSet {
  60. CHARSET_ASCII,
  61. CHARSET_LATIN,
  62. CHARSET_UNICODE,
  63. CHARSET_CUSTOM,
  64. CHARSET_CUSTOM_LATIN
  65. };
  66. FontMode font_mode;
  67. CharacterSet character_set;
  68. String custom_file;
  69. bool shadow;
  70. Vector2 shadow_offset;
  71. int shadow_radius;
  72. Color shadow_color;
  73. float shadow_transition;
  74. bool shadow2;
  75. Vector2 shadow2_offset;
  76. int shadow2_radius;
  77. Color shadow2_color;
  78. float shadow2_transition;
  79. ColorType color_type;
  80. Color color;
  81. Color gradient_begin;
  82. Color gradient_end;
  83. bool color_use_monochrome;
  84. String gradient_image;
  85. bool disable_filter;
  86. bool round_advance;
  87. bool premultiply_alpha;
  88. bool _set(const StringName &p_name, const Variant &p_value) {
  89. String n = p_name;
  90. if (n == "mode/mode") {
  91. font_mode = FontMode(int(p_value));
  92. _change_notify();
  93. } else if (n == "extra_space/char")
  94. char_extra_spacing = p_value;
  95. else if (n == "extra_space/space")
  96. space_extra_spacing = p_value;
  97. else if (n == "extra_space/top")
  98. top_extra_spacing = p_value;
  99. else if (n == "extra_space/bottom")
  100. bottom_extra_spacing = p_value;
  101. else if (n == "character_set/mode") {
  102. character_set = CharacterSet(int(p_value));
  103. _change_notify();
  104. } else if (n == "character_set/custom")
  105. custom_file = p_value;
  106. else if (n == "shadow/enabled") {
  107. shadow = p_value;
  108. _change_notify();
  109. } else if (n == "shadow/radius")
  110. shadow_radius = p_value;
  111. else if (n == "shadow/offset")
  112. shadow_offset = p_value;
  113. else if (n == "shadow/color")
  114. shadow_color = p_value;
  115. else if (n == "shadow/transition")
  116. shadow_transition = p_value;
  117. else if (n == "shadow2/enabled") {
  118. shadow2 = p_value;
  119. _change_notify();
  120. } else if (n == "shadow2/radius")
  121. shadow2_radius = p_value;
  122. else if (n == "shadow2/offset")
  123. shadow2_offset = p_value;
  124. else if (n == "shadow2/color")
  125. shadow2_color = p_value;
  126. else if (n == "shadow2/transition")
  127. shadow2_transition = p_value;
  128. else if (n == "color/mode") {
  129. color_type = ColorType(int(p_value));
  130. _change_notify();
  131. } else if (n == "color/color")
  132. color = p_value;
  133. else if (n == "color/begin")
  134. gradient_begin = p_value;
  135. else if (n == "color/end")
  136. gradient_end = p_value;
  137. else if (n == "color/image")
  138. gradient_image = p_value;
  139. else if (n == "color/monochrome")
  140. color_use_monochrome = p_value;
  141. else if (n == "advanced/round_advance")
  142. round_advance = p_value;
  143. else if (n == "advanced/disable_filter")
  144. disable_filter = p_value;
  145. else if (n == "advanced/premultiply_alpha")
  146. premultiply_alpha = p_value;
  147. else
  148. return false;
  149. emit_signal("changed");
  150. return true;
  151. }
  152. bool _get(const StringName &p_name, Variant &r_ret) const {
  153. String n = p_name;
  154. if (n == "mode/mode")
  155. r_ret = font_mode;
  156. else if (n == "extra_space/char")
  157. r_ret = char_extra_spacing;
  158. else if (n == "extra_space/space")
  159. r_ret = space_extra_spacing;
  160. else if (n == "extra_space/top")
  161. r_ret = top_extra_spacing;
  162. else if (n == "extra_space/bottom")
  163. r_ret = bottom_extra_spacing;
  164. else if (n == "character_set/mode")
  165. r_ret = character_set;
  166. else if (n == "character_set/custom")
  167. r_ret = custom_file;
  168. else if (n == "shadow/enabled")
  169. r_ret = shadow;
  170. else if (n == "shadow/radius")
  171. r_ret = shadow_radius;
  172. else if (n == "shadow/offset")
  173. r_ret = shadow_offset;
  174. else if (n == "shadow/color")
  175. r_ret = shadow_color;
  176. else if (n == "shadow/transition")
  177. r_ret = shadow_transition;
  178. else if (n == "shadow2/enabled")
  179. r_ret = shadow2;
  180. else if (n == "shadow2/radius")
  181. r_ret = shadow2_radius;
  182. else if (n == "shadow2/offset")
  183. r_ret = shadow2_offset;
  184. else if (n == "shadow2/color")
  185. r_ret = shadow2_color;
  186. else if (n == "shadow2/transition")
  187. r_ret = shadow2_transition;
  188. else if (n == "color/mode")
  189. r_ret = color_type;
  190. else if (n == "color/color")
  191. r_ret = color;
  192. else if (n == "color/begin")
  193. r_ret = gradient_begin;
  194. else if (n == "color/end")
  195. r_ret = gradient_end;
  196. else if (n == "color/image")
  197. r_ret = gradient_image;
  198. else if (n == "color/monochrome")
  199. r_ret = color_use_monochrome;
  200. else if (n == "advanced/round_advance")
  201. r_ret = round_advance;
  202. else if (n == "advanced/disable_filter")
  203. r_ret = disable_filter;
  204. else if (n == "advanced/premultiply_alpha")
  205. r_ret = premultiply_alpha;
  206. else
  207. return false;
  208. return true;
  209. }
  210. void _get_property_list(List<PropertyInfo> *p_list) const {
  211. p_list->push_back(PropertyInfo(Variant::INT, "mode/mode", PROPERTY_HINT_ENUM, "Bitmap,Distance Field"));
  212. p_list->push_back(PropertyInfo(Variant::INT, "extra_space/char", PROPERTY_HINT_RANGE, "-64,64,1"));
  213. p_list->push_back(PropertyInfo(Variant::INT, "extra_space/space", PROPERTY_HINT_RANGE, "-64,64,1"));
  214. p_list->push_back(PropertyInfo(Variant::INT, "extra_space/top", PROPERTY_HINT_RANGE, "-64,64,1"));
  215. p_list->push_back(PropertyInfo(Variant::INT, "extra_space/bottom", PROPERTY_HINT_RANGE, "-64,64,1"));
  216. p_list->push_back(PropertyInfo(Variant::INT, "character_set/mode", PROPERTY_HINT_ENUM, "Ascii,Latin,Unicode,Custom,Custom&Latin"));
  217. if (character_set >= CHARSET_CUSTOM)
  218. p_list->push_back(PropertyInfo(Variant::STRING, "character_set/custom", PROPERTY_HINT_GLOBAL_FILE));
  219. int usage = PROPERTY_USAGE_DEFAULT;
  220. if (font_mode == FONT_DISTANCE_FIELD) {
  221. usage = PROPERTY_USAGE_NOEDITOR;
  222. }
  223. {
  224. p_list->push_back(PropertyInfo(Variant::BOOL, "shadow/enabled", PROPERTY_HINT_NONE, "", usage));
  225. if (shadow) {
  226. p_list->push_back(PropertyInfo(Variant::INT, "shadow/radius", PROPERTY_HINT_RANGE, "-64,64,1", usage));
  227. p_list->push_back(PropertyInfo(Variant::VECTOR2, "shadow/offset", PROPERTY_HINT_NONE, "", usage));
  228. p_list->push_back(PropertyInfo(Variant::COLOR, "shadow/color", PROPERTY_HINT_NONE, "", usage));
  229. p_list->push_back(PropertyInfo(Variant::REAL, "shadow/transition", PROPERTY_HINT_EXP_EASING, "", usage));
  230. }
  231. p_list->push_back(PropertyInfo(Variant::BOOL, "shadow2/enabled", PROPERTY_HINT_NONE, "", usage));
  232. if (shadow2) {
  233. p_list->push_back(PropertyInfo(Variant::INT, "shadow2/radius", PROPERTY_HINT_RANGE, "-64,64,1", usage));
  234. p_list->push_back(PropertyInfo(Variant::VECTOR2, "shadow2/offset", PROPERTY_HINT_NONE, "", usage));
  235. p_list->push_back(PropertyInfo(Variant::COLOR, "shadow2/color", PROPERTY_HINT_NONE, "", usage));
  236. p_list->push_back(PropertyInfo(Variant::REAL, "shadow2/transition", PROPERTY_HINT_EXP_EASING, "", usage));
  237. }
  238. p_list->push_back(PropertyInfo(Variant::INT, "color/mode", PROPERTY_HINT_ENUM, "White,Color,Gradient,Gradient Image", usage));
  239. if (color_type == COLOR_CUSTOM) {
  240. p_list->push_back(PropertyInfo(Variant::COLOR, "color/color", PROPERTY_HINT_NONE, "", usage));
  241. }
  242. if (color_type == COLOR_GRADIENT_RANGE) {
  243. p_list->push_back(PropertyInfo(Variant::COLOR, "color/begin", PROPERTY_HINT_NONE, "", usage));
  244. p_list->push_back(PropertyInfo(Variant::COLOR, "color/end", PROPERTY_HINT_NONE, "", usage));
  245. }
  246. if (color_type == COLOR_GRADIENT_IMAGE) {
  247. p_list->push_back(PropertyInfo(Variant::STRING, "color/image", PROPERTY_HINT_GLOBAL_FILE, "", usage));
  248. }
  249. p_list->push_back(PropertyInfo(Variant::BOOL, "color/monochrome", PROPERTY_HINT_NONE, "", usage));
  250. }
  251. p_list->push_back(PropertyInfo(Variant::BOOL, "advanced/round_advance"));
  252. p_list->push_back(PropertyInfo(Variant::BOOL, "advanced/disable_filter"));
  253. p_list->push_back(PropertyInfo(Variant::BOOL, "advanced/premultiply_alpha"));
  254. }
  255. static void _bind_methods() {
  256. ADD_SIGNAL(MethodInfo("changed"));
  257. }
  258. void reset() {
  259. char_extra_spacing = 0;
  260. top_extra_spacing = 0;
  261. bottom_extra_spacing = 0;
  262. space_extra_spacing = 0;
  263. character_set = CHARSET_LATIN;
  264. shadow = false;
  265. shadow_radius = 2;
  266. shadow_color = Color(0, 0, 0, 0.3);
  267. shadow_transition = 1.0;
  268. shadow2 = false;
  269. shadow2_radius = 2;
  270. shadow2_color = Color(0, 0, 0, 0.3);
  271. shadow2_transition = 1.0;
  272. color_type = COLOR_WHITE;
  273. color = Color(1, 1, 1, 1);
  274. gradient_begin = Color(1, 1, 1, 1);
  275. gradient_end = Color(0.5, 0.5, 0.5, 1);
  276. color_use_monochrome = false;
  277. font_mode = FONT_BITMAP;
  278. round_advance = true;
  279. disable_filter = false;
  280. premultiply_alpha = false;
  281. }
  282. _EditorFontImportOptions() {
  283. font_mode = FONT_BITMAP;
  284. char_extra_spacing = 0;
  285. top_extra_spacing = 0;
  286. bottom_extra_spacing = 0;
  287. space_extra_spacing = 0;
  288. character_set = CHARSET_LATIN;
  289. shadow = false;
  290. shadow_radius = 2;
  291. shadow_color = Color(0, 0, 0, 0.3);
  292. shadow_transition = 1.0;
  293. shadow2 = false;
  294. shadow2_radius = 2;
  295. shadow2_color = Color(0, 0, 0, 0.3);
  296. shadow2_transition = 1.0;
  297. color_type = COLOR_WHITE;
  298. color = Color(1, 1, 1, 1);
  299. gradient_begin = Color(1, 1, 1, 1);
  300. gradient_end = Color(0.5, 0.5, 0.5, 1);
  301. color_use_monochrome = false;
  302. round_advance = true;
  303. disable_filter = false;
  304. premultiply_alpha = false;
  305. }
  306. };
  307. class EditorFontImportDialog : public ConfirmationDialog {
  308. OBJ_TYPE(EditorFontImportDialog, ConfirmationDialog);
  309. EditorLineEditFileChooser *source;
  310. EditorLineEditFileChooser *dest;
  311. SpinBox *font_size;
  312. LineEdit *test_string;
  313. ColorPickerButton *test_color;
  314. Label *test_label;
  315. PropertyEditor *prop_edit;
  316. Timer *timer;
  317. ConfirmationDialog *error_dialog;
  318. Ref<ResourceImportMetadata> get_rimd() {
  319. Ref<ResourceImportMetadata> imd = memnew(ResourceImportMetadata);
  320. List<PropertyInfo> pl;
  321. options->_get_property_list(&pl);
  322. for (List<PropertyInfo>::Element *E = pl.front(); E; E = E->next()) {
  323. Variant v;
  324. String opt = E->get().name;
  325. options->_get(opt, v);
  326. if (opt == "color/image" || opt == "character_set/custom") {
  327. v = EditorImportPlugin::validate_source_path(v);
  328. }
  329. imd->set_option(opt, v);
  330. }
  331. String src_path = EditorImportPlugin::validate_source_path(source->get_line_edit()->get_text());
  332. //print_line("pre src path "+source->get_line_edit()->get_text());
  333. //print_line("src path "+src_path);
  334. imd->add_source(src_path);
  335. imd->set_option("font/size", font_size->get_val());
  336. return imd;
  337. }
  338. void _src_changed(String) {
  339. _prop_changed();
  340. }
  341. void _update_text2(String) {
  342. _update_text();
  343. }
  344. void _update_text3(Color) {
  345. _update_text();
  346. }
  347. void _update_text() {
  348. test_label->set_text("");
  349. test_label->set_text(test_string->get_text());
  350. test_label->add_color_override("font_color", test_color->get_color());
  351. }
  352. void _update() {
  353. Ref<ResourceImportMetadata> imd = get_rimd();
  354. Ref<BitmapFont> font = plugin->generate_font(imd);
  355. test_label->add_font_override("font", font);
  356. _update_text();
  357. }
  358. void _font_size_changed(double) {
  359. _prop_changed();
  360. }
  361. void _prop_changed() {
  362. timer->start();
  363. }
  364. void _import_inc(String p_font) {
  365. Ref<BitmapFont> font = ResourceLoader::load(p_font);
  366. if (!font.is_valid())
  367. return;
  368. Ref<ImageTexture> tex = font->get_texture(0);
  369. if (tex.is_null())
  370. return;
  371. FileAccessRef f = FileAccess::open(p_font.basename() + ".inc", FileAccess::WRITE);
  372. Vector<CharType> ck = font->get_char_keys();
  373. f->store_line("static const int _builtin_font_height=" + itos(font->get_height()) + ";");
  374. f->store_line("static const int _builtin_font_ascent=" + itos(font->get_ascent()) + ";");
  375. f->store_line("static const int _builtin_font_charcount=" + itos(ck.size()) + ";");
  376. f->store_line("static const int _builtin_font_charrects[" + itos(ck.size()) + "][8]={");
  377. f->store_line("/* charidx , ofs_x, ofs_y, size_x, size_y, valign, halign, advance */");
  378. for (int i = 0; i < ck.size(); i++) {
  379. CharType k = ck[i];
  380. BitmapFont::Character c = font->get_character(k);
  381. 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) + "},");
  382. }
  383. f->store_line("};");
  384. Vector<BitmapFont::KerningPairKey> kp = font->get_kerning_pair_keys();
  385. f->store_line("static const int _builtin_font_kerning_pair_count=" + itos(kp.size()) + ";");
  386. f->store_line("static const int _builtin_font_kerning_pairs[" + itos(kp.size()) + "][3]={");
  387. for (int i = 0; i < kp.size(); i++) {
  388. int d = font->get_kerning_pair(kp[i].A, kp[i].B);
  389. f->store_line("{" + itos(kp[i].A) + "," + itos(kp[i].B) + "," + itos(d) + "},");
  390. }
  391. f->store_line("};");
  392. Image img = tex->get_data();
  393. f->store_line("static const int _builtin_font_img_width=" + itos(img.get_width()) + ";");
  394. f->store_line("static const int _builtin_font_img_height=" + itos(img.get_height()) + ";");
  395. String fname = p_font.basename() + ".sv.png";
  396. ResourceSaver::save(fname, tex);
  397. Vector<uint8_t> data = FileAccess::get_file_as_array(fname);
  398. f->store_line("static const int _builtin_font_img_data_size=" + itos(data.size()) + ";");
  399. f->store_line("static const unsigned char _builtin_font_img_data[" + itos(data.size()) + "]={");
  400. for (int i = 0; i < data.size(); i++) {
  401. f->store_line(itos(data[i]) + ",");
  402. }
  403. f->store_line("};");
  404. }
  405. void _import() {
  406. if (source->get_line_edit()->get_text() == "") {
  407. error_dialog->set_text(TTR("No source font file!"));
  408. error_dialog->popup_centered(Size2(200, 100) * EDSCALE);
  409. return;
  410. }
  411. if (dest->get_line_edit()->get_text() == "") {
  412. error_dialog->set_text(TTR("No target font resource!"));
  413. error_dialog->popup_centered(Size2(200, 100) * EDSCALE);
  414. return;
  415. }
  416. if (dest->get_line_edit()->get_text().get_file() == ".fnt") {
  417. dest->get_line_edit()->set_text(dest->get_line_edit()->get_text().get_base_dir() + "/" + source->get_line_edit()->get_text().get_file().basename() + ".fnt");
  418. }
  419. if (dest->get_line_edit()->get_text().extension() == dest->get_line_edit()->get_text()) {
  420. dest->get_line_edit()->set_text(dest->get_line_edit()->get_text() + ".fnt");
  421. }
  422. if (dest->get_line_edit()->get_text().extension().to_lower() != "fnt") {
  423. error_dialog->set_text(TTR("Invalid file extension.\nPlease use .fnt."));
  424. error_dialog->popup_centered(Size2(200, 100));
  425. return;
  426. }
  427. Ref<ResourceImportMetadata> rimd = get_rimd();
  428. if (rimd.is_null()) {
  429. error_dialog->set_text(TTR("Can't load/process source font."));
  430. error_dialog->popup_centered(Size2(200, 100) * EDSCALE);
  431. return;
  432. }
  433. Error err = plugin->import(dest->get_line_edit()->get_text(), rimd);
  434. if (err != OK) {
  435. error_dialog->set_text(TTR("Couldn't save font."));
  436. error_dialog->popup_centered(Size2(200, 100) * EDSCALE);
  437. return;
  438. }
  439. _import_inc(dest->get_line_edit()->get_text());
  440. hide();
  441. }
  442. EditorFontImportPlugin *plugin;
  443. _EditorFontImportOptions *options;
  444. static void _bind_methods() {
  445. ObjectTypeDB::bind_method("_update", &EditorFontImportDialog::_update);
  446. ObjectTypeDB::bind_method("_update_text", &EditorFontImportDialog::_update_text);
  447. ObjectTypeDB::bind_method("_update_text2", &EditorFontImportDialog::_update_text2);
  448. ObjectTypeDB::bind_method("_update_text3", &EditorFontImportDialog::_update_text3);
  449. ObjectTypeDB::bind_method("_prop_changed", &EditorFontImportDialog::_prop_changed);
  450. ObjectTypeDB::bind_method("_src_changed", &EditorFontImportDialog::_src_changed);
  451. ObjectTypeDB::bind_method("_font_size_changed", &EditorFontImportDialog::_font_size_changed);
  452. ObjectTypeDB::bind_method("_import", &EditorFontImportDialog::_import);
  453. }
  454. public:
  455. void _notification(int p_what) {
  456. if (p_what == NOTIFICATION_ENTER_TREE) {
  457. prop_edit->edit(options);
  458. _update_text();
  459. }
  460. }
  461. void popup_import(const String &p_path) {
  462. popup_centered(Size2(600, 500) * EDSCALE);
  463. if (p_path != "") {
  464. Ref<ResourceImportMetadata> rimd = ResourceLoader::load_import_metadata(p_path);
  465. ERR_FAIL_COND(!rimd.is_valid());
  466. dest->get_line_edit()->set_text(p_path);
  467. List<String> opts;
  468. rimd->get_options(&opts);
  469. options->reset();
  470. for (List<String>::Element *E = opts.front(); E; E = E->next()) {
  471. options->_set(E->get(), rimd->get_option(E->get()));
  472. }
  473. String src = "";
  474. for (int i = 0; i < rimd->get_source_count(); i++) {
  475. if (i > 0)
  476. src += ",";
  477. src += EditorImportPlugin::expand_source_path(rimd->get_source_path(i));
  478. }
  479. source->get_line_edit()->set_text(src);
  480. font_size->set_val(rimd->get_option("font/size"));
  481. }
  482. }
  483. void set_source_and_dest(const String &p_font, const String &p_dest) {
  484. source->get_line_edit()->set_text(p_font);
  485. dest->get_line_edit()->set_text(p_dest);
  486. _prop_changed();
  487. }
  488. EditorFontImportDialog(EditorFontImportPlugin *p_plugin) {
  489. plugin = p_plugin;
  490. VBoxContainer *vbc = memnew(VBoxContainer);
  491. add_child(vbc);
  492. set_child_rect(vbc);
  493. HBoxContainer *hbc = memnew(HBoxContainer);
  494. vbc->add_child(hbc);
  495. VBoxContainer *vbl = memnew(VBoxContainer);
  496. hbc->add_child(vbl);
  497. hbc->set_v_size_flags(SIZE_EXPAND_FILL);
  498. vbl->set_h_size_flags(SIZE_EXPAND_FILL);
  499. VBoxContainer *vbr = memnew(VBoxContainer);
  500. hbc->add_child(vbr);
  501. vbr->set_h_size_flags(SIZE_EXPAND_FILL);
  502. source = memnew(EditorLineEditFileChooser);
  503. source->get_file_dialog()->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
  504. source->get_file_dialog()->set_mode(EditorFileDialog::MODE_OPEN_FILE);
  505. source->get_file_dialog()->add_filter("*.ttf;TrueType");
  506. source->get_file_dialog()->add_filter("*.otf;OpenType");
  507. source->get_file_dialog()->add_filter("*.fnt;BMFont");
  508. source->get_line_edit()->connect("text_entered", this, "_src_changed");
  509. vbl->add_margin_child(TTR("Source Font:"), source);
  510. font_size = memnew(SpinBox);
  511. vbl->add_margin_child(TTR("Source Font Size:"), font_size);
  512. font_size->set_min(3);
  513. font_size->set_max(256);
  514. font_size->set_val(16);
  515. font_size->connect("value_changed", this, "_font_size_changed");
  516. dest = memnew(EditorLineEditFileChooser);
  517. //
  518. List<String> fl;
  519. Ref<BitmapFont> font = memnew(BitmapFont);
  520. dest->get_file_dialog()->add_filter("*.fnt ; Font");
  521. //ResourceSaver::get_recognized_extensions(font,&fl);
  522. //for(List<String>::Element *E=fl.front();E;E=E->next()) {
  523. // dest->get_file_dialog()->add_filter("*."+E->get());
  524. //}
  525. vbl->add_margin_child(TTR("Dest Resource:"), dest);
  526. HBoxContainer *testhb = memnew(HBoxContainer);
  527. test_string = memnew(LineEdit);
  528. test_string->set_text(TTR("The quick brown fox jumps over the lazy dog."));
  529. test_string->set_h_size_flags(SIZE_EXPAND_FILL);
  530. test_string->set_stretch_ratio(5);
  531. testhb->add_child(test_string);
  532. test_color = memnew(ColorPickerButton);
  533. test_color->set_color(get_color("font_color", "Label"));
  534. test_color->set_h_size_flags(SIZE_EXPAND_FILL);
  535. test_color->set_stretch_ratio(1);
  536. test_color->connect("color_changed", this, "_update_text3");
  537. testhb->add_child(test_color);
  538. vbl->add_spacer();
  539. vbl->add_margin_child(TTR("Test:") + " ", testhb);
  540. /*
  541. HBoxContainer *upd_hb = memnew( HBoxContainer );
  542. // vbl->add_child(upd_hb);
  543. upd_hb->add_spacer();
  544. Button *update = memnew( Button);
  545. upd_hb->add_child(update);
  546. update->set_text("Update");
  547. update->connect("pressed",this,"_update");
  548. */
  549. options = memnew(_EditorFontImportOptions);
  550. prop_edit = memnew(PropertyEditor());
  551. vbr->add_margin_child(TTR("Options:"), prop_edit, true);
  552. options->connect("changed", this, "_prop_changed");
  553. prop_edit->hide_top_label();
  554. Panel *panel = memnew(Panel);
  555. vbc->add_child(panel);
  556. test_label = memnew(Label);
  557. test_label->set_autowrap(true);
  558. panel->add_child(test_label);
  559. test_label->set_area_as_parent_rect();
  560. panel->set_v_size_flags(SIZE_EXPAND_FILL);
  561. test_string->connect("text_changed", this, "_update_text2");
  562. set_title(TTR("Font Import"));
  563. timer = memnew(Timer);
  564. add_child(timer);
  565. timer->connect("timeout", this, "_update");
  566. timer->set_wait_time(0.4);
  567. timer->set_one_shot(true);
  568. get_ok()->connect("pressed", this, "_import");
  569. get_ok()->set_text(TTR("Import"));
  570. error_dialog = memnew(ConfirmationDialog);
  571. add_child(error_dialog);
  572. error_dialog->get_ok()->set_text(TTR("Accept"));
  573. set_hide_on_ok(false);
  574. }
  575. ~EditorFontImportDialog() {
  576. memdelete(options);
  577. }
  578. };
  579. ///////////////////////////////////////
  580. struct _EditorFontData {
  581. Vector<uint8_t> bitmap;
  582. int width, height;
  583. int ofs_x; //ofset to center, from ABOVE
  584. int ofs_y; //ofset to begining, from LEFT
  585. int valign; //vertical alignment
  586. int halign;
  587. float advance;
  588. int character;
  589. int glyph;
  590. int texture;
  591. Image blit;
  592. Point2i blit_ofs;
  593. // bool printable;
  594. };
  595. struct _EditorFontDataSort {
  596. bool operator()(const _EditorFontData *p_A, const _EditorFontData *p_B) const {
  597. return p_A->height > p_B->height;
  598. };
  599. };
  600. struct _EditorKerningKey {
  601. CharType A, B;
  602. bool operator<(const _EditorKerningKey &p_k) const { return (A == p_k.A) ? (B < p_k.B) : (A < p_k.A); }
  603. };
  604. static unsigned char get_SDF_radial(
  605. unsigned char *fontmap,
  606. int w, int h,
  607. int x, int y,
  608. int max_radius) {
  609. // hideous brute force method
  610. float d2 = max_radius * max_radius + 1.0;
  611. unsigned char v = fontmap[x + y * w];
  612. for (int radius = 1; (radius <= max_radius) && (radius * radius < d2); ++radius) {
  613. int line, lo, hi;
  614. // north
  615. line = y - radius;
  616. if ((line >= 0) && (line < h)) {
  617. lo = x - radius;
  618. hi = x + radius;
  619. if (lo < 0) {
  620. lo = 0;
  621. }
  622. if (hi >= w) {
  623. hi = w - 1;
  624. }
  625. int idx = line * w + lo;
  626. for (int i = lo; i <= hi; ++i) {
  627. // check this pixel
  628. if (fontmap[idx] != v) {
  629. float nx = i - x;
  630. float ny = line - y;
  631. float nd2 = nx * nx + ny * ny;
  632. if (nd2 < d2) {
  633. d2 = nd2;
  634. }
  635. }
  636. // move on
  637. ++idx;
  638. }
  639. }
  640. // south
  641. line = y + radius;
  642. if ((line >= 0) && (line < h)) {
  643. lo = x - radius;
  644. hi = x + radius;
  645. if (lo < 0) {
  646. lo = 0;
  647. }
  648. if (hi >= w) {
  649. hi = w - 1;
  650. }
  651. int idx = line * w + lo;
  652. for (int i = lo; i <= hi; ++i) {
  653. // check this pixel
  654. if (fontmap[idx] != v) {
  655. float nx = i - x;
  656. float ny = line - y;
  657. float nd2 = nx * nx + ny * ny;
  658. if (nd2 < d2) {
  659. d2 = nd2;
  660. }
  661. }
  662. // move on
  663. ++idx;
  664. }
  665. }
  666. // west
  667. line = x - radius;
  668. if ((line >= 0) && (line < w)) {
  669. lo = y - radius + 1;
  670. hi = y + radius - 1;
  671. if (lo < 0) {
  672. lo = 0;
  673. }
  674. if (hi >= h) {
  675. hi = h - 1;
  676. }
  677. int idx = lo * w + line;
  678. for (int i = lo; i <= hi; ++i) {
  679. // check this pixel
  680. if (fontmap[idx] != v) {
  681. float nx = line - x;
  682. float ny = i - y;
  683. float nd2 = nx * nx + ny * ny;
  684. if (nd2 < d2) {
  685. d2 = nd2;
  686. }
  687. }
  688. // move on
  689. idx += w;
  690. }
  691. }
  692. // east
  693. line = x + radius;
  694. if ((line >= 0) && (line < w)) {
  695. lo = y - radius + 1;
  696. hi = y + radius - 1;
  697. if (lo < 0) {
  698. lo = 0;
  699. }
  700. if (hi >= h) {
  701. hi = h - 1;
  702. }
  703. int idx = lo * w + line;
  704. for (int i = lo; i <= hi; ++i) {
  705. // check this pixel
  706. if (fontmap[idx] != v) {
  707. float nx = line - x;
  708. float ny = i - y;
  709. float nd2 = nx * nx + ny * ny;
  710. if (nd2 < d2) {
  711. d2 = nd2;
  712. }
  713. }
  714. // move on
  715. idx += w;
  716. }
  717. }
  718. }
  719. d2 = sqrtf(d2);
  720. if (v == 0) {
  721. d2 = -d2;
  722. }
  723. d2 *= 127.5 / max_radius;
  724. d2 += 127.5;
  725. if (d2 < 0.0) d2 = 0.0;
  726. if (d2 > 255.0) d2 = 255.0;
  727. return (unsigned char)(d2 + 0.5);
  728. }
  729. Ref<BitmapFont> EditorFontImportPlugin::generate_font(const Ref<ResourceImportMetadata> &p_from, const String &p_existing) {
  730. Ref<ResourceImportMetadata> from = p_from;
  731. ERR_FAIL_COND_V(from->get_source_count() != 1, Ref<BitmapFont>());
  732. String src_path = EditorImportPlugin::expand_source_path(from->get_source_path(0));
  733. if (src_path.extension().to_lower() == "fnt") {
  734. if (ResourceLoader::load(src_path).is_valid()) {
  735. 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."));
  736. return Ref<BitmapFont>();
  737. }
  738. Ref<BitmapFont> font;
  739. font.instance();
  740. Error err = font->create_from_fnt(src_path);
  741. if (err) {
  742. EditorNode::get_singleton()->show_warning(TTR("Path:") + " " + src_path + "\n" + TTR("Failed opening as BMFont file."));
  743. return Ref<BitmapFont>();
  744. }
  745. return font;
  746. }
  747. int size = from->get_option("font/size");
  748. #ifdef FREETYPE_ENABLED
  749. FT_Library library; /* handle to library */
  750. FT_Face face; /* handle to face object */
  751. Vector<_EditorFontData *> font_data_list;
  752. int error = FT_Init_FreeType(&library);
  753. ERR_EXPLAIN(TTR("Error initializing FreeType."));
  754. ERR_FAIL_COND_V(error != 0, Ref<BitmapFont>());
  755. print_line("loadfrom: " + src_path);
  756. error = FT_New_Face(library, src_path.utf8().get_data(), 0, &face);
  757. if (error == FT_Err_Unknown_File_Format) {
  758. ERR_EXPLAIN(TTR("Unknown font format."));
  759. FT_Done_FreeType(library);
  760. } else if (error) {
  761. ERR_EXPLAIN(TTR("Error loading font."));
  762. FT_Done_FreeType(library);
  763. }
  764. ERR_FAIL_COND_V(error, Ref<BitmapFont>());
  765. int height = 0;
  766. int ascent = 0;
  767. int font_spacing = 0;
  768. error = FT_Set_Char_Size(face, 0, 64 * size, 512, 512);
  769. if (error) {
  770. FT_Done_FreeType(library);
  771. ERR_EXPLAIN(TTR("Invalid font size."));
  772. ERR_FAIL_COND_V(error, Ref<BitmapFont>());
  773. }
  774. int font_mode = from->get_option("mode/mode");
  775. int scaler = (font_mode == _EditorFontImportOptions::FONT_DISTANCE_FIELD) ? 16 : 1;
  776. error = FT_Set_Pixel_Sizes(face, 0, size * scaler);
  777. FT_GlyphSlot slot = face->glyph;
  778. // error = FT_Set_Charmap(face,ft_encoding_unicode ); /* encoding.. */
  779. /* PRINT CHARACTERS TO INDIVIDUAL BITMAPS */
  780. // int space_size=5; //size for space, if none found.. 5!
  781. // int min_valign=500; //some ridiculous number
  782. FT_ULong charcode;
  783. FT_UInt gindex;
  784. int max_up = -1324345; ///gibberish
  785. int max_down = 124232;
  786. Map<_EditorKerningKey, int> kerning_map;
  787. charcode = FT_Get_First_Char(face, &gindex);
  788. Set<CharType> import_chars;
  789. int import_mode = from->get_option("character_set/mode");
  790. bool round_advance = from->get_option("advanced/round_advance");
  791. if (import_mode >= _EditorFontImportOptions::CHARSET_CUSTOM) {
  792. //load from custom text
  793. String path = from->get_option("character_set/custom");
  794. FileAccess *fa = FileAccess::open(EditorImportPlugin::expand_source_path(path), FileAccess::READ);
  795. if (!fa) {
  796. FT_Done_FreeType(library);
  797. ERR_EXPLAIN(TTR("Invalid font custom source."));
  798. ERR_FAIL_COND_V(!fa, Ref<BitmapFont>());
  799. }
  800. while (!fa->eof_reached()) {
  801. String line = fa->get_line();
  802. for (int i = 0; i < line.length(); i++) {
  803. import_chars.insert(line[i]);
  804. }
  805. }
  806. if (import_mode == _EditorFontImportOptions::CHARSET_CUSTOM_LATIN) {
  807. for (int i = 32; i < 128; i++)
  808. import_chars.insert(i);
  809. }
  810. memdelete(fa);
  811. }
  812. int xsize = 0;
  813. while (gindex != 0) {
  814. bool skip = false;
  815. error = FT_Load_Char(face, charcode, font_mode == _EditorFontImportOptions::FONT_BITMAP ? FT_LOAD_RENDER : FT_LOAD_MONOCHROME);
  816. if (error)
  817. skip = true;
  818. else
  819. error = FT_Render_Glyph(face->glyph, font_mode == _EditorFontImportOptions::FONT_BITMAP ? ft_render_mode_normal : ft_render_mode_mono);
  820. if (error) {
  821. skip = true;
  822. } else if (!skip) {
  823. switch (import_mode) {
  824. case _EditorFontImportOptions::CHARSET_ASCII: skip = charcode > 127; break;
  825. case _EditorFontImportOptions::CHARSET_LATIN: skip = charcode > 255; break;
  826. case _EditorFontImportOptions::CHARSET_UNICODE:
  827. break; //none
  828. case _EditorFontImportOptions::CHARSET_CUSTOM:
  829. case _EditorFontImportOptions::CHARSET_CUSTOM_LATIN: skip = !import_chars.has(charcode); break;
  830. }
  831. }
  832. if (charcode <= 32) //??
  833. skip = true;
  834. if (skip) {
  835. charcode = FT_Get_Next_Char(face, charcode, &gindex);
  836. continue;
  837. }
  838. _EditorFontData *fdata = memnew(_EditorFontData);
  839. int w = slot->bitmap.width;
  840. int h = slot->bitmap.rows;
  841. int p = slot->bitmap.pitch;
  842. //print_line("W: "+itos(w)+" P: "+itos(slot->bitmap.pitch));
  843. if (font_mode == _EditorFontImportOptions::FONT_DISTANCE_FIELD) {
  844. // oversize the holding buffer so I can smooth it!
  845. int sw = w + scaler * 4;
  846. int sh = h + scaler * 4;
  847. // do the SDF
  848. int sdfw = sw / scaler;
  849. int sdfh = sh / scaler;
  850. fdata->width = sdfw;
  851. fdata->height = sdfh;
  852. } else {
  853. fdata->width = w;
  854. fdata->height = h;
  855. }
  856. fdata->character = charcode;
  857. fdata->glyph = FT_Get_Char_Index(face, charcode);
  858. if (charcode == 'x')
  859. xsize = w / scaler;
  860. fdata->valign = slot->bitmap_top;
  861. fdata->halign = slot->bitmap_left;
  862. if (round_advance)
  863. fdata->advance = (slot->advance.x + (1 << 5)) >> 6;
  864. else
  865. fdata->advance = slot->advance.x / float(1 << 6);
  866. if (font_mode == _EditorFontImportOptions::FONT_DISTANCE_FIELD) {
  867. fdata->halign = fdata->halign / scaler - 1.5;
  868. fdata->valign = fdata->valign / scaler + 1.5;
  869. fdata->advance /= scaler;
  870. }
  871. fdata->advance += font_spacing;
  872. if (charcode < 127) {
  873. int top = fdata->valign;
  874. int hmax = h / scaler;
  875. if (top > max_up) {
  876. max_up = top;
  877. }
  878. if ((top - hmax) < max_down) {
  879. max_down = top - hmax;
  880. }
  881. }
  882. if (font_mode == _EditorFontImportOptions::FONT_DISTANCE_FIELD) {
  883. // oversize the holding buffer so I can smooth it!
  884. int sw = w + scaler * 4;
  885. int sh = h + scaler * 4;
  886. unsigned char *smooth_buf = new unsigned char[sw * sh];
  887. for (int i = 0; i < sw * sh; ++i) {
  888. smooth_buf[i] = 0;
  889. }
  890. // copy the glyph into the buffer to be smoothed
  891. unsigned char *buf = slot->bitmap.buffer;
  892. for (int j = 0; j < h; ++j) {
  893. for (int i = 0; i < w; ++i) {
  894. smooth_buf[scaler * 2 + i + (j + scaler * 2) * sw] = 255 * ((buf[j * p + (i >> 3)] >> (7 - (i & 7))) & 1);
  895. }
  896. }
  897. // do the SDF
  898. int sdfw = fdata->width;
  899. int sdfh = fdata->height;
  900. fdata->bitmap.resize(sdfw * sdfh);
  901. for (int j = 0; j < sdfh; ++j) {
  902. for (int i = 0; i < sdfw; ++i) {
  903. int pd_idx = j * sdfw + i;
  904. //fdata->bitmap[j*slot->bitmap.width+i]=slot->bitmap.buffer[j*slot->bitmap.width+i];
  905. fdata->bitmap[pd_idx] =
  906. //get_SDF
  907. get_SDF_radial(smooth_buf, sw, sh,
  908. i * scaler + (scaler >> 1), j * scaler + (scaler >> 1),
  909. 2 * scaler);
  910. }
  911. }
  912. delete[] smooth_buf;
  913. } else {
  914. fdata->bitmap.resize(slot->bitmap.width * slot->bitmap.rows);
  915. for (int i = 0; i < slot->bitmap.width; i++) {
  916. for (int j = 0; j < slot->bitmap.rows; j++) {
  917. fdata->bitmap[j * slot->bitmap.width + i] = slot->bitmap.buffer[j * slot->bitmap.width + i];
  918. }
  919. }
  920. }
  921. font_data_list.push_back(fdata);
  922. charcode = FT_Get_Next_Char(face, charcode, &gindex);
  923. // printf("reading char %i\n",charcode);
  924. }
  925. /* SPACE */
  926. _EditorFontData *spd = memnew(_EditorFontData);
  927. spd->advance = 0;
  928. spd->character = ' ';
  929. spd->halign = 0;
  930. spd->valign = 0;
  931. spd->width = 0;
  932. spd->height = 0;
  933. spd->ofs_x = 0;
  934. spd->ofs_y = 0;
  935. 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)) {
  936. spd->advance = slot->advance.x >> 6; //round to nearest or store as float
  937. spd->advance /= scaler;
  938. spd->advance += font_spacing;
  939. } else {
  940. spd->advance = xsize;
  941. spd->advance += font_spacing;
  942. }
  943. font_data_list.push_back(spd);
  944. Set<CharType> exported;
  945. for (int i = 0; i < font_data_list.size(); i++) {
  946. exported.insert(font_data_list[i]->character);
  947. };
  948. int missing = 0;
  949. for (Set<CharType>::Element *E = import_chars.front(); E; E = E->next()) {
  950. CharType c = E->get();
  951. if (!exported.has(c)) {
  952. CharType str[2] = { c, 0 };
  953. printf("** Warning: character %i (%ls) not exported\n", (int)c, str);
  954. ++missing;
  955. };
  956. };
  957. print_line("total_chars: " + itos(font_data_list.size()));
  958. /* KERNING */
  959. for (int i = 0; i < font_data_list.size(); i++) {
  960. if (font_data_list[i]->character > 512)
  961. continue;
  962. for (int j = 0; j < font_data_list.size(); j++) {
  963. if (font_data_list[j]->character > 512)
  964. continue;
  965. FT_Vector delta;
  966. FT_Get_Kerning(face, font_data_list[i]->glyph, font_data_list[j]->glyph, FT_KERNING_DEFAULT, &delta);
  967. if (delta.x != 0) {
  968. _EditorKerningKey kpk;
  969. kpk.A = font_data_list[i]->character;
  970. kpk.B = font_data_list[j]->character;
  971. int kern = ((-delta.x) + (1 << 5)) >> 6;
  972. if (kern == 0)
  973. continue;
  974. kerning_map[kpk] = kern / scaler;
  975. }
  976. }
  977. }
  978. height = max_up - max_down;
  979. ascent = max_up;
  980. /* FIND OUT WHAT THE FONT HEIGHT FOR THIS IS */
  981. /* ADJUST THE VALIGN FOR EACH CHARACTER */
  982. for (int i = 0; i < (int)font_data_list.size(); i++) {
  983. font_data_list[i]->valign = max_up - font_data_list[i]->valign;
  984. }
  985. /* ADD THE SPACEBAR CHARACTER */
  986. /*
  987. _EditorFontData * fdata = new _EditorFontData;
  988. fdata->character=32;
  989. fdata->bitmap=0;
  990. fdata->width=xsize;
  991. fdata->height=1;
  992. fdata->valign=0;
  993. font_data_list.push_back(fdata);
  994. */
  995. /* SORT BY HEIGHT, SO THEY FIT BETTER ON THE TEXTURE */
  996. font_data_list.sort_custom<_EditorFontDataSort>();
  997. Color *color = memnew_arr(Color, height);
  998. int gradient_type = from->get_option("color/mode");
  999. switch (gradient_type) {
  1000. case _EditorFontImportOptions::COLOR_WHITE: {
  1001. for (int i = 0; i < height; i++) {
  1002. color[i] = Color(1, 1, 1, 1);
  1003. }
  1004. } break;
  1005. case _EditorFontImportOptions::COLOR_CUSTOM: {
  1006. Color cc = from->get_option("color/color");
  1007. for (int i = 0; i < height; i++) {
  1008. color[i] = cc;
  1009. }
  1010. } break;
  1011. case _EditorFontImportOptions::COLOR_GRADIENT_RANGE: {
  1012. Color src = from->get_option("color/begin");
  1013. Color to = from->get_option("color/end");
  1014. for (int i = 0; i < height; i++) {
  1015. color[i] = src.linear_interpolate(to, i / float(height));
  1016. }
  1017. } break;
  1018. case _EditorFontImportOptions::COLOR_GRADIENT_IMAGE: {
  1019. String fp = EditorImportPlugin::expand_source_path(from->get_option("color/image"));
  1020. Image img;
  1021. Error err = ImageLoader::load_image(fp, &img);
  1022. if (err == OK) {
  1023. for (int i = 0; i < height; i++) {
  1024. color[i] = img.get_pixel(0, i * img.get_height() / height);
  1025. }
  1026. } else {
  1027. for (int i = 0; i < height; i++) {
  1028. color[i] = Color(1, 1, 1, 1);
  1029. }
  1030. }
  1031. } break;
  1032. }
  1033. for (int i = 0; i < font_data_list.size(); i++) {
  1034. if (font_data_list[i]->bitmap.size() == 0)
  1035. continue;
  1036. int margin[4] = { 0, 0, 0, 0 };
  1037. if (from->get_option("shadow/enabled").operator bool()) {
  1038. int r = from->get_option("shadow/radius");
  1039. Point2i ofs = Point2(from->get_option("shadow/offset"));
  1040. margin[MARGIN_LEFT] = MAX(r - ofs.x, 0);
  1041. margin[MARGIN_RIGHT] = MAX(r + ofs.x, 0);
  1042. margin[MARGIN_TOP] = MAX(r - ofs.y, 0);
  1043. margin[MARGIN_BOTTOM] = MAX(r + ofs.y, 0);
  1044. }
  1045. if (from->get_option("shadow2/enabled").operator bool()) {
  1046. int r = from->get_option("shadow2/radius");
  1047. Point2i ofs = Point2(from->get_option("shadow2/offset"));
  1048. margin[MARGIN_LEFT] = MAX(r - ofs.x, margin[MARGIN_LEFT]);
  1049. margin[MARGIN_RIGHT] = MAX(r + ofs.x, margin[MARGIN_RIGHT]);
  1050. margin[MARGIN_TOP] = MAX(r - ofs.y, margin[MARGIN_TOP]);
  1051. margin[MARGIN_BOTTOM] = MAX(r + ofs.y, margin[MARGIN_BOTTOM]);
  1052. }
  1053. Size2i s;
  1054. s.width = font_data_list[i]->width + margin[MARGIN_LEFT] + margin[MARGIN_RIGHT];
  1055. s.height = font_data_list[i]->height + margin[MARGIN_TOP] + margin[MARGIN_BOTTOM];
  1056. Point2i o;
  1057. o.x = margin[MARGIN_LEFT];
  1058. o.y = margin[MARGIN_TOP];
  1059. int ow = font_data_list[i]->width;
  1060. int oh = font_data_list[i]->height;
  1061. DVector<uint8_t> pixels;
  1062. pixels.resize(s.x * s.y * 4);
  1063. DVector<uint8_t>::Write w = pixels.write();
  1064. //print_line("val: "+itos(font_data_list[i]->valign));
  1065. for (int y = 0; y < s.height; y++) {
  1066. int yc = CLAMP(y - o.y + font_data_list[i]->valign, 0, height - 1);
  1067. Color c = color[yc];
  1068. c.a = 0;
  1069. for (int x = 0; x < s.width; x++) {
  1070. int ofs = y * s.x + x;
  1071. w[ofs * 4 + 0] = c.r * 255.0;
  1072. w[ofs * 4 + 1] = c.g * 255.0;
  1073. w[ofs * 4 + 2] = c.b * 255.0;
  1074. w[ofs * 4 + 3] = c.a * 255.0;
  1075. }
  1076. }
  1077. for (int si = 0; si < 2; si++) {
  1078. #define S_VAR(m_v) (String(si == 0 ? "shadow/" : "shadow2/") + m_v)
  1079. if (from->get_option(S_VAR("enabled")).operator bool()) {
  1080. int r = from->get_option(S_VAR("radius"));
  1081. Color sc = from->get_option(S_VAR("color"));
  1082. Point2i so = Point2(from->get_option(S_VAR("offset")));
  1083. float tr = from->get_option(S_VAR("transition"));
  1084. print_line("shadow enabled: " + itos(si));
  1085. Vector<uint8_t> s2buf;
  1086. s2buf.resize(s.x * s.y);
  1087. uint8_t *wa = s2buf.ptr();
  1088. for (int j = 0; j < s.x * s.y; j++) {
  1089. wa[j] = 0;
  1090. }
  1091. // blit shadowa
  1092. for (int x = 0; x < ow; x++) {
  1093. for (int y = 0; y < oh; y++) {
  1094. int ofs = (o.y + y + so.y) * s.x + x + o.x + so.x;
  1095. wa[ofs] = font_data_list[i]->bitmap[y * ow + x];
  1096. }
  1097. }
  1098. //blur shadow2 with separatable convolution
  1099. if (r > 0) {
  1100. Vector<uint8_t> pixels2;
  1101. pixels2.resize(s2buf.size());
  1102. uint8_t *w2 = pixels2.ptr();
  1103. //vert
  1104. for (int x = 0; x < s.width; x++) {
  1105. for (int y = 0; y < s.height; y++) {
  1106. int ofs = y * s.width + x;
  1107. int sum = wa[ofs];
  1108. for (int k = 1; k <= r; k++) {
  1109. int ofs_d = MIN(y + k, s.height - 1) * s.width + x;
  1110. int ofs_u = MAX(y - k, 0) * s.width + x;
  1111. sum += wa[ofs_d];
  1112. sum += wa[ofs_u];
  1113. }
  1114. w2[ofs] = sum / (r * 2 + 1);
  1115. }
  1116. }
  1117. //horiz
  1118. for (int x = 0; x < s.width; x++) {
  1119. for (int y = 0; y < s.height; y++) {
  1120. int ofs = y * s.width + x;
  1121. int sum = w2[ofs];
  1122. for (int k = 1; k <= r; k++) {
  1123. int ofs_r = MIN(x + k, s.width - 1) + s.width * y;
  1124. int ofs_l = MAX(x - k, 0) + s.width * y;
  1125. sum += w2[ofs_r];
  1126. sum += w2[ofs_l];
  1127. }
  1128. wa[ofs] = Math::pow(float(sum / (r * 2 + 1)) / 255.0, tr) * 255.0;
  1129. }
  1130. }
  1131. }
  1132. //blend back
  1133. for (int j = 0; j < s.x * s.y; j++) {
  1134. 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);
  1135. Color ws(sc.r, sc.g, sc.b, sc.a * (wa[j] / 255.0));
  1136. Color b = wd.blend(ws);
  1137. w[j * 4 + 0] = b.r * 255.0;
  1138. w[j * 4 + 1] = b.g * 255.0;
  1139. w[j * 4 + 2] = b.b * 255.0;
  1140. w[j * 4 + 3] = b.a * 255.0;
  1141. }
  1142. }
  1143. }
  1144. for (int y = 0; y < oh; y++) {
  1145. int yc = CLAMP(y + font_data_list[i]->valign, 0, height - 1);
  1146. Color sc = color[yc];
  1147. for (int x = 0; x < ow; x++) {
  1148. int ofs = (o.y + y) * s.x + x + o.x;
  1149. float c = font_data_list[i]->bitmap[y * ow + x] / 255.0;
  1150. Color src_col = sc;
  1151. src_col.a *= c;
  1152. 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);
  1153. dst_col = dst_col.blend(src_col);
  1154. w[ofs * 4 + 0] = dst_col.r * 255.0;
  1155. w[ofs * 4 + 1] = dst_col.g * 255.0;
  1156. w[ofs * 4 + 2] = dst_col.b * 255.0;
  1157. w[ofs * 4 + 3] = dst_col.a * 255.0;
  1158. }
  1159. }
  1160. w = DVector<uint8_t>::Write();
  1161. Image img(s.width, s.height, 0, Image::FORMAT_RGBA, pixels);
  1162. font_data_list[i]->blit = img;
  1163. font_data_list[i]->blit_ofs = o;
  1164. }
  1165. //make atlas
  1166. int spacing = 2;
  1167. Vector<Size2i> sizes;
  1168. sizes.resize(font_data_list.size());
  1169. for (int i = 0; i < font_data_list.size(); i++) {
  1170. sizes[i] = Size2(font_data_list[i]->blit.get_width() + spacing * 2, font_data_list[i]->blit.get_height() + spacing * 2);
  1171. }
  1172. Vector<Point2i> res;
  1173. Size2i res_size;
  1174. EditorAtlas::fit(sizes, res, res_size);
  1175. res_size.x = next_power_of_2(res_size.x);
  1176. res_size.y = next_power_of_2(res_size.y);
  1177. print_line("Atlas size: " + res_size);
  1178. Image atlas(res_size.x, res_size.y, 0, Image::FORMAT_RGBA);
  1179. for (int i = 0; i < font_data_list.size(); i++) {
  1180. if (font_data_list[i]->bitmap.size() == 0)
  1181. continue;
  1182. 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));
  1183. font_data_list[i]->ofs_x = res[i].x + spacing;
  1184. font_data_list[i]->ofs_y = res[i].y + spacing;
  1185. }
  1186. if (from->has_option("advanced/premultiply_alpha") && bool(from->get_option("advanced/premultiply_alpha"))) {
  1187. DVector<uint8_t> data = atlas.get_data();
  1188. int dl = data.size();
  1189. {
  1190. DVector<uint8_t>::Write w = data.write();
  1191. for (int i = 0; i < dl; i += 4) {
  1192. w[i + 0] = uint8_t(int(w[i + 0]) * int(w[i + 3]) / 255);
  1193. w[i + 1] = uint8_t(int(w[i + 1]) * int(w[i + 3]) / 255);
  1194. w[i + 2] = uint8_t(int(w[i + 2]) * int(w[i + 3]) / 255);
  1195. }
  1196. }
  1197. atlas = Image(res_size.x, res_size.y, 0, Image::FORMAT_RGBA, data);
  1198. }
  1199. if (from->has_option("color/monochrome") && bool(from->get_option("color/monochrome"))) {
  1200. atlas.convert(Image::FORMAT_GRAYSCALE_ALPHA);
  1201. }
  1202. if (0) {
  1203. //debug the texture
  1204. Ref<ImageTexture> atlast = memnew(ImageTexture);
  1205. atlast->create_from_image(atlas);
  1206. // atlast->create_from_image(font_data_list[5]->blit);
  1207. TextureFrame *tf = memnew(TextureFrame);
  1208. tf->set_texture(atlast);
  1209. dialog->add_child(tf);
  1210. }
  1211. /* CREATE FONT */
  1212. int char_space = from->get_option("extra_space/char");
  1213. int space_space = from->get_option("extra_space/space");
  1214. int top_space = from->get_option("extra_space/top");
  1215. int bottom_space = from->get_option("extra_space/bottom");
  1216. bool disable_filter = from->get_option("advanced/disable_filter");
  1217. Ref<BitmapFont> font;
  1218. if (p_existing != String() && ResourceCache::has(p_existing)) {
  1219. font = Ref<BitmapFont>(ResourceCache::get(p_existing)->cast_to<BitmapFont>());
  1220. }
  1221. if (font.is_null()) {
  1222. font = Ref<BitmapFont>(memnew(BitmapFont));
  1223. }
  1224. font->clear();
  1225. font->set_height(height + bottom_space + top_space);
  1226. font->set_ascent(ascent + top_space);
  1227. font->set_distance_field_hint(font_mode == _EditorFontImportOptions::FONT_DISTANCE_FIELD);
  1228. //register textures
  1229. {
  1230. Ref<ImageTexture> t = memnew(ImageTexture);
  1231. int flags;
  1232. if (disable_filter)
  1233. flags = 0;
  1234. else
  1235. flags = Texture::FLAG_FILTER;
  1236. t->create_from_image(atlas, flags);
  1237. t->set_storage(ImageTexture::STORAGE_COMPRESS_LOSSLESS);
  1238. font->add_texture(t);
  1239. }
  1240. //register characters
  1241. for (int i = 0; i < font_data_list.size(); i++) {
  1242. _EditorFontData *fd = font_data_list[i];
  1243. int tex_idx = 0;
  1244. 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));
  1245. memdelete(fd);
  1246. }
  1247. for (Map<_EditorKerningKey, int>::Element *E = kerning_map.front(); E; E = E->next()) {
  1248. font->add_kerning_pair(E->key().A, E->key().B, E->get());
  1249. }
  1250. FT_Done_FreeType(library);
  1251. return font;
  1252. #else
  1253. return Ref<BitmapFont>();
  1254. #endif
  1255. }
  1256. String EditorFontImportPlugin::get_name() const {
  1257. return "font";
  1258. }
  1259. String EditorFontImportPlugin::get_visible_name() const {
  1260. return TTR("Font");
  1261. }
  1262. void EditorFontImportPlugin::import_dialog(const String &p_from) {
  1263. dialog->popup_import(p_from);
  1264. }
  1265. Error EditorFontImportPlugin::import(const String &p_path, const Ref<ResourceImportMetadata> &p_from) {
  1266. Ref<BitmapFont> font = EditorFontImportPlugin::generate_font(p_from, p_path);
  1267. if (!font.is_valid())
  1268. return ERR_CANT_CREATE;
  1269. Ref<ResourceImportMetadata> from = p_from;
  1270. from->set_source_md5(0, FileAccess::get_md5(EditorImportPlugin::expand_source_path(from->get_source_path(0))));
  1271. from->set_editor(get_name());
  1272. font->set_import_metadata(from);
  1273. return ResourceSaver::save(p_path, font);
  1274. }
  1275. void EditorFontImportPlugin::import_from_drop(const Vector<String> &p_drop, const String &p_dest_path) {
  1276. for (int i = 0; i < p_drop.size(); i++) {
  1277. String ext = p_drop[i].extension().to_lower();
  1278. String file = p_drop[i].get_file();
  1279. if (ext == "ttf" || ext == "otf" || ext == "fnt") {
  1280. import_dialog();
  1281. dialog->set_source_and_dest(p_drop[i], p_dest_path.plus_file(file.basename() + ".fnt"));
  1282. break;
  1283. }
  1284. }
  1285. }
  1286. EditorFontImportPlugin::EditorFontImportPlugin(EditorNode *p_editor) {
  1287. dialog = memnew(EditorFontImportDialog(this));
  1288. p_editor->get_gui_base()->add_child(dialog);
  1289. }