aboutsummaryrefslogtreecommitdiff
path: root/textures/base/pack/gear_icon.png
blob: 520e82e1dc7c61ddfa15e1f741c7a85975277137 (plain)
ofshex dumpascii
0000 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 00 00 00 80 00 00 00 80 08 04 00 00 00 69 37 a9 .PNG........IHDR.............i7.
0020 40 00 00 00 02 73 42 49 54 08 08 55 ec 46 04 00 00 00 09 70 48 59 73 00 00 03 b1 00 00 03 b1 01 @....sBIT..U.F.....pHYs.........
0040 f5 83 ed 49 00 00 00 19 74 45 58 74 53 6f 66 74 77 61 72 65 00 77 77 77 2e 69 6e 6b 73 63 61 70 ...I....tEXtSoftware.www.inkscap
0060 65 2e 6f 72 67 9b ee 3c 1a 00 00 06 c1 49 44 41 54 78 01 ed c1 5f 6c 55 85 01 c7 f1 df bd 2d 42 e.org..<.....IDATx..._lU......-B
0080 69 4b 56 d7 87 31 4c 41 2c c4 41 c2 32 41 fe 2c 1a 13 8d 46 1f 16 26 99 cd 10 14 1c c6 b0 2c 59 iKV..1LA,.A.2A.,...F..&.......,Y
00a0 b6 99 cd 07 37 b3 bd f8 e0 03 0f 8d 2e 8e 2d 4a 22 ca f8 a7 2c ea 83 0f 4d ed 6d 2f 5e fa f7 42 ....7.........-J"...,...M.m/^..B
00c0 0b fd 77 e9 ff 5a 4a 49 84 b6 b4 5c 42 cf 77 90 60 bc f7 dc 73 db 7b 6e cf bd 3d b5 e7 f3 91 c7 ..w..ZJI...\B.w.`...s.{n..=.....
00e0 e3 f1 78 3c 1e 8f c7 e3 f1 78 3c 1e 8f c7 e3 f1 64 07 6f 70 8e 8b 5c e4 1c 6f 68 e1 a1 94 3e be ..x<.....x<.....d.op..\..oh...>.
0100 d5 47 a9 16 1a 8e 13 eb a8 16 16 8a e8 22 56 17 3f d4 f7 09 3e 7c 9a 06 07 30 3b a0 69 e0 c7 a7 .G..........."V.?...>|...0;.i...
0120 f9 82 1c 7e 4f 3d f5 ec 53 52 d4 60 56 a3 a4 d8 47 3d f5 fc 81 1c b9 1f 6b f8 8a 9b dc 31 c6 29 ...~O=..SR.`V...G=......k....1.)
0140 0a 65 81 02 7a 30 eb a1 40 16 28 e4 7f 8c 71 c7 4d 4e b3 46 6e 47 23 b1 9a d9 a2 04 6c 25 8a 59 .e..z0..@.(...q.MN.FnG#.....l%.Y
0160 94 ad 4a c0 56 9a 89 d5 28 b7 a3 85 78 dd 6c 95 09 4f 63 60 66 f0 b4 4c d8 46 37 f1 5a e4 76 84 ..J.V...(...x.l..Oc`f..L.F7.Z.v.
0180 31 8b b0 56 71 58 c1 25 cc 2e b1 42 71 58 cb 45 cc c2 72 3b 02 24 aa 51 1c ee a1 17 b3 5e ee 51 1..VqX.%...BqX.E..r;.$.Q.....^.Q
01a0 1c 6a 48 14 90 db f1 19 89 ae b0 5e 31 f0 11 c1 2c 82 4f 31 58 c7 15 12 7d 26 b7 e3 3d ac 9c 52 .jH........^1...,.O1X...}&..=..R
01c0 0c 9e e7 3a 66 d7 79 5e 31 38 85 95 f7 e4 76 3c c1 24 89 86 78 54 22 97 c7 38 48 35 83 58 19 a4 ...:f.y^18....v<.$..xT"..8H5.X..
01e0 9a 83 3c 46 ae c4 a3 0c 91 68 92 27 e4 76 e4 d2 86 95 21 aa 68 67 82 99 4c d0 4e 15 43 58 69 63 ..<F.....h.'.v....!.hg..L.N.CXic
0200 91 dc 8f 7f 61 90 09 06 ff d4 7c c0 52 42 64 42 88 a5 9a 1f 58 4d 37 4e eb 63 ad e6 0f ca 71 5a ....a.....|.RBdB....XM7N.c....qZ
0220 b9 e6 13 f6 e0 b4 17 e5 1e ac a6 89 56 9a 09 f2 05 1f b0 9d 25 8a 43 31 8d 38 ad 91 62 c5 61 09 ............V.......%.C1.8..b.a.
0240 db f9 80 2f 08 d2 4c 2b 4d ac 56 76 90 43 90 58 37 e9 e4 10 85 ba 8b 62 1a c8 84 06 8a 75 17 85 .../..L+M.Vv.C.X7......b.....u..
0260 1c a2 93 9b c4 0a 92 a3 6c 60 3f 51 12 d5 b1 5e b7 51 4c 03 99 d2 40 b1 6e 63 3d f5 24 8a b2 5f ........l`?Q...^.QL...@.nc=.$.._
0280 99 87 8f 5a ac 0d 70 90 fd 34 90 49 0d ec e7 20 03 58 ab c5 a7 cc 23 c4 ec dd 62 90 0b 84 08 12 ...Z..p..4.I.....X....#...b.....
02a0 24 c4 05 be e6 16 b3 17 52 36 50 c6 55 d2 37 c1 39 3e e4 57 14 2b 06 c5 94 71 84 73 4c 90 be ab $.......R6P.U.7.9>.W.+...q.sL...
02c0 94 29 3b 38 82 41 3a ae 52 c5 76 fc 4a 02 3f cf 52 cd 55 d2 61 70 44 d9 42 1e 4d d8 35 45 98 5f .);8.A:.R.v.J.?.R.U.apD.B.M.5E._
02e0 28 05 3c 4b 18 03 bb 9a c8 53 f6 b0 81 08 76 7c c3 61 16 2b 45 2c e1 23 ae 61 47 84 0d ca 2e 7e (.<K.....S....v|.a.+E,.#.aG....~
0300 4a 07 a9 1a e6 8f b2 89 3f 33 4c aa da d9 a0 ec 63 15 95 5c 66 66 c3 ec 55 1a f8 0d c3 cc ec 32 J.......?3L.....c..\ff..U......2
0320 95 ac d4 5c 61 35 47 19 60 3a df f0 27 a5 89 bf 70 8d e9 0c 70 94 d5 9a 6b fc 8c 3e 92 99 e2 43 ...\a5G.`:..'...p...p...k..>...C
0340 cd 02 47 30 48 66 90 8d 72 07 2a 48 26 cc 62 cd 02 79 9c 25 99 0a b9 03 39 b4 61 ed 2a bf d4 2c ..G0Hf..r.*H&.b..y.%....9.a.*..,
0360 51 c6 28 d6 da c8 91 1b b0 8d 31 ac 05 e4 00 4e 63 6d 9c 6d 72 03 de c6 da 24 3b e4 00 ca 98 c4 Q.(.......1....Ncm.mr....$;.....
0380 da db 72 03 be c4 5a 33 39 72 00 7e 9a b1 f6 a5 e6 06 85 3c c2 76 4a c8 c7 c7 2e fa b1 f6 5f 39 ..r...Z39r.~.......<.vJ......._9
03a0 84 63 58 eb 67 17 3e f2 29 61 3b 8f 50 a8 cc e3 5e 0e 10 a4 87 5b c0 08 fd 74 33 81 b5 29 7e 2d .cX.g.>.)a;.P...^....[...t3..)~-
03c0 87 b0 9b 29 ac 4d d0 4d 3f 23 c0 2d 7a 08 72 80 7b 95 29 94 72 8c 2e 52 35 c4 8f e4 10 7e cc 25 ...).M.M?#.-z.r.{.).r..R5....~.%
03e0 52 d5 c5 31 4a e5 3c 5e a7 0f 3b 5a e5 20 da b0 a3 8f d7 e5 34 c2 d8 53 2b 07 51 8f 3d 4d 72 1a R..1J.<^..;Z........4..S+.Q.=Mr.
0400 1d d8 53 23 07 11 c4 9e 0e 39 8d 0e ec a9 91 83 08 62 4f 87 9c 46 13 f6 d4 c9 41 d4 63 4f a3 9c ..S#.....9.......bO..F....A.cO..
0420 c6 ab f4 60 47 9b 1c 83 8f 76 ec e8 e1 55 39 8f 12 0e 13 c1 20 35 43 2c 97 43 58 c1 25 52 63 10 ...`G....v...U9......5C,.CX.%Rc.
0440 e1 30 25 ca 14 96 f1 26 01 ba 98 c0 60 88 6e da 19 c7 da 14 2f c8 21 ec 65 0a 6b e3 b4 d3 cd 10 .0%....&....`.n...../.!.e.k.....
0460 06 13 74 11 e0 4d 96 29 f3 c8 63 23 8f b3 1c bf c4 0e fa b0 76 4c 0e e1 04 d6 fa d8 21 e1 67 39 ..t..M.)..c#........vL......!.g9
0480 8f b3 91 3c cd 0d 2a b1 76 9e 5c 39 80 5c ce 63 ad 52 6e 40 39 d6 6e b0 53 0e 60 17 51 ac 95 cb ...<..*.v.\9.\.c.Rn@9.n.S.`.Q...
04a0 0d d8 c2 18 d6 6a e4 00 be c2 da 38 9b e5 06 f8 69 c5 da 28 3b 35 4b ec 61 1c 6b ad f8 e5 0e 54 .....j.....8....i..(;5K.a.k....T
04c0 90 cc 39 96 6a 16 28 a0 85 64 2a e4 0e 6c 63 90 64 0c 4e 68 16 38 89 41 32 43 fc 5c 73 8d 75 7c ..9.j.(..d*..lc.d.Nh.8.A2C.\s.u|
04e0 c2 d7 4c 67 94 bf 2a 4d fc 83 71 a6 33 c4 29 d6 69 ae 50 4a 35 57 98 d9 08 bf 55 1a f8 1d 23 cc ..Lg..*M..q.3.).i.PJ5W....U...#.
0500 ec 0a d5 94 2a fb 78 98 4e 52 35 c2 df 64 13 7f 67 84 54 75 f2 b0 b2 8b 4d 74 61 c7 28 27 c9 57 ....*.x.NR5..d..g.Tu....Mta.('.W
0520 8a 28 e0 13 c6 b1 a3 8b 4d ca 1e f2 39 8b 5d 06 cd bc a0 14 f0 12 2d d8 77 96 7c 65 0b c7 31 48 .(......M...9.].......-.w.|e..1H
0540 c7 18 a7 d9 45 ae 92 60 11 2f 12 62 9c 74 18 1c 57 76 b0 9b 51 d2 17 e5 3c 27 78 89 12 7c ba 0b ....E..`./.b.t..Wv..Q...<'x..|..
0560 1f 25 ec e3 24 17 88 92 be 51 76 2b f3 f0 51 cb ec 4d 71 99 0e 1a 08 12 a4 81 4e 2e 63 30 7b b5 .%..$....Qv+..Q..Mq.......N.c0{.
0580 f8 94 79 84 b0 d6 4b 39 bb a9 23 93 ea d8 4d 39 bd 58 0b 29 1b 78 99 1b 24 3a c3 1a dd 46 11 75 ..y...K9..#...M9.X.).x..$:...F.u
05a0 64 4a 1d 45 ba 8d 35 9c 21 d1 0d 5e 56 36 e0 27 40 ac 49 da 78 97 7c dd 45 11 75 64 42 1d 45 ba dJ.E..5.!..^V6.'@.I.x.|.E.udB.E.
05c0 8b 7c de a5 8d 49 62 05 f0 2b 3b 58 49 23 cd 84 a9 e2 53 0e f1 24 b9 8a 43 11 75 38 ad 8e 22 c5 .|...Ib..+;XI#....S..$..C.u8..".
05e0 21 97 27 39 c4 a7 54 11 a6 99 46 56 ca 3d d8 8b d3 f6 68 3e e1 1d 9c f6 8e e6 0f 4a e9 c5 69 03 !.'9..T...FV.=....h>.......J..i.
0600 fc 44 f3 03 05 d4 92 09 b5 14 68 3e e0 3f 64 ca bf e5 7e 2c a2 1d 2b 83 54 d0 ca 18 33 19 a3 95 .D........h>.?d...~,..+.T...3...
0620 0a 06 b1 d2 ce 22 b9 1d 4f 71 83 44 83 6c 96 f0 b3 99 72 2a e9 c7 4a 3f 95 94 b3 19 bf c4 66 06 ....."..Oq.D.l....r*..J?......f.
0640 49 74 83 a7 e4 76 bc 8f 95 8f 15 83 e7 b8 8e d9 75 9e 53 0c 3e c6 ca fb 72 3b 3e 27 d1 08 0f 2a It...v..........u.S.>...r;>'...*
0660 0e 11 cc 22 8a c3 83 8c 90 e8 73 b9 1d 01 12 05 14 87 c5 f4 62 d6 cb 62 c5 21 40 a2 80 dc 8e 30 ..."......s.........b..b.!@....0
0680 66 9d 3c a0 38 dc c7 30 66 c3 dc a7 38 3c 40 27 66 61 b9 1d 2d c4 bb c8 26 99 f0 0c 06 66 06 cf f.<.8..0f...8<@'fa..-...&....f..
06a0 c8 84 4d 5c 24 5e 8b dc 8e 06 be 63 10 e6 21 25 60 0b 51 cc a2 6c 51 02 1e 22 8c c1 77 1a e4 76 ..M\$^.....c..!%`.Q..lQ.."..w..v
06c0 ac a2 9a 28 77 5c e3 38 4b 65 81 7c ba 31 eb 26 5f 16 58 ca 71 ae 71 47 94 6a 56 c9 fd f0 f3 0a ...(w\.8Ke.|.1.&_.X.q.qG.jV.....
06e0 67 08 b1 53 49 51 8d 59 b5 92 62 27 21 ce f0 0a 7e 7d 5f f0 16 66 6f 69 21 61 19 11 62 45 f8 81 g..SIQ.Y..b'!...~}_..foi!a..bE..
0700 16 16 3e 22 d6 61 2d 34 dc 4f 2f df ea e5 7e 2d 3c bc 46 13 9d 74 d2 c4 6b f2 78 3c 1e 8f c7 e3 ..>".a-4.O/...~-<.F..t..k.x<....
0720 f1 78 3c 1e 8f c7 e3 f1 78 3c 9e ac f8 3f 4d 95 ea 96 77 e1 af 91 00 00 00 00 49 45 4e 44 ae 42 .x<.....x<...?M...w.......IEND.B
0740 60 82 `.
#n386'>386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197
/*
   CGUITTFont FreeType class for Irrlicht
   Copyright (c) 2009-2010 John Norman
   Copyright (c) 2016 Nathanaël Courant

   This software is provided 'as-is', without any express or implied
   warranty. In no event will the authors be held liable for any
   damages arising from the use of this software.

   Permission is granted to anyone to use this software for any
   purpose, including commercial applications, and to alter it and
   redistribute it freely, subject to the following restrictions:

   1. The origin of this software must not be misrepresented; you
      must not claim that you wrote the original software. If you use
      this software in a product, an acknowledgment in the product
      documentation would be appreciated but is not required.

   2. Altered source versions must be plainly marked as such, and
      must not be misrepresented as being the original software.

   3. This notice may not be removed or altered from any source
      distribution.

   The original version of this class can be located at:
   http://irrlicht.suckerfreegames.com/

   John Norman
   john@suckerfreegames.com
*/

#include <irrlicht.h>
#include <iostream>
#include "CGUITTFont.h"

namespace irr
{
namespace gui
{

// Manages the FT_Face cache.
struct SGUITTFace : public virtual irr::IReferenceCounted
{
	SGUITTFace() : face_buffer(0), face_buffer_size(0)
	{
		memset((void*)&face, 0, sizeof(FT_Face));
	}

	~SGUITTFace()
	{
		FT_Done_Face(face);
		delete[] face_buffer;
	}

	FT_Face face;
	FT_Byte* face_buffer;
	FT_Long face_buffer_size;
};

// Static variables.
FT_Library CGUITTFont::c_library;
core::map<io::path, SGUITTFace*> CGUITTFont::c_faces;
bool CGUITTFont::c_libraryLoaded = false;
scene::IMesh* CGUITTFont::shared_plane_ptr_ = 0;
scene::SMesh CGUITTFont::shared_plane_;

//

/** Checks that no dimension of the FT_BitMap object is negative.  If either is
 * negative, abort execution.
 */
inline void checkFontBitmapSize(const FT_Bitmap &bits)
{
	if ((s32)bits.rows < 0 || (s32)bits.width < 0) {
		std::cout << "Insane font glyph size. File: "
		          << __FILE__ << " Line " << __LINE__
		          << std::endl;
		abort();
	}
}

video::IImage* SGUITTGlyph::createGlyphImage(const FT_Bitmap& bits, video::IVideoDriver* driver) const
{
	// Make sure our casts to s32 in the loops below will not cause problems
	checkFontBitmapSize(bits);

	// Determine what our texture size should be.
	// Add 1 because textures are inclusive-exclusive.
	core::dimension2du d(bits.width + 1, bits.rows + 1);
	core::dimension2du texture_size;
	//core::dimension2du texture_size(bits.width + 1, bits.rows + 1);

	// Create and load our image now.
	video::IImage* image = 0;
	switch (bits.pixel_mode)
	{
		case FT_PIXEL_MODE_MONO:
		{
			// Create a blank image and fill it with transparent pixels.
			texture_size = d.getOptimalSize(true, true);
			image = driver->createImage(video::ECF_A1R5G5B5, texture_size);
			image->fill(video::SColor(0, 255, 255, 255));

			// Load the monochrome data in.
			const u32 image_pitch = image->getPitch() / sizeof(u16);
			u16* image_data = (u16*)image->lock();
			u8* glyph_data = bits.buffer;

			for (s32 y = 0; y < (s32)bits.rows; ++y)
			{
				u16* row = image_data;
				for (s32 x = 0; x < (s32)bits.width; ++x)
				{
					// Monochrome bitmaps store 8 pixels per byte.  The left-most pixel is the bit 0x80.
					// So, we go through the data each bit at a time.
					if ((glyph_data[y * bits.pitch + (x / 8)] & (0x80 >> (x % 8))) != 0)
						*row = 0xFFFF;
					++row;
				}
				image_data += image_pitch;
			}
			image->unlock();
			break;
		}

		case FT_PIXEL_MODE_GRAY:
		{
			// Create our blank image.
			texture_size = d.getOptimalSize(!driver->queryFeature(video::EVDF_TEXTURE_NPOT), !driver->queryFeature(video::EVDF_TEXTURE_NSQUARE), true, 0);
			image = driver->createImage(video::ECF_A8R8G8B8, texture_size);
			image->fill(video::SColor(0, 255, 255, 255));

			// Load the grayscale data in.
			const float gray_count = static_cast<float>(bits.num_grays);
			const u32 image_pitch = image->getPitch() / sizeof(u32);
			u32* image_data = (u32*)image->lock();
			u8* glyph_data = bits.buffer;
			for (s32 y = 0; y < (s32)bits.rows; ++y)
			{
				u8* row = glyph_data;
				for (s32 x = 0; x < (s32)bits.width; ++x)
				{
					image_data[y * image_pitch + x] |= static_cast<u32>(255.0f * (static_cast<float>(*row++) / gray_count)) << 24;
					//data[y * image_pitch + x] |= ((u32)(*bitsdata++) << 24);
				}
				glyph_data += bits.pitch;
			}
			image->unlock();
			break;
		}
		default:
			// TODO: error message?
			return 0;
	}
	return image;
}

void SGUITTGlyph::preload(u32 char_index, FT_Face face, video::IVideoDriver* driver, u32 font_size, const FT_Int32 loadFlags)
{
	if (isLoaded) return;

	// Set the size of the glyph.
	FT_Set_Pixel_Sizes(face, 0, font_size);

	// Attempt to load the glyph.
	if (FT_Load_Glyph(face, char_index, loadFlags) != FT_Err_Ok)
		// TODO: error message?
		return;

	FT_GlyphSlot glyph = face->glyph;
	FT_Bitmap bits = glyph->bitmap;

	// Setup the glyph information here:
	advance = glyph->advance;
	offset = core::vector2di(glyph->bitmap_left, glyph->bitmap_top);

	// Try to get the last page with available slots.
	CGUITTGlyphPage* page = parent->getLastGlyphPage();

	// If we need to make a new page, do that now.
	if (!page)
	{
		page = parent->createGlyphPage(bits.pixel_mode);
		if (!page)
			// TODO: add error message?
			return;
	}

	glyph_page = parent->getLastGlyphPageIndex();
	u32 texture_side_length = page->texture->getOriginalSize().Width;
	core::vector2di page_position(
		(page->used_slots % (texture_side_length / font_size)) * font_size,
		(page->used_slots / (texture_side_length / font_size)) * font_size
		);
	source_rect.UpperLeftCorner = page_position;
	source_rect.LowerRightCorner = core::vector2di(page_position.X + bits.width, page_position.Y + bits.rows);

	page->dirty = true;
	++page->used_slots;
	--page->available_slots;

	// We grab the glyph bitmap here so the data won't be removed when the next glyph is loaded.
	surface = createGlyphImage(bits, driver);

	// Set our glyph as loaded.
	isLoaded = true;
}

void SGUITTGlyph::unload()
{
	if (surface)
	{
		surface->drop();
		surface = 0;
	}
	isLoaded = false;
}

//////////////////////

CGUITTFont* CGUITTFont::createTTFont(IGUIEnvironment *env, const io::path& filename, const u32 size, const bool antialias, const bool transparency, const u32 shadow, const u32 shadow_alpha)
{
	if (!c_libraryLoaded)
	{
		if (FT_Init_FreeType(&c_library))
			return 0;
		c_libraryLoaded = true;
	}

	CGUITTFont* font = new CGUITTFont(env);
	bool ret = font->load(filename, size, antialias, transparency);
	if (!ret)
	{
		font->drop();
		return 0;
	}

	font->shadow_offset = shadow;
	font->shadow_alpha = shadow_alpha;

	return font;
}

CGUITTFont* CGUITTFont::createTTFont(IrrlichtDevice *device, const io::path& filename, const u32 size, const bool antialias, const bool transparency)
{
	if (!c_libraryLoaded)
	{
		if (FT_Init_FreeType(&c_library))
			return 0;
		c_libraryLoaded = true;
	}

	CGUITTFont* font = new CGUITTFont(device->getGUIEnvironment());
	font->Device = device;
	bool ret = font->load(filename, size, antialias, transparency);
	if (!ret)
	{
		font->drop();
		return 0;
	}

	return font;
}

CGUITTFont* CGUITTFont::create(IGUIEnvironment *env, const io::path& filename, const u32 size, const bool antialias, const bool transparency)
{
	return CGUITTFont::createTTFont(env, filename, size, antialias, transparency);
}

CGUITTFont* CGUITTFont::create(IrrlichtDevice *device, const io::path& filename, const u32 size, const bool antialias, const bool transparency)
{
	return CGUITTFont::createTTFont(device, filename, size, antialias, transparency);
}

//////////////////////

//! Constructor.
CGUITTFont::CGUITTFont(IGUIEnvironment *env)
: use_monochrome(false), use_transparency(true), use_hinting(true), use_auto_hinting(true),
batch_load_size(1), Device(0), Environment(env), Driver(0), GlobalKerningWidth(0), GlobalKerningHeight(0)
{
	#ifdef _DEBUG
	setDebugName("CGUITTFont");
	#endif

	if (Environment)
	{
		// don't grab environment, to avoid circular references
		Driver = Environment->getVideoDriver();
	}

	if (Driver)
		Driver->grab();

	setInvisibleCharacters(L" ");

	// Glyphs aren't reference counted, so don't try to delete them when we free the array.
	Glyphs.set_free_when_destroyed(false);
}

bool CGUITTFont::load(const io::path& filename, const u32 size, const bool antialias, const bool transparency)
{
	// Some sanity checks.
	if (Environment == 0 || Driver == 0) return false;
	if (size == 0) return false;
	if (filename.size() == 0) return false;

	io::IFileSystem* filesystem = Environment->getFileSystem();
	irr::ILogger* logger = (Device != 0 ? Device->getLogger() : 0);
	this->size = size;
	this->filename = filename;

	// Update the font loading flags when the font is first loaded.
	this->use_monochrome = !antialias;
	this->use_transparency = transparency;
	update_load_flags();

	// Log.
	if (logger)
		logger->log(L"CGUITTFont", core::stringw(core::stringw(L"Creating new font: ") + core::ustring(filename).toWCHAR_s() + L" " + core::stringc(size) + L"pt " + (antialias ? L"+antialias " : L"-antialias ") + (transparency ? L"+transparency" : L"-transparency")).c_str(), irr::ELL_INFORMATION);

	// Grab the face.
	SGUITTFace* face = 0;
	core::map<io::path, SGUITTFace*>::Node* node = c_faces.find(filename);
	if (node == 0)
	{
		face = new SGUITTFace();
		c_faces.set(filename, face);

		if (filesystem)
		{
			// Read in the file data.
			io::IReadFile* file = filesystem->createAndOpenFile(filename);
			if (file == 0)
			{
				if (logger) logger->log(L"CGUITTFont", L"Failed to open the file.", irr::ELL_INFORMATION);

				c_faces.remove(filename);
				delete face;
				face = 0;
				return false;
			}
			face->face_buffer = new FT_Byte[file->getSize()];
			file->read(face->face_buffer, file->getSize());
			face->face_buffer_size = file->getSize();
			file->drop();

			// Create the face.
			if (FT_New_Memory_Face(c_library, face->face_buffer, face->face_buffer_size, 0, &face->face))
			{
				if (logger) logger->log(L"CGUITTFont", L"FT_New_Memory_Face failed.", irr::ELL_INFORMATION);

				c_faces.remove(filename);
				delete face;
				face = 0;
				return false;
			}
		}
		else
		{
			core::ustring converter(filename);
			if (FT_New_Face(c_library, reinterpret_cast<const char*>(converter.toUTF8_s().c_str()), 0, &face->face))
			{
				if (logger) logger->log(L"CGUITTFont", L"FT_New_Face failed.", irr::ELL_INFORMATION);

				c_faces.remove(filename);
				delete face;
				face = 0;
				return false;
			}
		}
	}
	else
	{
		// Using another instance of this face.
		face = node->getValue();
		face->grab();
	}

	// Store our face.
	tt_face = face->face;

	// Store font metrics.
	FT_Set_Pixel_Sizes(tt_face, size, 0);
	font_metrics = tt_face->size->metrics;

	// Allocate our glyphs.
	Glyphs.clear();
	Glyphs.reallocate(tt_face->num_glyphs);
	Glyphs.set_used(tt_face->num_glyphs);
	for (FT_Long i = 0; i < tt_face->num_glyphs; ++i)
	{
		Glyphs[i].isLoaded = false;
		Glyphs[i].glyph_page = 0;
		Glyphs[i].source_rect = core::recti();
		Glyphs[i].offset = core::vector2di();
		Glyphs[i].advance = FT_Vector();
		Glyphs[i].surface = 0;
		Glyphs[i].parent = this;
	}

	// Cache the first 127 ascii characters.
	u32 old_size = batch_load_size;
	batch_load_size = 127;
	getGlyphIndexByChar((uchar32_t)0);
	batch_load_size = old_size;

	return true;
}

CGUITTFont::~CGUITTFont()
{
	// Delete the glyphs and glyph pages.
	reset_images();
	CGUITTAssistDelete::Delete(Glyphs);
	//Glyphs.clear();

	// We aren't using this face anymore.
	core::map<io::path, SGUITTFace*>::Node* n = c_faces.find(filename);
	if (n)
	{
		SGUITTFace* f = n->getValue();

		// Drop our face.  If this was the last face, the destructor will clean up.
		if (f->drop())
			c_faces.remove(filename);

		// If there are no more faces referenced by FreeType, clean up.
		if (c_faces.size() == 0)
		{
			FT_Done_FreeType(c_library);
			c_libraryLoaded = false;
		}
	}

	// Drop our driver now.
	if (Driver)
		Driver->drop();
}

void CGUITTFont::reset_images()
{
	// Delete the glyphs.
	for (u32 i = 0; i != Glyphs.size(); ++i)
		Glyphs[i].unload();

	// Unload the glyph pages from video memory.
	for (u32 i = 0; i != Glyph_Pages.size(); ++i)
		delete Glyph_Pages[i];
	Glyph_Pages.clear();

	// Always update the internal FreeType loading flags after resetting.
	update_load_flags();
}

void CGUITTFont::update_glyph_pages() const
{
	for (u32 i = 0; i != Glyph_Pages.size(); ++i)
	{
		if (Glyph_Pages[i]->dirty)
			Glyph_Pages[i]->updateTexture();
	}
}

CGUITTGlyphPage* CGUITTFont::getLastGlyphPage() const
{
	CGUITTGlyphPage* page = 0;
	if (Glyph_Pages.empty())
		return 0;
	else
	{
		page = Glyph_Pages[getLastGlyphPageIndex()];
		if (page->available_slots == 0)
			page = 0;
	}
	return page;
}

CGUITTGlyphPage* CGUITTFont::createGlyphPage(const u8& pixel_mode)
{
	CGUITTGlyphPage* page = 0;
	
	// Name of our page.
	io::path name("TTFontGlyphPage_");
	name += tt_face->family_name;
	name += ".";
	name += tt_face->style_name;
	name += ".";
	name += size;
	name += "_";
	name += Glyph_Pages.size(); // The newly created page will be at the end of the collection.

	// Create the new page.
	page = new CGUITTGlyphPage(Driver, name);

	// Determine our maximum texture size.
	// If we keep getting 0, set it to 1024x1024, as that number is pretty safe.
	core::dimension2du max_texture_size = max_page_texture_size;
	if (max_texture_size.Width == 0 || max_texture_size.Height == 0)
		max_texture_size = Driver->getMaxTextureSize();
	if (max_texture_size.Width == 0 || max_texture_size.Height == 0)
		max_texture_size = core::dimension2du(1024, 1024);

	// We want to try to put at least 144 glyphs on a single texture.
	core::dimension2du page_texture_size;
	if (size <= 21) page_texture_size = core::dimension2du(256, 256);
	else if (size <= 42) page_texture_size = core::dimension2du(512, 512);
	else if (size <= 84) page_texture_size = core::dimension2du(1024, 1024);
	else if (size <= 168) page_texture_size = core::dimension2du(2048, 2048);
	else page_texture_size = core::dimension2du(4096, 4096);

	if (page_texture_size.Width > max_texture_size.Width || page_texture_size.Height > max_texture_size.Height)
		page_texture_size = max_texture_size;

	if (!page->createPageTexture(pixel_mode, page_texture_size)) {
		// TODO: add error message?
		delete page;
		return 0;
	}

	if (page)
	{
		// Determine the number of glyph slots on the page and add it to the list of pages.
		page->available_slots = (page_texture_size.Width / size) * (page_texture_size.Height / size);
		Glyph_Pages.push_back(page);
	}
	return page;
}

void CGUITTFont::setTransparency(const bool flag)
{
	use_transparency = flag;
	reset_images();
}

void CGUITTFont::setMonochrome(const bool flag)
{
	use_monochrome = flag;
	reset_images();
}

void CGUITTFont::setFontHinting(const bool enable, const bool enable_auto_hinting)
{
	use_hinting = enable;
	use_auto_hinting = enable_auto_hinting;
	reset_images();
}

void CGUITTFont::draw(const core::stringw& text, const core::rect<s32>& position, video::SColor color, bool hcenter, bool vcenter, const core::rect<s32>* clip)
{
	draw(EnrichedString(std::wstring(text.c_str()), color), position, color, hcenter, vcenter, clip);
}

void CGUITTFont::draw(const EnrichedString &text, const core::rect<s32>& position, video::SColor color, bool hcenter, bool vcenter, const core::rect<s32>* clip)
{
	std::vector<video::SColor> colors = text.getColors();

	if (!Driver)
		return;

	// Clear the glyph pages of their render information.
	for (u32 i = 0; i < Glyph_Pages.size(); ++i)
	{
		Glyph_Pages[i]->render_positions.clear();
		Glyph_Pages[i]->render_source_rects.clear();
	}

	// Set up some variables.
	core::dimension2d<s32> textDimension;
	core::position2d<s32> offset = position.UpperLeftCorner;

	// Determine offset positions.
	if (hcenter || vcenter)
	{
		textDimension = getDimension(text.c_str());

		if (hcenter)
			offset.X = ((position.getWidth() - textDimension.Width) >> 1) + offset.X;

		if (vcenter)
			offset.Y = ((position.getHeight() - textDimension.Height) >> 1) + offset.Y;
	}

	// Convert to a unicode string.
	core::ustring utext = text.getString();

	// Set up our render map.
	core::map<u32, CGUITTGlyphPage*> Render_Map;

	// Start parsing characters.
	u32 n;
	uchar32_t previousChar = 0;
	core::ustring::const_iterator iter(utext);
	std::vector<video::SColor> applied_colors;
	while (!iter.atEnd())
	{
		uchar32_t currentChar = *iter;
		n = getGlyphIndexByChar(currentChar);
		bool visible = (Invisible.findFirst(currentChar) == -1);
		bool lineBreak=false;
		if (currentChar == L'\r') // Mac or Windows breaks
		{
			lineBreak = true;
			if (*(iter + 1) == (uchar32_t)'\n') 	// Windows line breaks.
				currentChar = *(++iter);
		}
		else if (currentChar == (uchar32_t)'\n') // Unix breaks
		{
			lineBreak = true;
		}

		if (lineBreak)
		{
			previousChar = 0;
			offset.Y += font_metrics.height / 64;
			offset.X = position.UpperLeftCorner.X;

			if (hcenter)
				offset.X += (position.getWidth() - textDimension.Width) >> 1;
			++iter;
			continue;
		}

		if (n > 0 && visible)
		{
			// Calculate the glyph offset.
			s32 offx = Glyphs[n-1].offset.X;
			s32 offy = (font_metrics.ascender / 64) - Glyphs[n-1].offset.Y;

			// Apply kerning.
			core::vector2di k = getKerning(currentChar, previousChar);
			offset.X += k.X;
			offset.Y += k.Y;

			// Determine rendering information.
			SGUITTGlyph& glyph = Glyphs[n-1];
			CGUITTGlyphPage* const page = Glyph_Pages[glyph.glyph_page];
			page->render_positions.push_back(core::position2di(offset.X + offx, offset.Y + offy));
			page->render_source_rects.push_back(glyph.source_rect);
			Render_Map.set(glyph.glyph_page, page);
			u32 current_color = iter.getPos();
			if (current_color < colors.size())
				applied_colors.push_back(colors[current_color]);
		}
		offset.X += getWidthFromCharacter(currentChar);

		previousChar = currentChar;
		++iter;
	}

	// Draw now.
	update_glyph_pages();
	core::map<u32, CGUITTGlyphPage*>::Iterator j = Render_Map.getIterator();
	while (!j.atEnd())
	{
		core::map<u32, CGUITTGlyphPage*>::Node* n = j.getNode();
		j++;
		if (n == 0) continue;

		CGUITTGlyphPage* page = n->getValue();

		if (shadow_offset) {
			for (size_t i = 0; i < page->render_positions.size(); ++i)
				page->render_positions[i] += core::vector2di(shadow_offset, shadow_offset);
			Driver->draw2DImageBatch(page->texture, page->render_positions, page->render_source_rects, clip, video::SColor(shadow_alpha,0,0,0), true);
			for (size_t i = 0; i < page->render_positions.size(); ++i)
				page->render_positions[i] -= core::vector2di(shadow_offset, shadow_offset);
		}
		for (size_t i = 0; i < page->render_positions.size(); ++i) {
			irr::video::SColor col;
			if (!applied_colors.empty()) {
				col = applied_colors[i < applied_colors.size() ? i : 0];
			} else {
				col = irr::video::SColor(255, 255, 255, 255);
			}
			if (!use_transparency)
				col.color |= 0xff000000;
			Driver->draw2DImage(page->texture, page->render_positions[i], page->render_source_rects[i], clip, col, true);
		}
	}
}

core::dimension2d<u32> CGUITTFont::getCharDimension(const wchar_t ch) const
{
	return core::dimension2d<u32>(getWidthFromCharacter(ch), getHeightFromCharacter(ch));
}

core::dimension2d<u32> CGUITTFont::getDimension(const wchar_t* text) const
{
	return getDimension(core::ustring(text));
}