imgui_draw.cpp 112 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523
  1. // dear imgui, v1.51
  2. // (drawing and font code)
  3. // Contains implementation for
  4. // - ImDrawList
  5. // - ImDrawData
  6. // - ImFontAtlas
  7. // - ImFont
  8. // - Default font data
  9. #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
  10. #define _CRT_SECURE_NO_WARNINGS
  11. #endif
  12. #include "imgui.h"
  13. #define IMGUI_DEFINE_MATH_OPERATORS
  14. #define IMGUI_DEFINE_PLACEMENT_NEW
  15. #include "imgui_internal.h"
  16. #include <stdio.h> // vsnprintf, sscanf, printf
  17. #if !defined(alloca)
  18. #ifdef _WIN32
  19. #include <malloc.h> // alloca
  20. #elif (defined(__FreeBSD__) || defined(FreeBSD_kernel) || defined(__DragonFly__)) && !defined(__GLIBC__)
  21. #include <stdlib.h> // alloca. FreeBSD uses stdlib.h unless GLIBC
  22. #else
  23. #include <alloca.h> // alloca
  24. #endif
  25. #endif
  26. #ifdef _MSC_VER
  27. #pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff)
  28. #pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
  29. #define snprintf _snprintf
  30. #endif
  31. #ifdef __clang__
  32. #pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse.
  33. #pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants ok.
  34. #pragma clang diagnostic ignored "-Wglobal-constructors" // warning : declaration requires a global destructor // similar to above, not sure what the exact difference it.
  35. #pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness //
  36. #if __has_warning("-Wreserved-id-macro")
  37. #pragma clang diagnostic ignored "-Wreserved-id-macro" // warning : macro name is a reserved identifier //
  38. #endif
  39. #elif defined(__GNUC__)
  40. #pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used
  41. #pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function
  42. #pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value
  43. #pragma GCC diagnostic ignored "-Wcast-qual" // warning: cast from type 'xxxx' to type 'xxxx' casts away qualifiers
  44. #endif
  45. //-------------------------------------------------------------------------
  46. // STB libraries implementation
  47. //-------------------------------------------------------------------------
  48. //#define IMGUI_STB_NAMESPACE ImGuiStb
  49. //#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
  50. //#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
  51. #ifdef IMGUI_STB_NAMESPACE
  52. namespace IMGUI_STB_NAMESPACE
  53. {
  54. #endif
  55. #ifdef _MSC_VER
  56. #pragma warning (push)
  57. #pragma warning (disable: 4456) // declaration of 'xx' hides previous local declaration
  58. #endif
  59. #ifdef __clang__
  60. #pragma clang diagnostic push
  61. #pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse.
  62. #pragma clang diagnostic ignored "-Wunused-function"
  63. #pragma clang diagnostic ignored "-Wmissing-prototypes"
  64. #endif
  65. #ifdef __GNUC__
  66. #pragma GCC diagnostic push
  67. #pragma GCC diagnostic ignored "-Wtype-limits" // warning: comparison is always true due to limited range of data type [-Wtype-limits]
  68. #endif
  69. #define STBRP_ASSERT(x) IM_ASSERT(x)
  70. #ifndef IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
  71. #define STBRP_STATIC
  72. #define STB_RECT_PACK_IMPLEMENTATION
  73. #endif
  74. #include "stb_rect_pack.h"
  75. #define STBTT_malloc(x,u) ((void)(u), ImGui::MemAlloc(x))
  76. #define STBTT_free(x,u) ((void)(u), ImGui::MemFree(x))
  77. #define STBTT_assert(x) IM_ASSERT(x)
  78. #ifndef IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
  79. #define STBTT_STATIC
  80. #define STB_TRUETYPE_IMPLEMENTATION
  81. #else
  82. #define STBTT_DEF extern
  83. #endif
  84. #include "stb_truetype.h"
  85. #ifdef __GNUC__
  86. #pragma GCC diagnostic pop
  87. #endif
  88. #ifdef __clang__
  89. #pragma clang diagnostic pop
  90. #endif
  91. #ifdef _MSC_VER
  92. #pragma warning (pop)
  93. #endif
  94. #ifdef IMGUI_STB_NAMESPACE
  95. } // namespace ImGuiStb
  96. using namespace IMGUI_STB_NAMESPACE;
  97. #endif
  98. //-----------------------------------------------------------------------------
  99. // ImDrawList
  100. //-----------------------------------------------------------------------------
  101. static const ImVec4 GNullClipRect(-8192.0f, -8192.0f, +8192.0f, +8192.0f); // Large values that are easy to encode in a few bits+shift
  102. void ImDrawList::Clear()
  103. {
  104. CmdBuffer.resize(0);
  105. IdxBuffer.resize(0);
  106. VtxBuffer.resize(0);
  107. _VtxCurrentIdx = 0;
  108. _VtxWritePtr = NULL;
  109. _IdxWritePtr = NULL;
  110. _ClipRectStack.resize(0);
  111. _TextureIdStack.resize(0);
  112. _Path.resize(0);
  113. _ChannelsCurrent = 0;
  114. _ChannelsCount = 1;
  115. // NB: Do not clear channels so our allocations are re-used after the first frame.
  116. }
  117. void ImDrawList::ClearFreeMemory()
  118. {
  119. CmdBuffer.clear();
  120. IdxBuffer.clear();
  121. VtxBuffer.clear();
  122. _VtxCurrentIdx = 0;
  123. _VtxWritePtr = NULL;
  124. _IdxWritePtr = NULL;
  125. _ClipRectStack.clear();
  126. _TextureIdStack.clear();
  127. _Path.clear();
  128. _ChannelsCurrent = 0;
  129. _ChannelsCount = 1;
  130. for (int i = 0; i < _Channels.Size; i++)
  131. {
  132. if (i == 0) memset(&_Channels[0], 0, sizeof(_Channels[0])); // channel 0 is a copy of CmdBuffer/IdxBuffer, don't destruct again
  133. _Channels[i].CmdBuffer.clear();
  134. _Channels[i].IdxBuffer.clear();
  135. }
  136. _Channels.clear();
  137. }
  138. // Use macros because C++ is a terrible language, we want guaranteed inline, no code in header, and no overhead in Debug mode
  139. #define GetCurrentClipRect() (_ClipRectStack.Size ? _ClipRectStack.Data[_ClipRectStack.Size-1] : GNullClipRect)
  140. #define GetCurrentTextureId() (_TextureIdStack.Size ? _TextureIdStack.Data[_TextureIdStack.Size-1] : NULL)
  141. void ImDrawList::AddDrawCmd()
  142. {
  143. ImDrawCmd draw_cmd;
  144. draw_cmd.ClipRect = GetCurrentClipRect();
  145. draw_cmd.TextureId = GetCurrentTextureId();
  146. IM_ASSERT(draw_cmd.ClipRect.x <= draw_cmd.ClipRect.z && draw_cmd.ClipRect.y <= draw_cmd.ClipRect.w);
  147. CmdBuffer.push_back(draw_cmd);
  148. }
  149. void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data)
  150. {
  151. ImDrawCmd* current_cmd = CmdBuffer.Size ? &CmdBuffer.back() : NULL;
  152. if (!current_cmd || current_cmd->ElemCount != 0 || current_cmd->UserCallback != NULL)
  153. {
  154. AddDrawCmd();
  155. current_cmd = &CmdBuffer.back();
  156. }
  157. current_cmd->UserCallback = callback;
  158. current_cmd->UserCallbackData = callback_data;
  159. AddDrawCmd(); // Force a new command after us (see comment below)
  160. }
  161. // Our scheme may appears a bit unusual, basically we want the most-common calls AddLine AddRect etc. to not have to perform any check so we always have a command ready in the stack.
  162. // The cost of figuring out if a new command has to be added or if we can merge is paid in those Update** functions only.
  163. void ImDrawList::UpdateClipRect()
  164. {
  165. // If current command is used with different settings we need to add a new command
  166. const ImVec4 curr_clip_rect = GetCurrentClipRect();
  167. ImDrawCmd* curr_cmd = CmdBuffer.Size > 0 ? &CmdBuffer.Data[CmdBuffer.Size-1] : NULL;
  168. if (!curr_cmd || (curr_cmd->ElemCount != 0 && memcmp(&curr_cmd->ClipRect, &curr_clip_rect, sizeof(ImVec4)) != 0) || curr_cmd->UserCallback != NULL)
  169. {
  170. AddDrawCmd();
  171. return;
  172. }
  173. // Try to merge with previous command if it matches, else use current command
  174. ImDrawCmd* prev_cmd = CmdBuffer.Size > 1 ? curr_cmd - 1 : NULL;
  175. if (curr_cmd->ElemCount == 0 && prev_cmd && memcmp(&prev_cmd->ClipRect, &curr_clip_rect, sizeof(ImVec4)) == 0 && prev_cmd->TextureId == GetCurrentTextureId() && prev_cmd->UserCallback == NULL)
  176. CmdBuffer.pop_back();
  177. else
  178. curr_cmd->ClipRect = curr_clip_rect;
  179. }
  180. void ImDrawList::UpdateTextureID()
  181. {
  182. // If current command is used with different settings we need to add a new command
  183. const ImTextureID curr_texture_id = GetCurrentTextureId();
  184. ImDrawCmd* curr_cmd = CmdBuffer.Size ? &CmdBuffer.back() : NULL;
  185. if (!curr_cmd || (curr_cmd->ElemCount != 0 && curr_cmd->TextureId != curr_texture_id) || curr_cmd->UserCallback != NULL)
  186. {
  187. AddDrawCmd();
  188. return;
  189. }
  190. // Try to merge with previous command if it matches, else use current command
  191. ImDrawCmd* prev_cmd = CmdBuffer.Size > 1 ? curr_cmd - 1 : NULL;
  192. if (prev_cmd && prev_cmd->TextureId == curr_texture_id && memcmp(&prev_cmd->ClipRect, &GetCurrentClipRect(), sizeof(ImVec4)) == 0 && prev_cmd->UserCallback == NULL)
  193. CmdBuffer.pop_back();
  194. else
  195. curr_cmd->TextureId = curr_texture_id;
  196. }
  197. #undef GetCurrentClipRect
  198. #undef GetCurrentTextureId
  199. // Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling)
  200. void ImDrawList::PushClipRect(ImVec2 cr_min, ImVec2 cr_max, bool intersect_with_current_clip_rect)
  201. {
  202. ImVec4 cr(cr_min.x, cr_min.y, cr_max.x, cr_max.y);
  203. if (intersect_with_current_clip_rect && _ClipRectStack.Size)
  204. {
  205. ImVec4 current = _ClipRectStack.Data[_ClipRectStack.Size-1];
  206. if (cr.x < current.x) cr.x = current.x;
  207. if (cr.y < current.y) cr.y = current.y;
  208. if (cr.z > current.z) cr.z = current.z;
  209. if (cr.w > current.w) cr.w = current.w;
  210. }
  211. cr.z = ImMax(cr.x, cr.z);
  212. cr.w = ImMax(cr.y, cr.w);
  213. _ClipRectStack.push_back(cr);
  214. UpdateClipRect();
  215. }
  216. void ImDrawList::PushClipRectFullScreen()
  217. {
  218. PushClipRect(ImVec2(GNullClipRect.x, GNullClipRect.y), ImVec2(GNullClipRect.z, GNullClipRect.w));
  219. //PushClipRect(GetVisibleRect()); // FIXME-OPT: This would be more correct but we're not supposed to access ImGuiContext from here?
  220. }
  221. void ImDrawList::PopClipRect()
  222. {
  223. IM_ASSERT(_ClipRectStack.Size > 0);
  224. _ClipRectStack.pop_back();
  225. UpdateClipRect();
  226. }
  227. void ImDrawList::PushTextureID(const ImTextureID& texture_id)
  228. {
  229. _TextureIdStack.push_back(texture_id);
  230. UpdateTextureID();
  231. }
  232. void ImDrawList::PopTextureID()
  233. {
  234. IM_ASSERT(_TextureIdStack.Size > 0);
  235. _TextureIdStack.pop_back();
  236. UpdateTextureID();
  237. }
  238. void ImDrawList::ChannelsSplit(int channels_count)
  239. {
  240. IM_ASSERT(_ChannelsCurrent == 0 && _ChannelsCount == 1);
  241. int old_channels_count = _Channels.Size;
  242. if (old_channels_count < channels_count)
  243. _Channels.resize(channels_count);
  244. _ChannelsCount = channels_count;
  245. // _Channels[] (24 bytes each) hold storage that we'll swap with this->_CmdBuffer/_IdxBuffer
  246. // The content of _Channels[0] at this point doesn't matter. We clear it to make state tidy in a debugger but we don't strictly need to.
  247. // When we switch to the next channel, we'll copy _CmdBuffer/_IdxBuffer into _Channels[0] and then _Channels[1] into _CmdBuffer/_IdxBuffer
  248. memset(&_Channels[0], 0, sizeof(ImDrawChannel));
  249. for (int i = 1; i < channels_count; i++)
  250. {
  251. if (i >= old_channels_count)
  252. {
  253. IM_PLACEMENT_NEW(&_Channels[i]) ImDrawChannel();
  254. }
  255. else
  256. {
  257. _Channels[i].CmdBuffer.resize(0);
  258. _Channels[i].IdxBuffer.resize(0);
  259. }
  260. if (_Channels[i].CmdBuffer.Size == 0)
  261. {
  262. ImDrawCmd draw_cmd;
  263. draw_cmd.ClipRect = _ClipRectStack.back();
  264. draw_cmd.TextureId = _TextureIdStack.back();
  265. _Channels[i].CmdBuffer.push_back(draw_cmd);
  266. }
  267. }
  268. }
  269. void ImDrawList::ChannelsMerge()
  270. {
  271. // Note that we never use or rely on channels.Size because it is merely a buffer that we never shrink back to 0 to keep all sub-buffers ready for use.
  272. if (_ChannelsCount <= 1)
  273. return;
  274. ChannelsSetCurrent(0);
  275. if (CmdBuffer.Size && CmdBuffer.back().ElemCount == 0)
  276. CmdBuffer.pop_back();
  277. int new_cmd_buffer_count = 0, new_idx_buffer_count = 0;
  278. for (int i = 1; i < _ChannelsCount; i++)
  279. {
  280. ImDrawChannel& ch = _Channels[i];
  281. if (ch.CmdBuffer.Size && ch.CmdBuffer.back().ElemCount == 0)
  282. ch.CmdBuffer.pop_back();
  283. new_cmd_buffer_count += ch.CmdBuffer.Size;
  284. new_idx_buffer_count += ch.IdxBuffer.Size;
  285. }
  286. CmdBuffer.resize(CmdBuffer.Size + new_cmd_buffer_count);
  287. IdxBuffer.resize(IdxBuffer.Size + new_idx_buffer_count);
  288. ImDrawCmd* cmd_write = CmdBuffer.Data + CmdBuffer.Size - new_cmd_buffer_count;
  289. _IdxWritePtr = IdxBuffer.Data + IdxBuffer.Size - new_idx_buffer_count;
  290. for (int i = 1; i < _ChannelsCount; i++)
  291. {
  292. ImDrawChannel& ch = _Channels[i];
  293. if (int sz = ch.CmdBuffer.Size) { memcpy(cmd_write, ch.CmdBuffer.Data, sz * sizeof(ImDrawCmd)); cmd_write += sz; }
  294. if (int sz = ch.IdxBuffer.Size) { memcpy(_IdxWritePtr, ch.IdxBuffer.Data, sz * sizeof(ImDrawIdx)); _IdxWritePtr += sz; }
  295. }
  296. AddDrawCmd();
  297. _ChannelsCount = 1;
  298. }
  299. void ImDrawList::ChannelsSetCurrent(int idx)
  300. {
  301. IM_ASSERT(idx < _ChannelsCount);
  302. if (_ChannelsCurrent == idx) return;
  303. memcpy(&_Channels.Data[_ChannelsCurrent].CmdBuffer, &CmdBuffer, sizeof(CmdBuffer)); // copy 12 bytes, four times
  304. memcpy(&_Channels.Data[_ChannelsCurrent].IdxBuffer, &IdxBuffer, sizeof(IdxBuffer));
  305. _ChannelsCurrent = idx;
  306. memcpy(&CmdBuffer, &_Channels.Data[_ChannelsCurrent].CmdBuffer, sizeof(CmdBuffer));
  307. memcpy(&IdxBuffer, &_Channels.Data[_ChannelsCurrent].IdxBuffer, sizeof(IdxBuffer));
  308. _IdxWritePtr = IdxBuffer.Data + IdxBuffer.Size;
  309. }
  310. // NB: this can be called with negative count for removing primitives (as long as the result does not underflow)
  311. void ImDrawList::PrimReserve(int idx_count, int vtx_count)
  312. {
  313. ImDrawCmd& draw_cmd = CmdBuffer.Data[CmdBuffer.Size-1];
  314. draw_cmd.ElemCount += idx_count;
  315. int vtx_buffer_old_size = VtxBuffer.Size;
  316. VtxBuffer.resize(vtx_buffer_old_size + vtx_count);
  317. _VtxWritePtr = VtxBuffer.Data + vtx_buffer_old_size;
  318. int idx_buffer_old_size = IdxBuffer.Size;
  319. IdxBuffer.resize(idx_buffer_old_size + idx_count);
  320. _IdxWritePtr = IdxBuffer.Data + idx_buffer_old_size;
  321. }
  322. // Fully unrolled with inline call to keep our debug builds decently fast.
  323. void ImDrawList::PrimRect(const ImVec2& a, const ImVec2& c, ImU32 col)
  324. {
  325. ImVec2 b(c.x, a.y), d(a.x, c.y), uv(GImGui->FontTexUvWhitePixel);
  326. ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx;
  327. _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2);
  328. _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3);
  329. _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;
  330. _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col;
  331. _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col;
  332. _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv; _VtxWritePtr[3].col = col;
  333. _VtxWritePtr += 4;
  334. _VtxCurrentIdx += 4;
  335. _IdxWritePtr += 6;
  336. }
  337. void ImDrawList::PrimRectUV(const ImVec2& a, const ImVec2& c, const ImVec2& uv_a, const ImVec2& uv_c, ImU32 col)
  338. {
  339. ImVec2 b(c.x, a.y), d(a.x, c.y), uv_b(uv_c.x, uv_a.y), uv_d(uv_a.x, uv_c.y);
  340. ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx;
  341. _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2);
  342. _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3);
  343. _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv_a; _VtxWritePtr[0].col = col;
  344. _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv_b; _VtxWritePtr[1].col = col;
  345. _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv_c; _VtxWritePtr[2].col = col;
  346. _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv_d; _VtxWritePtr[3].col = col;
  347. _VtxWritePtr += 4;
  348. _VtxCurrentIdx += 4;
  349. _IdxWritePtr += 6;
  350. }
  351. void ImDrawList::PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, const ImVec2& uv_a, const ImVec2& uv_b, const ImVec2& uv_c, const ImVec2& uv_d, ImU32 col)
  352. {
  353. ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx;
  354. _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2);
  355. _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3);
  356. _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv_a; _VtxWritePtr[0].col = col;
  357. _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv_b; _VtxWritePtr[1].col = col;
  358. _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv_c; _VtxWritePtr[2].col = col;
  359. _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv_d; _VtxWritePtr[3].col = col;
  360. _VtxWritePtr += 4;
  361. _VtxCurrentIdx += 4;
  362. _IdxWritePtr += 6;
  363. }
  364. // TODO: Thickness anti-aliased lines cap are missing their AA fringe.
  365. void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 col, bool closed, float thickness, bool anti_aliased)
  366. {
  367. if (points_count < 2)
  368. return;
  369. const ImVec2 uv = GImGui->FontTexUvWhitePixel;
  370. anti_aliased &= GImGui->Style.AntiAliasedLines;
  371. //if (ImGui::GetIO().KeyCtrl) anti_aliased = false; // Debug
  372. int count = points_count;
  373. if (!closed)
  374. count = points_count-1;
  375. const bool thick_line = thickness > 1.0f;
  376. if (anti_aliased)
  377. {
  378. // Anti-aliased stroke
  379. const float AA_SIZE = 1.0f;
  380. const ImU32 col_trans = col & ~IM_COL32_A_MASK;
  381. const int idx_count = thick_line ? count*18 : count*12;
  382. const int vtx_count = thick_line ? points_count*4 : points_count*3;
  383. PrimReserve(idx_count, vtx_count);
  384. // Temporary buffer
  385. ImVec2* temp_normals = (ImVec2*)alloca(points_count * (thick_line ? 5 : 3) * sizeof(ImVec2));
  386. ImVec2* temp_points = temp_normals + points_count;
  387. for (int i1 = 0; i1 < count; i1++)
  388. {
  389. const int i2 = (i1+1) == points_count ? 0 : i1+1;
  390. ImVec2 diff = points[i2] - points[i1];
  391. diff *= ImInvLength(diff, 1.0f);
  392. temp_normals[i1].x = diff.y;
  393. temp_normals[i1].y = -diff.x;
  394. }
  395. if (!closed)
  396. temp_normals[points_count-1] = temp_normals[points_count-2];
  397. if (!thick_line)
  398. {
  399. if (!closed)
  400. {
  401. temp_points[0] = points[0] + temp_normals[0] * AA_SIZE;
  402. temp_points[1] = points[0] - temp_normals[0] * AA_SIZE;
  403. temp_points[(points_count-1)*2+0] = points[points_count-1] + temp_normals[points_count-1] * AA_SIZE;
  404. temp_points[(points_count-1)*2+1] = points[points_count-1] - temp_normals[points_count-1] * AA_SIZE;
  405. }
  406. // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer.
  407. unsigned int idx1 = _VtxCurrentIdx;
  408. for (int i1 = 0; i1 < count; i1++)
  409. {
  410. const int i2 = (i1+1) == points_count ? 0 : i1+1;
  411. unsigned int idx2 = (i1+1) == points_count ? _VtxCurrentIdx : idx1+3;
  412. // Average normals
  413. ImVec2 dm = (temp_normals[i1] + temp_normals[i2]) * 0.5f;
  414. float dmr2 = dm.x*dm.x + dm.y*dm.y;
  415. if (dmr2 > 0.000001f)
  416. {
  417. float scale = 1.0f / dmr2;
  418. if (scale > 100.0f) scale = 100.0f;
  419. dm *= scale;
  420. }
  421. dm *= AA_SIZE;
  422. temp_points[i2*2+0] = points[i2] + dm;
  423. temp_points[i2*2+1] = points[i2] - dm;
  424. // Add indexes
  425. _IdxWritePtr[0] = (ImDrawIdx)(idx2+0); _IdxWritePtr[1] = (ImDrawIdx)(idx1+0); _IdxWritePtr[2] = (ImDrawIdx)(idx1+2);
  426. _IdxWritePtr[3] = (ImDrawIdx)(idx1+2); _IdxWritePtr[4] = (ImDrawIdx)(idx2+2); _IdxWritePtr[5] = (ImDrawIdx)(idx2+0);
  427. _IdxWritePtr[6] = (ImDrawIdx)(idx2+1); _IdxWritePtr[7] = (ImDrawIdx)(idx1+1); _IdxWritePtr[8] = (ImDrawIdx)(idx1+0);
  428. _IdxWritePtr[9] = (ImDrawIdx)(idx1+0); _IdxWritePtr[10]= (ImDrawIdx)(idx2+0); _IdxWritePtr[11]= (ImDrawIdx)(idx2+1);
  429. _IdxWritePtr += 12;
  430. idx1 = idx2;
  431. }
  432. // Add vertexes
  433. for (int i = 0; i < points_count; i++)
  434. {
  435. _VtxWritePtr[0].pos = points[i]; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;
  436. _VtxWritePtr[1].pos = temp_points[i*2+0]; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col_trans;
  437. _VtxWritePtr[2].pos = temp_points[i*2+1]; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col_trans;
  438. _VtxWritePtr += 3;
  439. }
  440. }
  441. else
  442. {
  443. const float half_inner_thickness = (thickness - AA_SIZE) * 0.5f;
  444. if (!closed)
  445. {
  446. temp_points[0] = points[0] + temp_normals[0] * (half_inner_thickness + AA_SIZE);
  447. temp_points[1] = points[0] + temp_normals[0] * (half_inner_thickness);
  448. temp_points[2] = points[0] - temp_normals[0] * (half_inner_thickness);
  449. temp_points[3] = points[0] - temp_normals[0] * (half_inner_thickness + AA_SIZE);
  450. temp_points[(points_count-1)*4+0] = points[points_count-1] + temp_normals[points_count-1] * (half_inner_thickness + AA_SIZE);
  451. temp_points[(points_count-1)*4+1] = points[points_count-1] + temp_normals[points_count-1] * (half_inner_thickness);
  452. temp_points[(points_count-1)*4+2] = points[points_count-1] - temp_normals[points_count-1] * (half_inner_thickness);
  453. temp_points[(points_count-1)*4+3] = points[points_count-1] - temp_normals[points_count-1] * (half_inner_thickness + AA_SIZE);
  454. }
  455. // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer.
  456. unsigned int idx1 = _VtxCurrentIdx;
  457. for (int i1 = 0; i1 < count; i1++)
  458. {
  459. const int i2 = (i1+1) == points_count ? 0 : i1+1;
  460. unsigned int idx2 = (i1+1) == points_count ? _VtxCurrentIdx : idx1+4;
  461. // Average normals
  462. ImVec2 dm = (temp_normals[i1] + temp_normals[i2]) * 0.5f;
  463. float dmr2 = dm.x*dm.x + dm.y*dm.y;
  464. if (dmr2 > 0.000001f)
  465. {
  466. float scale = 1.0f / dmr2;
  467. if (scale > 100.0f) scale = 100.0f;
  468. dm *= scale;
  469. }
  470. ImVec2 dm_out = dm * (half_inner_thickness + AA_SIZE);
  471. ImVec2 dm_in = dm * half_inner_thickness;
  472. temp_points[i2*4+0] = points[i2] + dm_out;
  473. temp_points[i2*4+1] = points[i2] + dm_in;
  474. temp_points[i2*4+2] = points[i2] - dm_in;
  475. temp_points[i2*4+3] = points[i2] - dm_out;
  476. // Add indexes
  477. _IdxWritePtr[0] = (ImDrawIdx)(idx2+1); _IdxWritePtr[1] = (ImDrawIdx)(idx1+1); _IdxWritePtr[2] = (ImDrawIdx)(idx1+2);
  478. _IdxWritePtr[3] = (ImDrawIdx)(idx1+2); _IdxWritePtr[4] = (ImDrawIdx)(idx2+2); _IdxWritePtr[5] = (ImDrawIdx)(idx2+1);
  479. _IdxWritePtr[6] = (ImDrawIdx)(idx2+1); _IdxWritePtr[7] = (ImDrawIdx)(idx1+1); _IdxWritePtr[8] = (ImDrawIdx)(idx1+0);
  480. _IdxWritePtr[9] = (ImDrawIdx)(idx1+0); _IdxWritePtr[10] = (ImDrawIdx)(idx2+0); _IdxWritePtr[11] = (ImDrawIdx)(idx2+1);
  481. _IdxWritePtr[12] = (ImDrawIdx)(idx2+2); _IdxWritePtr[13] = (ImDrawIdx)(idx1+2); _IdxWritePtr[14] = (ImDrawIdx)(idx1+3);
  482. _IdxWritePtr[15] = (ImDrawIdx)(idx1+3); _IdxWritePtr[16] = (ImDrawIdx)(idx2+3); _IdxWritePtr[17] = (ImDrawIdx)(idx2+2);
  483. _IdxWritePtr += 18;
  484. idx1 = idx2;
  485. }
  486. // Add vertexes
  487. for (int i = 0; i < points_count; i++)
  488. {
  489. _VtxWritePtr[0].pos = temp_points[i*4+0]; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col_trans;
  490. _VtxWritePtr[1].pos = temp_points[i*4+1]; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col;
  491. _VtxWritePtr[2].pos = temp_points[i*4+2]; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col;
  492. _VtxWritePtr[3].pos = temp_points[i*4+3]; _VtxWritePtr[3].uv = uv; _VtxWritePtr[3].col = col_trans;
  493. _VtxWritePtr += 4;
  494. }
  495. }
  496. _VtxCurrentIdx += (ImDrawIdx)vtx_count;
  497. }
  498. else
  499. {
  500. // Non Anti-aliased Stroke
  501. const int idx_count = count*6;
  502. const int vtx_count = count*4; // FIXME-OPT: Not sharing edges
  503. PrimReserve(idx_count, vtx_count);
  504. for (int i1 = 0; i1 < count; i1++)
  505. {
  506. const int i2 = (i1+1) == points_count ? 0 : i1+1;
  507. const ImVec2& p1 = points[i1];
  508. const ImVec2& p2 = points[i2];
  509. ImVec2 diff = p2 - p1;
  510. diff *= ImInvLength(diff, 1.0f);
  511. const float dx = diff.x * (thickness * 0.5f);
  512. const float dy = diff.y * (thickness * 0.5f);
  513. _VtxWritePtr[0].pos.x = p1.x + dy; _VtxWritePtr[0].pos.y = p1.y - dx; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;
  514. _VtxWritePtr[1].pos.x = p2.x + dy; _VtxWritePtr[1].pos.y = p2.y - dx; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col;
  515. _VtxWritePtr[2].pos.x = p2.x - dy; _VtxWritePtr[2].pos.y = p2.y + dx; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col;
  516. _VtxWritePtr[3].pos.x = p1.x - dy; _VtxWritePtr[3].pos.y = p1.y + dx; _VtxWritePtr[3].uv = uv; _VtxWritePtr[3].col = col;
  517. _VtxWritePtr += 4;
  518. _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx+1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx+2);
  519. _IdxWritePtr[3] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[4] = (ImDrawIdx)(_VtxCurrentIdx+2); _IdxWritePtr[5] = (ImDrawIdx)(_VtxCurrentIdx+3);
  520. _IdxWritePtr += 6;
  521. _VtxCurrentIdx += 4;
  522. }
  523. }
  524. }
  525. void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_count, ImU32 col, bool anti_aliased)
  526. {
  527. const ImVec2 uv = GImGui->FontTexUvWhitePixel;
  528. anti_aliased &= GImGui->Style.AntiAliasedShapes;
  529. //if (ImGui::GetIO().KeyCtrl) anti_aliased = false; // Debug
  530. if (anti_aliased)
  531. {
  532. // Anti-aliased Fill
  533. const float AA_SIZE = 1.0f;
  534. const ImU32 col_trans = col & ~IM_COL32_A_MASK;
  535. const int idx_count = (points_count-2)*3 + points_count*6;
  536. const int vtx_count = (points_count*2);
  537. PrimReserve(idx_count, vtx_count);
  538. // Add indexes for fill
  539. unsigned int vtx_inner_idx = _VtxCurrentIdx;
  540. unsigned int vtx_outer_idx = _VtxCurrentIdx+1;
  541. for (int i = 2; i < points_count; i++)
  542. {
  543. _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx+((i-1)<<1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_inner_idx+(i<<1));
  544. _IdxWritePtr += 3;
  545. }
  546. // Compute normals
  547. ImVec2* temp_normals = (ImVec2*)alloca(points_count * sizeof(ImVec2));
  548. for (int i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++)
  549. {
  550. const ImVec2& p0 = points[i0];
  551. const ImVec2& p1 = points[i1];
  552. ImVec2 diff = p1 - p0;
  553. diff *= ImInvLength(diff, 1.0f);
  554. temp_normals[i0].x = diff.y;
  555. temp_normals[i0].y = -diff.x;
  556. }
  557. for (int i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++)
  558. {
  559. // Average normals
  560. const ImVec2& n0 = temp_normals[i0];
  561. const ImVec2& n1 = temp_normals[i1];
  562. ImVec2 dm = (n0 + n1) * 0.5f;
  563. float dmr2 = dm.x*dm.x + dm.y*dm.y;
  564. if (dmr2 > 0.000001f)
  565. {
  566. float scale = 1.0f / dmr2;
  567. if (scale > 100.0f) scale = 100.0f;
  568. dm *= scale;
  569. }
  570. dm *= AA_SIZE * 0.5f;
  571. // Add vertices
  572. _VtxWritePtr[0].pos = (points[i1] - dm); _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; // Inner
  573. _VtxWritePtr[1].pos = (points[i1] + dm); _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col_trans; // Outer
  574. _VtxWritePtr += 2;
  575. // Add indexes for fringes
  576. _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx+(i1<<1)); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx+(i0<<1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_outer_idx+(i0<<1));
  577. _IdxWritePtr[3] = (ImDrawIdx)(vtx_outer_idx+(i0<<1)); _IdxWritePtr[4] = (ImDrawIdx)(vtx_outer_idx+(i1<<1)); _IdxWritePtr[5] = (ImDrawIdx)(vtx_inner_idx+(i1<<1));
  578. _IdxWritePtr += 6;
  579. }
  580. _VtxCurrentIdx += (ImDrawIdx)vtx_count;
  581. }
  582. else
  583. {
  584. // Non Anti-aliased Fill
  585. const int idx_count = (points_count-2)*3;
  586. const int vtx_count = points_count;
  587. PrimReserve(idx_count, vtx_count);
  588. for (int i = 0; i < vtx_count; i++)
  589. {
  590. _VtxWritePtr[0].pos = points[i]; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;
  591. _VtxWritePtr++;
  592. }
  593. for (int i = 2; i < points_count; i++)
  594. {
  595. _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx+i-1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx+i);
  596. _IdxWritePtr += 3;
  597. }
  598. _VtxCurrentIdx += (ImDrawIdx)vtx_count;
  599. }
  600. }
  601. void ImDrawList::PathArcToFast(const ImVec2& centre, float radius, int a_min_of_12, int a_max_of_12)
  602. {
  603. static ImVec2 circle_vtx[12];
  604. static bool circle_vtx_builds = false;
  605. const int circle_vtx_count = IM_ARRAYSIZE(circle_vtx);
  606. if (!circle_vtx_builds)
  607. {
  608. for (int i = 0; i < circle_vtx_count; i++)
  609. {
  610. const float a = ((float)i / (float)circle_vtx_count) * 2*IM_PI;
  611. circle_vtx[i].x = cosf(a);
  612. circle_vtx[i].y = sinf(a);
  613. }
  614. circle_vtx_builds = true;
  615. }
  616. if (a_min_of_12 > a_max_of_12) return;
  617. if (radius == 0.0f)
  618. {
  619. _Path.push_back(centre);
  620. }
  621. else
  622. {
  623. _Path.reserve(_Path.Size + (a_max_of_12 - a_min_of_12 + 1));
  624. for (int a = a_min_of_12; a <= a_max_of_12; a++)
  625. {
  626. const ImVec2& c = circle_vtx[a % circle_vtx_count];
  627. _Path.push_back(ImVec2(centre.x + c.x * radius, centre.y + c.y * radius));
  628. }
  629. }
  630. }
  631. void ImDrawList::PathArcTo(const ImVec2& centre, float radius, float amin, float amax, int num_segments)
  632. {
  633. if (radius == 0.0f)
  634. _Path.push_back(centre);
  635. _Path.reserve(_Path.Size + (num_segments + 1));
  636. for (int i = 0; i <= num_segments; i++)
  637. {
  638. const float a = amin + ((float)i / (float)num_segments) * (amax - amin);
  639. _Path.push_back(ImVec2(centre.x + cosf(a) * radius, centre.y + sinf(a) * radius));
  640. }
  641. }
  642. static void PathBezierToCasteljau(ImVector<ImVec2>* path, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float tess_tol, int level)
  643. {
  644. float dx = x4 - x1;
  645. float dy = y4 - y1;
  646. float d2 = ((x2 - x4) * dy - (y2 - y4) * dx);
  647. float d3 = ((x3 - x4) * dy - (y3 - y4) * dx);
  648. d2 = (d2 >= 0) ? d2 : -d2;
  649. d3 = (d3 >= 0) ? d3 : -d3;
  650. if ((d2+d3) * (d2+d3) < tess_tol * (dx*dx + dy*dy))
  651. {
  652. path->push_back(ImVec2(x4, y4));
  653. }
  654. else if (level < 10)
  655. {
  656. float x12 = (x1+x2)*0.5f, y12 = (y1+y2)*0.5f;
  657. float x23 = (x2+x3)*0.5f, y23 = (y2+y3)*0.5f;
  658. float x34 = (x3+x4)*0.5f, y34 = (y3+y4)*0.5f;
  659. float x123 = (x12+x23)*0.5f, y123 = (y12+y23)*0.5f;
  660. float x234 = (x23+x34)*0.5f, y234 = (y23+y34)*0.5f;
  661. float x1234 = (x123+x234)*0.5f, y1234 = (y123+y234)*0.5f;
  662. PathBezierToCasteljau(path, x1,y1, x12,y12, x123,y123, x1234,y1234, tess_tol, level+1);
  663. PathBezierToCasteljau(path, x1234,y1234, x234,y234, x34,y34, x4,y4, tess_tol, level+1);
  664. }
  665. }
  666. void ImDrawList::PathBezierCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments)
  667. {
  668. ImVec2 p1 = _Path.back();
  669. if (num_segments == 0)
  670. {
  671. // Auto-tessellated
  672. PathBezierToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, GImGui->Style.CurveTessellationTol, 0);
  673. }
  674. else
  675. {
  676. float t_step = 1.0f / (float)num_segments;
  677. for (int i_step = 1; i_step <= num_segments; i_step++)
  678. {
  679. float t = t_step * i_step;
  680. float u = 1.0f - t;
  681. float w1 = u*u*u;
  682. float w2 = 3*u*u*t;
  683. float w3 = 3*u*t*t;
  684. float w4 = t*t*t;
  685. _Path.push_back(ImVec2(w1*p1.x + w2*p2.x + w3*p3.x + w4*p4.x, w1*p1.y + w2*p2.y + w3*p3.y + w4*p4.y));
  686. }
  687. }
  688. }
  689. void ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, int rounding_corners)
  690. {
  691. const int corners_top = ImGuiCorner_TopLeft | ImGuiCorner_TopRight;
  692. const int corners_bottom = ImGuiCorner_BottomLeft | ImGuiCorner_BottomRight;
  693. const int corners_left = ImGuiCorner_TopLeft | ImGuiCorner_BottomLeft;
  694. const int corners_right = ImGuiCorner_TopRight | ImGuiCorner_BottomRight;
  695. float r = rounding;
  696. r = ImMin(r, fabsf(b.x-a.x) * ( ((rounding_corners & corners_top) == corners_top) || ((rounding_corners & corners_bottom) == corners_bottom) ? 0.5f : 1.0f ) - 1.0f);
  697. r = ImMin(r, fabsf(b.y-a.y) * ( ((rounding_corners & corners_left) == corners_left) || ((rounding_corners & corners_right) == corners_right) ? 0.5f : 1.0f ) - 1.0f);
  698. if (r <= 0.0f || rounding_corners == 0)
  699. {
  700. PathLineTo(a);
  701. PathLineTo(ImVec2(b.x,a.y));
  702. PathLineTo(b);
  703. PathLineTo(ImVec2(a.x,b.y));
  704. }
  705. else
  706. {
  707. const float r0 = (rounding_corners & ImGuiCorner_TopLeft) ? r : 0.0f;
  708. const float r1 = (rounding_corners & ImGuiCorner_TopRight) ? r : 0.0f;
  709. const float r2 = (rounding_corners & ImGuiCorner_BottomRight) ? r : 0.0f;
  710. const float r3 = (rounding_corners & ImGuiCorner_BottomLeft) ? r : 0.0f;
  711. PathArcToFast(ImVec2(a.x+r0,a.y+r0), r0, 6, 9);
  712. PathArcToFast(ImVec2(b.x-r1,a.y+r1), r1, 9, 12);
  713. PathArcToFast(ImVec2(b.x-r2,b.y-r2), r2, 0, 3);
  714. PathArcToFast(ImVec2(a.x+r3,b.y-r3), r3, 3, 6);
  715. }
  716. }
  717. void ImDrawList::AddLine(const ImVec2& a, const ImVec2& b, ImU32 col, float thickness)
  718. {
  719. if ((col & IM_COL32_A_MASK) == 0)
  720. return;
  721. PathLineTo(a + ImVec2(0.5f,0.5f));
  722. PathLineTo(b + ImVec2(0.5f,0.5f));
  723. PathStroke(col, false, thickness);
  724. }
  725. // a: upper-left, b: lower-right. we don't render 1 px sized rectangles properly.
  726. void ImDrawList::AddRect(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding, int rounding_corners_flags, float thickness)
  727. {
  728. if ((col & IM_COL32_A_MASK) == 0)
  729. return;
  730. PathRect(a + ImVec2(0.5f,0.5f), b - ImVec2(0.5f,0.5f), rounding, rounding_corners_flags);
  731. PathStroke(col, true, thickness);
  732. }
  733. void ImDrawList::AddRectFilled(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding, int rounding_corners_flags)
  734. {
  735. if ((col & IM_COL32_A_MASK) == 0)
  736. return;
  737. if (rounding > 0.0f)
  738. {
  739. PathRect(a, b, rounding, rounding_corners_flags);
  740. PathFillConvex(col);
  741. }
  742. else
  743. {
  744. PrimReserve(6, 4);
  745. PrimRect(a, b, col);
  746. }
  747. }
  748. void ImDrawList::AddRectFilledMultiColor(const ImVec2& a, const ImVec2& c, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left)
  749. {
  750. if (((col_upr_left | col_upr_right | col_bot_right | col_bot_left) & IM_COL32_A_MASK) == 0)
  751. return;
  752. const ImVec2 uv = GImGui->FontTexUvWhitePixel;
  753. PrimReserve(6, 4);
  754. PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx+1)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx+2));
  755. PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx+2)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx+3));
  756. PrimWriteVtx(a, uv, col_upr_left);
  757. PrimWriteVtx(ImVec2(c.x, a.y), uv, col_upr_right);
  758. PrimWriteVtx(c, uv, col_bot_right);
  759. PrimWriteVtx(ImVec2(a.x, c.y), uv, col_bot_left);
  760. }
  761. void ImDrawList::AddQuad(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, ImU32 col, float thickness)
  762. {
  763. if ((col & IM_COL32_A_MASK) == 0)
  764. return;
  765. PathLineTo(a);
  766. PathLineTo(b);
  767. PathLineTo(c);
  768. PathLineTo(d);
  769. PathStroke(col, true, thickness);
  770. }
  771. void ImDrawList::AddQuadFilled(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, ImU32 col)
  772. {
  773. if ((col & IM_COL32_A_MASK) == 0)
  774. return;
  775. PathLineTo(a);
  776. PathLineTo(b);
  777. PathLineTo(c);
  778. PathLineTo(d);
  779. PathFillConvex(col);
  780. }
  781. void ImDrawList::AddTriangle(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col, float thickness)
  782. {
  783. if ((col & IM_COL32_A_MASK) == 0)
  784. return;
  785. PathLineTo(a);
  786. PathLineTo(b);
  787. PathLineTo(c);
  788. PathStroke(col, true, thickness);
  789. }
  790. void ImDrawList::AddTriangleFilled(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col)
  791. {
  792. if ((col & IM_COL32_A_MASK) == 0)
  793. return;
  794. PathLineTo(a);
  795. PathLineTo(b);
  796. PathLineTo(c);
  797. PathFillConvex(col);
  798. }
  799. void ImDrawList::AddCircle(const ImVec2& centre, float radius, ImU32 col, int num_segments, float thickness)
  800. {
  801. if ((col & IM_COL32_A_MASK) == 0)
  802. return;
  803. const float a_max = IM_PI*2.0f * ((float)num_segments - 1.0f) / (float)num_segments;
  804. PathArcTo(centre, radius-0.5f, 0.0f, a_max, num_segments);
  805. PathStroke(col, true, thickness);
  806. }
  807. void ImDrawList::AddCircleFilled(const ImVec2& centre, float radius, ImU32 col, int num_segments)
  808. {
  809. if ((col & IM_COL32_A_MASK) == 0)
  810. return;
  811. const float a_max = IM_PI*2.0f * ((float)num_segments - 1.0f) / (float)num_segments;
  812. PathArcTo(centre, radius, 0.0f, a_max, num_segments);
  813. PathFillConvex(col);
  814. }
  815. void ImDrawList::AddBezierCurve(const ImVec2& pos0, const ImVec2& cp0, const ImVec2& cp1, const ImVec2& pos1, ImU32 col, float thickness, int num_segments)
  816. {
  817. if ((col & IM_COL32_A_MASK) == 0)
  818. return;
  819. PathLineTo(pos0);
  820. PathBezierCurveTo(cp0, cp1, pos1, num_segments);
  821. PathStroke(col, false, thickness);
  822. }
  823. void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end, float wrap_width, const ImVec4* cpu_fine_clip_rect)
  824. {
  825. if ((col & IM_COL32_A_MASK) == 0)
  826. return;
  827. if (text_end == NULL)
  828. text_end = text_begin + strlen(text_begin);
  829. if (text_begin == text_end)
  830. return;
  831. // IMPORTANT: This is one of the few instance of breaking the encapsulation of ImDrawList, as we pull this from ImGui state, but it is just SO useful.
  832. // Might just move Font/FontSize to ImDrawList?
  833. if (font == NULL)
  834. font = GImGui->Font;
  835. if (font_size == 0.0f)
  836. font_size = GImGui->FontSize;
  837. IM_ASSERT(font->ContainerAtlas->TexID == _TextureIdStack.back()); // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font.
  838. ImVec4 clip_rect = _ClipRectStack.back();
  839. if (cpu_fine_clip_rect)
  840. {
  841. clip_rect.x = ImMax(clip_rect.x, cpu_fine_clip_rect->x);
  842. clip_rect.y = ImMax(clip_rect.y, cpu_fine_clip_rect->y);
  843. clip_rect.z = ImMin(clip_rect.z, cpu_fine_clip_rect->z);
  844. clip_rect.w = ImMin(clip_rect.w, cpu_fine_clip_rect->w);
  845. }
  846. font->RenderText(this, font_size, pos, col, clip_rect, text_begin, text_end, wrap_width, cpu_fine_clip_rect != NULL);
  847. }
  848. void ImDrawList::AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end)
  849. {
  850. AddText(NULL, 0.0f, pos, col, text_begin, text_end);
  851. }
  852. void ImDrawList::AddImage(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col)
  853. {
  854. if ((col & IM_COL32_A_MASK) == 0)
  855. return;
  856. // FIXME-OPT: This is wasting draw calls.
  857. const bool push_texture_id = _TextureIdStack.empty() || user_texture_id != _TextureIdStack.back();
  858. if (push_texture_id)
  859. PushTextureID(user_texture_id);
  860. PrimReserve(6, 4);
  861. PrimRectUV(a, b, uv_a, uv_b, col);
  862. if (push_texture_id)
  863. PopTextureID();
  864. }
  865. void ImDrawList::AddImageQuad(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, const ImVec2& uv_a, const ImVec2& uv_b, const ImVec2& uv_c, const ImVec2& uv_d, ImU32 col)
  866. {
  867. if ((col & IM_COL32_A_MASK) == 0)
  868. return;
  869. const bool push_texture_id = _TextureIdStack.empty() || user_texture_id != _TextureIdStack.back();
  870. if (push_texture_id)
  871. PushTextureID(user_texture_id);
  872. PrimReserve(6, 4);
  873. PrimQuadUV(a, b, c, d, uv_a, uv_b, uv_c, uv_d, col);
  874. if (push_texture_id)
  875. PopTextureID();
  876. }
  877. //-----------------------------------------------------------------------------
  878. // ImDrawData
  879. //-----------------------------------------------------------------------------
  880. // For backward compatibility: convert all buffers from indexed to de-indexed, in case you cannot render indexed. Note: this is slow and most likely a waste of resources. Always prefer indexed rendering!
  881. void ImDrawData::DeIndexAllBuffers()
  882. {
  883. ImVector<ImDrawVert> new_vtx_buffer;
  884. TotalVtxCount = TotalIdxCount = 0;
  885. for (int i = 0; i < CmdListsCount; i++)
  886. {
  887. ImDrawList* cmd_list = CmdLists[i];
  888. if (cmd_list->IdxBuffer.empty())
  889. continue;
  890. new_vtx_buffer.resize(cmd_list->IdxBuffer.Size);
  891. for (int j = 0; j < cmd_list->IdxBuffer.Size; j++)
  892. new_vtx_buffer[j] = cmd_list->VtxBuffer[cmd_list->IdxBuffer[j]];
  893. cmd_list->VtxBuffer.swap(new_vtx_buffer);
  894. cmd_list->IdxBuffer.resize(0);
  895. TotalVtxCount += cmd_list->VtxBuffer.Size;
  896. }
  897. }
  898. // Helper to scale the ClipRect field of each ImDrawCmd. Use if your final output buffer is at a different scale than ImGui expects, or if there is a difference between your window resolution and framebuffer resolution.
  899. void ImDrawData::ScaleClipRects(const ImVec2& scale)
  900. {
  901. for (int i = 0; i < CmdListsCount; i++)
  902. {
  903. ImDrawList* cmd_list = CmdLists[i];
  904. for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
  905. {
  906. ImDrawCmd* cmd = &cmd_list->CmdBuffer[cmd_i];
  907. cmd->ClipRect = ImVec4(cmd->ClipRect.x * scale.x, cmd->ClipRect.y * scale.y, cmd->ClipRect.z * scale.x, cmd->ClipRect.w * scale.y);
  908. }
  909. }
  910. }
  911. //-----------------------------------------------------------------------------
  912. // ImFontConfig
  913. //-----------------------------------------------------------------------------
  914. ImFontConfig::ImFontConfig()
  915. {
  916. FontData = NULL;
  917. FontDataSize = 0;
  918. FontDataOwnedByAtlas = true;
  919. FontNo = 0;
  920. SizePixels = 0.0f;
  921. OversampleH = 3;
  922. OversampleV = 1;
  923. PixelSnapH = false;
  924. GlyphExtraSpacing = ImVec2(0.0f, 0.0f);
  925. GlyphOffset = ImVec2(0.0f, 0.0f);
  926. GlyphRanges = NULL;
  927. MergeMode = false;
  928. DstFont = NULL;
  929. memset(Name, 0, sizeof(Name));
  930. }
  931. //-----------------------------------------------------------------------------
  932. // ImFontAtlas
  933. //-----------------------------------------------------------------------------
  934. // A work of art lies ahead! (. = white layer, X = black layer, others are blank)
  935. // The white texels on the top left are the ones we'll use everywhere in ImGui to render filled shapes.
  936. const int FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF = 90;
  937. const int FONT_ATLAS_DEFAULT_TEX_DATA_H = 27;
  938. const int FONT_ATLAS_DEFAULT_TEX_DATA_ID = 0xF0000;
  939. const char FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF * FONT_ATLAS_DEFAULT_TEX_DATA_H + 1] =
  940. {
  941. "..- -XXXXXXX- X - X -XXXXXXX - XXXXXXX"
  942. "..- -X.....X- X.X - X.X -X.....X - X.....X"
  943. "--- -XXX.XXX- X...X - X...X -X....X - X....X"
  944. "X - X.X - X.....X - X.....X -X...X - X...X"
  945. "XX - X.X -X.......X- X.......X -X..X.X - X.X..X"
  946. "X.X - X.X -XXXX.XXXX- XXXX.XXXX -X.X X.X - X.X X.X"
  947. "X..X - X.X - X.X - X.X -XX X.X - X.X XX"
  948. "X...X - X.X - X.X - XX X.X XX - X.X - X.X "
  949. "X....X - X.X - X.X - X.X X.X X.X - X.X - X.X "
  950. "X.....X - X.X - X.X - X..X X.X X..X - X.X - X.X "
  951. "X......X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X XX-XX X.X "
  952. "X.......X - X.X - X.X -X.....................X- X.X X.X-X.X X.X "
  953. "X........X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X..X-X..X.X "
  954. "X.........X -XXX.XXX- X.X - X..X X.X X..X - X...X-X...X "
  955. "X..........X-X.....X- X.X - X.X X.X X.X - X....X-X....X "
  956. "X......XXXXX-XXXXXXX- X.X - XX X.X XX - X.....X-X.....X "
  957. "X...X..X --------- X.X - X.X - XXXXXXX-XXXXXXX "
  958. "X..X X..X - -XXXX.XXXX- XXXX.XXXX ------------------------------------"
  959. "X.X X..X - -X.......X- X.......X - XX XX - "
  960. "XX X..X - - X.....X - X.....X - X.X X.X - "
  961. " X..X - X...X - X...X - X..X X..X - "
  962. " XX - X.X - X.X - X...XXXXXXXXXXXXX...X - "
  963. "------------ - X - X -X.....................X- "
  964. " ----------------------------------- X...XXXXXXXXXXXXX...X - "
  965. " - X..X X..X - "
  966. " - X.X X.X - "
  967. " - XX XX - "
  968. };
  969. ImFontAtlas::ImFontAtlas()
  970. {
  971. TexID = NULL;
  972. TexPixelsAlpha8 = NULL;
  973. TexPixelsRGBA32 = NULL;
  974. TexWidth = TexHeight = TexDesiredWidth = 0;
  975. TexGlyphPadding = 1;
  976. TexUvWhitePixel = ImVec2(0, 0);
  977. }
  978. ImFontAtlas::~ImFontAtlas()
  979. {
  980. Clear();
  981. }
  982. void ImFontAtlas::ClearInputData()
  983. {
  984. for (int i = 0; i < ConfigData.Size; i++)
  985. if (ConfigData[i].FontData && ConfigData[i].FontDataOwnedByAtlas)
  986. {
  987. ImGui::MemFree(ConfigData[i].FontData);
  988. ConfigData[i].FontData = NULL;
  989. }
  990. // When clearing this we lose access to the font name and other information used to build the font.
  991. for (int i = 0; i < Fonts.Size; i++)
  992. if (Fonts[i]->ConfigData >= ConfigData.Data && Fonts[i]->ConfigData < ConfigData.Data + ConfigData.Size)
  993. {
  994. Fonts[i]->ConfigData = NULL;
  995. Fonts[i]->ConfigDataCount = 0;
  996. }
  997. ConfigData.clear();
  998. CustomRects.clear();
  999. }
  1000. void ImFontAtlas::ClearTexData()
  1001. {
  1002. if (TexPixelsAlpha8)
  1003. ImGui::MemFree(TexPixelsAlpha8);
  1004. if (TexPixelsRGBA32)
  1005. ImGui::MemFree(TexPixelsRGBA32);
  1006. TexPixelsAlpha8 = NULL;
  1007. TexPixelsRGBA32 = NULL;
  1008. }
  1009. void ImFontAtlas::ClearFonts()
  1010. {
  1011. for (int i = 0; i < Fonts.Size; i++)
  1012. {
  1013. Fonts[i]->~ImFont();
  1014. ImGui::MemFree(Fonts[i]);
  1015. }
  1016. Fonts.clear();
  1017. }
  1018. void ImFontAtlas::Clear()
  1019. {
  1020. ClearInputData();
  1021. ClearTexData();
  1022. ClearFonts();
  1023. }
  1024. void ImFontAtlas::GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel)
  1025. {
  1026. // Build atlas on demand
  1027. if (TexPixelsAlpha8 == NULL)
  1028. {
  1029. if (ConfigData.empty())
  1030. AddFontDefault();
  1031. Build();
  1032. }
  1033. *out_pixels = TexPixelsAlpha8;
  1034. if (out_width) *out_width = TexWidth;
  1035. if (out_height) *out_height = TexHeight;
  1036. if (out_bytes_per_pixel) *out_bytes_per_pixel = 1;
  1037. }
  1038. void ImFontAtlas::GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel)
  1039. {
  1040. // Convert to RGBA32 format on demand
  1041. // Although it is likely to be the most commonly used format, our font rendering is 1 channel / 8 bpp
  1042. if (!TexPixelsRGBA32)
  1043. {
  1044. unsigned char* pixels;
  1045. GetTexDataAsAlpha8(&pixels, NULL, NULL);
  1046. TexPixelsRGBA32 = (unsigned int*)ImGui::MemAlloc((size_t)(TexWidth * TexHeight * 4));
  1047. const unsigned char* src = pixels;
  1048. unsigned int* dst = TexPixelsRGBA32;
  1049. for (int n = TexWidth * TexHeight; n > 0; n--)
  1050. *dst++ = IM_COL32(255, 255, 255, (unsigned int)(*src++));
  1051. }
  1052. *out_pixels = (unsigned char*)TexPixelsRGBA32;
  1053. if (out_width) *out_width = TexWidth;
  1054. if (out_height) *out_height = TexHeight;
  1055. if (out_bytes_per_pixel) *out_bytes_per_pixel = 4;
  1056. }
  1057. ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg)
  1058. {
  1059. IM_ASSERT(font_cfg->FontData != NULL && font_cfg->FontDataSize > 0);
  1060. IM_ASSERT(font_cfg->SizePixels > 0.0f);
  1061. // Create new font
  1062. if (!font_cfg->MergeMode)
  1063. {
  1064. ImFont* font = (ImFont*)ImGui::MemAlloc(sizeof(ImFont));
  1065. IM_PLACEMENT_NEW(font) ImFont();
  1066. Fonts.push_back(font);
  1067. }
  1068. else
  1069. {
  1070. IM_ASSERT(!Fonts.empty()); // When using MergeMode make sure that a font has already been added before. You can use ImGui::GetIO().Fonts->AddFontDefault() to add the default imgui font.
  1071. }
  1072. ConfigData.push_back(*font_cfg);
  1073. ImFontConfig& new_font_cfg = ConfigData.back();
  1074. if (!new_font_cfg.DstFont)
  1075. new_font_cfg.DstFont = Fonts.back();
  1076. if (!new_font_cfg.FontDataOwnedByAtlas)
  1077. {
  1078. new_font_cfg.FontData = ImGui::MemAlloc(new_font_cfg.FontDataSize);
  1079. new_font_cfg.FontDataOwnedByAtlas = true;
  1080. memcpy(new_font_cfg.FontData, font_cfg->FontData, (size_t)new_font_cfg.FontDataSize);
  1081. }
  1082. // Invalidate texture
  1083. ClearTexData();
  1084. return new_font_cfg.DstFont;
  1085. }
  1086. // Default font TTF is compressed with stb_compress then base85 encoded (see extra_fonts/binary_to_compressed_c.cpp for encoder)
  1087. static unsigned int stb_decompress_length(unsigned char *input);
  1088. static unsigned int stb_decompress(unsigned char *output, unsigned char *i, unsigned int length);
  1089. static const char* GetDefaultCompressedFontDataTTFBase85();
  1090. static unsigned int Decode85Byte(char c) { return c >= '\\' ? c-36 : c-35; }
  1091. static void Decode85(const unsigned char* src, unsigned char* dst)
  1092. {
  1093. while (*src)
  1094. {
  1095. unsigned int tmp = Decode85Byte(src[0]) + 85*(Decode85Byte(src[1]) + 85*(Decode85Byte(src[2]) + 85*(Decode85Byte(src[3]) + 85*Decode85Byte(src[4]))));
  1096. dst[0] = ((tmp >> 0) & 0xFF); dst[1] = ((tmp >> 8) & 0xFF); dst[2] = ((tmp >> 16) & 0xFF); dst[3] = ((tmp >> 24) & 0xFF); // We can't assume little-endianness.
  1097. src += 5;
  1098. dst += 4;
  1099. }
  1100. }
  1101. // Load embedded ProggyClean.ttf at size 13, disable oversampling
  1102. ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template)
  1103. {
  1104. ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
  1105. if (!font_cfg_template)
  1106. {
  1107. font_cfg.OversampleH = font_cfg.OversampleV = 1;
  1108. font_cfg.PixelSnapH = true;
  1109. }
  1110. if (font_cfg.Name[0] == '\0') strcpy(font_cfg.Name, "ProggyClean.ttf, 13px");
  1111. if (font_cfg.SizePixels <= 0.0f) font_cfg.SizePixels = 13.0f;
  1112. const char* ttf_compressed_base85 = GetDefaultCompressedFontDataTTFBase85();
  1113. ImFont* font = AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, font_cfg.SizePixels, &font_cfg, GetGlyphRangesDefault());
  1114. return font;
  1115. }
  1116. ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)
  1117. {
  1118. int data_size = 0;
  1119. void* data = ImFileLoadToMemory(filename, "rb", &data_size, 0);
  1120. if (!data)
  1121. {
  1122. IM_ASSERT(0); // Could not load file.
  1123. return NULL;
  1124. }
  1125. ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
  1126. if (font_cfg.Name[0] == '\0')
  1127. {
  1128. // Store a short copy of filename into into the font name for convenience
  1129. const char* p;
  1130. for (p = filename + strlen(filename); p > filename && p[-1] != '/' && p[-1] != '\\'; p--) {}
  1131. snprintf(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "%s, %.0fpx", p, size_pixels);
  1132. }
  1133. return AddFontFromMemoryTTF(data, data_size, size_pixels, &font_cfg, glyph_ranges);
  1134. }
  1135. // NBM Transfer ownership of 'ttf_data' to ImFontAtlas, unless font_cfg_template->FontDataOwnedByAtlas == false. Owned TTF buffer will be deleted after Build().
  1136. ImFont* ImFontAtlas::AddFontFromMemoryTTF(void* ttf_data, int ttf_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)
  1137. {
  1138. ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
  1139. IM_ASSERT(font_cfg.FontData == NULL);
  1140. font_cfg.FontData = ttf_data;
  1141. font_cfg.FontDataSize = ttf_size;
  1142. font_cfg.SizePixels = size_pixels;
  1143. if (glyph_ranges)
  1144. font_cfg.GlyphRanges = glyph_ranges;
  1145. return AddFont(&font_cfg);
  1146. }
  1147. ImFont* ImFontAtlas::AddFontFromMemoryCompressedTTF(const void* compressed_ttf_data, int compressed_ttf_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)
  1148. {
  1149. const unsigned int buf_decompressed_size = stb_decompress_length((unsigned char*)compressed_ttf_data);
  1150. unsigned char* buf_decompressed_data = (unsigned char *)ImGui::MemAlloc(buf_decompressed_size);
  1151. stb_decompress(buf_decompressed_data, (unsigned char*)compressed_ttf_data, (unsigned int)compressed_ttf_size);
  1152. ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
  1153. IM_ASSERT(font_cfg.FontData == NULL);
  1154. font_cfg.FontDataOwnedByAtlas = true;
  1155. return AddFontFromMemoryTTF(buf_decompressed_data, (int)buf_decompressed_size, size_pixels, &font_cfg, glyph_ranges);
  1156. }
  1157. ImFont* ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(const char* compressed_ttf_data_base85, float size_pixels, const ImFontConfig* font_cfg, const ImWchar* glyph_ranges)
  1158. {
  1159. int compressed_ttf_size = (((int)strlen(compressed_ttf_data_base85) + 4) / 5) * 4;
  1160. void* compressed_ttf = ImGui::MemAlloc((size_t)compressed_ttf_size);
  1161. Decode85((const unsigned char*)compressed_ttf_data_base85, (unsigned char*)compressed_ttf);
  1162. ImFont* font = AddFontFromMemoryCompressedTTF(compressed_ttf, compressed_ttf_size, size_pixels, font_cfg, glyph_ranges);
  1163. ImGui::MemFree(compressed_ttf);
  1164. return font;
  1165. }
  1166. int ImFontAtlas::CustomRectRegister(unsigned int id, int width, int height)
  1167. {
  1168. IM_ASSERT(width > 0 && width <= 0xFFFF);
  1169. IM_ASSERT(height > 0 && height <= 0xFFFF);
  1170. CustomRect r;
  1171. r.ID = id;
  1172. r.Width = (unsigned short)width;
  1173. r.Height = (unsigned short)height;
  1174. CustomRects.push_back(r);
  1175. return CustomRects.Size - 1; // Return index
  1176. }
  1177. void ImFontAtlas::CustomRectCalcUV(const CustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max)
  1178. {
  1179. IM_ASSERT(TexWidth > 0 && TexHeight > 0); // Font atlas needs to be built before we can calculate UV coordinates
  1180. IM_ASSERT(rect->IsPacked()); // Make sure the rectangle has been packed
  1181. *out_uv_min = ImVec2((float)rect->X / TexWidth, (float)rect->Y / TexHeight);
  1182. *out_uv_max = ImVec2((float)(rect->X + rect->Width) / TexWidth, (float)(rect->Y + rect->Height) / TexHeight);
  1183. }
  1184. bool ImFontAtlas::Build()
  1185. {
  1186. return ImFontAtlasBuildWithStbTruetype(this);
  1187. }
  1188. bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
  1189. {
  1190. IM_ASSERT(atlas->ConfigData.Size > 0);
  1191. ImFontAtlasBuildRegisterDefaultCustomRects(atlas);
  1192. atlas->TexID = NULL;
  1193. atlas->TexWidth = atlas->TexHeight = 0;
  1194. atlas->TexUvWhitePixel = ImVec2(0, 0);
  1195. atlas->ClearTexData();
  1196. // Count glyphs/ranges
  1197. int total_glyphs_count = 0;
  1198. int total_ranges_count = 0;
  1199. for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
  1200. {
  1201. ImFontConfig& cfg = atlas->ConfigData[input_i];
  1202. if (!cfg.GlyphRanges)
  1203. cfg.GlyphRanges = atlas->GetGlyphRangesDefault();
  1204. for (const ImWchar* in_range = cfg.GlyphRanges; in_range[0] && in_range[1]; in_range += 2, total_ranges_count++)
  1205. total_glyphs_count += (in_range[1] - in_range[0]) + 1;
  1206. }
  1207. // We need a width for the skyline algorithm. Using a dumb heuristic here to decide of width. User can override TexDesiredWidth and TexGlyphPadding if they wish.
  1208. // Width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height.
  1209. atlas->TexWidth = (atlas->TexDesiredWidth > 0) ? atlas->TexDesiredWidth : (total_glyphs_count > 4000) ? 4096 : (total_glyphs_count > 2000) ? 2048 : (total_glyphs_count > 1000) ? 1024 : 512;
  1210. atlas->TexHeight = 0;
  1211. // Start packing
  1212. const int max_tex_height = 1024*32;
  1213. stbtt_pack_context spc;
  1214. stbtt_PackBegin(&spc, NULL, atlas->TexWidth, max_tex_height, 0, atlas->TexGlyphPadding, NULL);
  1215. stbtt_PackSetOversampling(&spc, 1, 1);
  1216. // Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values).
  1217. ImFontAtlasBuildPackCustomRects(atlas, spc.pack_info);
  1218. // Initialize font information (so we can error without any cleanup)
  1219. struct ImFontTempBuildData
  1220. {
  1221. stbtt_fontinfo FontInfo;
  1222. stbrp_rect* Rects;
  1223. stbtt_pack_range* Ranges;
  1224. int RangesCount;
  1225. };
  1226. ImFontTempBuildData* tmp_array = (ImFontTempBuildData*)ImGui::MemAlloc((size_t)atlas->ConfigData.Size * sizeof(ImFontTempBuildData));
  1227. for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
  1228. {
  1229. ImFontConfig& cfg = atlas->ConfigData[input_i];
  1230. ImFontTempBuildData& tmp = tmp_array[input_i];
  1231. IM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas));
  1232. const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)cfg.FontData, cfg.FontNo);
  1233. IM_ASSERT(font_offset >= 0);
  1234. if (!stbtt_InitFont(&tmp.FontInfo, (unsigned char*)cfg.FontData, font_offset))
  1235. return false;
  1236. }
  1237. // Allocate packing character data and flag packed characters buffer as non-packed (x0=y0=x1=y1=0)
  1238. int buf_packedchars_n = 0, buf_rects_n = 0, buf_ranges_n = 0;
  1239. stbtt_packedchar* buf_packedchars = (stbtt_packedchar*)ImGui::MemAlloc(total_glyphs_count * sizeof(stbtt_packedchar));
  1240. stbrp_rect* buf_rects = (stbrp_rect*)ImGui::MemAlloc(total_glyphs_count * sizeof(stbrp_rect));
  1241. stbtt_pack_range* buf_ranges = (stbtt_pack_range*)ImGui::MemAlloc(total_ranges_count * sizeof(stbtt_pack_range));
  1242. memset(buf_packedchars, 0, total_glyphs_count * sizeof(stbtt_packedchar));
  1243. memset(buf_rects, 0, total_glyphs_count * sizeof(stbrp_rect)); // Unnecessary but let's clear this for the sake of sanity.
  1244. memset(buf_ranges, 0, total_ranges_count * sizeof(stbtt_pack_range));
  1245. // First font pass: pack all glyphs (no rendering at this point, we are working with rectangles in an infinitely tall texture at this point)
  1246. for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
  1247. {
  1248. ImFontConfig& cfg = atlas->ConfigData[input_i];
  1249. ImFontTempBuildData& tmp = tmp_array[input_i];
  1250. // Setup ranges
  1251. int font_glyphs_count = 0;
  1252. int font_ranges_count = 0;
  1253. for (const ImWchar* in_range = cfg.GlyphRanges; in_range[0] && in_range[1]; in_range += 2, font_ranges_count++)
  1254. font_glyphs_count += (in_range[1] - in_range[0]) + 1;
  1255. tmp.Ranges = buf_ranges + buf_ranges_n;
  1256. tmp.RangesCount = font_ranges_count;
  1257. buf_ranges_n += font_ranges_count;
  1258. for (int i = 0; i < font_ranges_count; i++)
  1259. {
  1260. const ImWchar* in_range = &cfg.GlyphRanges[i * 2];
  1261. stbtt_pack_range& range = tmp.Ranges[i];
  1262. range.font_size = cfg.SizePixels;
  1263. range.first_unicode_codepoint_in_range = in_range[0];
  1264. range.num_chars = (in_range[1] - in_range[0]) + 1;
  1265. range.chardata_for_range = buf_packedchars + buf_packedchars_n;
  1266. buf_packedchars_n += range.num_chars;
  1267. }
  1268. // Pack
  1269. tmp.Rects = buf_rects + buf_rects_n;
  1270. buf_rects_n += font_glyphs_count;
  1271. stbtt_PackSetOversampling(&spc, cfg.OversampleH, cfg.OversampleV);
  1272. int n = stbtt_PackFontRangesGatherRects(&spc, &tmp.FontInfo, tmp.Ranges, tmp.RangesCount, tmp.Rects);
  1273. IM_ASSERT(n == font_glyphs_count);
  1274. stbrp_pack_rects((stbrp_context*)spc.pack_info, tmp.Rects, n);
  1275. // Extend texture height
  1276. for (int i = 0; i < n; i++)
  1277. if (tmp.Rects[i].was_packed)
  1278. atlas->TexHeight = ImMax(atlas->TexHeight, tmp.Rects[i].y + tmp.Rects[i].h);
  1279. }
  1280. IM_ASSERT(buf_rects_n == total_glyphs_count);
  1281. IM_ASSERT(buf_packedchars_n == total_glyphs_count);
  1282. IM_ASSERT(buf_ranges_n == total_ranges_count);
  1283. // Create texture
  1284. atlas->TexHeight = ImUpperPowerOfTwo(atlas->TexHeight);
  1285. atlas->TexPixelsAlpha8 = (unsigned char*)ImGui::MemAlloc(atlas->TexWidth * atlas->TexHeight);
  1286. memset(atlas->TexPixelsAlpha8, 0, atlas->TexWidth * atlas->TexHeight);
  1287. spc.pixels = atlas->TexPixelsAlpha8;
  1288. spc.height = atlas->TexHeight;
  1289. // Second pass: render font characters
  1290. for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
  1291. {
  1292. ImFontConfig& cfg = atlas->ConfigData[input_i];
  1293. ImFontTempBuildData& tmp = tmp_array[input_i];
  1294. stbtt_PackSetOversampling(&spc, cfg.OversampleH, cfg.OversampleV);
  1295. stbtt_PackFontRangesRenderIntoRects(&spc, &tmp.FontInfo, tmp.Ranges, tmp.RangesCount, tmp.Rects);
  1296. tmp.Rects = NULL;
  1297. }
  1298. // End packing
  1299. stbtt_PackEnd(&spc);
  1300. ImGui::MemFree(buf_rects);
  1301. buf_rects = NULL;
  1302. // Third pass: setup ImFont and glyphs for runtime
  1303. for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
  1304. {
  1305. ImFontConfig& cfg = atlas->ConfigData[input_i];
  1306. ImFontTempBuildData& tmp = tmp_array[input_i];
  1307. ImFont* dst_font = cfg.DstFont; // We can have multiple input fonts writing into a same destination font (when using MergeMode=true)
  1308. float font_scale = stbtt_ScaleForPixelHeight(&tmp.FontInfo, cfg.SizePixels);
  1309. int unscaled_ascent, unscaled_descent, unscaled_line_gap;
  1310. stbtt_GetFontVMetrics(&tmp.FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap);
  1311. float ascent = unscaled_ascent * font_scale;
  1312. float descent = unscaled_descent * font_scale;
  1313. ImFontAtlasBuildSetupFont(atlas, dst_font, &cfg, ascent, descent);
  1314. float off_x = cfg.GlyphOffset.x;
  1315. float off_y = cfg.GlyphOffset.y + (float)(int)(dst_font->Ascent + 0.5f);
  1316. dst_font->FallbackGlyph = NULL; // Always clear fallback so FindGlyph can return NULL. It will be set again in BuildLookupTable()
  1317. for (int i = 0; i < tmp.RangesCount; i++)
  1318. {
  1319. stbtt_pack_range& range = tmp.Ranges[i];
  1320. for (int char_idx = 0; char_idx < range.num_chars; char_idx += 1)
  1321. {
  1322. const stbtt_packedchar& pc = range.chardata_for_range[char_idx];
  1323. if (!pc.x0 && !pc.x1 && !pc.y0 && !pc.y1)
  1324. continue;
  1325. const int codepoint = range.first_unicode_codepoint_in_range + char_idx;
  1326. if (cfg.MergeMode && dst_font->FindGlyph((unsigned short)codepoint))
  1327. continue;
  1328. stbtt_aligned_quad q;
  1329. float dummy_x = 0.0f, dummy_y = 0.0f;
  1330. stbtt_GetPackedQuad(range.chardata_for_range, atlas->TexWidth, atlas->TexHeight, char_idx, &dummy_x, &dummy_y, &q, 0);
  1331. dst_font->Glyphs.resize(dst_font->Glyphs.Size + 1);
  1332. ImFont::Glyph& glyph = dst_font->Glyphs.back();
  1333. glyph.Codepoint = (ImWchar)codepoint;
  1334. glyph.X0 = q.x0 + off_x;
  1335. glyph.Y0 = q.y0 + off_y;
  1336. glyph.X1 = q.x1 + off_x;
  1337. glyph.Y1 = q.y1 + off_y;
  1338. glyph.U0 = q.s0;
  1339. glyph.V0 = q.t0;
  1340. glyph.U1 = q.s1;
  1341. glyph.V1 = q.t1;
  1342. glyph.XAdvance = (pc.xadvance + cfg.GlyphExtraSpacing.x); // Bake spacing into XAdvance
  1343. if (cfg.PixelSnapH)
  1344. glyph.XAdvance = (float)(int)(glyph.XAdvance + 0.5f);
  1345. dst_font->MetricsTotalSurface += (int)((glyph.U1 - glyph.U0) * atlas->TexWidth + 1.99f) * (int)((glyph.V1 - glyph.V0) * atlas->TexHeight + 1.99f); // +1 to account for average padding, +0.99 to round
  1346. }
  1347. }
  1348. cfg.DstFont->BuildLookupTable();
  1349. }
  1350. // Cleanup temporaries
  1351. ImGui::MemFree(buf_packedchars);
  1352. ImGui::MemFree(buf_ranges);
  1353. ImGui::MemFree(tmp_array);
  1354. // Render into our custom data block
  1355. ImFontAtlasBuildRenderDefaultTexData(atlas);
  1356. return true;
  1357. }
  1358. void ImFontAtlasBuildRegisterDefaultCustomRects(ImFontAtlas* atlas)
  1359. {
  1360. // FIXME-WIP: We should register in the constructor (but cannot because our static instances may not have allocator ready by the time they initialize). This needs to be fixed because we can expose CustomRects.
  1361. if (atlas->CustomRects.empty())
  1362. atlas->CustomRectRegister(FONT_ATLAS_DEFAULT_TEX_DATA_ID, FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF*2+1, FONT_ATLAS_DEFAULT_TEX_DATA_H);
  1363. }
  1364. void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent)
  1365. {
  1366. if (!font_config->MergeMode)
  1367. {
  1368. font->ContainerAtlas = atlas;
  1369. font->ConfigData = font_config;
  1370. font->ConfigDataCount = 0;
  1371. font->FontSize = font_config->SizePixels;
  1372. font->Ascent = ascent;
  1373. font->Descent = descent;
  1374. font->Glyphs.resize(0);
  1375. font->MetricsTotalSurface = 0;
  1376. }
  1377. font->ConfigDataCount++;
  1378. }
  1379. void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* pack_context_opaque)
  1380. {
  1381. stbrp_context* pack_context = (stbrp_context*)pack_context_opaque;
  1382. ImVector<ImFontAtlas::CustomRect>& user_rects = atlas->CustomRects;
  1383. ImVector<stbrp_rect> pack_rects;
  1384. pack_rects.resize(user_rects.Size);
  1385. memset(pack_rects.Data, 0, sizeof(stbrp_rect) * user_rects.Size);
  1386. for (int i = 0; i < user_rects.Size; i++)
  1387. {
  1388. pack_rects[i].w = user_rects[i].Width;
  1389. pack_rects[i].h = user_rects[i].Height;
  1390. }
  1391. stbrp_pack_rects(pack_context, &pack_rects[0], pack_rects.Size);
  1392. for (int i = 0; i < pack_rects.Size; i++)
  1393. if (pack_rects[i].was_packed)
  1394. {
  1395. user_rects[i].X = pack_rects[i].x;
  1396. user_rects[i].Y = pack_rects[i].y;
  1397. IM_ASSERT(pack_rects[i].w == user_rects[i].Width && pack_rects[i].h == user_rects[i].Height);
  1398. atlas->TexHeight = ImMax(atlas->TexHeight, pack_rects[i].y + pack_rects[i].h);
  1399. }
  1400. }
  1401. void ImFontAtlasBuildRenderDefaultTexData(ImFontAtlas* atlas)
  1402. {
  1403. ImFontAtlas::CustomRect& r = atlas->CustomRects[0];
  1404. IM_ASSERT(r.ID == FONT_ATLAS_DEFAULT_TEX_DATA_ID);
  1405. IM_ASSERT(r.Width == FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF*2+1);
  1406. IM_ASSERT(r.Height == FONT_ATLAS_DEFAULT_TEX_DATA_H);
  1407. IM_ASSERT(r.IsPacked());
  1408. IM_ASSERT(atlas->TexPixelsAlpha8 != NULL);
  1409. // Render/copy pixels
  1410. for (int y = 0, n = 0; y < FONT_ATLAS_DEFAULT_TEX_DATA_H; y++)
  1411. for (int x = 0; x < FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF; x++, n++)
  1412. {
  1413. const int offset0 = (int)(r.X + x) + (int)(r.Y + y) * atlas->TexWidth;
  1414. const int offset1 = offset0 + FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF + 1;
  1415. atlas->TexPixelsAlpha8[offset0] = FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[n] == '.' ? 0xFF : 0x00;
  1416. atlas->TexPixelsAlpha8[offset1] = FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[n] == 'X' ? 0xFF : 0x00;
  1417. }
  1418. const ImVec2 tex_uv_scale(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight);
  1419. atlas->TexUvWhitePixel = ImVec2((r.X + 0.5f) * tex_uv_scale.x, (r.Y + 0.5f) * tex_uv_scale.y);
  1420. // Setup mouse cursors
  1421. const ImVec2 cursor_datas[ImGuiMouseCursor_Count_][3] =
  1422. {
  1423. // Pos ........ Size ......... Offset ......
  1424. { ImVec2(0,3), ImVec2(12,19), ImVec2( 0, 0) }, // ImGuiMouseCursor_Arrow
  1425. { ImVec2(13,0), ImVec2(7,16), ImVec2( 4, 8) }, // ImGuiMouseCursor_TextInput
  1426. { ImVec2(31,0), ImVec2(23,23), ImVec2(11,11) }, // ImGuiMouseCursor_Move
  1427. { ImVec2(21,0), ImVec2( 9,23), ImVec2( 5,11) }, // ImGuiMouseCursor_ResizeNS
  1428. { ImVec2(55,18),ImVec2(23, 9), ImVec2(11, 5) }, // ImGuiMouseCursor_ResizeEW
  1429. { ImVec2(73,0), ImVec2(17,17), ImVec2( 9, 9) }, // ImGuiMouseCursor_ResizeNESW
  1430. { ImVec2(55,0), ImVec2(17,17), ImVec2( 9, 9) }, // ImGuiMouseCursor_ResizeNWSE
  1431. };
  1432. for (int type = 0; type < ImGuiMouseCursor_Count_; type++)
  1433. {
  1434. ImGuiMouseCursorData& cursor_data = GImGui->MouseCursorData[type];
  1435. ImVec2 pos = cursor_datas[type][0] + ImVec2((float)r.X, (float)r.Y);
  1436. const ImVec2 size = cursor_datas[type][1];
  1437. cursor_data.Type = type;
  1438. cursor_data.Size = size;
  1439. cursor_data.HotOffset = cursor_datas[type][2];
  1440. cursor_data.TexUvMin[0] = (pos) * tex_uv_scale;
  1441. cursor_data.TexUvMax[0] = (pos + size) * tex_uv_scale;
  1442. pos.x += FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF + 1;
  1443. cursor_data.TexUvMin[1] = (pos) * tex_uv_scale;
  1444. cursor_data.TexUvMax[1] = (pos + size) * tex_uv_scale;
  1445. }
  1446. }
  1447. // Retrieve list of range (2 int per range, values are inclusive)
  1448. const ImWchar* ImFontAtlas::GetGlyphRangesDefault()
  1449. {
  1450. static const ImWchar ranges[] =
  1451. {
  1452. 0x0020, 0x00FF, // Basic Latin + Latin Supplement
  1453. 0,
  1454. };
  1455. return &ranges[0];
  1456. }
  1457. const ImWchar* ImFontAtlas::GetGlyphRangesKorean()
  1458. {
  1459. static const ImWchar ranges[] =
  1460. {
  1461. 0x0020, 0x00FF, // Basic Latin + Latin Supplement
  1462. 0x3131, 0x3163, // Korean alphabets
  1463. 0xAC00, 0xD79D, // Korean characters
  1464. 0,
  1465. };
  1466. return &ranges[0];
  1467. }
  1468. const ImWchar* ImFontAtlas::GetGlyphRangesChinese()
  1469. {
  1470. static const ImWchar ranges[] =
  1471. {
  1472. 0x0020, 0x00FF, // Basic Latin + Latin Supplement
  1473. 0x3000, 0x30FF, // Punctuations, Hiragana, Katakana
  1474. 0x31F0, 0x31FF, // Katakana Phonetic Extensions
  1475. 0xFF00, 0xFFEF, // Half-width characters
  1476. 0x4e00, 0x9FAF, // CJK Ideograms
  1477. 0,
  1478. };
  1479. return &ranges[0];
  1480. }
  1481. const ImWchar* ImFontAtlas::GetGlyphRangesJapanese()
  1482. {
  1483. // Store the 1946 ideograms code points as successive offsets from the initial unicode codepoint 0x4E00. Each offset has an implicit +1.
  1484. // This encoding helps us reduce the source code size.
  1485. static const short offsets_from_0x4E00[] =
  1486. {
  1487. -1,0,1,3,0,0,0,0,1,0,5,1,1,0,7,4,6,10,0,1,9,9,7,1,3,19,1,10,7,1,0,1,0,5,1,0,6,4,2,6,0,0,12,6,8,0,3,5,0,1,0,9,0,0,8,1,1,3,4,5,13,0,0,8,2,17,
  1488. 4,3,1,1,9,6,0,0,0,2,1,3,2,22,1,9,11,1,13,1,3,12,0,5,9,2,0,6,12,5,3,12,4,1,2,16,1,1,4,6,5,3,0,6,13,15,5,12,8,14,0,0,6,15,3,6,0,18,8,1,6,14,1,
  1489. 5,4,12,24,3,13,12,10,24,0,0,0,1,0,1,1,2,9,10,2,2,0,0,3,3,1,0,3,8,0,3,2,4,4,1,6,11,10,14,6,15,3,4,15,1,0,0,5,2,2,0,0,1,6,5,5,6,0,3,6,5,0,0,1,0,
  1490. 11,2,2,8,4,7,0,10,0,1,2,17,19,3,0,2,5,0,6,2,4,4,6,1,1,11,2,0,3,1,2,1,2,10,7,6,3,16,0,8,24,0,0,3,1,1,3,0,1,6,0,0,0,2,0,1,5,15,0,1,0,0,2,11,19,
  1491. 1,4,19,7,6,5,1,0,0,0,0,5,1,0,1,9,0,0,5,0,2,0,1,0,3,0,11,3,0,2,0,0,0,0,0,9,3,6,4,12,0,14,0,0,29,10,8,0,14,37,13,0,31,16,19,0,8,30,1,20,8,3,48,
  1492. 21,1,0,12,0,10,44,34,42,54,11,18,82,0,2,1,2,12,1,0,6,2,17,2,12,7,0,7,17,4,2,6,24,23,8,23,39,2,16,23,1,0,5,1,2,15,14,5,6,2,11,0,8,6,2,2,2,14,
  1493. 20,4,15,3,4,11,10,10,2,5,2,1,30,2,1,0,0,22,5,5,0,3,1,5,4,1,0,0,2,2,21,1,5,1,2,16,2,1,3,4,0,8,4,0,0,5,14,11,2,16,1,13,1,7,0,22,15,3,1,22,7,14,
  1494. 22,19,11,24,18,46,10,20,64,45,3,2,0,4,5,0,1,4,25,1,0,0,2,10,0,0,0,1,0,1,2,0,0,9,1,2,0,0,0,2,5,2,1,1,5,5,8,1,1,1,5,1,4,9,1,3,0,1,0,1,1,2,0,0,
  1495. 2,0,1,8,22,8,1,0,0,0,0,4,2,1,0,9,8,5,0,9,1,30,24,2,6,4,39,0,14,5,16,6,26,179,0,2,1,1,0,0,0,5,2,9,6,0,2,5,16,7,5,1,1,0,2,4,4,7,15,13,14,0,0,
  1496. 3,0,1,0,0,0,2,1,6,4,5,1,4,9,0,3,1,8,0,0,10,5,0,43,0,2,6,8,4,0,2,0,0,9,6,0,9,3,1,6,20,14,6,1,4,0,7,2,3,0,2,0,5,0,3,1,0,3,9,7,0,3,4,0,4,9,1,6,0,
  1497. 9,0,0,2,3,10,9,28,3,6,2,4,1,2,32,4,1,18,2,0,3,1,5,30,10,0,2,2,2,0,7,9,8,11,10,11,7,2,13,7,5,10,0,3,40,2,0,1,6,12,0,4,5,1,5,11,11,21,4,8,3,7,
  1498. 8,8,33,5,23,0,0,19,8,8,2,3,0,6,1,1,1,5,1,27,4,2,5,0,3,5,6,3,1,0,3,1,12,5,3,3,2,0,7,7,2,1,0,4,0,1,1,2,0,10,10,6,2,5,9,7,5,15,15,21,6,11,5,20,
  1499. 4,3,5,5,2,5,0,2,1,0,1,7,28,0,9,0,5,12,5,5,18,30,0,12,3,3,21,16,25,32,9,3,14,11,24,5,66,9,1,2,0,5,9,1,5,1,8,0,8,3,3,0,1,15,1,4,8,1,2,7,0,7,2,
  1500. 8,3,7,5,3,7,10,2,1,0,0,2,25,0,6,4,0,10,0,4,2,4,1,12,5,38,4,0,4,1,10,5,9,4,0,14,4,2,5,18,20,21,1,3,0,5,0,7,0,3,7,1,3,1,1,8,1,0,0,0,3,2,5,2,11,
  1501. 6,0,13,1,3,9,1,12,0,16,6,2,1,0,2,1,12,6,13,11,2,0,28,1,7,8,14,13,8,13,0,2,0,5,4,8,10,2,37,42,19,6,6,7,4,14,11,18,14,80,7,6,0,4,72,12,36,27,
  1502. 7,7,0,14,17,19,164,27,0,5,10,7,3,13,6,14,0,2,2,5,3,0,6,13,0,0,10,29,0,4,0,3,13,0,3,1,6,51,1,5,28,2,0,8,0,20,2,4,0,25,2,10,13,10,0,16,4,0,1,0,
  1503. 2,1,7,0,1,8,11,0,0,1,2,7,2,23,11,6,6,4,16,2,2,2,0,22,9,3,3,5,2,0,15,16,21,2,9,20,15,15,5,3,9,1,0,0,1,7,7,5,4,2,2,2,38,24,14,0,0,15,5,6,24,14,
  1504. 5,5,11,0,21,12,0,3,8,4,11,1,8,0,11,27,7,2,4,9,21,59,0,1,39,3,60,62,3,0,12,11,0,3,30,11,0,13,88,4,15,5,28,13,1,4,48,17,17,4,28,32,46,0,16,0,
  1505. 18,11,1,8,6,38,11,2,6,11,38,2,0,45,3,11,2,7,8,4,30,14,17,2,1,1,65,18,12,16,4,2,45,123,12,56,33,1,4,3,4,7,0,0,0,3,2,0,16,4,2,4,2,0,7,4,5,2,26,
  1506. 2,25,6,11,6,1,16,2,6,17,77,15,3,35,0,1,0,5,1,0,38,16,6,3,12,3,3,3,0,9,3,1,3,5,2,9,0,18,0,25,1,3,32,1,72,46,6,2,7,1,3,14,17,0,28,1,40,13,0,20,
  1507. 15,40,6,38,24,12,43,1,1,9,0,12,6,0,6,2,4,19,3,7,1,48,0,9,5,0,5,6,9,6,10,15,2,11,19,3,9,2,0,1,10,1,27,8,1,3,6,1,14,0,26,0,27,16,3,4,9,6,2,23,
  1508. 9,10,5,25,2,1,6,1,1,48,15,9,15,14,3,4,26,60,29,13,37,21,1,6,4,0,2,11,22,23,16,16,2,2,1,3,0,5,1,6,4,0,0,4,0,0,8,3,0,2,5,0,7,1,7,3,13,2,4,10,
  1509. 3,0,2,31,0,18,3,0,12,10,4,1,0,7,5,7,0,5,4,12,2,22,10,4,2,15,2,8,9,0,23,2,197,51,3,1,1,4,13,4,3,21,4,19,3,10,5,40,0,4,1,1,10,4,1,27,34,7,21,
  1510. 2,17,2,9,6,4,2,3,0,4,2,7,8,2,5,1,15,21,3,4,4,2,2,17,22,1,5,22,4,26,7,0,32,1,11,42,15,4,1,2,5,0,19,3,1,8,6,0,10,1,9,2,13,30,8,2,24,17,19,1,4,
  1511. 4,25,13,0,10,16,11,39,18,8,5,30,82,1,6,8,18,77,11,13,20,75,11,112,78,33,3,0,0,60,17,84,9,1,1,12,30,10,49,5,32,158,178,5,5,6,3,3,1,3,1,4,7,6,
  1512. 19,31,21,0,2,9,5,6,27,4,9,8,1,76,18,12,1,4,0,3,3,6,3,12,2,8,30,16,2,25,1,5,5,4,3,0,6,10,2,3,1,0,5,1,19,3,0,8,1,5,2,6,0,0,0,19,1,2,0,5,1,2,5,
  1513. 1,3,7,0,4,12,7,3,10,22,0,9,5,1,0,2,20,1,1,3,23,30,3,9,9,1,4,191,14,3,15,6,8,50,0,1,0,0,4,0,0,1,0,2,4,2,0,2,3,0,2,0,2,2,8,7,0,1,1,1,3,3,17,11,
  1514. 91,1,9,3,2,13,4,24,15,41,3,13,3,1,20,4,125,29,30,1,0,4,12,2,21,4,5,5,19,11,0,13,11,86,2,18,0,7,1,8,8,2,2,22,1,2,6,5,2,0,1,2,8,0,2,0,5,2,1,0,
  1515. 2,10,2,0,5,9,2,1,2,0,1,0,4,0,0,10,2,5,3,0,6,1,0,1,4,4,33,3,13,17,3,18,6,4,7,1,5,78,0,4,1,13,7,1,8,1,0,35,27,15,3,0,0,0,1,11,5,41,38,15,22,6,
  1516. 14,14,2,1,11,6,20,63,5,8,27,7,11,2,2,40,58,23,50,54,56,293,8,8,1,5,1,14,0,1,12,37,89,8,8,8,2,10,6,0,0,0,4,5,2,1,0,1,1,2,7,0,3,3,0,4,6,0,3,2,
  1517. 19,3,8,0,0,0,4,4,16,0,4,1,5,1,3,0,3,4,6,2,17,10,10,31,6,4,3,6,10,126,7,3,2,2,0,9,0,0,5,20,13,0,15,0,6,0,2,5,8,64,50,3,2,12,2,9,0,0,11,8,20,
  1518. 109,2,18,23,0,0,9,61,3,0,28,41,77,27,19,17,81,5,2,14,5,83,57,252,14,154,263,14,20,8,13,6,57,39,38,
  1519. };
  1520. static ImWchar base_ranges[] =
  1521. {
  1522. 0x0020, 0x00FF, // Basic Latin + Latin Supplement
  1523. 0x3000, 0x30FF, // Punctuations, Hiragana, Katakana
  1524. 0x31F0, 0x31FF, // Katakana Phonetic Extensions
  1525. 0xFF00, 0xFFEF, // Half-width characters
  1526. };
  1527. static bool full_ranges_unpacked = false;
  1528. static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(offsets_from_0x4E00)*2 + 1];
  1529. if (!full_ranges_unpacked)
  1530. {
  1531. // Unpack
  1532. int codepoint = 0x4e00;
  1533. memcpy(full_ranges, base_ranges, sizeof(base_ranges));
  1534. ImWchar* dst = full_ranges + IM_ARRAYSIZE(base_ranges);;
  1535. for (int n = 0; n < IM_ARRAYSIZE(offsets_from_0x4E00); n++, dst += 2)
  1536. dst[0] = dst[1] = (ImWchar)(codepoint += (offsets_from_0x4E00[n] + 1));
  1537. dst[0] = 0;
  1538. full_ranges_unpacked = true;
  1539. }
  1540. return &full_ranges[0];
  1541. }
  1542. const ImWchar* ImFontAtlas::GetGlyphRangesCyrillic()
  1543. {
  1544. static const ImWchar ranges[] =
  1545. {
  1546. 0x0020, 0x00FF, // Basic Latin + Latin Supplement
  1547. 0x0400, 0x052F, // Cyrillic + Cyrillic Supplement
  1548. 0x2DE0, 0x2DFF, // Cyrillic Extended-A
  1549. 0xA640, 0xA69F, // Cyrillic Extended-B
  1550. 0,
  1551. };
  1552. return &ranges[0];
  1553. }
  1554. const ImWchar* ImFontAtlas::GetGlyphRangesThai()
  1555. {
  1556. static const ImWchar ranges[] =
  1557. {
  1558. 0x0020, 0x00FF, // Basic Latin
  1559. 0x0E00, 0x0E7F, // Thai
  1560. 0,
  1561. };
  1562. return &ranges[0];
  1563. }
  1564. //-----------------------------------------------------------------------------
  1565. // ImFontAtlas::GlyphRangesBuilder
  1566. //-----------------------------------------------------------------------------
  1567. void ImFontAtlas::GlyphRangesBuilder::AddText(const char* text, const char* text_end)
  1568. {
  1569. while (text_end ? (text < text_end) : *text)
  1570. {
  1571. unsigned int c = 0;
  1572. int c_len = ImTextCharFromUtf8(&c, text, text_end);
  1573. text += c_len;
  1574. if (c_len == 0)
  1575. break;
  1576. if (c < 0x10000)
  1577. AddChar((ImWchar)c);
  1578. }
  1579. }
  1580. void ImFontAtlas::GlyphRangesBuilder::AddRanges(const ImWchar* ranges)
  1581. {
  1582. for (; ranges[0]; ranges += 2)
  1583. for (ImWchar c = ranges[0]; c <= ranges[1]; c++)
  1584. AddChar(c);
  1585. }
  1586. void ImFontAtlas::GlyphRangesBuilder::BuildRanges(ImVector<ImWchar>* out_ranges)
  1587. {
  1588. for (int n = 0; n < 0x10000; n++)
  1589. if (GetBit(n))
  1590. {
  1591. out_ranges->push_back((ImWchar)n);
  1592. while (n < 0x10000 && GetBit(n + 1))
  1593. n++;
  1594. out_ranges->push_back((ImWchar)n);
  1595. }
  1596. out_ranges->push_back(0);
  1597. }
  1598. //-----------------------------------------------------------------------------
  1599. // ImFont
  1600. //-----------------------------------------------------------------------------
  1601. ImFont::ImFont()
  1602. {
  1603. Scale = 1.0f;
  1604. FallbackChar = (ImWchar)'?';
  1605. Clear();
  1606. }
  1607. ImFont::~ImFont()
  1608. {
  1609. // Invalidate active font so that the user gets a clear crash instead of a dangling pointer.
  1610. // If you want to delete fonts you need to do it between Render() and NewFrame().
  1611. // FIXME-CLEANUP
  1612. /*
  1613. ImGuiContext& g = *GImGui;
  1614. if (g.Font == this)
  1615. g.Font = NULL;
  1616. */
  1617. Clear();
  1618. }
  1619. void ImFont::Clear()
  1620. {
  1621. FontSize = 0.0f;
  1622. DisplayOffset = ImVec2(0.0f, 1.0f);
  1623. Glyphs.clear();
  1624. IndexXAdvance.clear();
  1625. IndexLookup.clear();
  1626. FallbackGlyph = NULL;
  1627. FallbackXAdvance = 0.0f;
  1628. ConfigDataCount = 0;
  1629. ConfigData = NULL;
  1630. ContainerAtlas = NULL;
  1631. Ascent = Descent = 0.0f;
  1632. MetricsTotalSurface = 0;
  1633. }
  1634. void ImFont::BuildLookupTable()
  1635. {
  1636. int max_codepoint = 0;
  1637. for (int i = 0; i != Glyphs.Size; i++)
  1638. max_codepoint = ImMax(max_codepoint, (int)Glyphs[i].Codepoint);
  1639. IM_ASSERT(Glyphs.Size < 0xFFFF); // -1 is reserved
  1640. IndexXAdvance.clear();
  1641. IndexLookup.clear();
  1642. GrowIndex(max_codepoint + 1);
  1643. for (int i = 0; i < Glyphs.Size; i++)
  1644. {
  1645. int codepoint = (int)Glyphs[i].Codepoint;
  1646. IndexXAdvance[codepoint] = Glyphs[i].XAdvance;
  1647. IndexLookup[codepoint] = (unsigned short)i;
  1648. }
  1649. // Create a glyph to handle TAB
  1650. // FIXME: Needs proper TAB handling but it needs to be contextualized (or we could arbitrary say that each string starts at "column 0" ?)
  1651. if (FindGlyph((unsigned short)' '))
  1652. {
  1653. if (Glyphs.back().Codepoint != '\t') // So we can call this function multiple times
  1654. Glyphs.resize(Glyphs.Size + 1);
  1655. ImFont::Glyph& tab_glyph = Glyphs.back();
  1656. tab_glyph = *FindGlyph((unsigned short)' ');
  1657. tab_glyph.Codepoint = '\t';
  1658. tab_glyph.XAdvance *= 4;
  1659. IndexXAdvance[(int)tab_glyph.Codepoint] = (float)tab_glyph.XAdvance;
  1660. IndexLookup[(int)tab_glyph.Codepoint] = (unsigned short)(Glyphs.Size-1);
  1661. }
  1662. FallbackGlyph = NULL;
  1663. FallbackGlyph = FindGlyph(FallbackChar);
  1664. FallbackXAdvance = FallbackGlyph ? FallbackGlyph->XAdvance : 0.0f;
  1665. for (int i = 0; i < max_codepoint + 1; i++)
  1666. if (IndexXAdvance[i] < 0.0f)
  1667. IndexXAdvance[i] = FallbackXAdvance;
  1668. }
  1669. void ImFont::SetFallbackChar(ImWchar c)
  1670. {
  1671. FallbackChar = c;
  1672. BuildLookupTable();
  1673. }
  1674. void ImFont::GrowIndex(int new_size)
  1675. {
  1676. IM_ASSERT(IndexXAdvance.Size == IndexLookup.Size);
  1677. int old_size = IndexLookup.Size;
  1678. if (new_size <= old_size)
  1679. return;
  1680. IndexXAdvance.resize(new_size);
  1681. IndexLookup.resize(new_size);
  1682. for (int i = old_size; i < new_size; i++)
  1683. {
  1684. IndexXAdvance[i] = -1.0f;
  1685. IndexLookup[i] = (unsigned short)-1;
  1686. }
  1687. }
  1688. void ImFont::AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst)
  1689. {
  1690. IM_ASSERT(IndexLookup.Size > 0); // Currently this can only be called AFTER the font has been built, aka after calling ImFontAtlas::GetTexDataAs*() function.
  1691. int index_size = IndexLookup.Size;
  1692. if (dst < index_size && IndexLookup.Data[dst] == (unsigned short)-1 && !overwrite_dst) // 'dst' already exists
  1693. return;
  1694. if (src >= index_size && dst >= index_size) // both 'dst' and 'src' don't exist -> no-op
  1695. return;
  1696. GrowIndex(dst + 1);
  1697. IndexLookup[dst] = (src < index_size) ? IndexLookup.Data[src] : (unsigned short)-1;
  1698. IndexXAdvance[dst] = (src < index_size) ? IndexXAdvance.Data[src] : 1.0f;
  1699. }
  1700. const ImFont::Glyph* ImFont::FindGlyph(unsigned short c) const
  1701. {
  1702. if (c < IndexLookup.Size)
  1703. {
  1704. const unsigned short i = IndexLookup[c];
  1705. if (i != (unsigned short)-1)
  1706. return &Glyphs.Data[i];
  1707. }
  1708. return FallbackGlyph;
  1709. }
  1710. const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) const
  1711. {
  1712. // Simple word-wrapping for English, not full-featured. Please submit failing cases!
  1713. // FIXME: Much possible improvements (don't cut things like "word !", "word!!!" but cut within "word,,,,", more sensible support for punctuations, support for Unicode punctuations, etc.)
  1714. // For references, possible wrap point marked with ^
  1715. // "aaa bbb, ccc,ddd. eee fff. ggg!"
  1716. // ^ ^ ^ ^ ^__ ^ ^
  1717. // List of hardcoded separators: .,;!?'"
  1718. // Skip extra blanks after a line returns (that includes not counting them in width computation)
  1719. // e.g. "Hello world" --> "Hello" "World"
  1720. // Cut words that cannot possibly fit within one line.
  1721. // e.g.: "The tropical fish" with ~5 characters worth of width --> "The tr" "opical" "fish"
  1722. float line_width = 0.0f;
  1723. float word_width = 0.0f;
  1724. float blank_width = 0.0f;
  1725. wrap_width /= scale; // We work with unscaled widths to avoid scaling every characters
  1726. const char* word_end = text;
  1727. const char* prev_word_end = NULL;
  1728. bool inside_word = true;
  1729. const char* s = text;
  1730. while (s < text_end)
  1731. {
  1732. unsigned int c = (unsigned int)*s;
  1733. const char* next_s;
  1734. if (c < 0x80)
  1735. next_s = s + 1;
  1736. else
  1737. next_s = s + ImTextCharFromUtf8(&c, s, text_end);
  1738. if (c == 0)
  1739. break;
  1740. if (c < 32)
  1741. {
  1742. if (c == '\n')
  1743. {
  1744. line_width = word_width = blank_width = 0.0f;
  1745. inside_word = true;
  1746. s = next_s;
  1747. continue;
  1748. }
  1749. if (c == '\r')
  1750. {
  1751. s = next_s;
  1752. continue;
  1753. }
  1754. }
  1755. const float char_width = ((int)c < IndexXAdvance.Size ? IndexXAdvance[(int)c] : FallbackXAdvance);
  1756. if (ImCharIsSpace(c))
  1757. {
  1758. if (inside_word)
  1759. {
  1760. line_width += blank_width;
  1761. blank_width = 0.0f;
  1762. word_end = s;
  1763. }
  1764. blank_width += char_width;
  1765. inside_word = false;
  1766. }
  1767. else
  1768. {
  1769. word_width += char_width;
  1770. if (inside_word)
  1771. {
  1772. word_end = next_s;
  1773. }
  1774. else
  1775. {
  1776. prev_word_end = word_end;
  1777. line_width += word_width + blank_width;
  1778. word_width = blank_width = 0.0f;
  1779. }
  1780. // Allow wrapping after punctuation.
  1781. inside_word = !(c == '.' || c == ',' || c == ';' || c == '!' || c == '?' || c == '\"');
  1782. }
  1783. // We ignore blank width at the end of the line (they can be skipped)
  1784. if (line_width + word_width >= wrap_width)
  1785. {
  1786. // Words that cannot possibly fit within an entire line will be cut anywhere.
  1787. if (word_width < wrap_width)
  1788. s = prev_word_end ? prev_word_end : word_end;
  1789. break;
  1790. }
  1791. s = next_s;
  1792. }
  1793. return s;
  1794. }
  1795. ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end, const char** remaining) const
  1796. {
  1797. if (!text_end)
  1798. text_end = text_begin + strlen(text_begin); // FIXME-OPT: Need to avoid this.
  1799. const float line_height = size;
  1800. const float scale = size / FontSize;
  1801. ImVec2 text_size = ImVec2(0,0);
  1802. float line_width = 0.0f;
  1803. const bool word_wrap_enabled = (wrap_width > 0.0f);
  1804. const char* word_wrap_eol = NULL;
  1805. const char* s = text_begin;
  1806. while (s < text_end)
  1807. {
  1808. if (word_wrap_enabled)
  1809. {
  1810. // Calculate how far we can render. Requires two passes on the string data but keeps the code simple and not intrusive for what's essentially an uncommon feature.
  1811. if (!word_wrap_eol)
  1812. {
  1813. word_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - line_width);
  1814. if (word_wrap_eol == s) // Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity.
  1815. word_wrap_eol++; // +1 may not be a character start point in UTF-8 but it's ok because we use s >= word_wrap_eol below
  1816. }
  1817. if (s >= word_wrap_eol)
  1818. {
  1819. if (text_size.x < line_width)
  1820. text_size.x = line_width;
  1821. text_size.y += line_height;
  1822. line_width = 0.0f;
  1823. word_wrap_eol = NULL;
  1824. // Wrapping skips upcoming blanks
  1825. while (s < text_end)
  1826. {
  1827. const char c = *s;
  1828. if (ImCharIsSpace(c)) { s++; } else if (c == '\n') { s++; break; } else { break; }
  1829. }
  1830. continue;
  1831. }
  1832. }
  1833. // Decode and advance source
  1834. const char* prev_s = s;
  1835. unsigned int c = (unsigned int)*s;
  1836. if (c < 0x80)
  1837. {
  1838. s += 1;
  1839. }
  1840. else
  1841. {
  1842. s += ImTextCharFromUtf8(&c, s, text_end);
  1843. if (c == 0) // Malformed UTF-8?
  1844. break;
  1845. }
  1846. if (c < 32)
  1847. {
  1848. if (c == '\n')
  1849. {
  1850. text_size.x = ImMax(text_size.x, line_width);
  1851. text_size.y += line_height;
  1852. line_width = 0.0f;
  1853. continue;
  1854. }
  1855. if (c == '\r')
  1856. continue;
  1857. }
  1858. const float char_width = ((int)c < IndexXAdvance.Size ? IndexXAdvance[(int)c] : FallbackXAdvance) * scale;
  1859. if (line_width + char_width >= max_width)
  1860. {
  1861. s = prev_s;
  1862. break;
  1863. }
  1864. line_width += char_width;
  1865. }
  1866. if (text_size.x < line_width)
  1867. text_size.x = line_width;
  1868. if (line_width > 0 || text_size.y == 0.0f)
  1869. text_size.y += line_height;
  1870. if (remaining)
  1871. *remaining = s;
  1872. return text_size;
  1873. }
  1874. void ImFont::RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, unsigned short c) const
  1875. {
  1876. if (c == ' ' || c == '\t' || c == '\n' || c == '\r') // Match behavior of RenderText(), those 4 codepoints are hard-coded.
  1877. return;
  1878. if (const Glyph* glyph = FindGlyph(c))
  1879. {
  1880. float scale = (size >= 0.0f) ? (size / FontSize) : 1.0f;
  1881. pos.x = (float)(int)pos.x + DisplayOffset.x;
  1882. pos.y = (float)(int)pos.y + DisplayOffset.y;
  1883. draw_list->PrimReserve(6, 4);
  1884. draw_list->PrimRectUV(ImVec2(pos.x + glyph->X0 * scale, pos.y + glyph->Y0 * scale), ImVec2(pos.x + glyph->X1 * scale, pos.y + glyph->Y1 * scale), ImVec2(glyph->U0, glyph->V0), ImVec2(glyph->U1, glyph->V1), col);
  1885. }
  1886. }
  1887. void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width, bool cpu_fine_clip) const
  1888. {
  1889. if (!text_end)
  1890. text_end = text_begin + strlen(text_begin); // ImGui functions generally already provides a valid text_end, so this is merely to handle direct calls.
  1891. // Align to be pixel perfect
  1892. pos.x = (float)(int)pos.x + DisplayOffset.x;
  1893. pos.y = (float)(int)pos.y + DisplayOffset.y;
  1894. float x = pos.x;
  1895. float y = pos.y;
  1896. if (y > clip_rect.w)
  1897. return;
  1898. const float scale = size / FontSize;
  1899. const float line_height = FontSize * scale;
  1900. const bool word_wrap_enabled = (wrap_width > 0.0f);
  1901. const char* word_wrap_eol = NULL;
  1902. // Skip non-visible lines
  1903. const char* s = text_begin;
  1904. if (!word_wrap_enabled && y + line_height < clip_rect.y)
  1905. while (s < text_end && *s != '\n') // Fast-forward to next line
  1906. s++;
  1907. // Reserve vertices for remaining worse case (over-reserving is useful and easily amortized)
  1908. const int vtx_count_max = (int)(text_end - s) * 4;
  1909. const int idx_count_max = (int)(text_end - s) * 6;
  1910. const int idx_expected_size = draw_list->IdxBuffer.Size + idx_count_max;
  1911. draw_list->PrimReserve(idx_count_max, vtx_count_max);
  1912. ImDrawVert* vtx_write = draw_list->_VtxWritePtr;
  1913. ImDrawIdx* idx_write = draw_list->_IdxWritePtr;
  1914. unsigned int vtx_current_idx = draw_list->_VtxCurrentIdx;
  1915. while (s < text_end)
  1916. {
  1917. if (word_wrap_enabled)
  1918. {
  1919. // Calculate how far we can render. Requires two passes on the string data but keeps the code simple and not intrusive for what's essentially an uncommon feature.
  1920. if (!word_wrap_eol)
  1921. {
  1922. word_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - (x - pos.x));
  1923. if (word_wrap_eol == s) // Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity.
  1924. word_wrap_eol++; // +1 may not be a character start point in UTF-8 but it's ok because we use s >= word_wrap_eol below
  1925. }
  1926. if (s >= word_wrap_eol)
  1927. {
  1928. x = pos.x;
  1929. y += line_height;
  1930. word_wrap_eol = NULL;
  1931. // Wrapping skips upcoming blanks
  1932. while (s < text_end)
  1933. {
  1934. const char c = *s;
  1935. if (ImCharIsSpace(c)) { s++; } else if (c == '\n') { s++; break; } else { break; }
  1936. }
  1937. continue;
  1938. }
  1939. }
  1940. // Decode and advance source
  1941. unsigned int c = (unsigned int)*s;
  1942. if (c < 0x80)
  1943. {
  1944. s += 1;
  1945. }
  1946. else
  1947. {
  1948. s += ImTextCharFromUtf8(&c, s, text_end);
  1949. if (c == 0) // Malformed UTF-8?
  1950. break;
  1951. }
  1952. if (c < 32)
  1953. {
  1954. if (c == '\n')
  1955. {
  1956. x = pos.x;
  1957. y += line_height;
  1958. if (y > clip_rect.w)
  1959. break;
  1960. if (!word_wrap_enabled && y + line_height < clip_rect.y)
  1961. while (s < text_end && *s != '\n') // Fast-forward to next line
  1962. s++;
  1963. continue;
  1964. }
  1965. if (c == '\r')
  1966. continue;
  1967. }
  1968. float char_width = 0.0f;
  1969. if (const Glyph* glyph = FindGlyph((unsigned short)c))
  1970. {
  1971. char_width = glyph->XAdvance * scale;
  1972. // Arbitrarily assume that both space and tabs are empty glyphs as an optimization
  1973. if (c != ' ' && c != '\t')
  1974. {
  1975. // We don't do a second finer clipping test on the Y axis as we've already skipped anything before clip_rect.y and exit once we pass clip_rect.w
  1976. float x1 = x + glyph->X0 * scale;
  1977. float x2 = x + glyph->X1 * scale;
  1978. float y1 = y + glyph->Y0 * scale;
  1979. float y2 = y + glyph->Y1 * scale;
  1980. if (x1 <= clip_rect.z && x2 >= clip_rect.x)
  1981. {
  1982. // Render a character
  1983. float u1 = glyph->U0;
  1984. float v1 = glyph->V0;
  1985. float u2 = glyph->U1;
  1986. float v2 = glyph->V1;
  1987. // CPU side clipping used to fit text in their frame when the frame is too small. Only does clipping for axis aligned quads.
  1988. if (cpu_fine_clip)
  1989. {
  1990. if (x1 < clip_rect.x)
  1991. {
  1992. u1 = u1 + (1.0f - (x2 - clip_rect.x) / (x2 - x1)) * (u2 - u1);
  1993. x1 = clip_rect.x;
  1994. }
  1995. if (y1 < clip_rect.y)
  1996. {
  1997. v1 = v1 + (1.0f - (y2 - clip_rect.y) / (y2 - y1)) * (v2 - v1);
  1998. y1 = clip_rect.y;
  1999. }
  2000. if (x2 > clip_rect.z)
  2001. {
  2002. u2 = u1 + ((clip_rect.z - x1) / (x2 - x1)) * (u2 - u1);
  2003. x2 = clip_rect.z;
  2004. }
  2005. if (y2 > clip_rect.w)
  2006. {
  2007. v2 = v1 + ((clip_rect.w - y1) / (y2 - y1)) * (v2 - v1);
  2008. y2 = clip_rect.w;
  2009. }
  2010. if (y1 >= y2)
  2011. {
  2012. x += char_width;
  2013. continue;
  2014. }
  2015. }
  2016. // We are NOT calling PrimRectUV() here because non-inlined causes too much overhead in a debug builds. Inlined here:
  2017. {
  2018. idx_write[0] = (ImDrawIdx)(vtx_current_idx); idx_write[1] = (ImDrawIdx)(vtx_current_idx+1); idx_write[2] = (ImDrawIdx)(vtx_current_idx+2);
  2019. idx_write[3] = (ImDrawIdx)(vtx_current_idx); idx_write[4] = (ImDrawIdx)(vtx_current_idx+2); idx_write[5] = (ImDrawIdx)(vtx_current_idx+3);
  2020. vtx_write[0].pos.x = x1; vtx_write[0].pos.y = y1; vtx_write[0].col = col; vtx_write[0].uv.x = u1; vtx_write[0].uv.y = v1;
  2021. vtx_write[1].pos.x = x2; vtx_write[1].pos.y = y1; vtx_write[1].col = col; vtx_write[1].uv.x = u2; vtx_write[1].uv.y = v1;
  2022. vtx_write[2].pos.x = x2; vtx_write[2].pos.y = y2; vtx_write[2].col = col; vtx_write[2].uv.x = u2; vtx_write[2].uv.y = v2;
  2023. vtx_write[3].pos.x = x1; vtx_write[3].pos.y = y2; vtx_write[3].col = col; vtx_write[3].uv.x = u1; vtx_write[3].uv.y = v2;
  2024. vtx_write += 4;
  2025. vtx_current_idx += 4;
  2026. idx_write += 6;
  2027. }
  2028. }
  2029. }
  2030. }
  2031. x += char_width;
  2032. }
  2033. // Give back unused vertices
  2034. draw_list->VtxBuffer.resize((int)(vtx_write - draw_list->VtxBuffer.Data));
  2035. draw_list->IdxBuffer.resize((int)(idx_write - draw_list->IdxBuffer.Data));
  2036. draw_list->CmdBuffer[draw_list->CmdBuffer.Size-1].ElemCount -= (idx_expected_size - draw_list->IdxBuffer.Size);
  2037. draw_list->_VtxWritePtr = vtx_write;
  2038. draw_list->_IdxWritePtr = idx_write;
  2039. draw_list->_VtxCurrentIdx = (unsigned int)draw_list->VtxBuffer.Size;
  2040. }
  2041. //-----------------------------------------------------------------------------
  2042. // DEFAULT FONT DATA
  2043. //-----------------------------------------------------------------------------
  2044. // Compressed with stb_compress() then converted to a C array.
  2045. // Use the program in extra_fonts/binary_to_compressed_c.cpp to create the array from a TTF file.
  2046. // Decompression from stb.h (public domain) by Sean Barrett https://github.com/nothings/stb/blob/master/stb.h
  2047. //-----------------------------------------------------------------------------
  2048. static unsigned int stb_decompress_length(unsigned char *input)
  2049. {
  2050. return (input[8] << 24) + (input[9] << 16) + (input[10] << 8) + input[11];
  2051. }
  2052. static unsigned char *stb__barrier, *stb__barrier2, *stb__barrier3, *stb__barrier4;
  2053. static unsigned char *stb__dout;
  2054. static void stb__match(unsigned char *data, unsigned int length)
  2055. {
  2056. // INVERSE of memmove... write each byte before copying the next...
  2057. IM_ASSERT (stb__dout + length <= stb__barrier);
  2058. if (stb__dout + length > stb__barrier) { stb__dout += length; return; }
  2059. if (data < stb__barrier4) { stb__dout = stb__barrier+1; return; }
  2060. while (length--) *stb__dout++ = *data++;
  2061. }
  2062. static void stb__lit(unsigned char *data, unsigned int length)
  2063. {
  2064. IM_ASSERT (stb__dout + length <= stb__barrier);
  2065. if (stb__dout + length > stb__barrier) { stb__dout += length; return; }
  2066. if (data < stb__barrier2) { stb__dout = stb__barrier+1; return; }
  2067. memcpy(stb__dout, data, length);
  2068. stb__dout += length;
  2069. }
  2070. #define stb__in2(x) ((i[x] << 8) + i[(x)+1])
  2071. #define stb__in3(x) ((i[x] << 16) + stb__in2((x)+1))
  2072. #define stb__in4(x) ((i[x] << 24) + stb__in3((x)+1))
  2073. static unsigned char *stb_decompress_token(unsigned char *i)
  2074. {
  2075. if (*i >= 0x20) { // use fewer if's for cases that expand small
  2076. if (*i >= 0x80) stb__match(stb__dout-i[1]-1, i[0] - 0x80 + 1), i += 2;
  2077. else if (*i >= 0x40) stb__match(stb__dout-(stb__in2(0) - 0x4000 + 1), i[2]+1), i += 3;
  2078. else /* *i >= 0x20 */ stb__lit(i+1, i[0] - 0x20 + 1), i += 1 + (i[0] - 0x20 + 1);
  2079. } else { // more ifs for cases that expand large, since overhead is amortized
  2080. if (*i >= 0x18) stb__match(stb__dout-(stb__in3(0) - 0x180000 + 1), i[3]+1), i += 4;
  2081. else if (*i >= 0x10) stb__match(stb__dout-(stb__in3(0) - 0x100000 + 1), stb__in2(3)+1), i += 5;
  2082. else if (*i >= 0x08) stb__lit(i+2, stb__in2(0) - 0x0800 + 1), i += 2 + (stb__in2(0) - 0x0800 + 1);
  2083. else if (*i == 0x07) stb__lit(i+3, stb__in2(1) + 1), i += 3 + (stb__in2(1) + 1);
  2084. else if (*i == 0x06) stb__match(stb__dout-(stb__in3(1)+1), i[4]+1), i += 5;
  2085. else if (*i == 0x04) stb__match(stb__dout-(stb__in3(1)+1), stb__in2(4)+1), i += 6;
  2086. }
  2087. return i;
  2088. }
  2089. static unsigned int stb_adler32(unsigned int adler32, unsigned char *buffer, unsigned int buflen)
  2090. {
  2091. const unsigned long ADLER_MOD = 65521;
  2092. unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16;
  2093. unsigned long blocklen, i;
  2094. blocklen = buflen % 5552;
  2095. while (buflen) {
  2096. for (i=0; i + 7 < blocklen; i += 8) {
  2097. s1 += buffer[0], s2 += s1;
  2098. s1 += buffer[1], s2 += s1;
  2099. s1 += buffer[2], s2 += s1;
  2100. s1 += buffer[3], s2 += s1;
  2101. s1 += buffer[4], s2 += s1;
  2102. s1 += buffer[5], s2 += s1;
  2103. s1 += buffer[6], s2 += s1;
  2104. s1 += buffer[7], s2 += s1;
  2105. buffer += 8;
  2106. }
  2107. for (; i < blocklen; ++i)
  2108. s1 += *buffer++, s2 += s1;
  2109. s1 %= ADLER_MOD, s2 %= ADLER_MOD;
  2110. buflen -= blocklen;
  2111. blocklen = 5552;
  2112. }
  2113. return (unsigned int)(s2 << 16) + (unsigned int)s1;
  2114. }
  2115. static unsigned int stb_decompress(unsigned char *output, unsigned char *i, unsigned int length)
  2116. {
  2117. unsigned int olen;
  2118. if (stb__in4(0) != 0x57bC0000) return 0;
  2119. if (stb__in4(4) != 0) return 0; // error! stream is > 4GB
  2120. olen = stb_decompress_length(i);
  2121. stb__barrier2 = i;
  2122. stb__barrier3 = i+length;
  2123. stb__barrier = output + olen;
  2124. stb__barrier4 = output;
  2125. i += 16;
  2126. stb__dout = output;
  2127. for (;;) {
  2128. unsigned char *old_i = i;
  2129. i = stb_decompress_token(i);
  2130. if (i == old_i) {
  2131. if (*i == 0x05 && i[1] == 0xfa) {
  2132. IM_ASSERT(stb__dout == output + olen);
  2133. if (stb__dout != output + olen) return 0;
  2134. if (stb_adler32(1, output, olen) != (unsigned int) stb__in4(2))
  2135. return 0;
  2136. return olen;
  2137. } else {
  2138. IM_ASSERT(0); /* NOTREACHED */
  2139. return 0;
  2140. }
  2141. }
  2142. IM_ASSERT(stb__dout <= output + olen);
  2143. if (stb__dout > output + olen)
  2144. return 0;
  2145. }
  2146. }
  2147. //-----------------------------------------------------------------------------
  2148. // ProggyClean.ttf
  2149. // Copyright (c) 2004, 2005 Tristan Grimmer
  2150. // MIT license (see License.txt in http://www.upperbounds.net/download/ProggyClean.ttf.zip)
  2151. // Download and more information at http://upperbounds.net
  2152. //-----------------------------------------------------------------------------
  2153. // File: 'ProggyClean.ttf' (41208 bytes)
  2154. // Exported using binary_to_compressed_c.cpp
  2155. //-----------------------------------------------------------------------------
  2156. static const char proggy_clean_ttf_compressed_data_base85[11980+1] =
  2157. "7])#######hV0qs'/###[),##/l:$#Q6>##5[n42>c-TH`->>#/e>11NNV=Bv(*:.F?uu#(gRU.o0XGH`$vhLG1hxt9?W`#,5LsCp#-i>.r$<$6pD>Lb';9Crc6tgXmKVeU2cD4Eo3R/"
  2158. "2*>]b(MC;$jPfY.;h^`IWM9<Lh2TlS+f-s$o6Q<BWH`YiU.xfLq$N;$0iR/GX:U(jcW2p/W*q?-qmnUCI;jHSAiFWM.R*kU@C=GH?a9wp8f$e.-4^Qg1)Q-GL(lf(r/7GrRgwV%MS=C#"
  2159. "`8ND>Qo#t'X#(v#Y9w0#1D$CIf;W'#pWUPXOuxXuU(H9M(1<q-UE31#^-V'8IRUo7Qf./L>=Ke$$'5F%)]0^#[email protected]<r:QLtFsLcL6##lOj)#.Y5<-R&KgLwqJfLgN&;Q?gI^#DY2uL"
  2160. "i@^rMl9t=cWq6##weg>$FBjVQTSDgEKnIS7EM9>ZY9w0#L;>>#Mx&4Mvt//L[MkA#[email protected]'[0#7RL_&#w+F%HtG9M#XL`N&.,GM4Pg;-<nLENhvx>-VsM.M0rJfLH2eTM`*oJMHRC`N"
  2161. "kfimM2J,W-jXS:)r0wK#@Fge$U>`w'N7G#$#fB#$E^$#:9:hk+eOe--6x)F7*E%?76%^GMHePW-Z5l'&GiF#$956:rS?dA#fiK:)Yr+`&#0j@'DbG&#^$PG.Ll+DNa<XCMKEV*N)LN/N"
  2162. "*b=%Q6pia-Xg8I$<MR&,VdJe$<(7G;Ckl'&hF;;$<_=X(b.RS%%)###MPBuuE1V:v&cX&#2m#(&cV]`k9OhLMbn%s$G2,B$BfD3X*sp5#l,$R#]x_X1xKX%b5U*[r5iMfUo9U`N99hG)"
  2163. "tm+/Us9pG)XPu`<0s-)WTt(gCRxIg(%6sfh=ktMKn3j)<6<b5Sk_/0(^]AaN#(p/L>&VZ>1i%h1S9u5o@YaaW$e+b<TWFn/Z:Oh(Cx2$lNEoN^e)#CFY@@I;BOQ*sRwZtZxRcU7uW6CX"
  2164. "ow0i(?$Q[cjOd[P4d)]>ROPOpxTO7Stwi1::iB1q)C_=dV26J;2,]7op$]uQr@_V7$q^%lQwtuHY]=DX,n3L#0PHDO4f9>dC@O>HBuKPpP*E,N+b3L#lpR/MrTEH.IAQk.a>D[.e;mc."
  2165. "x]Ip.PH^'/aqUO/$1WxLoW0[iLA<QT;5HKD+@qQ'NQ(3_PLhE48R.qAPSwQ0/WK?Z,[x?-J;jQTWA0X@KJ(_Y8N-:/M74:/-ZpKrUss?d#dZq]DAbkU*JqkL+nwX@@47`5>w=4h(9.`G"
  2166. "CRUxHPeR`5Mjol(dUWxZa(>STrPkrJiWx`5U7F#.g*jrohGg`cg:lSTvEY/EV_7H4Q9[Z%cnv;JQYZ5q.l7Zeas:HOIZOB?G<Nald$qs]@]L<J7bR*>gv:[7MI2k).'2($5FNP&EQ(,)"
  2167. "U]W]+fh18.vsai00);D3@4ku5P?DP8aJt+;qUM]=+b'8@;mViBKx0DE[-auGl8:PJ&Dj+M6OC]O^((##]`0i)drT;-7X`=-H3[igUnPG-NZlo.#k@h#=Ork$m>a>$-?Tm$UV(?#P6YY#"
  2168. "'/###xe7q.73rI3*pP/$1>s9)W,JrM7SN]'/4C#v$U`0#V.[0>xQsH$fEmPMgY2u7Kh(G%siIfLSoS+MK2eTM$=5,M8p`A.;_R%#u[K#$x4AG8.kK/HSB==-'Ie/QTtG?-.*^N-4B/ZM"
  2169. "_3YlQC7(p7q)&](`6_c)$/*JL(L-^(]$wIM`dPtOdGA,U3:w2M-0<q-]L_?^)1vw'.,MRsqVr.L;aN&#/EgJ)PBc[-f>+WomX2u7lqM2iEumMTcsF?-aT=Z-97UEnXglEn1K-bnEO`gu"
  2170. "Ft(c%=;Am_Qs@jLooI&NX;]0#j4#F14;gl8-GQpgwhrq8'=l_f-b49'UOqkLu7-##oDY2L(te+Mch&gLYtJ,MEtJfLh'x'M=$CS-ZZ%P]8bZ>#S?YY#%Q&q'3^Fw&?D)UDNrocM3A76/"
  2171. "/oL?#h7gl85[qW/NDOk%16ij;+:1a'iNIdb-ou8.P*w,v5#EI$TWS>Pot-R*H'-SEpA:g)f+O$%%`kA#G=8RMmG1&O`>to8bC]T&$,n.LoO>29sp3dt-52U%VM#q7'DHpg+#Z9%H[K<L"
  2172. "%a2E-grWVM3@2=-k22tL]4$##6We'8UJCKE[d_=%wI;'6X-GsLX4j^SgJ$##R*w,vP3wK#iiW&#*h^D&R?jp7+/u&#(AP##XU8c$fSYW-J95_-Dp[g9wcO&#M-h1OcJlc-*vpw0xUX&#"
  2173. "OQFKNX@QI'IoPp7nb,QU//MQ&ZDkKP)X<WSVL(68uVl&#c'[0#(s1X&xm$Y%B7*K:eDA323j998GXbA#pwMs-jgD$9QISB-A_(aN4xoFM^@C58D0+Q+q3n0#3U1InDjF682-SjMXJK)("
  2174. "h$hxua_K]ul92%'BOU&#BRRh-slg8KDlr:%L71Ka:.A;%YULjDPmL<LYs8i#XwJOYaKPKc1h:'9Ke,g)b),78=I39B;xiY$bgGw-&.Zi9InXDuYa%G*f2Bq7mn9^#p1vv%#(Wi-;/Z5h"
  2175. "o;#2:;%d&#x9v68C5g?ntX0X)pT`;%pB3q7mgGN)3%(P8nTd5L7GeA-GL@+%J3u2:(Yf>et`e;)f#Km8&+DC$I46>#Kr]]u-[=99tts1.qb#q72g1WJO81q+eN'03'eM>&1XxY-caEnO"
  2176. "j%2n8)),?ILR5^.Ibn<-X-Mq7[a82Lq:F&#ce+S9wsCK*x`569E8ew'He]h:sI[2LM$[guka3ZRd6:t%IG:;$%YiJ:Nq=?eAw;/:nnDq0(CYcMpG)qLN4$##&J<j$UpK<Q4a1]MupW^-"
  2177. "sj_$%[HK%'F####QRZJ::Y3EGl4'@%FkiAOg#p[##O`gukTfBHagL<LHw%q&OV0##F=6/:chIm0@eCP8X]:kFI%hl8hgO@RcBhS-@Qb$%+m=hPDLg*%K8ln(wcf3/'DW-$.lR?n[nCH-"
  2178. "eXOONTJlh:.RYF%3'p6sq:UIMA945&^HFS87@$EP2iG<-lCO$%c`uKGD3rC$x0BL8aFn--`ke%#HMP'vh1/R&O_J9'um,.<tx[@%wsJk&bUT2`0uMv7gg#qp/ij.L56'hl;.s5CUrxjO"
  2179. "M7-##.l+Au'A&O:-T72L]P`&=;ctp'XScX*rU.>-XTt,%OVU4)S1+R-#dg0/Nn?Ku1^0f$B*P:Rowwm-`0PKjYDDM'3]d39VZHEl4,.j']Pk-M.h^&:0FACm$maq-&sgw0t7/6(^xtk%"
  2180. "LuH88Fj-ekm>GA#_>568x6(OFRl-IZp`&b,_P'$M<Jnq79VsJW/mWS*PUiq76;]/NM_>hLbxfc$mj`,O;&%W2m`Zh:/)Uetw:aJ%]K9h:TcF]u_-Sj9,VK3M.*'&0D[Ca]J9gp8,kAW]"
  2181. "%(?A%R$f<->Zts'^kn=-^@c4%-pY6qI%J%1IGxfLU9CP8cbPlXv);C=b),<2mOvP8up,UVf3839acAWAW-W?#ao/^#%KYo8fRULNd2.>%m]UK:n%r$'sw]J;5pAoO_#2mO3n,'=H5(et"
  2182. "Hg*`+RLgv>=4U8guD$I%D:W>-r5V*%j*W:Kvej.Lp$<M-SGZ':+Q_k+uvOSLiEo(<aD/K<CCc`'Lx>'?;++O'>()jLR-^u68PHm8ZFWe+ej8h:9r6L*0//c&iH&R8pRbA#Kjm%upV1g:"
  2183. "a_#Ur7FuA#(tRh#.Y5K+@?3<-8m0$PEn;J:rh6?I6uG<-`wMU'ircp0LaE_OtlMb&1#6T.#FDKu#1Lw%u%+GM+X'e?YLfjM[VO0MbuFp7;>Q&#WIo)0@F%q7c#4XAXN-U&VB<HFF*qL("
  2184. "$/V,;(kXZejWO`<[5?\?ewY(*9=%wDc;,u<'9t3W-(H1th3+G]ucQ]kLs7df($/*JL]@*t7Bu_G3_7mp7<[email protected];x3B0lqp7Hf,^Ze7-##@/c58Mo(3;knp0%)A7?-W+eI'o8)b<"
  2185. "nKnw'Ho8C=Y>pqB>0ie&jhZ[?iLR@@_AvA-iQC(=ksRZRVp7`.=+NpBC%rh&3]R:8XDmE5^V8O(x<<aG/1N$#FX$0V5Y6x'aErI3I$7x%E`v<-BY,)%-?Psf*l?%C3.mM(=/M0:JxG'?"
  2186. "7WhH%o'a<-80g0NBxoO(GH<dM]n.+%q@jH?f.UsJ2Ggs&4<-e47&Kl+f//9@`b+?.TeN_&B8Ss?v;^Trk;f#YvJkl&w$]>-+k?'(<S:68tq*WoDfZu';mM?8X[ma8W%*`-=;D.(nc7/;"
  2187. ")g:T1=^J$&BRV(-lTmNB6xqB[@0*o.erM*<SWF]u2=st-*(6v>^](H.aREZSi,#1:[IXaZFOm<-ui#qUq2$##Ri;u75OK#(RtaW-K-F`S+cF]uN`-KMQ%rP/Xri.LRcB##=YL3BgM/3M"
  2188. "D?@f&1'BW-)Ju<L25gl8uhVm1hL$##*8###'A3/LkKW+(^rWX?5W_8g)a(m&K8P>#bmmWCMkk&#TR`C,5d>g)F;t,4:@_l8G/5h4vUd%&%950:VXD'QdWoY-F$BtUwmfe$YqL'8(PWX("
  2189. "P?^@Po3$##`MSs?DWBZ/S>+4%>fX,VWv/w'KD`LP5IbH;rTV>n3cEK8U#bX]l-/V+^lj3;vlMb&[5YQ8#pekX9JP3XUC72L,,?+Ni&co7ApnO*5NK,((W-i:$,kp'UDAO(G0Sq7MVjJs"
  2190. "bIu)'Z,*[>br5fX^:FPAWr-m2KgL<LUN098kTF&#lvo58=/vjDo;.;)Ka*hLR#/k=rKbxuV`>Q_nN6'8uTG&#1T5g)uLv:873UpTLgH+#FgpH'_o1780Ph8KmxQJ8#H72L4@768@Tm&Q"
  2191. "h4CB/5OvmA&,Q&QbUoi$a_%3M01H)4x7I^&KQVgtFnV+;[Pc>[m4k//,]1?#`VY[Jr*3&&slRfLiVZJ:]?=K3Sw=[$=uRB?3xk48@aeg<Z'<$#4H)6,>e0jT6'N#(q%.O=?2S]u*(m<-"
  2192. "V8J'(1)G][68hW$5'q[GC&5j`TE?m'esFGNRM)j,ffZ?-qx8;->g4t*:CIP/[Qap7/9'#(1sao7w-.qNUdkJ)tCF&#B^;[email protected]$m%#QvQS8U@)2Z+3K:AKM5i"
  2193. "sZ88+dKQ)W6>J%CL<KE>`.d*(B`-n8D9oK<Up]c$X$(,)M8Zt7/[rdkqTgl-0cuGMv'?>-XV1q['-5k'cAZ69e;D_?$ZPP&s^+7])$*$#@QYi9,5P&#9r+$%CE=68>K8r0=dSC%%(@p7"
  2194. ".m7jilQ02'0-VWAg<a/''3u.=4L$Y)6k/K:_[3=&jvL<L0C/2'v:^;-DIBW,B4E68:kZ;%?8(Q8BH=kO65BW?xSG&#@uU,DS*,?.+(o(#1vCS8#CHF>TlGW'b)Tq7VT9q^*^$$.:&N@@"
  2195. "$&)WHtPm*5_rO0&e%K&#-30j(E4#'Zb.o/(Tpm$>K'f@[PvFl,hfINTNU6u'0pao7%XUp9]5.>%h`8_=VYbxuel.NTSsJfLacFu3B'lQSu/m6-Oqem8T+oE--$0a/k]uj9EwsG>%veR*"
  2196. "hv^BFpQj:K'#SJ,sB-'#](j.Lg92rTw-*n%@/;39rrJF,l#qV%OrtBeC6/,;qB3ebNW[?,Hqj2L.1NP&GjUR=1D8QaS3Up&@*9wP?+lo7b?@%'k4`p0Z$22%K3+iCZj?XJN4Nm&+YF]u"
  2197. "@-W$U%VEQ/,,>>#)D<h#`)h0:<Q6909ua+&VU%n2:cG3FJ-%@Bj-DgLr`Hw&HAKjKjseK</xKT*)B,N9X3]krc12t'pgTV(Lv-tL[xg_%=M_q7a^x?7Ubd>#%8cY#YZ?=,`Wdxu/ae&#"
  2198. "w6)R89tI#6@s'(6Bf7a&?S=^ZI_kS&ai`&=tE72L_D,;^R)7[$s<Eh#c&)q.MXI%#v9ROa5FZO%sF7q7Nwb&#ptUJ:aqJe$Sl68%.D###EC><?-aF&#RNQv>o8lKN%5/$(vdfq7+ebA#"
  2199. "u1p]ovUKW&Y%q]'>$1@-[xfn$7ZTp7mM,G,Ko7a&Gu%G[RMxJs[0MM%wci.LFDK)(<c`Q8N)jEIF*+?P2a8g%)$q]o2aH8C&<SibC/q,(e:v;-b#6[$NtDZ84Je2KNvB#$P5?tQ3nt(0"
  2200. "d=j.LQf./Ll33+(;q3L-w=8dX$#WF&uIJ@-bfI>%:_i2B5CsR8&9Z&#=mPEnm0f`<&c)QL5uJ#%u%lJj+D-r;BoF&#4DoS97h5g)E#o:&S4weDF,9^Hoe`h*L+_a*NrLW-1pG_&2UdB8"
  2201. "6e%B/:=>)N4xeW.*wft-;$'58-ESqr<b?UI(_%@[P46>#U`'6AQ]m&6/`Z>#S?YY#Vc;r7U2&326d=w&H####?TZ`*4?&.MK?LP8Vxg>$[QXc%QJv92.(Db*B)gb*BM9dM*hJMAo*c&#"
  2202. "b0v=Pjer]$gG&JXDf->'StvU7505l9$AFvgYRI^&<^b68?j#q9QX4SM'RO#&sL1IM.rJfLUAj221]d##DW=m83u5;'bYx,*Sl0hL(W;;$doB&O/TQ:(Z^xBdLjL<Lni;''X.`$#8+1GD"
  2203. ":k$YUWsbn8ogh6rxZ2Z9]%nd+>V#*8U_72Lh+2Q8Cj0i:6hp&$C/:p(HK>T8Y[gHQ4`4)'$Ab(Nof%V'8hL&#<NEdtg(n'=S1A(Q1/I&4([%dM`,Iu'1:_hL>SfD07&6D<fp8dHM7/g+"
  2204. "tlPN9J*rKaPct&?'uBCem^jn%9_K)<,C5K3s=5g&GmJb*[SYq7K;TRLGCsM-$$;S%:Y@r7AK0pprpL<Lrh,q7e/%KWK:50I^+m'vi`3?%Zp+<-d+$L-Sv:@.o19n$s0&39;kn;S%BSq*"
  2205. "$3WoJSCLweV[aZ'MQIjO<7;X-X;&+dMLvu#^UsGEC9WEc[X(wI7#2.(F0jV*eZf<-Qv3J-c+J5AlrB#$p(H68LvEA'q3n0#m,[`*8Ft)FcYgEud]CWfm68,(aLA$@EFTgLXoBq/UPlp7"
  2206. ":d[/;r_ix=:TF`S5H-b<LI&HY(K=h#)]Lk$K14lVfm:x$H<3^Ql<M`$OhapBnkup'D#L$Pb_`N*g]2e;X/Dtg,bsj&K#2[-:iYr'_wgH)NUIR8a1n#S?Yej'h8^58UbZd+^FKD*T@;6A"
  2207. "7aQC[K8d-(v6GI$x:T<&'Gp5Uf>@M.*J:;$-rv29'M]8qMv-tLp,'886iaC=Hb*YJoKJ,(j%K=H`K.v9HggqBIiZu'QvBT.#=)0ukruV&.)3=(^1`o*Pj4<-<aN((^7('#Z0wK#5GX@7"
  2208. "u][`*S^43933A4rl][`*O4CgLEl]v$1Q3AeF37dbXk,.)vj#x'd`;qgbQR%FW,2(?LO=s%Sc68%NP'##Aotl8x=BE#j1UD([3$M(]UI2LX3RpKN@;/#f'f/&_mt&F)XdF<9t4)Qa.*kT"
  2209. "LwQ'(TTB9.xH'>#MJ+gLq9-##@HuZPN0]u:h7.T..G:;$/Usj(T7`Q8tT72LnYl<-qx8;-HV7Q-&Xdx%1a,hC=0u+HlsV>nuIQL-5<N?)NBS)QN*_I,?&)2'IM%L3I)X((e/dl2&8'<M"
  2210. ":^#M*Q+[T.Xri.LYS3v%fF`68h;b-X[/En'CR.q7E)p'/kle2HM,u;^%OKC-N+Ll%F9CF<Nf'^#t2L,;27W:0O@6##U6W7:$rJfLWHj$#)woqBefIZ.PK<b*t7ed;p*_m;4ExK#h@&]>"
  2211. "_>@kXQtMacfD.m-VAb8;IReM3$wf0''hra*so568'Ip&vRs849'MRYSp%:t:h5qSgwpEr$B>Q,;s(C#$)`svQuF$##-D,##,g68@2[T;.XSdN9Qe)rpt._K-#5wF)sP'##p#C0c%-Gb%"
  2212. "hd+<-j'Ai*x&&HMkT]C'OSl##5RG[JXaHN;d'uA#x._U;.`PU@(Z3dt4r152@:v,'R.Sj'w#0<-;kPI)FfJ&#AYJ&#//)>-k=m=*XnK$>=)72L]0I%>.G690a:$##<,);?;72#?x9+d;"
  2213. "^V'9;jY@;)br#q^YQpx:X#Te$Z^'=-=bGhLf:D6&bNwZ9-ZD#n^9HhLMr5G;']d&6'wYmTFmL<LD)F^%[tC'8;+9E#C$g%#5Y>q9wI>P(9mI[>kC-ekLC/R&CH+s'B;K-M6$EB%is00:"
  2214. "+A4[7xks.LrNk0&E)wILYF@2L'0Nb$+pv<(2.768/FrY&h$^3i&@+G%JT'<-,v`3;_)I9M^AE]CN?Cl2AZg+%4iTpT3<n-&%H%b<FDj2M<hH=&Eh<2Len$b*aTX=-8QxN)k11IM1c^j%"
  2215. "9s<L<NFSo)B?+<-(GxsF,^-Eh@$4dXhN$+#rxK8'je'D7k`e;)2pYwPA'_p9&@^18ml1^[@g4t*[JOa*[=Qp7(qJ_oOL^('7fB&Hq-:sf,sNj8xq^>$U4O]GKx'm9)b@p7YsvK3w^YR-"
  2216. "CdQ*:Ir<($u&)#(&?L9Rg3H)4fiEp^iI9O8KnTj,]H?D*r7'M;PwZ9K0E^k&-cpI;.p/6_vwoFMV<->#%Xi.LxVnrU(4&8/P+:hLSKj$#U%]49t'I:rgMi'FL@a:0Y-uA[39',(vbma*"
  2217. "hU%<-SRF`Tt:542R_VV$p@[p8DV[A,?1839FWdF<TddF<9Ah-6&9tWoDlh]&1SpGMq>Ti1O*H&#(AL8[_P%.M>v^-))qOT*F5Cq0`Ye%+$B6i:7@0IX<N+T+0MlMBPQ*Vj>SsD<U4JHY"
  2218. "8kD2)2fU/M#$e.)T4,_=8hLim[&);?UkK'-x?'(:siIfL<$pFM`i<?%W(mGDHM%>iWP,##P`%/L<eXi:@Z9C.7o=@(pXdAO/NLQ8lPl+HPOQa8wD8=^GlPa8TKI1CjhsCTSLJM'/Wl>-"
  2219. "S(qw%sf/@%#B6;/U7K]uZbi^Oc^2n<bhPmUkMw>%t<)'mEVE''n`WnJra$^TKvX5B>;_aSEK',(hwa0:i4G?.Bci.(X[?b*($,=-n<.Q%`(X=?+@Am*Js0&=3bh8K]mL<LoNs'6,'85`"
  2220. "0?t/'_U59@]ddF<#LdF<eWdF<OuN/45rY<-L@&#+fm>69=Lb,OcZV/);TTm8VI;?%OtJ<(b4mq7M6:u?KRdF<gR@2L=FNU-<b[(9c/ML3m;Z[$oF3g)GAWqpARc=<ROu7cL5l;-[A]%/"
  2221. "+fsd;l#SafT/f*W]0=O'$(Tb<[)*@e775R-:Yob%g*>l*:xP?Yb.5)%w_I?7uk5JC+FS(m#i'k.'a0i)9<7b'fs'59hq$*5Uhv##pi^8+hIEBF`nvo`;'l0.^S1<-wUK2/Coh58KKhLj"
  2222. "M=SO*rfO`+qC`W-On.=AJ56>>i2@2LH6A:&5q`?9I3@@'04&p2/LVa*T-4<-i3;M9UvZd+N7>b*eIwg:CC)c<>nO&#<IGe;__.thjZl<%w(Wk2xmp4Q@I#I9,DF]u7-P=.-_:YJ]aS@V"
  2223. "?6*C()dOp7:WL,b&3Rg/.cmM9&r^>$(>.Z-I&J(Q0Hd5Q%7Co-b`-c<N(6r@ip+AurK<m86QIth*#v;-OBqi+L7wDE-Ir8K['m+DDSLwK&/.?-V%U_%3:qKNu$_b*B-kp7NaD'QdWQPK"
  2224. "Yq[@>P)hI;*_F]u`Rb[.j8_Q/<&>uu+VsH$sM9TA%?)(vmJ80),P7E>)tjD%2L=-t#fK[%`v=Q8<FfNkgg^oIbah*#8/Qt$F&:K*-(N/'+1vMB,u()-a.VUU*#[e%gAAO(S>WlA2);Sa"
  2225. ">gXm8YB`1d@K#n]76-a$U,mF<fX]idqd)<3,]J7JmW4`6]uks=4-72L(jEk+:bJ0M^q-8Dm_Z?0olP1C9Sa&H[d&c$ooQUj]Exd*3ZM@-WGW2%s',B-_M%>%Ul:#/'xoFM9QX-$.QN'>"
  2226. "[%$Z$uF6pA6Ki2O5:8w*vP1<-1`[G,)-m#>0`P&#eb#.3i)rtB61(o'$?X3B</R90;eZ]%Ncq;-Tl]#F>2Qft^ae_5tKL9MUe9b*sLEQ95C&`=G?@Mj=wh*'3E>=-<)Gt*Iw)'QG:`@I"
  2227. "wOf7&]1i'S01B+Ev/Nac#9S;=;YQpg_6U`*kVY39xK,[/6Aj7:'1Bm-_1EYfa1+o&o4hp7KN_Q(OlIo@S%;jVdn0'1<Vc52=u`3^o-n1'g4v58Hj&6_t7$##?M)c<$bgQ_'SY((-xkA#"
  2228. "Y(,p'H9rIVY-b,'%bCPF7.J<Up^,(dU1VY*5#WkTU>h19w,WQhLI)3S#f$2(eb,jr*b;3Vw]*7NH%$c4Vs,eD9>XW8?N]o+(*pgC%/72LV-u<Hp,3@e^9UB1J+ak9-TN/mhKPg+AJYd$"
  2229. "MlvAF_jCK*.O-^(63adMT->W%iewS8W6m2rtCpo'RS1R84=@paTKt)>=%&1[)*vp'u+x,VrwN;&]kuO9JDbg=pO$J*.jVe;u'm0dr9l,<*wMK*Oe=g8lV_KEBFkO'oU]^=[-792#ok,)"
  2230. "i]lR8qQ2oA8wcRCZ^7w/Njh;?.stX?Q1>S1q4Bn$)K1<-rGdO'$Wr.Lc.CG)$/*JL4tNR/,SVO3,aUw'DJN:)Ss;wGn9A32ijw%FL+Z0Fn.U9;reSq)bmI32U==5ALuG&#Vf1398/pVo"
  2231. "1*c-(aY168o<`JsSbk-,1N;$>0:OUas(3:8Z972LSfF8eb=c-;>SPw7.6hn3m`9^Xkn(r.qS[0;T%&Qc=+STRxX'q1BNk3&*eu2;&8q$&x>Q#Q7^Tf+6<(d%ZVmj2bDi%.3L2n+4W'$P"
  2232. "iDDG)g,r%+?,$@?uou5tSe2aN_AQU*<h`e-GI7)?OK2A.d7_c)?wQ5AS@DL3r#7fSkgl6-++D:'A,uq7SvlB$pcpH'q3n0#_%dY#xCpr-l<F0NR@-##FEV6NTF6##$l84N1w?AO>'IAO"
  2233. "URQ##V^Fv-XFbGM7Fl(N<3DhLGF%q.1rC$#:T__&Pi68%0xi_&[qFJ(77j_&JWoF.V735&T,[R*:xFR*K5>>#`bW-?4Ne_&6Ne_&6Ne_&n`kr-#GJcM6X;uM6X;uM(.a..^2TkL%oR(#"
  2234. ";u.T%fAr%4tJ8&><1=GHZ_+m9/#H1F^R#SC#*N=BA9(D?v[UiFY>>^8p,KKF.W]L29uLkLlu/+4T<XoIB&hx=T1PcDaB&;HH+-AFr?(m9HZV)FKS8JCw;SD=6[^/DZUL`EUDf]GGlG&>"
  2235. "w$)F./^n3+rlo+DB;5sIYGNk+i1t-69Jg--0pao7Sm#K)pdHW&;LuDNH@H>#/X-TI(;P>#,Gc>#0Su>#4`1?#8lC?#<xU?#@.i?#D:%@#HF7@#LRI@#P_[@#Tkn@#Xw*A#]-=A#a9OA#"
  2236. "d<F&#*;G##.GY##2Sl##6`($#:l:$#>xL$#B.`$#F:r$#JF.%#NR@%#R_R%#Vke%#Zww%#_-4&#3^Rh%Sflr-k'MS.o?.5/sWel/wpEM0%3'/1)K^f1-d>G21&v(35>V`39V7A4=onx4"
  2237. "A1OY5EI0;6Ibgr6M$HS7Q<)58C5w,;WoA*#[%T*#`1g*#d=#+#hI5+#lUG+#pbY+#tnl+#x$),#&1;,#*=M,#.I`,#2Ur,#6b.-#;w[H#iQtA#m^0B#qjBB#uvTB##-hB#'9$C#+E6C#"
  2238. "/QHC#3^ZC#7jmC#;v)D#?,<D#C8ND#GDaD#KPsD#O]/E#g1A5#KA*1#gC17#MGd;#8(02#L-d3#rWM4#Hga1#,<w0#T.j<#O#'2#CYN1#qa^:#_4m3#o@/=#eG8=#t8J5#`+78#4uI-#"
  2239. "m3B2#SB[8#Q0@8#i[*9#iOn8#1Nm;#^sN9#qh<9#:=x-#P;K2#$%X9#bC+.#Rg;<#mN=.#MTF.#RZO.#2?)4#Y#(/#[)1/#b;L/#dAU/#0Sv;#lY$0#n`-0#sf60#(F24#wrH0#%/e0#"
  2240. "TmD<#%JSMFove:CTBEXI:<eh2g)B,3h2^G3i;#d3jD>)4kMYD4lVu`4m`:&5niUA5@(A5BA1]PBB:xlBCC=2CDLXMCEUtiCf&0g2'tN?PGT4CPGT4CPGT4CPGT4CPGT4CPGT4CPGT4CP"
  2241. "GT4CPGT4CPGT4CPGT4CPGT4CPGT4CP-qekC`.9kEg^+F$kwViFJTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5o,^<-28ZI'O?;xp"
  2242. "O?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xp;7q-#lLYI:xvD=#";
  2243. static const char* GetDefaultCompressedFontDataTTFBase85()
  2244. {
  2245. return proggy_clean_ttf_compressed_data_base85;
  2246. }