1 // dear imgui, v1.53 WIP
2 // (drawing and font code)
4 // Contains implementation for
10 // - Default font data
12 #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
13 #define _CRT_SECURE_NO_WARNINGS
17 #define IMGUI_DEFINE_MATH_OPERATORS
18 #define IMGUI_DEFINE_PLACEMENT_NEW
19 #include "imgui_internal.h"
21 #include <stdio.h> // vsnprintf, sscanf, printf
24 #include <malloc.h> // alloca
25 #elif defined(__GLIBC__) || defined(__sun)
26 #include <alloca.h> // alloca
28 #include <stdlib.h> // alloca
33 #pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff)
34 #pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
35 #define snprintf _snprintf
39 #pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse.
40 #pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants ok.
41 #pragma clang diagnostic ignored "-Wglobal-constructors" // warning : declaration requires a global destructor // similar to above, not sure what the exact difference it.
42 #pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness //
43 #if __has_warning("-Wreserved-id-macro")
44 #pragma clang diagnostic ignored "-Wreserved-id-macro" // warning : macro name is a reserved identifier //
46 #if __has_warning("-Wdouble-promotion")
47 #pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function
49 #elif defined(__GNUC__)
50 #pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used
51 #pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function
52 #pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value
53 #pragma GCC diagnostic ignored "-Wcast-qual" // warning: cast from type 'xxxx' to type 'xxxx' casts away qualifiers
56 //-------------------------------------------------------------------------
57 // STB libraries implementation
58 //-------------------------------------------------------------------------
60 //#define IMGUI_STB_NAMESPACE ImGuiStb
61 //#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
62 //#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
64 #ifdef IMGUI_STB_NAMESPACE
65 namespace IMGUI_STB_NAMESPACE
70 #pragma warning (push)
71 #pragma warning (disable: 4456) // declaration of 'xx' hides previous local declaration
75 #pragma clang diagnostic push
76 #pragma clang diagnostic ignored "-Wunused-function"
77 #pragma clang diagnostic ignored "-Wmissing-prototypes"
81 #pragma GCC diagnostic push
82 #pragma GCC diagnostic ignored "-Wtype-limits" // warning: comparison is always true due to limited range of data type [-Wtype-limits]
85 #define STBRP_ASSERT(x) IM_ASSERT(x)
86 #ifndef IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
88 #define STB_RECT_PACK_IMPLEMENTATION
90 #include "stb_rect_pack.h"
92 #define STBTT_malloc(x,u) ((void)(u), ImGui::MemAlloc(x))
93 #define STBTT_free(x,u) ((void)(u), ImGui::MemFree(x))
94 #define STBTT_assert(x) IM_ASSERT(x)
95 #ifndef IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
97 #define STB_TRUETYPE_IMPLEMENTATION
99 #define STBTT_DEF extern
101 #include "stb_truetype.h"
104 #pragma GCC diagnostic pop
108 #pragma clang diagnostic pop
112 #pragma warning (pop)
115 #ifdef IMGUI_STB_NAMESPACE
116 } // namespace ImGuiStb
117 using namespace IMGUI_STB_NAMESPACE;
120 //-----------------------------------------------------------------------------
122 //-----------------------------------------------------------------------------
124 void ImGui::StyleColorsClassic(ImGuiStyle* dst)
126 ImGuiStyle* style = dst ? dst : &ImGui::GetStyle();
127 ImVec4* colors = style->Colors;
129 colors[ImGuiCol_Text] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
130 colors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f);
131 colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.70f);
132 colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
133 colors[ImGuiCol_PopupBg] = ImVec4(0.11f, 0.11f, 0.14f, 0.92f);
134 colors[ImGuiCol_Border] = ImVec4(0.50f, 0.50f, 0.50f, 0.50f);
135 colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
136 colors[ImGuiCol_FrameBg] = ImVec4(0.43f, 0.43f, 0.43f, 0.39f);
137 colors[ImGuiCol_FrameBgHovered] = ImVec4(0.47f, 0.47f, 0.69f, 0.40f);
138 colors[ImGuiCol_FrameBgActive] = ImVec4(0.42f, 0.41f, 0.64f, 0.69f);
139 colors[ImGuiCol_TitleBg] = ImVec4(0.27f, 0.27f, 0.54f, 0.83f);
140 colors[ImGuiCol_TitleBgActive] = ImVec4(0.32f, 0.32f, 0.63f, 0.87f);
141 colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.40f, 0.40f, 0.80f, 0.20f);
142 colors[ImGuiCol_MenuBarBg] = ImVec4(0.40f, 0.40f, 0.55f, 0.80f);
143 colors[ImGuiCol_ScrollbarBg] = ImVec4(0.20f, 0.25f, 0.30f, 0.60f);
144 colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.40f, 0.40f, 0.80f, 0.30f);
145 colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.40f, 0.40f, 0.80f, 0.40f);
146 colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.41f, 0.39f, 0.80f, 0.60f);
147 colors[ImGuiCol_CheckMark] = ImVec4(0.90f, 0.90f, 0.90f, 0.50f);
148 colors[ImGuiCol_SliderGrab] = ImVec4(1.00f, 1.00f, 1.00f, 0.30f);
149 colors[ImGuiCol_SliderGrabActive] = ImVec4(0.41f, 0.39f, 0.80f, 0.60f);
150 colors[ImGuiCol_Button] = ImVec4(0.35f, 0.40f, 0.61f, 0.62f);
151 colors[ImGuiCol_ButtonHovered] = ImVec4(0.40f, 0.48f, 0.71f, 0.79f);
152 colors[ImGuiCol_ButtonActive] = ImVec4(0.46f, 0.54f, 0.80f, 1.00f);
153 colors[ImGuiCol_Header] = ImVec4(0.40f, 0.40f, 0.90f, 0.45f);
154 colors[ImGuiCol_HeaderHovered] = ImVec4(0.45f, 0.45f, 0.90f, 0.80f);
155 colors[ImGuiCol_HeaderActive] = ImVec4(0.53f, 0.53f, 0.87f, 0.80f);
156 colors[ImGuiCol_Separator] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
157 colors[ImGuiCol_SeparatorHovered] = ImVec4(0.60f, 0.60f, 0.70f, 1.00f);
158 colors[ImGuiCol_SeparatorActive] = ImVec4(0.70f, 0.70f, 0.90f, 1.00f);
159 colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.16f);
160 colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.78f, 0.82f, 1.00f, 0.60f);
161 colors[ImGuiCol_ResizeGripActive] = ImVec4(0.78f, 0.82f, 1.00f, 0.90f);
162 colors[ImGuiCol_CloseButton] = ImVec4(0.50f, 0.50f, 0.90f, 0.50f);
163 colors[ImGuiCol_CloseButtonHovered] = ImVec4(0.70f, 0.70f, 0.90f, 0.60f);
164 colors[ImGuiCol_CloseButtonActive] = ImVec4(0.70f, 0.70f, 0.70f, 1.00f);
165 colors[ImGuiCol_PlotLines] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
166 colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
167 colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
168 colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
169 colors[ImGuiCol_TextSelectedBg] = ImVec4(0.00f, 0.00f, 1.00f, 0.35f);
170 colors[ImGuiCol_ModalWindowDarkening] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f);
173 void ImGui::StyleColorsDark(ImGuiStyle* dst)
175 ImGuiStyle* style = dst ? dst : &ImGui::GetStyle();
176 ImVec4* colors = style->Colors;
178 colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
179 colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
180 colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.06f, 0.06f, 0.94f);
181 colors[ImGuiCol_ChildBg] = ImVec4(1.00f, 1.00f, 1.00f, 0.00f);
182 colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.08f, 0.94f);
183 colors[ImGuiCol_Border] = ImVec4(0.43f, 0.43f, 0.50f, 0.50f);
184 colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
185 colors[ImGuiCol_FrameBg] = ImVec4(0.16f, 0.29f, 0.48f, 0.54f);
186 colors[ImGuiCol_FrameBgHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);
187 colors[ImGuiCol_FrameBgActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
188 colors[ImGuiCol_TitleBg] = ImVec4(0.04f, 0.04f, 0.04f, 1.00f);
189 colors[ImGuiCol_TitleBgActive] = ImVec4(0.16f, 0.29f, 0.48f, 1.00f);
190 colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.00f, 0.00f, 0.51f);
191 colors[ImGuiCol_MenuBarBg] = ImVec4(0.14f, 0.14f, 0.14f, 1.00f);
192 colors[ImGuiCol_ScrollbarBg] = ImVec4(0.02f, 0.02f, 0.02f, 0.53f);
193 colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.31f, 0.31f, 0.31f, 1.00f);
194 colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f);
195 colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.51f, 0.51f, 0.51f, 1.00f);
196 colors[ImGuiCol_CheckMark] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
197 colors[ImGuiCol_SliderGrab] = ImVec4(0.24f, 0.52f, 0.88f, 1.00f);
198 colors[ImGuiCol_SliderGrabActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
199 colors[ImGuiCol_Button] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);
200 colors[ImGuiCol_ButtonHovered] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
201 colors[ImGuiCol_ButtonActive] = ImVec4(0.06f, 0.53f, 0.98f, 1.00f);
202 colors[ImGuiCol_Header] = ImVec4(0.26f, 0.59f, 0.98f, 0.31f);
203 colors[ImGuiCol_HeaderHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.80f);
204 colors[ImGuiCol_HeaderActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
205 colors[ImGuiCol_Separator] = colors[ImGuiCol_Border];//ImVec4(0.61f, 0.61f, 0.61f, 1.00f);
206 colors[ImGuiCol_SeparatorHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.78f);
207 colors[ImGuiCol_SeparatorActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
208 colors[ImGuiCol_ResizeGrip] = ImVec4(0.26f, 0.59f, 0.98f, 0.25f);
209 colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
210 colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
211 colors[ImGuiCol_CloseButton] = ImVec4(0.41f, 0.41f, 0.41f, 0.50f);
212 colors[ImGuiCol_CloseButtonHovered] = ImVec4(0.98f, 0.39f, 0.36f, 1.00f);
213 colors[ImGuiCol_CloseButtonActive] = ImVec4(0.98f, 0.39f, 0.36f, 1.00f);
214 colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);
215 colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
216 colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
217 colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
218 colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
219 colors[ImGuiCol_ModalWindowDarkening] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f);
222 void ImGui::StyleColorsLight(ImGuiStyle* dst)
224 ImGuiStyle* style = dst ? dst : &ImGui::GetStyle();
225 ImVec4* colors = style->Colors;
227 colors[ImGuiCol_Text] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f);
228 colors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f);
229 //colors[ImGuiCol_TextHovered] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
230 //colors[ImGuiCol_TextActive] = ImVec4(1.00f, 1.00f, 0.00f, 1.00f);
231 colors[ImGuiCol_WindowBg] = ImVec4(0.94f, 0.94f, 0.94f, 1.00f);
232 colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
233 colors[ImGuiCol_PopupBg] = ImVec4(1.00f, 1.00f, 1.00f, 0.94f);
234 colors[ImGuiCol_Border] = ImVec4(0.00f, 0.00f, 0.00f, 0.30f);
235 colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
236 colors[ImGuiCol_FrameBg] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
237 colors[ImGuiCol_FrameBgHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);
238 colors[ImGuiCol_FrameBgActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
239 colors[ImGuiCol_TitleBg] = ImVec4(0.96f, 0.96f, 0.96f, 1.00f);
240 colors[ImGuiCol_TitleBgActive] = ImVec4(0.82f, 0.82f, 0.82f, 1.00f);
241 colors[ImGuiCol_TitleBgCollapsed] = ImVec4(1.00f, 1.00f, 1.00f, 0.51f);
242 colors[ImGuiCol_MenuBarBg] = ImVec4(0.86f, 0.86f, 0.86f, 1.00f);
243 colors[ImGuiCol_ScrollbarBg] = ImVec4(0.98f, 0.98f, 0.98f, 0.53f);
244 colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.69f, 0.69f, 0.69f, 0.80f);
245 colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.49f, 0.49f, 0.49f, 0.80f);
246 colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.49f, 0.49f, 0.49f, 1.00f);
247 colors[ImGuiCol_CheckMark] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
248 colors[ImGuiCol_SliderGrab] = ImVec4(0.26f, 0.59f, 0.98f, 0.78f);
249 colors[ImGuiCol_SliderGrabActive] = ImVec4(0.46f, 0.54f, 0.80f, 0.60f);
250 colors[ImGuiCol_Button] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);
251 colors[ImGuiCol_ButtonHovered] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
252 colors[ImGuiCol_ButtonActive] = ImVec4(0.06f, 0.53f, 0.98f, 1.00f);
253 colors[ImGuiCol_Header] = ImVec4(0.26f, 0.59f, 0.98f, 0.31f);
254 colors[ImGuiCol_HeaderHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.80f);
255 colors[ImGuiCol_HeaderActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
256 colors[ImGuiCol_Separator] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f);
257 colors[ImGuiCol_SeparatorHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.78f);
258 colors[ImGuiCol_SeparatorActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
259 colors[ImGuiCol_ResizeGrip] = ImVec4(0.80f, 0.80f, 0.80f, 0.56f);
260 colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
261 colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
262 colors[ImGuiCol_CloseButton] = ImVec4(0.59f, 0.59f, 0.59f, 0.50f);
263 colors[ImGuiCol_CloseButtonHovered] = ImVec4(0.98f, 0.39f, 0.36f, 1.00f);
264 colors[ImGuiCol_CloseButtonActive] = ImVec4(0.98f, 0.39f, 0.36f, 1.00f);
265 colors[ImGuiCol_PlotLines] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f);
266 colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
267 colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
268 colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.45f, 0.00f, 1.00f);
269 colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
270 colors[ImGuiCol_ModalWindowDarkening] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f);
274 //-----------------------------------------------------------------------------
276 //-----------------------------------------------------------------------------
278 static const ImVec4 GNullClipRect(-8192.0f, -8192.0f, +8192.0f, +8192.0f); // Large values that are easy to encode in a few bits+shift
280 void ImDrawList::Clear()
288 _ClipRectStack.resize(0);
289 _TextureIdStack.resize(0);
291 _ChannelsCurrent = 0;
293 // NB: Do not clear channels so our allocations are re-used after the first frame.
296 void ImDrawList::ClearFreeMemory()
304 _ClipRectStack.clear();
305 _TextureIdStack.clear();
307 _ChannelsCurrent = 0;
309 for (int i = 0; i < _Channels.Size; i++)
311 if (i == 0) memset(&_Channels[0], 0, sizeof(_Channels[0])); // channel 0 is a copy of CmdBuffer/IdxBuffer, don't destruct again
312 _Channels[i].CmdBuffer.clear();
313 _Channels[i].IdxBuffer.clear();
318 // Using macros because C++ is a terrible language, we want guaranteed inline, no code in header, and no overhead in Debug builds
319 #define GetCurrentClipRect() (_ClipRectStack.Size ? _ClipRectStack.Data[_ClipRectStack.Size-1] : GNullClipRect)
320 #define GetCurrentTextureId() (_TextureIdStack.Size ? _TextureIdStack.Data[_TextureIdStack.Size-1] : NULL)
322 void ImDrawList::AddDrawCmd()
325 draw_cmd.ClipRect = GetCurrentClipRect();
326 draw_cmd.TextureId = GetCurrentTextureId();
328 IM_ASSERT(draw_cmd.ClipRect.x <= draw_cmd.ClipRect.z && draw_cmd.ClipRect.y <= draw_cmd.ClipRect.w);
329 CmdBuffer.push_back(draw_cmd);
332 void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data)
334 ImDrawCmd* current_cmd = CmdBuffer.Size ? &CmdBuffer.back() : NULL;
335 if (!current_cmd || current_cmd->ElemCount != 0 || current_cmd->UserCallback != NULL)
338 current_cmd = &CmdBuffer.back();
340 current_cmd->UserCallback = callback;
341 current_cmd->UserCallbackData = callback_data;
343 AddDrawCmd(); // Force a new command after us (see comment below)
346 // 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.
347 // 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.
348 void ImDrawList::UpdateClipRect()
350 // If current command is used with different settings we need to add a new command
351 const ImVec4 curr_clip_rect = GetCurrentClipRect();
352 ImDrawCmd* curr_cmd = CmdBuffer.Size > 0 ? &CmdBuffer.Data[CmdBuffer.Size-1] : NULL;
353 if (!curr_cmd || (curr_cmd->ElemCount != 0 && memcmp(&curr_cmd->ClipRect, &curr_clip_rect, sizeof(ImVec4)) != 0) || curr_cmd->UserCallback != NULL)
359 // Try to merge with previous command if it matches, else use current command
360 ImDrawCmd* prev_cmd = CmdBuffer.Size > 1 ? curr_cmd - 1 : NULL;
361 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)
362 CmdBuffer.pop_back();
364 curr_cmd->ClipRect = curr_clip_rect;
367 void ImDrawList::UpdateTextureID()
369 // If current command is used with different settings we need to add a new command
370 const ImTextureID curr_texture_id = GetCurrentTextureId();
371 ImDrawCmd* curr_cmd = CmdBuffer.Size ? &CmdBuffer.back() : NULL;
372 if (!curr_cmd || (curr_cmd->ElemCount != 0 && curr_cmd->TextureId != curr_texture_id) || curr_cmd->UserCallback != NULL)
378 // Try to merge with previous command if it matches, else use current command
379 ImDrawCmd* prev_cmd = CmdBuffer.Size > 1 ? curr_cmd - 1 : NULL;
380 if (curr_cmd->ElemCount == 0 && prev_cmd && prev_cmd->TextureId == curr_texture_id && memcmp(&prev_cmd->ClipRect, &GetCurrentClipRect(), sizeof(ImVec4)) == 0 && prev_cmd->UserCallback == NULL)
381 CmdBuffer.pop_back();
383 curr_cmd->TextureId = curr_texture_id;
386 #undef GetCurrentClipRect
387 #undef GetCurrentTextureId
389 // 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)
390 void ImDrawList::PushClipRect(ImVec2 cr_min, ImVec2 cr_max, bool intersect_with_current_clip_rect)
392 ImVec4 cr(cr_min.x, cr_min.y, cr_max.x, cr_max.y);
393 if (intersect_with_current_clip_rect && _ClipRectStack.Size)
395 ImVec4 current = _ClipRectStack.Data[_ClipRectStack.Size-1];
396 if (cr.x < current.x) cr.x = current.x;
397 if (cr.y < current.y) cr.y = current.y;
398 if (cr.z > current.z) cr.z = current.z;
399 if (cr.w > current.w) cr.w = current.w;
401 cr.z = ImMax(cr.x, cr.z);
402 cr.w = ImMax(cr.y, cr.w);
404 _ClipRectStack.push_back(cr);
408 void ImDrawList::PushClipRectFullScreen()
410 PushClipRect(ImVec2(GNullClipRect.x, GNullClipRect.y), ImVec2(GNullClipRect.z, GNullClipRect.w));
411 //PushClipRect(GetVisibleRect()); // FIXME-OPT: This would be more correct but we're not supposed to access ImGuiContext from here?
414 void ImDrawList::PopClipRect()
416 IM_ASSERT(_ClipRectStack.Size > 0);
417 _ClipRectStack.pop_back();
421 void ImDrawList::PushTextureID(const ImTextureID& texture_id)
423 _TextureIdStack.push_back(texture_id);
427 void ImDrawList::PopTextureID()
429 IM_ASSERT(_TextureIdStack.Size > 0);
430 _TextureIdStack.pop_back();
434 void ImDrawList::ChannelsSplit(int channels_count)
436 IM_ASSERT(_ChannelsCurrent == 0 && _ChannelsCount == 1);
437 int old_channels_count = _Channels.Size;
438 if (old_channels_count < channels_count)
439 _Channels.resize(channels_count);
440 _ChannelsCount = channels_count;
442 // _Channels[] (24/32 bytes each) hold storage that we'll swap with this->_CmdBuffer/_IdxBuffer
443 // 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.
444 // When we switch to the next channel, we'll copy _CmdBuffer/_IdxBuffer into _Channels[0] and then _Channels[1] into _CmdBuffer/_IdxBuffer
445 memset(&_Channels[0], 0, sizeof(ImDrawChannel));
446 for (int i = 1; i < channels_count; i++)
448 if (i >= old_channels_count)
450 IM_PLACEMENT_NEW(&_Channels[i]) ImDrawChannel();
454 _Channels[i].CmdBuffer.resize(0);
455 _Channels[i].IdxBuffer.resize(0);
457 if (_Channels[i].CmdBuffer.Size == 0)
460 draw_cmd.ClipRect = _ClipRectStack.back();
461 draw_cmd.TextureId = _TextureIdStack.back();
462 _Channels[i].CmdBuffer.push_back(draw_cmd);
467 void ImDrawList::ChannelsMerge()
469 // 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.
470 if (_ChannelsCount <= 1)
473 ChannelsSetCurrent(0);
474 if (CmdBuffer.Size && CmdBuffer.back().ElemCount == 0)
475 CmdBuffer.pop_back();
477 int new_cmd_buffer_count = 0, new_idx_buffer_count = 0;
478 for (int i = 1; i < _ChannelsCount; i++)
480 ImDrawChannel& ch = _Channels[i];
481 if (ch.CmdBuffer.Size && ch.CmdBuffer.back().ElemCount == 0)
482 ch.CmdBuffer.pop_back();
483 new_cmd_buffer_count += ch.CmdBuffer.Size;
484 new_idx_buffer_count += ch.IdxBuffer.Size;
486 CmdBuffer.resize(CmdBuffer.Size + new_cmd_buffer_count);
487 IdxBuffer.resize(IdxBuffer.Size + new_idx_buffer_count);
489 ImDrawCmd* cmd_write = CmdBuffer.Data + CmdBuffer.Size - new_cmd_buffer_count;
490 _IdxWritePtr = IdxBuffer.Data + IdxBuffer.Size - new_idx_buffer_count;
491 for (int i = 1; i < _ChannelsCount; i++)
493 ImDrawChannel& ch = _Channels[i];
494 if (int sz = ch.CmdBuffer.Size) { memcpy(cmd_write, ch.CmdBuffer.Data, sz * sizeof(ImDrawCmd)); cmd_write += sz; }
495 if (int sz = ch.IdxBuffer.Size) { memcpy(_IdxWritePtr, ch.IdxBuffer.Data, sz * sizeof(ImDrawIdx)); _IdxWritePtr += sz; }
497 UpdateClipRect(); // We call this instead of AddDrawCmd(), so that empty channels won't produce an extra draw call.
501 void ImDrawList::ChannelsSetCurrent(int idx)
503 IM_ASSERT(idx < _ChannelsCount);
504 if (_ChannelsCurrent == idx) return;
505 memcpy(&_Channels.Data[_ChannelsCurrent].CmdBuffer, &CmdBuffer, sizeof(CmdBuffer)); // copy 12 bytes, four times
506 memcpy(&_Channels.Data[_ChannelsCurrent].IdxBuffer, &IdxBuffer, sizeof(IdxBuffer));
507 _ChannelsCurrent = idx;
508 memcpy(&CmdBuffer, &_Channels.Data[_ChannelsCurrent].CmdBuffer, sizeof(CmdBuffer));
509 memcpy(&IdxBuffer, &_Channels.Data[_ChannelsCurrent].IdxBuffer, sizeof(IdxBuffer));
510 _IdxWritePtr = IdxBuffer.Data + IdxBuffer.Size;
513 // NB: this can be called with negative count for removing primitives (as long as the result does not underflow)
514 void ImDrawList::PrimReserve(int idx_count, int vtx_count)
516 ImDrawCmd& draw_cmd = CmdBuffer.Data[CmdBuffer.Size-1];
517 draw_cmd.ElemCount += idx_count;
519 int vtx_buffer_old_size = VtxBuffer.Size;
520 VtxBuffer.resize(vtx_buffer_old_size + vtx_count);
521 _VtxWritePtr = VtxBuffer.Data + vtx_buffer_old_size;
523 int idx_buffer_old_size = IdxBuffer.Size;
524 IdxBuffer.resize(idx_buffer_old_size + idx_count);
525 _IdxWritePtr = IdxBuffer.Data + idx_buffer_old_size;
528 // Fully unrolled with inline call to keep our debug builds decently fast.
529 void ImDrawList::PrimRect(const ImVec2& a, const ImVec2& c, ImU32 col)
531 ImVec2 b(c.x, a.y), d(a.x, c.y), uv(GImGui->FontTexUvWhitePixel);
532 ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx;
533 _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2);
534 _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3);
535 _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;
536 _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col;
537 _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col;
538 _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv; _VtxWritePtr[3].col = col;
544 void ImDrawList::PrimRectUV(const ImVec2& a, const ImVec2& c, const ImVec2& uv_a, const ImVec2& uv_c, ImU32 col)
546 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);
547 ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx;
548 _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2);
549 _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3);
550 _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv_a; _VtxWritePtr[0].col = col;
551 _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv_b; _VtxWritePtr[1].col = col;
552 _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv_c; _VtxWritePtr[2].col = col;
553 _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv_d; _VtxWritePtr[3].col = col;
559 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)
561 ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx;
562 _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2);
563 _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3);
564 _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv_a; _VtxWritePtr[0].col = col;
565 _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv_b; _VtxWritePtr[1].col = col;
566 _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv_c; _VtxWritePtr[2].col = col;
567 _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv_d; _VtxWritePtr[3].col = col;
573 // TODO: Thickness anti-aliased lines cap are missing their AA fringe.
574 void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 col, bool closed, float thickness, bool anti_aliased)
576 if (points_count < 2)
579 const ImVec2 uv = GImGui->FontTexUvWhitePixel;
580 anti_aliased &= GImGui->Style.AntiAliasedLines;
581 //if (ImGui::GetIO().KeyCtrl) anti_aliased = false; // Debug
583 int count = points_count;
585 count = points_count-1;
587 const bool thick_line = thickness > 1.0f;
590 // Anti-aliased stroke
591 const float AA_SIZE = 1.0f;
592 const ImU32 col_trans = col & ~IM_COL32_A_MASK;
594 const int idx_count = thick_line ? count*18 : count*12;
595 const int vtx_count = thick_line ? points_count*4 : points_count*3;
596 PrimReserve(idx_count, vtx_count);
599 ImVec2* temp_normals = (ImVec2*)alloca(points_count * (thick_line ? 5 : 3) * sizeof(ImVec2));
600 ImVec2* temp_points = temp_normals + points_count;
602 for (int i1 = 0; i1 < count; i1++)
604 const int i2 = (i1+1) == points_count ? 0 : i1+1;
605 ImVec2 diff = points[i2] - points[i1];
606 diff *= ImInvLength(diff, 1.0f);
607 temp_normals[i1].x = diff.y;
608 temp_normals[i1].y = -diff.x;
611 temp_normals[points_count-1] = temp_normals[points_count-2];
617 temp_points[0] = points[0] + temp_normals[0] * AA_SIZE;
618 temp_points[1] = points[0] - temp_normals[0] * AA_SIZE;
619 temp_points[(points_count-1)*2+0] = points[points_count-1] + temp_normals[points_count-1] * AA_SIZE;
620 temp_points[(points_count-1)*2+1] = points[points_count-1] - temp_normals[points_count-1] * AA_SIZE;
623 // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer.
624 unsigned int idx1 = _VtxCurrentIdx;
625 for (int i1 = 0; i1 < count; i1++)
627 const int i2 = (i1+1) == points_count ? 0 : i1+1;
628 unsigned int idx2 = (i1+1) == points_count ? _VtxCurrentIdx : idx1+3;
631 ImVec2 dm = (temp_normals[i1] + temp_normals[i2]) * 0.5f;
632 float dmr2 = dm.x*dm.x + dm.y*dm.y;
633 if (dmr2 > 0.000001f)
635 float scale = 1.0f / dmr2;
636 if (scale > 100.0f) scale = 100.0f;
640 temp_points[i2*2+0] = points[i2] + dm;
641 temp_points[i2*2+1] = points[i2] - dm;
644 _IdxWritePtr[0] = (ImDrawIdx)(idx2+0); _IdxWritePtr[1] = (ImDrawIdx)(idx1+0); _IdxWritePtr[2] = (ImDrawIdx)(idx1+2);
645 _IdxWritePtr[3] = (ImDrawIdx)(idx1+2); _IdxWritePtr[4] = (ImDrawIdx)(idx2+2); _IdxWritePtr[5] = (ImDrawIdx)(idx2+0);
646 _IdxWritePtr[6] = (ImDrawIdx)(idx2+1); _IdxWritePtr[7] = (ImDrawIdx)(idx1+1); _IdxWritePtr[8] = (ImDrawIdx)(idx1+0);
647 _IdxWritePtr[9] = (ImDrawIdx)(idx1+0); _IdxWritePtr[10]= (ImDrawIdx)(idx2+0); _IdxWritePtr[11]= (ImDrawIdx)(idx2+1);
654 for (int i = 0; i < points_count; i++)
656 _VtxWritePtr[0].pos = points[i]; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;
657 _VtxWritePtr[1].pos = temp_points[i*2+0]; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col_trans;
658 _VtxWritePtr[2].pos = temp_points[i*2+1]; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col_trans;
664 const float half_inner_thickness = (thickness - AA_SIZE) * 0.5f;
667 temp_points[0] = points[0] + temp_normals[0] * (half_inner_thickness + AA_SIZE);
668 temp_points[1] = points[0] + temp_normals[0] * (half_inner_thickness);
669 temp_points[2] = points[0] - temp_normals[0] * (half_inner_thickness);
670 temp_points[3] = points[0] - temp_normals[0] * (half_inner_thickness + AA_SIZE);
671 temp_points[(points_count-1)*4+0] = points[points_count-1] + temp_normals[points_count-1] * (half_inner_thickness + AA_SIZE);
672 temp_points[(points_count-1)*4+1] = points[points_count-1] + temp_normals[points_count-1] * (half_inner_thickness);
673 temp_points[(points_count-1)*4+2] = points[points_count-1] - temp_normals[points_count-1] * (half_inner_thickness);
674 temp_points[(points_count-1)*4+3] = points[points_count-1] - temp_normals[points_count-1] * (half_inner_thickness + AA_SIZE);
677 // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer.
678 unsigned int idx1 = _VtxCurrentIdx;
679 for (int i1 = 0; i1 < count; i1++)
681 const int i2 = (i1+1) == points_count ? 0 : i1+1;
682 unsigned int idx2 = (i1+1) == points_count ? _VtxCurrentIdx : idx1+4;
685 ImVec2 dm = (temp_normals[i1] + temp_normals[i2]) * 0.5f;
686 float dmr2 = dm.x*dm.x + dm.y*dm.y;
687 if (dmr2 > 0.000001f)
689 float scale = 1.0f / dmr2;
690 if (scale > 100.0f) scale = 100.0f;
693 ImVec2 dm_out = dm * (half_inner_thickness + AA_SIZE);
694 ImVec2 dm_in = dm * half_inner_thickness;
695 temp_points[i2*4+0] = points[i2] + dm_out;
696 temp_points[i2*4+1] = points[i2] + dm_in;
697 temp_points[i2*4+2] = points[i2] - dm_in;
698 temp_points[i2*4+3] = points[i2] - dm_out;
701 _IdxWritePtr[0] = (ImDrawIdx)(idx2+1); _IdxWritePtr[1] = (ImDrawIdx)(idx1+1); _IdxWritePtr[2] = (ImDrawIdx)(idx1+2);
702 _IdxWritePtr[3] = (ImDrawIdx)(idx1+2); _IdxWritePtr[4] = (ImDrawIdx)(idx2+2); _IdxWritePtr[5] = (ImDrawIdx)(idx2+1);
703 _IdxWritePtr[6] = (ImDrawIdx)(idx2+1); _IdxWritePtr[7] = (ImDrawIdx)(idx1+1); _IdxWritePtr[8] = (ImDrawIdx)(idx1+0);
704 _IdxWritePtr[9] = (ImDrawIdx)(idx1+0); _IdxWritePtr[10] = (ImDrawIdx)(idx2+0); _IdxWritePtr[11] = (ImDrawIdx)(idx2+1);
705 _IdxWritePtr[12] = (ImDrawIdx)(idx2+2); _IdxWritePtr[13] = (ImDrawIdx)(idx1+2); _IdxWritePtr[14] = (ImDrawIdx)(idx1+3);
706 _IdxWritePtr[15] = (ImDrawIdx)(idx1+3); _IdxWritePtr[16] = (ImDrawIdx)(idx2+3); _IdxWritePtr[17] = (ImDrawIdx)(idx2+2);
713 for (int i = 0; i < points_count; i++)
715 _VtxWritePtr[0].pos = temp_points[i*4+0]; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col_trans;
716 _VtxWritePtr[1].pos = temp_points[i*4+1]; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col;
717 _VtxWritePtr[2].pos = temp_points[i*4+2]; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col;
718 _VtxWritePtr[3].pos = temp_points[i*4+3]; _VtxWritePtr[3].uv = uv; _VtxWritePtr[3].col = col_trans;
722 _VtxCurrentIdx += (ImDrawIdx)vtx_count;
726 // Non Anti-aliased Stroke
727 const int idx_count = count*6;
728 const int vtx_count = count*4; // FIXME-OPT: Not sharing edges
729 PrimReserve(idx_count, vtx_count);
731 for (int i1 = 0; i1 < count; i1++)
733 const int i2 = (i1+1) == points_count ? 0 : i1+1;
734 const ImVec2& p1 = points[i1];
735 const ImVec2& p2 = points[i2];
736 ImVec2 diff = p2 - p1;
737 diff *= ImInvLength(diff, 1.0f);
739 const float dx = diff.x * (thickness * 0.5f);
740 const float dy = diff.y * (thickness * 0.5f);
741 _VtxWritePtr[0].pos.x = p1.x + dy; _VtxWritePtr[0].pos.y = p1.y - dx; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;
742 _VtxWritePtr[1].pos.x = p2.x + dy; _VtxWritePtr[1].pos.y = p2.y - dx; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col;
743 _VtxWritePtr[2].pos.x = p2.x - dy; _VtxWritePtr[2].pos.y = p2.y + dx; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col;
744 _VtxWritePtr[3].pos.x = p1.x - dy; _VtxWritePtr[3].pos.y = p1.y + dx; _VtxWritePtr[3].uv = uv; _VtxWritePtr[3].col = col;
747 _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx+1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx+2);
748 _IdxWritePtr[3] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[4] = (ImDrawIdx)(_VtxCurrentIdx+2); _IdxWritePtr[5] = (ImDrawIdx)(_VtxCurrentIdx+3);
755 void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_count, ImU32 col, bool anti_aliased)
757 const ImVec2 uv = GImGui->FontTexUvWhitePixel;
758 anti_aliased &= GImGui->Style.AntiAliasedShapes;
759 //if (ImGui::GetIO().KeyCtrl) anti_aliased = false; // Debug
764 const float AA_SIZE = 1.0f;
765 const ImU32 col_trans = col & ~IM_COL32_A_MASK;
766 const int idx_count = (points_count-2)*3 + points_count*6;
767 const int vtx_count = (points_count*2);
768 PrimReserve(idx_count, vtx_count);
770 // Add indexes for fill
771 unsigned int vtx_inner_idx = _VtxCurrentIdx;
772 unsigned int vtx_outer_idx = _VtxCurrentIdx+1;
773 for (int i = 2; i < points_count; i++)
775 _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx+((i-1)<<1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_inner_idx+(i<<1));
780 ImVec2* temp_normals = (ImVec2*)alloca(points_count * sizeof(ImVec2));
781 for (int i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++)
783 const ImVec2& p0 = points[i0];
784 const ImVec2& p1 = points[i1];
785 ImVec2 diff = p1 - p0;
786 diff *= ImInvLength(diff, 1.0f);
787 temp_normals[i0].x = diff.y;
788 temp_normals[i0].y = -diff.x;
791 for (int i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++)
794 const ImVec2& n0 = temp_normals[i0];
795 const ImVec2& n1 = temp_normals[i1];
796 ImVec2 dm = (n0 + n1) * 0.5f;
797 float dmr2 = dm.x*dm.x + dm.y*dm.y;
798 if (dmr2 > 0.000001f)
800 float scale = 1.0f / dmr2;
801 if (scale > 100.0f) scale = 100.0f;
804 dm *= AA_SIZE * 0.5f;
807 _VtxWritePtr[0].pos = (points[i1] - dm); _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; // Inner
808 _VtxWritePtr[1].pos = (points[i1] + dm); _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col_trans; // Outer
811 // Add indexes for fringes
812 _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx+(i1<<1)); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx+(i0<<1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_outer_idx+(i0<<1));
813 _IdxWritePtr[3] = (ImDrawIdx)(vtx_outer_idx+(i0<<1)); _IdxWritePtr[4] = (ImDrawIdx)(vtx_outer_idx+(i1<<1)); _IdxWritePtr[5] = (ImDrawIdx)(vtx_inner_idx+(i1<<1));
816 _VtxCurrentIdx += (ImDrawIdx)vtx_count;
820 // Non Anti-aliased Fill
821 const int idx_count = (points_count-2)*3;
822 const int vtx_count = points_count;
823 PrimReserve(idx_count, vtx_count);
824 for (int i = 0; i < vtx_count; i++)
826 _VtxWritePtr[0].pos = points[i]; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;
829 for (int i = 2; i < points_count; i++)
831 _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx+i-1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx+i);
834 _VtxCurrentIdx += (ImDrawIdx)vtx_count;
838 void ImDrawList::PathArcToFast(const ImVec2& centre, float radius, int a_min_of_12, int a_max_of_12)
840 static ImVec2 circle_vtx[12];
841 static bool circle_vtx_builds = false;
842 const int circle_vtx_count = IM_ARRAYSIZE(circle_vtx);
843 if (!circle_vtx_builds)
845 for (int i = 0; i < circle_vtx_count; i++)
847 const float a = ((float)i / (float)circle_vtx_count) * 2*IM_PI;
848 circle_vtx[i].x = cosf(a);
849 circle_vtx[i].y = sinf(a);
851 circle_vtx_builds = true;
854 if (radius == 0.0f || a_min_of_12 > a_max_of_12)
856 _Path.push_back(centre);
859 _Path.reserve(_Path.Size + (a_max_of_12 - a_min_of_12 + 1));
860 for (int a = a_min_of_12; a <= a_max_of_12; a++)
862 const ImVec2& c = circle_vtx[a % circle_vtx_count];
863 _Path.push_back(ImVec2(centre.x + c.x * radius, centre.y + c.y * radius));
867 void ImDrawList::PathArcTo(const ImVec2& centre, float radius, float a_min, float a_max, int num_segments)
871 _Path.push_back(centre);
874 _Path.reserve(_Path.Size + (num_segments + 1));
875 for (int i = 0; i <= num_segments; i++)
877 const float a = a_min + ((float)i / (float)num_segments) * (a_max - a_min);
878 _Path.push_back(ImVec2(centre.x + cosf(a) * radius, centre.y + sinf(a) * radius));
882 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)
886 float d2 = ((x2 - x4) * dy - (y2 - y4) * dx);
887 float d3 = ((x3 - x4) * dy - (y3 - y4) * dx);
888 d2 = (d2 >= 0) ? d2 : -d2;
889 d3 = (d3 >= 0) ? d3 : -d3;
890 if ((d2+d3) * (d2+d3) < tess_tol * (dx*dx + dy*dy))
892 path->push_back(ImVec2(x4, y4));
896 float x12 = (x1+x2)*0.5f, y12 = (y1+y2)*0.5f;
897 float x23 = (x2+x3)*0.5f, y23 = (y2+y3)*0.5f;
898 float x34 = (x3+x4)*0.5f, y34 = (y3+y4)*0.5f;
899 float x123 = (x12+x23)*0.5f, y123 = (y12+y23)*0.5f;
900 float x234 = (x23+x34)*0.5f, y234 = (y23+y34)*0.5f;
901 float x1234 = (x123+x234)*0.5f, y1234 = (y123+y234)*0.5f;
903 PathBezierToCasteljau(path, x1,y1, x12,y12, x123,y123, x1234,y1234, tess_tol, level+1);
904 PathBezierToCasteljau(path, x1234,y1234, x234,y234, x34,y34, x4,y4, tess_tol, level+1);
908 void ImDrawList::PathBezierCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments)
910 ImVec2 p1 = _Path.back();
911 if (num_segments == 0)
914 PathBezierToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, GImGui->Style.CurveTessellationTol, 0);
918 float t_step = 1.0f / (float)num_segments;
919 for (int i_step = 1; i_step <= num_segments; i_step++)
921 float t = t_step * i_step;
927 _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));
932 void ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, int rounding_corners)
934 rounding = ImMin(rounding, fabsf(b.x - a.x) * ( ((rounding_corners & ImDrawCornerFlags_Top) == ImDrawCornerFlags_Top) || ((rounding_corners & ImDrawCornerFlags_Bot) == ImDrawCornerFlags_Bot) ? 0.5f : 1.0f ) - 1.0f);
935 rounding = ImMin(rounding, fabsf(b.y - a.y) * ( ((rounding_corners & ImDrawCornerFlags_Left) == ImDrawCornerFlags_Left) || ((rounding_corners & ImDrawCornerFlags_Right) == ImDrawCornerFlags_Right) ? 0.5f : 1.0f ) - 1.0f);
937 if (rounding <= 0.0f || rounding_corners == 0)
940 PathLineTo(ImVec2(b.x, a.y));
942 PathLineTo(ImVec2(a.x, b.y));
946 const float rounding_tl = (rounding_corners & ImDrawCornerFlags_TopLeft) ? rounding : 0.0f;
947 const float rounding_tr = (rounding_corners & ImDrawCornerFlags_TopRight) ? rounding : 0.0f;
948 const float rounding_br = (rounding_corners & ImDrawCornerFlags_BotRight) ? rounding : 0.0f;
949 const float rounding_bl = (rounding_corners & ImDrawCornerFlags_BotLeft) ? rounding : 0.0f;
950 PathArcToFast(ImVec2(a.x + rounding_tl, a.y + rounding_tl), rounding_tl, 6, 9);
951 PathArcToFast(ImVec2(b.x - rounding_tr, a.y + rounding_tr), rounding_tr, 9, 12);
952 PathArcToFast(ImVec2(b.x - rounding_br, b.y - rounding_br), rounding_br, 0, 3);
953 PathArcToFast(ImVec2(a.x + rounding_bl, b.y - rounding_bl), rounding_bl, 3, 6);
957 void ImDrawList::AddLine(const ImVec2& a, const ImVec2& b, ImU32 col, float thickness)
959 if ((col & IM_COL32_A_MASK) == 0)
961 PathLineTo(a + ImVec2(0.5f,0.5f));
962 PathLineTo(b + ImVec2(0.5f,0.5f));
963 PathStroke(col, false, thickness);
966 // a: upper-left, b: lower-right. we don't render 1 px sized rectangles properly.
967 void ImDrawList::AddRect(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding, int rounding_corners_flags, float thickness)
969 if ((col & IM_COL32_A_MASK) == 0)
971 PathRect(a + ImVec2(0.5f,0.5f), b - ImVec2(0.5f,0.5f), rounding, rounding_corners_flags);
972 PathStroke(col, true, thickness);
975 void ImDrawList::AddRectFilled(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding, int rounding_corners_flags)
977 if ((col & IM_COL32_A_MASK) == 0)
981 PathRect(a, b, rounding, rounding_corners_flags);
991 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)
993 if (((col_upr_left | col_upr_right | col_bot_right | col_bot_left) & IM_COL32_A_MASK) == 0)
996 const ImVec2 uv = GImGui->FontTexUvWhitePixel;
998 PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx+1)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx+2));
999 PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx+2)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx+3));
1000 PrimWriteVtx(a, uv, col_upr_left);
1001 PrimWriteVtx(ImVec2(c.x, a.y), uv, col_upr_right);
1002 PrimWriteVtx(c, uv, col_bot_right);
1003 PrimWriteVtx(ImVec2(a.x, c.y), uv, col_bot_left);
1006 void ImDrawList::AddQuad(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, ImU32 col, float thickness)
1008 if ((col & IM_COL32_A_MASK) == 0)
1015 PathStroke(col, true, thickness);
1018 void ImDrawList::AddQuadFilled(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, ImU32 col)
1020 if ((col & IM_COL32_A_MASK) == 0)
1027 PathFillConvex(col);
1030 void ImDrawList::AddTriangle(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col, float thickness)
1032 if ((col & IM_COL32_A_MASK) == 0)
1038 PathStroke(col, true, thickness);
1041 void ImDrawList::AddTriangleFilled(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col)
1043 if ((col & IM_COL32_A_MASK) == 0)
1049 PathFillConvex(col);
1052 void ImDrawList::AddCircle(const ImVec2& centre, float radius, ImU32 col, int num_segments, float thickness)
1054 if ((col & IM_COL32_A_MASK) == 0)
1057 const float a_max = IM_PI*2.0f * ((float)num_segments - 1.0f) / (float)num_segments;
1058 PathArcTo(centre, radius-0.5f, 0.0f, a_max, num_segments);
1059 PathStroke(col, true, thickness);
1062 void ImDrawList::AddCircleFilled(const ImVec2& centre, float radius, ImU32 col, int num_segments)
1064 if ((col & IM_COL32_A_MASK) == 0)
1067 const float a_max = IM_PI*2.0f * ((float)num_segments - 1.0f) / (float)num_segments;
1068 PathArcTo(centre, radius, 0.0f, a_max, num_segments);
1069 PathFillConvex(col);
1072 void ImDrawList::AddBezierCurve(const ImVec2& pos0, const ImVec2& cp0, const ImVec2& cp1, const ImVec2& pos1, ImU32 col, float thickness, int num_segments)
1074 if ((col & IM_COL32_A_MASK) == 0)
1078 PathBezierCurveTo(cp0, cp1, pos1, num_segments);
1079 PathStroke(col, false, thickness);
1082 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)
1084 if ((col & IM_COL32_A_MASK) == 0)
1087 if (text_end == NULL)
1088 text_end = text_begin + strlen(text_begin);
1089 if (text_begin == text_end)
1092 // 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.
1093 // Might just move Font/FontSize to ImDrawList?
1095 font = GImGui->Font;
1096 if (font_size == 0.0f)
1097 font_size = GImGui->FontSize;
1099 IM_ASSERT(font->ContainerAtlas->TexID == _TextureIdStack.back()); // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font.
1101 ImVec4 clip_rect = _ClipRectStack.back();
1102 if (cpu_fine_clip_rect)
1104 clip_rect.x = ImMax(clip_rect.x, cpu_fine_clip_rect->x);
1105 clip_rect.y = ImMax(clip_rect.y, cpu_fine_clip_rect->y);
1106 clip_rect.z = ImMin(clip_rect.z, cpu_fine_clip_rect->z);
1107 clip_rect.w = ImMin(clip_rect.w, cpu_fine_clip_rect->w);
1109 font->RenderText(this, font_size, pos, col, clip_rect, text_begin, text_end, wrap_width, cpu_fine_clip_rect != NULL);
1112 void ImDrawList::AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end)
1114 AddText(NULL, 0.0f, pos, col, text_begin, text_end);
1117 void ImDrawList::AddImage(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col)
1119 if ((col & IM_COL32_A_MASK) == 0)
1122 const bool push_texture_id = _TextureIdStack.empty() || user_texture_id != _TextureIdStack.back();
1123 if (push_texture_id)
1124 PushTextureID(user_texture_id);
1127 PrimRectUV(a, b, uv_a, uv_b, col);
1129 if (push_texture_id)
1133 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)
1135 if ((col & IM_COL32_A_MASK) == 0)
1138 const bool push_texture_id = _TextureIdStack.empty() || user_texture_id != _TextureIdStack.back();
1139 if (push_texture_id)
1140 PushTextureID(user_texture_id);
1143 PrimQuadUV(a, b, c, d, uv_a, uv_b, uv_c, uv_d, col);
1145 if (push_texture_id)
1149 void ImDrawList::AddImageRounded(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col, float rounding, int rounding_corners)
1151 if ((col & IM_COL32_A_MASK) == 0)
1154 if (rounding <= 0.0f || (rounding_corners & ImDrawCornerFlags_All) == 0)
1156 AddImage(user_texture_id, a, b, uv_a, uv_b, col);
1160 const bool push_texture_id = _TextureIdStack.empty() || user_texture_id != _TextureIdStack.back();
1161 if (push_texture_id)
1162 PushTextureID(user_texture_id);
1164 int vert_start_idx = VtxBuffer.Size;
1165 PathRect(a, b, rounding, rounding_corners);
1166 PathFillConvex(col);
1167 int vert_end_idx = VtxBuffer.Size;
1168 ImGui::ShadeVertsLinearUV(VtxBuffer.Data + vert_start_idx, VtxBuffer.Data + vert_end_idx, a, b, uv_a, uv_b, true);
1170 if (push_texture_id)
1174 //-----------------------------------------------------------------------------
1176 //-----------------------------------------------------------------------------
1178 // 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!
1179 void ImDrawData::DeIndexAllBuffers()
1181 ImVector<ImDrawVert> new_vtx_buffer;
1182 TotalVtxCount = TotalIdxCount = 0;
1183 for (int i = 0; i < CmdListsCount; i++)
1185 ImDrawList* cmd_list = CmdLists[i];
1186 if (cmd_list->IdxBuffer.empty())
1188 new_vtx_buffer.resize(cmd_list->IdxBuffer.Size);
1189 for (int j = 0; j < cmd_list->IdxBuffer.Size; j++)
1190 new_vtx_buffer[j] = cmd_list->VtxBuffer[cmd_list->IdxBuffer[j]];
1191 cmd_list->VtxBuffer.swap(new_vtx_buffer);
1192 cmd_list->IdxBuffer.resize(0);
1193 TotalVtxCount += cmd_list->VtxBuffer.Size;
1197 // 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.
1198 void ImDrawData::ScaleClipRects(const ImVec2& scale)
1200 for (int i = 0; i < CmdListsCount; i++)
1202 ImDrawList* cmd_list = CmdLists[i];
1203 for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
1205 ImDrawCmd* cmd = &cmd_list->CmdBuffer[cmd_i];
1206 cmd->ClipRect = ImVec4(cmd->ClipRect.x * scale.x, cmd->ClipRect.y * scale.y, cmd->ClipRect.z * scale.x, cmd->ClipRect.w * scale.y);
1211 //-----------------------------------------------------------------------------
1213 //-----------------------------------------------------------------------------
1215 // Generic linear color gradient, write to RGB fields, leave A untouched.
1216 void ImGui::ShadeVertsLinearColorGradientKeepAlpha(ImDrawVert* vert_start, ImDrawVert* vert_end, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1)
1218 ImVec2 gradient_extent = gradient_p1 - gradient_p0;
1219 float gradient_inv_length2 = 1.0f / ImLengthSqr(gradient_extent);
1220 for (ImDrawVert* vert = vert_start; vert < vert_end; vert++)
1222 float d = ImDot(vert->pos - gradient_p0, gradient_extent);
1223 float t = ImClamp(d * gradient_inv_length2, 0.0f, 1.0f);
1224 int r = ImLerp((int)(col0 >> IM_COL32_R_SHIFT) & 0xFF, (int)(col1 >> IM_COL32_R_SHIFT) & 0xFF, t);
1225 int g = ImLerp((int)(col0 >> IM_COL32_G_SHIFT) & 0xFF, (int)(col1 >> IM_COL32_G_SHIFT) & 0xFF, t);
1226 int b = ImLerp((int)(col0 >> IM_COL32_B_SHIFT) & 0xFF, (int)(col1 >> IM_COL32_B_SHIFT) & 0xFF, t);
1227 vert->col = (r << IM_COL32_R_SHIFT) | (g << IM_COL32_G_SHIFT) | (b << IM_COL32_B_SHIFT) | (vert->col & IM_COL32_A_MASK);
1231 // Scan and shade backward from the end of given vertices. Assume vertices are text only (= vert_start..vert_end going left to right) so we can break as soon as we are out the gradient bounds.
1232 void ImGui::ShadeVertsLinearAlphaGradientForLeftToRightText(ImDrawVert* vert_start, ImDrawVert* vert_end, float gradient_p0_x, float gradient_p1_x)
1234 float gradient_extent_x = gradient_p1_x - gradient_p0_x;
1235 float gradient_inv_length2 = 1.0f / (gradient_extent_x * gradient_extent_x);
1236 int full_alpha_count = 0;
1237 for (ImDrawVert* vert = vert_end - 1; vert >= vert_start; vert--)
1239 float d = (vert->pos.x - gradient_p0_x) * (gradient_extent_x);
1240 float alpha_mul = 1.0f - ImClamp(d * gradient_inv_length2, 0.0f, 1.0f);
1241 if (alpha_mul >= 1.0f && ++full_alpha_count > 2)
1242 return; // Early out
1243 int a = (int)(((vert->col >> IM_COL32_A_SHIFT) & 0xFF) * alpha_mul);
1244 vert->col = (vert->col & ~IM_COL32_A_MASK) | (a << IM_COL32_A_SHIFT);
1248 // Distribute UV over (a, b) rectangle
1249 void ImGui::ShadeVertsLinearUV(ImDrawVert* vert_start, ImDrawVert* vert_end, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, bool clamp)
1251 const ImVec2 size = b - a;
1252 const ImVec2 uv_size = uv_b - uv_a;
1253 const ImVec2 scale = ImVec2(
1254 size.x ? (uv_size.x / size.x) : 0.0f,
1255 size.y ? (uv_size.y / size.y) : 0.0f);
1259 const ImVec2 min = ImMin(uv_a, uv_b);
1260 const ImVec2 max = ImMax(uv_a, uv_b);
1262 for (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex)
1263 vertex->uv = ImClamp(uv_a + ImMul(ImVec2(vertex->pos.x, vertex->pos.y) - a, scale), min, max);
1267 for (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex)
1268 vertex->uv = uv_a + ImMul(ImVec2(vertex->pos.x, vertex->pos.y) - a, scale);
1272 //-----------------------------------------------------------------------------
1274 //-----------------------------------------------------------------------------
1276 ImFontConfig::ImFontConfig()
1280 FontDataOwnedByAtlas = true;
1286 GlyphExtraSpacing = ImVec2(0.0f, 0.0f);
1287 GlyphOffset = ImVec2(0.0f, 0.0f);
1290 RasterizerFlags = 0x00;
1291 RasterizerMultiply = 1.0f;
1292 memset(Name, 0, sizeof(Name));
1296 //-----------------------------------------------------------------------------
1298 //-----------------------------------------------------------------------------
1300 // A work of art lies ahead! (. = white layer, X = black layer, others are blank)
1301 // The white texels on the top left are the ones we'll use everywhere in ImGui to render filled shapes.
1302 const int FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF = 90;
1303 const int FONT_ATLAS_DEFAULT_TEX_DATA_H = 27;
1304 const unsigned int FONT_ATLAS_DEFAULT_TEX_DATA_ID = 0x80000000;
1305 static const char FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF * FONT_ATLAS_DEFAULT_TEX_DATA_H + 1] =
1307 "..- -XXXXXXX- X - X -XXXXXXX - XXXXXXX"
1308 "..- -X.....X- X.X - X.X -X.....X - X.....X"
1309 "--- -XXX.XXX- X...X - X...X -X....X - X....X"
1310 "X - X.X - X.....X - X.....X -X...X - X...X"
1311 "XX - X.X -X.......X- X.......X -X..X.X - X.X..X"
1312 "X.X - X.X -XXXX.XXXX- XXXX.XXXX -X.X X.X - X.X X.X"
1313 "X..X - X.X - X.X - X.X -XX X.X - X.X XX"
1314 "X...X - X.X - X.X - XX X.X XX - X.X - X.X "
1315 "X....X - X.X - X.X - X.X X.X X.X - X.X - X.X "
1316 "X.....X - X.X - X.X - X..X X.X X..X - X.X - X.X "
1317 "X......X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X XX-XX X.X "
1318 "X.......X - X.X - X.X -X.....................X- X.X X.X-X.X X.X "
1319 "X........X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X..X-X..X.X "
1320 "X.........X -XXX.XXX- X.X - X..X X.X X..X - X...X-X...X "
1321 "X..........X-X.....X- X.X - X.X X.X X.X - X....X-X....X "
1322 "X......XXXXX-XXXXXXX- X.X - XX X.X XX - X.....X-X.....X "
1323 "X...X..X --------- X.X - X.X - XXXXXXX-XXXXXXX "
1324 "X..X X..X - -XXXX.XXXX- XXXX.XXXX ------------------------------------"
1325 "X.X X..X - -X.......X- X.......X - XX XX - "
1326 "XX X..X - - X.....X - X.....X - X.X X.X - "
1327 " X..X - X...X - X...X - X..X X..X - "
1328 " XX - X.X - X.X - X...XXXXXXXXXXXXX...X - "
1329 "------------ - X - X -X.....................X- "
1330 " ----------------------------------- X...XXXXXXXXXXXXX...X - "
1336 static const ImVec2 FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[ImGuiMouseCursor_Count_][3] =
1338 // Pos ........ Size ......... Offset ......
1339 { ImVec2(0,3), ImVec2(12,19), ImVec2( 0, 0) }, // ImGuiMouseCursor_Arrow
1340 { ImVec2(13,0), ImVec2(7,16), ImVec2( 4, 8) }, // ImGuiMouseCursor_TextInput
1341 { ImVec2(31,0), ImVec2(23,23), ImVec2(11,11) }, // ImGuiMouseCursor_Move
1342 { ImVec2(21,0), ImVec2( 9,23), ImVec2( 5,11) }, // ImGuiMouseCursor_ResizeNS
1343 { ImVec2(55,18),ImVec2(23, 9), ImVec2(11, 5) }, // ImGuiMouseCursor_ResizeEW
1344 { ImVec2(73,0), ImVec2(17,17), ImVec2( 9, 9) }, // ImGuiMouseCursor_ResizeNESW
1345 { ImVec2(55,0), ImVec2(17,17), ImVec2( 9, 9) }, // ImGuiMouseCursor_ResizeNWSE
1349 ImFontAtlas::ImFontAtlas()
1352 TexDesiredWidth = 0;
1353 TexGlyphPadding = 1;
1354 TexPixelsAlpha8 = NULL;
1355 TexPixelsRGBA32 = NULL;
1356 TexWidth = TexHeight = 0;
1357 TexUvWhitePixel = ImVec2(0, 0);
1358 for (int n = 0; n < IM_ARRAYSIZE(CustomRectIds); n++)
1359 CustomRectIds[n] = -1;
1362 ImFontAtlas::~ImFontAtlas()
1367 void ImFontAtlas::ClearInputData()
1369 for (int i = 0; i < ConfigData.Size; i++)
1370 if (ConfigData[i].FontData && ConfigData[i].FontDataOwnedByAtlas)
1372 ImGui::MemFree(ConfigData[i].FontData);
1373 ConfigData[i].FontData = NULL;
1376 // When clearing this we lose access to the font name and other information used to build the font.
1377 for (int i = 0; i < Fonts.Size; i++)
1378 if (Fonts[i]->ConfigData >= ConfigData.Data && Fonts[i]->ConfigData < ConfigData.Data + ConfigData.Size)
1380 Fonts[i]->ConfigData = NULL;
1381 Fonts[i]->ConfigDataCount = 0;
1384 CustomRects.clear();
1385 for (int n = 0; n < IM_ARRAYSIZE(CustomRectIds); n++)
1386 CustomRectIds[n] = -1;
1389 void ImFontAtlas::ClearTexData()
1391 if (TexPixelsAlpha8)
1392 ImGui::MemFree(TexPixelsAlpha8);
1393 if (TexPixelsRGBA32)
1394 ImGui::MemFree(TexPixelsRGBA32);
1395 TexPixelsAlpha8 = NULL;
1396 TexPixelsRGBA32 = NULL;
1399 void ImFontAtlas::ClearFonts()
1401 for (int i = 0; i < Fonts.Size; i++)
1403 Fonts[i]->~ImFont();
1404 ImGui::MemFree(Fonts[i]);
1409 void ImFontAtlas::Clear()
1416 void ImFontAtlas::GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel)
1418 // Build atlas on demand
1419 if (TexPixelsAlpha8 == NULL)
1421 if (ConfigData.empty())
1426 *out_pixels = TexPixelsAlpha8;
1427 if (out_width) *out_width = TexWidth;
1428 if (out_height) *out_height = TexHeight;
1429 if (out_bytes_per_pixel) *out_bytes_per_pixel = 1;
1432 void ImFontAtlas::GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel)
1434 // Convert to RGBA32 format on demand
1435 // Although it is likely to be the most commonly used format, our font rendering is 1 channel / 8 bpp
1436 if (!TexPixelsRGBA32)
1438 unsigned char* pixels;
1439 GetTexDataAsAlpha8(&pixels, NULL, NULL);
1440 TexPixelsRGBA32 = (unsigned int*)ImGui::MemAlloc((size_t)(TexWidth * TexHeight * 4));
1441 const unsigned char* src = pixels;
1442 unsigned int* dst = TexPixelsRGBA32;
1443 for (int n = TexWidth * TexHeight; n > 0; n--)
1444 *dst++ = IM_COL32(255, 255, 255, (unsigned int)(*src++));
1447 *out_pixels = (unsigned char*)TexPixelsRGBA32;
1448 if (out_width) *out_width = TexWidth;
1449 if (out_height) *out_height = TexHeight;
1450 if (out_bytes_per_pixel) *out_bytes_per_pixel = 4;
1453 ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg)
1455 IM_ASSERT(font_cfg->FontData != NULL && font_cfg->FontDataSize > 0);
1456 IM_ASSERT(font_cfg->SizePixels > 0.0f);
1459 if (!font_cfg->MergeMode)
1461 ImFont* font = (ImFont*)ImGui::MemAlloc(sizeof(ImFont));
1462 IM_PLACEMENT_NEW(font) ImFont();
1463 Fonts.push_back(font);
1467 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.
1470 ConfigData.push_back(*font_cfg);
1471 ImFontConfig& new_font_cfg = ConfigData.back();
1472 if (!new_font_cfg.DstFont)
1473 new_font_cfg.DstFont = Fonts.back();
1474 if (!new_font_cfg.FontDataOwnedByAtlas)
1476 new_font_cfg.FontData = ImGui::MemAlloc(new_font_cfg.FontDataSize);
1477 new_font_cfg.FontDataOwnedByAtlas = true;
1478 memcpy(new_font_cfg.FontData, font_cfg->FontData, (size_t)new_font_cfg.FontDataSize);
1481 // Invalidate texture
1483 return new_font_cfg.DstFont;
1486 // Default font TTF is compressed with stb_compress then base85 encoded (see extra_fonts/binary_to_compressed_c.cpp for encoder)
1487 static unsigned int stb_decompress_length(unsigned char *input);
1488 static unsigned int stb_decompress(unsigned char *output, unsigned char *i, unsigned int length);
1489 static const char* GetDefaultCompressedFontDataTTFBase85();
1490 static unsigned int Decode85Byte(char c) { return c >= '\\' ? c-36 : c-35; }
1491 static void Decode85(const unsigned char* src, unsigned char* dst)
1495 unsigned int tmp = Decode85Byte(src[0]) + 85*(Decode85Byte(src[1]) + 85*(Decode85Byte(src[2]) + 85*(Decode85Byte(src[3]) + 85*Decode85Byte(src[4]))));
1496 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.
1502 // Load embedded ProggyClean.ttf at size 13, disable oversampling
1503 ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template)
1505 ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
1506 if (!font_cfg_template)
1508 font_cfg.OversampleH = font_cfg.OversampleV = 1;
1509 font_cfg.PixelSnapH = true;
1511 if (font_cfg.Name[0] == '\0') strcpy(font_cfg.Name, "ProggyClean.ttf, 13px");
1512 if (font_cfg.SizePixels <= 0.0f) font_cfg.SizePixels = 13.0f;
1514 const char* ttf_compressed_base85 = GetDefaultCompressedFontDataTTFBase85();
1515 ImFont* font = AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, font_cfg.SizePixels, &font_cfg, GetGlyphRangesDefault());
1519 ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)
1522 void* data = ImFileLoadToMemory(filename, "rb", &data_size, 0);
1525 IM_ASSERT(0); // Could not load file.
1528 ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
1529 if (font_cfg.Name[0] == '\0')
1531 // Store a short copy of filename into into the font name for convenience
1533 for (p = filename + strlen(filename); p > filename && p[-1] != '/' && p[-1] != '\\'; p--) {}
1534 snprintf(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "%s, %.0fpx", p, size_pixels);
1536 return AddFontFromMemoryTTF(data, data_size, size_pixels, &font_cfg, glyph_ranges);
1539 // NB: Transfer ownership of 'ttf_data' to ImFontAtlas, unless font_cfg_template->FontDataOwnedByAtlas == false. Owned TTF buffer will be deleted after Build().
1540 ImFont* ImFontAtlas::AddFontFromMemoryTTF(void* ttf_data, int ttf_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)
1542 ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
1543 IM_ASSERT(font_cfg.FontData == NULL);
1544 font_cfg.FontData = ttf_data;
1545 font_cfg.FontDataSize = ttf_size;
1546 font_cfg.SizePixels = size_pixels;
1548 font_cfg.GlyphRanges = glyph_ranges;
1549 return AddFont(&font_cfg);
1552 ImFont* ImFontAtlas::AddFontFromMemoryCompressedTTF(const void* compressed_ttf_data, int compressed_ttf_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)
1554 const unsigned int buf_decompressed_size = stb_decompress_length((unsigned char*)compressed_ttf_data);
1555 unsigned char* buf_decompressed_data = (unsigned char *)ImGui::MemAlloc(buf_decompressed_size);
1556 stb_decompress(buf_decompressed_data, (unsigned char*)compressed_ttf_data, (unsigned int)compressed_ttf_size);
1558 ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
1559 IM_ASSERT(font_cfg.FontData == NULL);
1560 font_cfg.FontDataOwnedByAtlas = true;
1561 return AddFontFromMemoryTTF(buf_decompressed_data, (int)buf_decompressed_size, size_pixels, &font_cfg, glyph_ranges);
1564 ImFont* ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(const char* compressed_ttf_data_base85, float size_pixels, const ImFontConfig* font_cfg, const ImWchar* glyph_ranges)
1566 int compressed_ttf_size = (((int)strlen(compressed_ttf_data_base85) + 4) / 5) * 4;
1567 void* compressed_ttf = ImGui::MemAlloc((size_t)compressed_ttf_size);
1568 Decode85((const unsigned char*)compressed_ttf_data_base85, (unsigned char*)compressed_ttf);
1569 ImFont* font = AddFontFromMemoryCompressedTTF(compressed_ttf, compressed_ttf_size, size_pixels, font_cfg, glyph_ranges);
1570 ImGui::MemFree(compressed_ttf);
1574 int ImFontAtlas::AddCustomRectRegular(unsigned int id, int width, int height)
1576 IM_ASSERT(id >= 0x10000);
1577 IM_ASSERT(width > 0 && width <= 0xFFFF);
1578 IM_ASSERT(height > 0 && height <= 0xFFFF);
1581 r.Width = (unsigned short)width;
1582 r.Height = (unsigned short)height;
1583 CustomRects.push_back(r);
1584 return CustomRects.Size - 1; // Return index
1587 int ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset)
1589 IM_ASSERT(font != NULL);
1590 IM_ASSERT(width > 0 && width <= 0xFFFF);
1591 IM_ASSERT(height > 0 && height <= 0xFFFF);
1594 r.Width = (unsigned short)width;
1595 r.Height = (unsigned short)height;
1596 r.GlyphAdvanceX = advance_x;
1597 r.GlyphOffset = offset;
1599 CustomRects.push_back(r);
1600 return CustomRects.Size - 1; // Return index
1603 void ImFontAtlas::CalcCustomRectUV(const CustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max)
1605 IM_ASSERT(TexWidth > 0 && TexHeight > 0); // Font atlas needs to be built before we can calculate UV coordinates
1606 IM_ASSERT(rect->IsPacked()); // Make sure the rectangle has been packed
1607 *out_uv_min = ImVec2((float)rect->X / TexWidth, (float)rect->Y / TexHeight);
1608 *out_uv_max = ImVec2((float)(rect->X + rect->Width) / TexWidth, (float)(rect->Y + rect->Height) / TexHeight);
1611 bool ImFontAtlas::Build()
1613 return ImFontAtlasBuildWithStbTruetype(this);
1616 void ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_brighten_factor)
1618 for (unsigned int i = 0; i < 256; i++)
1620 unsigned int value = (unsigned int)(i * in_brighten_factor);
1621 out_table[i] = value > 255 ? 255 : (value & 0xFF);
1625 void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride)
1627 unsigned char* data = pixels + x + y * stride;
1628 for (int j = h; j > 0; j--, data += stride)
1629 for (int i = 0; i < w; i++)
1630 data[i] = table[data[i]];
1633 bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
1635 IM_ASSERT(atlas->ConfigData.Size > 0);
1637 ImFontAtlasBuildRegisterDefaultCustomRects(atlas);
1639 atlas->TexID = NULL;
1640 atlas->TexWidth = atlas->TexHeight = 0;
1641 atlas->TexUvWhitePixel = ImVec2(0, 0);
1642 atlas->ClearTexData();
1644 // Count glyphs/ranges
1645 int total_glyphs_count = 0;
1646 int total_ranges_count = 0;
1647 for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
1649 ImFontConfig& cfg = atlas->ConfigData[input_i];
1650 if (!cfg.GlyphRanges)
1651 cfg.GlyphRanges = atlas->GetGlyphRangesDefault();
1652 for (const ImWchar* in_range = cfg.GlyphRanges; in_range[0] && in_range[1]; in_range += 2, total_ranges_count++)
1653 total_glyphs_count += (in_range[1] - in_range[0]) + 1;
1656 // 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.
1657 // Width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height.
1658 atlas->TexWidth = (atlas->TexDesiredWidth > 0) ? atlas->TexDesiredWidth : (total_glyphs_count > 4000) ? 4096 : (total_glyphs_count > 2000) ? 2048 : (total_glyphs_count > 1000) ? 1024 : 512;
1659 atlas->TexHeight = 0;
1662 const int max_tex_height = 1024*32;
1663 stbtt_pack_context spc = {};
1664 stbtt_PackBegin(&spc, NULL, atlas->TexWidth, max_tex_height, 0, atlas->TexGlyphPadding, NULL);
1665 stbtt_PackSetOversampling(&spc, 1, 1);
1667 // Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values).
1668 ImFontAtlasBuildPackCustomRects(atlas, spc.pack_info);
1670 // Initialize font information (so we can error without any cleanup)
1671 struct ImFontTempBuildData
1673 stbtt_fontinfo FontInfo;
1676 stbtt_pack_range* Ranges;
1679 ImFontTempBuildData* tmp_array = (ImFontTempBuildData*)ImGui::MemAlloc((size_t)atlas->ConfigData.Size * sizeof(ImFontTempBuildData));
1680 for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
1682 ImFontConfig& cfg = atlas->ConfigData[input_i];
1683 ImFontTempBuildData& tmp = tmp_array[input_i];
1684 IM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas));
1686 const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)cfg.FontData, cfg.FontNo);
1687 IM_ASSERT(font_offset >= 0);
1688 if (!stbtt_InitFont(&tmp.FontInfo, (unsigned char*)cfg.FontData, font_offset))
1690 ImGui::MemFree(tmp_array);
1695 // Allocate packing character data and flag packed characters buffer as non-packed (x0=y0=x1=y1=0)
1696 int buf_packedchars_n = 0, buf_rects_n = 0, buf_ranges_n = 0;
1697 stbtt_packedchar* buf_packedchars = (stbtt_packedchar*)ImGui::MemAlloc(total_glyphs_count * sizeof(stbtt_packedchar));
1698 stbrp_rect* buf_rects = (stbrp_rect*)ImGui::MemAlloc(total_glyphs_count * sizeof(stbrp_rect));
1699 stbtt_pack_range* buf_ranges = (stbtt_pack_range*)ImGui::MemAlloc(total_ranges_count * sizeof(stbtt_pack_range));
1700 memset(buf_packedchars, 0, total_glyphs_count * sizeof(stbtt_packedchar));
1701 memset(buf_rects, 0, total_glyphs_count * sizeof(stbrp_rect)); // Unnecessary but let's clear this for the sake of sanity.
1702 memset(buf_ranges, 0, total_ranges_count * sizeof(stbtt_pack_range));
1704 // First font pass: pack all glyphs (no rendering at this point, we are working with rectangles in an infinitely tall texture at this point)
1705 for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
1707 ImFontConfig& cfg = atlas->ConfigData[input_i];
1708 ImFontTempBuildData& tmp = tmp_array[input_i];
1711 int font_glyphs_count = 0;
1712 int font_ranges_count = 0;
1713 for (const ImWchar* in_range = cfg.GlyphRanges; in_range[0] && in_range[1]; in_range += 2, font_ranges_count++)
1714 font_glyphs_count += (in_range[1] - in_range[0]) + 1;
1715 tmp.Ranges = buf_ranges + buf_ranges_n;
1716 tmp.RangesCount = font_ranges_count;
1717 buf_ranges_n += font_ranges_count;
1718 for (int i = 0; i < font_ranges_count; i++)
1720 const ImWchar* in_range = &cfg.GlyphRanges[i * 2];
1721 stbtt_pack_range& range = tmp.Ranges[i];
1722 range.font_size = cfg.SizePixels;
1723 range.first_unicode_codepoint_in_range = in_range[0];
1724 range.num_chars = (in_range[1] - in_range[0]) + 1;
1725 range.chardata_for_range = buf_packedchars + buf_packedchars_n;
1726 buf_packedchars_n += range.num_chars;
1730 tmp.Rects = buf_rects + buf_rects_n;
1731 tmp.RectsCount = font_glyphs_count;
1732 buf_rects_n += font_glyphs_count;
1733 stbtt_PackSetOversampling(&spc, cfg.OversampleH, cfg.OversampleV);
1734 int n = stbtt_PackFontRangesGatherRects(&spc, &tmp.FontInfo, tmp.Ranges, tmp.RangesCount, tmp.Rects);
1735 IM_ASSERT(n == font_glyphs_count);
1736 stbrp_pack_rects((stbrp_context*)spc.pack_info, tmp.Rects, n);
1738 // Extend texture height
1739 for (int i = 0; i < n; i++)
1740 if (tmp.Rects[i].was_packed)
1741 atlas->TexHeight = ImMax(atlas->TexHeight, tmp.Rects[i].y + tmp.Rects[i].h);
1743 IM_ASSERT(buf_rects_n == total_glyphs_count);
1744 IM_ASSERT(buf_packedchars_n == total_glyphs_count);
1745 IM_ASSERT(buf_ranges_n == total_ranges_count);
1748 atlas->TexHeight = ImUpperPowerOfTwo(atlas->TexHeight);
1749 atlas->TexPixelsAlpha8 = (unsigned char*)ImGui::MemAlloc(atlas->TexWidth * atlas->TexHeight);
1750 memset(atlas->TexPixelsAlpha8, 0, atlas->TexWidth * atlas->TexHeight);
1751 spc.pixels = atlas->TexPixelsAlpha8;
1752 spc.height = atlas->TexHeight;
1754 // Second pass: render font characters
1755 for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
1757 ImFontConfig& cfg = atlas->ConfigData[input_i];
1758 ImFontTempBuildData& tmp = tmp_array[input_i];
1759 stbtt_PackSetOversampling(&spc, cfg.OversampleH, cfg.OversampleV);
1760 stbtt_PackFontRangesRenderIntoRects(&spc, &tmp.FontInfo, tmp.Ranges, tmp.RangesCount, tmp.Rects);
1761 if (cfg.RasterizerMultiply != 1.0f)
1763 unsigned char multiply_table[256];
1764 ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply);
1765 for (const stbrp_rect* r = tmp.Rects; r != tmp.Rects + tmp.RectsCount; r++)
1767 ImFontAtlasBuildMultiplyRectAlpha8(multiply_table, spc.pixels, r->x, r->y, r->w, r->h, spc.stride_in_bytes);
1773 stbtt_PackEnd(&spc);
1774 ImGui::MemFree(buf_rects);
1777 // Third pass: setup ImFont and glyphs for runtime
1778 for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
1780 ImFontConfig& cfg = atlas->ConfigData[input_i];
1781 ImFontTempBuildData& tmp = tmp_array[input_i];
1782 ImFont* dst_font = cfg.DstFont; // We can have multiple input fonts writing into a same destination font (when using MergeMode=true)
1784 const float font_scale = stbtt_ScaleForPixelHeight(&tmp.FontInfo, cfg.SizePixels);
1785 int unscaled_ascent, unscaled_descent, unscaled_line_gap;
1786 stbtt_GetFontVMetrics(&tmp.FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap);
1788 const float ascent = unscaled_ascent * font_scale;
1789 const float descent = unscaled_descent * font_scale;
1790 ImFontAtlasBuildSetupFont(atlas, dst_font, &cfg, ascent, descent);
1791 const float off_x = cfg.GlyphOffset.x;
1792 const float off_y = cfg.GlyphOffset.y + (float)(int)(dst_font->Ascent + 0.5f);
1794 for (int i = 0; i < tmp.RangesCount; i++)
1796 stbtt_pack_range& range = tmp.Ranges[i];
1797 for (int char_idx = 0; char_idx < range.num_chars; char_idx += 1)
1799 const stbtt_packedchar& pc = range.chardata_for_range[char_idx];
1800 if (!pc.x0 && !pc.x1 && !pc.y0 && !pc.y1)
1803 const int codepoint = range.first_unicode_codepoint_in_range + char_idx;
1804 if (cfg.MergeMode && dst_font->FindGlyph((unsigned short)codepoint))
1807 stbtt_aligned_quad q;
1808 float dummy_x = 0.0f, dummy_y = 0.0f;
1809 stbtt_GetPackedQuad(range.chardata_for_range, atlas->TexWidth, atlas->TexHeight, char_idx, &dummy_x, &dummy_y, &q, 0);
1810 dst_font->AddGlyph((ImWchar)codepoint, q.x0 + off_x, q.y0 + off_y, q.x1 + off_x, q.y1 + off_y, q.s0, q.t0, q.s1, q.t1, pc.xadvance);
1815 // Cleanup temporaries
1816 ImGui::MemFree(buf_packedchars);
1817 ImGui::MemFree(buf_ranges);
1818 ImGui::MemFree(tmp_array);
1820 ImFontAtlasBuildFinish(atlas);
1825 void ImFontAtlasBuildRegisterDefaultCustomRects(ImFontAtlas* atlas)
1827 if (atlas->CustomRectIds[0] < 0)
1828 atlas->CustomRectIds[0] = atlas->AddCustomRectRegular(FONT_ATLAS_DEFAULT_TEX_DATA_ID, FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF*2+1, FONT_ATLAS_DEFAULT_TEX_DATA_H);
1831 void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent)
1833 if (!font_config->MergeMode)
1835 font->ClearOutputData();
1836 font->FontSize = font_config->SizePixels;
1837 font->ConfigData = font_config;
1838 font->ContainerAtlas = atlas;
1839 font->Ascent = ascent;
1840 font->Descent = descent;
1842 font->ConfigDataCount++;
1845 void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* pack_context_opaque)
1847 stbrp_context* pack_context = (stbrp_context*)pack_context_opaque;
1849 ImVector<ImFontAtlas::CustomRect>& user_rects = atlas->CustomRects;
1850 IM_ASSERT(user_rects.Size >= 1); // We expect at least the default custom rects to be registered, else something went wrong.
1852 ImVector<stbrp_rect> pack_rects;
1853 pack_rects.resize(user_rects.Size);
1854 memset(pack_rects.Data, 0, sizeof(stbrp_rect) * user_rects.Size);
1855 for (int i = 0; i < user_rects.Size; i++)
1857 pack_rects[i].w = user_rects[i].Width;
1858 pack_rects[i].h = user_rects[i].Height;
1860 stbrp_pack_rects(pack_context, &pack_rects[0], pack_rects.Size);
1861 for (int i = 0; i < pack_rects.Size; i++)
1862 if (pack_rects[i].was_packed)
1864 user_rects[i].X = pack_rects[i].x;
1865 user_rects[i].Y = pack_rects[i].y;
1866 IM_ASSERT(pack_rects[i].w == user_rects[i].Width && pack_rects[i].h == user_rects[i].Height);
1867 atlas->TexHeight = ImMax(atlas->TexHeight, pack_rects[i].y + pack_rects[i].h);
1871 static void ImFontAtlasBuildRenderDefaultTexData(ImFontAtlas* atlas)
1873 IM_ASSERT(atlas->CustomRectIds[0] >= 0);
1874 ImFontAtlas::CustomRect& r = atlas->CustomRects[atlas->CustomRectIds[0]];
1875 IM_ASSERT(r.ID == FONT_ATLAS_DEFAULT_TEX_DATA_ID);
1876 IM_ASSERT(r.Width == FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF*2+1);
1877 IM_ASSERT(r.Height == FONT_ATLAS_DEFAULT_TEX_DATA_H);
1878 IM_ASSERT(r.IsPacked());
1879 IM_ASSERT(atlas->TexPixelsAlpha8 != NULL);
1881 // Render/copy pixels
1882 for (int y = 0, n = 0; y < FONT_ATLAS_DEFAULT_TEX_DATA_H; y++)
1883 for (int x = 0; x < FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF; x++, n++)
1885 const int offset0 = (int)(r.X + x) + (int)(r.Y + y) * atlas->TexWidth;
1886 const int offset1 = offset0 + FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF + 1;
1887 atlas->TexPixelsAlpha8[offset0] = FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[n] == '.' ? 0xFF : 0x00;
1888 atlas->TexPixelsAlpha8[offset1] = FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[n] == 'X' ? 0xFF : 0x00;
1890 const ImVec2 tex_uv_scale(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight);
1891 atlas->TexUvWhitePixel = ImVec2((r.X + 0.5f) * tex_uv_scale.x, (r.Y + 0.5f) * tex_uv_scale.y);
1893 // Setup mouse cursors
1894 for (int type = 0; type < ImGuiMouseCursor_Count_; type++)
1896 ImGuiMouseCursorData& cursor_data = GImGui->MouseCursorData[type];
1897 ImVec2 pos = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[type][0] + ImVec2((float)r.X, (float)r.Y);
1898 const ImVec2 size = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[type][1];
1899 cursor_data.Type = type;
1900 cursor_data.Size = size;
1901 cursor_data.HotOffset = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[type][2];
1902 cursor_data.TexUvMin[0] = (pos) * tex_uv_scale;
1903 cursor_data.TexUvMax[0] = (pos + size) * tex_uv_scale;
1904 pos.x += FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF + 1;
1905 cursor_data.TexUvMin[1] = (pos) * tex_uv_scale;
1906 cursor_data.TexUvMax[1] = (pos + size) * tex_uv_scale;
1910 void ImFontAtlasBuildFinish(ImFontAtlas* atlas)
1912 // Render into our custom data block
1913 ImFontAtlasBuildRenderDefaultTexData(atlas);
1915 // Register custom rectangle glyphs
1916 for (int i = 0; i < atlas->CustomRects.Size; i++)
1918 const ImFontAtlas::CustomRect& r = atlas->CustomRects[i];
1919 if (r.Font == NULL || r.ID > 0x10000)
1922 IM_ASSERT(r.Font->ContainerAtlas == atlas);
1924 atlas->CalcCustomRectUV(&r, &uv0, &uv1);
1925 r.Font->AddGlyph((ImWchar)r.ID, r.GlyphOffset.x, r.GlyphOffset.y, r.GlyphOffset.x + r.Width, r.GlyphOffset.y + r.Height, uv0.x, uv0.y, uv1.x, uv1.y, r.GlyphAdvanceX);
1928 // Build all fonts lookup tables
1929 for (int i = 0; i < atlas->Fonts.Size; i++)
1930 atlas->Fonts[i]->BuildLookupTable();
1933 // Retrieve list of range (2 int per range, values are inclusive)
1934 const ImWchar* ImFontAtlas::GetGlyphRangesDefault()
1936 static const ImWchar ranges[] =
1938 0x0020, 0x00FF, // Basic Latin + Latin Supplement
1944 const ImWchar* ImFontAtlas::GetGlyphRangesKorean()
1946 static const ImWchar ranges[] =
1948 0x0020, 0x00FF, // Basic Latin + Latin Supplement
1949 0x3131, 0x3163, // Korean alphabets
1950 0xAC00, 0xD79D, // Korean characters
1956 const ImWchar* ImFontAtlas::GetGlyphRangesChinese()
1958 static const ImWchar ranges[] =
1960 0x0020, 0x00FF, // Basic Latin + Latin Supplement
1961 0x3000, 0x30FF, // Punctuations, Hiragana, Katakana
1962 0x31F0, 0x31FF, // Katakana Phonetic Extensions
1963 0xFF00, 0xFFEF, // Half-width characters
1964 0x4e00, 0x9FAF, // CJK Ideograms
1970 const ImWchar* ImFontAtlas::GetGlyphRangesJapanese()
1972 // Store the 1946 ideograms code points as successive offsets from the initial unicode codepoint 0x4E00. Each offset has an implicit +1.
1973 // This encoding is designed to helps us reduce the source code size.
1974 // FIXME: Source a list of the revised 2136 joyo kanji list from 2010 and rebuild this.
1975 // The current list was sourced from http://theinstructionlimit.com/author/renaudbedardrenaudbedard/page/3
1976 // Note that you may use ImFontAtlas::GlyphRangesBuilder to create your own ranges, by merging existing ranges or adding new characters.
1977 static const short offsets_from_0x4E00[] =
1979 -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,
1980 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,
1981 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,
1982 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,
1983 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,
1984 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,
1985 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,
1986 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,
1987 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,
1988 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,
1989 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,
1990 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,
1991 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,
1992 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,
1993 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,
1994 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,
1995 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,
1996 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,
1997 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,
1998 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,
1999 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,
2000 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,
2001 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,
2002 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,
2003 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,
2004 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,
2005 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,
2006 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,
2007 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,
2008 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,
2009 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,
2010 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,
2012 static ImWchar base_ranges[] =
2014 0x0020, 0x00FF, // Basic Latin + Latin Supplement
2015 0x3000, 0x30FF, // Punctuations, Hiragana, Katakana
2016 0x31F0, 0x31FF, // Katakana Phonetic Extensions
2017 0xFF00, 0xFFEF, // Half-width characters
2019 static bool full_ranges_unpacked = false;
2020 static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(offsets_from_0x4E00)*2 + 1];
2021 if (!full_ranges_unpacked)
2024 int codepoint = 0x4e00;
2025 memcpy(full_ranges, base_ranges, sizeof(base_ranges));
2026 ImWchar* dst = full_ranges + IM_ARRAYSIZE(base_ranges);;
2027 for (int n = 0; n < IM_ARRAYSIZE(offsets_from_0x4E00); n++, dst += 2)
2028 dst[0] = dst[1] = (ImWchar)(codepoint += (offsets_from_0x4E00[n] + 1));
2030 full_ranges_unpacked = true;
2032 return &full_ranges[0];
2035 const ImWchar* ImFontAtlas::GetGlyphRangesCyrillic()
2037 static const ImWchar ranges[] =
2039 0x0020, 0x00FF, // Basic Latin + Latin Supplement
2040 0x0400, 0x052F, // Cyrillic + Cyrillic Supplement
2041 0x2DE0, 0x2DFF, // Cyrillic Extended-A
2042 0xA640, 0xA69F, // Cyrillic Extended-B
2048 const ImWchar* ImFontAtlas::GetGlyphRangesThai()
2050 static const ImWchar ranges[] =
2052 0x0020, 0x00FF, // Basic Latin
2053 0x2010, 0x205E, // Punctuations
2054 0x0E00, 0x0E7F, // Thai
2060 //-----------------------------------------------------------------------------
2061 // ImFontAtlas::GlyphRangesBuilder
2062 //-----------------------------------------------------------------------------
2064 void ImFontAtlas::GlyphRangesBuilder::AddText(const char* text, const char* text_end)
2066 while (text_end ? (text < text_end) : *text)
2069 int c_len = ImTextCharFromUtf8(&c, text, text_end);
2074 AddChar((ImWchar)c);
2078 void ImFontAtlas::GlyphRangesBuilder::AddRanges(const ImWchar* ranges)
2080 for (; ranges[0]; ranges += 2)
2081 for (ImWchar c = ranges[0]; c <= ranges[1]; c++)
2085 void ImFontAtlas::GlyphRangesBuilder::BuildRanges(ImVector<ImWchar>* out_ranges)
2087 for (int n = 0; n < 0x10000; n++)
2090 out_ranges->push_back((ImWchar)n);
2091 while (n < 0x10000 && GetBit(n + 1))
2093 out_ranges->push_back((ImWchar)n);
2095 out_ranges->push_back(0);
2098 //-----------------------------------------------------------------------------
2100 //-----------------------------------------------------------------------------
2105 FallbackChar = (ImWchar)'?';
2106 DisplayOffset = ImVec2(0.0f, 1.0f);
2112 // Invalidate active font so that the user gets a clear crash instead of a dangling pointer.
2113 // If you want to delete fonts you need to do it between Render() and NewFrame().
2116 ImGuiContext& g = *GImGui;
2123 void ImFont::ClearOutputData()
2127 IndexAdvanceX.clear();
2128 IndexLookup.clear();
2129 FallbackGlyph = NULL;
2130 FallbackAdvanceX = 0.0f;
2131 ConfigDataCount = 0;
2133 ContainerAtlas = NULL;
2134 Ascent = Descent = 0.0f;
2135 MetricsTotalSurface = 0;
2138 void ImFont::BuildLookupTable()
2140 int max_codepoint = 0;
2141 for (int i = 0; i != Glyphs.Size; i++)
2142 max_codepoint = ImMax(max_codepoint, (int)Glyphs[i].Codepoint);
2144 IM_ASSERT(Glyphs.Size < 0xFFFF); // -1 is reserved
2145 IndexAdvanceX.clear();
2146 IndexLookup.clear();
2147 GrowIndex(max_codepoint + 1);
2148 for (int i = 0; i < Glyphs.Size; i++)
2150 int codepoint = (int)Glyphs[i].Codepoint;
2151 IndexAdvanceX[codepoint] = Glyphs[i].AdvanceX;
2152 IndexLookup[codepoint] = (unsigned short)i;
2155 // Create a glyph to handle TAB
2156 // FIXME: Needs proper TAB handling but it needs to be contextualized (or we could arbitrary say that each string starts at "column 0" ?)
2157 if (FindGlyph((unsigned short)' '))
2159 if (Glyphs.back().Codepoint != '\t') // So we can call this function multiple times
2160 Glyphs.resize(Glyphs.Size + 1);
2161 ImFontGlyph& tab_glyph = Glyphs.back();
2162 tab_glyph = *FindGlyph((unsigned short)' ');
2163 tab_glyph.Codepoint = '\t';
2164 tab_glyph.AdvanceX *= 4;
2165 IndexAdvanceX[(int)tab_glyph.Codepoint] = (float)tab_glyph.AdvanceX;
2166 IndexLookup[(int)tab_glyph.Codepoint] = (unsigned short)(Glyphs.Size-1);
2169 FallbackGlyph = NULL;
2170 FallbackGlyph = FindGlyph(FallbackChar);
2171 FallbackAdvanceX = FallbackGlyph ? FallbackGlyph->AdvanceX : 0.0f;
2172 for (int i = 0; i < max_codepoint + 1; i++)
2173 if (IndexAdvanceX[i] < 0.0f)
2174 IndexAdvanceX[i] = FallbackAdvanceX;
2177 void ImFont::SetFallbackChar(ImWchar c)
2183 void ImFont::GrowIndex(int new_size)
2185 IM_ASSERT(IndexAdvanceX.Size == IndexLookup.Size);
2186 if (new_size <= IndexLookup.Size)
2188 IndexAdvanceX.resize(new_size, -1.0f);
2189 IndexLookup.resize(new_size, (unsigned short)-1);
2192 void ImFont::AddGlyph(ImWchar codepoint, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x)
2194 Glyphs.resize(Glyphs.Size + 1);
2195 ImFontGlyph& glyph = Glyphs.back();
2196 glyph.Codepoint = (ImWchar)codepoint;
2205 glyph.AdvanceX = advance_x + ConfigData->GlyphExtraSpacing.x; // Bake spacing into AdvanceX
2207 if (ConfigData->PixelSnapH)
2208 glyph.AdvanceX = (float)(int)(glyph.AdvanceX + 0.5f);
2210 // Compute rough surface usage metrics (+1 to account for average padding, +0.99 to round)
2211 MetricsTotalSurface += (int)((glyph.U1 - glyph.U0) * ContainerAtlas->TexWidth + 1.99f) * (int)((glyph.V1 - glyph.V0) * ContainerAtlas->TexHeight + 1.99f);
2214 void ImFont::AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst)
2216 IM_ASSERT(IndexLookup.Size > 0); // Currently this can only be called AFTER the font has been built, aka after calling ImFontAtlas::GetTexDataAs*() function.
2217 int index_size = IndexLookup.Size;
2219 if (dst < index_size && IndexLookup.Data[dst] == (unsigned short)-1 && !overwrite_dst) // 'dst' already exists
2221 if (src >= index_size && dst >= index_size) // both 'dst' and 'src' don't exist -> no-op
2225 IndexLookup[dst] = (src < index_size) ? IndexLookup.Data[src] : (unsigned short)-1;
2226 IndexAdvanceX[dst] = (src < index_size) ? IndexAdvanceX.Data[src] : 1.0f;
2229 const ImFontGlyph* ImFont::FindGlyph(ImWchar c) const
2231 if (c < IndexLookup.Size)
2233 const unsigned short i = IndexLookup[c];
2234 if (i != (unsigned short)-1)
2235 return &Glyphs.Data[i];
2237 return FallbackGlyph;
2240 const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) const
2242 // Simple word-wrapping for English, not full-featured. Please submit failing cases!
2243 // 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.)
2245 // For references, possible wrap point marked with ^
2246 // "aaa bbb, ccc,ddd. eee fff. ggg!"
2249 // List of hardcoded separators: .,;!?'"
2251 // Skip extra blanks after a line returns (that includes not counting them in width computation)
2252 // e.g. "Hello world" --> "Hello" "World"
2254 // Cut words that cannot possibly fit within one line.
2255 // e.g.: "The tropical fish" with ~5 characters worth of width --> "The tr" "opical" "fish"
2257 float line_width = 0.0f;
2258 float word_width = 0.0f;
2259 float blank_width = 0.0f;
2260 wrap_width /= scale; // We work with unscaled widths to avoid scaling every characters
2262 const char* word_end = text;
2263 const char* prev_word_end = NULL;
2264 bool inside_word = true;
2266 const char* s = text;
2267 while (s < text_end)
2269 unsigned int c = (unsigned int)*s;
2274 next_s = s + ImTextCharFromUtf8(&c, s, text_end);
2282 line_width = word_width = blank_width = 0.0f;
2294 const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX[(int)c] : FallbackAdvanceX);
2295 if (ImCharIsSpace(c))
2299 line_width += blank_width;
2303 blank_width += char_width;
2304 inside_word = false;
2308 word_width += char_width;
2315 prev_word_end = word_end;
2316 line_width += word_width + blank_width;
2317 word_width = blank_width = 0.0f;
2320 // Allow wrapping after punctuation.
2321 inside_word = !(c == '.' || c == ',' || c == ';' || c == '!' || c == '?' || c == '\"');
2324 // We ignore blank width at the end of the line (they can be skipped)
2325 if (line_width + word_width >= wrap_width)
2327 // Words that cannot possibly fit within an entire line will be cut anywhere.
2328 if (word_width < wrap_width)
2329 s = prev_word_end ? prev_word_end : word_end;
2339 ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end, const char** remaining) const
2342 text_end = text_begin + strlen(text_begin); // FIXME-OPT: Need to avoid this.
2344 const float line_height = size;
2345 const float scale = size / FontSize;
2347 ImVec2 text_size = ImVec2(0,0);
2348 float line_width = 0.0f;
2350 const bool word_wrap_enabled = (wrap_width > 0.0f);
2351 const char* word_wrap_eol = NULL;
2353 const char* s = text_begin;
2354 while (s < text_end)
2356 if (word_wrap_enabled)
2358 // 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.
2361 word_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - line_width);
2362 if (word_wrap_eol == s) // Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity.
2363 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
2366 if (s >= word_wrap_eol)
2368 if (text_size.x < line_width)
2369 text_size.x = line_width;
2370 text_size.y += line_height;
2372 word_wrap_eol = NULL;
2374 // Wrapping skips upcoming blanks
2375 while (s < text_end)
2378 if (ImCharIsSpace(c)) { s++; } else if (c == '\n') { s++; break; } else { break; }
2384 // Decode and advance source
2385 const char* prev_s = s;
2386 unsigned int c = (unsigned int)*s;
2393 s += ImTextCharFromUtf8(&c, s, text_end);
2394 if (c == 0) // Malformed UTF-8?
2402 text_size.x = ImMax(text_size.x, line_width);
2403 text_size.y += line_height;
2411 const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX[(int)c] : FallbackAdvanceX) * scale;
2412 if (line_width + char_width >= max_width)
2418 line_width += char_width;
2421 if (text_size.x < line_width)
2422 text_size.x = line_width;
2424 if (line_width > 0 || text_size.y == 0.0f)
2425 text_size.y += line_height;
2433 void ImFont::RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, unsigned short c) const
2435 if (c == ' ' || c == '\t' || c == '\n' || c == '\r') // Match behavior of RenderText(), those 4 codepoints are hard-coded.
2437 if (const ImFontGlyph* glyph = FindGlyph(c))
2439 float scale = (size >= 0.0f) ? (size / FontSize) : 1.0f;
2440 pos.x = (float)(int)pos.x + DisplayOffset.x;
2441 pos.y = (float)(int)pos.y + DisplayOffset.y;
2442 draw_list->PrimReserve(6, 4);
2443 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);
2447 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
2450 text_end = text_begin + strlen(text_begin); // ImGui functions generally already provides a valid text_end, so this is merely to handle direct calls.
2452 // Align to be pixel perfect
2453 pos.x = (float)(int)pos.x + DisplayOffset.x;
2454 pos.y = (float)(int)pos.y + DisplayOffset.y;
2457 if (y > clip_rect.w)
2460 const float scale = size / FontSize;
2461 const float line_height = FontSize * scale;
2462 const bool word_wrap_enabled = (wrap_width > 0.0f);
2463 const char* word_wrap_eol = NULL;
2465 // Skip non-visible lines
2466 const char* s = text_begin;
2467 if (!word_wrap_enabled && y + line_height < clip_rect.y)
2468 while (s < text_end && *s != '\n') // Fast-forward to next line
2471 // Reserve vertices for remaining worse case (over-reserving is useful and easily amortized)
2472 const int vtx_count_max = (int)(text_end - s) * 4;
2473 const int idx_count_max = (int)(text_end - s) * 6;
2474 const int idx_expected_size = draw_list->IdxBuffer.Size + idx_count_max;
2475 draw_list->PrimReserve(idx_count_max, vtx_count_max);
2477 ImDrawVert* vtx_write = draw_list->_VtxWritePtr;
2478 ImDrawIdx* idx_write = draw_list->_IdxWritePtr;
2479 unsigned int vtx_current_idx = draw_list->_VtxCurrentIdx;
2481 while (s < text_end)
2483 if (word_wrap_enabled)
2485 // 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.
2488 word_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - (x - pos.x));
2489 if (word_wrap_eol == s) // Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity.
2490 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
2493 if (s >= word_wrap_eol)
2497 word_wrap_eol = NULL;
2499 // Wrapping skips upcoming blanks
2500 while (s < text_end)
2503 if (ImCharIsSpace(c)) { s++; } else if (c == '\n') { s++; break; } else { break; }
2509 // Decode and advance source
2510 unsigned int c = (unsigned int)*s;
2517 s += ImTextCharFromUtf8(&c, s, text_end);
2518 if (c == 0) // Malformed UTF-8?
2529 if (y > clip_rect.w)
2531 if (!word_wrap_enabled && y + line_height < clip_rect.y)
2532 while (s < text_end && *s != '\n') // Fast-forward to next line
2540 float char_width = 0.0f;
2541 if (const ImFontGlyph* glyph = FindGlyph((unsigned short)c))
2543 char_width = glyph->AdvanceX * scale;
2545 // Arbitrarily assume that both space and tabs are empty glyphs as an optimization
2546 if (c != ' ' && c != '\t')
2548 // 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
2549 float x1 = x + glyph->X0 * scale;
2550 float x2 = x + glyph->X1 * scale;
2551 float y1 = y + glyph->Y0 * scale;
2552 float y2 = y + glyph->Y1 * scale;
2553 if (x1 <= clip_rect.z && x2 >= clip_rect.x)
2555 // Render a character
2556 float u1 = glyph->U0;
2557 float v1 = glyph->V0;
2558 float u2 = glyph->U1;
2559 float v2 = glyph->V1;
2561 // CPU side clipping used to fit text in their frame when the frame is too small. Only does clipping for axis aligned quads.
2564 if (x1 < clip_rect.x)
2566 u1 = u1 + (1.0f - (x2 - clip_rect.x) / (x2 - x1)) * (u2 - u1);
2569 if (y1 < clip_rect.y)
2571 v1 = v1 + (1.0f - (y2 - clip_rect.y) / (y2 - y1)) * (v2 - v1);
2574 if (x2 > clip_rect.z)
2576 u2 = u1 + ((clip_rect.z - x1) / (x2 - x1)) * (u2 - u1);
2579 if (y2 > clip_rect.w)
2581 v2 = v1 + ((clip_rect.w - y1) / (y2 - y1)) * (v2 - v1);
2591 // We are NOT calling PrimRectUV() here because non-inlined causes too much overhead in a debug builds. Inlined here:
2593 idx_write[0] = (ImDrawIdx)(vtx_current_idx); idx_write[1] = (ImDrawIdx)(vtx_current_idx+1); idx_write[2] = (ImDrawIdx)(vtx_current_idx+2);
2594 idx_write[3] = (ImDrawIdx)(vtx_current_idx); idx_write[4] = (ImDrawIdx)(vtx_current_idx+2); idx_write[5] = (ImDrawIdx)(vtx_current_idx+3);
2595 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;
2596 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;
2597 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;
2598 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;
2600 vtx_current_idx += 4;
2610 // Give back unused vertices
2611 draw_list->VtxBuffer.resize((int)(vtx_write - draw_list->VtxBuffer.Data));
2612 draw_list->IdxBuffer.resize((int)(idx_write - draw_list->IdxBuffer.Data));
2613 draw_list->CmdBuffer[draw_list->CmdBuffer.Size-1].ElemCount -= (idx_expected_size - draw_list->IdxBuffer.Size);
2614 draw_list->_VtxWritePtr = vtx_write;
2615 draw_list->_IdxWritePtr = idx_write;
2616 draw_list->_VtxCurrentIdx = (unsigned int)draw_list->VtxBuffer.Size;
2619 //-----------------------------------------------------------------------------
2620 // Internals Drawing Helpers
2621 //-----------------------------------------------------------------------------
2623 static inline float ImAcos01(float x)
2625 if (x <= 0.0f) return IM_PI * 0.5f;
2626 if (x >= 1.0f) return 0.0f;
2628 //return (-0.69813170079773212f * x * x - 0.87266462599716477f) * x + 1.5707963267948966f; // Cheap approximation, may be enough for what we do.
2631 // FIXME: Cleanup and move code to ImDrawList.
2632 void ImGui::RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, ImU32 col, float x_start_norm, float x_end_norm, float rounding)
2634 if (x_end_norm == x_start_norm)
2636 if (x_start_norm > x_end_norm)
2637 ImSwap(x_start_norm, x_end_norm);
2639 ImVec2 p0 = ImVec2(ImLerp(rect.Min.x, rect.Max.x, x_start_norm), rect.Min.y);
2640 ImVec2 p1 = ImVec2(ImLerp(rect.Min.x, rect.Max.x, x_end_norm), rect.Max.y);
2641 if (rounding == 0.0f)
2643 draw_list->AddRectFilled(p0, p1, col, 0.0f);
2647 rounding = ImClamp(ImMin((rect.Max.x - rect.Min.x) * 0.5f, (rect.Max.y - rect.Min.y) * 0.5f) - 1.0f, 0.0f, rounding);
2648 const float inv_rounding = 1.0f / rounding;
2649 const float arc0_b = ImAcos01(1.0f - (p0.x - rect.Min.x) * inv_rounding);
2650 const float arc0_e = ImAcos01(1.0f - (p1.x - rect.Min.x) * inv_rounding);
2651 const float x0 = ImMax(p0.x, rect.Min.x + rounding);
2652 if (arc0_b == arc0_e)
2654 draw_list->PathLineTo(ImVec2(x0, p1.y));
2655 draw_list->PathLineTo(ImVec2(x0, p0.y));
2657 else if (arc0_b == 0.0f && arc0_e == IM_PI*0.5f)
2659 draw_list->PathArcToFast(ImVec2(x0, p1.y - rounding), rounding, 3, 6); // BL
2660 draw_list->PathArcToFast(ImVec2(x0, p0.y + rounding), rounding, 6, 9); // TR
2664 draw_list->PathArcTo(ImVec2(x0, p1.y - rounding), rounding, IM_PI - arc0_e, IM_PI - arc0_b, 3); // BL
2665 draw_list->PathArcTo(ImVec2(x0, p0.y + rounding), rounding, IM_PI + arc0_b, IM_PI + arc0_e, 3); // TR
2667 if (p1.x > rect.Min.x + rounding)
2669 const float arc1_b = ImAcos01(1.0f - (rect.Max.x - p1.x) * inv_rounding);
2670 const float arc1_e = ImAcos01(1.0f - (rect.Max.x - p0.x) * inv_rounding);
2671 const float x1 = ImMin(p1.x, rect.Max.x - rounding);
2672 if (arc1_b == arc1_e)
2674 draw_list->PathLineTo(ImVec2(x1, p0.y));
2675 draw_list->PathLineTo(ImVec2(x1, p1.y));
2677 else if (arc1_b == 0.0f && arc1_e == IM_PI*0.5f)
2679 draw_list->PathArcToFast(ImVec2(x1, p0.y + rounding), rounding, 9, 12); // TR
2680 draw_list->PathArcToFast(ImVec2(x1, p1.y - rounding), rounding, 0, 3); // BR
2684 draw_list->PathArcTo(ImVec2(x1, p0.y + rounding), rounding, -arc1_e, -arc1_b, 3); // TR
2685 draw_list->PathArcTo(ImVec2(x1, p1.y - rounding), rounding, +arc1_b, +arc1_e, 3); // BR
2688 draw_list->PathFillConvex(col);
2691 //-----------------------------------------------------------------------------
2692 // DEFAULT FONT DATA
2693 //-----------------------------------------------------------------------------
2694 // Compressed with stb_compress() then converted to a C array.
2695 // Use the program in extra_fonts/binary_to_compressed_c.cpp to create the array from a TTF file.
2696 // Decompression from stb.h (public domain) by Sean Barrett https://github.com/nothings/stb/blob/master/stb.h
2697 //-----------------------------------------------------------------------------
2699 static unsigned int stb_decompress_length(unsigned char *input)
2701 return (input[8] << 24) + (input[9] << 16) + (input[10] << 8) + input[11];
2704 static unsigned char *stb__barrier, *stb__barrier2, *stb__barrier3, *stb__barrier4;
2705 static unsigned char *stb__dout;
2706 static void stb__match(unsigned char *data, unsigned int length)
2708 // INVERSE of memmove... write each byte before copying the next...
2709 IM_ASSERT (stb__dout + length <= stb__barrier);
2710 if (stb__dout + length > stb__barrier) { stb__dout += length; return; }
2711 if (data < stb__barrier4) { stb__dout = stb__barrier+1; return; }
2712 while (length--) *stb__dout++ = *data++;
2715 static void stb__lit(unsigned char *data, unsigned int length)
2717 IM_ASSERT (stb__dout + length <= stb__barrier);
2718 if (stb__dout + length > stb__barrier) { stb__dout += length; return; }
2719 if (data < stb__barrier2) { stb__dout = stb__barrier+1; return; }
2720 memcpy(stb__dout, data, length);
2721 stb__dout += length;
2724 #define stb__in2(x) ((i[x] << 8) + i[(x)+1])
2725 #define stb__in3(x) ((i[x] << 16) + stb__in2((x)+1))
2726 #define stb__in4(x) ((i[x] << 24) + stb__in3((x)+1))
2728 static unsigned char *stb_decompress_token(unsigned char *i)
2730 if (*i >= 0x20) { // use fewer if's for cases that expand small
2731 if (*i >= 0x80) stb__match(stb__dout-i[1]-1, i[0] - 0x80 + 1), i += 2;
2732 else if (*i >= 0x40) stb__match(stb__dout-(stb__in2(0) - 0x4000 + 1), i[2]+1), i += 3;
2733 else /* *i >= 0x20 */ stb__lit(i+1, i[0] - 0x20 + 1), i += 1 + (i[0] - 0x20 + 1);
2734 } else { // more ifs for cases that expand large, since overhead is amortized
2735 if (*i >= 0x18) stb__match(stb__dout-(stb__in3(0) - 0x180000 + 1), i[3]+1), i += 4;
2736 else if (*i >= 0x10) stb__match(stb__dout-(stb__in3(0) - 0x100000 + 1), stb__in2(3)+1), i += 5;
2737 else if (*i >= 0x08) stb__lit(i+2, stb__in2(0) - 0x0800 + 1), i += 2 + (stb__in2(0) - 0x0800 + 1);
2738 else if (*i == 0x07) stb__lit(i+3, stb__in2(1) + 1), i += 3 + (stb__in2(1) + 1);
2739 else if (*i == 0x06) stb__match(stb__dout-(stb__in3(1)+1), i[4]+1), i += 5;
2740 else if (*i == 0x04) stb__match(stb__dout-(stb__in3(1)+1), stb__in2(4)+1), i += 6;
2745 static unsigned int stb_adler32(unsigned int adler32, unsigned char *buffer, unsigned int buflen)
2747 const unsigned long ADLER_MOD = 65521;
2748 unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16;
2749 unsigned long blocklen, i;
2751 blocklen = buflen % 5552;
2753 for (i=0; i + 7 < blocklen; i += 8) {
2754 s1 += buffer[0], s2 += s1;
2755 s1 += buffer[1], s2 += s1;
2756 s1 += buffer[2], s2 += s1;
2757 s1 += buffer[3], s2 += s1;
2758 s1 += buffer[4], s2 += s1;
2759 s1 += buffer[5], s2 += s1;
2760 s1 += buffer[6], s2 += s1;
2761 s1 += buffer[7], s2 += s1;
2766 for (; i < blocklen; ++i)
2767 s1 += *buffer++, s2 += s1;
2769 s1 %= ADLER_MOD, s2 %= ADLER_MOD;
2773 return (unsigned int)(s2 << 16) + (unsigned int)s1;
2776 static unsigned int stb_decompress(unsigned char *output, unsigned char *i, unsigned int length)
2779 if (stb__in4(0) != 0x57bC0000) return 0;
2780 if (stb__in4(4) != 0) return 0; // error! stream is > 4GB
2781 olen = stb_decompress_length(i);
2783 stb__barrier3 = i+length;
2784 stb__barrier = output + olen;
2785 stb__barrier4 = output;
2790 unsigned char *old_i = i;
2791 i = stb_decompress_token(i);
2793 if (*i == 0x05 && i[1] == 0xfa) {
2794 IM_ASSERT(stb__dout == output + olen);
2795 if (stb__dout != output + olen) return 0;
2796 if (stb_adler32(1, output, olen) != (unsigned int) stb__in4(2))
2800 IM_ASSERT(0); /* NOTREACHED */
2804 IM_ASSERT(stb__dout <= output + olen);
2805 if (stb__dout > output + olen)
2810 //-----------------------------------------------------------------------------
2812 // Copyright (c) 2004, 2005 Tristan Grimmer
2813 // MIT license (see License.txt in http://www.upperbounds.net/download/ProggyClean.ttf.zip)
2814 // Download and more information at http://upperbounds.net
2815 //-----------------------------------------------------------------------------
2816 // File: 'ProggyClean.ttf' (41208 bytes)
2817 // Exported using binary_to_compressed_c.cpp
2818 //-----------------------------------------------------------------------------
2819 static const char proggy_clean_ttf_compressed_data_base85[11980+1] =
2820 "7])#######hV0qs'/###[),##/l:$#Q6>##5[n42>c-TH`->>#/e>11NNV=Bv(*:.F?uu#(gRU.o0XGH`$vhLG1hxt9?W`#,5LsCp#-i>.r$<$6pD>Lb';9Crc6tgXmKVeU2cD4Eo3R/"
2821 "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#"
2822 "`8ND>Qo#t'X#(v#Y9w0#1D$CIf;W'#pWUPXOuxXuU(H9M(1<q-UE31#^-V'8IRUo7Qf./L>=Ke$$'5F%)]0^#0X@U.a<r:QLtFsLcL6##lOj)#.Y5<-R&KgLwqJfLgN&;Q?gI^#DY2uL"
2823 "i@^rMl9t=cWq6##weg>$FBjVQTSDgEKnIS7EM9>ZY9w0#L;>>#Mx&4Mvt//L[MkA#W@lK.N'[0#7RL_&#w+F%HtG9M#XL`N&.,GM4Pg;-<nLENhvx>-VsM.M0rJfLH2eTM`*oJMHRC`N"
2824 "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+`�j@'DbG&#^$PG.Ll+DNa<XCMKEV*N)LN/N"
2825 "*b=%Q6pia-Xg8I$<MR&,VdJe$<(7G;Ckl'&hF;;$<_=X(b.RS%%)###MPBuuE1V:v&cXm#(&cV]`k9OhLMbn%s$G2,B$BfD3X*sp5#l,$R#]x_X1xKX%b5U*[r5iMfUo9U`N99hG)"
2826 "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"
2827 "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."
2828 "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"
2829 "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(,)"
2830 "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#"
2831 "'/###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"
2832 "_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"
2833 "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/"
2834 "/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"
2835 "%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&#"
2836 "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)("
2837 "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"
2838 "o;#2:;%d	v68C5g?ntX0X)pT`;%pB3q7mgGN)3%(P8nTd5L7GeA-GL@+%J3u2:(Yf>et`e;)f#Km8&+DC$I46>#Kr]]u-[=99tts1.qb#q72g1WJO81q+eN'03'eM>&1XxY-caEnO"
2839 "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^-"
2840 "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-"
2841 "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"
2842 "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%"
2843 "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]"
2844 "%(?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"
2845 "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:"
2846 "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("
2847 "$/V,;(kXZejWO`<[5?\?ewY(*9=%wDc;,u<'9t3W-(H1th3+G]ucQ]kLs7df($/*JL]@*t7Bu_G3_7mp7<iaQjO@.kLg;x3B0lqp7Hf,^Ze7-##@/c58Mo(3;knp0%)A7?-W+eI'o8)b<"
2848 "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'?"
2849 "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/;"
2850 ")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"
2851 "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("
2852 "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"
2853 "bIu)'Z,*[>br5fX^:FPAWr-m2KgL<LUN098kTF&#lvo58=/vjDo;.;)Ka*hLR#/k=rKbxuV`>Q_nN6'8uTGT5g)uLv:873UpTLgH+#FgpH'_o1780Ph8KmxQJ8#H72L4@768@Tm&Q"
2854 "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<-"
2855 "V8J'(1)G][68hW$5'q[GC&5j`TE?m'esFGNRM)j,ffZ?-qx8;->g4t*:CIP/[Qap7/9'#(1sao7w-.qNUdkJ)tCF&#B^;xGvn2r9FEPFFFcL@.iFNkTve$m%#QvQS8U@)2Z+3K:AKM5i"
2856 "sZ88+dKQ)W6>J%CL<KE>`.d*(B`-n8D9oK<Up]c$X$(,)M8Zt7/[rdkqTgl-0cuGMv'?>-XV1q['-5k'cAZ69e;D_?$ZPP&s^+7])$*$#@QYi9,5P	r+$%CE=68>K8r0=dSC%%(@p7"
2857 ".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@@"
2858 "$&)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*"
2859 "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"
2860 "@-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&#"
2861 "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#"
2862 "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"
2863 "d=j.LQf./Ll33+(;q3L-w=8dX$#WF&uIJ@-bfI>%:_i2B5CsR8&9Z&#=mPEnm0f`<&c)QL5uJ#%u%lJj+D-r;BoFDoS97h5g)E#o:&S4weDF,9^Hoe`h*L+_a*NrLW-1pG_&2UdB8"
2864 "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&#"
2865 "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"
2866 ":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+"
2867 "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*"
2868 "$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"
2869 ":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"
2870 "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"
2871 "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"
2872 "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"
2873 ":^#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@&]>"
2874 "_>@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%"
2875 "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;"
2876 "^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:"
2877 "+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%"
2878 "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-"
2879 "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*"
2880 "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"
2881 "8kD2)2fU/M#$e.)T4,_=8hLim[&);?UkK'-x?'(:siIfL<$pFM`i<?%W(mGDHM%>iWP,##P`%/L<eXi:@Z9C.7o=@(pXdAO/NLQ8lPl+HPOQa8wD8=^GlPa8TKI1CjhsCTSLJM'/Wl>-"
2882 "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`"
2883 "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]%/"
2884 "+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"
2885 "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"
2886 "?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"
2887 "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"
2888 ">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'>"
2889 "[%$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"
2890 "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#"
2891 "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$"
2892 "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,)"
2893 "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"
2894 "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"
2895 "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"
2896 "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(#"
2897 ";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&>"
2898 "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#"
2899 "d<F&#*;G##.GY##2Sl##6`($#:l:$#>xL$#B.`$#F:r$#JF.%#NR@%#R_R%#Vke%#Zww%#_-4^Rh%Sflr-k'MS.o?.5/sWel/wpEM0%3'/1)K^f1-d>G21&v(35>V`39V7A4=onx4"
2900 "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#"
2901 "/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-#"
2902 "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#"
2903 "TmD<#%JSMFove:CTBEXI:<eh2g)B,3h2^G3i;#d3jD>)4kMYD4lVu`4m`:&5niUA5@(A5BA1]PBB:xlBCC=2CDLXMCEUtiCf&0g2'tN?PGT4CPGT4CPGT4CPGT4CPGT4CPGT4CPGT4CP"
2904 "GT4CPGT4CPGT4CPGT4CPGT4CPGT4CP-qekC`.9kEg^+F$kwViFJTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5o,^<-28ZI'O?;xp"
2905 "O?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xp;7q-#lLYI:xvD=#";
2907 static const char* GetDefaultCompressedFontDataTTFBase85()
2909 return proggy_clean_ttf_compressed_data_base85;