1 // dear imgui, v1.60 WIP
2 // (drawing and font code)
3
4 // Contains implementation for
5 // - Default styles
6 // - ImDrawList
7 // - ImDrawData
8 // - ImFontAtlas
9 // - ImFont
10 // - Default font data
11
12 #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
13 #define _CRT_SECURE_NO_WARNINGS
14 #endif
15
16 #include "imgui.h"
17 #define IMGUI_DEFINE_MATH_OPERATORS
18 #include "imgui_internal.h"
19
20 #include <stdio.h> // vsnprintf, sscanf, printf
21 #if !defined(alloca)
22 #ifdef _WIN32
23 #include <malloc.h> // alloca
24 #if !defined(alloca)
25 #define alloca _alloca // for clang with MS Codegen
26 #endif
27 #elif defined(__GLIBC__) || defined(__sun)
28 #include <alloca.h> // alloca
29 #else
30 #include <stdlib.h> // alloca
31 #endif
32 #endif
33
34 #ifdef _MSC_VER
35 #pragma warning(disable : 4505) // unreferenced local function has been removed (stb stuff)
36 #pragma warning(disable : 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
37 #define snprintf _snprintf
38 #endif
39
40 #ifdef __clang__
41 #pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse.
42 #pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants ok.
43 #pragma clang diagnostic ignored "-Wglobal-constructors" // warning : declaration requires a global destructor // similar to above, not sure what the exact difference it.
44 #pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness //
45 #if __has_warning("-Wcomma")
46 #pragma clang diagnostic ignored "-Wcomma" // warning : possible misuse of comma operator here //
47 #endif
48 #if __has_warning("-Wreserved-id-macro")
49 #pragma clang diagnostic ignored "-Wreserved-id-macro" // warning : macro name is a reserved identifier //
50 #endif
51 #if __has_warning("-Wdouble-promotion")
52 #pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function
53 #endif
54 #elif defined(__GNUC__)
55 #pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used
56 #pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function
57 #pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value
58 #pragma GCC diagnostic ignored "-Wcast-qual" // warning: cast from type 'xxxx' to type 'xxxx' casts away qualifiers
59 #endif
60
61 //-------------------------------------------------------------------------
62 // STB libraries implementation
63 //-------------------------------------------------------------------------
64
65 //#define IMGUI_STB_NAMESPACE ImGuiStb
66 //#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
67 //#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
68
69 #ifdef IMGUI_STB_NAMESPACE
70 namespace IMGUI_STB_NAMESPACE
71 {
72 #endif
73
74 #ifdef _MSC_VER
75 #pragma warning(push)
76 #pragma warning(disable : 4456) // declaration of 'xx' hides previous local declaration
77 #endif
78
79 #ifdef __clang__
80 #pragma clang diagnostic push
81 #pragma clang diagnostic ignored "-Wunused-function"
82 #pragma clang diagnostic ignored "-Wmissing-prototypes"
83 #pragma clang diagnostic ignored "-Wimplicit-fallthrough"
84 #endif
85
86 #ifdef __GNUC__
87 #pragma GCC diagnostic push
88 #pragma GCC diagnostic ignored "-Wtype-limits" // warning: comparison is always true due to limited range of data type [-Wtype-limits]
89 #endif
90
91 #define STBRP_ASSERT(x) IM_ASSERT(x)
92 #ifndef IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
93 #define STBRP_STATIC
94 #define STB_RECT_PACK_IMPLEMENTATION
95 #endif
96 #include "stb_rect_pack.h"
97
98 #define STBTT_malloc(x, u) ((void)(u), ImGui::MemAlloc(x))
99 #define STBTT_free(x, u) ((void)(u), ImGui::MemFree(x))
100 #define STBTT_assert(x) IM_ASSERT(x)
101 #ifndef IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
102 #define STBTT_STATIC
103 #define STB_TRUETYPE_IMPLEMENTATION
104 #else
105 #define STBTT_DEF extern
106 #endif
107 #include "stb_truetype.h"
108
109 #ifdef __GNUC__
110 #pragma GCC diagnostic pop
111 #endif
112
113 #ifdef __clang__
114 #pragma clang diagnostic pop
115 #endif
116
117 #ifdef _MSC_VER
118 #pragma warning(pop)
119 #endif
120
121 #ifdef IMGUI_STB_NAMESPACE
122 } // namespace ImGuiStb
123 using namespace IMGUI_STB_NAMESPACE;
124 #endif
125
126 //-----------------------------------------------------------------------------
127 // Style functions
128 //-----------------------------------------------------------------------------
129
StyleColorsDark(ImGuiStyle * dst)130 void ImGui::StyleColorsDark(ImGuiStyle* dst)
131 {
132 ImGuiStyle* style = dst ? dst : &ImGui::GetStyle();
133 ImVec4* colors = style->Colors;
134
135 colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
136 colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
137 colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.06f, 0.06f, 0.94f);
138 colors[ImGuiCol_ChildBg] = ImVec4(1.00f, 1.00f, 1.00f, 0.00f);
139 colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.08f, 0.94f);
140 colors[ImGuiCol_Border] = ImVec4(0.43f, 0.43f, 0.50f, 0.50f);
141 colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
142 colors[ImGuiCol_FrameBg] = ImVec4(0.16f, 0.29f, 0.48f, 0.54f);
143 colors[ImGuiCol_FrameBgHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);
144 colors[ImGuiCol_FrameBgActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
145 colors[ImGuiCol_TitleBg] = ImVec4(0.04f, 0.04f, 0.04f, 1.00f);
146 colors[ImGuiCol_TitleBgActive] = ImVec4(0.16f, 0.29f, 0.48f, 1.00f);
147 colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.00f, 0.00f, 0.51f);
148 colors[ImGuiCol_MenuBarBg] = ImVec4(0.14f, 0.14f, 0.14f, 1.00f);
149 colors[ImGuiCol_ScrollbarBg] = ImVec4(0.02f, 0.02f, 0.02f, 0.53f);
150 colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.31f, 0.31f, 0.31f, 1.00f);
151 colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f);
152 colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.51f, 0.51f, 0.51f, 1.00f);
153 colors[ImGuiCol_CheckMark] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
154 colors[ImGuiCol_SliderGrab] = ImVec4(0.24f, 0.52f, 0.88f, 1.00f);
155 colors[ImGuiCol_SliderGrabActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
156 colors[ImGuiCol_Button] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);
157 colors[ImGuiCol_ButtonHovered] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
158 colors[ImGuiCol_ButtonActive] = ImVec4(0.06f, 0.53f, 0.98f, 1.00f);
159 colors[ImGuiCol_Header] = ImVec4(0.26f, 0.59f, 0.98f, 0.31f);
160 colors[ImGuiCol_HeaderHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.80f);
161 colors[ImGuiCol_HeaderActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
162 colors[ImGuiCol_Separator] = colors[ImGuiCol_Border];
163 colors[ImGuiCol_SeparatorHovered] = ImVec4(0.10f, 0.40f, 0.75f, 0.78f);
164 colors[ImGuiCol_SeparatorActive] = ImVec4(0.10f, 0.40f, 0.75f, 1.00f);
165 colors[ImGuiCol_ResizeGrip] = ImVec4(0.26f, 0.59f, 0.98f, 0.25f);
166 colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
167 colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
168 colors[ImGuiCol_CloseButton] = ImVec4(0.41f, 0.41f, 0.41f, 0.50f);
169 colors[ImGuiCol_CloseButtonHovered] = ImVec4(0.98f, 0.39f, 0.36f, 1.00f);
170 colors[ImGuiCol_CloseButtonActive] = ImVec4(0.98f, 0.39f, 0.36f, 1.00f);
171 colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);
172 colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
173 colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
174 colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
175 colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
176 colors[ImGuiCol_ModalWindowDarkening] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f);
177 colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
178 colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
179 colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);
180 }
181
StyleColorsClassic(ImGuiStyle * dst)182 void ImGui::StyleColorsClassic(ImGuiStyle* dst)
183 {
184 ImGuiStyle* style = dst ? dst : &ImGui::GetStyle();
185 ImVec4* colors = style->Colors;
186
187 colors[ImGuiCol_Text] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
188 colors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f);
189 colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.70f);
190 colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
191 colors[ImGuiCol_PopupBg] = ImVec4(0.11f, 0.11f, 0.14f, 0.92f);
192 colors[ImGuiCol_Border] = ImVec4(0.50f, 0.50f, 0.50f, 0.50f);
193 colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
194 colors[ImGuiCol_FrameBg] = ImVec4(0.43f, 0.43f, 0.43f, 0.39f);
195 colors[ImGuiCol_FrameBgHovered] = ImVec4(0.47f, 0.47f, 0.69f, 0.40f);
196 colors[ImGuiCol_FrameBgActive] = ImVec4(0.42f, 0.41f, 0.64f, 0.69f);
197 colors[ImGuiCol_TitleBg] = ImVec4(0.27f, 0.27f, 0.54f, 0.83f);
198 colors[ImGuiCol_TitleBgActive] = ImVec4(0.32f, 0.32f, 0.63f, 0.87f);
199 colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.40f, 0.40f, 0.80f, 0.20f);
200 colors[ImGuiCol_MenuBarBg] = ImVec4(0.40f, 0.40f, 0.55f, 0.80f);
201 colors[ImGuiCol_ScrollbarBg] = ImVec4(0.20f, 0.25f, 0.30f, 0.60f);
202 colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.40f, 0.40f, 0.80f, 0.30f);
203 colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.40f, 0.40f, 0.80f, 0.40f);
204 colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.41f, 0.39f, 0.80f, 0.60f);
205 colors[ImGuiCol_CheckMark] = ImVec4(0.90f, 0.90f, 0.90f, 0.50f);
206 colors[ImGuiCol_SliderGrab] = ImVec4(1.00f, 1.00f, 1.00f, 0.30f);
207 colors[ImGuiCol_SliderGrabActive] = ImVec4(0.41f, 0.39f, 0.80f, 0.60f);
208 colors[ImGuiCol_Button] = ImVec4(0.35f, 0.40f, 0.61f, 0.62f);
209 colors[ImGuiCol_ButtonHovered] = ImVec4(0.40f, 0.48f, 0.71f, 0.79f);
210 colors[ImGuiCol_ButtonActive] = ImVec4(0.46f, 0.54f, 0.80f, 1.00f);
211 colors[ImGuiCol_Header] = ImVec4(0.40f, 0.40f, 0.90f, 0.45f);
212 colors[ImGuiCol_HeaderHovered] = ImVec4(0.45f, 0.45f, 0.90f, 0.80f);
213 colors[ImGuiCol_HeaderActive] = ImVec4(0.53f, 0.53f, 0.87f, 0.80f);
214 colors[ImGuiCol_Separator] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
215 colors[ImGuiCol_SeparatorHovered] = ImVec4(0.60f, 0.60f, 0.70f, 1.00f);
216 colors[ImGuiCol_SeparatorActive] = ImVec4(0.70f, 0.70f, 0.90f, 1.00f);
217 colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.16f);
218 colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.78f, 0.82f, 1.00f, 0.60f);
219 colors[ImGuiCol_ResizeGripActive] = ImVec4(0.78f, 0.82f, 1.00f, 0.90f);
220 colors[ImGuiCol_CloseButton] = ImVec4(0.50f, 0.50f, 0.90f, 0.50f);
221 colors[ImGuiCol_CloseButtonHovered] = ImVec4(0.70f, 0.70f, 0.90f, 0.60f);
222 colors[ImGuiCol_CloseButtonActive] = ImVec4(0.70f, 0.70f, 0.70f, 1.00f);
223 colors[ImGuiCol_PlotLines] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
224 colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
225 colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
226 colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
227 colors[ImGuiCol_TextSelectedBg] = ImVec4(0.00f, 0.00f, 1.00f, 0.35f);
228 colors[ImGuiCol_ModalWindowDarkening] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f);
229 colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
230 colors[ImGuiCol_NavHighlight] = colors[ImGuiCol_HeaderHovered];
231 colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);
232 }
233
234 // Those light colors are better suited with a thicker font than the default one + FrameBorder
StyleColorsLight(ImGuiStyle * dst)235 void ImGui::StyleColorsLight(ImGuiStyle* dst)
236 {
237 ImGuiStyle* style = dst ? dst : &ImGui::GetStyle();
238 ImVec4* colors = style->Colors;
239
240 colors[ImGuiCol_Text] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f);
241 colors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f);
242 //colors[ImGuiCol_TextHovered] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
243 //colors[ImGuiCol_TextActive] = ImVec4(1.00f, 1.00f, 0.00f, 1.00f);
244 colors[ImGuiCol_WindowBg] = ImVec4(0.94f, 0.94f, 0.94f, 1.00f);
245 colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
246 colors[ImGuiCol_PopupBg] = ImVec4(1.00f, 1.00f, 1.00f, 0.98f);
247 colors[ImGuiCol_Border] = ImVec4(0.00f, 0.00f, 0.00f, 0.30f);
248 colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
249 colors[ImGuiCol_FrameBg] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
250 colors[ImGuiCol_FrameBgHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);
251 colors[ImGuiCol_FrameBgActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
252 colors[ImGuiCol_TitleBg] = ImVec4(0.96f, 0.96f, 0.96f, 1.00f);
253 colors[ImGuiCol_TitleBgActive] = ImVec4(0.82f, 0.82f, 0.82f, 1.00f);
254 colors[ImGuiCol_TitleBgCollapsed] = ImVec4(1.00f, 1.00f, 1.00f, 0.51f);
255 colors[ImGuiCol_MenuBarBg] = ImVec4(0.86f, 0.86f, 0.86f, 1.00f);
256 colors[ImGuiCol_ScrollbarBg] = ImVec4(0.98f, 0.98f, 0.98f, 0.53f);
257 colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.69f, 0.69f, 0.69f, 0.80f);
258 colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.49f, 0.49f, 0.49f, 0.80f);
259 colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.49f, 0.49f, 0.49f, 1.00f);
260 colors[ImGuiCol_CheckMark] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
261 colors[ImGuiCol_SliderGrab] = ImVec4(0.26f, 0.59f, 0.98f, 0.78f);
262 colors[ImGuiCol_SliderGrabActive] = ImVec4(0.46f, 0.54f, 0.80f, 0.60f);
263 colors[ImGuiCol_Button] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);
264 colors[ImGuiCol_ButtonHovered] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
265 colors[ImGuiCol_ButtonActive] = ImVec4(0.06f, 0.53f, 0.98f, 1.00f);
266 colors[ImGuiCol_Header] = ImVec4(0.26f, 0.59f, 0.98f, 0.31f);
267 colors[ImGuiCol_HeaderHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.80f);
268 colors[ImGuiCol_HeaderActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
269 colors[ImGuiCol_Separator] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f);
270 colors[ImGuiCol_SeparatorHovered] = ImVec4(0.14f, 0.44f, 0.80f, 0.78f);
271 colors[ImGuiCol_SeparatorActive] = ImVec4(0.14f, 0.44f, 0.80f, 1.00f);
272 colors[ImGuiCol_ResizeGrip] = ImVec4(0.80f, 0.80f, 0.80f, 0.56f);
273 colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
274 colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
275 colors[ImGuiCol_CloseButton] = ImVec4(0.59f, 0.59f, 0.59f, 0.50f);
276 colors[ImGuiCol_CloseButtonHovered] = ImVec4(0.98f, 0.39f, 0.36f, 1.00f);
277 colors[ImGuiCol_CloseButtonActive] = ImVec4(0.98f, 0.39f, 0.36f, 1.00f);
278 colors[ImGuiCol_PlotLines] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f);
279 colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
280 colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
281 colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.45f, 0.00f, 1.00f);
282 colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
283 colors[ImGuiCol_ModalWindowDarkening] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f);
284 colors[ImGuiCol_DragDropTarget] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
285 colors[ImGuiCol_NavHighlight] = colors[ImGuiCol_HeaderHovered];
286 colors[ImGuiCol_NavWindowingHighlight] = ImVec4(0.70f, 0.70f, 0.70f, 0.70f);
287 }
288
289 //-----------------------------------------------------------------------------
290 // ImDrawListData
291 //-----------------------------------------------------------------------------
292
ImDrawListSharedData()293 ImDrawListSharedData::ImDrawListSharedData()
294 {
295 Font = NULL;
296 FontSize = 0.0f;
297 CurveTessellationTol = 0.0f;
298 ClipRectFullscreen = ImVec4(-8192.0f, -8192.0f, +8192.0f, +8192.0f);
299
300 // Const data
301 for (int i = 0; i < IM_ARRAYSIZE(CircleVtx12); i++)
302 {
303 const float a = ((float)i * 2 * IM_PI) / (float)IM_ARRAYSIZE(CircleVtx12);
304 CircleVtx12[i] = ImVec2(cosf(a), sinf(a));
305 }
306 }
307
308 //-----------------------------------------------------------------------------
309 // ImDrawList
310 //-----------------------------------------------------------------------------
311
Clear()312 void ImDrawList::Clear()
313 {
314 CmdBuffer.resize(0);
315 IdxBuffer.resize(0);
316 VtxBuffer.resize(0);
317 Flags = ImDrawListFlags_AntiAliasedLines | ImDrawListFlags_AntiAliasedFill;
318 _VtxCurrentIdx = 0;
319 _VtxWritePtr = NULL;
320 _IdxWritePtr = NULL;
321 _ClipRectStack.resize(0);
322 _TextureIdStack.resize(0);
323 _Path.resize(0);
324 _ChannelsCurrent = 0;
325 _ChannelsCount = 1;
326 // NB: Do not clear channels so our allocations are re-used after the first frame.
327 }
328
ClearFreeMemory()329 void ImDrawList::ClearFreeMemory()
330 {
331 CmdBuffer.clear();
332 IdxBuffer.clear();
333 VtxBuffer.clear();
334 _VtxCurrentIdx = 0;
335 _VtxWritePtr = NULL;
336 _IdxWritePtr = NULL;
337 _ClipRectStack.clear();
338 _TextureIdStack.clear();
339 _Path.clear();
340 _ChannelsCurrent = 0;
341 _ChannelsCount = 1;
342 for (int i = 0; i < _Channels.Size; i++)
343 {
344 if (i == 0) memset(&_Channels[0], 0, sizeof(_Channels[0])); // channel 0 is a copy of CmdBuffer/IdxBuffer, don't destruct again
345 _Channels[i].CmdBuffer.clear();
346 _Channels[i].IdxBuffer.clear();
347 }
348 _Channels.clear();
349 }
350
351 // Using macros because C++ is a terrible language, we want guaranteed inline, no code in header, and no overhead in Debug builds
352 #define GetCurrentClipRect() (_ClipRectStack.Size ? _ClipRectStack.Data[_ClipRectStack.Size - 1] : _Data->ClipRectFullscreen)
353 #define GetCurrentTextureId() (_TextureIdStack.Size ? _TextureIdStack.Data[_TextureIdStack.Size - 1] : NULL)
354
AddDrawCmd()355 void ImDrawList::AddDrawCmd()
356 {
357 ImDrawCmd draw_cmd;
358 draw_cmd.ClipRect = GetCurrentClipRect();
359 draw_cmd.TextureId = GetCurrentTextureId();
360
361 IM_ASSERT(draw_cmd.ClipRect.x <= draw_cmd.ClipRect.z && draw_cmd.ClipRect.y <= draw_cmd.ClipRect.w);
362 CmdBuffer.push_back(draw_cmd);
363 }
364
AddCallback(ImDrawCallback callback,void * callback_data)365 void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data)
366 {
367 ImDrawCmd* current_cmd = CmdBuffer.Size ? &CmdBuffer.back() : NULL;
368 if (!current_cmd || current_cmd->ElemCount != 0 || current_cmd->UserCallback != NULL)
369 {
370 AddDrawCmd();
371 current_cmd = &CmdBuffer.back();
372 }
373 current_cmd->UserCallback = callback;
374 current_cmd->UserCallbackData = callback_data;
375
376 AddDrawCmd(); // Force a new command after us (see comment below)
377 }
378
379 // 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.
380 // 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.
UpdateClipRect()381 void ImDrawList::UpdateClipRect()
382 {
383 // If current command is used with different settings we need to add a new command
384 const ImVec4 curr_clip_rect = GetCurrentClipRect();
385 ImDrawCmd* curr_cmd = CmdBuffer.Size > 0 ? &CmdBuffer.Data[CmdBuffer.Size - 1] : NULL;
386 if (!curr_cmd || (curr_cmd->ElemCount != 0 && memcmp(&curr_cmd->ClipRect, &curr_clip_rect, sizeof(ImVec4)) != 0) || curr_cmd->UserCallback != NULL)
387 {
388 AddDrawCmd();
389 return;
390 }
391
392 // Try to merge with previous command if it matches, else use current command
393 ImDrawCmd* prev_cmd = CmdBuffer.Size > 1 ? curr_cmd - 1 : NULL;
394 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)
395 CmdBuffer.pop_back();
396 else
397 curr_cmd->ClipRect = curr_clip_rect;
398 }
399
UpdateTextureID()400 void ImDrawList::UpdateTextureID()
401 {
402 // If current command is used with different settings we need to add a new command
403 const ImTextureID curr_texture_id = GetCurrentTextureId();
404 ImDrawCmd* curr_cmd = CmdBuffer.Size ? &CmdBuffer.back() : NULL;
405 if (!curr_cmd || (curr_cmd->ElemCount != 0 && curr_cmd->TextureId != curr_texture_id) || curr_cmd->UserCallback != NULL)
406 {
407 AddDrawCmd();
408 return;
409 }
410
411 // Try to merge with previous command if it matches, else use current command
412 ImDrawCmd* prev_cmd = CmdBuffer.Size > 1 ? curr_cmd - 1 : NULL;
413 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)
414 CmdBuffer.pop_back();
415 else
416 curr_cmd->TextureId = curr_texture_id;
417 }
418
419 #undef GetCurrentClipRect
420 #undef GetCurrentTextureId
421
422 // 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)
PushClipRect(ImVec2 cr_min,ImVec2 cr_max,bool intersect_with_current_clip_rect)423 void ImDrawList::PushClipRect(ImVec2 cr_min, ImVec2 cr_max, bool intersect_with_current_clip_rect)
424 {
425 ImVec4 cr(cr_min.x, cr_min.y, cr_max.x, cr_max.y);
426 if (intersect_with_current_clip_rect && _ClipRectStack.Size)
427 {
428 ImVec4 current = _ClipRectStack.Data[_ClipRectStack.Size - 1];
429 if (cr.x < current.x) cr.x = current.x;
430 if (cr.y < current.y) cr.y = current.y;
431 if (cr.z > current.z) cr.z = current.z;
432 if (cr.w > current.w) cr.w = current.w;
433 }
434 cr.z = ImMax(cr.x, cr.z);
435 cr.w = ImMax(cr.y, cr.w);
436
437 _ClipRectStack.push_back(cr);
438 UpdateClipRect();
439 }
440
PushClipRectFullScreen()441 void ImDrawList::PushClipRectFullScreen()
442 {
443 PushClipRect(ImVec2(_Data->ClipRectFullscreen.x, _Data->ClipRectFullscreen.y), ImVec2(_Data->ClipRectFullscreen.z, _Data->ClipRectFullscreen.w));
444 }
445
PopClipRect()446 void ImDrawList::PopClipRect()
447 {
448 IM_ASSERT(_ClipRectStack.Size > 0);
449 _ClipRectStack.pop_back();
450 UpdateClipRect();
451 }
452
PushTextureID(ImTextureID texture_id)453 void ImDrawList::PushTextureID(ImTextureID texture_id)
454 {
455 _TextureIdStack.push_back(texture_id);
456 UpdateTextureID();
457 }
458
PopTextureID()459 void ImDrawList::PopTextureID()
460 {
461 IM_ASSERT(_TextureIdStack.Size > 0);
462 _TextureIdStack.pop_back();
463 UpdateTextureID();
464 }
465
ChannelsSplit(int channels_count)466 void ImDrawList::ChannelsSplit(int channels_count)
467 {
468 IM_ASSERT(_ChannelsCurrent == 0 && _ChannelsCount == 1);
469 int old_channels_count = _Channels.Size;
470 if (old_channels_count < channels_count)
471 _Channels.resize(channels_count);
472 _ChannelsCount = channels_count;
473
474 // _Channels[] (24/32 bytes each) hold storage that we'll swap with this->_CmdBuffer/_IdxBuffer
475 // 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.
476 // When we switch to the next channel, we'll copy _CmdBuffer/_IdxBuffer into _Channels[0] and then _Channels[1] into _CmdBuffer/_IdxBuffer
477 memset(&_Channels[0], 0, sizeof(ImDrawChannel));
478 for (int i = 1; i < channels_count; i++)
479 {
480 if (i >= old_channels_count)
481 {
482 IM_PLACEMENT_NEW(&_Channels[i])
483 ImDrawChannel();
484 }
485 else
486 {
487 _Channels[i].CmdBuffer.resize(0);
488 _Channels[i].IdxBuffer.resize(0);
489 }
490 if (_Channels[i].CmdBuffer.Size == 0)
491 {
492 ImDrawCmd draw_cmd;
493 draw_cmd.ClipRect = _ClipRectStack.back();
494 draw_cmd.TextureId = _TextureIdStack.back();
495 _Channels[i].CmdBuffer.push_back(draw_cmd);
496 }
497 }
498 }
499
ChannelsMerge()500 void ImDrawList::ChannelsMerge()
501 {
502 // 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.
503 if (_ChannelsCount <= 1)
504 return;
505
506 ChannelsSetCurrent(0);
507 if (CmdBuffer.Size && CmdBuffer.back().ElemCount == 0)
508 CmdBuffer.pop_back();
509
510 int new_cmd_buffer_count = 0, new_idx_buffer_count = 0;
511 for (int i = 1; i < _ChannelsCount; i++)
512 {
513 ImDrawChannel& ch = _Channels[i];
514 if (ch.CmdBuffer.Size && ch.CmdBuffer.back().ElemCount == 0)
515 ch.CmdBuffer.pop_back();
516 new_cmd_buffer_count += ch.CmdBuffer.Size;
517 new_idx_buffer_count += ch.IdxBuffer.Size;
518 }
519 CmdBuffer.resize(CmdBuffer.Size + new_cmd_buffer_count);
520 IdxBuffer.resize(IdxBuffer.Size + new_idx_buffer_count);
521
522 ImDrawCmd* cmd_write = CmdBuffer.Data + CmdBuffer.Size - new_cmd_buffer_count;
523 _IdxWritePtr = IdxBuffer.Data + IdxBuffer.Size - new_idx_buffer_count;
524 for (int i = 1; i < _ChannelsCount; i++)
525 {
526 ImDrawChannel& ch = _Channels[i];
527 if (int sz = ch.CmdBuffer.Size)
528 {
529 memcpy(cmd_write, ch.CmdBuffer.Data, sz * sizeof(ImDrawCmd));
530 cmd_write += sz;
531 }
532 if (int sz = ch.IdxBuffer.Size)
533 {
534 memcpy(_IdxWritePtr, ch.IdxBuffer.Data, sz * sizeof(ImDrawIdx));
535 _IdxWritePtr += sz;
536 }
537 }
538 UpdateClipRect(); // We call this instead of AddDrawCmd(), so that empty channels won't produce an extra draw call.
539 _ChannelsCount = 1;
540 }
541
ChannelsSetCurrent(int idx)542 void ImDrawList::ChannelsSetCurrent(int idx)
543 {
544 IM_ASSERT(idx < _ChannelsCount);
545 if (_ChannelsCurrent == idx) return;
546 memcpy(&_Channels.Data[_ChannelsCurrent].CmdBuffer, &CmdBuffer, sizeof(CmdBuffer)); // copy 12 bytes, four times
547 memcpy(&_Channels.Data[_ChannelsCurrent].IdxBuffer, &IdxBuffer, sizeof(IdxBuffer));
548 _ChannelsCurrent = idx;
549 memcpy(&CmdBuffer, &_Channels.Data[_ChannelsCurrent].CmdBuffer, sizeof(CmdBuffer));
550 memcpy(&IdxBuffer, &_Channels.Data[_ChannelsCurrent].IdxBuffer, sizeof(IdxBuffer));
551 _IdxWritePtr = IdxBuffer.Data + IdxBuffer.Size;
552 }
553
554 // NB: this can be called with negative count for removing primitives (as long as the result does not underflow)
PrimReserve(int idx_count,int vtx_count)555 void ImDrawList::PrimReserve(int idx_count, int vtx_count)
556 {
557 ImDrawCmd& draw_cmd = CmdBuffer.Data[CmdBuffer.Size - 1];
558 draw_cmd.ElemCount += idx_count;
559
560 int vtx_buffer_old_size = VtxBuffer.Size;
561 VtxBuffer.resize(vtx_buffer_old_size + vtx_count);
562 _VtxWritePtr = VtxBuffer.Data + vtx_buffer_old_size;
563
564 int idx_buffer_old_size = IdxBuffer.Size;
565 IdxBuffer.resize(idx_buffer_old_size + idx_count);
566 _IdxWritePtr = IdxBuffer.Data + idx_buffer_old_size;
567 }
568
569 // Fully unrolled with inline call to keep our debug builds decently fast.
PrimRect(const ImVec2 & a,const ImVec2 & c,ImU32 col)570 void ImDrawList::PrimRect(const ImVec2& a, const ImVec2& c, ImU32 col)
571 {
572 ImVec2 b(c.x, a.y), d(a.x, c.y), uv(_Data->TexUvWhitePixel);
573 ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx;
574 _IdxWritePtr[0] = idx;
575 _IdxWritePtr[1] = (ImDrawIdx)(idx + 1);
576 _IdxWritePtr[2] = (ImDrawIdx)(idx + 2);
577 _IdxWritePtr[3] = idx;
578 _IdxWritePtr[4] = (ImDrawIdx)(idx + 2);
579 _IdxWritePtr[5] = (ImDrawIdx)(idx + 3);
580 _VtxWritePtr[0].pos = a;
581 _VtxWritePtr[0].uv = uv;
582 _VtxWritePtr[0].col = col;
583 _VtxWritePtr[1].pos = b;
584 _VtxWritePtr[1].uv = uv;
585 _VtxWritePtr[1].col = col;
586 _VtxWritePtr[2].pos = c;
587 _VtxWritePtr[2].uv = uv;
588 _VtxWritePtr[2].col = col;
589 _VtxWritePtr[3].pos = d;
590 _VtxWritePtr[3].uv = uv;
591 _VtxWritePtr[3].col = col;
592 _VtxWritePtr += 4;
593 _VtxCurrentIdx += 4;
594 _IdxWritePtr += 6;
595 }
596
PrimRectUV(const ImVec2 & a,const ImVec2 & c,const ImVec2 & uv_a,const ImVec2 & uv_c,ImU32 col)597 void ImDrawList::PrimRectUV(const ImVec2& a, const ImVec2& c, const ImVec2& uv_a, const ImVec2& uv_c, ImU32 col)
598 {
599 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);
600 ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx;
601 _IdxWritePtr[0] = idx;
602 _IdxWritePtr[1] = (ImDrawIdx)(idx + 1);
603 _IdxWritePtr[2] = (ImDrawIdx)(idx + 2);
604 _IdxWritePtr[3] = idx;
605 _IdxWritePtr[4] = (ImDrawIdx)(idx + 2);
606 _IdxWritePtr[5] = (ImDrawIdx)(idx + 3);
607 _VtxWritePtr[0].pos = a;
608 _VtxWritePtr[0].uv = uv_a;
609 _VtxWritePtr[0].col = col;
610 _VtxWritePtr[1].pos = b;
611 _VtxWritePtr[1].uv = uv_b;
612 _VtxWritePtr[1].col = col;
613 _VtxWritePtr[2].pos = c;
614 _VtxWritePtr[2].uv = uv_c;
615 _VtxWritePtr[2].col = col;
616 _VtxWritePtr[3].pos = d;
617 _VtxWritePtr[3].uv = uv_d;
618 _VtxWritePtr[3].col = col;
619 _VtxWritePtr += 4;
620 _VtxCurrentIdx += 4;
621 _IdxWritePtr += 6;
622 }
623
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)624 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)
625 {
626 ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx;
627 _IdxWritePtr[0] = idx;
628 _IdxWritePtr[1] = (ImDrawIdx)(idx + 1);
629 _IdxWritePtr[2] = (ImDrawIdx)(idx + 2);
630 _IdxWritePtr[3] = idx;
631 _IdxWritePtr[4] = (ImDrawIdx)(idx + 2);
632 _IdxWritePtr[5] = (ImDrawIdx)(idx + 3);
633 _VtxWritePtr[0].pos = a;
634 _VtxWritePtr[0].uv = uv_a;
635 _VtxWritePtr[0].col = col;
636 _VtxWritePtr[1].pos = b;
637 _VtxWritePtr[1].uv = uv_b;
638 _VtxWritePtr[1].col = col;
639 _VtxWritePtr[2].pos = c;
640 _VtxWritePtr[2].uv = uv_c;
641 _VtxWritePtr[2].col = col;
642 _VtxWritePtr[3].pos = d;
643 _VtxWritePtr[3].uv = uv_d;
644 _VtxWritePtr[3].col = col;
645 _VtxWritePtr += 4;
646 _VtxCurrentIdx += 4;
647 _IdxWritePtr += 6;
648 }
649
650 // TODO: Thickness anti-aliased lines cap are missing their AA fringe.
AddPolyline(const ImVec2 * points,const int points_count,ImU32 col,bool closed,float thickness)651 void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 col, bool closed, float thickness)
652 {
653 if (points_count < 2)
654 return;
655
656 const ImVec2 uv = _Data->TexUvWhitePixel;
657
658 int count = points_count;
659 if (!closed)
660 count = points_count - 1;
661
662 const bool thick_line = thickness > 1.0f;
663 if (Flags & ImDrawListFlags_AntiAliasedLines)
664 {
665 // Anti-aliased stroke
666 const float AA_SIZE = 1.0f;
667 const ImU32 col_trans = col & ~IM_COL32_A_MASK;
668
669 const int idx_count = thick_line ? count * 18 : count * 12;
670 const int vtx_count = thick_line ? points_count * 4 : points_count * 3;
671 PrimReserve(idx_count, vtx_count);
672
673 // Temporary buffer
674 ImVec2* temp_normals = (ImVec2*)alloca(points_count * (thick_line ? 5 : 3) * sizeof(ImVec2));
675 ImVec2* temp_points = temp_normals + points_count;
676
677 for (int i1 = 0; i1 < count; i1++)
678 {
679 const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1;
680 ImVec2 diff = points[i2] - points[i1];
681 diff *= ImInvLength(diff, 1.0f);
682 temp_normals[i1].x = diff.y;
683 temp_normals[i1].y = -diff.x;
684 }
685 if (!closed)
686 temp_normals[points_count - 1] = temp_normals[points_count - 2];
687
688 if (!thick_line)
689 {
690 if (!closed)
691 {
692 temp_points[0] = points[0] + temp_normals[0] * AA_SIZE;
693 temp_points[1] = points[0] - temp_normals[0] * AA_SIZE;
694 temp_points[(points_count - 1) * 2 + 0] = points[points_count - 1] + temp_normals[points_count - 1] * AA_SIZE;
695 temp_points[(points_count - 1) * 2 + 1] = points[points_count - 1] - temp_normals[points_count - 1] * AA_SIZE;
696 }
697
698 // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer.
699 unsigned int idx1 = _VtxCurrentIdx;
700 for (int i1 = 0; i1 < count; i1++)
701 {
702 const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1;
703 unsigned int idx2 = (i1 + 1) == points_count ? _VtxCurrentIdx : idx1 + 3;
704
705 // Average normals
706 ImVec2 dm = (temp_normals[i1] + temp_normals[i2]) * 0.5f;
707 float dmr2 = dm.x * dm.x + dm.y * dm.y;
708 if (dmr2 > 0.000001f)
709 {
710 float scale = 1.0f / dmr2;
711 if (scale > 100.0f) scale = 100.0f;
712 dm *= scale;
713 }
714 dm *= AA_SIZE;
715 temp_points[i2 * 2 + 0] = points[i2] + dm;
716 temp_points[i2 * 2 + 1] = points[i2] - dm;
717
718 // Add indexes
719 _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 0);
720 _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 0);
721 _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 2);
722 _IdxWritePtr[3] = (ImDrawIdx)(idx1 + 2);
723 _IdxWritePtr[4] = (ImDrawIdx)(idx2 + 2);
724 _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 0);
725 _IdxWritePtr[6] = (ImDrawIdx)(idx2 + 1);
726 _IdxWritePtr[7] = (ImDrawIdx)(idx1 + 1);
727 _IdxWritePtr[8] = (ImDrawIdx)(idx1 + 0);
728 _IdxWritePtr[9] = (ImDrawIdx)(idx1 + 0);
729 _IdxWritePtr[10] = (ImDrawIdx)(idx2 + 0);
730 _IdxWritePtr[11] = (ImDrawIdx)(idx2 + 1);
731 _IdxWritePtr += 12;
732
733 idx1 = idx2;
734 }
735
736 // Add vertexes
737 for (int i = 0; i < points_count; i++)
738 {
739 _VtxWritePtr[0].pos = points[i];
740 _VtxWritePtr[0].uv = uv;
741 _VtxWritePtr[0].col = col;
742 _VtxWritePtr[1].pos = temp_points[i * 2 + 0];
743 _VtxWritePtr[1].uv = uv;
744 _VtxWritePtr[1].col = col_trans;
745 _VtxWritePtr[2].pos = temp_points[i * 2 + 1];
746 _VtxWritePtr[2].uv = uv;
747 _VtxWritePtr[2].col = col_trans;
748 _VtxWritePtr += 3;
749 }
750 }
751 else
752 {
753 const float half_inner_thickness = (thickness - AA_SIZE) * 0.5f;
754 if (!closed)
755 {
756 temp_points[0] = points[0] + temp_normals[0] * (half_inner_thickness + AA_SIZE);
757 temp_points[1] = points[0] + temp_normals[0] * (half_inner_thickness);
758 temp_points[2] = points[0] - temp_normals[0] * (half_inner_thickness);
759 temp_points[3] = points[0] - temp_normals[0] * (half_inner_thickness + AA_SIZE);
760 temp_points[(points_count - 1) * 4 + 0] = points[points_count - 1] + temp_normals[points_count - 1] * (half_inner_thickness + AA_SIZE);
761 temp_points[(points_count - 1) * 4 + 1] = points[points_count - 1] + temp_normals[points_count - 1] * (half_inner_thickness);
762 temp_points[(points_count - 1) * 4 + 2] = points[points_count - 1] - temp_normals[points_count - 1] * (half_inner_thickness);
763 temp_points[(points_count - 1) * 4 + 3] = points[points_count - 1] - temp_normals[points_count - 1] * (half_inner_thickness + AA_SIZE);
764 }
765
766 // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer.
767 unsigned int idx1 = _VtxCurrentIdx;
768 for (int i1 = 0; i1 < count; i1++)
769 {
770 const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1;
771 unsigned int idx2 = (i1 + 1) == points_count ? _VtxCurrentIdx : idx1 + 4;
772
773 // Average normals
774 ImVec2 dm = (temp_normals[i1] + temp_normals[i2]) * 0.5f;
775 float dmr2 = dm.x * dm.x + dm.y * dm.y;
776 if (dmr2 > 0.000001f)
777 {
778 float scale = 1.0f / dmr2;
779 if (scale > 100.0f) scale = 100.0f;
780 dm *= scale;
781 }
782 ImVec2 dm_out = dm * (half_inner_thickness + AA_SIZE);
783 ImVec2 dm_in = dm * half_inner_thickness;
784 temp_points[i2 * 4 + 0] = points[i2] + dm_out;
785 temp_points[i2 * 4 + 1] = points[i2] + dm_in;
786 temp_points[i2 * 4 + 2] = points[i2] - dm_in;
787 temp_points[i2 * 4 + 3] = points[i2] - dm_out;
788
789 // Add indexes
790 _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 1);
791 _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 1);
792 _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 2);
793 _IdxWritePtr[3] = (ImDrawIdx)(idx1 + 2);
794 _IdxWritePtr[4] = (ImDrawIdx)(idx2 + 2);
795 _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 1);
796 _IdxWritePtr[6] = (ImDrawIdx)(idx2 + 1);
797 _IdxWritePtr[7] = (ImDrawIdx)(idx1 + 1);
798 _IdxWritePtr[8] = (ImDrawIdx)(idx1 + 0);
799 _IdxWritePtr[9] = (ImDrawIdx)(idx1 + 0);
800 _IdxWritePtr[10] = (ImDrawIdx)(idx2 + 0);
801 _IdxWritePtr[11] = (ImDrawIdx)(idx2 + 1);
802 _IdxWritePtr[12] = (ImDrawIdx)(idx2 + 2);
803 _IdxWritePtr[13] = (ImDrawIdx)(idx1 + 2);
804 _IdxWritePtr[14] = (ImDrawIdx)(idx1 + 3);
805 _IdxWritePtr[15] = (ImDrawIdx)(idx1 + 3);
806 _IdxWritePtr[16] = (ImDrawIdx)(idx2 + 3);
807 _IdxWritePtr[17] = (ImDrawIdx)(idx2 + 2);
808 _IdxWritePtr += 18;
809
810 idx1 = idx2;
811 }
812
813 // Add vertexes
814 for (int i = 0; i < points_count; i++)
815 {
816 _VtxWritePtr[0].pos = temp_points[i * 4 + 0];
817 _VtxWritePtr[0].uv = uv;
818 _VtxWritePtr[0].col = col_trans;
819 _VtxWritePtr[1].pos = temp_points[i * 4 + 1];
820 _VtxWritePtr[1].uv = uv;
821 _VtxWritePtr[1].col = col;
822 _VtxWritePtr[2].pos = temp_points[i * 4 + 2];
823 _VtxWritePtr[2].uv = uv;
824 _VtxWritePtr[2].col = col;
825 _VtxWritePtr[3].pos = temp_points[i * 4 + 3];
826 _VtxWritePtr[3].uv = uv;
827 _VtxWritePtr[3].col = col_trans;
828 _VtxWritePtr += 4;
829 }
830 }
831 _VtxCurrentIdx += (ImDrawIdx)vtx_count;
832 }
833 else
834 {
835 // Non Anti-aliased Stroke
836 const int idx_count = count * 6;
837 const int vtx_count = count * 4; // FIXME-OPT: Not sharing edges
838 PrimReserve(idx_count, vtx_count);
839
840 for (int i1 = 0; i1 < count; i1++)
841 {
842 const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1;
843 const ImVec2& p1 = points[i1];
844 const ImVec2& p2 = points[i2];
845 ImVec2 diff = p2 - p1;
846 diff *= ImInvLength(diff, 1.0f);
847
848 const float dx = diff.x * (thickness * 0.5f);
849 const float dy = diff.y * (thickness * 0.5f);
850 _VtxWritePtr[0].pos.x = p1.x + dy;
851 _VtxWritePtr[0].pos.y = p1.y - dx;
852 _VtxWritePtr[0].uv = uv;
853 _VtxWritePtr[0].col = col;
854 _VtxWritePtr[1].pos.x = p2.x + dy;
855 _VtxWritePtr[1].pos.y = p2.y - dx;
856 _VtxWritePtr[1].uv = uv;
857 _VtxWritePtr[1].col = col;
858 _VtxWritePtr[2].pos.x = p2.x - dy;
859 _VtxWritePtr[2].pos.y = p2.y + dx;
860 _VtxWritePtr[2].uv = uv;
861 _VtxWritePtr[2].col = col;
862 _VtxWritePtr[3].pos.x = p1.x - dy;
863 _VtxWritePtr[3].pos.y = p1.y + dx;
864 _VtxWritePtr[3].uv = uv;
865 _VtxWritePtr[3].col = col;
866 _VtxWritePtr += 4;
867
868 _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx);
869 _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx + 1);
870 _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx + 2);
871 _IdxWritePtr[3] = (ImDrawIdx)(_VtxCurrentIdx);
872 _IdxWritePtr[4] = (ImDrawIdx)(_VtxCurrentIdx + 2);
873 _IdxWritePtr[5] = (ImDrawIdx)(_VtxCurrentIdx + 3);
874 _IdxWritePtr += 6;
875 _VtxCurrentIdx += 4;
876 }
877 }
878 }
879
AddConvexPolyFilled(const ImVec2 * points,const int points_count,ImU32 col)880 void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_count, ImU32 col)
881 {
882 const ImVec2 uv = _Data->TexUvWhitePixel;
883
884 if (Flags & ImDrawListFlags_AntiAliasedFill)
885 {
886 // Anti-aliased Fill
887 const float AA_SIZE = 1.0f;
888 const ImU32 col_trans = col & ~IM_COL32_A_MASK;
889 const int idx_count = (points_count - 2) * 3 + points_count * 6;
890 const int vtx_count = (points_count * 2);
891 PrimReserve(idx_count, vtx_count);
892
893 // Add indexes for fill
894 unsigned int vtx_inner_idx = _VtxCurrentIdx;
895 unsigned int vtx_outer_idx = _VtxCurrentIdx + 1;
896 for (int i = 2; i < points_count; i++)
897 {
898 _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx);
899 _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + ((i - 1) << 1));
900 _IdxWritePtr[2] = (ImDrawIdx)(vtx_inner_idx + (i << 1));
901 _IdxWritePtr += 3;
902 }
903
904 // Compute normals
905 ImVec2* temp_normals = (ImVec2*)alloca(points_count * sizeof(ImVec2));
906 for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++)
907 {
908 const ImVec2& p0 = points[i0];
909 const ImVec2& p1 = points[i1];
910 ImVec2 diff = p1 - p0;
911 diff *= ImInvLength(diff, 1.0f);
912 temp_normals[i0].x = diff.y;
913 temp_normals[i0].y = -diff.x;
914 }
915
916 for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++)
917 {
918 // Average normals
919 const ImVec2& n0 = temp_normals[i0];
920 const ImVec2& n1 = temp_normals[i1];
921 ImVec2 dm = (n0 + n1) * 0.5f;
922 float dmr2 = dm.x * dm.x + dm.y * dm.y;
923 if (dmr2 > 0.000001f)
924 {
925 float scale = 1.0f / dmr2;
926 if (scale > 100.0f) scale = 100.0f;
927 dm *= scale;
928 }
929 dm *= AA_SIZE * 0.5f;
930
931 // Add vertices
932 _VtxWritePtr[0].pos = (points[i1] - dm);
933 _VtxWritePtr[0].uv = uv;
934 _VtxWritePtr[0].col = col; // Inner
935 _VtxWritePtr[1].pos = (points[i1] + dm);
936 _VtxWritePtr[1].uv = uv;
937 _VtxWritePtr[1].col = col_trans; // Outer
938 _VtxWritePtr += 2;
939
940 // Add indexes for fringes
941 _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1));
942 _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + (i0 << 1));
943 _IdxWritePtr[2] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1));
944 _IdxWritePtr[3] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1));
945 _IdxWritePtr[4] = (ImDrawIdx)(vtx_outer_idx + (i1 << 1));
946 _IdxWritePtr[5] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1));
947 _IdxWritePtr += 6;
948 }
949 _VtxCurrentIdx += (ImDrawIdx)vtx_count;
950 }
951 else
952 {
953 // Non Anti-aliased Fill
954 const int idx_count = (points_count - 2) * 3;
955 const int vtx_count = points_count;
956 PrimReserve(idx_count, vtx_count);
957 for (int i = 0; i < vtx_count; i++)
958 {
959 _VtxWritePtr[0].pos = points[i];
960 _VtxWritePtr[0].uv = uv;
961 _VtxWritePtr[0].col = col;
962 _VtxWritePtr++;
963 }
964 for (int i = 2; i < points_count; i++)
965 {
966 _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx);
967 _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx + i - 1);
968 _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx + i);
969 _IdxWritePtr += 3;
970 }
971 _VtxCurrentIdx += (ImDrawIdx)vtx_count;
972 }
973 }
974
PathArcToFast(const ImVec2 & centre,float radius,int a_min_of_12,int a_max_of_12)975 void ImDrawList::PathArcToFast(const ImVec2& centre, float radius, int a_min_of_12, int a_max_of_12)
976 {
977 if (radius == 0.0f || a_min_of_12 > a_max_of_12)
978 {
979 _Path.push_back(centre);
980 return;
981 }
982 _Path.reserve(_Path.Size + (a_max_of_12 - a_min_of_12 + 1));
983 for (int a = a_min_of_12; a <= a_max_of_12; a++)
984 {
985 const ImVec2& c = _Data->CircleVtx12[a % IM_ARRAYSIZE(_Data->CircleVtx12)];
986 _Path.push_back(ImVec2(centre.x + c.x * radius, centre.y + c.y * radius));
987 }
988 }
989
PathArcTo(const ImVec2 & centre,float radius,float a_min,float a_max,int num_segments)990 void ImDrawList::PathArcTo(const ImVec2& centre, float radius, float a_min, float a_max, int num_segments)
991 {
992 if (radius == 0.0f)
993 {
994 _Path.push_back(centre);
995 return;
996 }
997 _Path.reserve(_Path.Size + (num_segments + 1));
998 for (int i = 0; i <= num_segments; i++)
999 {
1000 const float a = a_min + ((float)i / (float)num_segments) * (a_max - a_min);
1001 _Path.push_back(ImVec2(centre.x + cosf(a) * radius, centre.y + sinf(a) * radius));
1002 }
1003 }
1004
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)1005 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)
1006 {
1007 float dx = x4 - x1;
1008 float dy = y4 - y1;
1009 float d2 = ((x2 - x4) * dy - (y2 - y4) * dx);
1010 float d3 = ((x3 - x4) * dy - (y3 - y4) * dx);
1011 d2 = (d2 >= 0) ? d2 : -d2;
1012 d3 = (d3 >= 0) ? d3 : -d3;
1013 if ((d2 + d3) * (d2 + d3) < tess_tol * (dx * dx + dy * dy))
1014 {
1015 path->push_back(ImVec2(x4, y4));
1016 }
1017 else if (level < 10)
1018 {
1019 float x12 = (x1 + x2) * 0.5f, y12 = (y1 + y2) * 0.5f;
1020 float x23 = (x2 + x3) * 0.5f, y23 = (y2 + y3) * 0.5f;
1021 float x34 = (x3 + x4) * 0.5f, y34 = (y3 + y4) * 0.5f;
1022 float x123 = (x12 + x23) * 0.5f, y123 = (y12 + y23) * 0.5f;
1023 float x234 = (x23 + x34) * 0.5f, y234 = (y23 + y34) * 0.5f;
1024 float x1234 = (x123 + x234) * 0.5f, y1234 = (y123 + y234) * 0.5f;
1025
1026 PathBezierToCasteljau(path, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1);
1027 PathBezierToCasteljau(path, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1);
1028 }
1029 }
1030
PathBezierCurveTo(const ImVec2 & p2,const ImVec2 & p3,const ImVec2 & p4,int num_segments)1031 void ImDrawList::PathBezierCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments)
1032 {
1033 ImVec2 p1 = _Path.back();
1034 if (num_segments == 0)
1035 {
1036 // Auto-tessellated
1037 PathBezierToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, _Data->CurveTessellationTol, 0);
1038 }
1039 else
1040 {
1041 float t_step = 1.0f / (float)num_segments;
1042 for (int i_step = 1; i_step <= num_segments; i_step++)
1043 {
1044 float t = t_step * i_step;
1045 float u = 1.0f - t;
1046 float w1 = u * u * u;
1047 float w2 = 3 * u * u * t;
1048 float w3 = 3 * u * t * t;
1049 float w4 = t * t * t;
1050 _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));
1051 }
1052 }
1053 }
1054
PathRect(const ImVec2 & a,const ImVec2 & b,float rounding,int rounding_corners)1055 void ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, int rounding_corners)
1056 {
1057 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);
1058 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);
1059
1060 if (rounding <= 0.0f || rounding_corners == 0)
1061 {
1062 PathLineTo(a);
1063 PathLineTo(ImVec2(b.x, a.y));
1064 PathLineTo(b);
1065 PathLineTo(ImVec2(a.x, b.y));
1066 }
1067 else
1068 {
1069 const float rounding_tl = (rounding_corners & ImDrawCornerFlags_TopLeft) ? rounding : 0.0f;
1070 const float rounding_tr = (rounding_corners & ImDrawCornerFlags_TopRight) ? rounding : 0.0f;
1071 const float rounding_br = (rounding_corners & ImDrawCornerFlags_BotRight) ? rounding : 0.0f;
1072 const float rounding_bl = (rounding_corners & ImDrawCornerFlags_BotLeft) ? rounding : 0.0f;
1073 PathArcToFast(ImVec2(a.x + rounding_tl, a.y + rounding_tl), rounding_tl, 6, 9);
1074 PathArcToFast(ImVec2(b.x - rounding_tr, a.y + rounding_tr), rounding_tr, 9, 12);
1075 PathArcToFast(ImVec2(b.x - rounding_br, b.y - rounding_br), rounding_br, 0, 3);
1076 PathArcToFast(ImVec2(a.x + rounding_bl, b.y - rounding_bl), rounding_bl, 3, 6);
1077 }
1078 }
1079
AddLine(const ImVec2 & a,const ImVec2 & b,ImU32 col,float thickness)1080 void ImDrawList::AddLine(const ImVec2& a, const ImVec2& b, ImU32 col, float thickness)
1081 {
1082 if ((col & IM_COL32_A_MASK) == 0)
1083 return;
1084 PathLineTo(a + ImVec2(0.5f, 0.5f));
1085 PathLineTo(b + ImVec2(0.5f, 0.5f));
1086 PathStroke(col, false, thickness);
1087 }
1088
1089 // a: upper-left, b: lower-right. we don't render 1 px sized rectangles properly.
AddRect(const ImVec2 & a,const ImVec2 & b,ImU32 col,float rounding,int rounding_corners_flags,float thickness)1090 void ImDrawList::AddRect(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding, int rounding_corners_flags, float thickness)
1091 {
1092 if ((col & IM_COL32_A_MASK) == 0)
1093 return;
1094 PathRect(a + ImVec2(0.5f, 0.5f), b - ImVec2(0.5f, 0.5f), rounding, rounding_corners_flags);
1095 PathStroke(col, true, thickness);
1096 }
1097
AddRectFilled(const ImVec2 & a,const ImVec2 & b,ImU32 col,float rounding,int rounding_corners_flags)1098 void ImDrawList::AddRectFilled(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding, int rounding_corners_flags)
1099 {
1100 if ((col & IM_COL32_A_MASK) == 0)
1101 return;
1102 if (rounding > 0.0f)
1103 {
1104 PathRect(a, b, rounding, rounding_corners_flags);
1105 PathFillConvex(col);
1106 }
1107 else
1108 {
1109 PrimReserve(6, 4);
1110 PrimRect(a, b, col);
1111 }
1112 }
1113
AddRectFilledMultiColor(const ImVec2 & a,const ImVec2 & c,ImU32 col_upr_left,ImU32 col_upr_right,ImU32 col_bot_right,ImU32 col_bot_left)1114 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)
1115 {
1116 if (((col_upr_left | col_upr_right | col_bot_right | col_bot_left) & IM_COL32_A_MASK) == 0)
1117 return;
1118
1119 const ImVec2 uv = _Data->TexUvWhitePixel;
1120 PrimReserve(6, 4);
1121 PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx));
1122 PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 1));
1123 PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 2));
1124 PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx));
1125 PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 2));
1126 PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 3));
1127 PrimWriteVtx(a, uv, col_upr_left);
1128 PrimWriteVtx(ImVec2(c.x, a.y), uv, col_upr_right);
1129 PrimWriteVtx(c, uv, col_bot_right);
1130 PrimWriteVtx(ImVec2(a.x, c.y), uv, col_bot_left);
1131 }
1132
AddQuad(const ImVec2 & a,const ImVec2 & b,const ImVec2 & c,const ImVec2 & d,ImU32 col,float thickness)1133 void ImDrawList::AddQuad(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, ImU32 col, float thickness)
1134 {
1135 if ((col & IM_COL32_A_MASK) == 0)
1136 return;
1137
1138 PathLineTo(a);
1139 PathLineTo(b);
1140 PathLineTo(c);
1141 PathLineTo(d);
1142 PathStroke(col, true, thickness);
1143 }
1144
AddQuadFilled(const ImVec2 & a,const ImVec2 & b,const ImVec2 & c,const ImVec2 & d,ImU32 col)1145 void ImDrawList::AddQuadFilled(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, ImU32 col)
1146 {
1147 if ((col & IM_COL32_A_MASK) == 0)
1148 return;
1149
1150 PathLineTo(a);
1151 PathLineTo(b);
1152 PathLineTo(c);
1153 PathLineTo(d);
1154 PathFillConvex(col);
1155 }
1156
AddTriangle(const ImVec2 & a,const ImVec2 & b,const ImVec2 & c,ImU32 col,float thickness)1157 void ImDrawList::AddTriangle(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col, float thickness)
1158 {
1159 if ((col & IM_COL32_A_MASK) == 0)
1160 return;
1161
1162 PathLineTo(a);
1163 PathLineTo(b);
1164 PathLineTo(c);
1165 PathStroke(col, true, thickness);
1166 }
1167
AddTriangleFilled(const ImVec2 & a,const ImVec2 & b,const ImVec2 & c,ImU32 col)1168 void ImDrawList::AddTriangleFilled(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col)
1169 {
1170 if ((col & IM_COL32_A_MASK) == 0)
1171 return;
1172
1173 PathLineTo(a);
1174 PathLineTo(b);
1175 PathLineTo(c);
1176 PathFillConvex(col);
1177 }
1178
AddCircle(const ImVec2 & centre,float radius,ImU32 col,int num_segments,float thickness)1179 void ImDrawList::AddCircle(const ImVec2& centre, float radius, ImU32 col, int num_segments, float thickness)
1180 {
1181 if ((col & IM_COL32_A_MASK) == 0)
1182 return;
1183
1184 const float a_max = IM_PI * 2.0f * ((float)num_segments - 1.0f) / (float)num_segments;
1185 PathArcTo(centre, radius - 0.5f, 0.0f, a_max, num_segments);
1186 PathStroke(col, true, thickness);
1187 }
1188
AddCircleFilled(const ImVec2 & centre,float radius,ImU32 col,int num_segments)1189 void ImDrawList::AddCircleFilled(const ImVec2& centre, float radius, ImU32 col, int num_segments)
1190 {
1191 if ((col & IM_COL32_A_MASK) == 0)
1192 return;
1193
1194 const float a_max = IM_PI * 2.0f * ((float)num_segments - 1.0f) / (float)num_segments;
1195 PathArcTo(centre, radius, 0.0f, a_max, num_segments);
1196 PathFillConvex(col);
1197 }
1198
AddBezierCurve(const ImVec2 & pos0,const ImVec2 & cp0,const ImVec2 & cp1,const ImVec2 & pos1,ImU32 col,float thickness,int num_segments)1199 void ImDrawList::AddBezierCurve(const ImVec2& pos0, const ImVec2& cp0, const ImVec2& cp1, const ImVec2& pos1, ImU32 col, float thickness, int num_segments)
1200 {
1201 if ((col & IM_COL32_A_MASK) == 0)
1202 return;
1203
1204 PathLineTo(pos0);
1205 PathBezierCurveTo(cp0, cp1, pos1, num_segments);
1206 PathStroke(col, false, thickness);
1207 }
1208
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)1209 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)
1210 {
1211 if ((col & IM_COL32_A_MASK) == 0)
1212 return;
1213
1214 if (text_end == NULL)
1215 text_end = text_begin + strlen(text_begin);
1216 if (text_begin == text_end)
1217 return;
1218
1219 // Pull default font/size from the shared ImDrawListSharedData instance
1220 if (font == NULL)
1221 font = _Data->Font;
1222 if (font_size == 0.0f)
1223 font_size = _Data->FontSize;
1224
1225 IM_ASSERT(font->ContainerAtlas->TexID == _TextureIdStack.back()); // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font.
1226
1227 ImVec4 clip_rect = _ClipRectStack.back();
1228 if (cpu_fine_clip_rect)
1229 {
1230 clip_rect.x = ImMax(clip_rect.x, cpu_fine_clip_rect->x);
1231 clip_rect.y = ImMax(clip_rect.y, cpu_fine_clip_rect->y);
1232 clip_rect.z = ImMin(clip_rect.z, cpu_fine_clip_rect->z);
1233 clip_rect.w = ImMin(clip_rect.w, cpu_fine_clip_rect->w);
1234 }
1235 font->RenderText(this, font_size, pos, col, clip_rect, text_begin, text_end, wrap_width, cpu_fine_clip_rect != NULL);
1236 }
1237
AddText(const ImVec2 & pos,ImU32 col,const char * text_begin,const char * text_end)1238 void ImDrawList::AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end)
1239 {
1240 AddText(NULL, 0.0f, pos, col, text_begin, text_end);
1241 }
1242
AddImage(ImTextureID user_texture_id,const ImVec2 & a,const ImVec2 & b,const ImVec2 & uv_a,const ImVec2 & uv_b,ImU32 col)1243 void ImDrawList::AddImage(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col)
1244 {
1245 if ((col & IM_COL32_A_MASK) == 0)
1246 return;
1247
1248 const bool push_texture_id = _TextureIdStack.empty() || user_texture_id != _TextureIdStack.back();
1249 if (push_texture_id)
1250 PushTextureID(user_texture_id);
1251
1252 PrimReserve(6, 4);
1253 PrimRectUV(a, b, uv_a, uv_b, col);
1254
1255 if (push_texture_id)
1256 PopTextureID();
1257 }
1258
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)1259 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)
1260 {
1261 if ((col & IM_COL32_A_MASK) == 0)
1262 return;
1263
1264 const bool push_texture_id = _TextureIdStack.empty() || user_texture_id != _TextureIdStack.back();
1265 if (push_texture_id)
1266 PushTextureID(user_texture_id);
1267
1268 PrimReserve(6, 4);
1269 PrimQuadUV(a, b, c, d, uv_a, uv_b, uv_c, uv_d, col);
1270
1271 if (push_texture_id)
1272 PopTextureID();
1273 }
1274
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)1275 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)
1276 {
1277 if ((col & IM_COL32_A_MASK) == 0)
1278 return;
1279
1280 if (rounding <= 0.0f || (rounding_corners & ImDrawCornerFlags_All) == 0)
1281 {
1282 AddImage(user_texture_id, a, b, uv_a, uv_b, col);
1283 return;
1284 }
1285
1286 const bool push_texture_id = _TextureIdStack.empty() || user_texture_id != _TextureIdStack.back();
1287 if (push_texture_id)
1288 PushTextureID(user_texture_id);
1289
1290 int vert_start_idx = VtxBuffer.Size;
1291 PathRect(a, b, rounding, rounding_corners);
1292 PathFillConvex(col);
1293 int vert_end_idx = VtxBuffer.Size;
1294 ImGui::ShadeVertsLinearUV(VtxBuffer.Data + vert_start_idx, VtxBuffer.Data + vert_end_idx, a, b, uv_a, uv_b, true);
1295
1296 if (push_texture_id)
1297 PopTextureID();
1298 }
1299
1300 //-----------------------------------------------------------------------------
1301 // ImDrawData
1302 //-----------------------------------------------------------------------------
1303
1304 // 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!
DeIndexAllBuffers()1305 void ImDrawData::DeIndexAllBuffers()
1306 {
1307 ImVector<ImDrawVert> new_vtx_buffer;
1308 TotalVtxCount = TotalIdxCount = 0;
1309 for (int i = 0; i < CmdListsCount; i++)
1310 {
1311 ImDrawList* cmd_list = CmdLists[i];
1312 if (cmd_list->IdxBuffer.empty())
1313 continue;
1314 new_vtx_buffer.resize(cmd_list->IdxBuffer.Size);
1315 for (int j = 0; j < cmd_list->IdxBuffer.Size; j++)
1316 new_vtx_buffer[j] = cmd_list->VtxBuffer[cmd_list->IdxBuffer[j]];
1317 cmd_list->VtxBuffer.swap(new_vtx_buffer);
1318 cmd_list->IdxBuffer.resize(0);
1319 TotalVtxCount += cmd_list->VtxBuffer.Size;
1320 }
1321 }
1322
1323 // 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.
ScaleClipRects(const ImVec2 & scale)1324 void ImDrawData::ScaleClipRects(const ImVec2& scale)
1325 {
1326 for (int i = 0; i < CmdListsCount; i++)
1327 {
1328 ImDrawList* cmd_list = CmdLists[i];
1329 for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
1330 {
1331 ImDrawCmd* cmd = &cmd_list->CmdBuffer[cmd_i];
1332 cmd->ClipRect = ImVec4(cmd->ClipRect.x * scale.x, cmd->ClipRect.y * scale.y, cmd->ClipRect.z * scale.x, cmd->ClipRect.w * scale.y);
1333 }
1334 }
1335 }
1336
1337 //-----------------------------------------------------------------------------
1338 // Shade functions
1339 //-----------------------------------------------------------------------------
1340
1341 // Generic linear color gradient, write to RGB fields, leave A untouched.
ShadeVertsLinearColorGradientKeepAlpha(ImDrawVert * vert_start,ImDrawVert * vert_end,ImVec2 gradient_p0,ImVec2 gradient_p1,ImU32 col0,ImU32 col1)1342 void ImGui::ShadeVertsLinearColorGradientKeepAlpha(ImDrawVert* vert_start, ImDrawVert* vert_end, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1)
1343 {
1344 ImVec2 gradient_extent = gradient_p1 - gradient_p0;
1345 float gradient_inv_length2 = 1.0f / ImLengthSqr(gradient_extent);
1346 for (ImDrawVert* vert = vert_start; vert < vert_end; vert++)
1347 {
1348 float d = ImDot(vert->pos - gradient_p0, gradient_extent);
1349 float t = ImClamp(d * gradient_inv_length2, 0.0f, 1.0f);
1350 int r = ImLerp((int)(col0 >> IM_COL32_R_SHIFT) & 0xFF, (int)(col1 >> IM_COL32_R_SHIFT) & 0xFF, t);
1351 int g = ImLerp((int)(col0 >> IM_COL32_G_SHIFT) & 0xFF, (int)(col1 >> IM_COL32_G_SHIFT) & 0xFF, t);
1352 int b = ImLerp((int)(col0 >> IM_COL32_B_SHIFT) & 0xFF, (int)(col1 >> IM_COL32_B_SHIFT) & 0xFF, t);
1353 vert->col = (r << IM_COL32_R_SHIFT) | (g << IM_COL32_G_SHIFT) | (b << IM_COL32_B_SHIFT) | (vert->col & IM_COL32_A_MASK);
1354 }
1355 }
1356
1357 // 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.
ShadeVertsLinearAlphaGradientForLeftToRightText(ImDrawVert * vert_start,ImDrawVert * vert_end,float gradient_p0_x,float gradient_p1_x)1358 void ImGui::ShadeVertsLinearAlphaGradientForLeftToRightText(ImDrawVert* vert_start, ImDrawVert* vert_end, float gradient_p0_x, float gradient_p1_x)
1359 {
1360 float gradient_extent_x = gradient_p1_x - gradient_p0_x;
1361 float gradient_inv_length2 = 1.0f / (gradient_extent_x * gradient_extent_x);
1362 int full_alpha_count = 0;
1363 for (ImDrawVert* vert = vert_end - 1; vert >= vert_start; vert--)
1364 {
1365 float d = (vert->pos.x - gradient_p0_x) * (gradient_extent_x);
1366 float alpha_mul = 1.0f - ImClamp(d * gradient_inv_length2, 0.0f, 1.0f);
1367 if (alpha_mul >= 1.0f && ++full_alpha_count > 2)
1368 return; // Early out
1369 int a = (int)(((vert->col >> IM_COL32_A_SHIFT) & 0xFF) * alpha_mul);
1370 vert->col = (vert->col & ~IM_COL32_A_MASK) | (a << IM_COL32_A_SHIFT);
1371 }
1372 }
1373
1374 // Distribute UV over (a, b) rectangle
ShadeVertsLinearUV(ImDrawVert * vert_start,ImDrawVert * vert_end,const ImVec2 & a,const ImVec2 & b,const ImVec2 & uv_a,const ImVec2 & uv_b,bool clamp)1375 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)
1376 {
1377 const ImVec2 size = b - a;
1378 const ImVec2 uv_size = uv_b - uv_a;
1379 const ImVec2 scale = ImVec2(
1380 size.x != 0.0f ? (uv_size.x / size.x) : 0.0f,
1381 size.y != 0.0f ? (uv_size.y / size.y) : 0.0f);
1382
1383 if (clamp)
1384 {
1385 const ImVec2 min = ImMin(uv_a, uv_b);
1386 const ImVec2 max = ImMax(uv_a, uv_b);
1387
1388 for (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex)
1389 vertex->uv = ImClamp(uv_a + ImMul(ImVec2(vertex->pos.x, vertex->pos.y) - a, scale), min, max);
1390 }
1391 else
1392 {
1393 for (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex)
1394 vertex->uv = uv_a + ImMul(ImVec2(vertex->pos.x, vertex->pos.y) - a, scale);
1395 }
1396 }
1397
1398 //-----------------------------------------------------------------------------
1399 // ImFontConfig
1400 //-----------------------------------------------------------------------------
1401
ImFontConfig()1402 ImFontConfig::ImFontConfig()
1403 {
1404 FontData = NULL;
1405 FontDataSize = 0;
1406 FontDataOwnedByAtlas = true;
1407 FontNo = 0;
1408 SizePixels = 0.0f;
1409 OversampleH = 3;
1410 OversampleV = 1;
1411 PixelSnapH = false;
1412 GlyphExtraSpacing = ImVec2(0.0f, 0.0f);
1413 GlyphOffset = ImVec2(0.0f, 0.0f);
1414 GlyphRanges = NULL;
1415 MergeMode = false;
1416 RasterizerFlags = 0x00;
1417 RasterizerMultiply = 1.0f;
1418 memset(Name, 0, sizeof(Name));
1419 DstFont = NULL;
1420 }
1421
1422 //-----------------------------------------------------------------------------
1423 // ImFontAtlas
1424 //-----------------------------------------------------------------------------
1425
1426 // A work of art lies ahead! (. = white layer, X = black layer, others are blank)
1427 // The white texels on the top left are the ones we'll use everywhere in ImGui to render filled shapes.
1428 const int FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF = 90;
1429 const int FONT_ATLAS_DEFAULT_TEX_DATA_H = 27;
1430 const unsigned int FONT_ATLAS_DEFAULT_TEX_DATA_ID = 0x80000000;
1431 static const char FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF * FONT_ATLAS_DEFAULT_TEX_DATA_H + 1] =
1432 {
1433 "..- -XXXXXXX- X - X -XXXXXXX - XXXXXXX"
1434 "..- -X.....X- X.X - X.X -X.....X - X.....X"
1435 "--- -XXX.XXX- X...X - X...X -X....X - X....X"
1436 "X - X.X - X.....X - X.....X -X...X - X...X"
1437 "XX - X.X -X.......X- X.......X -X..X.X - X.X..X"
1438 "X.X - X.X -XXXX.XXXX- XXXX.XXXX -X.X X.X - X.X X.X"
1439 "X..X - X.X - X.X - X.X -XX X.X - X.X XX"
1440 "X...X - X.X - X.X - XX X.X XX - X.X - X.X "
1441 "X....X - X.X - X.X - X.X X.X X.X - X.X - X.X "
1442 "X.....X - X.X - X.X - X..X X.X X..X - X.X - X.X "
1443 "X......X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X XX-XX X.X "
1444 "X.......X - X.X - X.X -X.....................X- X.X X.X-X.X X.X "
1445 "X........X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X..X-X..X.X "
1446 "X.........X -XXX.XXX- X.X - X..X X.X X..X - X...X-X...X "
1447 "X..........X-X.....X- X.X - X.X X.X X.X - X....X-X....X "
1448 "X......XXXXX-XXXXXXX- X.X - XX X.X XX - X.....X-X.....X "
1449 "X...X..X --------- X.X - X.X - XXXXXXX-XXXXXXX "
1450 "X..X X..X - -XXXX.XXXX- XXXX.XXXX ------------------------------------"
1451 "X.X X..X - -X.......X- X.......X - XX XX - "
1452 "XX X..X - - X.....X - X.....X - X.X X.X - "
1453 " X..X - X...X - X...X - X..X X..X - "
1454 " XX - X.X - X.X - X...XXXXXXXXXXXXX...X - "
1455 "------------ - X - X -X.....................X- "
1456 " ----------------------------------- X...XXXXXXXXXXXXX...X - "
1457 " - X..X X..X - "
1458 " - X.X X.X - "
1459 " - XX XX - "};
1460
1461 static const ImVec2 FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[ImGuiMouseCursor_Count_][3] =
1462 {
1463 // Pos ........ Size ......... Offset ......
1464 {ImVec2(0, 3), ImVec2(12, 19), ImVec2(0, 0)}, // ImGuiMouseCursor_Arrow
1465 {ImVec2(13, 0), ImVec2(7, 16), ImVec2(4, 8)}, // ImGuiMouseCursor_TextInput
1466 {ImVec2(31, 0), ImVec2(23, 23), ImVec2(11, 11)}, // ImGuiMouseCursor_ResizeAll
1467 {ImVec2(21, 0), ImVec2(9, 23), ImVec2(5, 11)}, // ImGuiMouseCursor_ResizeNS
1468 {ImVec2(55, 18), ImVec2(23, 9), ImVec2(11, 5)}, // ImGuiMouseCursor_ResizeEW
1469 {ImVec2(73, 0), ImVec2(17, 17), ImVec2(9, 9)}, // ImGuiMouseCursor_ResizeNESW
1470 {ImVec2(55, 0), ImVec2(17, 17), ImVec2(9, 9)}, // ImGuiMouseCursor_ResizeNWSE
1471 };
1472
ImFontAtlas()1473 ImFontAtlas::ImFontAtlas()
1474 {
1475 Flags = 0x00;
1476 TexID = NULL;
1477 TexDesiredWidth = 0;
1478 TexGlyphPadding = 1;
1479
1480 TexPixelsAlpha8 = NULL;
1481 TexPixelsRGBA32 = NULL;
1482 TexWidth = TexHeight = 0;
1483 TexUvScale = ImVec2(0.0f, 0.0f);
1484 TexUvWhitePixel = ImVec2(0.0f, 0.0f);
1485 for (int n = 0; n < IM_ARRAYSIZE(CustomRectIds); n++)
1486 CustomRectIds[n] = -1;
1487 }
1488
~ImFontAtlas()1489 ImFontAtlas::~ImFontAtlas()
1490 {
1491 Clear();
1492 }
1493
ClearInputData()1494 void ImFontAtlas::ClearInputData()
1495 {
1496 for (int i = 0; i < ConfigData.Size; i++)
1497 if (ConfigData[i].FontData && ConfigData[i].FontDataOwnedByAtlas)
1498 {
1499 ImGui::MemFree(ConfigData[i].FontData);
1500 ConfigData[i].FontData = NULL;
1501 }
1502
1503 // When clearing this we lose access to the font name and other information used to build the font.
1504 for (int i = 0; i < Fonts.Size; i++)
1505 if (Fonts[i]->ConfigData >= ConfigData.Data && Fonts[i]->ConfigData < ConfigData.Data + ConfigData.Size)
1506 {
1507 Fonts[i]->ConfigData = NULL;
1508 Fonts[i]->ConfigDataCount = 0;
1509 }
1510 ConfigData.clear();
1511 CustomRects.clear();
1512 for (int n = 0; n < IM_ARRAYSIZE(CustomRectIds); n++)
1513 CustomRectIds[n] = -1;
1514 }
1515
ClearTexData()1516 void ImFontAtlas::ClearTexData()
1517 {
1518 if (TexPixelsAlpha8)
1519 ImGui::MemFree(TexPixelsAlpha8);
1520 if (TexPixelsRGBA32)
1521 ImGui::MemFree(TexPixelsRGBA32);
1522 TexPixelsAlpha8 = NULL;
1523 TexPixelsRGBA32 = NULL;
1524 }
1525
ClearFonts()1526 void ImFontAtlas::ClearFonts()
1527 {
1528 for (int i = 0; i < Fonts.Size; i++)
1529 IM_DELETE(Fonts[i]);
1530 Fonts.clear();
1531 }
1532
Clear()1533 void ImFontAtlas::Clear()
1534 {
1535 ClearInputData();
1536 ClearTexData();
1537 ClearFonts();
1538 }
1539
GetTexDataAsAlpha8(unsigned char ** out_pixels,int * out_width,int * out_height,int * out_bytes_per_pixel)1540 void ImFontAtlas::GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel)
1541 {
1542 // Build atlas on demand
1543 if (TexPixelsAlpha8 == NULL)
1544 {
1545 if (ConfigData.empty())
1546 AddFontDefault();
1547 Build();
1548 }
1549
1550 *out_pixels = TexPixelsAlpha8;
1551 if (out_width) *out_width = TexWidth;
1552 if (out_height) *out_height = TexHeight;
1553 if (out_bytes_per_pixel) *out_bytes_per_pixel = 1;
1554 }
1555
GetTexDataAsRGBA32(unsigned char ** out_pixels,int * out_width,int * out_height,int * out_bytes_per_pixel)1556 void ImFontAtlas::GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel)
1557 {
1558 // Convert to RGBA32 format on demand
1559 // Although it is likely to be the most commonly used format, our font rendering is 1 channel / 8 bpp
1560 if (!TexPixelsRGBA32)
1561 {
1562 unsigned char* pixels = NULL;
1563 GetTexDataAsAlpha8(&pixels, NULL, NULL);
1564 if (pixels)
1565 {
1566 TexPixelsRGBA32 = (unsigned int*)ImGui::MemAlloc((size_t)(TexWidth * TexHeight * 4));
1567 const unsigned char* src = pixels;
1568 unsigned int* dst = TexPixelsRGBA32;
1569 for (int n = TexWidth * TexHeight; n > 0; n--)
1570 *dst++ = IM_COL32(255, 255, 255, (unsigned int)(*src++));
1571 }
1572 }
1573
1574 *out_pixels = (unsigned char*)TexPixelsRGBA32;
1575 if (out_width) *out_width = TexWidth;
1576 if (out_height) *out_height = TexHeight;
1577 if (out_bytes_per_pixel) *out_bytes_per_pixel = 4;
1578 }
1579
AddFont(const ImFontConfig * font_cfg)1580 ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg)
1581 {
1582 IM_ASSERT(font_cfg->FontData != NULL && font_cfg->FontDataSize > 0);
1583 IM_ASSERT(font_cfg->SizePixels > 0.0f);
1584
1585 // Create new font
1586 if (!font_cfg->MergeMode)
1587 Fonts.push_back(IM_NEW(ImFont));
1588 else
1589 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.
1590
1591 ConfigData.push_back(*font_cfg);
1592 ImFontConfig& new_font_cfg = ConfigData.back();
1593 if (!new_font_cfg.DstFont)
1594 new_font_cfg.DstFont = Fonts.back();
1595 if (!new_font_cfg.FontDataOwnedByAtlas)
1596 {
1597 new_font_cfg.FontData = ImGui::MemAlloc(new_font_cfg.FontDataSize);
1598 new_font_cfg.FontDataOwnedByAtlas = true;
1599 memcpy(new_font_cfg.FontData, font_cfg->FontData, (size_t)new_font_cfg.FontDataSize);
1600 }
1601
1602 // Invalidate texture
1603 ClearTexData();
1604 return new_font_cfg.DstFont;
1605 }
1606
1607 // Default font TTF is compressed with stb_compress then base85 encoded (see misc/fonts/binary_to_compressed_c.cpp for encoder)
1608 static unsigned int stb_decompress_length(unsigned char* input);
1609 static unsigned int stb_decompress(unsigned char* output, unsigned char* i, unsigned int length);
1610 static const char* GetDefaultCompressedFontDataTTFBase85();
Decode85Byte(char c)1611 static unsigned int Decode85Byte(char c) { return c >= '\\' ? c - 36 : c - 35; }
Decode85(const unsigned char * src,unsigned char * dst)1612 static void Decode85(const unsigned char* src, unsigned char* dst)
1613 {
1614 while (*src)
1615 {
1616 unsigned int tmp = Decode85Byte(src[0]) + 85 * (Decode85Byte(src[1]) + 85 * (Decode85Byte(src[2]) + 85 * (Decode85Byte(src[3]) + 85 * Decode85Byte(src[4]))));
1617 dst[0] = ((tmp >> 0) & 0xFF);
1618 dst[1] = ((tmp >> 8) & 0xFF);
1619 dst[2] = ((tmp >> 16) & 0xFF);
1620 dst[3] = ((tmp >> 24) & 0xFF); // We can't assume little-endianness.
1621 src += 5;
1622 dst += 4;
1623 }
1624 }
1625
1626 // Load embedded ProggyClean.ttf at size 13, disable oversampling
AddFontDefault(const ImFontConfig * font_cfg_template)1627 ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template)
1628 {
1629 ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
1630 if (!font_cfg_template)
1631 {
1632 font_cfg.OversampleH = font_cfg.OversampleV = 1;
1633 font_cfg.PixelSnapH = true;
1634 }
1635 if (font_cfg.Name[0] == '\0') strcpy(font_cfg.Name, "ProggyClean.ttf, 13px");
1636 if (font_cfg.SizePixels <= 0.0f) font_cfg.SizePixels = 13.0f;
1637
1638 const char* ttf_compressed_base85 = GetDefaultCompressedFontDataTTFBase85();
1639 ImFont* font = AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, font_cfg.SizePixels, &font_cfg, GetGlyphRangesDefault());
1640 return font;
1641 }
1642
AddFontFromFileTTF(const char * filename,float size_pixels,const ImFontConfig * font_cfg_template,const ImWchar * glyph_ranges)1643 ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)
1644 {
1645 int data_size = 0;
1646 void* data = ImFileLoadToMemory(filename, "rb", &data_size, 0);
1647 if (!data)
1648 {
1649 IM_ASSERT(0); // Could not load file.
1650 return NULL;
1651 }
1652 ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
1653 if (font_cfg.Name[0] == '\0')
1654 {
1655 // Store a short copy of filename into into the font name for convenience
1656 const char* p;
1657 for (p = filename + strlen(filename); p > filename && p[-1] != '/' && p[-1] != '\\'; p--)
1658 {
1659 }
1660 snprintf(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "%s, %.0fpx", p, size_pixels);
1661 }
1662 return AddFontFromMemoryTTF(data, data_size, size_pixels, &font_cfg, glyph_ranges);
1663 }
1664
1665 // NB: Transfer ownership of 'ttf_data' to ImFontAtlas, unless font_cfg_template->FontDataOwnedByAtlas == false. Owned TTF buffer will be deleted after Build().
AddFontFromMemoryTTF(void * ttf_data,int ttf_size,float size_pixels,const ImFontConfig * font_cfg_template,const ImWchar * glyph_ranges)1666 ImFont* ImFontAtlas::AddFontFromMemoryTTF(void* ttf_data, int ttf_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)
1667 {
1668 ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
1669 IM_ASSERT(font_cfg.FontData == NULL);
1670 font_cfg.FontData = ttf_data;
1671 font_cfg.FontDataSize = ttf_size;
1672 font_cfg.SizePixels = size_pixels;
1673 if (glyph_ranges)
1674 font_cfg.GlyphRanges = glyph_ranges;
1675 return AddFont(&font_cfg);
1676 }
1677
AddFontFromMemoryCompressedTTF(const void * compressed_ttf_data,int compressed_ttf_size,float size_pixels,const ImFontConfig * font_cfg_template,const ImWchar * glyph_ranges)1678 ImFont* ImFontAtlas::AddFontFromMemoryCompressedTTF(const void* compressed_ttf_data, int compressed_ttf_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)
1679 {
1680 const unsigned int buf_decompressed_size = stb_decompress_length((unsigned char*)compressed_ttf_data);
1681 unsigned char* buf_decompressed_data = (unsigned char*)ImGui::MemAlloc(buf_decompressed_size);
1682 stb_decompress(buf_decompressed_data, (unsigned char*)compressed_ttf_data, (unsigned int)compressed_ttf_size);
1683
1684 ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
1685 IM_ASSERT(font_cfg.FontData == NULL);
1686 font_cfg.FontDataOwnedByAtlas = true;
1687 return AddFontFromMemoryTTF(buf_decompressed_data, (int)buf_decompressed_size, size_pixels, &font_cfg, glyph_ranges);
1688 }
1689
AddFontFromMemoryCompressedBase85TTF(const char * compressed_ttf_data_base85,float size_pixels,const ImFontConfig * font_cfg,const ImWchar * glyph_ranges)1690 ImFont* ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(const char* compressed_ttf_data_base85, float size_pixels, const ImFontConfig* font_cfg, const ImWchar* glyph_ranges)
1691 {
1692 int compressed_ttf_size = (((int)strlen(compressed_ttf_data_base85) + 4) / 5) * 4;
1693 void* compressed_ttf = ImGui::MemAlloc((size_t)compressed_ttf_size);
1694 Decode85((const unsigned char*)compressed_ttf_data_base85, (unsigned char*)compressed_ttf);
1695 ImFont* font = AddFontFromMemoryCompressedTTF(compressed_ttf, compressed_ttf_size, size_pixels, font_cfg, glyph_ranges);
1696 ImGui::MemFree(compressed_ttf);
1697 return font;
1698 }
1699
AddCustomRectRegular(unsigned int id,int width,int height)1700 int ImFontAtlas::AddCustomRectRegular(unsigned int id, int width, int height)
1701 {
1702 IM_ASSERT(id >= 0x10000);
1703 IM_ASSERT(width > 0 && width <= 0xFFFF);
1704 IM_ASSERT(height > 0 && height <= 0xFFFF);
1705 CustomRect r;
1706 r.ID = id;
1707 r.Width = (unsigned short)width;
1708 r.Height = (unsigned short)height;
1709 CustomRects.push_back(r);
1710 return CustomRects.Size - 1; // Return index
1711 }
1712
AddCustomRectFontGlyph(ImFont * font,ImWchar id,int width,int height,float advance_x,const ImVec2 & offset)1713 int ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset)
1714 {
1715 IM_ASSERT(font != NULL);
1716 IM_ASSERT(width > 0 && width <= 0xFFFF);
1717 IM_ASSERT(height > 0 && height <= 0xFFFF);
1718 CustomRect r;
1719 r.ID = id;
1720 r.Width = (unsigned short)width;
1721 r.Height = (unsigned short)height;
1722 r.GlyphAdvanceX = advance_x;
1723 r.GlyphOffset = offset;
1724 r.Font = font;
1725 CustomRects.push_back(r);
1726 return CustomRects.Size - 1; // Return index
1727 }
1728
CalcCustomRectUV(const CustomRect * rect,ImVec2 * out_uv_min,ImVec2 * out_uv_max)1729 void ImFontAtlas::CalcCustomRectUV(const CustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max)
1730 {
1731 IM_ASSERT(TexWidth > 0 && TexHeight > 0); // Font atlas needs to be built before we can calculate UV coordinates
1732 IM_ASSERT(rect->IsPacked()); // Make sure the rectangle has been packed
1733 *out_uv_min = ImVec2((float)rect->X * TexUvScale.x, (float)rect->Y * TexUvScale.y);
1734 *out_uv_max = ImVec2((float)(rect->X + rect->Width) * TexUvScale.x, (float)(rect->Y + rect->Height) * TexUvScale.y);
1735 }
1736
GetMouseCursorTexData(ImGuiMouseCursor cursor_type,ImVec2 * out_offset,ImVec2 * out_size,ImVec2 out_uv_border[2],ImVec2 out_uv_fill[2])1737 bool ImFontAtlas::GetMouseCursorTexData(ImGuiMouseCursor cursor_type, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2])
1738 {
1739 if (cursor_type <= ImGuiMouseCursor_None || cursor_type >= ImGuiMouseCursor_Count_)
1740 return false;
1741 if (Flags & ImFontAtlasFlags_NoMouseCursors)
1742 return false;
1743
1744 ImFontAtlas::CustomRect& r = CustomRects[CustomRectIds[0]];
1745 IM_ASSERT(r.ID == FONT_ATLAS_DEFAULT_TEX_DATA_ID);
1746 ImVec2 pos = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][0] + ImVec2((float)r.X, (float)r.Y);
1747 ImVec2 size = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][1];
1748 *out_size = size;
1749 *out_offset = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][2];
1750 out_uv_border[0] = (pos)*TexUvScale;
1751 out_uv_border[1] = (pos + size) * TexUvScale;
1752 pos.x += FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF + 1;
1753 out_uv_fill[0] = (pos)*TexUvScale;
1754 out_uv_fill[1] = (pos + size) * TexUvScale;
1755 return true;
1756 }
1757
Build()1758 bool ImFontAtlas::Build()
1759 {
1760 return ImFontAtlasBuildWithStbTruetype(this);
1761 }
1762
ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256],float in_brighten_factor)1763 void ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_brighten_factor)
1764 {
1765 for (unsigned int i = 0; i < 256; i++)
1766 {
1767 unsigned int value = (unsigned int)(i * in_brighten_factor);
1768 out_table[i] = value > 255 ? 255 : (value & 0xFF);
1769 }
1770 }
1771
ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256],unsigned char * pixels,int x,int y,int w,int h,int stride)1772 void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride)
1773 {
1774 unsigned char* data = pixels + x + y * stride;
1775 for (int j = h; j > 0; j--, data += stride)
1776 for (int i = 0; i < w; i++)
1777 data[i] = table[data[i]];
1778 }
1779
ImFontAtlasBuildWithStbTruetype(ImFontAtlas * atlas)1780 bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
1781 {
1782 IM_ASSERT(atlas->ConfigData.Size > 0);
1783
1784 ImFontAtlasBuildRegisterDefaultCustomRects(atlas);
1785
1786 atlas->TexID = NULL;
1787 atlas->TexWidth = atlas->TexHeight = 0;
1788 atlas->TexUvScale = ImVec2(0.0f, 0.0f);
1789 atlas->TexUvWhitePixel = ImVec2(0.0f, 0.0f);
1790 atlas->ClearTexData();
1791
1792 // Count glyphs/ranges
1793 int total_glyphs_count = 0;
1794 int total_ranges_count = 0;
1795 for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
1796 {
1797 ImFontConfig& cfg = atlas->ConfigData[input_i];
1798 if (!cfg.GlyphRanges)
1799 cfg.GlyphRanges = atlas->GetGlyphRangesDefault();
1800 for (const ImWchar* in_range = cfg.GlyphRanges; in_range[0] && in_range[1]; in_range += 2, total_ranges_count++)
1801 total_glyphs_count += (in_range[1] - in_range[0]) + 1;
1802 }
1803
1804 // 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.
1805 // Width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height.
1806 atlas->TexWidth = (atlas->TexDesiredWidth > 0) ? atlas->TexDesiredWidth : (total_glyphs_count > 4000) ? 4096 : (total_glyphs_count > 2000) ? 2048 : (total_glyphs_count > 1000) ? 1024 : 512;
1807 atlas->TexHeight = 0;
1808
1809 // Start packing
1810 const int max_tex_height = 1024 * 32;
1811 stbtt_pack_context spc = {};
1812 if (!stbtt_PackBegin(&spc, NULL, atlas->TexWidth, max_tex_height, 0, atlas->TexGlyphPadding, NULL))
1813 return false;
1814 stbtt_PackSetOversampling(&spc, 1, 1);
1815
1816 // Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values).
1817 ImFontAtlasBuildPackCustomRects(atlas, spc.pack_info);
1818
1819 // Initialize font information (so we can error without any cleanup)
1820 struct ImFontTempBuildData
1821 {
1822 stbtt_fontinfo FontInfo;
1823 stbrp_rect* Rects;
1824 int RectsCount;
1825 stbtt_pack_range* Ranges;
1826 int RangesCount;
1827 };
1828 ImFontTempBuildData* tmp_array = (ImFontTempBuildData*)ImGui::MemAlloc((size_t)atlas->ConfigData.Size * sizeof(ImFontTempBuildData));
1829 for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
1830 {
1831 ImFontConfig& cfg = atlas->ConfigData[input_i];
1832 ImFontTempBuildData& tmp = tmp_array[input_i];
1833 IM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas));
1834
1835 const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)cfg.FontData, cfg.FontNo);
1836 IM_ASSERT(font_offset >= 0);
1837 if (!stbtt_InitFont(&tmp.FontInfo, (unsigned char*)cfg.FontData, font_offset))
1838 {
1839 atlas->TexWidth = atlas->TexHeight = 0; // Reset output on failure
1840 ImGui::MemFree(tmp_array);
1841 return false;
1842 }
1843 }
1844
1845 // Allocate packing character data and flag packed characters buffer as non-packed (x0=y0=x1=y1=0)
1846 int buf_packedchars_n = 0, buf_rects_n = 0, buf_ranges_n = 0;
1847 stbtt_packedchar* buf_packedchars = (stbtt_packedchar*)ImGui::MemAlloc(total_glyphs_count * sizeof(stbtt_packedchar));
1848 stbrp_rect* buf_rects = (stbrp_rect*)ImGui::MemAlloc(total_glyphs_count * sizeof(stbrp_rect));
1849 stbtt_pack_range* buf_ranges = (stbtt_pack_range*)ImGui::MemAlloc(total_ranges_count * sizeof(stbtt_pack_range));
1850 memset(buf_packedchars, 0, total_glyphs_count * sizeof(stbtt_packedchar));
1851 memset(buf_rects, 0, total_glyphs_count * sizeof(stbrp_rect)); // Unnecessary but let's clear this for the sake of sanity.
1852 memset(buf_ranges, 0, total_ranges_count * sizeof(stbtt_pack_range));
1853
1854 // First font pass: pack all glyphs (no rendering at this point, we are working with rectangles in an infinitely tall texture at this point)
1855 for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
1856 {
1857 ImFontConfig& cfg = atlas->ConfigData[input_i];
1858 ImFontTempBuildData& tmp = tmp_array[input_i];
1859
1860 // Setup ranges
1861 int font_glyphs_count = 0;
1862 int font_ranges_count = 0;
1863 for (const ImWchar* in_range = cfg.GlyphRanges; in_range[0] && in_range[1]; in_range += 2, font_ranges_count++)
1864 font_glyphs_count += (in_range[1] - in_range[0]) + 1;
1865 tmp.Ranges = buf_ranges + buf_ranges_n;
1866 tmp.RangesCount = font_ranges_count;
1867 buf_ranges_n += font_ranges_count;
1868 for (int i = 0; i < font_ranges_count; i++)
1869 {
1870 const ImWchar* in_range = &cfg.GlyphRanges[i * 2];
1871 stbtt_pack_range& range = tmp.Ranges[i];
1872 range.font_size = cfg.SizePixels;
1873 range.first_unicode_codepoint_in_range = in_range[0];
1874 range.num_chars = (in_range[1] - in_range[0]) + 1;
1875 range.chardata_for_range = buf_packedchars + buf_packedchars_n;
1876 buf_packedchars_n += range.num_chars;
1877 }
1878
1879 // Pack
1880 tmp.Rects = buf_rects + buf_rects_n;
1881 tmp.RectsCount = font_glyphs_count;
1882 buf_rects_n += font_glyphs_count;
1883 stbtt_PackSetOversampling(&spc, cfg.OversampleH, cfg.OversampleV);
1884 int n = stbtt_PackFontRangesGatherRects(&spc, &tmp.FontInfo, tmp.Ranges, tmp.RangesCount, tmp.Rects);
1885 IM_ASSERT(n == font_glyphs_count);
1886 stbrp_pack_rects((stbrp_context*)spc.pack_info, tmp.Rects, n);
1887
1888 // Extend texture height
1889 for (int i = 0; i < n; i++)
1890 if (tmp.Rects[i].was_packed)
1891 atlas->TexHeight = ImMax(atlas->TexHeight, tmp.Rects[i].y + tmp.Rects[i].h);
1892 }
1893 IM_ASSERT(buf_rects_n == total_glyphs_count);
1894 IM_ASSERT(buf_packedchars_n == total_glyphs_count);
1895 IM_ASSERT(buf_ranges_n == total_ranges_count);
1896
1897 // Create texture
1898 atlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight);
1899 atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight);
1900 atlas->TexPixelsAlpha8 = (unsigned char*)ImGui::MemAlloc(atlas->TexWidth * atlas->TexHeight);
1901 memset(atlas->TexPixelsAlpha8, 0, atlas->TexWidth * atlas->TexHeight);
1902 spc.pixels = atlas->TexPixelsAlpha8;
1903 spc.height = atlas->TexHeight;
1904
1905 // Second pass: render font characters
1906 for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
1907 {
1908 ImFontConfig& cfg = atlas->ConfigData[input_i];
1909 ImFontTempBuildData& tmp = tmp_array[input_i];
1910 stbtt_PackSetOversampling(&spc, cfg.OversampleH, cfg.OversampleV);
1911 stbtt_PackFontRangesRenderIntoRects(&spc, &tmp.FontInfo, tmp.Ranges, tmp.RangesCount, tmp.Rects);
1912 if (cfg.RasterizerMultiply != 1.0f)
1913 {
1914 unsigned char multiply_table[256];
1915 ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply);
1916 for (const stbrp_rect* r = tmp.Rects; r != tmp.Rects + tmp.RectsCount; r++)
1917 if (r->was_packed)
1918 ImFontAtlasBuildMultiplyRectAlpha8(multiply_table, spc.pixels, r->x, r->y, r->w, r->h, spc.stride_in_bytes);
1919 }
1920 tmp.Rects = NULL;
1921 }
1922
1923 // End packing
1924 stbtt_PackEnd(&spc);
1925 ImGui::MemFree(buf_rects);
1926 buf_rects = NULL;
1927
1928 // Third pass: setup ImFont and glyphs for runtime
1929 for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
1930 {
1931 ImFontConfig& cfg = atlas->ConfigData[input_i];
1932 ImFontTempBuildData& tmp = tmp_array[input_i];
1933 ImFont* dst_font = cfg.DstFont; // We can have multiple input fonts writing into a same destination font (when using MergeMode=true)
1934
1935 const float font_scale = stbtt_ScaleForPixelHeight(&tmp.FontInfo, cfg.SizePixels);
1936 int unscaled_ascent, unscaled_descent, unscaled_line_gap;
1937 stbtt_GetFontVMetrics(&tmp.FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap);
1938
1939 const float ascent = unscaled_ascent * font_scale;
1940 const float descent = unscaled_descent * font_scale;
1941 ImFontAtlasBuildSetupFont(atlas, dst_font, &cfg, ascent, descent);
1942 const float off_x = cfg.GlyphOffset.x;
1943 const float off_y = cfg.GlyphOffset.y + (float)(int)(dst_font->Ascent + 0.5f);
1944
1945 for (int i = 0; i < tmp.RangesCount; i++)
1946 {
1947 stbtt_pack_range& range = tmp.Ranges[i];
1948 for (int char_idx = 0; char_idx < range.num_chars; char_idx += 1)
1949 {
1950 const stbtt_packedchar& pc = range.chardata_for_range[char_idx];
1951 if (!pc.x0 && !pc.x1 && !pc.y0 && !pc.y1)
1952 continue;
1953
1954 const int codepoint = range.first_unicode_codepoint_in_range + char_idx;
1955 if (cfg.MergeMode && dst_font->FindGlyph((unsigned short)codepoint))
1956 continue;
1957
1958 stbtt_aligned_quad q;
1959 float dummy_x = 0.0f, dummy_y = 0.0f;
1960 stbtt_GetPackedQuad(range.chardata_for_range, atlas->TexWidth, atlas->TexHeight, char_idx, &dummy_x, &dummy_y, &q, 0);
1961 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);
1962 }
1963 }
1964 }
1965
1966 // Cleanup temporaries
1967 ImGui::MemFree(buf_packedchars);
1968 ImGui::MemFree(buf_ranges);
1969 ImGui::MemFree(tmp_array);
1970
1971 ImFontAtlasBuildFinish(atlas);
1972
1973 return true;
1974 }
1975
ImFontAtlasBuildRegisterDefaultCustomRects(ImFontAtlas * atlas)1976 void ImFontAtlasBuildRegisterDefaultCustomRects(ImFontAtlas* atlas)
1977 {
1978 if (atlas->CustomRectIds[0] >= 0)
1979 return;
1980 if (!(atlas->Flags & ImFontAtlasFlags_NoMouseCursors))
1981 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);
1982 else
1983 atlas->CustomRectIds[0] = atlas->AddCustomRectRegular(FONT_ATLAS_DEFAULT_TEX_DATA_ID, 2, 2);
1984 }
1985
ImFontAtlasBuildSetupFont(ImFontAtlas * atlas,ImFont * font,ImFontConfig * font_config,float ascent,float descent)1986 void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent)
1987 {
1988 if (!font_config->MergeMode)
1989 {
1990 font->ClearOutputData();
1991 font->FontSize = font_config->SizePixels;
1992 font->ConfigData = font_config;
1993 font->ContainerAtlas = atlas;
1994 font->Ascent = ascent;
1995 font->Descent = descent;
1996 }
1997 font->ConfigDataCount++;
1998 }
1999
ImFontAtlasBuildPackCustomRects(ImFontAtlas * atlas,void * pack_context_opaque)2000 void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* pack_context_opaque)
2001 {
2002 stbrp_context* pack_context = (stbrp_context*)pack_context_opaque;
2003
2004 ImVector<ImFontAtlas::CustomRect>& user_rects = atlas->CustomRects;
2005 IM_ASSERT(user_rects.Size >= 1); // We expect at least the default custom rects to be registered, else something went wrong.
2006
2007 ImVector<stbrp_rect> pack_rects;
2008 pack_rects.resize(user_rects.Size);
2009 memset(pack_rects.Data, 0, sizeof(stbrp_rect) * user_rects.Size);
2010 for (int i = 0; i < user_rects.Size; i++)
2011 {
2012 pack_rects[i].w = user_rects[i].Width;
2013 pack_rects[i].h = user_rects[i].Height;
2014 }
2015 stbrp_pack_rects(pack_context, &pack_rects[0], pack_rects.Size);
2016 for (int i = 0; i < pack_rects.Size; i++)
2017 if (pack_rects[i].was_packed)
2018 {
2019 user_rects[i].X = pack_rects[i].x;
2020 user_rects[i].Y = pack_rects[i].y;
2021 IM_ASSERT(pack_rects[i].w == user_rects[i].Width && pack_rects[i].h == user_rects[i].Height);
2022 atlas->TexHeight = ImMax(atlas->TexHeight, pack_rects[i].y + pack_rects[i].h);
2023 }
2024 }
2025
ImFontAtlasBuildRenderDefaultTexData(ImFontAtlas * atlas)2026 static void ImFontAtlasBuildRenderDefaultTexData(ImFontAtlas* atlas)
2027 {
2028 IM_ASSERT(atlas->CustomRectIds[0] >= 0);
2029 IM_ASSERT(atlas->TexPixelsAlpha8 != NULL);
2030 ImFontAtlas::CustomRect& r = atlas->CustomRects[atlas->CustomRectIds[0]];
2031 IM_ASSERT(r.ID == FONT_ATLAS_DEFAULT_TEX_DATA_ID);
2032 IM_ASSERT(r.IsPacked());
2033
2034 const int w = atlas->TexWidth;
2035 if (!(atlas->Flags & ImFontAtlasFlags_NoMouseCursors))
2036 {
2037 // Render/copy pixels
2038 IM_ASSERT(r.Width == FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF * 2 + 1 && r.Height == FONT_ATLAS_DEFAULT_TEX_DATA_H);
2039 for (int y = 0, n = 0; y < FONT_ATLAS_DEFAULT_TEX_DATA_H; y++)
2040 for (int x = 0; x < FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF; x++, n++)
2041 {
2042 const int offset0 = (int)(r.X + x) + (int)(r.Y + y) * w;
2043 const int offset1 = offset0 + FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF + 1;
2044 atlas->TexPixelsAlpha8[offset0] = FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[n] == '.' ? 0xFF : 0x00;
2045 atlas->TexPixelsAlpha8[offset1] = FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[n] == 'X' ? 0xFF : 0x00;
2046 }
2047 }
2048 else
2049 {
2050 IM_ASSERT(r.Width == 2 && r.Height == 2);
2051 const int offset = (int)(r.X) + (int)(r.Y) * w;
2052 atlas->TexPixelsAlpha8[offset] = atlas->TexPixelsAlpha8[offset + 1] = atlas->TexPixelsAlpha8[offset + w] = atlas->TexPixelsAlpha8[offset + w + 1] = 0xFF;
2053 }
2054 atlas->TexUvWhitePixel = ImVec2((r.X + 0.5f) * atlas->TexUvScale.x, (r.Y + 0.5f) * atlas->TexUvScale.y);
2055 }
2056
ImFontAtlasBuildFinish(ImFontAtlas * atlas)2057 void ImFontAtlasBuildFinish(ImFontAtlas* atlas)
2058 {
2059 // Render into our custom data block
2060 ImFontAtlasBuildRenderDefaultTexData(atlas);
2061
2062 // Register custom rectangle glyphs
2063 for (int i = 0; i < atlas->CustomRects.Size; i++)
2064 {
2065 const ImFontAtlas::CustomRect& r = atlas->CustomRects[i];
2066 if (r.Font == NULL || r.ID > 0x10000)
2067 continue;
2068
2069 IM_ASSERT(r.Font->ContainerAtlas == atlas);
2070 ImVec2 uv0, uv1;
2071 atlas->CalcCustomRectUV(&r, &uv0, &uv1);
2072 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);
2073 }
2074
2075 // Build all fonts lookup tables
2076 for (int i = 0; i < atlas->Fonts.Size; i++)
2077 atlas->Fonts[i]->BuildLookupTable();
2078 }
2079
2080 // Retrieve list of range (2 int per range, values are inclusive)
GetGlyphRangesDefault()2081 const ImWchar* ImFontAtlas::GetGlyphRangesDefault()
2082 {
2083 static const ImWchar ranges[] =
2084 {
2085 0x0020,
2086 0x00FF, // Basic Latin + Latin Supplement
2087 0,
2088 };
2089 return &ranges[0];
2090 }
2091
GetGlyphRangesKorean()2092 const ImWchar* ImFontAtlas::GetGlyphRangesKorean()
2093 {
2094 static const ImWchar ranges[] =
2095 {
2096 0x0020,
2097 0x00FF, // Basic Latin + Latin Supplement
2098 0x3131,
2099 0x3163, // Korean alphabets
2100 0xAC00,
2101 0xD79D, // Korean characters
2102 0,
2103 };
2104 return &ranges[0];
2105 }
2106
GetGlyphRangesChinese()2107 const ImWchar* ImFontAtlas::GetGlyphRangesChinese()
2108 {
2109 static const ImWchar ranges[] =
2110 {
2111 0x0020,
2112 0x00FF, // Basic Latin + Latin Supplement
2113 0x3000,
2114 0x30FF, // Punctuations, Hiragana, Katakana
2115 0x31F0,
2116 0x31FF, // Katakana Phonetic Extensions
2117 0xFF00,
2118 0xFFEF, // Half-width characters
2119 0x4e00,
2120 0x9FAF, // CJK Ideograms
2121 0,
2122 };
2123 return &ranges[0];
2124 }
2125
GetGlyphRangesJapanese()2126 const ImWchar* ImFontAtlas::GetGlyphRangesJapanese()
2127 {
2128 // Store the 1946 ideograms code points as successive offsets from the initial unicode codepoint 0x4E00. Each offset has an implicit +1.
2129 // This encoding is designed to helps us reduce the source code size.
2130 // FIXME: Source a list of the revised 2136 joyo kanji list from 2010 and rebuild this.
2131 // The current list was sourced from http://theinstructionlimit.com/author/renaudbedardrenaudbedard/page/3
2132 // Note that you may use ImFontAtlas::GlyphRangesBuilder to create your own ranges, by merging existing ranges or adding new characters.
2133 static const short offsets_from_0x4E00[] =
2134 {
2135 -1,
2136 0,
2137 1,
2138 3,
2139 0,
2140 0,
2141 0,
2142 0,
2143 1,
2144 0,
2145 5,
2146 1,
2147 1,
2148 0,
2149 7,
2150 4,
2151 6,
2152 10,
2153 0,
2154 1,
2155 9,
2156 9,
2157 7,
2158 1,
2159 3,
2160 19,
2161 1,
2162 10,
2163 7,
2164 1,
2165 0,
2166 1,
2167 0,
2168 5,
2169 1,
2170 0,
2171 6,
2172 4,
2173 2,
2174 6,
2175 0,
2176 0,
2177 12,
2178 6,
2179 8,
2180 0,
2181 3,
2182 5,
2183 0,
2184 1,
2185 0,
2186 9,
2187 0,
2188 0,
2189 8,
2190 1,
2191 1,
2192 3,
2193 4,
2194 5,
2195 13,
2196 0,
2197 0,
2198 8,
2199 2,
2200 17,
2201 4,
2202 3,
2203 1,
2204 1,
2205 9,
2206 6,
2207 0,
2208 0,
2209 0,
2210 2,
2211 1,
2212 3,
2213 2,
2214 22,
2215 1,
2216 9,
2217 11,
2218 1,
2219 13,
2220 1,
2221 3,
2222 12,
2223 0,
2224 5,
2225 9,
2226 2,
2227 0,
2228 6,
2229 12,
2230 5,
2231 3,
2232 12,
2233 4,
2234 1,
2235 2,
2236 16,
2237 1,
2238 1,
2239 4,
2240 6,
2241 5,
2242 3,
2243 0,
2244 6,
2245 13,
2246 15,
2247 5,
2248 12,
2249 8,
2250 14,
2251 0,
2252 0,
2253 6,
2254 15,
2255 3,
2256 6,
2257 0,
2258 18,
2259 8,
2260 1,
2261 6,
2262 14,
2263 1,
2264 5,
2265 4,
2266 12,
2267 24,
2268 3,
2269 13,
2270 12,
2271 10,
2272 24,
2273 0,
2274 0,
2275 0,
2276 1,
2277 0,
2278 1,
2279 1,
2280 2,
2281 9,
2282 10,
2283 2,
2284 2,
2285 0,
2286 0,
2287 3,
2288 3,
2289 1,
2290 0,
2291 3,
2292 8,
2293 0,
2294 3,
2295 2,
2296 4,
2297 4,
2298 1,
2299 6,
2300 11,
2301 10,
2302 14,
2303 6,
2304 15,
2305 3,
2306 4,
2307 15,
2308 1,
2309 0,
2310 0,
2311 5,
2312 2,
2313 2,
2314 0,
2315 0,
2316 1,
2317 6,
2318 5,
2319 5,
2320 6,
2321 0,
2322 3,
2323 6,
2324 5,
2325 0,
2326 0,
2327 1,
2328 0,
2329 11,
2330 2,
2331 2,
2332 8,
2333 4,
2334 7,
2335 0,
2336 10,
2337 0,
2338 1,
2339 2,
2340 17,
2341 19,
2342 3,
2343 0,
2344 2,
2345 5,
2346 0,
2347 6,
2348 2,
2349 4,
2350 4,
2351 6,
2352 1,
2353 1,
2354 11,
2355 2,
2356 0,
2357 3,
2358 1,
2359 2,
2360 1,
2361 2,
2362 10,
2363 7,
2364 6,
2365 3,
2366 16,
2367 0,
2368 8,
2369 24,
2370 0,
2371 0,
2372 3,
2373 1,
2374 1,
2375 3,
2376 0,
2377 1,
2378 6,
2379 0,
2380 0,
2381 0,
2382 2,
2383 0,
2384 1,
2385 5,
2386 15,
2387 0,
2388 1,
2389 0,
2390 0,
2391 2,
2392 11,
2393 19,
2394 1,
2395 4,
2396 19,
2397 7,
2398 6,
2399 5,
2400 1,
2401 0,
2402 0,
2403 0,
2404 0,
2405 5,
2406 1,
2407 0,
2408 1,
2409 9,
2410 0,
2411 0,
2412 5,
2413 0,
2414 2,
2415 0,
2416 1,
2417 0,
2418 3,
2419 0,
2420 11,
2421 3,
2422 0,
2423 2,
2424 0,
2425 0,
2426 0,
2427 0,
2428 0,
2429 9,
2430 3,
2431 6,
2432 4,
2433 12,
2434 0,
2435 14,
2436 0,
2437 0,
2438 29,
2439 10,
2440 8,
2441 0,
2442 14,
2443 37,
2444 13,
2445 0,
2446 31,
2447 16,
2448 19,
2449 0,
2450 8,
2451 30,
2452 1,
2453 20,
2454 8,
2455 3,
2456 48,
2457 21,
2458 1,
2459 0,
2460 12,
2461 0,
2462 10,
2463 44,
2464 34,
2465 42,
2466 54,
2467 11,
2468 18,
2469 82,
2470 0,
2471 2,
2472 1,
2473 2,
2474 12,
2475 1,
2476 0,
2477 6,
2478 2,
2479 17,
2480 2,
2481 12,
2482 7,
2483 0,
2484 7,
2485 17,
2486 4,
2487 2,
2488 6,
2489 24,
2490 23,
2491 8,
2492 23,
2493 39,
2494 2,
2495 16,
2496 23,
2497 1,
2498 0,
2499 5,
2500 1,
2501 2,
2502 15,
2503 14,
2504 5,
2505 6,
2506 2,
2507 11,
2508 0,
2509 8,
2510 6,
2511 2,
2512 2,
2513 2,
2514 14,
2515 20,
2516 4,
2517 15,
2518 3,
2519 4,
2520 11,
2521 10,
2522 10,
2523 2,
2524 5,
2525 2,
2526 1,
2527 30,
2528 2,
2529 1,
2530 0,
2531 0,
2532 22,
2533 5,
2534 5,
2535 0,
2536 3,
2537 1,
2538 5,
2539 4,
2540 1,
2541 0,
2542 0,
2543 2,
2544 2,
2545 21,
2546 1,
2547 5,
2548 1,
2549 2,
2550 16,
2551 2,
2552 1,
2553 3,
2554 4,
2555 0,
2556 8,
2557 4,
2558 0,
2559 0,
2560 5,
2561 14,
2562 11,
2563 2,
2564 16,
2565 1,
2566 13,
2567 1,
2568 7,
2569 0,
2570 22,
2571 15,
2572 3,
2573 1,
2574 22,
2575 7,
2576 14,
2577 22,
2578 19,
2579 11,
2580 24,
2581 18,
2582 46,
2583 10,
2584 20,
2585 64,
2586 45,
2587 3,
2588 2,
2589 0,
2590 4,
2591 5,
2592 0,
2593 1,
2594 4,
2595 25,
2596 1,
2597 0,
2598 0,
2599 2,
2600 10,
2601 0,
2602 0,
2603 0,
2604 1,
2605 0,
2606 1,
2607 2,
2608 0,
2609 0,
2610 9,
2611 1,
2612 2,
2613 0,
2614 0,
2615 0,
2616 2,
2617 5,
2618 2,
2619 1,
2620 1,
2621 5,
2622 5,
2623 8,
2624 1,
2625 1,
2626 1,
2627 5,
2628 1,
2629 4,
2630 9,
2631 1,
2632 3,
2633 0,
2634 1,
2635 0,
2636 1,
2637 1,
2638 2,
2639 0,
2640 0,
2641 2,
2642 0,
2643 1,
2644 8,
2645 22,
2646 8,
2647 1,
2648 0,
2649 0,
2650 0,
2651 0,
2652 4,
2653 2,
2654 1,
2655 0,
2656 9,
2657 8,
2658 5,
2659 0,
2660 9,
2661 1,
2662 30,
2663 24,
2664 2,
2665 6,
2666 4,
2667 39,
2668 0,
2669 14,
2670 5,
2671 16,
2672 6,
2673 26,
2674 179,
2675 0,
2676 2,
2677 1,
2678 1,
2679 0,
2680 0,
2681 0,
2682 5,
2683 2,
2684 9,
2685 6,
2686 0,
2687 2,
2688 5,
2689 16,
2690 7,
2691 5,
2692 1,
2693 1,
2694 0,
2695 2,
2696 4,
2697 4,
2698 7,
2699 15,
2700 13,
2701 14,
2702 0,
2703 0,
2704 3,
2705 0,
2706 1,
2707 0,
2708 0,
2709 0,
2710 2,
2711 1,
2712 6,
2713 4,
2714 5,
2715 1,
2716 4,
2717 9,
2718 0,
2719 3,
2720 1,
2721 8,
2722 0,
2723 0,
2724 10,
2725 5,
2726 0,
2727 43,
2728 0,
2729 2,
2730 6,
2731 8,
2732 4,
2733 0,
2734 2,
2735 0,
2736 0,
2737 9,
2738 6,
2739 0,
2740 9,
2741 3,
2742 1,
2743 6,
2744 20,
2745 14,
2746 6,
2747 1,
2748 4,
2749 0,
2750 7,
2751 2,
2752 3,
2753 0,
2754 2,
2755 0,
2756 5,
2757 0,
2758 3,
2759 1,
2760 0,
2761 3,
2762 9,
2763 7,
2764 0,
2765 3,
2766 4,
2767 0,
2768 4,
2769 9,
2770 1,
2771 6,
2772 0,
2773 9,
2774 0,
2775 0,
2776 2,
2777 3,
2778 10,
2779 9,
2780 28,
2781 3,
2782 6,
2783 2,
2784 4,
2785 1,
2786 2,
2787 32,
2788 4,
2789 1,
2790 18,
2791 2,
2792 0,
2793 3,
2794 1,
2795 5,
2796 30,
2797 10,
2798 0,
2799 2,
2800 2,
2801 2,
2802 0,
2803 7,
2804 9,
2805 8,
2806 11,
2807 10,
2808 11,
2809 7,
2810 2,
2811 13,
2812 7,
2813 5,
2814 10,
2815 0,
2816 3,
2817 40,
2818 2,
2819 0,
2820 1,
2821 6,
2822 12,
2823 0,
2824 4,
2825 5,
2826 1,
2827 5,
2828 11,
2829 11,
2830 21,
2831 4,
2832 8,
2833 3,
2834 7,
2835 8,
2836 8,
2837 33,
2838 5,
2839 23,
2840 0,
2841 0,
2842 19,
2843 8,
2844 8,
2845 2,
2846 3,
2847 0,
2848 6,
2849 1,
2850 1,
2851 1,
2852 5,
2853 1,
2854 27,
2855 4,
2856 2,
2857 5,
2858 0,
2859 3,
2860 5,
2861 6,
2862 3,
2863 1,
2864 0,
2865 3,
2866 1,
2867 12,
2868 5,
2869 3,
2870 3,
2871 2,
2872 0,
2873 7,
2874 7,
2875 2,
2876 1,
2877 0,
2878 4,
2879 0,
2880 1,
2881 1,
2882 2,
2883 0,
2884 10,
2885 10,
2886 6,
2887 2,
2888 5,
2889 9,
2890 7,
2891 5,
2892 15,
2893 15,
2894 21,
2895 6,
2896 11,
2897 5,
2898 20,
2899 4,
2900 3,
2901 5,
2902 5,
2903 2,
2904 5,
2905 0,
2906 2,
2907 1,
2908 0,
2909 1,
2910 7,
2911 28,
2912 0,
2913 9,
2914 0,
2915 5,
2916 12,
2917 5,
2918 5,
2919 18,
2920 30,
2921 0,
2922 12,
2923 3,
2924 3,
2925 21,
2926 16,
2927 25,
2928 32,
2929 9,
2930 3,
2931 14,
2932 11,
2933 24,
2934 5,
2935 66,
2936 9,
2937 1,
2938 2,
2939 0,
2940 5,
2941 9,
2942 1,
2943 5,
2944 1,
2945 8,
2946 0,
2947 8,
2948 3,
2949 3,
2950 0,
2951 1,
2952 15,
2953 1,
2954 4,
2955 8,
2956 1,
2957 2,
2958 7,
2959 0,
2960 7,
2961 2,
2962 8,
2963 3,
2964 7,
2965 5,
2966 3,
2967 7,
2968 10,
2969 2,
2970 1,
2971 0,
2972 0,
2973 2,
2974 25,
2975 0,
2976 6,
2977 4,
2978 0,
2979 10,
2980 0,
2981 4,
2982 2,
2983 4,
2984 1,
2985 12,
2986 5,
2987 38,
2988 4,
2989 0,
2990 4,
2991 1,
2992 10,
2993 5,
2994 9,
2995 4,
2996 0,
2997 14,
2998 4,
2999 2,
3000 5,
3001 18,
3002 20,
3003 21,
3004 1,
3005 3,
3006 0,
3007 5,
3008 0,
3009 7,
3010 0,
3011 3,
3012 7,
3013 1,
3014 3,
3015 1,
3016 1,
3017 8,
3018 1,
3019 0,
3020 0,
3021 0,
3022 3,
3023 2,
3024 5,
3025 2,
3026 11,
3027 6,
3028 0,
3029 13,
3030 1,
3031 3,
3032 9,
3033 1,
3034 12,
3035 0,
3036 16,
3037 6,
3038 2,
3039 1,
3040 0,
3041 2,
3042 1,
3043 12,
3044 6,
3045 13,
3046 11,
3047 2,
3048 0,
3049 28,
3050 1,
3051 7,
3052 8,
3053 14,
3054 13,
3055 8,
3056 13,
3057 0,
3058 2,
3059 0,
3060 5,
3061 4,
3062 8,
3063 10,
3064 2,
3065 37,
3066 42,
3067 19,
3068 6,
3069 6,
3070 7,
3071 4,
3072 14,
3073 11,
3074 18,
3075 14,
3076 80,
3077 7,
3078 6,
3079 0,
3080 4,
3081 72,
3082 12,
3083 36,
3084 27,
3085 7,
3086 7,
3087 0,
3088 14,
3089 17,
3090 19,
3091 164,
3092 27,
3093 0,
3094 5,
3095 10,
3096 7,
3097 3,
3098 13,
3099 6,
3100 14,
3101 0,
3102 2,
3103 2,
3104 5,
3105 3,
3106 0,
3107 6,
3108 13,
3109 0,
3110 0,
3111 10,
3112 29,
3113 0,
3114 4,
3115 0,
3116 3,
3117 13,
3118 0,
3119 3,
3120 1,
3121 6,
3122 51,
3123 1,
3124 5,
3125 28,
3126 2,
3127 0,
3128 8,
3129 0,
3130 20,
3131 2,
3132 4,
3133 0,
3134 25,
3135 2,
3136 10,
3137 13,
3138 10,
3139 0,
3140 16,
3141 4,
3142 0,
3143 1,
3144 0,
3145 2,
3146 1,
3147 7,
3148 0,
3149 1,
3150 8,
3151 11,
3152 0,
3153 0,
3154 1,
3155 2,
3156 7,
3157 2,
3158 23,
3159 11,
3160 6,
3161 6,
3162 4,
3163 16,
3164 2,
3165 2,
3166 2,
3167 0,
3168 22,
3169 9,
3170 3,
3171 3,
3172 5,
3173 2,
3174 0,
3175 15,
3176 16,
3177 21,
3178 2,
3179 9,
3180 20,
3181 15,
3182 15,
3183 5,
3184 3,
3185 9,
3186 1,
3187 0,
3188 0,
3189 1,
3190 7,
3191 7,
3192 5,
3193 4,
3194 2,
3195 2,
3196 2,
3197 38,
3198 24,
3199 14,
3200 0,
3201 0,
3202 15,
3203 5,
3204 6,
3205 24,
3206 14,
3207 5,
3208 5,
3209 11,
3210 0,
3211 21,
3212 12,
3213 0,
3214 3,
3215 8,
3216 4,
3217 11,
3218 1,
3219 8,
3220 0,
3221 11,
3222 27,
3223 7,
3224 2,
3225 4,
3226 9,
3227 21,
3228 59,
3229 0,
3230 1,
3231 39,
3232 3,
3233 60,
3234 62,
3235 3,
3236 0,
3237 12,
3238 11,
3239 0,
3240 3,
3241 30,
3242 11,
3243 0,
3244 13,
3245 88,
3246 4,
3247 15,
3248 5,
3249 28,
3250 13,
3251 1,
3252 4,
3253 48,
3254 17,
3255 17,
3256 4,
3257 28,
3258 32,
3259 46,
3260 0,
3261 16,
3262 0,
3263 18,
3264 11,
3265 1,
3266 8,
3267 6,
3268 38,
3269 11,
3270 2,
3271 6,
3272 11,
3273 38,
3274 2,
3275 0,
3276 45,
3277 3,
3278 11,
3279 2,
3280 7,
3281 8,
3282 4,
3283 30,
3284 14,
3285 17,
3286 2,
3287 1,
3288 1,
3289 65,
3290 18,
3291 12,
3292 16,
3293 4,
3294 2,
3295 45,
3296 123,
3297 12,
3298 56,
3299 33,
3300 1,
3301 4,
3302 3,
3303 4,
3304 7,
3305 0,
3306 0,
3307 0,
3308 3,
3309 2,
3310 0,
3311 16,
3312 4,
3313 2,
3314 4,
3315 2,
3316 0,
3317 7,
3318 4,
3319 5,
3320 2,
3321 26,
3322 2,
3323 25,
3324 6,
3325 11,
3326 6,
3327 1,
3328 16,
3329 2,
3330 6,
3331 17,
3332 77,
3333 15,
3334 3,
3335 35,
3336 0,
3337 1,
3338 0,
3339 5,
3340 1,
3341 0,
3342 38,
3343 16,
3344 6,
3345 3,
3346 12,
3347 3,
3348 3,
3349 3,
3350 0,
3351 9,
3352 3,
3353 1,
3354 3,
3355 5,
3356 2,
3357 9,
3358 0,
3359 18,
3360 0,
3361 25,
3362 1,
3363 3,
3364 32,
3365 1,
3366 72,
3367 46,
3368 6,
3369 2,
3370 7,
3371 1,
3372 3,
3373 14,
3374 17,
3375 0,
3376 28,
3377 1,
3378 40,
3379 13,
3380 0,
3381 20,
3382 15,
3383 40,
3384 6,
3385 38,
3386 24,
3387 12,
3388 43,
3389 1,
3390 1,
3391 9,
3392 0,
3393 12,
3394 6,
3395 0,
3396 6,
3397 2,
3398 4,
3399 19,
3400 3,
3401 7,
3402 1,
3403 48,
3404 0,
3405 9,
3406 5,
3407 0,
3408 5,
3409 6,
3410 9,
3411 6,
3412 10,
3413 15,
3414 2,
3415 11,
3416 19,
3417 3,
3418 9,
3419 2,
3420 0,
3421 1,
3422 10,
3423 1,
3424 27,
3425 8,
3426 1,
3427 3,
3428 6,
3429 1,
3430 14,
3431 0,
3432 26,
3433 0,
3434 27,
3435 16,
3436 3,
3437 4,
3438 9,
3439 6,
3440 2,
3441 23,
3442 9,
3443 10,
3444 5,
3445 25,
3446 2,
3447 1,
3448 6,
3449 1,
3450 1,
3451 48,
3452 15,
3453 9,
3454 15,
3455 14,
3456 3,
3457 4,
3458 26,
3459 60,
3460 29,
3461 13,
3462 37,
3463 21,
3464 1,
3465 6,
3466 4,
3467 0,
3468 2,
3469 11,
3470 22,
3471 23,
3472 16,
3473 16,
3474 2,
3475 2,
3476 1,
3477 3,
3478 0,
3479 5,
3480 1,
3481 6,
3482 4,
3483 0,
3484 0,
3485 4,
3486 0,
3487 0,
3488 8,
3489 3,
3490 0,
3491 2,
3492 5,
3493 0,
3494 7,
3495 1,
3496 7,
3497 3,
3498 13,
3499 2,
3500 4,
3501 10,
3502 3,
3503 0,
3504 2,
3505 31,
3506 0,
3507 18,
3508 3,
3509 0,
3510 12,
3511 10,
3512 4,
3513 1,
3514 0,
3515 7,
3516 5,
3517 7,
3518 0,
3519 5,
3520 4,
3521 12,
3522 2,
3523 22,
3524 10,
3525 4,
3526 2,
3527 15,
3528 2,
3529 8,
3530 9,
3531 0,
3532 23,
3533 2,
3534 197,
3535 51,
3536 3,
3537 1,
3538 1,
3539 4,
3540 13,
3541 4,
3542 3,
3543 21,
3544 4,
3545 19,
3546 3,
3547 10,
3548 5,
3549 40,
3550 0,
3551 4,
3552 1,
3553 1,
3554 10,
3555 4,
3556 1,
3557 27,
3558 34,
3559 7,
3560 21,
3561 2,
3562 17,
3563 2,
3564 9,
3565 6,
3566 4,
3567 2,
3568 3,
3569 0,
3570 4,
3571 2,
3572 7,
3573 8,
3574 2,
3575 5,
3576 1,
3577 15,
3578 21,
3579 3,
3580 4,
3581 4,
3582 2,
3583 2,
3584 17,
3585 22,
3586 1,
3587 5,
3588 22,
3589 4,
3590 26,
3591 7,
3592 0,
3593 32,
3594 1,
3595 11,
3596 42,
3597 15,
3598 4,
3599 1,
3600 2,
3601 5,
3602 0,
3603 19,
3604 3,
3605 1,
3606 8,
3607 6,
3608 0,
3609 10,
3610 1,
3611 9,
3612 2,
3613 13,
3614 30,
3615 8,
3616 2,
3617 24,
3618 17,
3619 19,
3620 1,
3621 4,
3622 4,
3623 25,
3624 13,
3625 0,
3626 10,
3627 16,
3628 11,
3629 39,
3630 18,
3631 8,
3632 5,
3633 30,
3634 82,
3635 1,
3636 6,
3637 8,
3638 18,
3639 77,
3640 11,
3641 13,
3642 20,
3643 75,
3644 11,
3645 112,
3646 78,
3647 33,
3648 3,
3649 0,
3650 0,
3651 60,
3652 17,
3653 84,
3654 9,
3655 1,
3656 1,
3657 12,
3658 30,
3659 10,
3660 49,
3661 5,
3662 32,
3663 158,
3664 178,
3665 5,
3666 5,
3667 6,
3668 3,
3669 3,
3670 1,
3671 3,
3672 1,
3673 4,
3674 7,
3675 6,
3676 19,
3677 31,
3678 21,
3679 0,
3680 2,
3681 9,
3682 5,
3683 6,
3684 27,
3685 4,
3686 9,
3687 8,
3688 1,
3689 76,
3690 18,
3691 12,
3692 1,
3693 4,
3694 0,
3695 3,
3696 3,
3697 6,
3698 3,
3699 12,
3700 2,
3701 8,
3702 30,
3703 16,
3704 2,
3705 25,
3706 1,
3707 5,
3708 5,
3709 4,
3710 3,
3711 0,
3712 6,
3713 10,
3714 2,
3715 3,
3716 1,
3717 0,
3718 5,
3719 1,
3720 19,
3721 3,
3722 0,
3723 8,
3724 1,
3725 5,
3726 2,
3727 6,
3728 0,
3729 0,
3730 0,
3731 19,
3732 1,
3733 2,
3734 0,
3735 5,
3736 1,
3737 2,
3738 5,
3739 1,
3740 3,
3741 7,
3742 0,
3743 4,
3744 12,
3745 7,
3746 3,
3747 10,
3748 22,
3749 0,
3750 9,
3751 5,
3752 1,
3753 0,
3754 2,
3755 20,
3756 1,
3757 1,
3758 3,
3759 23,
3760 30,
3761 3,
3762 9,
3763 9,
3764 1,
3765 4,
3766 191,
3767 14,
3768 3,
3769 15,
3770 6,
3771 8,
3772 50,
3773 0,
3774 1,
3775 0,
3776 0,
3777 4,
3778 0,
3779 0,
3780 1,
3781 0,
3782 2,
3783 4,
3784 2,
3785 0,
3786 2,
3787 3,
3788 0,
3789 2,
3790 0,
3791 2,
3792 2,
3793 8,
3794 7,
3795 0,
3796 1,
3797 1,
3798 1,
3799 3,
3800 3,
3801 17,
3802 11,
3803 91,
3804 1,
3805 9,
3806 3,
3807 2,
3808 13,
3809 4,
3810 24,
3811 15,
3812 41,
3813 3,
3814 13,
3815 3,
3816 1,
3817 20,
3818 4,
3819 125,
3820 29,
3821 30,
3822 1,
3823 0,
3824 4,
3825 12,
3826 2,
3827 21,
3828 4,
3829 5,
3830 5,
3831 19,
3832 11,
3833 0,
3834 13,
3835 11,
3836 86,
3837 2,
3838 18,
3839 0,
3840 7,
3841 1,
3842 8,
3843 8,
3844 2,
3845 2,
3846 22,
3847 1,
3848 2,
3849 6,
3850 5,
3851 2,
3852 0,
3853 1,
3854 2,
3855 8,
3856 0,
3857 2,
3858 0,
3859 5,
3860 2,
3861 1,
3862 0,
3863 2,
3864 10,
3865 2,
3866 0,
3867 5,
3868 9,
3869 2,
3870 1,
3871 2,
3872 0,
3873 1,
3874 0,
3875 4,
3876 0,
3877 0,
3878 10,
3879 2,
3880 5,
3881 3,
3882 0,
3883 6,
3884 1,
3885 0,
3886 1,
3887 4,
3888 4,
3889 33,
3890 3,
3891 13,
3892 17,
3893 3,
3894 18,
3895 6,
3896 4,
3897 7,
3898 1,
3899 5,
3900 78,
3901 0,
3902 4,
3903 1,
3904 13,
3905 7,
3906 1,
3907 8,
3908 1,
3909 0,
3910 35,
3911 27,
3912 15,
3913 3,
3914 0,
3915 0,
3916 0,
3917 1,
3918 11,
3919 5,
3920 41,
3921 38,
3922 15,
3923 22,
3924 6,
3925 14,
3926 14,
3927 2,
3928 1,
3929 11,
3930 6,
3931 20,
3932 63,
3933 5,
3934 8,
3935 27,
3936 7,
3937 11,
3938 2,
3939 2,
3940 40,
3941 58,
3942 23,
3943 50,
3944 54,
3945 56,
3946 293,
3947 8,
3948 8,
3949 1,
3950 5,
3951 1,
3952 14,
3953 0,
3954 1,
3955 12,
3956 37,
3957 89,
3958 8,
3959 8,
3960 8,
3961 2,
3962 10,
3963 6,
3964 0,
3965 0,
3966 0,
3967 4,
3968 5,
3969 2,
3970 1,
3971 0,
3972 1,
3973 1,
3974 2,
3975 7,
3976 0,
3977 3,
3978 3,
3979 0,
3980 4,
3981 6,
3982 0,
3983 3,
3984 2,
3985 19,
3986 3,
3987 8,
3988 0,
3989 0,
3990 0,
3991 4,
3992 4,
3993 16,
3994 0,
3995 4,
3996 1,
3997 5,
3998 1,
3999 3,
4000 0,
4001 3,
4002 4,
4003 6,
4004 2,
4005 17,
4006 10,
4007 10,
4008 31,
4009 6,
4010 4,
4011 3,
4012 6,
4013 10,
4014 126,
4015 7,
4016 3,
4017 2,
4018 2,
4019 0,
4020 9,
4021 0,
4022 0,
4023 5,
4024 20,
4025 13,
4026 0,
4027 15,
4028 0,
4029 6,
4030 0,
4031 2,
4032 5,
4033 8,
4034 64,
4035 50,
4036 3,
4037 2,
4038 12,
4039 2,
4040 9,
4041 0,
4042 0,
4043 11,
4044 8,
4045 20,
4046 109,
4047 2,
4048 18,
4049 23,
4050 0,
4051 0,
4052 9,
4053 61,
4054 3,
4055 0,
4056 28,
4057 41,
4058 77,
4059 27,
4060 19,
4061 17,
4062 81,
4063 5,
4064 2,
4065 14,
4066 5,
4067 83,
4068 57,
4069 252,
4070 14,
4071 154,
4072 263,
4073 14,
4074 20,
4075 8,
4076 13,
4077 6,
4078 57,
4079 39,
4080 38,
4081 };
4082 static ImWchar base_ranges[] =
4083 {
4084 0x0020, 0x00FF, // Basic Latin + Latin Supplement
4085 0x3000, 0x30FF, // Punctuations, Hiragana, Katakana
4086 0x31F0, 0x31FF, // Katakana Phonetic Extensions
4087 0xFF00, 0xFFEF, // Half-width characters
4088 };
4089 static bool full_ranges_unpacked = false;
4090 static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(offsets_from_0x4E00) * 2 + 1];
4091 if (!full_ranges_unpacked)
4092 {
4093 // Unpack
4094 int codepoint = 0x4e00;
4095 memcpy(full_ranges, base_ranges, sizeof(base_ranges));
4096 ImWchar* dst = full_ranges + IM_ARRAYSIZE(base_ranges);
4097 ;
4098 for (int n = 0; n < IM_ARRAYSIZE(offsets_from_0x4E00); n++, dst += 2)
4099 dst[0] = dst[1] = (ImWchar)(codepoint += (offsets_from_0x4E00[n] + 1));
4100 dst[0] = 0;
4101 full_ranges_unpacked = true;
4102 }
4103 return &full_ranges[0];
4104 }
4105
GetGlyphRangesCyrillic()4106 const ImWchar* ImFontAtlas::GetGlyphRangesCyrillic()
4107 {
4108 static const ImWchar ranges[] =
4109 {
4110 0x0020,
4111 0x00FF, // Basic Latin + Latin Supplement
4112 0x0400,
4113 0x052F, // Cyrillic + Cyrillic Supplement
4114 0x2DE0,
4115 0x2DFF, // Cyrillic Extended-A
4116 0xA640,
4117 0xA69F, // Cyrillic Extended-B
4118 0,
4119 };
4120 return &ranges[0];
4121 }
4122
GetGlyphRangesThai()4123 const ImWchar* ImFontAtlas::GetGlyphRangesThai()
4124 {
4125 static const ImWchar ranges[] =
4126 {
4127 0x0020,
4128 0x00FF, // Basic Latin
4129 0x2010,
4130 0x205E, // Punctuations
4131 0x0E00,
4132 0x0E7F, // Thai
4133 0,
4134 };
4135 return &ranges[0];
4136 }
4137
4138 //-----------------------------------------------------------------------------
4139 // ImFontAtlas::GlyphRangesBuilder
4140 //-----------------------------------------------------------------------------
4141
AddText(const char * text,const char * text_end)4142 void ImFontAtlas::GlyphRangesBuilder::AddText(const char* text, const char* text_end)
4143 {
4144 while (text_end ? (text < text_end) : *text)
4145 {
4146 unsigned int c = 0;
4147 int c_len = ImTextCharFromUtf8(&c, text, text_end);
4148 text += c_len;
4149 if (c_len == 0)
4150 break;
4151 if (c < 0x10000)
4152 AddChar((ImWchar)c);
4153 }
4154 }
4155
AddRanges(const ImWchar * ranges)4156 void ImFontAtlas::GlyphRangesBuilder::AddRanges(const ImWchar* ranges)
4157 {
4158 for (; ranges[0]; ranges += 2)
4159 for (ImWchar c = ranges[0]; c <= ranges[1]; c++)
4160 AddChar(c);
4161 }
4162
BuildRanges(ImVector<ImWchar> * out_ranges)4163 void ImFontAtlas::GlyphRangesBuilder::BuildRanges(ImVector<ImWchar>* out_ranges)
4164 {
4165 for (int n = 0; n < 0x10000; n++)
4166 if (GetBit(n))
4167 {
4168 out_ranges->push_back((ImWchar)n);
4169 while (n < 0x10000 && GetBit(n + 1))
4170 n++;
4171 out_ranges->push_back((ImWchar)n);
4172 }
4173 out_ranges->push_back(0);
4174 }
4175
4176 //-----------------------------------------------------------------------------
4177 // ImFont
4178 //-----------------------------------------------------------------------------
4179
ImFont()4180 ImFont::ImFont()
4181 {
4182 Scale = 1.0f;
4183 FallbackChar = (ImWchar)'?';
4184 DisplayOffset = ImVec2(0.0f, 1.0f);
4185 ClearOutputData();
4186 }
4187
~ImFont()4188 ImFont::~ImFont()
4189 {
4190 // Invalidate active font so that the user gets a clear crash instead of a dangling pointer.
4191 // If you want to delete fonts you need to do it between Render() and NewFrame().
4192 // FIXME-CLEANUP
4193 /*
4194 ImGuiContext& g = *GImGui;
4195 if (g.Font == this)
4196 g.Font = NULL;
4197 */
4198 ClearOutputData();
4199 }
4200
ClearOutputData()4201 void ImFont::ClearOutputData()
4202 {
4203 FontSize = 0.0f;
4204 Glyphs.clear();
4205 IndexAdvanceX.clear();
4206 IndexLookup.clear();
4207 FallbackGlyph = NULL;
4208 FallbackAdvanceX = 0.0f;
4209 ConfigDataCount = 0;
4210 ConfigData = NULL;
4211 ContainerAtlas = NULL;
4212 Ascent = Descent = 0.0f;
4213 MetricsTotalSurface = 0;
4214 }
4215
BuildLookupTable()4216 void ImFont::BuildLookupTable()
4217 {
4218 int max_codepoint = 0;
4219 for (int i = 0; i != Glyphs.Size; i++)
4220 max_codepoint = ImMax(max_codepoint, (int)Glyphs[i].Codepoint);
4221
4222 IM_ASSERT(Glyphs.Size < 0xFFFF); // -1 is reserved
4223 IndexAdvanceX.clear();
4224 IndexLookup.clear();
4225 GrowIndex(max_codepoint + 1);
4226 for (int i = 0; i < Glyphs.Size; i++)
4227 {
4228 int codepoint = (int)Glyphs[i].Codepoint;
4229 IndexAdvanceX[codepoint] = Glyphs[i].AdvanceX;
4230 IndexLookup[codepoint] = (unsigned short)i;
4231 }
4232
4233 // Create a glyph to handle TAB
4234 // FIXME: Needs proper TAB handling but it needs to be contextualized (or we could arbitrary say that each string starts at "column 0" ?)
4235 if (FindGlyph((unsigned short)' '))
4236 {
4237 if (Glyphs.back().Codepoint != '\t') // So we can call this function multiple times
4238 Glyphs.resize(Glyphs.Size + 1);
4239 ImFontGlyph& tab_glyph = Glyphs.back();
4240 tab_glyph = *FindGlyph((unsigned short)' ');
4241 tab_glyph.Codepoint = '\t';
4242 tab_glyph.AdvanceX *= 4;
4243 IndexAdvanceX[(int)tab_glyph.Codepoint] = (float)tab_glyph.AdvanceX;
4244 IndexLookup[(int)tab_glyph.Codepoint] = (unsigned short)(Glyphs.Size - 1);
4245 }
4246
4247 FallbackGlyph = NULL;
4248 FallbackGlyph = FindGlyph(FallbackChar);
4249 FallbackAdvanceX = FallbackGlyph ? FallbackGlyph->AdvanceX : 0.0f;
4250 for (int i = 0; i < max_codepoint + 1; i++)
4251 if (IndexAdvanceX[i] < 0.0f)
4252 IndexAdvanceX[i] = FallbackAdvanceX;
4253 }
4254
SetFallbackChar(ImWchar c)4255 void ImFont::SetFallbackChar(ImWchar c)
4256 {
4257 FallbackChar = c;
4258 BuildLookupTable();
4259 }
4260
GrowIndex(int new_size)4261 void ImFont::GrowIndex(int new_size)
4262 {
4263 IM_ASSERT(IndexAdvanceX.Size == IndexLookup.Size);
4264 if (new_size <= IndexLookup.Size)
4265 return;
4266 IndexAdvanceX.resize(new_size, -1.0f);
4267 IndexLookup.resize(new_size, (unsigned short)-1);
4268 }
4269
AddGlyph(ImWchar codepoint,float x0,float y0,float x1,float y1,float u0,float v0,float u1,float v1,float advance_x)4270 void ImFont::AddGlyph(ImWchar codepoint, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x)
4271 {
4272 Glyphs.resize(Glyphs.Size + 1);
4273 ImFontGlyph& glyph = Glyphs.back();
4274 glyph.Codepoint = (ImWchar)codepoint;
4275 glyph.X0 = x0;
4276 glyph.Y0 = y0;
4277 glyph.X1 = x1;
4278 glyph.Y1 = y1;
4279 glyph.U0 = u0;
4280 glyph.V0 = v0;
4281 glyph.U1 = u1;
4282 glyph.V1 = v1;
4283 glyph.AdvanceX = advance_x + ConfigData->GlyphExtraSpacing.x; // Bake spacing into AdvanceX
4284
4285 if (ConfigData->PixelSnapH)
4286 glyph.AdvanceX = (float)(int)(glyph.AdvanceX + 0.5f);
4287
4288 // Compute rough surface usage metrics (+1 to account for average padding, +0.99 to round)
4289 MetricsTotalSurface += (int)((glyph.U1 - glyph.U0) * ContainerAtlas->TexWidth + 1.99f) * (int)((glyph.V1 - glyph.V0) * ContainerAtlas->TexHeight + 1.99f);
4290 }
4291
AddRemapChar(ImWchar dst,ImWchar src,bool overwrite_dst)4292 void ImFont::AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst)
4293 {
4294 IM_ASSERT(IndexLookup.Size > 0); // Currently this can only be called AFTER the font has been built, aka after calling ImFontAtlas::GetTexDataAs*() function.
4295 int index_size = IndexLookup.Size;
4296
4297 if (dst < index_size && IndexLookup.Data[dst] == (unsigned short)-1 && !overwrite_dst) // 'dst' already exists
4298 return;
4299 if (src >= index_size && dst >= index_size) // both 'dst' and 'src' don't exist -> no-op
4300 return;
4301
4302 GrowIndex(dst + 1);
4303 IndexLookup[dst] = (src < index_size) ? IndexLookup.Data[src] : (unsigned short)-1;
4304 IndexAdvanceX[dst] = (src < index_size) ? IndexAdvanceX.Data[src] : 1.0f;
4305 }
4306
FindGlyph(ImWchar c) const4307 const ImFontGlyph* ImFont::FindGlyph(ImWchar c) const
4308 {
4309 if (c < IndexLookup.Size)
4310 {
4311 const unsigned short i = IndexLookup[c];
4312 if (i != (unsigned short)-1)
4313 return &Glyphs.Data[i];
4314 }
4315 return FallbackGlyph;
4316 }
4317
CalcWordWrapPositionA(float scale,const char * text,const char * text_end,float wrap_width) const4318 const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) const
4319 {
4320 // Simple word-wrapping for English, not full-featured. Please submit failing cases!
4321 // 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.)
4322
4323 // For references, possible wrap point marked with ^
4324 // "aaa bbb, ccc,ddd. eee fff. ggg!"
4325 // ^ ^ ^ ^ ^__ ^ ^
4326
4327 // List of hardcoded separators: .,;!?'"
4328
4329 // Skip extra blanks after a line returns (that includes not counting them in width computation)
4330 // e.g. "Hello world" --> "Hello" "World"
4331
4332 // Cut words that cannot possibly fit within one line.
4333 // e.g.: "The tropical fish" with ~5 characters worth of width --> "The tr" "opical" "fish"
4334
4335 float line_width = 0.0f;
4336 float word_width = 0.0f;
4337 float blank_width = 0.0f;
4338 wrap_width /= scale; // We work with unscaled widths to avoid scaling every characters
4339
4340 const char* word_end = text;
4341 const char* prev_word_end = NULL;
4342 bool inside_word = true;
4343
4344 const char* s = text;
4345 while (s < text_end)
4346 {
4347 unsigned int c = (unsigned int)*s;
4348 const char* next_s;
4349 if (c < 0x80)
4350 next_s = s + 1;
4351 else
4352 next_s = s + ImTextCharFromUtf8(&c, s, text_end);
4353 if (c == 0)
4354 break;
4355
4356 if (c < 32)
4357 {
4358 if (c == '\n')
4359 {
4360 line_width = word_width = blank_width = 0.0f;
4361 inside_word = true;
4362 s = next_s;
4363 continue;
4364 }
4365 if (c == '\r')
4366 {
4367 s = next_s;
4368 continue;
4369 }
4370 }
4371
4372 const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX[(int)c] : FallbackAdvanceX);
4373 if (ImCharIsSpace(c))
4374 {
4375 if (inside_word)
4376 {
4377 line_width += blank_width;
4378 blank_width = 0.0f;
4379 word_end = s;
4380 }
4381 blank_width += char_width;
4382 inside_word = false;
4383 }
4384 else
4385 {
4386 word_width += char_width;
4387 if (inside_word)
4388 {
4389 word_end = next_s;
4390 }
4391 else
4392 {
4393 prev_word_end = word_end;
4394 line_width += word_width + blank_width;
4395 word_width = blank_width = 0.0f;
4396 }
4397
4398 // Allow wrapping after punctuation.
4399 inside_word = !(c == '.' || c == ',' || c == ';' || c == '!' || c == '?' || c == '\"');
4400 }
4401
4402 // We ignore blank width at the end of the line (they can be skipped)
4403 if (line_width + word_width >= wrap_width)
4404 {
4405 // Words that cannot possibly fit within an entire line will be cut anywhere.
4406 if (word_width < wrap_width)
4407 s = prev_word_end ? prev_word_end : word_end;
4408 break;
4409 }
4410
4411 s = next_s;
4412 }
4413
4414 return s;
4415 }
4416
CalcTextSizeA(float size,float max_width,float wrap_width,const char * text_begin,const char * text_end,const char ** remaining) const4417 ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end, const char** remaining) const
4418 {
4419 if (!text_end)
4420 text_end = text_begin + strlen(text_begin); // FIXME-OPT: Need to avoid this.
4421
4422 const float line_height = size;
4423 const float scale = size / FontSize;
4424
4425 ImVec2 text_size = ImVec2(0, 0);
4426 float line_width = 0.0f;
4427
4428 const bool word_wrap_enabled = (wrap_width > 0.0f);
4429 const char* word_wrap_eol = NULL;
4430
4431 const char* s = text_begin;
4432 while (s < text_end)
4433 {
4434 if (word_wrap_enabled)
4435 {
4436 // 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.
4437 if (!word_wrap_eol)
4438 {
4439 word_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - line_width);
4440 if (word_wrap_eol == s) // Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity.
4441 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
4442 }
4443
4444 if (s >= word_wrap_eol)
4445 {
4446 if (text_size.x < line_width)
4447 text_size.x = line_width;
4448 text_size.y += line_height;
4449 line_width = 0.0f;
4450 word_wrap_eol = NULL;
4451
4452 // Wrapping skips upcoming blanks
4453 while (s < text_end)
4454 {
4455 const char c = *s;
4456 if (ImCharIsSpace(c))
4457 {
4458 s++;
4459 }
4460 else if (c == '\n')
4461 {
4462 s++;
4463 break;
4464 }
4465 else
4466 {
4467 break;
4468 }
4469 }
4470 continue;
4471 }
4472 }
4473
4474 // Decode and advance source
4475 const char* prev_s = s;
4476 unsigned int c = (unsigned int)*s;
4477 if (c < 0x80)
4478 {
4479 s += 1;
4480 }
4481 else
4482 {
4483 s += ImTextCharFromUtf8(&c, s, text_end);
4484 if (c == 0) // Malformed UTF-8?
4485 break;
4486 }
4487
4488 if (c < 32)
4489 {
4490 if (c == '\n')
4491 {
4492 text_size.x = ImMax(text_size.x, line_width);
4493 text_size.y += line_height;
4494 line_width = 0.0f;
4495 continue;
4496 }
4497 if (c == '\r')
4498 continue;
4499 }
4500
4501 const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX[(int)c] : FallbackAdvanceX) * scale;
4502 if (line_width + char_width >= max_width)
4503 {
4504 s = prev_s;
4505 break;
4506 }
4507
4508 line_width += char_width;
4509 }
4510
4511 if (text_size.x < line_width)
4512 text_size.x = line_width;
4513
4514 if (line_width > 0 || text_size.y == 0.0f)
4515 text_size.y += line_height;
4516
4517 if (remaining)
4518 *remaining = s;
4519
4520 return text_size;
4521 }
4522
RenderChar(ImDrawList * draw_list,float size,ImVec2 pos,ImU32 col,unsigned short c) const4523 void ImFont::RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, unsigned short c) const
4524 {
4525 if (c == ' ' || c == '\t' || c == '\n' || c == '\r') // Match behavior of RenderText(), those 4 codepoints are hard-coded.
4526 return;
4527 if (const ImFontGlyph* glyph = FindGlyph(c))
4528 {
4529 float scale = (size >= 0.0f) ? (size / FontSize) : 1.0f;
4530 pos.x = (float)(int)pos.x + DisplayOffset.x;
4531 pos.y = (float)(int)pos.y + DisplayOffset.y;
4532 draw_list->PrimReserve(6, 4);
4533 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);
4534 }
4535 }
4536
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) const4537 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
4538 {
4539 if (!text_end)
4540 text_end = text_begin + strlen(text_begin); // ImGui functions generally already provides a valid text_end, so this is merely to handle direct calls.
4541
4542 // Align to be pixel perfect
4543 pos.x = (float)(int)pos.x + DisplayOffset.x;
4544 pos.y = (float)(int)pos.y + DisplayOffset.y;
4545 float x = pos.x;
4546 float y = pos.y;
4547 if (y > clip_rect.w)
4548 return;
4549
4550 const float scale = size / FontSize;
4551 const float line_height = FontSize * scale;
4552 const bool word_wrap_enabled = (wrap_width > 0.0f);
4553 const char* word_wrap_eol = NULL;
4554
4555 // Skip non-visible lines
4556 const char* s = text_begin;
4557 if (!word_wrap_enabled && y + line_height < clip_rect.y)
4558 while (s < text_end && *s != '\n') // Fast-forward to next line
4559 s++;
4560
4561 // Reserve vertices for remaining worse case (over-reserving is useful and easily amortized)
4562 const int vtx_count_max = (int)(text_end - s) * 4;
4563 const int idx_count_max = (int)(text_end - s) * 6;
4564 const int idx_expected_size = draw_list->IdxBuffer.Size + idx_count_max;
4565 draw_list->PrimReserve(idx_count_max, vtx_count_max);
4566
4567 ImDrawVert* vtx_write = draw_list->_VtxWritePtr;
4568 ImDrawIdx* idx_write = draw_list->_IdxWritePtr;
4569 unsigned int vtx_current_idx = draw_list->_VtxCurrentIdx;
4570
4571 while (s < text_end)
4572 {
4573 if (word_wrap_enabled)
4574 {
4575 // 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.
4576 if (!word_wrap_eol)
4577 {
4578 word_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - (x - pos.x));
4579 if (word_wrap_eol == s) // Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity.
4580 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
4581 }
4582
4583 if (s >= word_wrap_eol)
4584 {
4585 x = pos.x;
4586 y += line_height;
4587 word_wrap_eol = NULL;
4588
4589 // Wrapping skips upcoming blanks
4590 while (s < text_end)
4591 {
4592 const char c = *s;
4593 if (ImCharIsSpace(c))
4594 {
4595 s++;
4596 }
4597 else if (c == '\n')
4598 {
4599 s++;
4600 break;
4601 }
4602 else
4603 {
4604 break;
4605 }
4606 }
4607 continue;
4608 }
4609 }
4610
4611 // Decode and advance source
4612 unsigned int c = (unsigned int)*s;
4613 if (c < 0x80)
4614 {
4615 s += 1;
4616 }
4617 else
4618 {
4619 s += ImTextCharFromUtf8(&c, s, text_end);
4620 if (c == 0) // Malformed UTF-8?
4621 break;
4622 }
4623
4624 if (c < 32)
4625 {
4626 if (c == '\n')
4627 {
4628 x = pos.x;
4629 y += line_height;
4630
4631 if (y > clip_rect.w)
4632 break;
4633 if (!word_wrap_enabled && y + line_height < clip_rect.y)
4634 while (s < text_end && *s != '\n') // Fast-forward to next line
4635 s++;
4636 continue;
4637 }
4638 if (c == '\r')
4639 continue;
4640 }
4641
4642 float char_width = 0.0f;
4643 if (const ImFontGlyph* glyph = FindGlyph((unsigned short)c))
4644 {
4645 char_width = glyph->AdvanceX * scale;
4646
4647 // Arbitrarily assume that both space and tabs are empty glyphs as an optimization
4648 if (c != ' ' && c != '\t')
4649 {
4650 // 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
4651 float x1 = x + glyph->X0 * scale;
4652 float x2 = x + glyph->X1 * scale;
4653 float y1 = y + glyph->Y0 * scale;
4654 float y2 = y + glyph->Y1 * scale;
4655 if (x1 <= clip_rect.z && x2 >= clip_rect.x)
4656 {
4657 // Render a character
4658 float u1 = glyph->U0;
4659 float v1 = glyph->V0;
4660 float u2 = glyph->U1;
4661 float v2 = glyph->V1;
4662
4663 // CPU side clipping used to fit text in their frame when the frame is too small. Only does clipping for axis aligned quads.
4664 if (cpu_fine_clip)
4665 {
4666 if (x1 < clip_rect.x)
4667 {
4668 u1 = u1 + (1.0f - (x2 - clip_rect.x) / (x2 - x1)) * (u2 - u1);
4669 x1 = clip_rect.x;
4670 }
4671 if (y1 < clip_rect.y)
4672 {
4673 v1 = v1 + (1.0f - (y2 - clip_rect.y) / (y2 - y1)) * (v2 - v1);
4674 y1 = clip_rect.y;
4675 }
4676 if (x2 > clip_rect.z)
4677 {
4678 u2 = u1 + ((clip_rect.z - x1) / (x2 - x1)) * (u2 - u1);
4679 x2 = clip_rect.z;
4680 }
4681 if (y2 > clip_rect.w)
4682 {
4683 v2 = v1 + ((clip_rect.w - y1) / (y2 - y1)) * (v2 - v1);
4684 y2 = clip_rect.w;
4685 }
4686 if (y1 >= y2)
4687 {
4688 x += char_width;
4689 continue;
4690 }
4691 }
4692
4693 // We are NOT calling PrimRectUV() here because non-inlined causes too much overhead in a debug builds. Inlined here:
4694 {
4695 idx_write[0] = (ImDrawIdx)(vtx_current_idx);
4696 idx_write[1] = (ImDrawIdx)(vtx_current_idx + 1);
4697 idx_write[2] = (ImDrawIdx)(vtx_current_idx + 2);
4698 idx_write[3] = (ImDrawIdx)(vtx_current_idx);
4699 idx_write[4] = (ImDrawIdx)(vtx_current_idx + 2);
4700 idx_write[5] = (ImDrawIdx)(vtx_current_idx + 3);
4701 vtx_write[0].pos.x = x1;
4702 vtx_write[0].pos.y = y1;
4703 vtx_write[0].col = col;
4704 vtx_write[0].uv.x = u1;
4705 vtx_write[0].uv.y = v1;
4706 vtx_write[1].pos.x = x2;
4707 vtx_write[1].pos.y = y1;
4708 vtx_write[1].col = col;
4709 vtx_write[1].uv.x = u2;
4710 vtx_write[1].uv.y = v1;
4711 vtx_write[2].pos.x = x2;
4712 vtx_write[2].pos.y = y2;
4713 vtx_write[2].col = col;
4714 vtx_write[2].uv.x = u2;
4715 vtx_write[2].uv.y = v2;
4716 vtx_write[3].pos.x = x1;
4717 vtx_write[3].pos.y = y2;
4718 vtx_write[3].col = col;
4719 vtx_write[3].uv.x = u1;
4720 vtx_write[3].uv.y = v2;
4721 vtx_write += 4;
4722 vtx_current_idx += 4;
4723 idx_write += 6;
4724 }
4725 }
4726 }
4727 }
4728
4729 x += char_width;
4730 }
4731
4732 // Give back unused vertices
4733 draw_list->VtxBuffer.resize((int)(vtx_write - draw_list->VtxBuffer.Data));
4734 draw_list->IdxBuffer.resize((int)(idx_write - draw_list->IdxBuffer.Data));
4735 draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 1].ElemCount -= (idx_expected_size - draw_list->IdxBuffer.Size);
4736 draw_list->_VtxWritePtr = vtx_write;
4737 draw_list->_IdxWritePtr = idx_write;
4738 draw_list->_VtxCurrentIdx = (unsigned int)draw_list->VtxBuffer.Size;
4739 }
4740
4741 //-----------------------------------------------------------------------------
4742 // Internals Drawing Helpers
4743 //-----------------------------------------------------------------------------
4744
ImAcos01(float x)4745 static inline float ImAcos01(float x)
4746 {
4747 if (x <= 0.0f) return IM_PI * 0.5f;
4748 if (x >= 1.0f) return 0.0f;
4749 return acosf(x);
4750 //return (-0.69813170079773212f * x * x - 0.87266462599716477f) * x + 1.5707963267948966f; // Cheap approximation, may be enough for what we do.
4751 }
4752
4753 // FIXME: Cleanup and move code to ImDrawList.
RenderRectFilledRangeH(ImDrawList * draw_list,const ImRect & rect,ImU32 col,float x_start_norm,float x_end_norm,float rounding)4754 void ImGui::RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, ImU32 col, float x_start_norm, float x_end_norm, float rounding)
4755 {
4756 if (x_end_norm == x_start_norm)
4757 return;
4758 if (x_start_norm > x_end_norm)
4759 ImSwap(x_start_norm, x_end_norm);
4760
4761 ImVec2 p0 = ImVec2(ImLerp(rect.Min.x, rect.Max.x, x_start_norm), rect.Min.y);
4762 ImVec2 p1 = ImVec2(ImLerp(rect.Min.x, rect.Max.x, x_end_norm), rect.Max.y);
4763 if (rounding == 0.0f)
4764 {
4765 draw_list->AddRectFilled(p0, p1, col, 0.0f);
4766 return;
4767 }
4768
4769 rounding = ImClamp(ImMin((rect.Max.x - rect.Min.x) * 0.5f, (rect.Max.y - rect.Min.y) * 0.5f) - 1.0f, 0.0f, rounding);
4770 const float inv_rounding = 1.0f / rounding;
4771 const float arc0_b = ImAcos01(1.0f - (p0.x - rect.Min.x) * inv_rounding);
4772 const float arc0_e = ImAcos01(1.0f - (p1.x - rect.Min.x) * inv_rounding);
4773 const float x0 = ImMax(p0.x, rect.Min.x + rounding);
4774 if (arc0_b == arc0_e)
4775 {
4776 draw_list->PathLineTo(ImVec2(x0, p1.y));
4777 draw_list->PathLineTo(ImVec2(x0, p0.y));
4778 }
4779 else if (arc0_b == 0.0f && arc0_e == IM_PI * 0.5f)
4780 {
4781 draw_list->PathArcToFast(ImVec2(x0, p1.y - rounding), rounding, 3, 6); // BL
4782 draw_list->PathArcToFast(ImVec2(x0, p0.y + rounding), rounding, 6, 9); // TR
4783 }
4784 else
4785 {
4786 draw_list->PathArcTo(ImVec2(x0, p1.y - rounding), rounding, IM_PI - arc0_e, IM_PI - arc0_b, 3); // BL
4787 draw_list->PathArcTo(ImVec2(x0, p0.y + rounding), rounding, IM_PI + arc0_b, IM_PI + arc0_e, 3); // TR
4788 }
4789 if (p1.x > rect.Min.x + rounding)
4790 {
4791 const float arc1_b = ImAcos01(1.0f - (rect.Max.x - p1.x) * inv_rounding);
4792 const float arc1_e = ImAcos01(1.0f - (rect.Max.x - p0.x) * inv_rounding);
4793 const float x1 = ImMin(p1.x, rect.Max.x - rounding);
4794 if (arc1_b == arc1_e)
4795 {
4796 draw_list->PathLineTo(ImVec2(x1, p0.y));
4797 draw_list->PathLineTo(ImVec2(x1, p1.y));
4798 }
4799 else if (arc1_b == 0.0f && arc1_e == IM_PI * 0.5f)
4800 {
4801 draw_list->PathArcToFast(ImVec2(x1, p0.y + rounding), rounding, 9, 12); // TR
4802 draw_list->PathArcToFast(ImVec2(x1, p1.y - rounding), rounding, 0, 3); // BR
4803 }
4804 else
4805 {
4806 draw_list->PathArcTo(ImVec2(x1, p0.y + rounding), rounding, -arc1_e, -arc1_b, 3); // TR
4807 draw_list->PathArcTo(ImVec2(x1, p1.y - rounding), rounding, +arc1_b, +arc1_e, 3); // BR
4808 }
4809 }
4810 draw_list->PathFillConvex(col);
4811 }
4812
4813 //-----------------------------------------------------------------------------
4814 // DEFAULT FONT DATA
4815 //-----------------------------------------------------------------------------
4816 // Compressed with stb_compress() then converted to a C array.
4817 // Use the program in misc/fonts/binary_to_compressed_c.cpp to create the array from a TTF file.
4818 // Decompression from stb.h (public domain) by Sean Barrett https://github.com/nothings/stb/blob/master/stb.h
4819 //-----------------------------------------------------------------------------
4820
stb_decompress_length(unsigned char * input)4821 static unsigned int stb_decompress_length(unsigned char* input)
4822 {
4823 return (input[8] << 24) + (input[9] << 16) + (input[10] << 8) + input[11];
4824 }
4825
4826 static unsigned char *stb__barrier, *stb__barrier2, *stb__barrier3, *stb__barrier4;
4827 static unsigned char* stb__dout;
stb__match(unsigned char * data,unsigned int length)4828 static void stb__match(unsigned char* data, unsigned int length)
4829 {
4830 // INVERSE of memmove... write each byte before copying the next...
4831 IM_ASSERT(stb__dout + length <= stb__barrier);
4832 if (stb__dout + length > stb__barrier)
4833 {
4834 stb__dout += length;
4835 return;
4836 }
4837 if (data < stb__barrier4)
4838 {
4839 stb__dout = stb__barrier + 1;
4840 return;
4841 }
4842 while (length--) *stb__dout++ = *data++;
4843 }
4844
stb__lit(unsigned char * data,unsigned int length)4845 static void stb__lit(unsigned char* data, unsigned int length)
4846 {
4847 IM_ASSERT(stb__dout + length <= stb__barrier);
4848 if (stb__dout + length > stb__barrier)
4849 {
4850 stb__dout += length;
4851 return;
4852 }
4853 if (data < stb__barrier2)
4854 {
4855 stb__dout = stb__barrier + 1;
4856 return;
4857 }
4858 memcpy(stb__dout, data, length);
4859 stb__dout += length;
4860 }
4861
4862 #define stb__in2(x) ((i[x] << 8) + i[(x) + 1])
4863 #define stb__in3(x) ((i[x] << 16) + stb__in2((x) + 1))
4864 #define stb__in4(x) ((i[x] << 24) + stb__in3((x) + 1))
4865
stb_decompress_token(unsigned char * i)4866 static unsigned char* stb_decompress_token(unsigned char* i)
4867 {
4868 if (*i >= 0x20)
4869 { // use fewer if's for cases that expand small
4870 if (*i >= 0x80)
4871 stb__match(stb__dout - i[1] - 1, i[0] - 0x80 + 1), i += 2;
4872 else if (*i >= 0x40)
4873 stb__match(stb__dout - (stb__in2(0) - 0x4000 + 1), i[2] + 1), i += 3;
4874 else /* *i >= 0x20 */
4875 stb__lit(i + 1, i[0] - 0x20 + 1), i += 1 + (i[0] - 0x20 + 1);
4876 }
4877 else
4878 { // more ifs for cases that expand large, since overhead is amortized
4879 if (*i >= 0x18)
4880 stb__match(stb__dout - (stb__in3(0) - 0x180000 + 1), i[3] + 1), i += 4;
4881 else if (*i >= 0x10)
4882 stb__match(stb__dout - (stb__in3(0) - 0x100000 + 1), stb__in2(3) + 1), i += 5;
4883 else if (*i >= 0x08)
4884 stb__lit(i + 2, stb__in2(0) - 0x0800 + 1), i += 2 + (stb__in2(0) - 0x0800 + 1);
4885 else if (*i == 0x07)
4886 stb__lit(i + 3, stb__in2(1) + 1), i += 3 + (stb__in2(1) + 1);
4887 else if (*i == 0x06)
4888 stb__match(stb__dout - (stb__in3(1) + 1), i[4] + 1), i += 5;
4889 else if (*i == 0x04)
4890 stb__match(stb__dout - (stb__in3(1) + 1), stb__in2(4) + 1), i += 6;
4891 }
4892 return i;
4893 }
4894
stb_adler32(unsigned int adler32,unsigned char * buffer,unsigned int buflen)4895 static unsigned int stb_adler32(unsigned int adler32, unsigned char* buffer, unsigned int buflen)
4896 {
4897 const unsigned long ADLER_MOD = 65521;
4898 unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16;
4899 unsigned long blocklen, i;
4900
4901 blocklen = buflen % 5552;
4902 while (buflen)
4903 {
4904 for (i = 0; i + 7 < blocklen; i += 8)
4905 {
4906 s1 += buffer[0], s2 += s1;
4907 s1 += buffer[1], s2 += s1;
4908 s1 += buffer[2], s2 += s1;
4909 s1 += buffer[3], s2 += s1;
4910 s1 += buffer[4], s2 += s1;
4911 s1 += buffer[5], s2 += s1;
4912 s1 += buffer[6], s2 += s1;
4913 s1 += buffer[7], s2 += s1;
4914
4915 buffer += 8;
4916 }
4917
4918 for (; i < blocklen; ++i)
4919 s1 += *buffer++, s2 += s1;
4920
4921 s1 %= ADLER_MOD, s2 %= ADLER_MOD;
4922 buflen -= blocklen;
4923 blocklen = 5552;
4924 }
4925 return (unsigned int)(s2 << 16) + (unsigned int)s1;
4926 }
4927
stb_decompress(unsigned char * output,unsigned char * i,unsigned int length)4928 static unsigned int stb_decompress(unsigned char* output, unsigned char* i, unsigned int length)
4929 {
4930 unsigned int olen;
4931 if (stb__in4(0) != 0x57bC0000) return 0;
4932 if (stb__in4(4) != 0) return 0; // error! stream is > 4GB
4933 olen = stb_decompress_length(i);
4934 stb__barrier2 = i;
4935 stb__barrier3 = i + length;
4936 stb__barrier = output + olen;
4937 stb__barrier4 = output;
4938 i += 16;
4939
4940 stb__dout = output;
4941 for (;;)
4942 {
4943 unsigned char* old_i = i;
4944 i = stb_decompress_token(i);
4945 if (i == old_i)
4946 {
4947 if (*i == 0x05 && i[1] == 0xfa)
4948 {
4949 IM_ASSERT(stb__dout == output + olen);
4950 if (stb__dout != output + olen) return 0;
4951 if (stb_adler32(1, output, olen) != (unsigned int)stb__in4(2))
4952 return 0;
4953 return olen;
4954 }
4955 else
4956 {
4957 IM_ASSERT(0); /* NOTREACHED */
4958 return 0;
4959 }
4960 }
4961 IM_ASSERT(stb__dout <= output + olen);
4962 if (stb__dout > output + olen)
4963 return 0;
4964 }
4965 }
4966
4967 //-----------------------------------------------------------------------------
4968 // ProggyClean.ttf
4969 // Copyright (c) 2004, 2005 Tristan Grimmer
4970 // MIT license (see License.txt in http://www.upperbounds.net/download/ProggyClean.ttf.zip)
4971 // Download and more information at http://upperbounds.net
4972 //-----------------------------------------------------------------------------
4973 // File: 'ProggyClean.ttf' (41208 bytes)
4974 // Exported using binary_to_compressed_c.cpp
4975 //-----------------------------------------------------------------------------
4976 static const char proggy_clean_ttf_compressed_data_base85[11980 + 1] =
4977 "7])#######hV0qs'/###[),##/l:$#Q6>##5[n42>c-TH`->>#/e>11NNV=Bv(*:.F?uu#(gRU.o0XGH`$vhLG1hxt9?W`#,5LsCp#-i>.r$<$6pD>Lb';9Crc6tgXmKVeU2cD4Eo3R/"
4978 "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#"
4979 "`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"
4980 "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"
4981 "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"
4982 "*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)"
4983 "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"
4984 "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."
4985 "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"
4986 "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(,)"
4987 "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#"
4988 "'/###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"
4989 "_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"
4990 "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/"
4991 "/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"
4992 "%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&#"
4993 "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)("
4994 "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"
4995 "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"
4996 "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^-"
4997 "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-"
4998 "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"
4999 "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%"
5000 "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]"
5001 "%(?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"
5002 "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:"
5003 "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("
5004 "$/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<"
5005 "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'?"
5006 "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/;"
5007 ")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"
5008 "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("
5009 "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"
5010 "bIu)'Z,*[>br5fX^:FPAWr-m2KgL<LUN098kTF&#lvo58=/vjDo;.;)Ka*hLR#/k=rKbxuV`>Q_nN6'8uTGT5g)uLv:873UpTLgH+#FgpH'_o1780Ph8KmxQJ8#H72L4@768@Tm&Q"
5011 "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<-"
5012 "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"
5013 "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"
5014 ".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@@"
5015 "$&)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*"
5016 "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"
5017 "@-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&#"
5018 "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#"
5019 "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"
5020 "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"
5021 "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&#"
5022 "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"
5023 ":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+"
5024 "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*"
5025 "$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"
5026 ":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"
5027 "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"
5028 "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"
5029 "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"
5030 ":^#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@&]>"
5031 "_>@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%"
5032 "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;"
5033 "^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:"
5034 "+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%"
5035 "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-"
5036 "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*"
5037 "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"
5038 "8kD2)2fU/M#$e.)T4,_=8hLim[&);?UkK'-x?'(:siIfL<$pFM`i<?%W(mGDHM%>iWP,##P`%/L<eXi:@Z9C.7o=@(pXdAO/NLQ8lPl+HPOQa8wD8=^GlPa8TKI1CjhsCTSLJM'/Wl>-"
5039 "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`"
5040 "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]%/"
5041 "+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"
5042 "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"
5043 "?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"
5044 "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"
5045 ">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'>"
5046 "[%$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"
5047 "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#"
5048 "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$"
5049 "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,)"
5050 "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"
5051 "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"
5052 "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"
5053 "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(#"
5054 ";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&>"
5055 "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#"
5056 "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"
5057 "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#"
5058 "/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-#"
5059 "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#"
5060 "TmD<#%JSMFove:CTBEXI:<eh2g)B,3h2^G3i;#d3jD>)4kMYD4lVu`4m`:&5niUA5@(A5BA1]PBB:xlBCC=2CDLXMCEUtiCf&0g2'tN?PGT4CPGT4CPGT4CPGT4CPGT4CPGT4CPGT4CP"
5061 "GT4CPGT4CPGT4CPGT4CPGT4CPGT4CP-qekC`.9kEg^+F$kwViFJTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5o,^<-28ZI'O?;xp"
5062 "O?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xp;7q-#lLYI:xvD=#";
5063
GetDefaultCompressedFontDataTTFBase85()5064 static const char* GetDefaultCompressedFontDataTTFBase85()
5065 {
5066 return proggy_clean_ttf_compressed_data_base85;
5067 }
5068