1 // dear imgui, v1.68 WIP
2 // (drawing and font code)
8 // [SECTION] STB libraries implementation
9 // [SECTION] Style functions
10 // [SECTION] ImDrawList
11 // [SECTION] ImDrawData
12 // [SECTION] Helpers ShadeVertsXXX functions
13 // [SECTION] ImFontConfig
14 // [SECTION] ImFontAtlas
15 // [SECTION] ImFontAtlas glyph ranges helpers
16 // [SECTION] ImFontGlyphRangesBuilder
18 // [SECTION] Internal Render Helpers
19 // [SECTION] Decompression code
20 // [SECTION] Default font data (ProggyClean.ttf)
24 #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
25 #define _CRT_SECURE_NO_WARNINGS
29 #ifndef IMGUI_DEFINE_MATH_OPERATORS
30 #define IMGUI_DEFINE_MATH_OPERATORS
32 #include "imgui_internal.h"
34 #include <stdio.h> // vsnprintf, sscanf, printf
36 #if defined(__GLIBC__) || defined(__sun) || defined(__CYGWIN__) || defined(__APPLE__)
37 #include <alloca.h> // alloca (glibc uses <alloca.h>. Note that Cygwin may have _WIN32 defined, so the order matters here)
39 #include <malloc.h> // alloca
41 #define alloca _alloca // for clang with MS Codegen
44 #include <stdlib.h> // alloca
48 // Visual Studio warnings
50 #pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff)
51 #pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
54 // Clang/GCC warnings with -Weverything
56 #pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse.
57 #pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants ok.
58 #pragma clang diagnostic ignored "-Wglobal-constructors" // warning : declaration requires a global destructor // similar to above, not sure what the exact difference it.
59 #pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness //
60 #if __has_warning("-Wzero-as-null-pointer-constant")
61 #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning : zero as null pointer constant // some standard header variations use #define NULL 0
63 #if __has_warning("-Wcomma")
64 #pragma clang diagnostic ignored "-Wcomma" // warning : possible misuse of comma operator here //
66 #if __has_warning("-Wreserved-id-macro")
67 #pragma clang diagnostic ignored "-Wreserved-id-macro" // warning : macro name is a reserved identifier //
69 #if __has_warning("-Wdouble-promotion")
70 #pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double.
72 #elif defined(__GNUC__)
73 #pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used
74 #pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function
75 #pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value
77 #pragma GCC diagnostic ignored "-Wclass-memaccess" // warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead
81 //-------------------------------------------------------------------------
82 // [SECTION] STB libraries implementation
83 //-------------------------------------------------------------------------
85 // Compile time options:
86 //#define IMGUI_STB_NAMESPACE ImGuiStb
87 //#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h"
88 //#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h"
89 //#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
90 //#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
92 #ifdef IMGUI_STB_NAMESPACE
93 namespace IMGUI_STB_NAMESPACE
98 #pragma warning (push)
99 #pragma warning (disable: 4456) // declaration of 'xx' hides previous local declaration
103 #pragma clang diagnostic push
104 #pragma clang diagnostic ignored "-Wunused-function"
105 #pragma clang diagnostic ignored "-Wmissing-prototypes"
106 #pragma clang diagnostic ignored "-Wimplicit-fallthrough"
107 #pragma clang diagnostic ignored "-Wcast-qual" // warning : cast from 'const xxxx *' to 'xxx *' drops const qualifier //
111 #pragma GCC diagnostic push
112 #pragma GCC diagnostic ignored "-Wtype-limits" // warning: comparison is always true due to limited range of data type [-Wtype-limits]
113 #pragma GCC diagnostic ignored "-Wcast-qual" // warning: cast from type 'const xxxx *' to type 'xxxx *' casts away qualifiers
116 #ifndef STB_RECT_PACK_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds)
117 #ifndef IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
119 #define STBRP_ASSERT(x) IM_ASSERT(x)
120 #define STBRP_SORT ImQsort
121 #define STB_RECT_PACK_IMPLEMENTATION
123 #ifdef IMGUI_STB_RECT_PACK_FILENAME
124 #include IMGUI_STB_RECT_PACK_FILENAME
126 #include "imstb_rectpack.h"
130 #ifndef STB_TRUETYPE_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds)
131 #ifndef IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
132 #define STBTT_malloc(x,u) ((void)(u), ImGui::MemAlloc(x))
133 #define STBTT_free(x,u) ((void)(u), ImGui::MemFree(x))
134 #define STBTT_assert(x) IM_ASSERT(x)
135 #define STBTT_fmod(x,y) ImFmod(x,y)
136 #define STBTT_sqrt(x) ImSqrt(x)
137 #define STBTT_pow(x,y) ImPow(x,y)
138 #define STBTT_fabs(x) ImFabs(x)
139 #define STBTT_ifloor(x) ((int)ImFloorStd(x))
140 #define STBTT_iceil(x) ((int)ImCeil(x))
142 #define STB_TRUETYPE_IMPLEMENTATION
144 #define STBTT_DEF extern
146 #ifdef IMGUI_STB_TRUETYPE_FILENAME
147 #include IMGUI_STB_TRUETYPE_FILENAME
149 #include "imstb_truetype.h"
154 #pragma GCC diagnostic pop
158 #pragma clang diagnostic pop
162 #pragma warning (pop)
165 #ifdef IMGUI_STB_NAMESPACE
166 } // namespace ImGuiStb
167 using namespace IMGUI_STB_NAMESPACE
;
170 //-----------------------------------------------------------------------------
171 // [SECTION] Style functions
172 //-----------------------------------------------------------------------------
174 void ImGui::StyleColorsDark(ImGuiStyle
* dst
)
176 ImGuiStyle
* style
= dst
? dst
: &ImGui::GetStyle();
177 ImVec4
* colors
= style
->Colors
;
179 colors
[ImGuiCol_Text
] = ImVec4(1.00f
, 1.00f
, 1.00f
, 1.00f
);
180 colors
[ImGuiCol_TextDisabled
] = ImVec4(0.50f
, 0.50f
, 0.50f
, 1.00f
);
181 colors
[ImGuiCol_WindowBg
] = ImVec4(0.06f
, 0.06f
, 0.06f
, 0.94f
);
182 colors
[ImGuiCol_ChildBg
] = ImVec4(0.00f
, 0.00f
, 0.00f
, 0.00f
);
183 colors
[ImGuiCol_PopupBg
] = ImVec4(0.08f
, 0.08f
, 0.08f
, 0.94f
);
184 colors
[ImGuiCol_Border
] = ImVec4(0.43f
, 0.43f
, 0.50f
, 0.50f
);
185 colors
[ImGuiCol_BorderShadow
] = ImVec4(0.00f
, 0.00f
, 0.00f
, 0.00f
);
186 colors
[ImGuiCol_FrameBg
] = ImVec4(0.16f
, 0.29f
, 0.48f
, 0.54f
);
187 colors
[ImGuiCol_FrameBgHovered
] = ImVec4(0.26f
, 0.59f
, 0.98f
, 0.40f
);
188 colors
[ImGuiCol_FrameBgActive
] = ImVec4(0.26f
, 0.59f
, 0.98f
, 0.67f
);
189 colors
[ImGuiCol_TitleBg
] = ImVec4(0.04f
, 0.04f
, 0.04f
, 1.00f
);
190 colors
[ImGuiCol_TitleBgActive
] = ImVec4(0.16f
, 0.29f
, 0.48f
, 1.00f
);
191 colors
[ImGuiCol_TitleBgCollapsed
] = ImVec4(0.00f
, 0.00f
, 0.00f
, 0.51f
);
192 colors
[ImGuiCol_MenuBarBg
] = ImVec4(0.14f
, 0.14f
, 0.14f
, 1.00f
);
193 colors
[ImGuiCol_ScrollbarBg
] = ImVec4(0.02f
, 0.02f
, 0.02f
, 0.53f
);
194 colors
[ImGuiCol_ScrollbarGrab
] = ImVec4(0.31f
, 0.31f
, 0.31f
, 1.00f
);
195 colors
[ImGuiCol_ScrollbarGrabHovered
] = ImVec4(0.41f
, 0.41f
, 0.41f
, 1.00f
);
196 colors
[ImGuiCol_ScrollbarGrabActive
] = ImVec4(0.51f
, 0.51f
, 0.51f
, 1.00f
);
197 colors
[ImGuiCol_CheckMark
] = ImVec4(0.26f
, 0.59f
, 0.98f
, 1.00f
);
198 colors
[ImGuiCol_SliderGrab
] = ImVec4(0.24f
, 0.52f
, 0.88f
, 1.00f
);
199 colors
[ImGuiCol_SliderGrabActive
] = ImVec4(0.26f
, 0.59f
, 0.98f
, 1.00f
);
200 colors
[ImGuiCol_Button
] = ImVec4(0.26f
, 0.59f
, 0.98f
, 0.40f
);
201 colors
[ImGuiCol_ButtonHovered
] = ImVec4(0.26f
, 0.59f
, 0.98f
, 1.00f
);
202 colors
[ImGuiCol_ButtonActive
] = ImVec4(0.06f
, 0.53f
, 0.98f
, 1.00f
);
203 colors
[ImGuiCol_Header
] = ImVec4(0.26f
, 0.59f
, 0.98f
, 0.31f
);
204 colors
[ImGuiCol_HeaderHovered
] = ImVec4(0.26f
, 0.59f
, 0.98f
, 0.80f
);
205 colors
[ImGuiCol_HeaderActive
] = ImVec4(0.26f
, 0.59f
, 0.98f
, 1.00f
);
206 colors
[ImGuiCol_Separator
] = colors
[ImGuiCol_Border
];
207 colors
[ImGuiCol_SeparatorHovered
] = ImVec4(0.10f
, 0.40f
, 0.75f
, 0.78f
);
208 colors
[ImGuiCol_SeparatorActive
] = ImVec4(0.10f
, 0.40f
, 0.75f
, 1.00f
);
209 colors
[ImGuiCol_ResizeGrip
] = ImVec4(0.26f
, 0.59f
, 0.98f
, 0.25f
);
210 colors
[ImGuiCol_ResizeGripHovered
] = ImVec4(0.26f
, 0.59f
, 0.98f
, 0.67f
);
211 colors
[ImGuiCol_ResizeGripActive
] = ImVec4(0.26f
, 0.59f
, 0.98f
, 0.95f
);
212 colors
[ImGuiCol_Tab
] = ImLerp(colors
[ImGuiCol_Header
], colors
[ImGuiCol_TitleBgActive
], 0.80f
);
213 colors
[ImGuiCol_TabHovered
] = colors
[ImGuiCol_HeaderHovered
];
214 colors
[ImGuiCol_TabActive
] = ImLerp(colors
[ImGuiCol_HeaderActive
], colors
[ImGuiCol_TitleBgActive
], 0.60f
);
215 colors
[ImGuiCol_TabUnfocused
] = ImLerp(colors
[ImGuiCol_Tab
], colors
[ImGuiCol_TitleBg
], 0.80f
);
216 colors
[ImGuiCol_TabUnfocusedActive
] = ImLerp(colors
[ImGuiCol_TabActive
], colors
[ImGuiCol_TitleBg
], 0.40f
);
217 colors
[ImGuiCol_PlotLines
] = ImVec4(0.61f
, 0.61f
, 0.61f
, 1.00f
);
218 colors
[ImGuiCol_PlotLinesHovered
] = ImVec4(1.00f
, 0.43f
, 0.35f
, 1.00f
);
219 colors
[ImGuiCol_PlotHistogram
] = ImVec4(0.90f
, 0.70f
, 0.00f
, 1.00f
);
220 colors
[ImGuiCol_PlotHistogramHovered
] = ImVec4(1.00f
, 0.60f
, 0.00f
, 1.00f
);
221 colors
[ImGuiCol_TextSelectedBg
] = ImVec4(0.26f
, 0.59f
, 0.98f
, 0.35f
);
222 colors
[ImGuiCol_DragDropTarget
] = ImVec4(1.00f
, 1.00f
, 0.00f
, 0.90f
);
223 colors
[ImGuiCol_NavHighlight
] = ImVec4(0.26f
, 0.59f
, 0.98f
, 1.00f
);
224 colors
[ImGuiCol_NavWindowingHighlight
] = ImVec4(1.00f
, 1.00f
, 1.00f
, 0.70f
);
225 colors
[ImGuiCol_NavWindowingDimBg
] = ImVec4(0.80f
, 0.80f
, 0.80f
, 0.20f
);
226 colors
[ImGuiCol_ModalWindowDimBg
] = ImVec4(0.80f
, 0.80f
, 0.80f
, 0.35f
);
229 void ImGui::StyleColorsClassic(ImGuiStyle
* dst
)
231 ImGuiStyle
* style
= dst
? dst
: &ImGui::GetStyle();
232 ImVec4
* colors
= style
->Colors
;
234 colors
[ImGuiCol_Text
] = ImVec4(0.90f
, 0.90f
, 0.90f
, 1.00f
);
235 colors
[ImGuiCol_TextDisabled
] = ImVec4(0.60f
, 0.60f
, 0.60f
, 1.00f
);
236 colors
[ImGuiCol_WindowBg
] = ImVec4(0.00f
, 0.00f
, 0.00f
, 0.70f
);
237 colors
[ImGuiCol_ChildBg
] = ImVec4(0.00f
, 0.00f
, 0.00f
, 0.00f
);
238 colors
[ImGuiCol_PopupBg
] = ImVec4(0.11f
, 0.11f
, 0.14f
, 0.92f
);
239 colors
[ImGuiCol_Border
] = ImVec4(0.50f
, 0.50f
, 0.50f
, 0.50f
);
240 colors
[ImGuiCol_BorderShadow
] = ImVec4(0.00f
, 0.00f
, 0.00f
, 0.00f
);
241 colors
[ImGuiCol_FrameBg
] = ImVec4(0.43f
, 0.43f
, 0.43f
, 0.39f
);
242 colors
[ImGuiCol_FrameBgHovered
] = ImVec4(0.47f
, 0.47f
, 0.69f
, 0.40f
);
243 colors
[ImGuiCol_FrameBgActive
] = ImVec4(0.42f
, 0.41f
, 0.64f
, 0.69f
);
244 colors
[ImGuiCol_TitleBg
] = ImVec4(0.27f
, 0.27f
, 0.54f
, 0.83f
);
245 colors
[ImGuiCol_TitleBgActive
] = ImVec4(0.32f
, 0.32f
, 0.63f
, 0.87f
);
246 colors
[ImGuiCol_TitleBgCollapsed
] = ImVec4(0.40f
, 0.40f
, 0.80f
, 0.20f
);
247 colors
[ImGuiCol_MenuBarBg
] = ImVec4(0.40f
, 0.40f
, 0.55f
, 0.80f
);
248 colors
[ImGuiCol_ScrollbarBg
] = ImVec4(0.20f
, 0.25f
, 0.30f
, 0.60f
);
249 colors
[ImGuiCol_ScrollbarGrab
] = ImVec4(0.40f
, 0.40f
, 0.80f
, 0.30f
);
250 colors
[ImGuiCol_ScrollbarGrabHovered
] = ImVec4(0.40f
, 0.40f
, 0.80f
, 0.40f
);
251 colors
[ImGuiCol_ScrollbarGrabActive
] = ImVec4(0.41f
, 0.39f
, 0.80f
, 0.60f
);
252 colors
[ImGuiCol_CheckMark
] = ImVec4(0.90f
, 0.90f
, 0.90f
, 0.50f
);
253 colors
[ImGuiCol_SliderGrab
] = ImVec4(1.00f
, 1.00f
, 1.00f
, 0.30f
);
254 colors
[ImGuiCol_SliderGrabActive
] = ImVec4(0.41f
, 0.39f
, 0.80f
, 0.60f
);
255 colors
[ImGuiCol_Button
] = ImVec4(0.35f
, 0.40f
, 0.61f
, 0.62f
);
256 colors
[ImGuiCol_ButtonHovered
] = ImVec4(0.40f
, 0.48f
, 0.71f
, 0.79f
);
257 colors
[ImGuiCol_ButtonActive
] = ImVec4(0.46f
, 0.54f
, 0.80f
, 1.00f
);
258 colors
[ImGuiCol_Header
] = ImVec4(0.40f
, 0.40f
, 0.90f
, 0.45f
);
259 colors
[ImGuiCol_HeaderHovered
] = ImVec4(0.45f
, 0.45f
, 0.90f
, 0.80f
);
260 colors
[ImGuiCol_HeaderActive
] = ImVec4(0.53f
, 0.53f
, 0.87f
, 0.80f
);
261 colors
[ImGuiCol_Separator
] = ImVec4(0.50f
, 0.50f
, 0.50f
, 1.00f
);
262 colors
[ImGuiCol_SeparatorHovered
] = ImVec4(0.60f
, 0.60f
, 0.70f
, 1.00f
);
263 colors
[ImGuiCol_SeparatorActive
] = ImVec4(0.70f
, 0.70f
, 0.90f
, 1.00f
);
264 colors
[ImGuiCol_ResizeGrip
] = ImVec4(1.00f
, 1.00f
, 1.00f
, 0.16f
);
265 colors
[ImGuiCol_ResizeGripHovered
] = ImVec4(0.78f
, 0.82f
, 1.00f
, 0.60f
);
266 colors
[ImGuiCol_ResizeGripActive
] = ImVec4(0.78f
, 0.82f
, 1.00f
, 0.90f
);
267 colors
[ImGuiCol_Tab
] = ImLerp(colors
[ImGuiCol_Header
], colors
[ImGuiCol_TitleBgActive
], 0.80f
);
268 colors
[ImGuiCol_TabHovered
] = colors
[ImGuiCol_HeaderHovered
];
269 colors
[ImGuiCol_TabActive
] = ImLerp(colors
[ImGuiCol_HeaderActive
], colors
[ImGuiCol_TitleBgActive
], 0.60f
);
270 colors
[ImGuiCol_TabUnfocused
] = ImLerp(colors
[ImGuiCol_Tab
], colors
[ImGuiCol_TitleBg
], 0.80f
);
271 colors
[ImGuiCol_TabUnfocusedActive
] = ImLerp(colors
[ImGuiCol_TabActive
], colors
[ImGuiCol_TitleBg
], 0.40f
);
272 colors
[ImGuiCol_PlotLines
] = ImVec4(1.00f
, 1.00f
, 1.00f
, 1.00f
);
273 colors
[ImGuiCol_PlotLinesHovered
] = ImVec4(0.90f
, 0.70f
, 0.00f
, 1.00f
);
274 colors
[ImGuiCol_PlotHistogram
] = ImVec4(0.90f
, 0.70f
, 0.00f
, 1.00f
);
275 colors
[ImGuiCol_PlotHistogramHovered
] = ImVec4(1.00f
, 0.60f
, 0.00f
, 1.00f
);
276 colors
[ImGuiCol_TextSelectedBg
] = ImVec4(0.00f
, 0.00f
, 1.00f
, 0.35f
);
277 colors
[ImGuiCol_DragDropTarget
] = ImVec4(1.00f
, 1.00f
, 0.00f
, 0.90f
);
278 colors
[ImGuiCol_NavHighlight
] = colors
[ImGuiCol_HeaderHovered
];
279 colors
[ImGuiCol_NavWindowingHighlight
] = ImVec4(1.00f
, 1.00f
, 1.00f
, 0.70f
);
280 colors
[ImGuiCol_NavWindowingDimBg
] = ImVec4(0.80f
, 0.80f
, 0.80f
, 0.20f
);
281 colors
[ImGuiCol_ModalWindowDimBg
] = ImVec4(0.20f
, 0.20f
, 0.20f
, 0.35f
);
284 // Those light colors are better suited with a thicker font than the default one + FrameBorder
285 void ImGui::StyleColorsLight(ImGuiStyle
* dst
)
287 ImGuiStyle
* style
= dst
? dst
: &ImGui::GetStyle();
288 ImVec4
* colors
= style
->Colors
;
290 colors
[ImGuiCol_Text
] = ImVec4(0.00f
, 0.00f
, 0.00f
, 1.00f
);
291 colors
[ImGuiCol_TextDisabled
] = ImVec4(0.60f
, 0.60f
, 0.60f
, 1.00f
);
292 colors
[ImGuiCol_WindowBg
] = ImVec4(0.94f
, 0.94f
, 0.94f
, 1.00f
);
293 colors
[ImGuiCol_ChildBg
] = ImVec4(0.00f
, 0.00f
, 0.00f
, 0.00f
);
294 colors
[ImGuiCol_PopupBg
] = ImVec4(1.00f
, 1.00f
, 1.00f
, 0.98f
);
295 colors
[ImGuiCol_Border
] = ImVec4(0.00f
, 0.00f
, 0.00f
, 0.30f
);
296 colors
[ImGuiCol_BorderShadow
] = ImVec4(0.00f
, 0.00f
, 0.00f
, 0.00f
);
297 colors
[ImGuiCol_FrameBg
] = ImVec4(1.00f
, 1.00f
, 1.00f
, 1.00f
);
298 colors
[ImGuiCol_FrameBgHovered
] = ImVec4(0.26f
, 0.59f
, 0.98f
, 0.40f
);
299 colors
[ImGuiCol_FrameBgActive
] = ImVec4(0.26f
, 0.59f
, 0.98f
, 0.67f
);
300 colors
[ImGuiCol_TitleBg
] = ImVec4(0.96f
, 0.96f
, 0.96f
, 1.00f
);
301 colors
[ImGuiCol_TitleBgActive
] = ImVec4(0.82f
, 0.82f
, 0.82f
, 1.00f
);
302 colors
[ImGuiCol_TitleBgCollapsed
] = ImVec4(1.00f
, 1.00f
, 1.00f
, 0.51f
);
303 colors
[ImGuiCol_MenuBarBg
] = ImVec4(0.86f
, 0.86f
, 0.86f
, 1.00f
);
304 colors
[ImGuiCol_ScrollbarBg
] = ImVec4(0.98f
, 0.98f
, 0.98f
, 0.53f
);
305 colors
[ImGuiCol_ScrollbarGrab
] = ImVec4(0.69f
, 0.69f
, 0.69f
, 0.80f
);
306 colors
[ImGuiCol_ScrollbarGrabHovered
] = ImVec4(0.49f
, 0.49f
, 0.49f
, 0.80f
);
307 colors
[ImGuiCol_ScrollbarGrabActive
] = ImVec4(0.49f
, 0.49f
, 0.49f
, 1.00f
);
308 colors
[ImGuiCol_CheckMark
] = ImVec4(0.26f
, 0.59f
, 0.98f
, 1.00f
);
309 colors
[ImGuiCol_SliderGrab
] = ImVec4(0.26f
, 0.59f
, 0.98f
, 0.78f
);
310 colors
[ImGuiCol_SliderGrabActive
] = ImVec4(0.46f
, 0.54f
, 0.80f
, 0.60f
);
311 colors
[ImGuiCol_Button
] = ImVec4(0.26f
, 0.59f
, 0.98f
, 0.40f
);
312 colors
[ImGuiCol_ButtonHovered
] = ImVec4(0.26f
, 0.59f
, 0.98f
, 1.00f
);
313 colors
[ImGuiCol_ButtonActive
] = ImVec4(0.06f
, 0.53f
, 0.98f
, 1.00f
);
314 colors
[ImGuiCol_Header
] = ImVec4(0.26f
, 0.59f
, 0.98f
, 0.31f
);
315 colors
[ImGuiCol_HeaderHovered
] = ImVec4(0.26f
, 0.59f
, 0.98f
, 0.80f
);
316 colors
[ImGuiCol_HeaderActive
] = ImVec4(0.26f
, 0.59f
, 0.98f
, 1.00f
);
317 colors
[ImGuiCol_Separator
] = ImVec4(0.39f
, 0.39f
, 0.39f
, 1.00f
);
318 colors
[ImGuiCol_SeparatorHovered
] = ImVec4(0.14f
, 0.44f
, 0.80f
, 0.78f
);
319 colors
[ImGuiCol_SeparatorActive
] = ImVec4(0.14f
, 0.44f
, 0.80f
, 1.00f
);
320 colors
[ImGuiCol_ResizeGrip
] = ImVec4(0.80f
, 0.80f
, 0.80f
, 0.56f
);
321 colors
[ImGuiCol_ResizeGripHovered
] = ImVec4(0.26f
, 0.59f
, 0.98f
, 0.67f
);
322 colors
[ImGuiCol_ResizeGripActive
] = ImVec4(0.26f
, 0.59f
, 0.98f
, 0.95f
);
323 colors
[ImGuiCol_Tab
] = ImLerp(colors
[ImGuiCol_Header
], colors
[ImGuiCol_TitleBgActive
], 0.90f
);
324 colors
[ImGuiCol_TabHovered
] = colors
[ImGuiCol_HeaderHovered
];
325 colors
[ImGuiCol_TabActive
] = ImLerp(colors
[ImGuiCol_HeaderActive
], colors
[ImGuiCol_TitleBgActive
], 0.60f
);
326 colors
[ImGuiCol_TabUnfocused
] = ImLerp(colors
[ImGuiCol_Tab
], colors
[ImGuiCol_TitleBg
], 0.80f
);
327 colors
[ImGuiCol_TabUnfocusedActive
] = ImLerp(colors
[ImGuiCol_TabActive
], colors
[ImGuiCol_TitleBg
], 0.40f
);
328 colors
[ImGuiCol_PlotLines
] = ImVec4(0.39f
, 0.39f
, 0.39f
, 1.00f
);
329 colors
[ImGuiCol_PlotLinesHovered
] = ImVec4(1.00f
, 0.43f
, 0.35f
, 1.00f
);
330 colors
[ImGuiCol_PlotHistogram
] = ImVec4(0.90f
, 0.70f
, 0.00f
, 1.00f
);
331 colors
[ImGuiCol_PlotHistogramHovered
] = ImVec4(1.00f
, 0.45f
, 0.00f
, 1.00f
);
332 colors
[ImGuiCol_TextSelectedBg
] = ImVec4(0.26f
, 0.59f
, 0.98f
, 0.35f
);
333 colors
[ImGuiCol_DragDropTarget
] = ImVec4(0.26f
, 0.59f
, 0.98f
, 0.95f
);
334 colors
[ImGuiCol_NavHighlight
] = colors
[ImGuiCol_HeaderHovered
];
335 colors
[ImGuiCol_NavWindowingHighlight
] = ImVec4(0.70f
, 0.70f
, 0.70f
, 0.70f
);
336 colors
[ImGuiCol_NavWindowingDimBg
] = ImVec4(0.20f
, 0.20f
, 0.20f
, 0.20f
);
337 colors
[ImGuiCol_ModalWindowDimBg
] = ImVec4(0.20f
, 0.20f
, 0.20f
, 0.35f
);
340 //-----------------------------------------------------------------------------
342 //-----------------------------------------------------------------------------
344 ImDrawListSharedData::ImDrawListSharedData()
348 CurveTessellationTol
= 0.0f
;
349 ClipRectFullscreen
= ImVec4(-8192.0f
, -8192.0f
, +8192.0f
, +8192.0f
);
352 for (int i
= 0; i
< IM_ARRAYSIZE(CircleVtx12
); i
++)
354 const float a
= ((float)i
* 2 * IM_PI
) / (float)IM_ARRAYSIZE(CircleVtx12
);
355 CircleVtx12
[i
] = ImVec2(ImCos(a
), ImSin(a
));
359 void ImDrawList::Clear()
364 Flags
= ImDrawListFlags_AntiAliasedLines
| ImDrawListFlags_AntiAliasedFill
;
368 _ClipRectStack
.resize(0);
369 _TextureIdStack
.resize(0);
371 _ChannelsCurrent
= 0;
373 // NB: Do not clear channels so our allocations are re-used after the first frame.
376 void ImDrawList::ClearFreeMemory()
384 _ClipRectStack
.clear();
385 _TextureIdStack
.clear();
387 _ChannelsCurrent
= 0;
389 for (int i
= 0; i
< _Channels
.Size
; i
++)
391 if (i
== 0) memset(&_Channels
[0], 0, sizeof(_Channels
[0])); // channel 0 is a copy of CmdBuffer/IdxBuffer, don't destruct again
392 _Channels
[i
].CmdBuffer
.clear();
393 _Channels
[i
].IdxBuffer
.clear();
398 ImDrawList
* ImDrawList::CloneOutput() const
400 ImDrawList
* dst
= IM_NEW(ImDrawList(NULL
));
401 dst
->CmdBuffer
= CmdBuffer
;
402 dst
->IdxBuffer
= IdxBuffer
;
403 dst
->VtxBuffer
= VtxBuffer
;
408 // Using macros because C++ is a terrible language, we want guaranteed inline, no code in header, and no overhead in Debug builds
409 #define GetCurrentClipRect() (_ClipRectStack.Size ? _ClipRectStack.Data[_ClipRectStack.Size-1] : _Data->ClipRectFullscreen)
410 #define GetCurrentTextureId() (_TextureIdStack.Size ? _TextureIdStack.Data[_TextureIdStack.Size-1] : NULL)
412 void ImDrawList::AddDrawCmd()
415 draw_cmd
.ClipRect
= GetCurrentClipRect();
416 draw_cmd
.TextureId
= GetCurrentTextureId();
418 IM_ASSERT(draw_cmd
.ClipRect
.x
<= draw_cmd
.ClipRect
.z
&& draw_cmd
.ClipRect
.y
<= draw_cmd
.ClipRect
.w
);
419 CmdBuffer
.push_back(draw_cmd
);
422 void ImDrawList::AddCallback(ImDrawCallback callback
, void* callback_data
)
424 ImDrawCmd
* current_cmd
= CmdBuffer
.Size
? &CmdBuffer
.back() : NULL
;
425 if (!current_cmd
|| current_cmd
->ElemCount
!= 0 || current_cmd
->UserCallback
!= NULL
)
428 current_cmd
= &CmdBuffer
.back();
430 current_cmd
->UserCallback
= callback
;
431 current_cmd
->UserCallbackData
= callback_data
;
433 AddDrawCmd(); // Force a new command after us (see comment below)
436 // 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.
437 // 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.
438 void ImDrawList::UpdateClipRect()
440 // If current command is used with different settings we need to add a new command
441 const ImVec4 curr_clip_rect
= GetCurrentClipRect();
442 ImDrawCmd
* curr_cmd
= CmdBuffer
.Size
> 0 ? &CmdBuffer
.Data
[CmdBuffer
.Size
-1] : NULL
;
443 if (!curr_cmd
|| (curr_cmd
->ElemCount
!= 0 && memcmp(&curr_cmd
->ClipRect
, &curr_clip_rect
, sizeof(ImVec4
)) != 0) || curr_cmd
->UserCallback
!= NULL
)
449 // Try to merge with previous command if it matches, else use current command
450 ImDrawCmd
* prev_cmd
= CmdBuffer
.Size
> 1 ? curr_cmd
- 1 : NULL
;
451 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
)
452 CmdBuffer
.pop_back();
454 curr_cmd
->ClipRect
= curr_clip_rect
;
457 void ImDrawList::UpdateTextureID()
459 // If current command is used with different settings we need to add a new command
460 const ImTextureID curr_texture_id
= GetCurrentTextureId();
461 ImDrawCmd
* curr_cmd
= CmdBuffer
.Size
? &CmdBuffer
.back() : NULL
;
462 if (!curr_cmd
|| (curr_cmd
->ElemCount
!= 0 && curr_cmd
->TextureId
!= curr_texture_id
) || curr_cmd
->UserCallback
!= NULL
)
468 // Try to merge with previous command if it matches, else use current command
469 ImDrawCmd
* prev_cmd
= CmdBuffer
.Size
> 1 ? curr_cmd
- 1 : NULL
;
470 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
)
471 CmdBuffer
.pop_back();
473 curr_cmd
->TextureId
= curr_texture_id
;
476 #undef GetCurrentClipRect
477 #undef GetCurrentTextureId
479 // 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)
480 void ImDrawList::PushClipRect(ImVec2 cr_min
, ImVec2 cr_max
, bool intersect_with_current_clip_rect
)
482 ImVec4
cr(cr_min
.x
, cr_min
.y
, cr_max
.x
, cr_max
.y
);
483 if (intersect_with_current_clip_rect
&& _ClipRectStack
.Size
)
485 ImVec4 current
= _ClipRectStack
.Data
[_ClipRectStack
.Size
-1];
486 if (cr
.x
< current
.x
) cr
.x
= current
.x
;
487 if (cr
.y
< current
.y
) cr
.y
= current
.y
;
488 if (cr
.z
> current
.z
) cr
.z
= current
.z
;
489 if (cr
.w
> current
.w
) cr
.w
= current
.w
;
491 cr
.z
= ImMax(cr
.x
, cr
.z
);
492 cr
.w
= ImMax(cr
.y
, cr
.w
);
494 _ClipRectStack
.push_back(cr
);
498 void ImDrawList::PushClipRectFullScreen()
500 PushClipRect(ImVec2(_Data
->ClipRectFullscreen
.x
, _Data
->ClipRectFullscreen
.y
), ImVec2(_Data
->ClipRectFullscreen
.z
, _Data
->ClipRectFullscreen
.w
));
503 void ImDrawList::PopClipRect()
505 IM_ASSERT(_ClipRectStack
.Size
> 0);
506 _ClipRectStack
.pop_back();
510 void ImDrawList::PushTextureID(ImTextureID texture_id
)
512 _TextureIdStack
.push_back(texture_id
);
516 void ImDrawList::PopTextureID()
518 IM_ASSERT(_TextureIdStack
.Size
> 0);
519 _TextureIdStack
.pop_back();
523 void ImDrawList::ChannelsSplit(int channels_count
)
525 IM_ASSERT(_ChannelsCurrent
== 0 && _ChannelsCount
== 1);
526 int old_channels_count
= _Channels
.Size
;
527 if (old_channels_count
< channels_count
)
528 _Channels
.resize(channels_count
);
529 _ChannelsCount
= channels_count
;
531 // _Channels[] (24/32 bytes each) hold storage that we'll swap with this->_CmdBuffer/_IdxBuffer
532 // 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.
533 // When we switch to the next channel, we'll copy _CmdBuffer/_IdxBuffer into _Channels[0] and then _Channels[1] into _CmdBuffer/_IdxBuffer
534 memset(&_Channels
[0], 0, sizeof(ImDrawChannel
));
535 for (int i
= 1; i
< channels_count
; i
++)
537 if (i
>= old_channels_count
)
539 IM_PLACEMENT_NEW(&_Channels
[i
]) ImDrawChannel();
543 _Channels
[i
].CmdBuffer
.resize(0);
544 _Channels
[i
].IdxBuffer
.resize(0);
546 if (_Channels
[i
].CmdBuffer
.Size
== 0)
549 draw_cmd
.ClipRect
= _ClipRectStack
.back();
550 draw_cmd
.TextureId
= _TextureIdStack
.back();
551 _Channels
[i
].CmdBuffer
.push_back(draw_cmd
);
556 void ImDrawList::ChannelsMerge()
558 // 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.
559 if (_ChannelsCount
<= 1)
562 ChannelsSetCurrent(0);
563 if (CmdBuffer
.Size
&& CmdBuffer
.back().ElemCount
== 0)
564 CmdBuffer
.pop_back();
566 int new_cmd_buffer_count
= 0, new_idx_buffer_count
= 0;
567 for (int i
= 1; i
< _ChannelsCount
; i
++)
569 ImDrawChannel
& ch
= _Channels
[i
];
570 if (ch
.CmdBuffer
.Size
&& ch
.CmdBuffer
.back().ElemCount
== 0)
571 ch
.CmdBuffer
.pop_back();
572 new_cmd_buffer_count
+= ch
.CmdBuffer
.Size
;
573 new_idx_buffer_count
+= ch
.IdxBuffer
.Size
;
575 CmdBuffer
.resize(CmdBuffer
.Size
+ new_cmd_buffer_count
);
576 IdxBuffer
.resize(IdxBuffer
.Size
+ new_idx_buffer_count
);
578 ImDrawCmd
* cmd_write
= CmdBuffer
.Data
+ CmdBuffer
.Size
- new_cmd_buffer_count
;
579 _IdxWritePtr
= IdxBuffer
.Data
+ IdxBuffer
.Size
- new_idx_buffer_count
;
580 for (int i
= 1; i
< _ChannelsCount
; i
++)
582 ImDrawChannel
& ch
= _Channels
[i
];
583 if (int sz
= ch
.CmdBuffer
.Size
) { memcpy(cmd_write
, ch
.CmdBuffer
.Data
, sz
* sizeof(ImDrawCmd
)); cmd_write
+= sz
; }
584 if (int sz
= ch
.IdxBuffer
.Size
) { memcpy(_IdxWritePtr
, ch
.IdxBuffer
.Data
, sz
* sizeof(ImDrawIdx
)); _IdxWritePtr
+= sz
; }
586 UpdateClipRect(); // We call this instead of AddDrawCmd(), so that empty channels won't produce an extra draw call.
590 void ImDrawList::ChannelsSetCurrent(int idx
)
592 IM_ASSERT(idx
< _ChannelsCount
);
593 if (_ChannelsCurrent
== idx
) return;
594 memcpy(&_Channels
.Data
[_ChannelsCurrent
].CmdBuffer
, &CmdBuffer
, sizeof(CmdBuffer
)); // copy 12 bytes, four times
595 memcpy(&_Channels
.Data
[_ChannelsCurrent
].IdxBuffer
, &IdxBuffer
, sizeof(IdxBuffer
));
596 _ChannelsCurrent
= idx
;
597 memcpy(&CmdBuffer
, &_Channels
.Data
[_ChannelsCurrent
].CmdBuffer
, sizeof(CmdBuffer
));
598 memcpy(&IdxBuffer
, &_Channels
.Data
[_ChannelsCurrent
].IdxBuffer
, sizeof(IdxBuffer
));
599 _IdxWritePtr
= IdxBuffer
.Data
+ IdxBuffer
.Size
;
602 // NB: this can be called with negative count for removing primitives (as long as the result does not underflow)
603 void ImDrawList::PrimReserve(int idx_count
, int vtx_count
)
605 ImDrawCmd
& draw_cmd
= CmdBuffer
.Data
[CmdBuffer
.Size
-1];
606 draw_cmd
.ElemCount
+= idx_count
;
608 int vtx_buffer_old_size
= VtxBuffer
.Size
;
609 VtxBuffer
.resize(vtx_buffer_old_size
+ vtx_count
);
610 _VtxWritePtr
= VtxBuffer
.Data
+ vtx_buffer_old_size
;
612 int idx_buffer_old_size
= IdxBuffer
.Size
;
613 IdxBuffer
.resize(idx_buffer_old_size
+ idx_count
);
614 _IdxWritePtr
= IdxBuffer
.Data
+ idx_buffer_old_size
;
617 // Fully unrolled with inline call to keep our debug builds decently fast.
618 void ImDrawList::PrimRect(const ImVec2
& a
, const ImVec2
& c
, ImU32 col
)
620 ImVec2
b(c
.x
, a
.y
), d(a
.x
, c
.y
), uv(_Data
->TexUvWhitePixel
);
621 ImDrawIdx idx
= (ImDrawIdx
)_VtxCurrentIdx
;
622 _IdxWritePtr
[0] = idx
; _IdxWritePtr
[1] = (ImDrawIdx
)(idx
+1); _IdxWritePtr
[2] = (ImDrawIdx
)(idx
+2);
623 _IdxWritePtr
[3] = idx
; _IdxWritePtr
[4] = (ImDrawIdx
)(idx
+2); _IdxWritePtr
[5] = (ImDrawIdx
)(idx
+3);
624 _VtxWritePtr
[0].pos
= a
; _VtxWritePtr
[0].uv
= uv
; _VtxWritePtr
[0].col
= col
;
625 _VtxWritePtr
[1].pos
= b
; _VtxWritePtr
[1].uv
= uv
; _VtxWritePtr
[1].col
= col
;
626 _VtxWritePtr
[2].pos
= c
; _VtxWritePtr
[2].uv
= uv
; _VtxWritePtr
[2].col
= col
;
627 _VtxWritePtr
[3].pos
= d
; _VtxWritePtr
[3].uv
= uv
; _VtxWritePtr
[3].col
= col
;
633 void ImDrawList::PrimRectUV(const ImVec2
& a
, const ImVec2
& c
, const ImVec2
& uv_a
, const ImVec2
& uv_c
, ImU32 col
)
635 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
);
636 ImDrawIdx idx
= (ImDrawIdx
)_VtxCurrentIdx
;
637 _IdxWritePtr
[0] = idx
; _IdxWritePtr
[1] = (ImDrawIdx
)(idx
+1); _IdxWritePtr
[2] = (ImDrawIdx
)(idx
+2);
638 _IdxWritePtr
[3] = idx
; _IdxWritePtr
[4] = (ImDrawIdx
)(idx
+2); _IdxWritePtr
[5] = (ImDrawIdx
)(idx
+3);
639 _VtxWritePtr
[0].pos
= a
; _VtxWritePtr
[0].uv
= uv_a
; _VtxWritePtr
[0].col
= col
;
640 _VtxWritePtr
[1].pos
= b
; _VtxWritePtr
[1].uv
= uv_b
; _VtxWritePtr
[1].col
= col
;
641 _VtxWritePtr
[2].pos
= c
; _VtxWritePtr
[2].uv
= uv_c
; _VtxWritePtr
[2].col
= col
;
642 _VtxWritePtr
[3].pos
= d
; _VtxWritePtr
[3].uv
= uv_d
; _VtxWritePtr
[3].col
= col
;
648 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
)
650 ImDrawIdx idx
= (ImDrawIdx
)_VtxCurrentIdx
;
651 _IdxWritePtr
[0] = idx
; _IdxWritePtr
[1] = (ImDrawIdx
)(idx
+1); _IdxWritePtr
[2] = (ImDrawIdx
)(idx
+2);
652 _IdxWritePtr
[3] = idx
; _IdxWritePtr
[4] = (ImDrawIdx
)(idx
+2); _IdxWritePtr
[5] = (ImDrawIdx
)(idx
+3);
653 _VtxWritePtr
[0].pos
= a
; _VtxWritePtr
[0].uv
= uv_a
; _VtxWritePtr
[0].col
= col
;
654 _VtxWritePtr
[1].pos
= b
; _VtxWritePtr
[1].uv
= uv_b
; _VtxWritePtr
[1].col
= col
;
655 _VtxWritePtr
[2].pos
= c
; _VtxWritePtr
[2].uv
= uv_c
; _VtxWritePtr
[2].col
= col
;
656 _VtxWritePtr
[3].pos
= d
; _VtxWritePtr
[3].uv
= uv_d
; _VtxWritePtr
[3].col
= col
;
662 // On AddPolyline() and AddConvexPolyFilled() we intentionally avoid using ImVec2 and superflous function calls to optimize debug/non-inlined builds.
663 // Those macros expects l-values.
664 #define IM_NORMALIZE2F_OVER_ZERO(VX,VY) { float d2 = VX*VX + VY*VY; if (d2 > 0.0f) { float inv_len = 1.0f / ImSqrt(d2); VX *= inv_len; VY *= inv_len; } }
665 #define IM_NORMALIZE2F_OVER_EPSILON_CLAMP(VX,VY,EPS,INVLENMAX) { float d2 = VX*VX + VY*VY; if (d2 > EPS) { float inv_len = 1.0f / ImSqrt(d2); if (inv_len > INVLENMAX) inv_len = INVLENMAX; VX *= inv_len; VY *= inv_len; } }
667 // TODO: Thickness anti-aliased lines cap are missing their AA fringe.
668 // We avoid using the ImVec2 math operators here to reduce cost to a minimum for debug/non-inlined builds.
669 void ImDrawList::AddPolyline(const ImVec2
* points
, const int points_count
, ImU32 col
, bool closed
, float thickness
)
671 if (points_count
< 2)
674 const ImVec2 uv
= _Data
->TexUvWhitePixel
;
676 int count
= points_count
;
678 count
= points_count
-1;
680 const bool thick_line
= thickness
> 1.0f
;
681 if (Flags
& ImDrawListFlags_AntiAliasedLines
)
683 // Anti-aliased stroke
684 const float AA_SIZE
= 1.0f
;
685 const ImU32 col_trans
= col
& ~IM_COL32_A_MASK
;
687 const int idx_count
= thick_line
? count
*18 : count
*12;
688 const int vtx_count
= thick_line
? points_count
*4 : points_count
*3;
689 PrimReserve(idx_count
, vtx_count
);
692 ImVec2
* temp_normals
= (ImVec2
*)alloca(points_count
* (thick_line
? 5 : 3) * sizeof(ImVec2
)); //-V630
693 ImVec2
* temp_points
= temp_normals
+ points_count
;
695 for (int i1
= 0; i1
< count
; i1
++)
697 const int i2
= (i1
+1) == points_count
? 0 : i1
+1;
698 float dx
= points
[i2
].x
- points
[i1
].x
;
699 float dy
= points
[i2
].y
- points
[i1
].y
;
700 IM_NORMALIZE2F_OVER_ZERO(dx
, dy
);
701 temp_normals
[i1
].x
= dy
;
702 temp_normals
[i1
].y
= -dx
;
705 temp_normals
[points_count
-1] = temp_normals
[points_count
-2];
711 temp_points
[0] = points
[0] + temp_normals
[0] * AA_SIZE
;
712 temp_points
[1] = points
[0] - temp_normals
[0] * AA_SIZE
;
713 temp_points
[(points_count
-1)*2+0] = points
[points_count
-1] + temp_normals
[points_count
-1] * AA_SIZE
;
714 temp_points
[(points_count
-1)*2+1] = points
[points_count
-1] - temp_normals
[points_count
-1] * AA_SIZE
;
717 // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer.
718 unsigned int idx1
= _VtxCurrentIdx
;
719 for (int i1
= 0; i1
< count
; i1
++)
721 const int i2
= (i1
+1) == points_count
? 0 : i1
+1;
722 unsigned int idx2
= (i1
+1) == points_count
? _VtxCurrentIdx
: idx1
+3;
725 float dm_x
= (temp_normals
[i1
].x
+ temp_normals
[i2
].x
) * 0.5f
;
726 float dm_y
= (temp_normals
[i1
].y
+ temp_normals
[i2
].y
) * 0.5f
;
727 IM_NORMALIZE2F_OVER_EPSILON_CLAMP(dm_x
, dm_y
, 0.000001f
, 100.0f
)
731 // Add temporary vertexes
732 ImVec2
* out_vtx
= &temp_points
[i2
*2];
733 out_vtx
[0].x
= points
[i2
].x
+ dm_x
;
734 out_vtx
[0].y
= points
[i2
].y
+ dm_y
;
735 out_vtx
[1].x
= points
[i2
].x
- dm_x
;
736 out_vtx
[1].y
= points
[i2
].y
- dm_y
;
739 _IdxWritePtr
[0] = (ImDrawIdx
)(idx2
+0); _IdxWritePtr
[1] = (ImDrawIdx
)(idx1
+0); _IdxWritePtr
[2] = (ImDrawIdx
)(idx1
+2);
740 _IdxWritePtr
[3] = (ImDrawIdx
)(idx1
+2); _IdxWritePtr
[4] = (ImDrawIdx
)(idx2
+2); _IdxWritePtr
[5] = (ImDrawIdx
)(idx2
+0);
741 _IdxWritePtr
[6] = (ImDrawIdx
)(idx2
+1); _IdxWritePtr
[7] = (ImDrawIdx
)(idx1
+1); _IdxWritePtr
[8] = (ImDrawIdx
)(idx1
+0);
742 _IdxWritePtr
[9] = (ImDrawIdx
)(idx1
+0); _IdxWritePtr
[10]= (ImDrawIdx
)(idx2
+0); _IdxWritePtr
[11]= (ImDrawIdx
)(idx2
+1);
749 for (int i
= 0; i
< points_count
; i
++)
751 _VtxWritePtr
[0].pos
= points
[i
]; _VtxWritePtr
[0].uv
= uv
; _VtxWritePtr
[0].col
= col
;
752 _VtxWritePtr
[1].pos
= temp_points
[i
*2+0]; _VtxWritePtr
[1].uv
= uv
; _VtxWritePtr
[1].col
= col_trans
;
753 _VtxWritePtr
[2].pos
= temp_points
[i
*2+1]; _VtxWritePtr
[2].uv
= uv
; _VtxWritePtr
[2].col
= col_trans
;
759 const float half_inner_thickness
= (thickness
- AA_SIZE
) * 0.5f
;
762 temp_points
[0] = points
[0] + temp_normals
[0] * (half_inner_thickness
+ AA_SIZE
);
763 temp_points
[1] = points
[0] + temp_normals
[0] * (half_inner_thickness
);
764 temp_points
[2] = points
[0] - temp_normals
[0] * (half_inner_thickness
);
765 temp_points
[3] = points
[0] - temp_normals
[0] * (half_inner_thickness
+ AA_SIZE
);
766 temp_points
[(points_count
-1)*4+0] = points
[points_count
-1] + temp_normals
[points_count
-1] * (half_inner_thickness
+ AA_SIZE
);
767 temp_points
[(points_count
-1)*4+1] = points
[points_count
-1] + temp_normals
[points_count
-1] * (half_inner_thickness
);
768 temp_points
[(points_count
-1)*4+2] = points
[points_count
-1] - temp_normals
[points_count
-1] * (half_inner_thickness
);
769 temp_points
[(points_count
-1)*4+3] = points
[points_count
-1] - temp_normals
[points_count
-1] * (half_inner_thickness
+ AA_SIZE
);
772 // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer.
773 unsigned int idx1
= _VtxCurrentIdx
;
774 for (int i1
= 0; i1
< count
; i1
++)
776 const int i2
= (i1
+1) == points_count
? 0 : i1
+1;
777 unsigned int idx2
= (i1
+1) == points_count
? _VtxCurrentIdx
: idx1
+4;
780 float dm_x
= (temp_normals
[i1
].x
+ temp_normals
[i2
].x
) * 0.5f
;
781 float dm_y
= (temp_normals
[i1
].y
+ temp_normals
[i2
].y
) * 0.5f
;
782 IM_NORMALIZE2F_OVER_EPSILON_CLAMP(dm_x
, dm_y
, 0.000001f
, 100.0f
);
783 float dm_out_x
= dm_x
* (half_inner_thickness
+ AA_SIZE
);
784 float dm_out_y
= dm_y
* (half_inner_thickness
+ AA_SIZE
);
785 float dm_in_x
= dm_x
* half_inner_thickness
;
786 float dm_in_y
= dm_y
* half_inner_thickness
;
788 // Add temporary vertexes
789 ImVec2
* out_vtx
= &temp_points
[i2
*4];
790 out_vtx
[0].x
= points
[i2
].x
+ dm_out_x
;
791 out_vtx
[0].y
= points
[i2
].y
+ dm_out_y
;
792 out_vtx
[1].x
= points
[i2
].x
+ dm_in_x
;
793 out_vtx
[1].y
= points
[i2
].y
+ dm_in_y
;
794 out_vtx
[2].x
= points
[i2
].x
- dm_in_x
;
795 out_vtx
[2].y
= points
[i2
].y
- dm_in_y
;
796 out_vtx
[3].x
= points
[i2
].x
- dm_out_x
;
797 out_vtx
[3].y
= points
[i2
].y
- dm_out_y
;
800 _IdxWritePtr
[0] = (ImDrawIdx
)(idx2
+1); _IdxWritePtr
[1] = (ImDrawIdx
)(idx1
+1); _IdxWritePtr
[2] = (ImDrawIdx
)(idx1
+2);
801 _IdxWritePtr
[3] = (ImDrawIdx
)(idx1
+2); _IdxWritePtr
[4] = (ImDrawIdx
)(idx2
+2); _IdxWritePtr
[5] = (ImDrawIdx
)(idx2
+1);
802 _IdxWritePtr
[6] = (ImDrawIdx
)(idx2
+1); _IdxWritePtr
[7] = (ImDrawIdx
)(idx1
+1); _IdxWritePtr
[8] = (ImDrawIdx
)(idx1
+0);
803 _IdxWritePtr
[9] = (ImDrawIdx
)(idx1
+0); _IdxWritePtr
[10] = (ImDrawIdx
)(idx2
+0); _IdxWritePtr
[11] = (ImDrawIdx
)(idx2
+1);
804 _IdxWritePtr
[12] = (ImDrawIdx
)(idx2
+2); _IdxWritePtr
[13] = (ImDrawIdx
)(idx1
+2); _IdxWritePtr
[14] = (ImDrawIdx
)(idx1
+3);
805 _IdxWritePtr
[15] = (ImDrawIdx
)(idx1
+3); _IdxWritePtr
[16] = (ImDrawIdx
)(idx2
+3); _IdxWritePtr
[17] = (ImDrawIdx
)(idx2
+2);
812 for (int i
= 0; i
< points_count
; i
++)
814 _VtxWritePtr
[0].pos
= temp_points
[i
*4+0]; _VtxWritePtr
[0].uv
= uv
; _VtxWritePtr
[0].col
= col_trans
;
815 _VtxWritePtr
[1].pos
= temp_points
[i
*4+1]; _VtxWritePtr
[1].uv
= uv
; _VtxWritePtr
[1].col
= col
;
816 _VtxWritePtr
[2].pos
= temp_points
[i
*4+2]; _VtxWritePtr
[2].uv
= uv
; _VtxWritePtr
[2].col
= col
;
817 _VtxWritePtr
[3].pos
= temp_points
[i
*4+3]; _VtxWritePtr
[3].uv
= uv
; _VtxWritePtr
[3].col
= col_trans
;
821 _VtxCurrentIdx
+= (ImDrawIdx
)vtx_count
;
825 // Non Anti-aliased Stroke
826 const int idx_count
= count
*6;
827 const int vtx_count
= count
*4; // FIXME-OPT: Not sharing edges
828 PrimReserve(idx_count
, vtx_count
);
830 for (int i1
= 0; i1
< count
; i1
++)
832 const int i2
= (i1
+1) == points_count
? 0 : i1
+1;
833 const ImVec2
& p1
= points
[i1
];
834 const ImVec2
& p2
= points
[i2
];
836 float dx
= p2
.x
- p1
.x
;
837 float dy
= p2
.y
- p1
.y
;
838 IM_NORMALIZE2F_OVER_ZERO(dx
, dy
);
839 dx
*= (thickness
* 0.5f
);
840 dy
*= (thickness
* 0.5f
);
842 _VtxWritePtr
[0].pos
.x
= p1
.x
+ dy
; _VtxWritePtr
[0].pos
.y
= p1
.y
- dx
; _VtxWritePtr
[0].uv
= uv
; _VtxWritePtr
[0].col
= col
;
843 _VtxWritePtr
[1].pos
.x
= p2
.x
+ dy
; _VtxWritePtr
[1].pos
.y
= p2
.y
- dx
; _VtxWritePtr
[1].uv
= uv
; _VtxWritePtr
[1].col
= col
;
844 _VtxWritePtr
[2].pos
.x
= p2
.x
- dy
; _VtxWritePtr
[2].pos
.y
= p2
.y
+ dx
; _VtxWritePtr
[2].uv
= uv
; _VtxWritePtr
[2].col
= col
;
845 _VtxWritePtr
[3].pos
.x
= p1
.x
- dy
; _VtxWritePtr
[3].pos
.y
= p1
.y
+ dx
; _VtxWritePtr
[3].uv
= uv
; _VtxWritePtr
[3].col
= col
;
848 _IdxWritePtr
[0] = (ImDrawIdx
)(_VtxCurrentIdx
); _IdxWritePtr
[1] = (ImDrawIdx
)(_VtxCurrentIdx
+1); _IdxWritePtr
[2] = (ImDrawIdx
)(_VtxCurrentIdx
+2);
849 _IdxWritePtr
[3] = (ImDrawIdx
)(_VtxCurrentIdx
); _IdxWritePtr
[4] = (ImDrawIdx
)(_VtxCurrentIdx
+2); _IdxWritePtr
[5] = (ImDrawIdx
)(_VtxCurrentIdx
+3);
856 // We intentionally avoid using ImVec2 and its math operators here to reduce cost to a minimum for debug/non-inlined builds.
857 void ImDrawList::AddConvexPolyFilled(const ImVec2
* points
, const int points_count
, ImU32 col
)
859 if (points_count
< 3)
862 const ImVec2 uv
= _Data
->TexUvWhitePixel
;
864 if (Flags
& ImDrawListFlags_AntiAliasedFill
)
867 const float AA_SIZE
= 1.0f
;
868 const ImU32 col_trans
= col
& ~IM_COL32_A_MASK
;
869 const int idx_count
= (points_count
-2)*3 + points_count
*6;
870 const int vtx_count
= (points_count
*2);
871 PrimReserve(idx_count
, vtx_count
);
873 // Add indexes for fill
874 unsigned int vtx_inner_idx
= _VtxCurrentIdx
;
875 unsigned int vtx_outer_idx
= _VtxCurrentIdx
+1;
876 for (int i
= 2; i
< points_count
; i
++)
878 _IdxWritePtr
[0] = (ImDrawIdx
)(vtx_inner_idx
); _IdxWritePtr
[1] = (ImDrawIdx
)(vtx_inner_idx
+((i
-1)<<1)); _IdxWritePtr
[2] = (ImDrawIdx
)(vtx_inner_idx
+(i
<<1));
883 ImVec2
* temp_normals
= (ImVec2
*)alloca(points_count
* sizeof(ImVec2
)); //-V630
884 for (int i0
= points_count
-1, i1
= 0; i1
< points_count
; i0
= i1
++)
886 const ImVec2
& p0
= points
[i0
];
887 const ImVec2
& p1
= points
[i1
];
888 float dx
= p1
.x
- p0
.x
;
889 float dy
= p1
.y
- p0
.y
;
890 IM_NORMALIZE2F_OVER_ZERO(dx
, dy
);
891 temp_normals
[i0
].x
= dy
;
892 temp_normals
[i0
].y
= -dx
;
895 for (int i0
= points_count
-1, i1
= 0; i1
< points_count
; i0
= i1
++)
898 const ImVec2
& n0
= temp_normals
[i0
];
899 const ImVec2
& n1
= temp_normals
[i1
];
900 float dm_x
= (n0
.x
+ n1
.x
) * 0.5f
;
901 float dm_y
= (n0
.y
+ n1
.y
) * 0.5f
;
902 IM_NORMALIZE2F_OVER_EPSILON_CLAMP(dm_x
, dm_y
, 0.000001f
, 100.0f
);
903 dm_x
*= AA_SIZE
* 0.5f
;
904 dm_y
*= AA_SIZE
* 0.5f
;
907 _VtxWritePtr
[0].pos
.x
= (points
[i1
].x
- dm_x
); _VtxWritePtr
[0].pos
.y
= (points
[i1
].y
- dm_y
); _VtxWritePtr
[0].uv
= uv
; _VtxWritePtr
[0].col
= col
; // Inner
908 _VtxWritePtr
[1].pos
.x
= (points
[i1
].x
+ dm_x
); _VtxWritePtr
[1].pos
.y
= (points
[i1
].y
+ dm_y
); _VtxWritePtr
[1].uv
= uv
; _VtxWritePtr
[1].col
= col_trans
; // Outer
911 // Add indexes for fringes
912 _IdxWritePtr
[0] = (ImDrawIdx
)(vtx_inner_idx
+(i1
<<1)); _IdxWritePtr
[1] = (ImDrawIdx
)(vtx_inner_idx
+(i0
<<1)); _IdxWritePtr
[2] = (ImDrawIdx
)(vtx_outer_idx
+(i0
<<1));
913 _IdxWritePtr
[3] = (ImDrawIdx
)(vtx_outer_idx
+(i0
<<1)); _IdxWritePtr
[4] = (ImDrawIdx
)(vtx_outer_idx
+(i1
<<1)); _IdxWritePtr
[5] = (ImDrawIdx
)(vtx_inner_idx
+(i1
<<1));
916 _VtxCurrentIdx
+= (ImDrawIdx
)vtx_count
;
920 // Non Anti-aliased Fill
921 const int idx_count
= (points_count
-2)*3;
922 const int vtx_count
= points_count
;
923 PrimReserve(idx_count
, vtx_count
);
924 for (int i
= 0; i
< vtx_count
; i
++)
926 _VtxWritePtr
[0].pos
= points
[i
]; _VtxWritePtr
[0].uv
= uv
; _VtxWritePtr
[0].col
= col
;
929 for (int i
= 2; i
< points_count
; i
++)
931 _IdxWritePtr
[0] = (ImDrawIdx
)(_VtxCurrentIdx
); _IdxWritePtr
[1] = (ImDrawIdx
)(_VtxCurrentIdx
+i
-1); _IdxWritePtr
[2] = (ImDrawIdx
)(_VtxCurrentIdx
+i
);
934 _VtxCurrentIdx
+= (ImDrawIdx
)vtx_count
;
938 void ImDrawList::PathArcToFast(const ImVec2
& centre
, float radius
, int a_min_of_12
, int a_max_of_12
)
940 if (radius
== 0.0f
|| a_min_of_12
> a_max_of_12
)
942 _Path
.push_back(centre
);
945 _Path
.reserve(_Path
.Size
+ (a_max_of_12
- a_min_of_12
+ 1));
946 for (int a
= a_min_of_12
; a
<= a_max_of_12
; a
++)
948 const ImVec2
& c
= _Data
->CircleVtx12
[a
% IM_ARRAYSIZE(_Data
->CircleVtx12
)];
949 _Path
.push_back(ImVec2(centre
.x
+ c
.x
* radius
, centre
.y
+ c
.y
* radius
));
953 void ImDrawList::PathArcTo(const ImVec2
& centre
, float radius
, float a_min
, float a_max
, int num_segments
)
957 _Path
.push_back(centre
);
961 // Note that we are adding a point at both a_min and a_max.
962 // If you are trying to draw a full closed circle you don't want the overlapping points!
963 _Path
.reserve(_Path
.Size
+ (num_segments
+ 1));
964 for (int i
= 0; i
<= num_segments
; i
++)
966 const float a
= a_min
+ ((float)i
/ (float)num_segments
) * (a_max
- a_min
);
967 _Path
.push_back(ImVec2(centre
.x
+ ImCos(a
) * radius
, centre
.y
+ ImSin(a
) * radius
));
971 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
)
975 float d2
= ((x2
- x4
) * dy
- (y2
- y4
) * dx
);
976 float d3
= ((x3
- x4
) * dy
- (y3
- y4
) * dx
);
977 d2
= (d2
>= 0) ? d2
: -d2
;
978 d3
= (d3
>= 0) ? d3
: -d3
;
979 if ((d2
+d3
) * (d2
+d3
) < tess_tol
* (dx
*dx
+ dy
*dy
))
981 path
->push_back(ImVec2(x4
, y4
));
985 float x12
= (x1
+x2
)*0.5f
, y12
= (y1
+y2
)*0.5f
;
986 float x23
= (x2
+x3
)*0.5f
, y23
= (y2
+y3
)*0.5f
;
987 float x34
= (x3
+x4
)*0.5f
, y34
= (y3
+y4
)*0.5f
;
988 float x123
= (x12
+x23
)*0.5f
, y123
= (y12
+y23
)*0.5f
;
989 float x234
= (x23
+x34
)*0.5f
, y234
= (y23
+y34
)*0.5f
;
990 float x1234
= (x123
+x234
)*0.5f
, y1234
= (y123
+y234
)*0.5f
;
992 PathBezierToCasteljau(path
, x1
,y1
, x12
,y12
, x123
,y123
, x1234
,y1234
, tess_tol
, level
+1);
993 PathBezierToCasteljau(path
, x1234
,y1234
, x234
,y234
, x34
,y34
, x4
,y4
, tess_tol
, level
+1);
997 void ImDrawList::PathBezierCurveTo(const ImVec2
& p2
, const ImVec2
& p3
, const ImVec2
& p4
, int num_segments
)
999 ImVec2 p1
= _Path
.back();
1000 if (num_segments
== 0)
1003 PathBezierToCasteljau(&_Path
, p1
.x
, p1
.y
, p2
.x
, p2
.y
, p3
.x
, p3
.y
, p4
.x
, p4
.y
, _Data
->CurveTessellationTol
, 0);
1007 float t_step
= 1.0f
/ (float)num_segments
;
1008 for (int i_step
= 1; i_step
<= num_segments
; i_step
++)
1010 float t
= t_step
* i_step
;
1016 _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
));
1021 void ImDrawList::PathRect(const ImVec2
& a
, const ImVec2
& b
, float rounding
, int rounding_corners
)
1023 rounding
= ImMin(rounding
, ImFabs(b
.x
- a
.x
) * ( ((rounding_corners
& ImDrawCornerFlags_Top
) == ImDrawCornerFlags_Top
) || ((rounding_corners
& ImDrawCornerFlags_Bot
) == ImDrawCornerFlags_Bot
) ? 0.5f
: 1.0f
) - 1.0f
);
1024 rounding
= ImMin(rounding
, ImFabs(b
.y
- a
.y
) * ( ((rounding_corners
& ImDrawCornerFlags_Left
) == ImDrawCornerFlags_Left
) || ((rounding_corners
& ImDrawCornerFlags_Right
) == ImDrawCornerFlags_Right
) ? 0.5f
: 1.0f
) - 1.0f
);
1026 if (rounding
<= 0.0f
|| rounding_corners
== 0)
1029 PathLineTo(ImVec2(b
.x
, a
.y
));
1031 PathLineTo(ImVec2(a
.x
, b
.y
));
1035 const float rounding_tl
= (rounding_corners
& ImDrawCornerFlags_TopLeft
) ? rounding
: 0.0f
;
1036 const float rounding_tr
= (rounding_corners
& ImDrawCornerFlags_TopRight
) ? rounding
: 0.0f
;
1037 const float rounding_br
= (rounding_corners
& ImDrawCornerFlags_BotRight
) ? rounding
: 0.0f
;
1038 const float rounding_bl
= (rounding_corners
& ImDrawCornerFlags_BotLeft
) ? rounding
: 0.0f
;
1039 PathArcToFast(ImVec2(a
.x
+ rounding_tl
, a
.y
+ rounding_tl
), rounding_tl
, 6, 9);
1040 PathArcToFast(ImVec2(b
.x
- rounding_tr
, a
.y
+ rounding_tr
), rounding_tr
, 9, 12);
1041 PathArcToFast(ImVec2(b
.x
- rounding_br
, b
.y
- rounding_br
), rounding_br
, 0, 3);
1042 PathArcToFast(ImVec2(a
.x
+ rounding_bl
, b
.y
- rounding_bl
), rounding_bl
, 3, 6);
1046 void ImDrawList::AddLine(const ImVec2
& a
, const ImVec2
& b
, ImU32 col
, float thickness
)
1048 if ((col
& IM_COL32_A_MASK
) == 0)
1050 PathLineTo(a
+ ImVec2(0.5f
,0.5f
));
1051 PathLineTo(b
+ ImVec2(0.5f
,0.5f
));
1052 PathStroke(col
, false, thickness
);
1055 // a: upper-left, b: lower-right. we don't render 1 px sized rectangles properly.
1056 void ImDrawList::AddRect(const ImVec2
& a
, const ImVec2
& b
, ImU32 col
, float rounding
, int rounding_corners_flags
, float thickness
)
1058 if ((col
& IM_COL32_A_MASK
) == 0)
1060 if (Flags
& ImDrawListFlags_AntiAliasedLines
)
1061 PathRect(a
+ ImVec2(0.5f
,0.5f
), b
- ImVec2(0.50f
,0.50f
), rounding
, rounding_corners_flags
);
1063 PathRect(a
+ ImVec2(0.5f
,0.5f
), b
- ImVec2(0.49f
,0.49f
), rounding
, rounding_corners_flags
); // Better looking lower-right corner and rounded non-AA shapes.
1064 PathStroke(col
, true, thickness
);
1067 void ImDrawList::AddRectFilled(const ImVec2
& a
, const ImVec2
& b
, ImU32 col
, float rounding
, int rounding_corners_flags
)
1069 if ((col
& IM_COL32_A_MASK
) == 0)
1071 if (rounding
> 0.0f
)
1073 PathRect(a
, b
, rounding
, rounding_corners_flags
);
1074 PathFillConvex(col
);
1079 PrimRect(a
, b
, col
);
1083 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
)
1085 if (((col_upr_left
| col_upr_right
| col_bot_right
| col_bot_left
) & IM_COL32_A_MASK
) == 0)
1088 const ImVec2 uv
= _Data
->TexUvWhitePixel
;
1090 PrimWriteIdx((ImDrawIdx
)(_VtxCurrentIdx
)); PrimWriteIdx((ImDrawIdx
)(_VtxCurrentIdx
+1)); PrimWriteIdx((ImDrawIdx
)(_VtxCurrentIdx
+2));
1091 PrimWriteIdx((ImDrawIdx
)(_VtxCurrentIdx
)); PrimWriteIdx((ImDrawIdx
)(_VtxCurrentIdx
+2)); PrimWriteIdx((ImDrawIdx
)(_VtxCurrentIdx
+3));
1092 PrimWriteVtx(a
, uv
, col_upr_left
);
1093 PrimWriteVtx(ImVec2(c
.x
, a
.y
), uv
, col_upr_right
);
1094 PrimWriteVtx(c
, uv
, col_bot_right
);
1095 PrimWriteVtx(ImVec2(a
.x
, c
.y
), uv
, col_bot_left
);
1098 void ImDrawList::AddQuad(const ImVec2
& a
, const ImVec2
& b
, const ImVec2
& c
, const ImVec2
& d
, ImU32 col
, float thickness
)
1100 if ((col
& IM_COL32_A_MASK
) == 0)
1107 PathStroke(col
, true, thickness
);
1110 void ImDrawList::AddQuadFilled(const ImVec2
& a
, const ImVec2
& b
, const ImVec2
& c
, const ImVec2
& d
, ImU32 col
)
1112 if ((col
& IM_COL32_A_MASK
) == 0)
1119 PathFillConvex(col
);
1122 void ImDrawList::AddTriangle(const ImVec2
& a
, const ImVec2
& b
, const ImVec2
& c
, ImU32 col
, float thickness
)
1124 if ((col
& IM_COL32_A_MASK
) == 0)
1130 PathStroke(col
, true, thickness
);
1133 void ImDrawList::AddTriangleFilled(const ImVec2
& a
, const ImVec2
& b
, const ImVec2
& c
, ImU32 col
)
1135 if ((col
& IM_COL32_A_MASK
) == 0)
1141 PathFillConvex(col
);
1144 void ImDrawList::AddCircle(const ImVec2
& centre
, float radius
, ImU32 col
, int num_segments
, float thickness
)
1146 if ((col
& IM_COL32_A_MASK
) == 0 || num_segments
<= 2)
1149 // Because we are filling a closed shape we remove 1 from the count of segments/points
1150 const float a_max
= IM_PI
*2.0f
* ((float)num_segments
- 1.0f
) / (float)num_segments
;
1151 PathArcTo(centre
, radius
-0.5f
, 0.0f
, a_max
, num_segments
- 1);
1152 PathStroke(col
, true, thickness
);
1155 void ImDrawList::AddCircleFilled(const ImVec2
& centre
, float radius
, ImU32 col
, int num_segments
)
1157 if ((col
& IM_COL32_A_MASK
) == 0 || num_segments
<= 2)
1160 // Because we are filling a closed shape we remove 1 from the count of segments/points
1161 const float a_max
= IM_PI
*2.0f
* ((float)num_segments
- 1.0f
) / (float)num_segments
;
1162 PathArcTo(centre
, radius
, 0.0f
, a_max
, num_segments
- 1);
1163 PathFillConvex(col
);
1166 void ImDrawList::AddBezierCurve(const ImVec2
& pos0
, const ImVec2
& cp0
, const ImVec2
& cp1
, const ImVec2
& pos1
, ImU32 col
, float thickness
, int num_segments
)
1168 if ((col
& IM_COL32_A_MASK
) == 0)
1172 PathBezierCurveTo(cp0
, cp1
, pos1
, num_segments
);
1173 PathStroke(col
, false, thickness
);
1176 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
)
1178 if ((col
& IM_COL32_A_MASK
) == 0)
1181 if (text_end
== NULL
)
1182 text_end
= text_begin
+ strlen(text_begin
);
1183 if (text_begin
== text_end
)
1186 // Pull default font/size from the shared ImDrawListSharedData instance
1189 if (font_size
== 0.0f
)
1190 font_size
= _Data
->FontSize
;
1192 IM_ASSERT(font
->ContainerAtlas
->TexID
== _TextureIdStack
.back()); // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font.
1194 ImVec4 clip_rect
= _ClipRectStack
.back();
1195 if (cpu_fine_clip_rect
)
1197 clip_rect
.x
= ImMax(clip_rect
.x
, cpu_fine_clip_rect
->x
);
1198 clip_rect
.y
= ImMax(clip_rect
.y
, cpu_fine_clip_rect
->y
);
1199 clip_rect
.z
= ImMin(clip_rect
.z
, cpu_fine_clip_rect
->z
);
1200 clip_rect
.w
= ImMin(clip_rect
.w
, cpu_fine_clip_rect
->w
);
1202 font
->RenderText(this, font_size
, pos
, col
, clip_rect
, text_begin
, text_end
, wrap_width
, cpu_fine_clip_rect
!= NULL
);
1205 void ImDrawList::AddText(const ImVec2
& pos
, ImU32 col
, const char* text_begin
, const char* text_end
)
1207 AddText(NULL
, 0.0f
, pos
, col
, text_begin
, text_end
);
1210 void ImDrawList::AddImage(ImTextureID user_texture_id
, const ImVec2
& a
, const ImVec2
& b
, const ImVec2
& uv_a
, const ImVec2
& uv_b
, ImU32 col
)
1212 if ((col
& IM_COL32_A_MASK
) == 0)
1215 const bool push_texture_id
= _TextureIdStack
.empty() || user_texture_id
!= _TextureIdStack
.back();
1216 if (push_texture_id
)
1217 PushTextureID(user_texture_id
);
1220 PrimRectUV(a
, b
, uv_a
, uv_b
, col
);
1222 if (push_texture_id
)
1226 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
)
1228 if ((col
& IM_COL32_A_MASK
) == 0)
1231 const bool push_texture_id
= _TextureIdStack
.empty() || user_texture_id
!= _TextureIdStack
.back();
1232 if (push_texture_id
)
1233 PushTextureID(user_texture_id
);
1236 PrimQuadUV(a
, b
, c
, d
, uv_a
, uv_b
, uv_c
, uv_d
, col
);
1238 if (push_texture_id
)
1242 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
)
1244 if ((col
& IM_COL32_A_MASK
) == 0)
1247 if (rounding
<= 0.0f
|| (rounding_corners
& ImDrawCornerFlags_All
) == 0)
1249 AddImage(user_texture_id
, a
, b
, uv_a
, uv_b
, col
);
1253 const bool push_texture_id
= _TextureIdStack
.empty() || user_texture_id
!= _TextureIdStack
.back();
1254 if (push_texture_id
)
1255 PushTextureID(user_texture_id
);
1257 int vert_start_idx
= VtxBuffer
.Size
;
1258 PathRect(a
, b
, rounding
, rounding_corners
);
1259 PathFillConvex(col
);
1260 int vert_end_idx
= VtxBuffer
.Size
;
1261 ImGui::ShadeVertsLinearUV(this, vert_start_idx
, vert_end_idx
, a
, b
, uv_a
, uv_b
, true);
1263 if (push_texture_id
)
1267 //-----------------------------------------------------------------------------
1268 // [SECTION] ImDrawData
1269 //-----------------------------------------------------------------------------
1271 // 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!
1272 void ImDrawData::DeIndexAllBuffers()
1274 ImVector
<ImDrawVert
> new_vtx_buffer
;
1275 TotalVtxCount
= TotalIdxCount
= 0;
1276 for (int i
= 0; i
< CmdListsCount
; i
++)
1278 ImDrawList
* cmd_list
= CmdLists
[i
];
1279 if (cmd_list
->IdxBuffer
.empty())
1281 new_vtx_buffer
.resize(cmd_list
->IdxBuffer
.Size
);
1282 for (int j
= 0; j
< cmd_list
->IdxBuffer
.Size
; j
++)
1283 new_vtx_buffer
[j
] = cmd_list
->VtxBuffer
[cmd_list
->IdxBuffer
[j
]];
1284 cmd_list
->VtxBuffer
.swap(new_vtx_buffer
);
1285 cmd_list
->IdxBuffer
.resize(0);
1286 TotalVtxCount
+= cmd_list
->VtxBuffer
.Size
;
1290 // Helper to scale the ClipRect field of each ImDrawCmd.
1291 // Use if your final output buffer is at a different scale than draw_data->DisplaySize,
1292 // or if there is a difference between your window resolution and framebuffer resolution.
1293 void ImDrawData::ScaleClipRects(const ImVec2
& fb_scale
)
1295 for (int i
= 0; i
< CmdListsCount
; i
++)
1297 ImDrawList
* cmd_list
= CmdLists
[i
];
1298 for (int cmd_i
= 0; cmd_i
< cmd_list
->CmdBuffer
.Size
; cmd_i
++)
1300 ImDrawCmd
* cmd
= &cmd_list
->CmdBuffer
[cmd_i
];
1301 cmd
->ClipRect
= ImVec4(cmd
->ClipRect
.x
* fb_scale
.x
, cmd
->ClipRect
.y
* fb_scale
.y
, cmd
->ClipRect
.z
* fb_scale
.x
, cmd
->ClipRect
.w
* fb_scale
.y
);
1306 //-----------------------------------------------------------------------------
1307 // [SECTION] Helpers ShadeVertsXXX functions
1308 //-----------------------------------------------------------------------------
1310 // Generic linear color gradient, write to RGB fields, leave A untouched.
1311 void ImGui::ShadeVertsLinearColorGradientKeepAlpha(ImDrawList
* draw_list
, int vert_start_idx
, int vert_end_idx
, ImVec2 gradient_p0
, ImVec2 gradient_p1
, ImU32 col0
, ImU32 col1
)
1313 ImVec2 gradient_extent
= gradient_p1
- gradient_p0
;
1314 float gradient_inv_length2
= 1.0f
/ ImLengthSqr(gradient_extent
);
1315 ImDrawVert
* vert_start
= draw_list
->VtxBuffer
.Data
+ vert_start_idx
;
1316 ImDrawVert
* vert_end
= draw_list
->VtxBuffer
.Data
+ vert_end_idx
;
1317 for (ImDrawVert
* vert
= vert_start
; vert
< vert_end
; vert
++)
1319 float d
= ImDot(vert
->pos
- gradient_p0
, gradient_extent
);
1320 float t
= ImClamp(d
* gradient_inv_length2
, 0.0f
, 1.0f
);
1321 int r
= ImLerp((int)(col0
>> IM_COL32_R_SHIFT
) & 0xFF, (int)(col1
>> IM_COL32_R_SHIFT
) & 0xFF, t
);
1322 int g
= ImLerp((int)(col0
>> IM_COL32_G_SHIFT
) & 0xFF, (int)(col1
>> IM_COL32_G_SHIFT
) & 0xFF, t
);
1323 int b
= ImLerp((int)(col0
>> IM_COL32_B_SHIFT
) & 0xFF, (int)(col1
>> IM_COL32_B_SHIFT
) & 0xFF, t
);
1324 vert
->col
= (r
<< IM_COL32_R_SHIFT
) | (g
<< IM_COL32_G_SHIFT
) | (b
<< IM_COL32_B_SHIFT
) | (vert
->col
& IM_COL32_A_MASK
);
1328 // Distribute UV over (a, b) rectangle
1329 void ImGui::ShadeVertsLinearUV(ImDrawList
* draw_list
, int vert_start_idx
, int vert_end_idx
, const ImVec2
& a
, const ImVec2
& b
, const ImVec2
& uv_a
, const ImVec2
& uv_b
, bool clamp
)
1331 const ImVec2 size
= b
- a
;
1332 const ImVec2 uv_size
= uv_b
- uv_a
;
1333 const ImVec2 scale
= ImVec2(
1334 size
.x
!= 0.0f
? (uv_size
.x
/ size
.x
) : 0.0f
,
1335 size
.y
!= 0.0f
? (uv_size
.y
/ size
.y
) : 0.0f
);
1337 ImDrawVert
* vert_start
= draw_list
->VtxBuffer
.Data
+ vert_start_idx
;
1338 ImDrawVert
* vert_end
= draw_list
->VtxBuffer
.Data
+ vert_end_idx
;
1341 const ImVec2 min
= ImMin(uv_a
, uv_b
);
1342 const ImVec2 max
= ImMax(uv_a
, uv_b
);
1343 for (ImDrawVert
* vertex
= vert_start
; vertex
< vert_end
; ++vertex
)
1344 vertex
->uv
= ImClamp(uv_a
+ ImMul(ImVec2(vertex
->pos
.x
, vertex
->pos
.y
) - a
, scale
), min
, max
);
1348 for (ImDrawVert
* vertex
= vert_start
; vertex
< vert_end
; ++vertex
)
1349 vertex
->uv
= uv_a
+ ImMul(ImVec2(vertex
->pos
.x
, vertex
->pos
.y
) - a
, scale
);
1353 //-----------------------------------------------------------------------------
1354 // [SECTION] ImFontConfig
1355 //-----------------------------------------------------------------------------
1357 ImFontConfig::ImFontConfig()
1361 FontDataOwnedByAtlas
= true;
1364 OversampleH
= 3; // FIXME: 2 may be a better default?
1367 GlyphExtraSpacing
= ImVec2(0.0f
, 0.0f
);
1368 GlyphOffset
= ImVec2(0.0f
, 0.0f
);
1370 GlyphMinAdvanceX
= 0.0f
;
1371 GlyphMaxAdvanceX
= FLT_MAX
;
1373 RasterizerFlags
= 0x00;
1374 RasterizerMultiply
= 1.0f
;
1375 memset(Name
, 0, sizeof(Name
));
1379 //-----------------------------------------------------------------------------
1380 // [SECTION] ImFontAtlas
1381 //-----------------------------------------------------------------------------
1383 // A work of art lies ahead! (. = white layer, X = black layer, others are blank)
1384 // The white texels on the top left are the ones we'll use everywhere in ImGui to render filled shapes.
1385 const int FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF
= 108;
1386 const int FONT_ATLAS_DEFAULT_TEX_DATA_H
= 27;
1387 const unsigned int FONT_ATLAS_DEFAULT_TEX_DATA_ID
= 0x80000000;
1388 static const char FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS
[FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF
* FONT_ATLAS_DEFAULT_TEX_DATA_H
+ 1] =
1390 "..- -XXXXXXX- X - X -XXXXXXX - XXXXXXX- XX "
1391 "..- -X.....X- X.X - X.X -X.....X - X.....X- X..X "
1392 "--- -XXX.XXX- X...X - X...X -X....X - X....X- X..X "
1393 "X - X.X - X.....X - X.....X -X...X - X...X- X..X "
1394 "XX - X.X -X.......X- X.......X -X..X.X - X.X..X- X..X "
1395 "X.X - X.X -XXXX.XXXX- XXXX.XXXX -X.X X.X - X.X X.X- X..XXX "
1396 "X..X - X.X - X.X - X.X -XX X.X - X.X XX- X..X..XXX "
1397 "X...X - X.X - X.X - XX X.X XX - X.X - X.X - X..X..X..XX "
1398 "X....X - X.X - X.X - X.X X.X X.X - X.X - X.X - X..X..X..X.X "
1399 "X.....X - X.X - X.X - X..X X.X X..X - X.X - X.X -XXX X..X..X..X..X"
1400 "X......X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X XX-XX X.X -X..XX........X..X"
1401 "X.......X - X.X - X.X -X.....................X- X.X X.X-X.X X.X -X...X...........X"
1402 "X........X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X..X-X..X.X - X..............X"
1403 "X.........X -XXX.XXX- X.X - X..X X.X X..X - X...X-X...X - X.............X"
1404 "X..........X-X.....X- X.X - X.X X.X X.X - X....X-X....X - X.............X"
1405 "X......XXXXX-XXXXXXX- X.X - XX X.X XX - X.....X-X.....X - X............X"
1406 "X...X..X --------- X.X - X.X - XXXXXXX-XXXXXXX - X...........X "
1407 "X..X X..X - -XXXX.XXXX- XXXX.XXXX ------------------------------------- X..........X "
1408 "X.X X..X - -X.......X- X.......X - XX XX - - X..........X "
1409 "XX X..X - - X.....X - X.....X - X.X X.X - - X........X "
1410 " X..X - X...X - X...X - X..X X..X - - X........X "
1411 " XX - X.X - X.X - X...XXXXXXXXXXXXX...X - - XXXXXXXXXX "
1412 "------------ - X - X -X.....................X- ------------------"
1413 " ----------------------------------- X...XXXXXXXXXXXXX...X - "
1419 static const ImVec2 FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA
[ImGuiMouseCursor_COUNT
][3] =
1421 // Pos ........ Size ......... Offset ......
1422 { ImVec2( 0,3), ImVec2(12,19), ImVec2( 0, 0) }, // ImGuiMouseCursor_Arrow
1423 { ImVec2(13,0), ImVec2( 7,16), ImVec2( 1, 8) }, // ImGuiMouseCursor_TextInput
1424 { ImVec2(31,0), ImVec2(23,23), ImVec2(11,11) }, // ImGuiMouseCursor_ResizeAll
1425 { ImVec2(21,0), ImVec2( 9,23), ImVec2( 4,11) }, // ImGuiMouseCursor_ResizeNS
1426 { ImVec2(55,18),ImVec2(23, 9), ImVec2(11, 4) }, // ImGuiMouseCursor_ResizeEW
1427 { ImVec2(73,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNESW
1428 { ImVec2(55,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNWSE
1429 { ImVec2(91,0), ImVec2(17,22), ImVec2( 5, 0) }, // ImGuiMouseCursor_Hand
1432 ImFontAtlas::ImFontAtlas()
1435 Flags
= ImFontAtlasFlags_None
;
1436 TexID
= (ImTextureID
)NULL
;
1437 TexDesiredWidth
= 0;
1438 TexGlyphPadding
= 1;
1440 TexPixelsAlpha8
= NULL
;
1441 TexPixelsRGBA32
= NULL
;
1442 TexWidth
= TexHeight
= 0;
1443 TexUvScale
= ImVec2(0.0f
, 0.0f
);
1444 TexUvWhitePixel
= ImVec2(0.0f
, 0.0f
);
1445 for (int n
= 0; n
< IM_ARRAYSIZE(CustomRectIds
); n
++)
1446 CustomRectIds
[n
] = -1;
1449 ImFontAtlas::~ImFontAtlas()
1451 IM_ASSERT(!Locked
&& "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
1455 void ImFontAtlas::ClearInputData()
1457 IM_ASSERT(!Locked
&& "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
1458 for (int i
= 0; i
< ConfigData
.Size
; i
++)
1459 if (ConfigData
[i
].FontData
&& ConfigData
[i
].FontDataOwnedByAtlas
)
1461 ImGui::MemFree(ConfigData
[i
].FontData
);
1462 ConfigData
[i
].FontData
= NULL
;
1465 // When clearing this we lose access to the font name and other information used to build the font.
1466 for (int i
= 0; i
< Fonts
.Size
; i
++)
1467 if (Fonts
[i
]->ConfigData
>= ConfigData
.Data
&& Fonts
[i
]->ConfigData
< ConfigData
.Data
+ ConfigData
.Size
)
1469 Fonts
[i
]->ConfigData
= NULL
;
1470 Fonts
[i
]->ConfigDataCount
= 0;
1473 CustomRects
.clear();
1474 for (int n
= 0; n
< IM_ARRAYSIZE(CustomRectIds
); n
++)
1475 CustomRectIds
[n
] = -1;
1478 void ImFontAtlas::ClearTexData()
1480 IM_ASSERT(!Locked
&& "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
1481 if (TexPixelsAlpha8
)
1482 ImGui::MemFree(TexPixelsAlpha8
);
1483 if (TexPixelsRGBA32
)
1484 ImGui::MemFree(TexPixelsRGBA32
);
1485 TexPixelsAlpha8
= NULL
;
1486 TexPixelsRGBA32
= NULL
;
1489 void ImFontAtlas::ClearFonts()
1491 IM_ASSERT(!Locked
&& "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
1492 for (int i
= 0; i
< Fonts
.Size
; i
++)
1493 IM_DELETE(Fonts
[i
]);
1497 void ImFontAtlas::Clear()
1504 void ImFontAtlas::GetTexDataAsAlpha8(unsigned char** out_pixels
, int* out_width
, int* out_height
, int* out_bytes_per_pixel
)
1506 // Build atlas on demand
1507 if (TexPixelsAlpha8
== NULL
)
1509 if (ConfigData
.empty())
1514 *out_pixels
= TexPixelsAlpha8
;
1515 if (out_width
) *out_width
= TexWidth
;
1516 if (out_height
) *out_height
= TexHeight
;
1517 if (out_bytes_per_pixel
) *out_bytes_per_pixel
= 1;
1520 void ImFontAtlas::GetTexDataAsRGBA32(unsigned char** out_pixels
, int* out_width
, int* out_height
, int* out_bytes_per_pixel
)
1522 // Convert to RGBA32 format on demand
1523 // Although it is likely to be the most commonly used format, our font rendering is 1 channel / 8 bpp
1524 if (!TexPixelsRGBA32
)
1526 unsigned char* pixels
= NULL
;
1527 GetTexDataAsAlpha8(&pixels
, NULL
, NULL
);
1530 TexPixelsRGBA32
= (unsigned int*)ImGui::MemAlloc((size_t)TexWidth
* (size_t)TexHeight
* 4);
1531 const unsigned char* src
= pixels
;
1532 unsigned int* dst
= TexPixelsRGBA32
;
1533 for (int n
= TexWidth
* TexHeight
; n
> 0; n
--)
1534 *dst
++ = IM_COL32(255, 255, 255, (unsigned int)(*src
++));
1538 *out_pixels
= (unsigned char*)TexPixelsRGBA32
;
1539 if (out_width
) *out_width
= TexWidth
;
1540 if (out_height
) *out_height
= TexHeight
;
1541 if (out_bytes_per_pixel
) *out_bytes_per_pixel
= 4;
1544 ImFont
* ImFontAtlas::AddFont(const ImFontConfig
* font_cfg
)
1546 IM_ASSERT(!Locked
&& "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
1547 IM_ASSERT(font_cfg
->FontData
!= NULL
&& font_cfg
->FontDataSize
> 0);
1548 IM_ASSERT(font_cfg
->SizePixels
> 0.0f
);
1551 if (!font_cfg
->MergeMode
)
1552 Fonts
.push_back(IM_NEW(ImFont
));
1554 IM_ASSERT(!Fonts
.empty() && "Cannot use MergeMode for the first font"); // 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.
1556 ConfigData
.push_back(*font_cfg
);
1557 ImFontConfig
& new_font_cfg
= ConfigData
.back();
1558 if (new_font_cfg
.DstFont
== NULL
)
1559 new_font_cfg
.DstFont
= Fonts
.back();
1560 if (!new_font_cfg
.FontDataOwnedByAtlas
)
1562 new_font_cfg
.FontData
= ImGui::MemAlloc(new_font_cfg
.FontDataSize
);
1563 new_font_cfg
.FontDataOwnedByAtlas
= true;
1564 memcpy(new_font_cfg
.FontData
, font_cfg
->FontData
, (size_t)new_font_cfg
.FontDataSize
);
1567 // Invalidate texture
1569 return new_font_cfg
.DstFont
;
1572 // Default font TTF is compressed with stb_compress then base85 encoded (see misc/fonts/binary_to_compressed_c.cpp for encoder)
1573 static unsigned int stb_decompress_length(const unsigned char *input
);
1574 static unsigned int stb_decompress(unsigned char *output
, const unsigned char *input
, unsigned int length
);
1575 static const char* GetDefaultCompressedFontDataTTFBase85();
1576 static unsigned int Decode85Byte(char c
) { return c
>= '\\' ? c
-36 : c
-35; }
1577 static void Decode85(const unsigned char* src
, unsigned char* dst
)
1581 unsigned int tmp
= Decode85Byte(src
[0]) + 85*(Decode85Byte(src
[1]) + 85*(Decode85Byte(src
[2]) + 85*(Decode85Byte(src
[3]) + 85*Decode85Byte(src
[4]))));
1582 dst
[0] = ((tmp
>> 0) & 0xFF); dst
[1] = ((tmp
>> 8) & 0xFF); dst
[2] = ((tmp
>> 16) & 0xFF); dst
[3] = ((tmp
>> 24) & 0xFF); // We can't assume little-endianness.
1588 // Load embedded ProggyClean.ttf at size 13, disable oversampling
1589 ImFont
* ImFontAtlas::AddFontDefault(const ImFontConfig
* font_cfg_template
)
1591 ImFontConfig font_cfg
= font_cfg_template
? *font_cfg_template
: ImFontConfig();
1592 if (!font_cfg_template
)
1594 font_cfg
.OversampleH
= font_cfg
.OversampleV
= 1;
1595 font_cfg
.PixelSnapH
= true;
1597 if (font_cfg
.SizePixels
<= 0.0f
)
1598 font_cfg
.SizePixels
= 13.0f
* 1.0f
;
1599 if (font_cfg
.Name
[0] == '\0')
1600 ImFormatString(font_cfg
.Name
, IM_ARRAYSIZE(font_cfg
.Name
), "ProggyClean.ttf, %dpx", (int)font_cfg
.SizePixels
);
1602 const char* ttf_compressed_base85
= GetDefaultCompressedFontDataTTFBase85();
1603 const ImWchar
* glyph_ranges
= font_cfg
.GlyphRanges
!= NULL
? font_cfg
.GlyphRanges
: GetGlyphRangesDefault();
1604 ImFont
* font
= AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85
, font_cfg
.SizePixels
, &font_cfg
, glyph_ranges
);
1605 font
->DisplayOffset
.y
= 1.0f
;
1609 ImFont
* ImFontAtlas::AddFontFromFileTTF(const char* filename
, float size_pixels
, const ImFontConfig
* font_cfg_template
, const ImWchar
* glyph_ranges
)
1611 IM_ASSERT(!Locked
&& "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
1612 size_t data_size
= 0;
1613 void* data
= ImFileLoadToMemory(filename
, "rb", &data_size
, 0);
1616 IM_ASSERT(0); // Could not load file.
1619 ImFontConfig font_cfg
= font_cfg_template
? *font_cfg_template
: ImFontConfig();
1620 if (font_cfg
.Name
[0] == '\0')
1622 // Store a short copy of filename into into the font name for convenience
1624 for (p
= filename
+ strlen(filename
); p
> filename
&& p
[-1] != '/' && p
[-1] != '\\'; p
--) {}
1625 ImFormatString(font_cfg
.Name
, IM_ARRAYSIZE(font_cfg
.Name
), "%s, %.0fpx", p
, size_pixels
);
1627 return AddFontFromMemoryTTF(data
, (int)data_size
, size_pixels
, &font_cfg
, glyph_ranges
);
1630 // NB: Transfer ownership of 'ttf_data' to ImFontAtlas, unless font_cfg_template->FontDataOwnedByAtlas == false. Owned TTF buffer will be deleted after Build().
1631 ImFont
* ImFontAtlas::AddFontFromMemoryTTF(void* ttf_data
, int ttf_size
, float size_pixels
, const ImFontConfig
* font_cfg_template
, const ImWchar
* glyph_ranges
)
1633 IM_ASSERT(!Locked
&& "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
1634 ImFontConfig font_cfg
= font_cfg_template
? *font_cfg_template
: ImFontConfig();
1635 IM_ASSERT(font_cfg
.FontData
== NULL
);
1636 font_cfg
.FontData
= ttf_data
;
1637 font_cfg
.FontDataSize
= ttf_size
;
1638 font_cfg
.SizePixels
= size_pixels
;
1640 font_cfg
.GlyphRanges
= glyph_ranges
;
1641 return AddFont(&font_cfg
);
1644 ImFont
* ImFontAtlas::AddFontFromMemoryCompressedTTF(const void* compressed_ttf_data
, int compressed_ttf_size
, float size_pixels
, const ImFontConfig
* font_cfg_template
, const ImWchar
* glyph_ranges
)
1646 const unsigned int buf_decompressed_size
= stb_decompress_length((const unsigned char*)compressed_ttf_data
);
1647 unsigned char* buf_decompressed_data
= (unsigned char *)ImGui::MemAlloc(buf_decompressed_size
);
1648 stb_decompress(buf_decompressed_data
, (const unsigned char*)compressed_ttf_data
, (unsigned int)compressed_ttf_size
);
1650 ImFontConfig font_cfg
= font_cfg_template
? *font_cfg_template
: ImFontConfig();
1651 IM_ASSERT(font_cfg
.FontData
== NULL
);
1652 font_cfg
.FontDataOwnedByAtlas
= true;
1653 return AddFontFromMemoryTTF(buf_decompressed_data
, (int)buf_decompressed_size
, size_pixels
, &font_cfg
, glyph_ranges
);
1656 ImFont
* ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(const char* compressed_ttf_data_base85
, float size_pixels
, const ImFontConfig
* font_cfg
, const ImWchar
* glyph_ranges
)
1658 int compressed_ttf_size
= (((int)strlen(compressed_ttf_data_base85
) + 4) / 5) * 4;
1659 void* compressed_ttf
= ImGui::MemAlloc((size_t)compressed_ttf_size
);
1660 Decode85((const unsigned char*)compressed_ttf_data_base85
, (unsigned char*)compressed_ttf
);
1661 ImFont
* font
= AddFontFromMemoryCompressedTTF(compressed_ttf
, compressed_ttf_size
, size_pixels
, font_cfg
, glyph_ranges
);
1662 ImGui::MemFree(compressed_ttf
);
1666 int ImFontAtlas::AddCustomRectRegular(unsigned int id
, int width
, int height
)
1668 IM_ASSERT(id
>= 0x10000);
1669 IM_ASSERT(width
> 0 && width
<= 0xFFFF);
1670 IM_ASSERT(height
> 0 && height
<= 0xFFFF);
1673 r
.Width
= (unsigned short)width
;
1674 r
.Height
= (unsigned short)height
;
1675 CustomRects
.push_back(r
);
1676 return CustomRects
.Size
- 1; // Return index
1679 int ImFontAtlas::AddCustomRectFontGlyph(ImFont
* font
, ImWchar id
, int width
, int height
, float advance_x
, const ImVec2
& offset
)
1681 IM_ASSERT(font
!= NULL
);
1682 IM_ASSERT(width
> 0 && width
<= 0xFFFF);
1683 IM_ASSERT(height
> 0 && height
<= 0xFFFF);
1686 r
.Width
= (unsigned short)width
;
1687 r
.Height
= (unsigned short)height
;
1688 r
.GlyphAdvanceX
= advance_x
;
1689 r
.GlyphOffset
= offset
;
1691 CustomRects
.push_back(r
);
1692 return CustomRects
.Size
- 1; // Return index
1695 void ImFontAtlas::CalcCustomRectUV(const CustomRect
* rect
, ImVec2
* out_uv_min
, ImVec2
* out_uv_max
)
1697 IM_ASSERT(TexWidth
> 0 && TexHeight
> 0); // Font atlas needs to be built before we can calculate UV coordinates
1698 IM_ASSERT(rect
->IsPacked()); // Make sure the rectangle has been packed
1699 *out_uv_min
= ImVec2((float)rect
->X
* TexUvScale
.x
, (float)rect
->Y
* TexUvScale
.y
);
1700 *out_uv_max
= ImVec2((float)(rect
->X
+ rect
->Width
) * TexUvScale
.x
, (float)(rect
->Y
+ rect
->Height
) * TexUvScale
.y
);
1703 bool ImFontAtlas::GetMouseCursorTexData(ImGuiMouseCursor cursor_type
, ImVec2
* out_offset
, ImVec2
* out_size
, ImVec2 out_uv_border
[2], ImVec2 out_uv_fill
[2])
1705 if (cursor_type
<= ImGuiMouseCursor_None
|| cursor_type
>= ImGuiMouseCursor_COUNT
)
1707 if (Flags
& ImFontAtlasFlags_NoMouseCursors
)
1710 IM_ASSERT(CustomRectIds
[0] != -1);
1711 ImFontAtlas::CustomRect
& r
= CustomRects
[CustomRectIds
[0]];
1712 IM_ASSERT(r
.ID
== FONT_ATLAS_DEFAULT_TEX_DATA_ID
);
1713 ImVec2 pos
= FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA
[cursor_type
][0] + ImVec2((float)r
.X
, (float)r
.Y
);
1714 ImVec2 size
= FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA
[cursor_type
][1];
1716 *out_offset
= FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA
[cursor_type
][2];
1717 out_uv_border
[0] = (pos
) * TexUvScale
;
1718 out_uv_border
[1] = (pos
+ size
) * TexUvScale
;
1719 pos
.x
+= FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF
+ 1;
1720 out_uv_fill
[0] = (pos
) * TexUvScale
;
1721 out_uv_fill
[1] = (pos
+ size
) * TexUvScale
;
1725 bool ImFontAtlas::Build()
1727 IM_ASSERT(!Locked
&& "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
1728 return ImFontAtlasBuildWithStbTruetype(this);
1731 void ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table
[256], float in_brighten_factor
)
1733 for (unsigned int i
= 0; i
< 256; i
++)
1735 unsigned int value
= (unsigned int)(i
* in_brighten_factor
);
1736 out_table
[i
] = value
> 255 ? 255 : (value
& 0xFF);
1740 void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table
[256], unsigned char* pixels
, int x
, int y
, int w
, int h
, int stride
)
1742 unsigned char* data
= pixels
+ x
+ y
* stride
;
1743 for (int j
= h
; j
> 0; j
--, data
+= stride
)
1744 for (int i
= 0; i
< w
; i
++)
1745 data
[i
] = table
[data
[i
]];
1748 // Temporary data for one source font (multiple source fonts can be merged into one destination ImFont)
1749 // (C++03 doesn't allow instancing ImVector<> with function-local types so we declare the type here.)
1750 struct ImFontBuildSrcData
1752 stbtt_fontinfo FontInfo
;
1753 stbtt_pack_range PackRange
; // Hold the list of codepoints to pack (essentially points to Codepoints.Data)
1754 stbrp_rect
* Rects
; // Rectangle to pack. We first fill in their size and the packer will give us their position.
1755 stbtt_packedchar
* PackedChars
; // Output glyphs
1756 const ImWchar
* SrcRanges
; // Ranges as requested by user (user is allowed to request too much, e.g. 0x0020..0xFFFF)
1757 int DstIndex
; // Index into atlas->Fonts[] and dst_tmp_array[]
1758 int GlyphsHighest
; // Highest requested codepoint
1759 int GlyphsCount
; // Glyph count (excluding missing glyphs and glyphs already set by an earlier source font)
1760 ImBoolVector GlyphsSet
; // Glyph bit map (random access, 1-bit per codepoint. This will be a maximum of 8KB)
1761 ImVector
<int> GlyphsList
; // Glyph codepoints list (flattened version of GlyphsMap)
1764 // Temporary data for one destination ImFont* (multiple source fonts can be merged into one destination ImFont)
1765 struct ImFontBuildDstData
1767 int SrcCount
; // Number of source fonts targeting this destination font.
1770 ImBoolVector GlyphsSet
; // This is used to resolve collision when multiple sources are merged into a same destination font.
1773 static void UnpackBoolVectorToFlatIndexList(const ImBoolVector
* in
, ImVector
<int>* out
)
1775 IM_ASSERT(sizeof(in
->Storage
.Data
[0]) == sizeof(int));
1776 const int* it_begin
= in
->Storage
.begin();
1777 const int* it_end
= in
->Storage
.end();
1778 for (const int* it
= it_begin
; it
< it_end
; it
++)
1779 if (int entries_32
= *it
)
1780 for (int bit_n
= 0; bit_n
< 32; bit_n
++)
1781 if (entries_32
& (1u << bit_n
))
1782 out
->push_back((int)((it
- it_begin
) << 5) + bit_n
);
1785 bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas
* atlas
)
1787 IM_ASSERT(atlas
->ConfigData
.Size
> 0);
1789 ImFontAtlasBuildRegisterDefaultCustomRects(atlas
);
1792 atlas
->TexID
= (ImTextureID
)NULL
;
1793 atlas
->TexWidth
= atlas
->TexHeight
= 0;
1794 atlas
->TexUvScale
= ImVec2(0.0f
, 0.0f
);
1795 atlas
->TexUvWhitePixel
= ImVec2(0.0f
, 0.0f
);
1796 atlas
->ClearTexData();
1798 // Temporary storage for building
1799 ImVector
<ImFontBuildSrcData
> src_tmp_array
;
1800 ImVector
<ImFontBuildDstData
> dst_tmp_array
;
1801 src_tmp_array
.resize(atlas
->ConfigData
.Size
);
1802 dst_tmp_array
.resize(atlas
->Fonts
.Size
);
1803 memset(src_tmp_array
.Data
, 0, (size_t)src_tmp_array
.size_in_bytes());
1804 memset(dst_tmp_array
.Data
, 0, (size_t)dst_tmp_array
.size_in_bytes());
1806 // 1. Initialize font loading structure, check font data validity
1807 for (int src_i
= 0; src_i
< atlas
->ConfigData
.Size
; src_i
++)
1809 ImFontBuildSrcData
& src_tmp
= src_tmp_array
[src_i
];
1810 ImFontConfig
& cfg
= atlas
->ConfigData
[src_i
];
1811 IM_ASSERT(cfg
.DstFont
&& (!cfg
.DstFont
->IsLoaded() || cfg
.DstFont
->ContainerAtlas
== atlas
));
1813 // Find index from cfg.DstFont (we allow the user to set cfg.DstFont. Also it makes casual debugging nicer than when storing indices)
1814 src_tmp
.DstIndex
= -1;
1815 for (int output_i
= 0; output_i
< atlas
->Fonts
.Size
&& src_tmp
.DstIndex
== -1; output_i
++)
1816 if (cfg
.DstFont
== atlas
->Fonts
[output_i
])
1817 src_tmp
.DstIndex
= output_i
;
1818 IM_ASSERT(src_tmp
.DstIndex
!= -1); // cfg.DstFont not pointing within atlas->Fonts[] array?
1819 if (src_tmp
.DstIndex
== -1)
1822 // Initialize helper structure for font loading and verify that the TTF/OTF data is correct
1823 const int font_offset
= stbtt_GetFontOffsetForIndex((unsigned char*)cfg
.FontData
, cfg
.FontNo
);
1824 IM_ASSERT(font_offset
>= 0 && "FontData is incorrect, or FontNo cannot be found.");
1825 if (!stbtt_InitFont(&src_tmp
.FontInfo
, (unsigned char*)cfg
.FontData
, font_offset
))
1828 // Measure highest codepoints
1829 ImFontBuildDstData
& dst_tmp
= dst_tmp_array
[src_tmp
.DstIndex
];
1830 src_tmp
.SrcRanges
= cfg
.GlyphRanges
? cfg
.GlyphRanges
: atlas
->GetGlyphRangesDefault();
1831 for (const ImWchar
* src_range
= src_tmp
.SrcRanges
; src_range
[0] && src_range
[1]; src_range
+= 2)
1832 src_tmp
.GlyphsHighest
= ImMax(src_tmp
.GlyphsHighest
, (int)src_range
[1]);
1834 dst_tmp
.GlyphsHighest
= ImMax(dst_tmp
.GlyphsHighest
, src_tmp
.GlyphsHighest
);
1837 // 2. For every requested codepoint, check for their presence in the font data, and handle redundancy or overlaps between source fonts to avoid unused glyphs.
1838 int total_glyphs_count
= 0;
1839 for (int src_i
= 0; src_i
< src_tmp_array
.Size
; src_i
++)
1841 ImFontBuildSrcData
& src_tmp
= src_tmp_array
[src_i
];
1842 ImFontBuildDstData
& dst_tmp
= dst_tmp_array
[src_tmp
.DstIndex
];
1843 ImFontConfig
& cfg
= atlas
->ConfigData
[src_i
];
1844 src_tmp
.GlyphsSet
.Resize(src_tmp
.GlyphsHighest
+ 1);
1845 if (dst_tmp
.SrcCount
> 1 && dst_tmp
.GlyphsSet
.Storage
.empty())
1846 dst_tmp
.GlyphsSet
.Resize(dst_tmp
.GlyphsHighest
+ 1);
1848 for (const ImWchar
* src_range
= src_tmp
.SrcRanges
; src_range
[0] && src_range
[1]; src_range
+= 2)
1849 for (int codepoint
= src_range
[0]; codepoint
<= src_range
[1]; codepoint
++)
1851 if (cfg
.MergeMode
&& dst_tmp
.GlyphsSet
.GetBit(codepoint
)) // Don't overwrite existing glyphs. We could make this an option (e.g. MergeOverwrite)
1853 if (!stbtt_FindGlyphIndex(&src_tmp
.FontInfo
, codepoint
)) // It is actually in the font?
1856 // Add to avail set/counters
1857 src_tmp
.GlyphsCount
++;
1858 dst_tmp
.GlyphsCount
++;
1859 src_tmp
.GlyphsSet
.SetBit(codepoint
, true);
1860 if (dst_tmp
.SrcCount
> 1)
1861 dst_tmp
.GlyphsSet
.SetBit(codepoint
, true);
1862 total_glyphs_count
++;
1866 // 3. Unpack our bit map into a flat list (we now have all the Unicode points that we know are requested _and_ available _and_ not overlapping another)
1867 for (int src_i
= 0; src_i
< src_tmp_array
.Size
; src_i
++)
1869 ImFontBuildSrcData
& src_tmp
= src_tmp_array
[src_i
];
1870 src_tmp
.GlyphsList
.reserve(src_tmp
.GlyphsCount
);
1871 UnpackBoolVectorToFlatIndexList(&src_tmp
.GlyphsSet
, &src_tmp
.GlyphsList
);
1872 src_tmp
.GlyphsSet
.Clear();
1873 IM_ASSERT(src_tmp
.GlyphsList
.Size
== src_tmp
.GlyphsCount
);
1875 for (int dst_i
= 0; dst_i
< dst_tmp_array
.Size
; dst_i
++)
1876 dst_tmp_array
[dst_i
].GlyphsSet
.Clear();
1877 dst_tmp_array
.clear();
1879 // Allocate packing character data and flag packed characters buffer as non-packed (x0=y0=x1=y1=0)
1880 // (We technically don't need to zero-clear buf_rects, but let's do it for the sake of sanity)
1881 ImVector
<stbrp_rect
> buf_rects
;
1882 ImVector
<stbtt_packedchar
> buf_packedchars
;
1883 buf_rects
.resize(total_glyphs_count
);
1884 buf_packedchars
.resize(total_glyphs_count
);
1885 memset(buf_rects
.Data
, 0, (size_t)buf_rects
.size_in_bytes());
1886 memset(buf_packedchars
.Data
, 0, (size_t)buf_packedchars
.size_in_bytes());
1888 // 4. Gather glyphs sizes so we can pack them in our virtual canvas.
1889 int total_surface
= 0;
1890 int buf_rects_out_n
= 0;
1891 int buf_packedchars_out_n
= 0;
1892 for (int src_i
= 0; src_i
< src_tmp_array
.Size
; src_i
++)
1894 ImFontBuildSrcData
& src_tmp
= src_tmp_array
[src_i
];
1895 if (src_tmp
.GlyphsCount
== 0)
1898 src_tmp
.Rects
= &buf_rects
[buf_rects_out_n
];
1899 src_tmp
.PackedChars
= &buf_packedchars
[buf_packedchars_out_n
];
1900 buf_rects_out_n
+= src_tmp
.GlyphsCount
;
1901 buf_packedchars_out_n
+= src_tmp
.GlyphsCount
;
1903 // Convert our ranges in the format stb_truetype wants
1904 ImFontConfig
& cfg
= atlas
->ConfigData
[src_i
];
1905 src_tmp
.PackRange
.font_size
= cfg
.SizePixels
;
1906 src_tmp
.PackRange
.first_unicode_codepoint_in_range
= 0;
1907 src_tmp
.PackRange
.array_of_unicode_codepoints
= src_tmp
.GlyphsList
.Data
;
1908 src_tmp
.PackRange
.num_chars
= src_tmp
.GlyphsList
.Size
;
1909 src_tmp
.PackRange
.chardata_for_range
= src_tmp
.PackedChars
;
1910 src_tmp
.PackRange
.h_oversample
= (unsigned char)cfg
.OversampleH
;
1911 src_tmp
.PackRange
.v_oversample
= (unsigned char)cfg
.OversampleV
;
1913 // Gather the sizes of all rectangles we will need to pack (this loop is based on stbtt_PackFontRangesGatherRects)
1914 const float scale
= (cfg
.SizePixels
> 0) ? stbtt_ScaleForPixelHeight(&src_tmp
.FontInfo
, cfg
.SizePixels
) : stbtt_ScaleForMappingEmToPixels(&src_tmp
.FontInfo
, -cfg
.SizePixels
);
1915 const int padding
= atlas
->TexGlyphPadding
;
1916 for (int glyph_i
= 0; glyph_i
< src_tmp
.GlyphsList
.Size
; glyph_i
++)
1919 const int glyph_index_in_font
= stbtt_FindGlyphIndex(&src_tmp
.FontInfo
, src_tmp
.GlyphsList
[glyph_i
]);
1920 IM_ASSERT(glyph_index_in_font
!= 0);
1921 stbtt_GetGlyphBitmapBoxSubpixel(&src_tmp
.FontInfo
, glyph_index_in_font
, scale
* cfg
.OversampleH
, scale
* cfg
.OversampleV
, 0, 0, &x0
, &y0
, &x1
, &y1
);
1922 src_tmp
.Rects
[glyph_i
].w
= (stbrp_coord
)(x1
- x0
+ padding
+ cfg
.OversampleH
- 1);
1923 src_tmp
.Rects
[glyph_i
].h
= (stbrp_coord
)(y1
- y0
+ padding
+ cfg
.OversampleV
- 1);
1924 total_surface
+= src_tmp
.Rects
[glyph_i
].w
* src_tmp
.Rects
[glyph_i
].h
;
1928 // We need a width for the skyline algorithm, any width!
1929 // The exact width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height.
1930 // User can override TexDesiredWidth and TexGlyphPadding if they wish, otherwise we use a simple heuristic to select the width based on expected surface.
1931 const int surface_sqrt
= (int)ImSqrt((float)total_surface
) + 1;
1932 atlas
->TexHeight
= 0;
1933 if (atlas
->TexDesiredWidth
> 0)
1934 atlas
->TexWidth
= atlas
->TexDesiredWidth
;
1936 atlas
->TexWidth
= (surface_sqrt
>= 4096*0.7f
) ? 4096 : (surface_sqrt
>= 2048*0.7f
) ? 2048 : (surface_sqrt
>= 1024*0.7f
) ? 1024 : 512;
1939 // Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values).
1940 const int TEX_HEIGHT_MAX
= 1024 * 32;
1941 stbtt_pack_context spc
= {};
1942 stbtt_PackBegin(&spc
, NULL
, atlas
->TexWidth
, TEX_HEIGHT_MAX
, 0, atlas
->TexGlyphPadding
, NULL
);
1943 ImFontAtlasBuildPackCustomRects(atlas
, spc
.pack_info
);
1945 // 6. Pack each source font. No rendering yet, we are working with rectangles in an infinitely tall texture at this point.
1946 for (int src_i
= 0; src_i
< src_tmp_array
.Size
; src_i
++)
1948 ImFontBuildSrcData
& src_tmp
= src_tmp_array
[src_i
];
1949 if (src_tmp
.GlyphsCount
== 0)
1952 stbrp_pack_rects((stbrp_context
*)spc
.pack_info
, src_tmp
.Rects
, src_tmp
.GlyphsCount
);
1954 // Extend texture height and mark missing glyphs as non-packed so we won't render them.
1955 // FIXME: We are not handling packing failure here (would happen if we got off TEX_HEIGHT_MAX or if a single if larger than TexWidth?)
1956 for (int glyph_i
= 0; glyph_i
< src_tmp
.GlyphsCount
; glyph_i
++)
1957 if (src_tmp
.Rects
[glyph_i
].was_packed
)
1958 atlas
->TexHeight
= ImMax(atlas
->TexHeight
, src_tmp
.Rects
[glyph_i
].y
+ src_tmp
.Rects
[glyph_i
].h
);
1961 // 7. Allocate texture
1962 atlas
->TexHeight
= (atlas
->Flags
& ImFontAtlasFlags_NoPowerOfTwoHeight
) ? (atlas
->TexHeight
+ 1) : ImUpperPowerOfTwo(atlas
->TexHeight
);
1963 atlas
->TexUvScale
= ImVec2(1.0f
/ atlas
->TexWidth
, 1.0f
/ atlas
->TexHeight
);
1964 atlas
->TexPixelsAlpha8
= (unsigned char*)ImGui::MemAlloc(atlas
->TexWidth
* atlas
->TexHeight
);
1965 memset(atlas
->TexPixelsAlpha8
, 0, atlas
->TexWidth
* atlas
->TexHeight
);
1966 spc
.pixels
= atlas
->TexPixelsAlpha8
;
1967 spc
.height
= atlas
->TexHeight
;
1969 // 8. Render/rasterize font characters into the texture
1970 for (int src_i
= 0; src_i
< src_tmp_array
.Size
; src_i
++)
1972 ImFontConfig
& cfg
= atlas
->ConfigData
[src_i
];
1973 ImFontBuildSrcData
& src_tmp
= src_tmp_array
[src_i
];
1974 if (src_tmp
.GlyphsCount
== 0)
1977 stbtt_PackFontRangesRenderIntoRects(&spc
, &src_tmp
.FontInfo
, &src_tmp
.PackRange
, 1, src_tmp
.Rects
);
1979 // Apply multiply operator
1980 if (cfg
.RasterizerMultiply
!= 1.0f
)
1982 unsigned char multiply_table
[256];
1983 ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table
, cfg
.RasterizerMultiply
);
1984 stbrp_rect
* r
= &src_tmp
.Rects
[0];
1985 for (int glyph_i
= 0; glyph_i
< src_tmp
.GlyphsCount
; glyph_i
++, r
++)
1987 ImFontAtlasBuildMultiplyRectAlpha8(multiply_table
, atlas
->TexPixelsAlpha8
, r
->x
, r
->y
, r
->w
, r
->h
, atlas
->TexWidth
* 1);
1989 src_tmp
.Rects
= NULL
;
1993 stbtt_PackEnd(&spc
);
1996 // 9. Setup ImFont and glyphs for runtime
1997 for (int src_i
= 0; src_i
< src_tmp_array
.Size
; src_i
++)
1999 ImFontBuildSrcData
& src_tmp
= src_tmp_array
[src_i
];
2000 if (src_tmp
.GlyphsCount
== 0)
2003 ImFontConfig
& cfg
= atlas
->ConfigData
[src_i
];
2004 ImFont
* dst_font
= cfg
.DstFont
; // We can have multiple input fonts writing into a same destination font (when using MergeMode=true)
2006 const float font_scale
= stbtt_ScaleForPixelHeight(&src_tmp
.FontInfo
, cfg
.SizePixels
);
2007 int unscaled_ascent
, unscaled_descent
, unscaled_line_gap
;
2008 stbtt_GetFontVMetrics(&src_tmp
.FontInfo
, &unscaled_ascent
, &unscaled_descent
, &unscaled_line_gap
);
2010 const float ascent
= ImFloor(unscaled_ascent
* font_scale
+ ((unscaled_ascent
> 0.0f
) ? +1 : -1));
2011 const float descent
= ImFloor(unscaled_descent
* font_scale
+ ((unscaled_descent
> 0.0f
) ? +1 : -1));
2012 ImFontAtlasBuildSetupFont(atlas
, dst_font
, &cfg
, ascent
, descent
);
2013 const float font_off_x
= cfg
.GlyphOffset
.x
;
2014 const float font_off_y
= cfg
.GlyphOffset
.y
+ (float)(int)(dst_font
->Ascent
+ 0.5f
);
2016 for (int glyph_i
= 0; glyph_i
< src_tmp
.GlyphsCount
; glyph_i
++)
2018 const int codepoint
= src_tmp
.GlyphsList
[glyph_i
];
2019 const stbtt_packedchar
& pc
= src_tmp
.PackedChars
[glyph_i
];
2021 const float char_advance_x_org
= pc
.xadvance
;
2022 const float char_advance_x_mod
= ImClamp(char_advance_x_org
, cfg
.GlyphMinAdvanceX
, cfg
.GlyphMaxAdvanceX
);
2023 float char_off_x
= font_off_x
;
2024 if (char_advance_x_org
!= char_advance_x_mod
)
2025 char_off_x
+= cfg
.PixelSnapH
? (float)(int)((char_advance_x_mod
- char_advance_x_org
) * 0.5f
) : (char_advance_x_mod
- char_advance_x_org
) * 0.5f
;
2028 stbtt_aligned_quad q
;
2029 float dummy_x
= 0.0f
, dummy_y
= 0.0f
;
2030 stbtt_GetPackedQuad(src_tmp
.PackedChars
, atlas
->TexWidth
, atlas
->TexHeight
, glyph_i
, &dummy_x
, &dummy_y
, &q
, 0);
2031 dst_font
->AddGlyph((ImWchar
)codepoint
, q
.x0
+ char_off_x
, q
.y0
+ font_off_y
, q
.x1
+ char_off_x
, q
.y1
+ font_off_y
, q
.s0
, q
.t0
, q
.s1
, q
.t1
, char_advance_x_mod
);
2035 // Cleanup temporary (ImVector doesn't honor destructor)
2036 for (int src_i
= 0; src_i
< src_tmp_array
.Size
; src_i
++)
2037 src_tmp_array
[src_i
].~ImFontBuildSrcData();
2039 ImFontAtlasBuildFinish(atlas
);
2043 void ImFontAtlasBuildRegisterDefaultCustomRects(ImFontAtlas
* atlas
)
2045 if (atlas
->CustomRectIds
[0] >= 0)
2047 if (!(atlas
->Flags
& ImFontAtlasFlags_NoMouseCursors
))
2048 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
);
2050 atlas
->CustomRectIds
[0] = atlas
->AddCustomRectRegular(FONT_ATLAS_DEFAULT_TEX_DATA_ID
, 2, 2);
2053 void ImFontAtlasBuildSetupFont(ImFontAtlas
* atlas
, ImFont
* font
, ImFontConfig
* font_config
, float ascent
, float descent
)
2055 if (!font_config
->MergeMode
)
2057 font
->ClearOutputData();
2058 font
->FontSize
= font_config
->SizePixels
;
2059 font
->ConfigData
= font_config
;
2060 font
->ContainerAtlas
= atlas
;
2061 font
->Ascent
= ascent
;
2062 font
->Descent
= descent
;
2064 font
->ConfigDataCount
++;
2067 void ImFontAtlasBuildPackCustomRects(ImFontAtlas
* atlas
, void* stbrp_context_opaque
)
2069 stbrp_context
* pack_context
= (stbrp_context
*)stbrp_context_opaque
;
2070 IM_ASSERT(pack_context
!= NULL
);
2072 ImVector
<ImFontAtlas::CustomRect
>& user_rects
= atlas
->CustomRects
;
2073 IM_ASSERT(user_rects
.Size
>= 1); // We expect at least the default custom rects to be registered, else something went wrong.
2075 ImVector
<stbrp_rect
> pack_rects
;
2076 pack_rects
.resize(user_rects
.Size
);
2077 memset(pack_rects
.Data
, 0, (size_t)pack_rects
.size_in_bytes());
2078 for (int i
= 0; i
< user_rects
.Size
; i
++)
2080 pack_rects
[i
].w
= user_rects
[i
].Width
;
2081 pack_rects
[i
].h
= user_rects
[i
].Height
;
2083 stbrp_pack_rects(pack_context
, &pack_rects
[0], pack_rects
.Size
);
2084 for (int i
= 0; i
< pack_rects
.Size
; i
++)
2085 if (pack_rects
[i
].was_packed
)
2087 user_rects
[i
].X
= pack_rects
[i
].x
;
2088 user_rects
[i
].Y
= pack_rects
[i
].y
;
2089 IM_ASSERT(pack_rects
[i
].w
== user_rects
[i
].Width
&& pack_rects
[i
].h
== user_rects
[i
].Height
);
2090 atlas
->TexHeight
= ImMax(atlas
->TexHeight
, pack_rects
[i
].y
+ pack_rects
[i
].h
);
2094 static void ImFontAtlasBuildRenderDefaultTexData(ImFontAtlas
* atlas
)
2096 IM_ASSERT(atlas
->CustomRectIds
[0] >= 0);
2097 IM_ASSERT(atlas
->TexPixelsAlpha8
!= NULL
);
2098 ImFontAtlas::CustomRect
& r
= atlas
->CustomRects
[atlas
->CustomRectIds
[0]];
2099 IM_ASSERT(r
.ID
== FONT_ATLAS_DEFAULT_TEX_DATA_ID
);
2100 IM_ASSERT(r
.IsPacked());
2102 const int w
= atlas
->TexWidth
;
2103 if (!(atlas
->Flags
& ImFontAtlasFlags_NoMouseCursors
))
2105 // Render/copy pixels
2106 IM_ASSERT(r
.Width
== FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF
* 2 + 1 && r
.Height
== FONT_ATLAS_DEFAULT_TEX_DATA_H
);
2107 for (int y
= 0, n
= 0; y
< FONT_ATLAS_DEFAULT_TEX_DATA_H
; y
++)
2108 for (int x
= 0; x
< FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF
; x
++, n
++)
2110 const int offset0
= (int)(r
.X
+ x
) + (int)(r
.Y
+ y
) * w
;
2111 const int offset1
= offset0
+ FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF
+ 1;
2112 atlas
->TexPixelsAlpha8
[offset0
] = FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS
[n
] == '.' ? 0xFF : 0x00;
2113 atlas
->TexPixelsAlpha8
[offset1
] = FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS
[n
] == 'X' ? 0xFF : 0x00;
2118 IM_ASSERT(r
.Width
== 2 && r
.Height
== 2);
2119 const int offset
= (int)(r
.X
) + (int)(r
.Y
) * w
;
2120 atlas
->TexPixelsAlpha8
[offset
] = atlas
->TexPixelsAlpha8
[offset
+ 1] = atlas
->TexPixelsAlpha8
[offset
+ w
] = atlas
->TexPixelsAlpha8
[offset
+ w
+ 1] = 0xFF;
2122 atlas
->TexUvWhitePixel
= ImVec2((r
.X
+ 0.5f
) * atlas
->TexUvScale
.x
, (r
.Y
+ 0.5f
) * atlas
->TexUvScale
.y
);
2125 void ImFontAtlasBuildFinish(ImFontAtlas
* atlas
)
2127 // Render into our custom data block
2128 ImFontAtlasBuildRenderDefaultTexData(atlas
);
2130 // Register custom rectangle glyphs
2131 for (int i
= 0; i
< atlas
->CustomRects
.Size
; i
++)
2133 const ImFontAtlas::CustomRect
& r
= atlas
->CustomRects
[i
];
2134 if (r
.Font
== NULL
|| r
.ID
> 0x10000)
2137 IM_ASSERT(r
.Font
->ContainerAtlas
== atlas
);
2139 atlas
->CalcCustomRectUV(&r
, &uv0
, &uv1
);
2140 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
);
2143 // Build all fonts lookup tables
2144 for (int i
= 0; i
< atlas
->Fonts
.Size
; i
++)
2145 if (atlas
->Fonts
[i
]->DirtyLookupTables
)
2146 atlas
->Fonts
[i
]->BuildLookupTable();
2149 // Retrieve list of range (2 int per range, values are inclusive)
2150 const ImWchar
* ImFontAtlas::GetGlyphRangesDefault()
2152 static const ImWchar ranges
[] =
2154 0x0020, 0x00FF, // Basic Latin + Latin Supplement
2160 const ImWchar
* ImFontAtlas::GetGlyphRangesKorean()
2162 static const ImWchar ranges
[] =
2164 0x0020, 0x00FF, // Basic Latin + Latin Supplement
2165 0x3131, 0x3163, // Korean alphabets
2166 0xAC00, 0xD79D, // Korean characters
2172 const ImWchar
* ImFontAtlas::GetGlyphRangesChineseFull()
2174 static const ImWchar ranges
[] =
2176 0x0020, 0x00FF, // Basic Latin + Latin Supplement
2177 0x2000, 0x206F, // General Punctuation
2178 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
2179 0x31F0, 0x31FF, // Katakana Phonetic Extensions
2180 0xFF00, 0xFFEF, // Half-width characters
2181 0x4e00, 0x9FAF, // CJK Ideograms
2187 static void UnpackAccumulativeOffsetsIntoRanges(int base_codepoint
, const short* accumulative_offsets
, int accumulative_offsets_count
, ImWchar
* out_ranges
)
2189 for (int n
= 0; n
< accumulative_offsets_count
; n
++, out_ranges
+= 2)
2191 out_ranges
[0] = out_ranges
[1] = (ImWchar
)(base_codepoint
+ accumulative_offsets
[n
]);
2192 base_codepoint
+= accumulative_offsets
[n
];
2197 //-------------------------------------------------------------------------
2198 // [SECTION] ImFontAtlas glyph ranges helpers
2199 //-------------------------------------------------------------------------
2201 const ImWchar
* ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon()
2203 // Store 2500 regularly used characters for Simplified Chinese.
2204 // Sourced from https://zh.wiktionary.org/wiki/%E9%99%84%E5%BD%95:%E7%8E%B0%E4%BB%A3%E6%B1%89%E8%AF%AD%E5%B8%B8%E7%94%A8%E5%AD%97%E8%A1%A8
2205 // This table covers 97.97% of all characters used during the month in July, 1987.
2206 // You can use ImFontGlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters.
2207 // (Stored as accumulative offsets from the initial unicode codepoint 0x4E00. This encoding is designed to helps us compact the source code size.)
2208 static const short accumulative_offsets_from_0x4E00
[] =
2210 0,1,2,4,1,1,1,1,2,1,3,2,1,2,2,1,1,1,1,1,5,2,1,2,3,3,3,2,2,4,1,1,1,2,1,5,2,3,1,2,1,2,1,1,2,1,1,2,2,1,4,1,1,1,1,5,10,1,2,19,2,1,2,1,2,1,2,1,2,
2211 1,5,1,6,3,2,1,2,2,1,1,1,4,8,5,1,1,4,1,1,3,1,2,1,5,1,2,1,1,1,10,1,1,5,2,4,6,1,4,2,2,2,12,2,1,1,6,1,1,1,4,1,1,4,6,5,1,4,2,2,4,10,7,1,1,4,2,4,
2212 2,1,4,3,6,10,12,5,7,2,14,2,9,1,1,6,7,10,4,7,13,1,5,4,8,4,1,1,2,28,5,6,1,1,5,2,5,20,2,2,9,8,11,2,9,17,1,8,6,8,27,4,6,9,20,11,27,6,68,2,2,1,1,
2213 1,2,1,2,2,7,6,11,3,3,1,1,3,1,2,1,1,1,1,1,3,1,1,8,3,4,1,5,7,2,1,4,4,8,4,2,1,2,1,1,4,5,6,3,6,2,12,3,1,3,9,2,4,3,4,1,5,3,3,1,3,7,1,5,1,1,1,1,2,
2214 3,4,5,2,3,2,6,1,1,2,1,7,1,7,3,4,5,15,2,2,1,5,3,22,19,2,1,1,1,1,2,5,1,1,1,6,1,1,12,8,2,9,18,22,4,1,1,5,1,16,1,2,7,10,15,1,1,6,2,4,1,2,4,1,6,
2215 1,1,3,2,4,1,6,4,5,1,2,1,1,2,1,10,3,1,3,2,1,9,3,2,5,7,2,19,4,3,6,1,1,1,1,1,4,3,2,1,1,1,2,5,3,1,1,1,2,2,1,1,2,1,1,2,1,3,1,1,1,3,7,1,4,1,1,2,1,
2216 1,2,1,2,4,4,3,8,1,1,1,2,1,3,5,1,3,1,3,4,6,2,2,14,4,6,6,11,9,1,15,3,1,28,5,2,5,5,3,1,3,4,5,4,6,14,3,2,3,5,21,2,7,20,10,1,2,19,2,4,28,28,2,3,
2217 2,1,14,4,1,26,28,42,12,40,3,52,79,5,14,17,3,2,2,11,3,4,6,3,1,8,2,23,4,5,8,10,4,2,7,3,5,1,1,6,3,1,2,2,2,5,28,1,1,7,7,20,5,3,29,3,17,26,1,8,4,
2218 27,3,6,11,23,5,3,4,6,13,24,16,6,5,10,25,35,7,3,2,3,3,14,3,6,2,6,1,4,2,3,8,2,1,1,3,3,3,4,1,1,13,2,2,4,5,2,1,14,14,1,2,2,1,4,5,2,3,1,14,3,12,
2219 3,17,2,16,5,1,2,1,8,9,3,19,4,2,2,4,17,25,21,20,28,75,1,10,29,103,4,1,2,1,1,4,2,4,1,2,3,24,2,2,2,1,1,2,1,3,8,1,1,1,2,1,1,3,1,1,1,6,1,5,3,1,1,
2220 1,3,4,1,1,5,2,1,5,6,13,9,16,1,1,1,1,3,2,3,2,4,5,2,5,2,2,3,7,13,7,2,2,1,1,1,1,2,3,3,2,1,6,4,9,2,1,14,2,14,2,1,18,3,4,14,4,11,41,15,23,15,23,
2221 176,1,3,4,1,1,1,1,5,3,1,2,3,7,3,1,1,2,1,2,4,4,6,2,4,1,9,7,1,10,5,8,16,29,1,1,2,2,3,1,3,5,2,4,5,4,1,1,2,2,3,3,7,1,6,10,1,17,1,44,4,6,2,1,1,6,
2222 5,4,2,10,1,6,9,2,8,1,24,1,2,13,7,8,8,2,1,4,1,3,1,3,3,5,2,5,10,9,4,9,12,2,1,6,1,10,1,1,7,7,4,10,8,3,1,13,4,3,1,6,1,3,5,2,1,2,17,16,5,2,16,6,
2223 1,4,2,1,3,3,6,8,5,11,11,1,3,3,2,4,6,10,9,5,7,4,7,4,7,1,1,4,2,1,3,6,8,7,1,6,11,5,5,3,24,9,4,2,7,13,5,1,8,82,16,61,1,1,1,4,2,2,16,10,3,8,1,1,
2224 6,4,2,1,3,1,1,1,4,3,8,4,2,2,1,1,1,1,1,6,3,5,1,1,4,6,9,2,1,1,1,2,1,7,2,1,6,1,5,4,4,3,1,8,1,3,3,1,3,2,2,2,2,3,1,6,1,2,1,2,1,3,7,1,8,2,1,2,1,5,
2225 2,5,3,5,10,1,2,1,1,3,2,5,11,3,9,3,5,1,1,5,9,1,2,1,5,7,9,9,8,1,3,3,3,6,8,2,3,2,1,1,32,6,1,2,15,9,3,7,13,1,3,10,13,2,14,1,13,10,2,1,3,10,4,15,
2226 2,15,15,10,1,3,9,6,9,32,25,26,47,7,3,2,3,1,6,3,4,3,2,8,5,4,1,9,4,2,2,19,10,6,2,3,8,1,2,2,4,2,1,9,4,4,4,6,4,8,9,2,3,1,1,1,1,3,5,5,1,3,8,4,6,
2227 2,1,4,12,1,5,3,7,13,2,5,8,1,6,1,2,5,14,6,1,5,2,4,8,15,5,1,23,6,62,2,10,1,1,8,1,2,2,10,4,2,2,9,2,1,1,3,2,3,1,5,3,3,2,1,3,8,1,1,1,11,3,1,1,4,
2228 3,7,1,14,1,2,3,12,5,2,5,1,6,7,5,7,14,11,1,3,1,8,9,12,2,1,11,8,4,4,2,6,10,9,13,1,1,3,1,5,1,3,2,4,4,1,18,2,3,14,11,4,29,4,2,7,1,3,13,9,2,2,5,
2229 3,5,20,7,16,8,5,72,34,6,4,22,12,12,28,45,36,9,7,39,9,191,1,1,1,4,11,8,4,9,2,3,22,1,1,1,1,4,17,1,7,7,1,11,31,10,2,4,8,2,3,2,1,4,2,16,4,32,2,
2230 3,19,13,4,9,1,5,2,14,8,1,1,3,6,19,6,5,1,16,6,2,10,8,5,1,2,3,1,5,5,1,11,6,6,1,3,3,2,6,3,8,1,1,4,10,7,5,7,7,5,8,9,2,1,3,4,1,1,3,1,3,3,2,6,16,
2231 1,4,6,3,1,10,6,1,3,15,2,9,2,10,25,13,9,16,6,2,2,10,11,4,3,9,1,2,6,6,5,4,30,40,1,10,7,12,14,33,6,3,6,7,3,1,3,1,11,14,4,9,5,12,11,49,18,51,31,
2232 140,31,2,2,1,5,1,8,1,10,1,4,4,3,24,1,10,1,3,6,6,16,3,4,5,2,1,4,2,57,10,6,22,2,22,3,7,22,6,10,11,36,18,16,33,36,2,5,5,1,1,1,4,10,1,4,13,2,7,
2233 5,2,9,3,4,1,7,43,3,7,3,9,14,7,9,1,11,1,1,3,7,4,18,13,1,14,1,3,6,10,73,2,2,30,6,1,11,18,19,13,22,3,46,42,37,89,7,3,16,34,2,2,3,9,1,7,1,1,1,2,
2234 2,4,10,7,3,10,3,9,5,28,9,2,6,13,7,3,1,3,10,2,7,2,11,3,6,21,54,85,2,1,4,2,2,1,39,3,21,2,2,5,1,1,1,4,1,1,3,4,15,1,3,2,4,4,2,3,8,2,20,1,8,7,13,
2235 4,1,26,6,2,9,34,4,21,52,10,4,4,1,5,12,2,11,1,7,2,30,12,44,2,30,1,1,3,6,16,9,17,39,82,2,2,24,7,1,7,3,16,9,14,44,2,1,2,1,2,3,5,2,4,1,6,7,5,3,
2236 2,6,1,11,5,11,2,1,18,19,8,1,3,24,29,2,1,3,5,2,2,1,13,6,5,1,46,11,3,5,1,1,5,8,2,10,6,12,6,3,7,11,2,4,16,13,2,5,1,1,2,2,5,2,28,5,2,23,10,8,4,
2237 4,22,39,95,38,8,14,9,5,1,13,5,4,3,13,12,11,1,9,1,27,37,2,5,4,4,63,211,95,2,2,2,1,3,5,2,1,1,2,2,1,1,1,3,2,4,1,2,1,1,5,2,2,1,1,2,3,1,3,1,1,1,
2238 3,1,4,2,1,3,6,1,1,3,7,15,5,3,2,5,3,9,11,4,2,22,1,6,3,8,7,1,4,28,4,16,3,3,25,4,4,27,27,1,4,1,2,2,7,1,3,5,2,28,8,2,14,1,8,6,16,25,3,3,3,14,3,
2239 3,1,1,2,1,4,6,3,8,4,1,1,1,2,3,6,10,6,2,3,18,3,2,5,5,4,3,1,5,2,5,4,23,7,6,12,6,4,17,11,9,5,1,1,10,5,12,1,1,11,26,33,7,3,6,1,17,7,1,5,12,1,11,
2240 2,4,1,8,14,17,23,1,2,1,7,8,16,11,9,6,5,2,6,4,16,2,8,14,1,11,8,9,1,1,1,9,25,4,11,19,7,2,15,2,12,8,52,7,5,19,2,16,4,36,8,1,16,8,24,26,4,6,2,9,
2241 5,4,36,3,28,12,25,15,37,27,17,12,59,38,5,32,127,1,2,9,17,14,4,1,2,1,1,8,11,50,4,14,2,19,16,4,17,5,4,5,26,12,45,2,23,45,104,30,12,8,3,10,2,2,
2242 3,3,1,4,20,7,2,9,6,15,2,20,1,3,16,4,11,15,6,134,2,5,59,1,2,2,2,1,9,17,3,26,137,10,211,59,1,2,4,1,4,1,1,1,2,6,2,3,1,1,2,3,2,3,1,3,4,4,2,3,3,
2243 1,4,3,1,7,2,2,3,1,2,1,3,3,3,2,2,3,2,1,3,14,6,1,3,2,9,6,15,27,9,34,145,1,1,2,1,1,1,1,2,1,1,1,1,2,2,2,3,1,2,1,1,1,2,3,5,8,3,5,2,4,1,3,2,2,2,12,
2244 4,1,1,1,10,4,5,1,20,4,16,1,15,9,5,12,2,9,2,5,4,2,26,19,7,1,26,4,30,12,15,42,1,6,8,172,1,1,4,2,1,1,11,2,2,4,2,1,2,1,10,8,1,2,1,4,5,1,2,5,1,8,
2245 4,1,3,4,2,1,6,2,1,3,4,1,2,1,1,1,1,12,5,7,2,4,3,1,1,1,3,3,6,1,2,2,3,3,3,2,1,2,12,14,11,6,6,4,12,2,8,1,7,10,1,35,7,4,13,15,4,3,23,21,28,52,5,
2246 26,5,6,1,7,10,2,7,53,3,2,1,1,1,2,163,532,1,10,11,1,3,3,4,8,2,8,6,2,2,23,22,4,2,2,4,2,1,3,1,3,3,5,9,8,2,1,2,8,1,10,2,12,21,20,15,105,2,3,1,1,
2247 3,2,3,1,1,2,5,1,4,15,11,19,1,1,1,1,5,4,5,1,1,2,5,3,5,12,1,2,5,1,11,1,1,15,9,1,4,5,3,26,8,2,1,3,1,1,15,19,2,12,1,2,5,2,7,2,19,2,20,6,26,7,5,
2248 2,2,7,34,21,13,70,2,128,1,1,2,1,1,2,1,1,3,2,2,2,15,1,4,1,3,4,42,10,6,1,49,85,8,1,2,1,1,4,4,2,3,6,1,5,7,4,3,211,4,1,2,1,2,5,1,2,4,2,2,6,5,6,
2249 10,3,4,48,100,6,2,16,296,5,27,387,2,2,3,7,16,8,5,38,15,39,21,9,10,3,7,59,13,27,21,47,5,21,6
2251 static ImWchar base_ranges
[] = // not zero-terminated
2253 0x0020, 0x00FF, // Basic Latin + Latin Supplement
2254 0x2000, 0x206F, // General Punctuation
2255 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
2256 0x31F0, 0x31FF, // Katakana Phonetic Extensions
2257 0xFF00, 0xFFEF // Half-width characters
2259 static ImWchar full_ranges
[IM_ARRAYSIZE(base_ranges
) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00
) * 2 + 1] = { 0 };
2260 if (!full_ranges
[0])
2262 memcpy(full_ranges
, base_ranges
, sizeof(base_ranges
));
2263 UnpackAccumulativeOffsetsIntoRanges(0x4E00, accumulative_offsets_from_0x4E00
, IM_ARRAYSIZE(accumulative_offsets_from_0x4E00
), full_ranges
+ IM_ARRAYSIZE(base_ranges
));
2265 return &full_ranges
[0];
2268 const ImWchar
* ImFontAtlas::GetGlyphRangesJapanese()
2270 // 1946 common ideograms code points for Japanese
2271 // Sourced from http://theinstructionlimit.com/common-kanji-character-ranges-for-xna-spritefont-rendering
2272 // FIXME: Source a list of the revised 2136 Joyo Kanji list from 2010 and rebuild this.
2273 // You can use ImFontGlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters.
2274 // (Stored as accumulative offsets from the initial unicode codepoint 0x4E00. This encoding is designed to helps us compact the source code size.)
2275 static const short accumulative_offsets_from_0x4E00
[] =
2277 0,1,2,4,1,1,1,1,2,1,6,2,2,1,8,5,7,11,1,2,10,10,8,2,4,20,2,11,8,2,1,2,1,6,2,1,7,5,3,7,1,1,13,7,9,1,4,6,1,2,1,10,1,1,9,2,2,4,5,6,14,1,1,9,3,18,
2278 5,4,2,2,10,7,1,1,1,3,2,4,3,23,2,10,12,2,14,2,4,13,1,6,10,3,1,7,13,6,4,13,5,2,3,17,2,2,5,7,6,4,1,7,14,16,6,13,9,15,1,1,7,16,4,7,1,19,9,2,7,15,
2279 2,6,5,13,25,4,14,13,11,25,1,1,1,2,1,2,2,3,10,11,3,3,1,1,4,4,2,1,4,9,1,4,3,5,5,2,7,12,11,15,7,16,4,5,16,2,1,1,6,3,3,1,1,2,7,6,6,7,1,4,7,6,1,1,
2280 2,1,12,3,3,9,5,8,1,11,1,2,3,18,20,4,1,3,6,1,7,3,5,5,7,2,2,12,3,1,4,2,3,2,3,11,8,7,4,17,1,9,25,1,1,4,2,2,4,1,2,7,1,1,1,3,1,2,6,16,1,2,1,1,3,12,
2281 20,2,5,20,8,7,6,2,1,1,1,1,6,2,1,2,10,1,1,6,1,3,1,2,1,4,1,12,4,1,3,1,1,1,1,1,10,4,7,5,13,1,15,1,1,30,11,9,1,15,38,14,1,32,17,20,1,9,31,2,21,9,
2282 4,49,22,2,1,13,1,11,45,35,43,55,12,19,83,1,3,2,3,13,2,1,7,3,18,3,13,8,1,8,18,5,3,7,25,24,9,24,40,3,17,24,2,1,6,2,3,16,15,6,7,3,12,1,9,7,3,3,
2283 3,15,21,5,16,4,5,12,11,11,3,6,3,2,31,3,2,1,1,23,6,6,1,4,2,6,5,2,1,1,3,3,22,2,6,2,3,17,3,2,4,5,1,9,5,1,1,6,15,12,3,17,2,14,2,8,1,23,16,4,2,23,
2284 8,15,23,20,12,25,19,47,11,21,65,46,4,3,1,5,6,1,2,5,26,2,1,1,3,11,1,1,1,2,1,2,3,1,1,10,2,3,1,1,1,3,6,3,2,2,6,6,9,2,2,2,6,2,5,10,2,4,1,2,1,2,2,
2285 3,1,1,3,1,2,9,23,9,2,1,1,1,1,5,3,2,1,10,9,6,1,10,2,31,25,3,7,5,40,1,15,6,17,7,27,180,1,3,2,2,1,1,1,6,3,10,7,1,3,6,17,8,6,2,2,1,3,5,5,8,16,14,
2286 15,1,1,4,1,2,1,1,1,3,2,7,5,6,2,5,10,1,4,2,9,1,1,11,6,1,44,1,3,7,9,5,1,3,1,1,10,7,1,10,4,2,7,21,15,7,2,5,1,8,3,4,1,3,1,6,1,4,2,1,4,10,8,1,4,5,
2287 1,5,10,2,7,1,10,1,1,3,4,11,10,29,4,7,3,5,2,3,33,5,2,19,3,1,4,2,6,31,11,1,3,3,3,1,8,10,9,12,11,12,8,3,14,8,6,11,1,4,41,3,1,2,7,13,1,5,6,2,6,12,
2288 12,22,5,9,4,8,9,9,34,6,24,1,1,20,9,9,3,4,1,7,2,2,2,6,2,28,5,3,6,1,4,6,7,4,2,1,4,2,13,6,4,4,3,1,8,8,3,2,1,5,1,2,2,3,1,11,11,7,3,6,10,8,6,16,16,
2289 22,7,12,6,21,5,4,6,6,3,6,1,3,2,1,2,8,29,1,10,1,6,13,6,6,19,31,1,13,4,4,22,17,26,33,10,4,15,12,25,6,67,10,2,3,1,6,10,2,6,2,9,1,9,4,4,1,2,16,2,
2290 5,9,2,3,8,1,8,3,9,4,8,6,4,8,11,3,2,1,1,3,26,1,7,5,1,11,1,5,3,5,2,13,6,39,5,1,5,2,11,6,10,5,1,15,5,3,6,19,21,22,2,4,1,6,1,8,1,4,8,2,4,2,2,9,2,
2291 1,1,1,4,3,6,3,12,7,1,14,2,4,10,2,13,1,17,7,3,2,1,3,2,13,7,14,12,3,1,29,2,8,9,15,14,9,14,1,3,1,6,5,9,11,3,38,43,20,7,7,8,5,15,12,19,15,81,8,7,
2292 1,5,73,13,37,28,8,8,1,15,18,20,165,28,1,6,11,8,4,14,7,15,1,3,3,6,4,1,7,14,1,1,11,30,1,5,1,4,14,1,4,2,7,52,2,6,29,3,1,9,1,21,3,5,1,26,3,11,14,
2293 11,1,17,5,1,2,1,3,2,8,1,2,9,12,1,1,2,3,8,3,24,12,7,7,5,17,3,3,3,1,23,10,4,4,6,3,1,16,17,22,3,10,21,16,16,6,4,10,2,1,1,2,8,8,6,5,3,3,3,39,25,
2294 15,1,1,16,6,7,25,15,6,6,12,1,22,13,1,4,9,5,12,2,9,1,12,28,8,3,5,10,22,60,1,2,40,4,61,63,4,1,13,12,1,4,31,12,1,14,89,5,16,6,29,14,2,5,49,18,18,
2295 5,29,33,47,1,17,1,19,12,2,9,7,39,12,3,7,12,39,3,1,46,4,12,3,8,9,5,31,15,18,3,2,2,66,19,13,17,5,3,46,124,13,57,34,2,5,4,5,8,1,1,1,4,3,1,17,5,
2296 3,5,3,1,8,5,6,3,27,3,26,7,12,7,2,17,3,7,18,78,16,4,36,1,2,1,6,2,1,39,17,7,4,13,4,4,4,1,10,4,2,4,6,3,10,1,19,1,26,2,4,33,2,73,47,7,3,8,2,4,15,
2297 18,1,29,2,41,14,1,21,16,41,7,39,25,13,44,2,2,10,1,13,7,1,7,3,5,20,4,8,2,49,1,10,6,1,6,7,10,7,11,16,3,12,20,4,10,3,1,2,11,2,28,9,2,4,7,2,15,1,
2298 27,1,28,17,4,5,10,7,3,24,10,11,6,26,3,2,7,2,2,49,16,10,16,15,4,5,27,61,30,14,38,22,2,7,5,1,3,12,23,24,17,17,3,3,2,4,1,6,2,7,5,1,1,5,1,1,9,4,
2299 1,3,6,1,8,2,8,4,14,3,5,11,4,1,3,32,1,19,4,1,13,11,5,2,1,8,6,8,1,6,5,13,3,23,11,5,3,16,3,9,10,1,24,3,198,52,4,2,2,5,14,5,4,22,5,20,4,11,6,41,
2300 1,5,2,2,11,5,2,28,35,8,22,3,18,3,10,7,5,3,4,1,5,3,8,9,3,6,2,16,22,4,5,5,3,3,18,23,2,6,23,5,27,8,1,33,2,12,43,16,5,2,3,6,1,20,4,2,9,7,1,11,2,
2301 10,3,14,31,9,3,25,18,20,2,5,5,26,14,1,11,17,12,40,19,9,6,31,83,2,7,9,19,78,12,14,21,76,12,113,79,34,4,1,1,61,18,85,10,2,2,13,31,11,50,6,33,159,
2302 179,6,6,7,4,4,2,4,2,5,8,7,20,32,22,1,3,10,6,7,28,5,10,9,2,77,19,13,2,5,1,4,4,7,4,13,3,9,31,17,3,26,2,6,6,5,4,1,7,11,3,4,2,1,6,2,20,4,1,9,2,6,
2303 3,7,1,1,1,20,2,3,1,6,2,3,6,2,4,8,1,5,13,8,4,11,23,1,10,6,2,1,3,21,2,2,4,24,31,4,10,10,2,5,192,15,4,16,7,9,51,1,2,1,1,5,1,1,2,1,3,5,3,1,3,4,1,
2304 3,1,3,3,9,8,1,2,2,2,4,4,18,12,92,2,10,4,3,14,5,25,16,42,4,14,4,2,21,5,126,30,31,2,1,5,13,3,22,5,6,6,20,12,1,14,12,87,3,19,1,8,2,9,9,3,3,23,2,
2305 3,7,6,3,1,2,3,9,1,3,1,6,3,2,1,3,11,3,1,6,10,3,2,3,1,2,1,5,1,1,11,3,6,4,1,7,2,1,2,5,5,34,4,14,18,4,19,7,5,8,2,6,79,1,5,2,14,8,2,9,2,1,36,28,16,
2306 4,1,1,1,2,12,6,42,39,16,23,7,15,15,3,2,12,7,21,64,6,9,28,8,12,3,3,41,59,24,51,55,57,294,9,9,2,6,2,15,1,2,13,38,90,9,9,9,3,11,7,1,1,1,5,6,3,2,
2307 1,2,2,3,8,1,4,4,1,5,7,1,4,3,20,4,9,1,1,1,5,5,17,1,5,2,6,2,4,1,4,5,7,3,18,11,11,32,7,5,4,7,11,127,8,4,3,3,1,10,1,1,6,21,14,1,16,1,7,1,3,6,9,65,
2308 51,4,3,13,3,10,1,1,12,9,21,110,3,19,24,1,1,10,62,4,1,29,42,78,28,20,18,82,6,3,15,6,84,58,253,15,155,264,15,21,9,14,7,58,40,39,
2310 static ImWchar base_ranges
[] = // not zero-terminated
2312 0x0020, 0x00FF, // Basic Latin + Latin Supplement
2313 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
2314 0x31F0, 0x31FF, // Katakana Phonetic Extensions
2315 0xFF00, 0xFFEF // Half-width characters
2317 static ImWchar full_ranges
[IM_ARRAYSIZE(base_ranges
) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00
)*2 + 1] = { 0 };
2318 if (!full_ranges
[0])
2320 memcpy(full_ranges
, base_ranges
, sizeof(base_ranges
));
2321 UnpackAccumulativeOffsetsIntoRanges(0x4E00, accumulative_offsets_from_0x4E00
, IM_ARRAYSIZE(accumulative_offsets_from_0x4E00
), full_ranges
+ IM_ARRAYSIZE(base_ranges
));
2323 return &full_ranges
[0];
2326 const ImWchar
* ImFontAtlas::GetGlyphRangesCyrillic()
2328 static const ImWchar ranges
[] =
2330 0x0020, 0x00FF, // Basic Latin + Latin Supplement
2331 0x0400, 0x052F, // Cyrillic + Cyrillic Supplement
2332 0x2DE0, 0x2DFF, // Cyrillic Extended-A
2333 0xA640, 0xA69F, // Cyrillic Extended-B
2339 const ImWchar
* ImFontAtlas::GetGlyphRangesThai()
2341 static const ImWchar ranges
[] =
2343 0x0020, 0x00FF, // Basic Latin
2344 0x2010, 0x205E, // Punctuations
2345 0x0E00, 0x0E7F, // Thai
2351 //-----------------------------------------------------------------------------
2352 // [SECTION] ImFontGlyphRangesBuilder
2353 //-----------------------------------------------------------------------------
2355 void ImFontGlyphRangesBuilder::AddText(const char* text
, const char* text_end
)
2357 while (text_end
? (text
< text_end
) : *text
)
2360 int c_len
= ImTextCharFromUtf8(&c
, text
, text_end
);
2365 AddChar((ImWchar
)c
);
2369 void ImFontGlyphRangesBuilder::AddRanges(const ImWchar
* ranges
)
2371 for (; ranges
[0]; ranges
+= 2)
2372 for (ImWchar c
= ranges
[0]; c
<= ranges
[1]; c
++)
2376 void ImFontGlyphRangesBuilder::BuildRanges(ImVector
<ImWchar
>* out_ranges
)
2378 for (int n
= 0; n
< 0x10000; n
++)
2381 out_ranges
->push_back((ImWchar
)n
);
2382 while (n
< 0x10000 && GetBit(n
+ 1))
2384 out_ranges
->push_back((ImWchar
)n
);
2386 out_ranges
->push_back(0);
2389 //-----------------------------------------------------------------------------
2391 //-----------------------------------------------------------------------------
2396 FallbackAdvanceX
= 0.0f
;
2397 FallbackChar
= (ImWchar
)'?';
2398 DisplayOffset
= ImVec2(0.0f
, 0.0f
);
2399 FallbackGlyph
= NULL
;
2400 ContainerAtlas
= NULL
;
2402 ConfigDataCount
= 0;
2403 DirtyLookupTables
= false;
2405 Ascent
= Descent
= 0.0f
;
2406 MetricsTotalSurface
= 0;
2414 void ImFont::ClearOutputData()
2417 FallbackAdvanceX
= 0.0f
;
2419 IndexAdvanceX
.clear();
2420 IndexLookup
.clear();
2421 FallbackGlyph
= NULL
;
2422 ContainerAtlas
= NULL
;
2423 DirtyLookupTables
= true;
2424 Ascent
= Descent
= 0.0f
;
2425 MetricsTotalSurface
= 0;
2428 void ImFont::BuildLookupTable()
2430 int max_codepoint
= 0;
2431 for (int i
= 0; i
!= Glyphs
.Size
; i
++)
2432 max_codepoint
= ImMax(max_codepoint
, (int)Glyphs
[i
].Codepoint
);
2434 IM_ASSERT(Glyphs
.Size
< 0xFFFF); // -1 is reserved
2435 IndexAdvanceX
.clear();
2436 IndexLookup
.clear();
2437 DirtyLookupTables
= false;
2438 GrowIndex(max_codepoint
+ 1);
2439 for (int i
= 0; i
< Glyphs
.Size
; i
++)
2441 int codepoint
= (int)Glyphs
[i
].Codepoint
;
2442 IndexAdvanceX
[codepoint
] = Glyphs
[i
].AdvanceX
;
2443 IndexLookup
[codepoint
] = (ImWchar
)i
;
2446 // Create a glyph to handle TAB
2447 // FIXME: Needs proper TAB handling but it needs to be contextualized (or we could arbitrary say that each string starts at "column 0" ?)
2448 if (FindGlyph((ImWchar
)' '))
2450 if (Glyphs
.back().Codepoint
!= '\t') // So we can call this function multiple times
2451 Glyphs
.resize(Glyphs
.Size
+ 1);
2452 ImFontGlyph
& tab_glyph
= Glyphs
.back();
2453 tab_glyph
= *FindGlyph((ImWchar
)' ');
2454 tab_glyph
.Codepoint
= '\t';
2455 tab_glyph
.AdvanceX
*= 4;
2456 IndexAdvanceX
[(int)tab_glyph
.Codepoint
] = (float)tab_glyph
.AdvanceX
;
2457 IndexLookup
[(int)tab_glyph
.Codepoint
] = (ImWchar
)(Glyphs
.Size
-1);
2460 FallbackGlyph
= FindGlyphNoFallback(FallbackChar
);
2461 FallbackAdvanceX
= FallbackGlyph
? FallbackGlyph
->AdvanceX
: 0.0f
;
2462 for (int i
= 0; i
< max_codepoint
+ 1; i
++)
2463 if (IndexAdvanceX
[i
] < 0.0f
)
2464 IndexAdvanceX
[i
] = FallbackAdvanceX
;
2467 void ImFont::SetFallbackChar(ImWchar c
)
2473 void ImFont::GrowIndex(int new_size
)
2475 IM_ASSERT(IndexAdvanceX
.Size
== IndexLookup
.Size
);
2476 if (new_size
<= IndexLookup
.Size
)
2478 IndexAdvanceX
.resize(new_size
, -1.0f
);
2479 IndexLookup
.resize(new_size
, (ImWchar
)-1);
2482 // x0/y0/x1/y1 are offset from the character upper-left layout position, in pixels. Therefore x0/y0 are often fairly close to zero.
2483 // Not to be mistaken with texture coordinates, which are held by u0/v0/u1/v1 in normalized format (0.0..1.0 on each texture axis).
2484 void ImFont::AddGlyph(ImWchar codepoint
, float x0
, float y0
, float x1
, float y1
, float u0
, float v0
, float u1
, float v1
, float advance_x
)
2486 Glyphs
.resize(Glyphs
.Size
+ 1);
2487 ImFontGlyph
& glyph
= Glyphs
.back();
2488 glyph
.Codepoint
= (ImWchar
)codepoint
;
2497 glyph
.AdvanceX
= advance_x
+ ConfigData
->GlyphExtraSpacing
.x
; // Bake spacing into AdvanceX
2499 if (ConfigData
->PixelSnapH
)
2500 glyph
.AdvanceX
= (float)(int)(glyph
.AdvanceX
+ 0.5f
);
2502 // Compute rough surface usage metrics (+1 to account for average padding, +0.99 to round)
2503 DirtyLookupTables
= true;
2504 MetricsTotalSurface
+= (int)((glyph
.U1
- glyph
.U0
) * ContainerAtlas
->TexWidth
+ 1.99f
) * (int)((glyph
.V1
- glyph
.V0
) * ContainerAtlas
->TexHeight
+ 1.99f
);
2507 void ImFont::AddRemapChar(ImWchar dst
, ImWchar src
, bool overwrite_dst
)
2509 IM_ASSERT(IndexLookup
.Size
> 0); // Currently this can only be called AFTER the font has been built, aka after calling ImFontAtlas::GetTexDataAs*() function.
2510 int index_size
= IndexLookup
.Size
;
2512 if (dst
< index_size
&& IndexLookup
.Data
[dst
] == (ImWchar
)-1 && !overwrite_dst
) // 'dst' already exists
2514 if (src
>= index_size
&& dst
>= index_size
) // both 'dst' and 'src' don't exist -> no-op
2518 IndexLookup
[dst
] = (src
< index_size
) ? IndexLookup
.Data
[src
] : (ImWchar
)-1;
2519 IndexAdvanceX
[dst
] = (src
< index_size
) ? IndexAdvanceX
.Data
[src
] : 1.0f
;
2522 const ImFontGlyph
* ImFont::FindGlyph(ImWchar c
) const
2524 if (c
>= IndexLookup
.Size
)
2525 return FallbackGlyph
;
2526 const ImWchar i
= IndexLookup
.Data
[c
];
2527 if (i
== (ImWchar
)-1)
2528 return FallbackGlyph
;
2529 return &Glyphs
.Data
[i
];
2532 const ImFontGlyph
* ImFont::FindGlyphNoFallback(ImWchar c
) const
2534 if (c
>= IndexLookup
.Size
)
2536 const ImWchar i
= IndexLookup
.Data
[c
];
2537 if (i
== (ImWchar
)-1)
2539 return &Glyphs
.Data
[i
];
2542 const char* ImFont::CalcWordWrapPositionA(float scale
, const char* text
, const char* text_end
, float wrap_width
) const
2544 // Simple word-wrapping for English, not full-featured. Please submit failing cases!
2545 // 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.)
2547 // For references, possible wrap point marked with ^
2548 // "aaa bbb, ccc,ddd. eee fff. ggg!"
2551 // List of hardcoded separators: .,;!?'"
2553 // Skip extra blanks after a line returns (that includes not counting them in width computation)
2554 // e.g. "Hello world" --> "Hello" "World"
2556 // Cut words that cannot possibly fit within one line.
2557 // e.g.: "The tropical fish" with ~5 characters worth of width --> "The tr" "opical" "fish"
2559 float line_width
= 0.0f
;
2560 float word_width
= 0.0f
;
2561 float blank_width
= 0.0f
;
2562 wrap_width
/= scale
; // We work with unscaled widths to avoid scaling every characters
2564 const char* word_end
= text
;
2565 const char* prev_word_end
= NULL
;
2566 bool inside_word
= true;
2568 const char* s
= text
;
2569 while (s
< text_end
)
2571 unsigned int c
= (unsigned int)*s
;
2576 next_s
= s
+ ImTextCharFromUtf8(&c
, s
, text_end
);
2584 line_width
= word_width
= blank_width
= 0.0f
;
2596 const float char_width
= ((int)c
< IndexAdvanceX
.Size
? IndexAdvanceX
.Data
[c
] : FallbackAdvanceX
);
2597 if (ImCharIsBlankW(c
))
2601 line_width
+= blank_width
;
2605 blank_width
+= char_width
;
2606 inside_word
= false;
2610 word_width
+= char_width
;
2617 prev_word_end
= word_end
;
2618 line_width
+= word_width
+ blank_width
;
2619 word_width
= blank_width
= 0.0f
;
2622 // Allow wrapping after punctuation.
2623 inside_word
= !(c
== '.' || c
== ',' || c
== ';' || c
== '!' || c
== '?' || c
== '\"');
2626 // We ignore blank width at the end of the line (they can be skipped)
2627 if (line_width
+ word_width
>= wrap_width
)
2629 // Words that cannot possibly fit within an entire line will be cut anywhere.
2630 if (word_width
< wrap_width
)
2631 s
= prev_word_end
? prev_word_end
: word_end
;
2641 ImVec2
ImFont::CalcTextSizeA(float size
, float max_width
, float wrap_width
, const char* text_begin
, const char* text_end
, const char** remaining
) const
2644 text_end
= text_begin
+ strlen(text_begin
); // FIXME-OPT: Need to avoid this.
2646 const float line_height
= size
;
2647 const float scale
= size
/ FontSize
;
2649 ImVec2 text_size
= ImVec2(0,0);
2650 float line_width
= 0.0f
;
2652 const bool word_wrap_enabled
= (wrap_width
> 0.0f
);
2653 const char* word_wrap_eol
= NULL
;
2655 const char* s
= text_begin
;
2656 while (s
< text_end
)
2658 if (word_wrap_enabled
)
2660 // 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.
2663 word_wrap_eol
= CalcWordWrapPositionA(scale
, s
, text_end
, wrap_width
- line_width
);
2664 if (word_wrap_eol
== s
) // Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity.
2665 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
2668 if (s
>= word_wrap_eol
)
2670 if (text_size
.x
< line_width
)
2671 text_size
.x
= line_width
;
2672 text_size
.y
+= line_height
;
2674 word_wrap_eol
= NULL
;
2676 // Wrapping skips upcoming blanks
2677 while (s
< text_end
)
2680 if (ImCharIsBlankA(c
)) { s
++; } else if (c
== '\n') { s
++; break; } else { break; }
2686 // Decode and advance source
2687 const char* prev_s
= s
;
2688 unsigned int c
= (unsigned int)*s
;
2695 s
+= ImTextCharFromUtf8(&c
, s
, text_end
);
2696 if (c
== 0) // Malformed UTF-8?
2704 text_size
.x
= ImMax(text_size
.x
, line_width
);
2705 text_size
.y
+= line_height
;
2713 const float char_width
= ((int)c
< IndexAdvanceX
.Size
? IndexAdvanceX
.Data
[c
] : FallbackAdvanceX
) * scale
;
2714 if (line_width
+ char_width
>= max_width
)
2720 line_width
+= char_width
;
2723 if (text_size
.x
< line_width
)
2724 text_size
.x
= line_width
;
2726 if (line_width
> 0 || text_size
.y
== 0.0f
)
2727 text_size
.y
+= line_height
;
2735 void ImFont::RenderChar(ImDrawList
* draw_list
, float size
, ImVec2 pos
, ImU32 col
, ImWchar c
) const
2737 if (c
== ' ' || c
== '\t' || c
== '\n' || c
== '\r') // Match behavior of RenderText(), those 4 codepoints are hard-coded.
2739 if (const ImFontGlyph
* glyph
= FindGlyph(c
))
2741 float scale
= (size
>= 0.0f
) ? (size
/ FontSize
) : 1.0f
;
2742 pos
.x
= (float)(int)pos
.x
+ DisplayOffset
.x
;
2743 pos
.y
= (float)(int)pos
.y
+ DisplayOffset
.y
;
2744 draw_list
->PrimReserve(6, 4);
2745 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
);
2749 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
2752 text_end
= text_begin
+ strlen(text_begin
); // ImGui functions generally already provides a valid text_end, so this is merely to handle direct calls.
2754 // Align to be pixel perfect
2755 pos
.x
= (float)(int)pos
.x
+ DisplayOffset
.x
;
2756 pos
.y
= (float)(int)pos
.y
+ DisplayOffset
.y
;
2759 if (y
> clip_rect
.w
)
2762 const float scale
= size
/ FontSize
;
2763 const float line_height
= FontSize
* scale
;
2764 const bool word_wrap_enabled
= (wrap_width
> 0.0f
);
2765 const char* word_wrap_eol
= NULL
;
2767 // Fast-forward to first visible line
2768 const char* s
= text_begin
;
2769 if (y
+ line_height
< clip_rect
.y
&& !word_wrap_enabled
)
2770 while (y
+ line_height
< clip_rect
.y
&& s
< text_end
)
2772 s
= (const char*)memchr(s
, '\n', text_end
- s
);
2773 s
= s
? s
+ 1 : text_end
;
2777 // For large text, scan for the last visible line in order to avoid over-reserving in the call to PrimReserve()
2778 // Note that very large horizontal line will still be affected by the issue (e.g. a one megabyte string buffer without a newline will likely crash atm)
2779 if (text_end
- s
> 10000 && !word_wrap_enabled
)
2781 const char* s_end
= s
;
2783 while (y_end
< clip_rect
.w
&& s_end
< text_end
)
2785 s_end
= (const char*)memchr(s_end
, '\n', text_end
- s_end
);
2786 s_end
= s_end
? s_end
+ 1 : text_end
;
2787 y_end
+= line_height
;
2794 // Reserve vertices for remaining worse case (over-reserving is useful and easily amortized)
2795 const int vtx_count_max
= (int)(text_end
- s
) * 4;
2796 const int idx_count_max
= (int)(text_end
- s
) * 6;
2797 const int idx_expected_size
= draw_list
->IdxBuffer
.Size
+ idx_count_max
;
2798 draw_list
->PrimReserve(idx_count_max
, vtx_count_max
);
2800 ImDrawVert
* vtx_write
= draw_list
->_VtxWritePtr
;
2801 ImDrawIdx
* idx_write
= draw_list
->_IdxWritePtr
;
2802 unsigned int vtx_current_idx
= draw_list
->_VtxCurrentIdx
;
2804 while (s
< text_end
)
2806 if (word_wrap_enabled
)
2808 // 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.
2811 word_wrap_eol
= CalcWordWrapPositionA(scale
, s
, text_end
, wrap_width
- (x
- pos
.x
));
2812 if (word_wrap_eol
== s
) // Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity.
2813 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
2816 if (s
>= word_wrap_eol
)
2820 word_wrap_eol
= NULL
;
2822 // Wrapping skips upcoming blanks
2823 while (s
< text_end
)
2826 if (ImCharIsBlankA(c
)) { s
++; } else if (c
== '\n') { s
++; break; } else { break; }
2832 // Decode and advance source
2833 unsigned int c
= (unsigned int)*s
;
2840 s
+= ImTextCharFromUtf8(&c
, s
, text_end
);
2841 if (c
== 0) // Malformed UTF-8?
2851 if (y
> clip_rect
.w
)
2852 break; // break out of main loop
2859 float char_width
= 0.0f
;
2860 if (const ImFontGlyph
* glyph
= FindGlyph((ImWchar
)c
))
2862 char_width
= glyph
->AdvanceX
* scale
;
2864 // Arbitrarily assume that both space and tabs are empty glyphs as an optimization
2865 if (c
!= ' ' && c
!= '\t')
2867 // 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
2868 float x1
= x
+ glyph
->X0
* scale
;
2869 float x2
= x
+ glyph
->X1
* scale
;
2870 float y1
= y
+ glyph
->Y0
* scale
;
2871 float y2
= y
+ glyph
->Y1
* scale
;
2872 if (x1
<= clip_rect
.z
&& x2
>= clip_rect
.x
)
2874 // Render a character
2875 float u1
= glyph
->U0
;
2876 float v1
= glyph
->V0
;
2877 float u2
= glyph
->U1
;
2878 float v2
= glyph
->V1
;
2880 // CPU side clipping used to fit text in their frame when the frame is too small. Only does clipping for axis aligned quads.
2883 if (x1
< clip_rect
.x
)
2885 u1
= u1
+ (1.0f
- (x2
- clip_rect
.x
) / (x2
- x1
)) * (u2
- u1
);
2888 if (y1
< clip_rect
.y
)
2890 v1
= v1
+ (1.0f
- (y2
- clip_rect
.y
) / (y2
- y1
)) * (v2
- v1
);
2893 if (x2
> clip_rect
.z
)
2895 u2
= u1
+ ((clip_rect
.z
- x1
) / (x2
- x1
)) * (u2
- u1
);
2898 if (y2
> clip_rect
.w
)
2900 v2
= v1
+ ((clip_rect
.w
- y1
) / (y2
- y1
)) * (v2
- v1
);
2910 // We are NOT calling PrimRectUV() here because non-inlined causes too much overhead in a debug builds. Inlined here:
2912 idx_write
[0] = (ImDrawIdx
)(vtx_current_idx
); idx_write
[1] = (ImDrawIdx
)(vtx_current_idx
+1); idx_write
[2] = (ImDrawIdx
)(vtx_current_idx
+2);
2913 idx_write
[3] = (ImDrawIdx
)(vtx_current_idx
); idx_write
[4] = (ImDrawIdx
)(vtx_current_idx
+2); idx_write
[5] = (ImDrawIdx
)(vtx_current_idx
+3);
2914 vtx_write
[0].pos
.x
= x1
; vtx_write
[0].pos
.y
= y1
; vtx_write
[0].col
= col
; vtx_write
[0].uv
.x
= u1
; vtx_write
[0].uv
.y
= v1
;
2915 vtx_write
[1].pos
.x
= x2
; vtx_write
[1].pos
.y
= y1
; vtx_write
[1].col
= col
; vtx_write
[1].uv
.x
= u2
; vtx_write
[1].uv
.y
= v1
;
2916 vtx_write
[2].pos
.x
= x2
; vtx_write
[2].pos
.y
= y2
; vtx_write
[2].col
= col
; vtx_write
[2].uv
.x
= u2
; vtx_write
[2].uv
.y
= v2
;
2917 vtx_write
[3].pos
.x
= x1
; vtx_write
[3].pos
.y
= y2
; vtx_write
[3].col
= col
; vtx_write
[3].uv
.x
= u1
; vtx_write
[3].uv
.y
= v2
;
2919 vtx_current_idx
+= 4;
2929 // Give back unused vertices
2930 draw_list
->VtxBuffer
.resize((int)(vtx_write
- draw_list
->VtxBuffer
.Data
));
2931 draw_list
->IdxBuffer
.resize((int)(idx_write
- draw_list
->IdxBuffer
.Data
));
2932 draw_list
->CmdBuffer
[draw_list
->CmdBuffer
.Size
-1].ElemCount
-= (idx_expected_size
- draw_list
->IdxBuffer
.Size
);
2933 draw_list
->_VtxWritePtr
= vtx_write
;
2934 draw_list
->_IdxWritePtr
= idx_write
;
2935 draw_list
->_VtxCurrentIdx
= (unsigned int)draw_list
->VtxBuffer
.Size
;
2938 //-----------------------------------------------------------------------------
2939 // [SECTION] Internal Render Helpers
2940 // (progressively moved from imgui.cpp to here when they are redesigned to stop accessing ImGui global state)
2941 //-----------------------------------------------------------------------------
2942 // - RenderMouseCursor()
2943 // - RenderArrowPointingAt()
2944 // - RenderRectFilledRangeH()
2945 // - RenderPixelEllipsis()
2946 //-----------------------------------------------------------------------------
2948 void ImGui::RenderMouseCursor(ImDrawList
* draw_list
, ImVec2 pos
, float scale
, ImGuiMouseCursor mouse_cursor
)
2950 if (mouse_cursor
== ImGuiMouseCursor_None
)
2952 IM_ASSERT(mouse_cursor
> ImGuiMouseCursor_None
&& mouse_cursor
< ImGuiMouseCursor_COUNT
);
2954 const ImU32 col_shadow
= IM_COL32(0, 0, 0, 48);
2955 const ImU32 col_border
= IM_COL32(0, 0, 0, 255); // Black
2956 const ImU32 col_fill
= IM_COL32(255, 255, 255, 255); // White
2958 ImFontAtlas
* font_atlas
= draw_list
->_Data
->Font
->ContainerAtlas
;
2959 ImVec2 offset
, size
, uv
[4];
2960 if (font_atlas
->GetMouseCursorTexData(mouse_cursor
, &offset
, &size
, &uv
[0], &uv
[2]))
2963 const ImTextureID tex_id
= font_atlas
->TexID
;
2964 draw_list
->PushTextureID(tex_id
);
2965 draw_list
->AddImage(tex_id
, pos
+ ImVec2(1,0)*scale
, pos
+ ImVec2(1,0)*scale
+ size
*scale
, uv
[2], uv
[3], col_shadow
);
2966 draw_list
->AddImage(tex_id
, pos
+ ImVec2(2,0)*scale
, pos
+ ImVec2(2,0)*scale
+ size
*scale
, uv
[2], uv
[3], col_shadow
);
2967 draw_list
->AddImage(tex_id
, pos
, pos
+ size
*scale
, uv
[2], uv
[3], col_border
);
2968 draw_list
->AddImage(tex_id
, pos
, pos
+ size
*scale
, uv
[0], uv
[1], col_fill
);
2969 draw_list
->PopTextureID();
2973 // Render an arrow. 'pos' is position of the arrow tip. half_sz.x is length from base to tip. half_sz.y is length on each side.
2974 void ImGui::RenderArrowPointingAt(ImDrawList
* draw_list
, ImVec2 pos
, ImVec2 half_sz
, ImGuiDir direction
, ImU32 col
)
2978 case ImGuiDir_Left
: draw_list
->AddTriangleFilled(ImVec2(pos
.x
+ half_sz
.x
, pos
.y
- half_sz
.y
), ImVec2(pos
.x
+ half_sz
.x
, pos
.y
+ half_sz
.y
), pos
, col
); return;
2979 case ImGuiDir_Right
: draw_list
->AddTriangleFilled(ImVec2(pos
.x
- half_sz
.x
, pos
.y
+ half_sz
.y
), ImVec2(pos
.x
- half_sz
.x
, pos
.y
- half_sz
.y
), pos
, col
); return;
2980 case ImGuiDir_Up
: draw_list
->AddTriangleFilled(ImVec2(pos
.x
+ half_sz
.x
, pos
.y
+ half_sz
.y
), ImVec2(pos
.x
- half_sz
.x
, pos
.y
+ half_sz
.y
), pos
, col
); return;
2981 case ImGuiDir_Down
: draw_list
->AddTriangleFilled(ImVec2(pos
.x
- half_sz
.x
, pos
.y
- half_sz
.y
), ImVec2(pos
.x
+ half_sz
.x
, pos
.y
- half_sz
.y
), pos
, col
); return;
2982 case ImGuiDir_None
: case ImGuiDir_COUNT
: break; // Fix warnings
2986 static inline float ImAcos01(float x
)
2988 if (x
<= 0.0f
) return IM_PI
* 0.5f
;
2989 if (x
>= 1.0f
) return 0.0f
;
2991 //return (-0.69813170079773212f * x * x - 0.87266462599716477f) * x + 1.5707963267948966f; // Cheap approximation, may be enough for what we do.
2994 // FIXME: Cleanup and move code to ImDrawList.
2995 void ImGui::RenderRectFilledRangeH(ImDrawList
* draw_list
, const ImRect
& rect
, ImU32 col
, float x_start_norm
, float x_end_norm
, float rounding
)
2997 if (x_end_norm
== x_start_norm
)
2999 if (x_start_norm
> x_end_norm
)
3000 ImSwap(x_start_norm
, x_end_norm
);
3002 ImVec2 p0
= ImVec2(ImLerp(rect
.Min
.x
, rect
.Max
.x
, x_start_norm
), rect
.Min
.y
);
3003 ImVec2 p1
= ImVec2(ImLerp(rect
.Min
.x
, rect
.Max
.x
, x_end_norm
), rect
.Max
.y
);
3004 if (rounding
== 0.0f
)
3006 draw_list
->AddRectFilled(p0
, p1
, col
, 0.0f
);
3010 rounding
= ImClamp(ImMin((rect
.Max
.x
- rect
.Min
.x
) * 0.5f
, (rect
.Max
.y
- rect
.Min
.y
) * 0.5f
) - 1.0f
, 0.0f
, rounding
);
3011 const float inv_rounding
= 1.0f
/ rounding
;
3012 const float arc0_b
= ImAcos01(1.0f
- (p0
.x
- rect
.Min
.x
) * inv_rounding
);
3013 const float arc0_e
= ImAcos01(1.0f
- (p1
.x
- rect
.Min
.x
) * inv_rounding
);
3014 const float half_pi
= IM_PI
* 0.5f
; // We will == compare to this because we know this is the exact value ImAcos01 can return.
3015 const float x0
= ImMax(p0
.x
, rect
.Min
.x
+ rounding
);
3016 if (arc0_b
== arc0_e
)
3018 draw_list
->PathLineTo(ImVec2(x0
, p1
.y
));
3019 draw_list
->PathLineTo(ImVec2(x0
, p0
.y
));
3021 else if (arc0_b
== 0.0f
&& arc0_e
== half_pi
)
3023 draw_list
->PathArcToFast(ImVec2(x0
, p1
.y
- rounding
), rounding
, 3, 6); // BL
3024 draw_list
->PathArcToFast(ImVec2(x0
, p0
.y
+ rounding
), rounding
, 6, 9); // TR
3028 draw_list
->PathArcTo(ImVec2(x0
, p1
.y
- rounding
), rounding
, IM_PI
- arc0_e
, IM_PI
- arc0_b
, 3); // BL
3029 draw_list
->PathArcTo(ImVec2(x0
, p0
.y
+ rounding
), rounding
, IM_PI
+ arc0_b
, IM_PI
+ arc0_e
, 3); // TR
3031 if (p1
.x
> rect
.Min
.x
+ rounding
)
3033 const float arc1_b
= ImAcos01(1.0f
- (rect
.Max
.x
- p1
.x
) * inv_rounding
);
3034 const float arc1_e
= ImAcos01(1.0f
- (rect
.Max
.x
- p0
.x
) * inv_rounding
);
3035 const float x1
= ImMin(p1
.x
, rect
.Max
.x
- rounding
);
3036 if (arc1_b
== arc1_e
)
3038 draw_list
->PathLineTo(ImVec2(x1
, p0
.y
));
3039 draw_list
->PathLineTo(ImVec2(x1
, p1
.y
));
3041 else if (arc1_b
== 0.0f
&& arc1_e
== half_pi
)
3043 draw_list
->PathArcToFast(ImVec2(x1
, p0
.y
+ rounding
), rounding
, 9, 12); // TR
3044 draw_list
->PathArcToFast(ImVec2(x1
, p1
.y
- rounding
), rounding
, 0, 3); // BR
3048 draw_list
->PathArcTo(ImVec2(x1
, p0
.y
+ rounding
), rounding
, -arc1_e
, -arc1_b
, 3); // TR
3049 draw_list
->PathArcTo(ImVec2(x1
, p1
.y
- rounding
), rounding
, +arc1_b
, +arc1_e
, 3); // BR
3052 draw_list
->PathFillConvex(col
);
3055 // FIXME: Rendering an ellipsis "..." is a surprisingly tricky problem for us... we cannot rely on font glyph having it,
3056 // and regular dot are typically too wide. If we render a dot/shape ourselves it comes with the risk that it wouldn't match
3057 // the boldness or positioning of what the font uses...
3058 void ImGui::RenderPixelEllipsis(ImDrawList
* draw_list
, ImVec2 pos
, int count
, ImU32 col
)
3060 ImFont
* font
= draw_list
->_Data
->Font
;
3061 const float font_scale
= draw_list
->_Data
->FontSize
/ font
->FontSize
;
3062 pos
.y
+= (float)(int)(font
->DisplayOffset
.y
+ font
->Ascent
* font_scale
+ 0.5f
- 1.0f
);
3063 for (int dot_n
= 0; dot_n
< count
; dot_n
++)
3064 draw_list
->AddRectFilled(ImVec2(pos
.x
+ dot_n
* 2.0f
, pos
.y
), ImVec2(pos
.x
+ dot_n
* 2.0f
+ 1.0f
, pos
.y
+ 1.0f
), col
);
3067 //-----------------------------------------------------------------------------
3068 // [SECTION] Decompression code
3069 //-----------------------------------------------------------------------------
3070 // Compressed with stb_compress() then converted to a C array and encoded as base85.
3071 // Use the program in misc/fonts/binary_to_compressed_c.cpp to create the array from a TTF file.
3072 // The purpose of encoding as base85 instead of "0x00,0x01,..." style is only save on _source code_ size.
3073 // Decompression from stb.h (public domain) by Sean Barrett https://github.com/nothings/stb/blob/master/stb.h
3074 //-----------------------------------------------------------------------------
3076 static unsigned int stb_decompress_length(const unsigned char *input
)
3078 return (input
[8] << 24) + (input
[9] << 16) + (input
[10] << 8) + input
[11];
3081 static unsigned char *stb__barrier_out_e
, *stb__barrier_out_b
;
3082 static const unsigned char *stb__barrier_in_b
;
3083 static unsigned char *stb__dout
;
3084 static void stb__match(const unsigned char *data
, unsigned int length
)
3086 // INVERSE of memmove... write each byte before copying the next...
3087 IM_ASSERT(stb__dout
+ length
<= stb__barrier_out_e
);
3088 if (stb__dout
+ length
> stb__barrier_out_e
) { stb__dout
+= length
; return; }
3089 if (data
< stb__barrier_out_b
) { stb__dout
= stb__barrier_out_e
+1; return; }
3090 while (length
--) *stb__dout
++ = *data
++;
3093 static void stb__lit(const unsigned char *data
, unsigned int length
)
3095 IM_ASSERT(stb__dout
+ length
<= stb__barrier_out_e
);
3096 if (stb__dout
+ length
> stb__barrier_out_e
) { stb__dout
+= length
; return; }
3097 if (data
< stb__barrier_in_b
) { stb__dout
= stb__barrier_out_e
+1; return; }
3098 memcpy(stb__dout
, data
, length
);
3099 stb__dout
+= length
;
3102 #define stb__in2(x) ((i[x] << 8) + i[(x)+1])
3103 #define stb__in3(x) ((i[x] << 16) + stb__in2((x)+1))
3104 #define stb__in4(x) ((i[x] << 24) + stb__in3((x)+1))
3106 static const unsigned char *stb_decompress_token(const unsigned char *i
)
3108 if (*i
>= 0x20) { // use fewer if's for cases that expand small
3109 if (*i
>= 0x80) stb__match(stb__dout
-i
[1]-1, i
[0] - 0x80 + 1), i
+= 2;
3110 else if (*i
>= 0x40) stb__match(stb__dout
-(stb__in2(0) - 0x4000 + 1), i
[2]+1), i
+= 3;
3111 else /* *i >= 0x20 */ stb__lit(i
+1, i
[0] - 0x20 + 1), i
+= 1 + (i
[0] - 0x20 + 1);
3112 } else { // more ifs for cases that expand large, since overhead is amortized
3113 if (*i
>= 0x18) stb__match(stb__dout
-(stb__in3(0) - 0x180000 + 1), i
[3]+1), i
+= 4;
3114 else if (*i
>= 0x10) stb__match(stb__dout
-(stb__in3(0) - 0x100000 + 1), stb__in2(3)+1), i
+= 5;
3115 else if (*i
>= 0x08) stb__lit(i
+2, stb__in2(0) - 0x0800 + 1), i
+= 2 + (stb__in2(0) - 0x0800 + 1);
3116 else if (*i
== 0x07) stb__lit(i
+3, stb__in2(1) + 1), i
+= 3 + (stb__in2(1) + 1);
3117 else if (*i
== 0x06) stb__match(stb__dout
-(stb__in3(1)+1), i
[4]+1), i
+= 5;
3118 else if (*i
== 0x04) stb__match(stb__dout
-(stb__in3(1)+1), stb__in2(4)+1), i
+= 6;
3123 static unsigned int stb_adler32(unsigned int adler32
, unsigned char *buffer
, unsigned int buflen
)
3125 const unsigned long ADLER_MOD
= 65521;
3126 unsigned long s1
= adler32
& 0xffff, s2
= adler32
>> 16;
3127 unsigned long blocklen
, i
;
3129 blocklen
= buflen
% 5552;
3131 for (i
=0; i
+ 7 < blocklen
; i
+= 8) {
3132 s1
+= buffer
[0], s2
+= s1
;
3133 s1
+= buffer
[1], s2
+= s1
;
3134 s1
+= buffer
[2], s2
+= s1
;
3135 s1
+= buffer
[3], s2
+= s1
;
3136 s1
+= buffer
[4], s2
+= s1
;
3137 s1
+= buffer
[5], s2
+= s1
;
3138 s1
+= buffer
[6], s2
+= s1
;
3139 s1
+= buffer
[7], s2
+= s1
;
3144 for (; i
< blocklen
; ++i
)
3145 s1
+= *buffer
++, s2
+= s1
;
3147 s1
%= ADLER_MOD
, s2
%= ADLER_MOD
;
3151 return (unsigned int)(s2
<< 16) + (unsigned int)s1
;
3154 static unsigned int stb_decompress(unsigned char *output
, const unsigned char *i
, unsigned int /*length*/)
3157 if (stb__in4(0) != 0x57bC0000) return 0;
3158 if (stb__in4(4) != 0) return 0; // error! stream is > 4GB
3159 olen
= stb_decompress_length(i
);
3160 stb__barrier_in_b
= i
;
3161 stb__barrier_out_e
= output
+ olen
;
3162 stb__barrier_out_b
= output
;
3167 const unsigned char *old_i
= i
;
3168 i
= stb_decompress_token(i
);
3170 if (*i
== 0x05 && i
[1] == 0xfa) {
3171 IM_ASSERT(stb__dout
== output
+ olen
);
3172 if (stb__dout
!= output
+ olen
) return 0;
3173 if (stb_adler32(1, output
, olen
) != (unsigned int) stb__in4(2))
3177 IM_ASSERT(0); /* NOTREACHED */
3181 IM_ASSERT(stb__dout
<= output
+ olen
);
3182 if (stb__dout
> output
+ olen
)
3187 //-----------------------------------------------------------------------------
3188 // [SECTION] Default font data (ProggyClean.ttf)
3189 //-----------------------------------------------------------------------------
3191 // Copyright (c) 2004, 2005 Tristan Grimmer
3192 // MIT license (see License.txt in http://www.upperbounds.net/download/ProggyClean.ttf.zip)
3193 // Download and more information at http://upperbounds.net
3194 //-----------------------------------------------------------------------------
3195 // File: 'ProggyClean.ttf' (41208 bytes)
3196 // Exported using misc/fonts/binary_to_compressed_c.cpp (with compression + base85 string encoding).
3197 // The purpose of encoding as base85 instead of "0x00,0x01,..." style is only save on _source code_ size.
3198 //-----------------------------------------------------------------------------
3199 static const char proggy_clean_ttf_compressed_data_base85
[11980+1] =
3200 "7])#######hV0qs'/###[),##/l:$#Q6>##5[n42>c-TH`->>#/e>11NNV=Bv(*:.F?uu#(gRU.o0XGH`$vhLG1hxt9?W`#,5LsCp#-i>.r$<$6pD>Lb';9Crc6tgXmKVeU2cD4Eo3R/"
3201 "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#"
3202 "`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"
3203 "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"
3204 "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"
3205 "*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)"
3206 "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"
3207 "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."
3208 "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"
3209 "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(,)"
3210 "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#"
3211 "'/###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"
3212 "_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"
3213 "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/"
3214 "/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"
3215 "%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&#"
3216 "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)("
3217 "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"
3218 "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"
3219 "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^-"
3220 "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-"
3221 "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"
3222 "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%"
3223 "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]"
3224 "%(?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"
3225 "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:"
3226 "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("
3227 "$/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<"
3228 "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'?"
3229 "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/;"
3230 ")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"
3231 "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("
3232 "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"
3233 "bIu)'Z,*[>br5fX^:FPAWr-m2KgL<LUN098kTF&#lvo58=/vjDo;.;)Ka*hLR#/k=rKbxuV`>Q_nN6'8uTGT5g)uLv:873UpTLgH+#FgpH'_o1780Ph8KmxQJ8#H72L4@768@Tm&Q"
3234 "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<-"
3235 "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"
3236 "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"
3237 ".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@@"
3238 "$&)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*"
3239 "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"
3240 "@-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&#"
3241 "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#"
3242 "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"
3243 "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"
3244 "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&#"
3245 "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"
3246 ":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+"
3247 "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*"
3248 "$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"
3249 ":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"
3250 "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"
3251 "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"
3252 "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"
3253 ":^#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@&]>"
3254 "_>@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%"
3255 "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;"
3256 "^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:"
3257 "+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%"
3258 "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-"
3259 "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*"
3260 "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"
3261 "8kD2)2fU/M#$e.)T4,_=8hLim[&);?UkK'-x?'(:siIfL<$pFM`i<?%W(mGDHM%>iWP,##P`%/L<eXi:@Z9C.7o=@(pXdAO/NLQ8lPl+HPOQa8wD8=^GlPa8TKI1CjhsCTSLJM'/Wl>-"
3262 "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`"
3263 "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]%/"
3264 "+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"
3265 "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"
3266 "?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"
3267 "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"
3268 ">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'>"
3269 "[%$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"
3270 "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#"
3271 "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$"
3272 "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,)"
3273 "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"
3274 "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"
3275 "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"
3276 "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(#"
3277 ";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&>"
3278 "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#"
3279 "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"
3280 "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#"
3281 "/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-#"
3282 "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#"
3283 "TmD<#%JSMFove:CTBEXI:<eh2g)B,3h2^G3i;#d3jD>)4kMYD4lVu`4m`:&5niUA5@(A5BA1]PBB:xlBCC=2CDLXMCEUtiCf&0g2'tN?PGT4CPGT4CPGT4CPGT4CPGT4CPGT4CPGT4CP"
3284 "GT4CPGT4CPGT4CPGT4CPGT4CPGT4CP-qekC`.9kEg^+F$kwViFJTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5o,^<-28ZI'O?;xp"
3285 "O?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xp;7q-#lLYI:xvD=#";
3287 static const char* GetDefaultCompressedFontDataTTFBase85()
3289 return proggy_clean_ttf_compressed_data_base85
;