imgui

FORK: Dear ImGui: Bloat-free Graphical User interface for C++ with minimal dependencies
git clone https://git.neptards.moe/neptards/imgui.git
Log | Files | Refs

imgui_draw.cpp (210871B)


      1 // dear imgui, v1.83
      2 // (drawing and font code)
      3 
      4 /*
      5 
      6 Index of this file:
      7 
      8 // [SECTION] STB libraries implementation
      9 // [SECTION] Style functions
     10 // [SECTION] ImDrawList
     11 // [SECTION] ImDrawListSplitter
     12 // [SECTION] ImDrawData
     13 // [SECTION] Helpers ShadeVertsXXX functions
     14 // [SECTION] ImFontConfig
     15 // [SECTION] ImFontAtlas
     16 // [SECTION] ImFontAtlas glyph ranges helpers
     17 // [SECTION] ImFontGlyphRangesBuilder
     18 // [SECTION] ImFont
     19 // [SECTION] ImGui Internal Render Helpers
     20 // [SECTION] Decompression code
     21 // [SECTION] Default font data (ProggyClean.ttf)
     22 
     23 */
     24 
     25 #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
     26 #define _CRT_SECURE_NO_WARNINGS
     27 #endif
     28 
     29 #include "imgui.h"
     30 #ifndef IMGUI_DISABLE
     31 
     32 #ifndef IMGUI_DEFINE_MATH_OPERATORS
     33 #define IMGUI_DEFINE_MATH_OPERATORS
     34 #endif
     35 
     36 #include "imgui_internal.h"
     37 #ifdef IMGUI_ENABLE_FREETYPE
     38 #include "misc/freetype/imgui_freetype.h"
     39 #endif
     40 
     41 #include <stdio.h>      // vsnprintf, sscanf, printf
     42 #if !defined(alloca)
     43 #if defined(__GLIBC__) || defined(__sun) || defined(__APPLE__) || defined(__NEWLIB__)
     44 #include <alloca.h>     // alloca (glibc uses <alloca.h>. Note that Cygwin may have _WIN32 defined, so the order matters here)
     45 #elif defined(_WIN32)
     46 #include <malloc.h>     // alloca
     47 #if !defined(alloca)
     48 #define alloca _alloca  // for clang with MS Codegen
     49 #endif
     50 #else
     51 #include <stdlib.h>     // alloca
     52 #endif
     53 #endif
     54 
     55 // Visual Studio warnings
     56 #ifdef _MSC_VER
     57 #pragma warning (disable: 4127)     // condition expression is constant
     58 #pragma warning (disable: 4505)     // unreferenced local function has been removed (stb stuff)
     59 #pragma warning (disable: 4996)     // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
     60 #pragma warning (disable: 6255)     // [Static Analyzer] _alloca indicates failure by raising a stack overflow exception.  Consider using _malloca instead.
     61 #pragma warning (disable: 26451)    // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2).
     62 #pragma warning (disable: 26812)    // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3). [MSVC Static Analyzer)
     63 #endif
     64 
     65 // Clang/GCC warnings with -Weverything
     66 #if defined(__clang__)
     67 #if __has_warning("-Wunknown-warning-option")
     68 #pragma clang diagnostic ignored "-Wunknown-warning-option"         // warning: unknown warning group 'xxx'                      // not all warnings are known by all Clang versions and they tend to be rename-happy.. so ignoring warnings triggers new warnings on some configuration. Great!
     69 #endif
     70 #if __has_warning("-Walloca")
     71 #pragma clang diagnostic ignored "-Walloca"                         // warning: use of function '__builtin_alloca' is discouraged
     72 #endif
     73 #pragma clang diagnostic ignored "-Wunknown-pragmas"                // warning: unknown warning group 'xxx'
     74 #pragma clang diagnostic ignored "-Wold-style-cast"                 // warning: use of old-style cast                            // yes, they are more terse.
     75 #pragma clang diagnostic ignored "-Wfloat-equal"                    // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants ok.
     76 #pragma clang diagnostic ignored "-Wglobal-constructors"            // warning: declaration requires a global destructor         // similar to above, not sure what the exact difference is.
     77 #pragma clang diagnostic ignored "-Wsign-conversion"                // warning: implicit conversion changes signedness
     78 #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"  // warning: zero as null pointer constant                    // some standard header variations use #define NULL 0
     79 #pragma clang diagnostic ignored "-Wcomma"                          // warning: possible misuse of comma operator here
     80 #pragma clang diagnostic ignored "-Wreserved-id-macro"              // warning: macro name is a reserved identifier
     81 #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.
     82 #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion"  // warning: implicit conversion from 'xxx' to 'float' may lose precision
     83 #elif defined(__GNUC__)
     84 #pragma GCC diagnostic ignored "-Wpragmas"                  // warning: unknown option after '#pragma GCC diagnostic' kind
     85 #pragma GCC diagnostic ignored "-Wunused-function"          // warning: 'xxxx' defined but not used
     86 #pragma GCC diagnostic ignored "-Wdouble-promotion"         // warning: implicit conversion from 'float' to 'double' when passing argument to function
     87 #pragma GCC diagnostic ignored "-Wconversion"               // warning: conversion to 'xxxx' from 'xxxx' may alter its value
     88 #pragma GCC diagnostic ignored "-Wstack-protector"          // warning: stack protector not protecting local variables: variable length buffer
     89 #pragma GCC diagnostic ignored "-Wclass-memaccess"          // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead
     90 #endif
     91 
     92 //-------------------------------------------------------------------------
     93 // [SECTION] STB libraries implementation
     94 //-------------------------------------------------------------------------
     95 
     96 // Compile time options:
     97 //#define IMGUI_STB_NAMESPACE           ImStb
     98 //#define IMGUI_STB_TRUETYPE_FILENAME   "my_folder/stb_truetype.h"
     99 //#define IMGUI_STB_RECT_PACK_FILENAME  "my_folder/stb_rect_pack.h"
    100 //#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
    101 //#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
    102 
    103 #ifdef IMGUI_STB_NAMESPACE
    104 namespace IMGUI_STB_NAMESPACE
    105 {
    106 #endif
    107 
    108 #ifdef _MSC_VER
    109 #pragma warning (push)
    110 #pragma warning (disable: 4456)                             // declaration of 'xx' hides previous local declaration
    111 #pragma warning (disable: 6011)                             // (stb_rectpack) Dereferencing NULL pointer 'cur->next'.
    112 #pragma warning (disable: 6385)                             // (stb_truetype) Reading invalid data from 'buffer':  the readable size is '_Old_3`kernel_width' bytes, but '3' bytes may be read.
    113 #pragma warning (disable: 28182)                            // (stb_rectpack) Dereferencing NULL pointer. 'cur' contains the same NULL value as 'cur->next' did.
    114 #endif
    115 
    116 #if defined(__clang__)
    117 #pragma clang diagnostic push
    118 #pragma clang diagnostic ignored "-Wunused-function"
    119 #pragma clang diagnostic ignored "-Wmissing-prototypes"
    120 #pragma clang diagnostic ignored "-Wimplicit-fallthrough"
    121 #pragma clang diagnostic ignored "-Wcast-qual"              // warning: cast from 'const xxxx *' to 'xxx *' drops const qualifier
    122 #endif
    123 
    124 #if defined(__GNUC__)
    125 #pragma GCC diagnostic push
    126 #pragma GCC diagnostic ignored "-Wtype-limits"              // warning: comparison is always true due to limited range of data type [-Wtype-limits]
    127 #pragma GCC diagnostic ignored "-Wcast-qual"                // warning: cast from type 'const xxxx *' to type 'xxxx *' casts away qualifiers
    128 #endif
    129 
    130 #ifndef STB_RECT_PACK_IMPLEMENTATION                        // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds)
    131 #ifndef IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION          // in case the user already have an implementation in another compilation unit
    132 #define STBRP_STATIC
    133 #define STBRP_ASSERT(x)     do { IM_ASSERT(x); } while (0)
    134 #define STBRP_SORT          ImQsort
    135 #define STB_RECT_PACK_IMPLEMENTATION
    136 #endif
    137 #ifdef IMGUI_STB_RECT_PACK_FILENAME
    138 #include IMGUI_STB_RECT_PACK_FILENAME
    139 #else
    140 #include "imstb_rectpack.h"
    141 #endif
    142 #endif
    143 
    144 #ifdef  IMGUI_ENABLE_STB_TRUETYPE
    145 #ifndef STB_TRUETYPE_IMPLEMENTATION                         // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds)
    146 #ifndef IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION           // in case the user already have an implementation in another compilation unit
    147 #define STBTT_malloc(x,u)   ((void)(u), IM_ALLOC(x))
    148 #define STBTT_free(x,u)     ((void)(u), IM_FREE(x))
    149 #define STBTT_assert(x)     do { IM_ASSERT(x); } while(0)
    150 #define STBTT_fmod(x,y)     ImFmod(x,y)
    151 #define STBTT_sqrt(x)       ImSqrt(x)
    152 #define STBTT_pow(x,y)      ImPow(x,y)
    153 #define STBTT_fabs(x)       ImFabs(x)
    154 #define STBTT_ifloor(x)     ((int)ImFloorSigned(x))
    155 #define STBTT_iceil(x)      ((int)ImCeil(x))
    156 #define STBTT_STATIC
    157 #define STB_TRUETYPE_IMPLEMENTATION
    158 #else
    159 #define STBTT_DEF extern
    160 #endif
    161 #ifdef IMGUI_STB_TRUETYPE_FILENAME
    162 #include IMGUI_STB_TRUETYPE_FILENAME
    163 #else
    164 #include "imstb_truetype.h"
    165 #endif
    166 #endif
    167 #endif // IMGUI_ENABLE_STB_TRUETYPE
    168 
    169 #if defined(__GNUC__)
    170 #pragma GCC diagnostic pop
    171 #endif
    172 
    173 #if defined(__clang__)
    174 #pragma clang diagnostic pop
    175 #endif
    176 
    177 #if defined(_MSC_VER)
    178 #pragma warning (pop)
    179 #endif
    180 
    181 #ifdef IMGUI_STB_NAMESPACE
    182 } // namespace ImStb
    183 using namespace IMGUI_STB_NAMESPACE;
    184 #endif
    185 
    186 //-----------------------------------------------------------------------------
    187 // [SECTION] Style functions
    188 //-----------------------------------------------------------------------------
    189 
    190 void ImGui::StyleColorsDark(ImGuiStyle* dst)
    191 {
    192     ImGuiStyle* style = dst ? dst : &ImGui::GetStyle();
    193     ImVec4* colors = style->Colors;
    194 
    195     colors[ImGuiCol_Text]                   = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
    196     colors[ImGuiCol_TextDisabled]           = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
    197     colors[ImGuiCol_WindowBg]               = ImVec4(0.06f, 0.06f, 0.06f, 0.94f);
    198     colors[ImGuiCol_ChildBg]                = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
    199     colors[ImGuiCol_PopupBg]                = ImVec4(0.08f, 0.08f, 0.08f, 0.94f);
    200     colors[ImGuiCol_Border]                 = ImVec4(0.43f, 0.43f, 0.50f, 0.50f);
    201     colors[ImGuiCol_BorderShadow]           = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
    202     colors[ImGuiCol_FrameBg]                = ImVec4(0.16f, 0.29f, 0.48f, 0.54f);
    203     colors[ImGuiCol_FrameBgHovered]         = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);
    204     colors[ImGuiCol_FrameBgActive]          = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
    205     colors[ImGuiCol_TitleBg]                = ImVec4(0.04f, 0.04f, 0.04f, 1.00f);
    206     colors[ImGuiCol_TitleBgActive]          = ImVec4(0.16f, 0.29f, 0.48f, 1.00f);
    207     colors[ImGuiCol_TitleBgCollapsed]       = ImVec4(0.00f, 0.00f, 0.00f, 0.51f);
    208     colors[ImGuiCol_MenuBarBg]              = ImVec4(0.14f, 0.14f, 0.14f, 1.00f);
    209     colors[ImGuiCol_ScrollbarBg]            = ImVec4(0.02f, 0.02f, 0.02f, 0.53f);
    210     colors[ImGuiCol_ScrollbarGrab]          = ImVec4(0.31f, 0.31f, 0.31f, 1.00f);
    211     colors[ImGuiCol_ScrollbarGrabHovered]   = ImVec4(0.41f, 0.41f, 0.41f, 1.00f);
    212     colors[ImGuiCol_ScrollbarGrabActive]    = ImVec4(0.51f, 0.51f, 0.51f, 1.00f);
    213     colors[ImGuiCol_CheckMark]              = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
    214     colors[ImGuiCol_SliderGrab]             = ImVec4(0.24f, 0.52f, 0.88f, 1.00f);
    215     colors[ImGuiCol_SliderGrabActive]       = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
    216     colors[ImGuiCol_Button]                 = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);
    217     colors[ImGuiCol_ButtonHovered]          = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
    218     colors[ImGuiCol_ButtonActive]           = ImVec4(0.06f, 0.53f, 0.98f, 1.00f);
    219     colors[ImGuiCol_Header]                 = ImVec4(0.26f, 0.59f, 0.98f, 0.31f);
    220     colors[ImGuiCol_HeaderHovered]          = ImVec4(0.26f, 0.59f, 0.98f, 0.80f);
    221     colors[ImGuiCol_HeaderActive]           = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
    222     colors[ImGuiCol_Separator]              = colors[ImGuiCol_Border];
    223     colors[ImGuiCol_SeparatorHovered]       = ImVec4(0.10f, 0.40f, 0.75f, 0.78f);
    224     colors[ImGuiCol_SeparatorActive]        = ImVec4(0.10f, 0.40f, 0.75f, 1.00f);
    225     colors[ImGuiCol_ResizeGrip]             = ImVec4(0.26f, 0.59f, 0.98f, 0.20f);
    226     colors[ImGuiCol_ResizeGripHovered]      = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
    227     colors[ImGuiCol_ResizeGripActive]       = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
    228     colors[ImGuiCol_Tab]                    = ImLerp(colors[ImGuiCol_Header],       colors[ImGuiCol_TitleBgActive], 0.80f);
    229     colors[ImGuiCol_TabHovered]             = colors[ImGuiCol_HeaderHovered];
    230     colors[ImGuiCol_TabActive]              = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
    231     colors[ImGuiCol_TabUnfocused]           = ImLerp(colors[ImGuiCol_Tab],          colors[ImGuiCol_TitleBg], 0.80f);
    232     colors[ImGuiCol_TabUnfocusedActive]     = ImLerp(colors[ImGuiCol_TabActive],    colors[ImGuiCol_TitleBg], 0.40f);
    233     colors[ImGuiCol_PlotLines]              = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);
    234     colors[ImGuiCol_PlotLinesHovered]       = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
    235     colors[ImGuiCol_PlotHistogram]          = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
    236     colors[ImGuiCol_PlotHistogramHovered]   = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
    237     colors[ImGuiCol_TableHeaderBg]          = ImVec4(0.19f, 0.19f, 0.20f, 1.00f);
    238     colors[ImGuiCol_TableBorderStrong]      = ImVec4(0.31f, 0.31f, 0.35f, 1.00f);   // Prefer using Alpha=1.0 here
    239     colors[ImGuiCol_TableBorderLight]       = ImVec4(0.23f, 0.23f, 0.25f, 1.00f);   // Prefer using Alpha=1.0 here
    240     colors[ImGuiCol_TableRowBg]             = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
    241     colors[ImGuiCol_TableRowBgAlt]          = ImVec4(1.00f, 1.00f, 1.00f, 0.06f);
    242     colors[ImGuiCol_TextSelectedBg]         = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
    243     colors[ImGuiCol_DragDropTarget]         = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
    244     colors[ImGuiCol_NavHighlight]           = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
    245     colors[ImGuiCol_NavWindowingHighlight]  = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);
    246     colors[ImGuiCol_NavWindowingDimBg]      = ImVec4(0.80f, 0.80f, 0.80f, 0.20f);
    247     colors[ImGuiCol_ModalWindowDimBg]       = ImVec4(0.80f, 0.80f, 0.80f, 0.35f);
    248 }
    249 
    250 void ImGui::StyleColorsClassic(ImGuiStyle* dst)
    251 {
    252     ImGuiStyle* style = dst ? dst : &ImGui::GetStyle();
    253     ImVec4* colors = style->Colors;
    254 
    255     colors[ImGuiCol_Text]                   = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
    256     colors[ImGuiCol_TextDisabled]           = ImVec4(0.60f, 0.60f, 0.60f, 1.00f);
    257     colors[ImGuiCol_WindowBg]               = ImVec4(0.00f, 0.00f, 0.00f, 0.85f);
    258     colors[ImGuiCol_ChildBg]                = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
    259     colors[ImGuiCol_PopupBg]                = ImVec4(0.11f, 0.11f, 0.14f, 0.92f);
    260     colors[ImGuiCol_Border]                 = ImVec4(0.50f, 0.50f, 0.50f, 0.50f);
    261     colors[ImGuiCol_BorderShadow]           = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
    262     colors[ImGuiCol_FrameBg]                = ImVec4(0.43f, 0.43f, 0.43f, 0.39f);
    263     colors[ImGuiCol_FrameBgHovered]         = ImVec4(0.47f, 0.47f, 0.69f, 0.40f);
    264     colors[ImGuiCol_FrameBgActive]          = ImVec4(0.42f, 0.41f, 0.64f, 0.69f);
    265     colors[ImGuiCol_TitleBg]                = ImVec4(0.27f, 0.27f, 0.54f, 0.83f);
    266     colors[ImGuiCol_TitleBgActive]          = ImVec4(0.32f, 0.32f, 0.63f, 0.87f);
    267     colors[ImGuiCol_TitleBgCollapsed]       = ImVec4(0.40f, 0.40f, 0.80f, 0.20f);
    268     colors[ImGuiCol_MenuBarBg]              = ImVec4(0.40f, 0.40f, 0.55f, 0.80f);
    269     colors[ImGuiCol_ScrollbarBg]            = ImVec4(0.20f, 0.25f, 0.30f, 0.60f);
    270     colors[ImGuiCol_ScrollbarGrab]          = ImVec4(0.40f, 0.40f, 0.80f, 0.30f);
    271     colors[ImGuiCol_ScrollbarGrabHovered]   = ImVec4(0.40f, 0.40f, 0.80f, 0.40f);
    272     colors[ImGuiCol_ScrollbarGrabActive]    = ImVec4(0.41f, 0.39f, 0.80f, 0.60f);
    273     colors[ImGuiCol_CheckMark]              = ImVec4(0.90f, 0.90f, 0.90f, 0.50f);
    274     colors[ImGuiCol_SliderGrab]             = ImVec4(1.00f, 1.00f, 1.00f, 0.30f);
    275     colors[ImGuiCol_SliderGrabActive]       = ImVec4(0.41f, 0.39f, 0.80f, 0.60f);
    276     colors[ImGuiCol_Button]                 = ImVec4(0.35f, 0.40f, 0.61f, 0.62f);
    277     colors[ImGuiCol_ButtonHovered]          = ImVec4(0.40f, 0.48f, 0.71f, 0.79f);
    278     colors[ImGuiCol_ButtonActive]           = ImVec4(0.46f, 0.54f, 0.80f, 1.00f);
    279     colors[ImGuiCol_Header]                 = ImVec4(0.40f, 0.40f, 0.90f, 0.45f);
    280     colors[ImGuiCol_HeaderHovered]          = ImVec4(0.45f, 0.45f, 0.90f, 0.80f);
    281     colors[ImGuiCol_HeaderActive]           = ImVec4(0.53f, 0.53f, 0.87f, 0.80f);
    282     colors[ImGuiCol_Separator]              = ImVec4(0.50f, 0.50f, 0.50f, 0.60f);
    283     colors[ImGuiCol_SeparatorHovered]       = ImVec4(0.60f, 0.60f, 0.70f, 1.00f);
    284     colors[ImGuiCol_SeparatorActive]        = ImVec4(0.70f, 0.70f, 0.90f, 1.00f);
    285     colors[ImGuiCol_ResizeGrip]             = ImVec4(1.00f, 1.00f, 1.00f, 0.10f);
    286     colors[ImGuiCol_ResizeGripHovered]      = ImVec4(0.78f, 0.82f, 1.00f, 0.60f);
    287     colors[ImGuiCol_ResizeGripActive]       = ImVec4(0.78f, 0.82f, 1.00f, 0.90f);
    288     colors[ImGuiCol_Tab]                    = ImLerp(colors[ImGuiCol_Header],       colors[ImGuiCol_TitleBgActive], 0.80f);
    289     colors[ImGuiCol_TabHovered]             = colors[ImGuiCol_HeaderHovered];
    290     colors[ImGuiCol_TabActive]              = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
    291     colors[ImGuiCol_TabUnfocused]           = ImLerp(colors[ImGuiCol_Tab],          colors[ImGuiCol_TitleBg], 0.80f);
    292     colors[ImGuiCol_TabUnfocusedActive]     = ImLerp(colors[ImGuiCol_TabActive],    colors[ImGuiCol_TitleBg], 0.40f);
    293     colors[ImGuiCol_PlotLines]              = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
    294     colors[ImGuiCol_PlotLinesHovered]       = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
    295     colors[ImGuiCol_PlotHistogram]          = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
    296     colors[ImGuiCol_PlotHistogramHovered]   = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
    297     colors[ImGuiCol_TableHeaderBg]          = ImVec4(0.27f, 0.27f, 0.38f, 1.00f);
    298     colors[ImGuiCol_TableBorderStrong]      = ImVec4(0.31f, 0.31f, 0.45f, 1.00f);   // Prefer using Alpha=1.0 here
    299     colors[ImGuiCol_TableBorderLight]       = ImVec4(0.26f, 0.26f, 0.28f, 1.00f);   // Prefer using Alpha=1.0 here
    300     colors[ImGuiCol_TableRowBg]             = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
    301     colors[ImGuiCol_TableRowBgAlt]          = ImVec4(1.00f, 1.00f, 1.00f, 0.07f);
    302     colors[ImGuiCol_TextSelectedBg]         = ImVec4(0.00f, 0.00f, 1.00f, 0.35f);
    303     colors[ImGuiCol_DragDropTarget]         = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
    304     colors[ImGuiCol_NavHighlight]           = colors[ImGuiCol_HeaderHovered];
    305     colors[ImGuiCol_NavWindowingHighlight]  = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);
    306     colors[ImGuiCol_NavWindowingDimBg]      = ImVec4(0.80f, 0.80f, 0.80f, 0.20f);
    307     colors[ImGuiCol_ModalWindowDimBg]       = ImVec4(0.20f, 0.20f, 0.20f, 0.35f);
    308 }
    309 
    310 // Those light colors are better suited with a thicker font than the default one + FrameBorder
    311 void ImGui::StyleColorsLight(ImGuiStyle* dst)
    312 {
    313     ImGuiStyle* style = dst ? dst : &ImGui::GetStyle();
    314     ImVec4* colors = style->Colors;
    315 
    316     colors[ImGuiCol_Text]                   = ImVec4(0.00f, 0.00f, 0.00f, 1.00f);
    317     colors[ImGuiCol_TextDisabled]           = ImVec4(0.60f, 0.60f, 0.60f, 1.00f);
    318     colors[ImGuiCol_WindowBg]               = ImVec4(0.94f, 0.94f, 0.94f, 1.00f);
    319     colors[ImGuiCol_ChildBg]                = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
    320     colors[ImGuiCol_PopupBg]                = ImVec4(1.00f, 1.00f, 1.00f, 0.98f);
    321     colors[ImGuiCol_Border]                 = ImVec4(0.00f, 0.00f, 0.00f, 0.30f);
    322     colors[ImGuiCol_BorderShadow]           = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
    323     colors[ImGuiCol_FrameBg]                = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
    324     colors[ImGuiCol_FrameBgHovered]         = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);
    325     colors[ImGuiCol_FrameBgActive]          = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
    326     colors[ImGuiCol_TitleBg]                = ImVec4(0.96f, 0.96f, 0.96f, 1.00f);
    327     colors[ImGuiCol_TitleBgActive]          = ImVec4(0.82f, 0.82f, 0.82f, 1.00f);
    328     colors[ImGuiCol_TitleBgCollapsed]       = ImVec4(1.00f, 1.00f, 1.00f, 0.51f);
    329     colors[ImGuiCol_MenuBarBg]              = ImVec4(0.86f, 0.86f, 0.86f, 1.00f);
    330     colors[ImGuiCol_ScrollbarBg]            = ImVec4(0.98f, 0.98f, 0.98f, 0.53f);
    331     colors[ImGuiCol_ScrollbarGrab]          = ImVec4(0.69f, 0.69f, 0.69f, 0.80f);
    332     colors[ImGuiCol_ScrollbarGrabHovered]   = ImVec4(0.49f, 0.49f, 0.49f, 0.80f);
    333     colors[ImGuiCol_ScrollbarGrabActive]    = ImVec4(0.49f, 0.49f, 0.49f, 1.00f);
    334     colors[ImGuiCol_CheckMark]              = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
    335     colors[ImGuiCol_SliderGrab]             = ImVec4(0.26f, 0.59f, 0.98f, 0.78f);
    336     colors[ImGuiCol_SliderGrabActive]       = ImVec4(0.46f, 0.54f, 0.80f, 0.60f);
    337     colors[ImGuiCol_Button]                 = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);
    338     colors[ImGuiCol_ButtonHovered]          = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
    339     colors[ImGuiCol_ButtonActive]           = ImVec4(0.06f, 0.53f, 0.98f, 1.00f);
    340     colors[ImGuiCol_Header]                 = ImVec4(0.26f, 0.59f, 0.98f, 0.31f);
    341     colors[ImGuiCol_HeaderHovered]          = ImVec4(0.26f, 0.59f, 0.98f, 0.80f);
    342     colors[ImGuiCol_HeaderActive]           = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
    343     colors[ImGuiCol_Separator]              = ImVec4(0.39f, 0.39f, 0.39f, 0.62f);
    344     colors[ImGuiCol_SeparatorHovered]       = ImVec4(0.14f, 0.44f, 0.80f, 0.78f);
    345     colors[ImGuiCol_SeparatorActive]        = ImVec4(0.14f, 0.44f, 0.80f, 1.00f);
    346     colors[ImGuiCol_ResizeGrip]             = ImVec4(0.35f, 0.35f, 0.35f, 0.17f);
    347     colors[ImGuiCol_ResizeGripHovered]      = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
    348     colors[ImGuiCol_ResizeGripActive]       = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
    349     colors[ImGuiCol_Tab]                    = ImLerp(colors[ImGuiCol_Header],       colors[ImGuiCol_TitleBgActive], 0.90f);
    350     colors[ImGuiCol_TabHovered]             = colors[ImGuiCol_HeaderHovered];
    351     colors[ImGuiCol_TabActive]              = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
    352     colors[ImGuiCol_TabUnfocused]           = ImLerp(colors[ImGuiCol_Tab],          colors[ImGuiCol_TitleBg], 0.80f);
    353     colors[ImGuiCol_TabUnfocusedActive]     = ImLerp(colors[ImGuiCol_TabActive],    colors[ImGuiCol_TitleBg], 0.40f);
    354     colors[ImGuiCol_PlotLines]              = ImVec4(0.39f, 0.39f, 0.39f, 1.00f);
    355     colors[ImGuiCol_PlotLinesHovered]       = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
    356     colors[ImGuiCol_PlotHistogram]          = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
    357     colors[ImGuiCol_PlotHistogramHovered]   = ImVec4(1.00f, 0.45f, 0.00f, 1.00f);
    358     colors[ImGuiCol_TableHeaderBg]          = ImVec4(0.78f, 0.87f, 0.98f, 1.00f);
    359     colors[ImGuiCol_TableBorderStrong]      = ImVec4(0.57f, 0.57f, 0.64f, 1.00f);   // Prefer using Alpha=1.0 here
    360     colors[ImGuiCol_TableBorderLight]       = ImVec4(0.68f, 0.68f, 0.74f, 1.00f);   // Prefer using Alpha=1.0 here
    361     colors[ImGuiCol_TableRowBg]             = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
    362     colors[ImGuiCol_TableRowBgAlt]          = ImVec4(0.30f, 0.30f, 0.30f, 0.09f);
    363     colors[ImGuiCol_TextSelectedBg]         = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
    364     colors[ImGuiCol_DragDropTarget]         = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
    365     colors[ImGuiCol_NavHighlight]           = colors[ImGuiCol_HeaderHovered];
    366     colors[ImGuiCol_NavWindowingHighlight]  = ImVec4(0.70f, 0.70f, 0.70f, 0.70f);
    367     colors[ImGuiCol_NavWindowingDimBg]      = ImVec4(0.20f, 0.20f, 0.20f, 0.20f);
    368     colors[ImGuiCol_ModalWindowDimBg]       = ImVec4(0.20f, 0.20f, 0.20f, 0.35f);
    369 }
    370 
    371 //-----------------------------------------------------------------------------
    372 // [SECTION] ImDrawList
    373 //-----------------------------------------------------------------------------
    374 
    375 ImDrawListSharedData::ImDrawListSharedData()
    376 {
    377     memset(this, 0, sizeof(*this));
    378     for (int i = 0; i < IM_ARRAYSIZE(ArcFastVtx); i++)
    379     {
    380         const float a = ((float)i * 2 * IM_PI) / (float)IM_ARRAYSIZE(ArcFastVtx);
    381         ArcFastVtx[i] = ImVec2(ImCos(a), ImSin(a));
    382     }
    383     ArcFastRadiusCutoff = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(IM_DRAWLIST_ARCFAST_SAMPLE_MAX, CircleSegmentMaxError);
    384 }
    385 
    386 void ImDrawListSharedData::SetCircleTessellationMaxError(float max_error)
    387 {
    388     if (CircleSegmentMaxError == max_error)
    389         return;
    390 
    391     IM_ASSERT(max_error > 0.0f);
    392     CircleSegmentMaxError = max_error;
    393     for (int i = 0; i < IM_ARRAYSIZE(CircleSegmentCounts); i++)
    394     {
    395         const float radius = (float)i;
    396         CircleSegmentCounts[i] = (ImU8)((i > 0) ? IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, CircleSegmentMaxError) : 0);
    397     }
    398     ArcFastRadiusCutoff = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(IM_DRAWLIST_ARCFAST_SAMPLE_MAX, CircleSegmentMaxError);
    399 }
    400 
    401 // Initialize before use in a new frame. We always have a command ready in the buffer.
    402 void ImDrawList::_ResetForNewFrame()
    403 {
    404     // Verify that the ImDrawCmd fields we want to memcmp() are contiguous in memory.
    405     // (those should be IM_STATIC_ASSERT() in theory but with our pre C++11 setup the whole check doesn't compile with GCC)
    406     IM_ASSERT(IM_OFFSETOF(ImDrawCmd, ClipRect) == 0);
    407     IM_ASSERT(IM_OFFSETOF(ImDrawCmd, TextureId) == sizeof(ImVec4));
    408     IM_ASSERT(IM_OFFSETOF(ImDrawCmd, VtxOffset) == sizeof(ImVec4) + sizeof(ImTextureID));
    409 
    410     CmdBuffer.resize(0);
    411     IdxBuffer.resize(0);
    412     VtxBuffer.resize(0);
    413     Flags = _Data->InitialFlags;
    414     memset(&_CmdHeader, 0, sizeof(_CmdHeader));
    415     _VtxCurrentIdx = 0;
    416     _VtxWritePtr = NULL;
    417     _IdxWritePtr = NULL;
    418     _ClipRectStack.resize(0);
    419     _TextureIdStack.resize(0);
    420     _Path.resize(0);
    421     _Splitter.Clear();
    422     CmdBuffer.push_back(ImDrawCmd());
    423     _FringeScale = 1.0f;
    424 }
    425 
    426 void ImDrawList::_ClearFreeMemory()
    427 {
    428     CmdBuffer.clear();
    429     IdxBuffer.clear();
    430     VtxBuffer.clear();
    431     Flags = ImDrawListFlags_None;
    432     _VtxCurrentIdx = 0;
    433     _VtxWritePtr = NULL;
    434     _IdxWritePtr = NULL;
    435     _ClipRectStack.clear();
    436     _TextureIdStack.clear();
    437     _Path.clear();
    438     _Splitter.ClearFreeMemory();
    439 }
    440 
    441 ImDrawList* ImDrawList::CloneOutput() const
    442 {
    443     ImDrawList* dst = IM_NEW(ImDrawList(_Data));
    444     dst->CmdBuffer = CmdBuffer;
    445     dst->IdxBuffer = IdxBuffer;
    446     dst->VtxBuffer = VtxBuffer;
    447     dst->Flags = Flags;
    448     return dst;
    449 }
    450 
    451 void ImDrawList::AddDrawCmd()
    452 {
    453     ImDrawCmd draw_cmd;
    454     draw_cmd.ClipRect = _CmdHeader.ClipRect;    // Same as calling ImDrawCmd_HeaderCopy()
    455     draw_cmd.TextureId = _CmdHeader.TextureId;
    456     draw_cmd.VtxOffset = _CmdHeader.VtxOffset;
    457     draw_cmd.IdxOffset = IdxBuffer.Size;
    458 
    459     IM_ASSERT(draw_cmd.ClipRect.x <= draw_cmd.ClipRect.z && draw_cmd.ClipRect.y <= draw_cmd.ClipRect.w);
    460     CmdBuffer.push_back(draw_cmd);
    461 }
    462 
    463 // Pop trailing draw command (used before merging or presenting to user)
    464 // Note that this leaves the ImDrawList in a state unfit for further commands, as most code assume that CmdBuffer.Size > 0 && CmdBuffer.back().UserCallback == NULL
    465 void ImDrawList::_PopUnusedDrawCmd()
    466 {
    467     if (CmdBuffer.Size == 0)
    468         return;
    469     ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
    470     if (curr_cmd->ElemCount == 0 && curr_cmd->UserCallback == NULL)
    471         CmdBuffer.pop_back();
    472 }
    473 
    474 void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data)
    475 {
    476     ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
    477     IM_ASSERT(curr_cmd->UserCallback == NULL);
    478     if (curr_cmd->ElemCount != 0)
    479     {
    480         AddDrawCmd();
    481         curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
    482     }
    483     curr_cmd->UserCallback = callback;
    484     curr_cmd->UserCallbackData = callback_data;
    485 
    486     AddDrawCmd(); // Force a new command after us (see comment below)
    487 }
    488 
    489 // Compare ClipRect, TextureId and VtxOffset with a single memcmp()
    490 #define ImDrawCmd_HeaderSize                        (IM_OFFSETOF(ImDrawCmd, VtxOffset) + sizeof(unsigned int))
    491 #define ImDrawCmd_HeaderCompare(CMD_LHS, CMD_RHS)   (memcmp(CMD_LHS, CMD_RHS, ImDrawCmd_HeaderSize))    // Compare ClipRect, TextureId, VtxOffset
    492 #define ImDrawCmd_HeaderCopy(CMD_DST, CMD_SRC)      (memcpy(CMD_DST, CMD_SRC, ImDrawCmd_HeaderSize))    // Copy ClipRect, TextureId, VtxOffset
    493 
    494 // 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.
    495 // 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.
    496 void ImDrawList::_OnChangedClipRect()
    497 {
    498     // If current command is used with different settings we need to add a new command
    499     ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
    500     if (curr_cmd->ElemCount != 0 && memcmp(&curr_cmd->ClipRect, &_CmdHeader.ClipRect, sizeof(ImVec4)) != 0)
    501     {
    502         AddDrawCmd();
    503         return;
    504     }
    505     IM_ASSERT(curr_cmd->UserCallback == NULL);
    506 
    507     // Try to merge with previous command if it matches, else use current command
    508     ImDrawCmd* prev_cmd = curr_cmd - 1;
    509     if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && prev_cmd->UserCallback == NULL)
    510     {
    511         CmdBuffer.pop_back();
    512         return;
    513     }
    514 
    515     curr_cmd->ClipRect = _CmdHeader.ClipRect;
    516 }
    517 
    518 void ImDrawList::_OnChangedTextureID()
    519 {
    520     // If current command is used with different settings we need to add a new command
    521     ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
    522     if (curr_cmd->ElemCount != 0 && curr_cmd->TextureId != _CmdHeader.TextureId)
    523     {
    524         AddDrawCmd();
    525         return;
    526     }
    527     IM_ASSERT(curr_cmd->UserCallback == NULL);
    528 
    529     // Try to merge with previous command if it matches, else use current command
    530     ImDrawCmd* prev_cmd = curr_cmd - 1;
    531     if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && prev_cmd->UserCallback == NULL)
    532     {
    533         CmdBuffer.pop_back();
    534         return;
    535     }
    536 
    537     curr_cmd->TextureId = _CmdHeader.TextureId;
    538 }
    539 
    540 void ImDrawList::_OnChangedVtxOffset()
    541 {
    542     // We don't need to compare curr_cmd->VtxOffset != _CmdHeader.VtxOffset because we know it'll be different at the time we call this.
    543     _VtxCurrentIdx = 0;
    544     ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
    545     //IM_ASSERT(curr_cmd->VtxOffset != _CmdHeader.VtxOffset); // See #3349
    546     if (curr_cmd->ElemCount != 0)
    547     {
    548         AddDrawCmd();
    549         return;
    550     }
    551     IM_ASSERT(curr_cmd->UserCallback == NULL);
    552     curr_cmd->VtxOffset = _CmdHeader.VtxOffset;
    553 }
    554 
    555 int ImDrawList::_CalcCircleAutoSegmentCount(float radius) const
    556 {
    557     // Automatic segment count
    558     const int radius_idx = (int)(radius + 0.999999f); // ceil to never reduce accuracy
    559     if (radius_idx < IM_ARRAYSIZE(_Data->CircleSegmentCounts))
    560         return _Data->CircleSegmentCounts[radius_idx]; // Use cached value
    561     else
    562         return IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, _Data->CircleSegmentMaxError);
    563 }
    564 
    565 // 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)
    566 void ImDrawList::PushClipRect(ImVec2 cr_min, ImVec2 cr_max, bool intersect_with_current_clip_rect)
    567 {
    568     ImVec4 cr(cr_min.x, cr_min.y, cr_max.x, cr_max.y);
    569     if (intersect_with_current_clip_rect)
    570     {
    571         ImVec4 current = _CmdHeader.ClipRect;
    572         if (cr.x < current.x) cr.x = current.x;
    573         if (cr.y < current.y) cr.y = current.y;
    574         if (cr.z > current.z) cr.z = current.z;
    575         if (cr.w > current.w) cr.w = current.w;
    576     }
    577     cr.z = ImMax(cr.x, cr.z);
    578     cr.w = ImMax(cr.y, cr.w);
    579 
    580     _ClipRectStack.push_back(cr);
    581     _CmdHeader.ClipRect = cr;
    582     _OnChangedClipRect();
    583 }
    584 
    585 void ImDrawList::PushClipRectFullScreen()
    586 {
    587     PushClipRect(ImVec2(_Data->ClipRectFullscreen.x, _Data->ClipRectFullscreen.y), ImVec2(_Data->ClipRectFullscreen.z, _Data->ClipRectFullscreen.w));
    588 }
    589 
    590 void ImDrawList::PopClipRect()
    591 {
    592     _ClipRectStack.pop_back();
    593     _CmdHeader.ClipRect = (_ClipRectStack.Size == 0) ? _Data->ClipRectFullscreen : _ClipRectStack.Data[_ClipRectStack.Size - 1];
    594     _OnChangedClipRect();
    595 }
    596 
    597 void ImDrawList::PushTextureID(ImTextureID texture_id)
    598 {
    599     _TextureIdStack.push_back(texture_id);
    600     _CmdHeader.TextureId = texture_id;
    601     _OnChangedTextureID();
    602 }
    603 
    604 void ImDrawList::PopTextureID()
    605 {
    606     _TextureIdStack.pop_back();
    607     _CmdHeader.TextureId = (_TextureIdStack.Size == 0) ? (ImTextureID)NULL : _TextureIdStack.Data[_TextureIdStack.Size - 1];
    608     _OnChangedTextureID();
    609 }
    610 
    611 // Reserve space for a number of vertices and indices.
    612 // You must finish filling your reserved data before calling PrimReserve() again, as it may reallocate or
    613 // submit the intermediate results. PrimUnreserve() can be used to release unused allocations.
    614 void ImDrawList::PrimReserve(int idx_count, int vtx_count)
    615 {
    616     // Large mesh support (when enabled)
    617     IM_ASSERT_PARANOID(idx_count >= 0 && vtx_count >= 0);
    618     if (sizeof(ImDrawIdx) == 2 && (_VtxCurrentIdx + vtx_count >= (1 << 16)) && (Flags & ImDrawListFlags_AllowVtxOffset))
    619     {
    620         // FIXME: In theory we should be testing that vtx_count <64k here.
    621         // In practice, RenderText() relies on reserving ahead for a worst case scenario so it is currently useful for us
    622         // to not make that check until we rework the text functions to handle clipping and large horizontal lines better.
    623         _CmdHeader.VtxOffset = VtxBuffer.Size;
    624         _OnChangedVtxOffset();
    625     }
    626 
    627     ImDrawCmd* draw_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
    628     draw_cmd->ElemCount += idx_count;
    629 
    630     int vtx_buffer_old_size = VtxBuffer.Size;
    631     VtxBuffer.resize(vtx_buffer_old_size + vtx_count);
    632     _VtxWritePtr = VtxBuffer.Data + vtx_buffer_old_size;
    633 
    634     int idx_buffer_old_size = IdxBuffer.Size;
    635     IdxBuffer.resize(idx_buffer_old_size + idx_count);
    636     _IdxWritePtr = IdxBuffer.Data + idx_buffer_old_size;
    637 }
    638 
    639 // Release the a number of reserved vertices/indices from the end of the last reservation made with PrimReserve().
    640 void ImDrawList::PrimUnreserve(int idx_count, int vtx_count)
    641 {
    642     IM_ASSERT_PARANOID(idx_count >= 0 && vtx_count >= 0);
    643 
    644     ImDrawCmd* draw_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
    645     draw_cmd->ElemCount -= idx_count;
    646     VtxBuffer.shrink(VtxBuffer.Size - vtx_count);
    647     IdxBuffer.shrink(IdxBuffer.Size - idx_count);
    648 }
    649 
    650 // Fully unrolled with inline call to keep our debug builds decently fast.
    651 void ImDrawList::PrimRect(const ImVec2& a, const ImVec2& c, ImU32 col)
    652 {
    653     ImVec2 b(c.x, a.y), d(a.x, c.y), uv(_Data->TexUvWhitePixel);
    654     ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx;
    655     _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2);
    656     _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3);
    657     _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;
    658     _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col;
    659     _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col;
    660     _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv; _VtxWritePtr[3].col = col;
    661     _VtxWritePtr += 4;
    662     _VtxCurrentIdx += 4;
    663     _IdxWritePtr += 6;
    664 }
    665 
    666 void ImDrawList::PrimRectUV(const ImVec2& a, const ImVec2& c, const ImVec2& uv_a, const ImVec2& uv_c, ImU32 col)
    667 {
    668     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);
    669     ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx;
    670     _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2);
    671     _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3);
    672     _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv_a; _VtxWritePtr[0].col = col;
    673     _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv_b; _VtxWritePtr[1].col = col;
    674     _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv_c; _VtxWritePtr[2].col = col;
    675     _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv_d; _VtxWritePtr[3].col = col;
    676     _VtxWritePtr += 4;
    677     _VtxCurrentIdx += 4;
    678     _IdxWritePtr += 6;
    679 }
    680 
    681 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)
    682 {
    683     ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx;
    684     _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2);
    685     _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3);
    686     _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv_a; _VtxWritePtr[0].col = col;
    687     _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv_b; _VtxWritePtr[1].col = col;
    688     _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv_c; _VtxWritePtr[2].col = col;
    689     _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv_d; _VtxWritePtr[3].col = col;
    690     _VtxWritePtr += 4;
    691     _VtxCurrentIdx += 4;
    692     _IdxWritePtr += 6;
    693 }
    694 
    695 // On AddPolyline() and AddConvexPolyFilled() we intentionally avoid using ImVec2 and superfluous function calls to optimize debug/non-inlined builds.
    696 // Those macros expects l-values.
    697 #define IM_NORMALIZE2F_OVER_ZERO(VX,VY)     do { float d2 = VX*VX + VY*VY; if (d2 > 0.0f) { float inv_len = ImRsqrt(d2); VX *= inv_len; VY *= inv_len; } } while (0)
    698 #define IM_FIXNORMAL2F_MAX_INVLEN2          100.0f // 500.0f (see #4053, #3366)
    699 #define IM_FIXNORMAL2F(VX,VY)               do { float d2 = VX*VX + VY*VY; if (d2 > 0.000001f) { float inv_len2 = 1.0f / d2; if (inv_len2 > IM_FIXNORMAL2F_MAX_INVLEN2) inv_len2 = IM_FIXNORMAL2F_MAX_INVLEN2; VX *= inv_len2; VY *= inv_len2; } } while (0)
    700 
    701 // TODO: Thickness anti-aliased lines cap are missing their AA fringe.
    702 // We avoid using the ImVec2 math operators here to reduce cost to a minimum for debug/non-inlined builds.
    703 void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 col, ImDrawFlags flags, float thickness)
    704 {
    705     if (points_count < 2)
    706         return;
    707 
    708     const bool closed = (flags & ImDrawFlags_Closed) != 0;
    709     const ImVec2 opaque_uv = _Data->TexUvWhitePixel;
    710     const int count = closed ? points_count : points_count - 1; // The number of line segments we need to draw
    711     const bool thick_line = (thickness > _FringeScale);
    712 
    713     if (Flags & ImDrawListFlags_AntiAliasedLines)
    714     {
    715         // Anti-aliased stroke
    716         const float AA_SIZE = _FringeScale;
    717         const ImU32 col_trans = col & ~IM_COL32_A_MASK;
    718 
    719         // Thicknesses <1.0 should behave like thickness 1.0
    720         thickness = ImMax(thickness, 1.0f);
    721         const int integer_thickness = (int)thickness;
    722         const float fractional_thickness = thickness - integer_thickness;
    723 
    724         // Do we want to draw this line using a texture?
    725         // - For now, only draw integer-width lines using textures to avoid issues with the way scaling occurs, could be improved.
    726         // - If AA_SIZE is not 1.0f we cannot use the texture path.
    727         const bool use_texture = (Flags & ImDrawListFlags_AntiAliasedLinesUseTex) && (integer_thickness < IM_DRAWLIST_TEX_LINES_WIDTH_MAX) && (fractional_thickness <= 0.00001f) && (AA_SIZE == 1.0f);
    728 
    729         // We should never hit this, because NewFrame() doesn't set ImDrawListFlags_AntiAliasedLinesUseTex unless ImFontAtlasFlags_NoBakedLines is off
    730         IM_ASSERT_PARANOID(!use_texture || !(_Data->Font->ContainerAtlas->Flags & ImFontAtlasFlags_NoBakedLines));
    731 
    732         const int idx_count = use_texture ? (count * 6) : (thick_line ? count * 18 : count * 12);
    733         const int vtx_count = use_texture ? (points_count * 2) : (thick_line ? points_count * 4 : points_count * 3);
    734         PrimReserve(idx_count, vtx_count);
    735 
    736         // Temporary buffer
    737         // The first <points_count> items are normals at each line point, then after that there are either 2 or 4 temp points for each line point
    738         ImVec2* temp_normals = (ImVec2*)alloca(points_count * ((use_texture || !thick_line) ? 3 : 5) * sizeof(ImVec2)); //-V630
    739         ImVec2* temp_points = temp_normals + points_count;
    740 
    741         // Calculate normals (tangents) for each line segment
    742         for (int i1 = 0; i1 < count; i1++)
    743         {
    744             const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1;
    745             float dx = points[i2].x - points[i1].x;
    746             float dy = points[i2].y - points[i1].y;
    747             IM_NORMALIZE2F_OVER_ZERO(dx, dy);
    748             temp_normals[i1].x = dy;
    749             temp_normals[i1].y = -dx;
    750         }
    751         if (!closed)
    752             temp_normals[points_count - 1] = temp_normals[points_count - 2];
    753 
    754         // If we are drawing a one-pixel-wide line without a texture, or a textured line of any width, we only need 2 or 3 vertices per point
    755         if (use_texture || !thick_line)
    756         {
    757             // [PATH 1] Texture-based lines (thick or non-thick)
    758             // [PATH 2] Non texture-based lines (non-thick)
    759 
    760             // The width of the geometry we need to draw - this is essentially <thickness> pixels for the line itself, plus "one pixel" for AA.
    761             // - In the texture-based path, we don't use AA_SIZE here because the +1 is tied to the generated texture
    762             //   (see ImFontAtlasBuildRenderLinesTexData() function), and so alternate values won't work without changes to that code.
    763             // - In the non texture-based paths, we would allow AA_SIZE to potentially be != 1.0f with a patch (e.g. fringe_scale patch to
    764             //   allow scaling geometry while preserving one-screen-pixel AA fringe).
    765             const float half_draw_size = use_texture ? ((thickness * 0.5f) + 1) : AA_SIZE;
    766 
    767             // If line is not closed, the first and last points need to be generated differently as there are no normals to blend
    768             if (!closed)
    769             {
    770                 temp_points[0] = points[0] + temp_normals[0] * half_draw_size;
    771                 temp_points[1] = points[0] - temp_normals[0] * half_draw_size;
    772                 temp_points[(points_count-1)*2+0] = points[points_count-1] + temp_normals[points_count-1] * half_draw_size;
    773                 temp_points[(points_count-1)*2+1] = points[points_count-1] - temp_normals[points_count-1] * half_draw_size;
    774             }
    775 
    776             // Generate the indices to form a number of triangles for each line segment, and the vertices for the line edges
    777             // This takes points n and n+1 and writes into n+1, with the first point in a closed line being generated from the final one (as n+1 wraps)
    778             // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer.
    779             unsigned int idx1 = _VtxCurrentIdx; // Vertex index for start of line segment
    780             for (int i1 = 0; i1 < count; i1++) // i1 is the first point of the line segment
    781             {
    782                 const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1; // i2 is the second point of the line segment
    783                 const unsigned int idx2 = ((i1 + 1) == points_count) ? _VtxCurrentIdx : (idx1 + (use_texture ? 2 : 3)); // Vertex index for end of segment
    784 
    785                 // Average normals
    786                 float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f;
    787                 float dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5f;
    788                 IM_FIXNORMAL2F(dm_x, dm_y);
    789                 dm_x *= half_draw_size; // dm_x, dm_y are offset to the outer edge of the AA area
    790                 dm_y *= half_draw_size;
    791 
    792                 // Add temporary vertexes for the outer edges
    793                 ImVec2* out_vtx = &temp_points[i2 * 2];
    794                 out_vtx[0].x = points[i2].x + dm_x;
    795                 out_vtx[0].y = points[i2].y + dm_y;
    796                 out_vtx[1].x = points[i2].x - dm_x;
    797                 out_vtx[1].y = points[i2].y - dm_y;
    798 
    799                 if (use_texture)
    800                 {
    801                     // Add indices for two triangles
    802                     _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 1); // Right tri
    803                     _IdxWritePtr[3] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[4] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 0); // Left tri
    804                     _IdxWritePtr += 6;
    805                 }
    806                 else
    807                 {
    808                     // Add indexes for four triangles
    809                     _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 2); // Right tri 1
    810                     _IdxWritePtr[3] = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[4] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 0); // Right tri 2
    811                     _IdxWritePtr[6] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[7] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[8] = (ImDrawIdx)(idx1 + 0); // Left tri 1
    812                     _IdxWritePtr[9] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[10] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[11] = (ImDrawIdx)(idx2 + 1); // Left tri 2
    813                     _IdxWritePtr += 12;
    814                 }
    815 
    816                 idx1 = idx2;
    817             }
    818 
    819             // Add vertexes for each point on the line
    820             if (use_texture)
    821             {
    822                 // If we're using textures we only need to emit the left/right edge vertices
    823                 ImVec4 tex_uvs = _Data->TexUvLines[integer_thickness];
    824                 /*if (fractional_thickness != 0.0f) // Currently always zero when use_texture==false!
    825                 {
    826                     const ImVec4 tex_uvs_1 = _Data->TexUvLines[integer_thickness + 1];
    827                     tex_uvs.x = tex_uvs.x + (tex_uvs_1.x - tex_uvs.x) * fractional_thickness; // inlined ImLerp()
    828                     tex_uvs.y = tex_uvs.y + (tex_uvs_1.y - tex_uvs.y) * fractional_thickness;
    829                     tex_uvs.z = tex_uvs.z + (tex_uvs_1.z - tex_uvs.z) * fractional_thickness;
    830                     tex_uvs.w = tex_uvs.w + (tex_uvs_1.w - tex_uvs.w) * fractional_thickness;
    831                 }*/
    832                 ImVec2 tex_uv0(tex_uvs.x, tex_uvs.y);
    833                 ImVec2 tex_uv1(tex_uvs.z, tex_uvs.w);
    834                 for (int i = 0; i < points_count; i++)
    835                 {
    836                     _VtxWritePtr[0].pos = temp_points[i * 2 + 0]; _VtxWritePtr[0].uv = tex_uv0; _VtxWritePtr[0].col = col; // Left-side outer edge
    837                     _VtxWritePtr[1].pos = temp_points[i * 2 + 1]; _VtxWritePtr[1].uv = tex_uv1; _VtxWritePtr[1].col = col; // Right-side outer edge
    838                     _VtxWritePtr += 2;
    839                 }
    840             }
    841             else
    842             {
    843                 // If we're not using a texture, we need the center vertex as well
    844                 for (int i = 0; i < points_count; i++)
    845                 {
    846                     _VtxWritePtr[0].pos = points[i];              _VtxWritePtr[0].uv = opaque_uv; _VtxWritePtr[0].col = col;       // Center of line
    847                     _VtxWritePtr[1].pos = temp_points[i * 2 + 0]; _VtxWritePtr[1].uv = opaque_uv; _VtxWritePtr[1].col = col_trans; // Left-side outer edge
    848                     _VtxWritePtr[2].pos = temp_points[i * 2 + 1]; _VtxWritePtr[2].uv = opaque_uv; _VtxWritePtr[2].col = col_trans; // Right-side outer edge
    849                     _VtxWritePtr += 3;
    850                 }
    851             }
    852         }
    853         else
    854         {
    855             // [PATH 2] Non texture-based lines (thick): we need to draw the solid line core and thus require four vertices per point
    856             const float half_inner_thickness = (thickness - AA_SIZE) * 0.5f;
    857 
    858             // If line is not closed, the first and last points need to be generated differently as there are no normals to blend
    859             if (!closed)
    860             {
    861                 const int points_last = points_count - 1;
    862                 temp_points[0] = points[0] + temp_normals[0] * (half_inner_thickness + AA_SIZE);
    863                 temp_points[1] = points[0] + temp_normals[0] * (half_inner_thickness);
    864                 temp_points[2] = points[0] - temp_normals[0] * (half_inner_thickness);
    865                 temp_points[3] = points[0] - temp_normals[0] * (half_inner_thickness + AA_SIZE);
    866                 temp_points[points_last * 4 + 0] = points[points_last] + temp_normals[points_last] * (half_inner_thickness + AA_SIZE);
    867                 temp_points[points_last * 4 + 1] = points[points_last] + temp_normals[points_last] * (half_inner_thickness);
    868                 temp_points[points_last * 4 + 2] = points[points_last] - temp_normals[points_last] * (half_inner_thickness);
    869                 temp_points[points_last * 4 + 3] = points[points_last] - temp_normals[points_last] * (half_inner_thickness + AA_SIZE);
    870             }
    871 
    872             // Generate the indices to form a number of triangles for each line segment, and the vertices for the line edges
    873             // This takes points n and n+1 and writes into n+1, with the first point in a closed line being generated from the final one (as n+1 wraps)
    874             // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer.
    875             unsigned int idx1 = _VtxCurrentIdx; // Vertex index for start of line segment
    876             for (int i1 = 0; i1 < count; i1++) // i1 is the first point of the line segment
    877             {
    878                 const int i2 = (i1 + 1) == points_count ? 0 : (i1 + 1); // i2 is the second point of the line segment
    879                 const unsigned int idx2 = (i1 + 1) == points_count ? _VtxCurrentIdx : (idx1 + 4); // Vertex index for end of segment
    880 
    881                 // Average normals
    882                 float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f;
    883                 float dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5f;
    884                 IM_FIXNORMAL2F(dm_x, dm_y);
    885                 float dm_out_x = dm_x * (half_inner_thickness + AA_SIZE);
    886                 float dm_out_y = dm_y * (half_inner_thickness + AA_SIZE);
    887                 float dm_in_x = dm_x * half_inner_thickness;
    888                 float dm_in_y = dm_y * half_inner_thickness;
    889 
    890                 // Add temporary vertices
    891                 ImVec2* out_vtx = &temp_points[i2 * 4];
    892                 out_vtx[0].x = points[i2].x + dm_out_x;
    893                 out_vtx[0].y = points[i2].y + dm_out_y;
    894                 out_vtx[1].x = points[i2].x + dm_in_x;
    895                 out_vtx[1].y = points[i2].y + dm_in_y;
    896                 out_vtx[2].x = points[i2].x - dm_in_x;
    897                 out_vtx[2].y = points[i2].y - dm_in_y;
    898                 out_vtx[3].x = points[i2].x - dm_out_x;
    899                 out_vtx[3].y = points[i2].y - dm_out_y;
    900 
    901                 // Add indexes
    902                 _IdxWritePtr[0]  = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[1]  = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[2]  = (ImDrawIdx)(idx1 + 2);
    903                 _IdxWritePtr[3]  = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[4]  = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[5]  = (ImDrawIdx)(idx2 + 1);
    904                 _IdxWritePtr[6]  = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[7]  = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[8]  = (ImDrawIdx)(idx1 + 0);
    905                 _IdxWritePtr[9]  = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[10] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[11] = (ImDrawIdx)(idx2 + 1);
    906                 _IdxWritePtr[12] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[13] = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[14] = (ImDrawIdx)(idx1 + 3);
    907                 _IdxWritePtr[15] = (ImDrawIdx)(idx1 + 3); _IdxWritePtr[16] = (ImDrawIdx)(idx2 + 3); _IdxWritePtr[17] = (ImDrawIdx)(idx2 + 2);
    908                 _IdxWritePtr += 18;
    909 
    910                 idx1 = idx2;
    911             }
    912 
    913             // Add vertices
    914             for (int i = 0; i < points_count; i++)
    915             {
    916                 _VtxWritePtr[0].pos = temp_points[i * 4 + 0]; _VtxWritePtr[0].uv = opaque_uv; _VtxWritePtr[0].col = col_trans;
    917                 _VtxWritePtr[1].pos = temp_points[i * 4 + 1]; _VtxWritePtr[1].uv = opaque_uv; _VtxWritePtr[1].col = col;
    918                 _VtxWritePtr[2].pos = temp_points[i * 4 + 2]; _VtxWritePtr[2].uv = opaque_uv; _VtxWritePtr[2].col = col;
    919                 _VtxWritePtr[3].pos = temp_points[i * 4 + 3]; _VtxWritePtr[3].uv = opaque_uv; _VtxWritePtr[3].col = col_trans;
    920                 _VtxWritePtr += 4;
    921             }
    922         }
    923         _VtxCurrentIdx += (ImDrawIdx)vtx_count;
    924     }
    925     else
    926     {
    927         // [PATH 4] Non texture-based, Non anti-aliased lines
    928         const int idx_count = count * 6;
    929         const int vtx_count = count * 4;    // FIXME-OPT: Not sharing edges
    930         PrimReserve(idx_count, vtx_count);
    931 
    932         for (int i1 = 0; i1 < count; i1++)
    933         {
    934             const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1;
    935             const ImVec2& p1 = points[i1];
    936             const ImVec2& p2 = points[i2];
    937 
    938             float dx = p2.x - p1.x;
    939             float dy = p2.y - p1.y;
    940             IM_NORMALIZE2F_OVER_ZERO(dx, dy);
    941             dx *= (thickness * 0.5f);
    942             dy *= (thickness * 0.5f);
    943 
    944             _VtxWritePtr[0].pos.x = p1.x + dy; _VtxWritePtr[0].pos.y = p1.y - dx; _VtxWritePtr[0].uv = opaque_uv; _VtxWritePtr[0].col = col;
    945             _VtxWritePtr[1].pos.x = p2.x + dy; _VtxWritePtr[1].pos.y = p2.y - dx; _VtxWritePtr[1].uv = opaque_uv; _VtxWritePtr[1].col = col;
    946             _VtxWritePtr[2].pos.x = p2.x - dy; _VtxWritePtr[2].pos.y = p2.y + dx; _VtxWritePtr[2].uv = opaque_uv; _VtxWritePtr[2].col = col;
    947             _VtxWritePtr[3].pos.x = p1.x - dy; _VtxWritePtr[3].pos.y = p1.y + dx; _VtxWritePtr[3].uv = opaque_uv; _VtxWritePtr[3].col = col;
    948             _VtxWritePtr += 4;
    949 
    950             _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx + 1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx + 2);
    951             _IdxWritePtr[3] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[4] = (ImDrawIdx)(_VtxCurrentIdx + 2); _IdxWritePtr[5] = (ImDrawIdx)(_VtxCurrentIdx + 3);
    952             _IdxWritePtr += 6;
    953             _VtxCurrentIdx += 4;
    954         }
    955     }
    956 }
    957 
    958 // We intentionally avoid using ImVec2 and its math operators here to reduce cost to a minimum for debug/non-inlined builds.
    959 void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_count, ImU32 col)
    960 {
    961     if (points_count < 3)
    962         return;
    963 
    964     const ImVec2 uv = _Data->TexUvWhitePixel;
    965 
    966     if (Flags & ImDrawListFlags_AntiAliasedFill)
    967     {
    968         // Anti-aliased Fill
    969         const float AA_SIZE = _FringeScale;
    970         const ImU32 col_trans = col & ~IM_COL32_A_MASK;
    971         const int idx_count = (points_count - 2)*3 + points_count * 6;
    972         const int vtx_count = (points_count * 2);
    973         PrimReserve(idx_count, vtx_count);
    974 
    975         // Add indexes for fill
    976         unsigned int vtx_inner_idx = _VtxCurrentIdx;
    977         unsigned int vtx_outer_idx = _VtxCurrentIdx + 1;
    978         for (int i = 2; i < points_count; i++)
    979         {
    980             _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + ((i - 1) << 1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_inner_idx + (i << 1));
    981             _IdxWritePtr += 3;
    982         }
    983 
    984         // Compute normals
    985         ImVec2* temp_normals = (ImVec2*)alloca(points_count * sizeof(ImVec2)); //-V630
    986         for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++)
    987         {
    988             const ImVec2& p0 = points[i0];
    989             const ImVec2& p1 = points[i1];
    990             float dx = p1.x - p0.x;
    991             float dy = p1.y - p0.y;
    992             IM_NORMALIZE2F_OVER_ZERO(dx, dy);
    993             temp_normals[i0].x = dy;
    994             temp_normals[i0].y = -dx;
    995         }
    996 
    997         for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++)
    998         {
    999             // Average normals
   1000             const ImVec2& n0 = temp_normals[i0];
   1001             const ImVec2& n1 = temp_normals[i1];
   1002             float dm_x = (n0.x + n1.x) * 0.5f;
   1003             float dm_y = (n0.y + n1.y) * 0.5f;
   1004             IM_FIXNORMAL2F(dm_x, dm_y);
   1005             dm_x *= AA_SIZE * 0.5f;
   1006             dm_y *= AA_SIZE * 0.5f;
   1007 
   1008             // Add vertices
   1009             _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
   1010             _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
   1011             _VtxWritePtr += 2;
   1012 
   1013             // Add indexes for fringes
   1014             _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1)); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + (i0 << 1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1));
   1015             _IdxWritePtr[3] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1)); _IdxWritePtr[4] = (ImDrawIdx)(vtx_outer_idx + (i1 << 1)); _IdxWritePtr[5] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1));
   1016             _IdxWritePtr += 6;
   1017         }
   1018         _VtxCurrentIdx += (ImDrawIdx)vtx_count;
   1019     }
   1020     else
   1021     {
   1022         // Non Anti-aliased Fill
   1023         const int idx_count = (points_count - 2)*3;
   1024         const int vtx_count = points_count;
   1025         PrimReserve(idx_count, vtx_count);
   1026         for (int i = 0; i < vtx_count; i++)
   1027         {
   1028             _VtxWritePtr[0].pos = points[i]; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;
   1029             _VtxWritePtr++;
   1030         }
   1031         for (int i = 2; i < points_count; i++)
   1032         {
   1033             _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx + i - 1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx + i);
   1034             _IdxWritePtr += 3;
   1035         }
   1036         _VtxCurrentIdx += (ImDrawIdx)vtx_count;
   1037     }
   1038 }
   1039 
   1040 void ImDrawList::_PathArcToFastEx(const ImVec2& center, float radius, int a_min_sample, int a_max_sample, int a_step)
   1041 {
   1042     if (radius <= 0.0f)
   1043     {
   1044         _Path.push_back(center);
   1045         return;
   1046     }
   1047 
   1048     // Calculate arc auto segment step size
   1049     if (a_step <= 0)
   1050         a_step = IM_DRAWLIST_ARCFAST_SAMPLE_MAX / _CalcCircleAutoSegmentCount(radius);
   1051 
   1052     // Make sure we never do steps larger than one quarter of the circle
   1053     a_step = ImClamp(a_step, 1, IM_DRAWLIST_ARCFAST_TABLE_SIZE / 4);
   1054 
   1055     const int sample_range = ImAbs(a_max_sample - a_min_sample);
   1056     const int a_next_step = a_step;
   1057 
   1058     int samples = sample_range + 1;
   1059     bool extra_max_sample = false;
   1060     if (a_step > 1)
   1061     {
   1062         samples            = sample_range / a_step + 1;
   1063         const int overstep = sample_range % a_step;
   1064 
   1065         if (overstep > 0)
   1066         {
   1067             extra_max_sample = true;
   1068             samples++;
   1069 
   1070             // When we have overstep to avoid awkwardly looking one long line and one tiny one at the end,
   1071             // distribute first step range evenly between them by reducing first step size.
   1072             if (sample_range > 0)
   1073                 a_step -= (a_step - overstep) / 2;
   1074         }
   1075     }
   1076 
   1077     _Path.resize(_Path.Size + samples);
   1078     ImVec2* out_ptr = _Path.Data + (_Path.Size - samples);
   1079 
   1080     int sample_index = a_min_sample;
   1081     if (sample_index < 0 || sample_index >= IM_DRAWLIST_ARCFAST_SAMPLE_MAX)
   1082     {
   1083         sample_index = sample_index % IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
   1084         if (sample_index < 0)
   1085             sample_index += IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
   1086     }
   1087 
   1088     if (a_max_sample >= a_min_sample)
   1089     {
   1090         for (int a = a_min_sample; a <= a_max_sample; a += a_step, sample_index += a_step, a_step = a_next_step)
   1091         {
   1092             // a_step is clamped to IM_DRAWLIST_ARCFAST_SAMPLE_MAX, so we have guaranteed that it will not wrap over range twice or more
   1093             if (sample_index >= IM_DRAWLIST_ARCFAST_SAMPLE_MAX)
   1094                 sample_index -= IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
   1095 
   1096             const ImVec2 s = _Data->ArcFastVtx[sample_index];
   1097             out_ptr->x = center.x + s.x * radius;
   1098             out_ptr->y = center.y + s.y * radius;
   1099             out_ptr++;
   1100         }
   1101     }
   1102     else
   1103     {
   1104         for (int a = a_min_sample; a >= a_max_sample; a -= a_step, sample_index -= a_step, a_step = a_next_step)
   1105         {
   1106             // a_step is clamped to IM_DRAWLIST_ARCFAST_SAMPLE_MAX, so we have guaranteed that it will not wrap over range twice or more
   1107             if (sample_index < 0)
   1108                 sample_index += IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
   1109 
   1110             const ImVec2 s = _Data->ArcFastVtx[sample_index];
   1111             out_ptr->x = center.x + s.x * radius;
   1112             out_ptr->y = center.y + s.y * radius;
   1113             out_ptr++;
   1114         }
   1115     }
   1116 
   1117     if (extra_max_sample)
   1118     {
   1119         int normalized_max_sample = a_max_sample % IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
   1120         if (normalized_max_sample < 0)
   1121             normalized_max_sample += IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
   1122 
   1123         const ImVec2 s = _Data->ArcFastVtx[normalized_max_sample];
   1124         out_ptr->x = center.x + s.x * radius;
   1125         out_ptr->y = center.y + s.y * radius;
   1126         out_ptr++;
   1127     }
   1128 
   1129     IM_ASSERT_PARANOID(_Path.Data + _Path.Size == out_ptr);
   1130 }
   1131 
   1132 void ImDrawList::_PathArcToN(const ImVec2& center, float radius, float a_min, float a_max, int num_segments)
   1133 {
   1134     if (radius <= 0.0f)
   1135     {
   1136         _Path.push_back(center);
   1137         return;
   1138     }
   1139 
   1140     // Note that we are adding a point at both a_min and a_max.
   1141     // If you are trying to draw a full closed circle you don't want the overlapping points!
   1142     _Path.reserve(_Path.Size + (num_segments + 1));
   1143     for (int i = 0; i <= num_segments; i++)
   1144     {
   1145         const float a = a_min + ((float)i / (float)num_segments) * (a_max - a_min);
   1146         _Path.push_back(ImVec2(center.x + ImCos(a) * radius, center.y + ImSin(a) * radius));
   1147     }
   1148 }
   1149 
   1150 // 0: East, 3: South, 6: West, 9: North, 12: East
   1151 void ImDrawList::PathArcToFast(const ImVec2& center, float radius, int a_min_of_12, int a_max_of_12)
   1152 {
   1153     if (radius <= 0.0f)
   1154     {
   1155         _Path.push_back(center);
   1156         return;
   1157     }
   1158     _PathArcToFastEx(center, radius, a_min_of_12 * IM_DRAWLIST_ARCFAST_SAMPLE_MAX / 12, a_max_of_12 * IM_DRAWLIST_ARCFAST_SAMPLE_MAX / 12, 0);
   1159 }
   1160 
   1161 void ImDrawList::PathArcTo(const ImVec2& center, float radius, float a_min, float a_max, int num_segments)
   1162 {
   1163     if (radius <= 0.0f)
   1164     {
   1165         _Path.push_back(center);
   1166         return;
   1167     }
   1168 
   1169     if (num_segments > 0)
   1170     {
   1171         _PathArcToN(center, radius, a_min, a_max, num_segments);
   1172         return;
   1173     }
   1174 
   1175     // Automatic segment count
   1176     if (radius <= _Data->ArcFastRadiusCutoff)
   1177     {
   1178         const bool a_is_reverse = a_max < a_min;
   1179 
   1180         // We are going to use precomputed values for mid samples.
   1181         // Determine first and last sample in lookup table that belong to the arc.
   1182         const float a_min_sample_f = IM_DRAWLIST_ARCFAST_SAMPLE_MAX * a_min / (IM_PI * 2.0f);
   1183         const float a_max_sample_f = IM_DRAWLIST_ARCFAST_SAMPLE_MAX * a_max / (IM_PI * 2.0f);
   1184 
   1185         const int a_min_sample = a_is_reverse ? (int)ImFloorSigned(a_min_sample_f) : (int)ImCeil(a_min_sample_f);
   1186         const int a_max_sample = a_is_reverse ? (int)ImCeil(a_max_sample_f) : (int)ImFloorSigned(a_max_sample_f);
   1187         const int a_mid_samples = a_is_reverse ? ImMax(a_min_sample - a_max_sample, 0) : ImMax(a_max_sample - a_min_sample, 0);
   1188 
   1189         const float a_min_segment_angle = a_min_sample * IM_PI * 2.0f / IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
   1190         const float a_max_segment_angle = a_max_sample * IM_PI * 2.0f / IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
   1191         const bool a_emit_start = (a_min_segment_angle - a_min) != 0.0f;
   1192         const bool a_emit_end = (a_max - a_max_segment_angle) != 0.0f;
   1193 
   1194         _Path.reserve(_Path.Size + (a_mid_samples + 1 + (a_emit_start ? 1 : 0) + (a_emit_end ? 1 : 0)));
   1195         if (a_emit_start)
   1196             _Path.push_back(ImVec2(center.x + ImCos(a_min) * radius, center.y + ImSin(a_min) * radius));
   1197         if (a_mid_samples > 0)
   1198             _PathArcToFastEx(center, radius, a_min_sample, a_max_sample, 0);
   1199         if (a_emit_end)
   1200             _Path.push_back(ImVec2(center.x + ImCos(a_max) * radius, center.y + ImSin(a_max) * radius));
   1201     }
   1202     else
   1203     {
   1204         const float arc_length = ImAbs(a_max - a_min);
   1205         const int circle_segment_count = _CalcCircleAutoSegmentCount(radius);
   1206         const int arc_segment_count = ImMax((int)ImCeil(circle_segment_count * arc_length / (IM_PI * 2.0f)), (int)(2.0f * IM_PI / arc_length));
   1207         _PathArcToN(center, radius, a_min, a_max, arc_segment_count);
   1208     }
   1209 }
   1210 
   1211 ImVec2 ImBezierCubicCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, float t)
   1212 {
   1213     float u = 1.0f - t;
   1214     float w1 = u * u * u;
   1215     float w2 = 3 * u * u * t;
   1216     float w3 = 3 * u * t * t;
   1217     float w4 = t * t * t;
   1218     return 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);
   1219 }
   1220 
   1221 ImVec2 ImBezierQuadraticCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float t)
   1222 {
   1223     float u = 1.0f - t;
   1224     float w1 = u * u;
   1225     float w2 = 2 * u * t;
   1226     float w3 = t * t;
   1227     return ImVec2(w1 * p1.x + w2 * p2.x + w3 * p3.x, w1 * p1.y + w2 * p2.y + w3 * p3.y);
   1228 }
   1229 
   1230 // Closely mimics ImBezierCubicClosestPointCasteljau() in imgui.cpp
   1231 static void PathBezierCubicCurveToCasteljau(ImVector<ImVec2>* path, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float tess_tol, int level)
   1232 {
   1233     float dx = x4 - x1;
   1234     float dy = y4 - y1;
   1235     float d2 = (x2 - x4) * dy - (y2 - y4) * dx;
   1236     float d3 = (x3 - x4) * dy - (y3 - y4) * dx;
   1237     d2 = (d2 >= 0) ? d2 : -d2;
   1238     d3 = (d3 >= 0) ? d3 : -d3;
   1239     if ((d2 + d3) * (d2 + d3) < tess_tol * (dx * dx + dy * dy))
   1240     {
   1241         path->push_back(ImVec2(x4, y4));
   1242     }
   1243     else if (level < 10)
   1244     {
   1245         float x12 = (x1 + x2) * 0.5f, y12 = (y1 + y2) * 0.5f;
   1246         float x23 = (x2 + x3) * 0.5f, y23 = (y2 + y3) * 0.5f;
   1247         float x34 = (x3 + x4) * 0.5f, y34 = (y3 + y4) * 0.5f;
   1248         float x123 = (x12 + x23) * 0.5f, y123 = (y12 + y23) * 0.5f;
   1249         float x234 = (x23 + x34) * 0.5f, y234 = (y23 + y34) * 0.5f;
   1250         float x1234 = (x123 + x234) * 0.5f, y1234 = (y123 + y234) * 0.5f;
   1251         PathBezierCubicCurveToCasteljau(path, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1);
   1252         PathBezierCubicCurveToCasteljau(path, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1);
   1253     }
   1254 }
   1255 
   1256 static void PathBezierQuadraticCurveToCasteljau(ImVector<ImVec2>* path, float x1, float y1, float x2, float y2, float x3, float y3, float tess_tol, int level)
   1257 {
   1258     float dx = x3 - x1, dy = y3 - y1;
   1259     float det = (x2 - x3) * dy - (y2 - y3) * dx;
   1260     if (det * det * 4.0f < tess_tol * (dx * dx + dy * dy))
   1261     {
   1262         path->push_back(ImVec2(x3, y3));
   1263     }
   1264     else if (level < 10)
   1265     {
   1266         float x12 = (x1 + x2) * 0.5f, y12 = (y1 + y2) * 0.5f;
   1267         float x23 = (x2 + x3) * 0.5f, y23 = (y2 + y3) * 0.5f;
   1268         float x123 = (x12 + x23) * 0.5f, y123 = (y12 + y23) * 0.5f;
   1269         PathBezierQuadraticCurveToCasteljau(path, x1, y1, x12, y12, x123, y123, tess_tol, level + 1);
   1270         PathBezierQuadraticCurveToCasteljau(path, x123, y123, x23, y23, x3, y3, tess_tol, level + 1);
   1271     }
   1272 }
   1273 
   1274 void ImDrawList::PathBezierCubicCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments)
   1275 {
   1276     ImVec2 p1 = _Path.back();
   1277     if (num_segments == 0)
   1278     {
   1279         PathBezierCubicCurveToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, _Data->CurveTessellationTol, 0); // Auto-tessellated
   1280     }
   1281     else
   1282     {
   1283         float t_step = 1.0f / (float)num_segments;
   1284         for (int i_step = 1; i_step <= num_segments; i_step++)
   1285             _Path.push_back(ImBezierCubicCalc(p1, p2, p3, p4, t_step * i_step));
   1286     }
   1287 }
   1288 
   1289 void ImDrawList::PathBezierQuadraticCurveTo(const ImVec2& p2, const ImVec2& p3, int num_segments)
   1290 {
   1291     ImVec2 p1 = _Path.back();
   1292     if (num_segments == 0)
   1293     {
   1294         PathBezierQuadraticCurveToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, _Data->CurveTessellationTol, 0);// Auto-tessellated
   1295     }
   1296     else
   1297     {
   1298         float t_step = 1.0f / (float)num_segments;
   1299         for (int i_step = 1; i_step <= num_segments; i_step++)
   1300             _Path.push_back(ImBezierQuadraticCalc(p1, p2, p3, t_step * i_step));
   1301     }
   1302 }
   1303 
   1304 IM_STATIC_ASSERT(ImDrawFlags_RoundCornersTopLeft == (1 << 4));
   1305 static inline ImDrawFlags FixRectCornerFlags(ImDrawFlags flags)
   1306 {
   1307 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
   1308     // Legacy Support for hard coded ~0 (used to be a suggested equivalent to ImDrawCornerFlags_All)
   1309     //   ~0   --> ImDrawFlags_RoundCornersAll or 0
   1310     if (flags == ~0)
   1311         return ImDrawFlags_RoundCornersAll;
   1312 
   1313     // Legacy Support for hard coded 0x01 to 0x0F (matching 15 out of 16 old flags combinations)
   1314     //   0x01 --> ImDrawFlags_RoundCornersTopLeft (VALUE 0x01 OVERLAPS ImDrawFlags_Closed but ImDrawFlags_Closed is never valid in this path!)
   1315     //   0x02 --> ImDrawFlags_RoundCornersTopRight
   1316     //   0x03 --> ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight
   1317     //   0x04 --> ImDrawFlags_RoundCornersBotLeft
   1318     //   0x05 --> ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersBotLeft
   1319     //   ...
   1320     //   0x0F --> ImDrawFlags_RoundCornersAll or 0
   1321     // (See all values in ImDrawCornerFlags_)
   1322     if (flags >= 0x01 && flags <= 0x0F)
   1323         return (flags << 4);
   1324 
   1325     // We cannot support hard coded 0x00 with 'float rounding > 0.0f' --> replace with ImDrawFlags_RoundCornersNone or use 'float rounding = 0.0f'
   1326 #endif
   1327 
   1328     // If this triggers, please update your code replacing hardcoded values with new ImDrawFlags_RoundCorners* values.
   1329     // Note that ImDrawFlags_Closed (== 0x01) is an invalid flag for AddRect(), AddRectFilled(), PathRect() etc...
   1330     IM_ASSERT((flags & 0x0F) == 0 && "Misuse of legacy hardcoded ImDrawCornerFlags values!");
   1331 
   1332     if ((flags & ImDrawFlags_RoundCornersMask_) == 0)
   1333         flags |= ImDrawFlags_RoundCornersAll;
   1334 
   1335     return flags;
   1336 }
   1337 
   1338 void ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, ImDrawFlags flags)
   1339 {
   1340     flags = FixRectCornerFlags(flags);
   1341     rounding = ImMin(rounding, ImFabs(b.x - a.x) * ( ((flags & ImDrawFlags_RoundCornersTop)  == ImDrawFlags_RoundCornersTop)  || ((flags & ImDrawFlags_RoundCornersBottom) == ImDrawFlags_RoundCornersBottom) ? 0.5f : 1.0f ) - 1.0f);
   1342     rounding = ImMin(rounding, ImFabs(b.y - a.y) * ( ((flags & ImDrawFlags_RoundCornersLeft) == ImDrawFlags_RoundCornersLeft) || ((flags & ImDrawFlags_RoundCornersRight)  == ImDrawFlags_RoundCornersRight)  ? 0.5f : 1.0f ) - 1.0f);
   1343 
   1344     if (rounding <= 0.0f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone)
   1345     {
   1346         PathLineTo(a);
   1347         PathLineTo(ImVec2(b.x, a.y));
   1348         PathLineTo(b);
   1349         PathLineTo(ImVec2(a.x, b.y));
   1350     }
   1351     else
   1352     {
   1353         const float rounding_tl = (flags & ImDrawFlags_RoundCornersTopLeft)     ? rounding : 0.0f;
   1354         const float rounding_tr = (flags & ImDrawFlags_RoundCornersTopRight)    ? rounding : 0.0f;
   1355         const float rounding_br = (flags & ImDrawFlags_RoundCornersBottomRight) ? rounding : 0.0f;
   1356         const float rounding_bl = (flags & ImDrawFlags_RoundCornersBottomLeft)  ? rounding : 0.0f;
   1357         PathArcToFast(ImVec2(a.x + rounding_tl, a.y + rounding_tl), rounding_tl, 6, 9);
   1358         PathArcToFast(ImVec2(b.x - rounding_tr, a.y + rounding_tr), rounding_tr, 9, 12);
   1359         PathArcToFast(ImVec2(b.x - rounding_br, b.y - rounding_br), rounding_br, 0, 3);
   1360         PathArcToFast(ImVec2(a.x + rounding_bl, b.y - rounding_bl), rounding_bl, 3, 6);
   1361     }
   1362 }
   1363 
   1364 void ImDrawList::AddLine(const ImVec2& p1, const ImVec2& p2, ImU32 col, float thickness)
   1365 {
   1366     if ((col & IM_COL32_A_MASK) == 0)
   1367         return;
   1368     PathLineTo(p1 + ImVec2(0.5f, 0.5f));
   1369     PathLineTo(p2 + ImVec2(0.5f, 0.5f));
   1370     PathStroke(col, 0, thickness);
   1371 }
   1372 
   1373 // p_min = upper-left, p_max = lower-right
   1374 // Note we don't render 1 pixels sized rectangles properly.
   1375 void ImDrawList::AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, ImDrawFlags flags, float thickness)
   1376 {
   1377     if ((col & IM_COL32_A_MASK) == 0)
   1378         return;
   1379     if (Flags & ImDrawListFlags_AntiAliasedLines)
   1380         PathRect(p_min + ImVec2(0.50f, 0.50f), p_max - ImVec2(0.50f, 0.50f), rounding, flags);
   1381     else
   1382         PathRect(p_min + ImVec2(0.50f, 0.50f), p_max - ImVec2(0.49f, 0.49f), rounding, flags); // Better looking lower-right corner and rounded non-AA shapes.
   1383     PathStroke(col, ImDrawFlags_Closed, thickness);
   1384 }
   1385 
   1386 void ImDrawList::AddRectFilled(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, ImDrawFlags flags)
   1387 {
   1388     if ((col & IM_COL32_A_MASK) == 0)
   1389         return;
   1390     if (rounding <= 0.0f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone)
   1391     {
   1392         PrimReserve(6, 4);
   1393         PrimRect(p_min, p_max, col);
   1394     }
   1395     else
   1396     {
   1397         PathRect(p_min, p_max, rounding, flags);
   1398         PathFillConvex(col);
   1399     }
   1400 }
   1401 
   1402 // p_min = upper-left, p_max = lower-right
   1403 void ImDrawList::AddRectFilledMultiColor(const ImVec2& p_min, const ImVec2& p_max, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left)
   1404 {
   1405     if (((col_upr_left | col_upr_right | col_bot_right | col_bot_left) & IM_COL32_A_MASK) == 0)
   1406         return;
   1407 
   1408     const ImVec2 uv = _Data->TexUvWhitePixel;
   1409     PrimReserve(6, 4);
   1410     PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 1)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 2));
   1411     PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 2)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 3));
   1412     PrimWriteVtx(p_min, uv, col_upr_left);
   1413     PrimWriteVtx(ImVec2(p_max.x, p_min.y), uv, col_upr_right);
   1414     PrimWriteVtx(p_max, uv, col_bot_right);
   1415     PrimWriteVtx(ImVec2(p_min.x, p_max.y), uv, col_bot_left);
   1416 }
   1417 
   1418 void ImDrawList::AddQuad(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness)
   1419 {
   1420     if ((col & IM_COL32_A_MASK) == 0)
   1421         return;
   1422 
   1423     PathLineTo(p1);
   1424     PathLineTo(p2);
   1425     PathLineTo(p3);
   1426     PathLineTo(p4);
   1427     PathStroke(col, ImDrawFlags_Closed, thickness);
   1428 }
   1429 
   1430 void ImDrawList::AddQuadFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col)
   1431 {
   1432     if ((col & IM_COL32_A_MASK) == 0)
   1433         return;
   1434 
   1435     PathLineTo(p1);
   1436     PathLineTo(p2);
   1437     PathLineTo(p3);
   1438     PathLineTo(p4);
   1439     PathFillConvex(col);
   1440 }
   1441 
   1442 void ImDrawList::AddTriangle(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness)
   1443 {
   1444     if ((col & IM_COL32_A_MASK) == 0)
   1445         return;
   1446 
   1447     PathLineTo(p1);
   1448     PathLineTo(p2);
   1449     PathLineTo(p3);
   1450     PathStroke(col, ImDrawFlags_Closed, thickness);
   1451 }
   1452 
   1453 void ImDrawList::AddTriangleFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col)
   1454 {
   1455     if ((col & IM_COL32_A_MASK) == 0)
   1456         return;
   1457 
   1458     PathLineTo(p1);
   1459     PathLineTo(p2);
   1460     PathLineTo(p3);
   1461     PathFillConvex(col);
   1462 }
   1463 
   1464 void ImDrawList::AddCircle(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness)
   1465 {
   1466     if ((col & IM_COL32_A_MASK) == 0 || radius <= 0.0f)
   1467         return;
   1468 
   1469     // Obtain segment count
   1470     if (num_segments <= 0)
   1471     {
   1472         // Automatic segment count
   1473         num_segments = _CalcCircleAutoSegmentCount(radius);
   1474     }
   1475     else
   1476     {
   1477         // Explicit segment count (still clamp to avoid drawing insanely tessellated shapes)
   1478         num_segments = ImClamp(num_segments, 3, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX);
   1479     }
   1480 
   1481     // Because we are filling a closed shape we remove 1 from the count of segments/points
   1482     const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments;
   1483     if (num_segments == 12)
   1484         PathArcToFast(center, radius - 0.5f, 0, 12 - 1);
   1485     else
   1486         PathArcTo(center, radius - 0.5f, 0.0f, a_max, num_segments - 1);
   1487     PathStroke(col, ImDrawFlags_Closed, thickness);
   1488 }
   1489 
   1490 void ImDrawList::AddCircleFilled(const ImVec2& center, float radius, ImU32 col, int num_segments)
   1491 {
   1492     if ((col & IM_COL32_A_MASK) == 0 || radius <= 0.0f)
   1493         return;
   1494 
   1495     // Obtain segment count
   1496     if (num_segments <= 0)
   1497     {
   1498         // Automatic segment count
   1499         num_segments = _CalcCircleAutoSegmentCount(radius);
   1500     }
   1501     else
   1502     {
   1503         // Explicit segment count (still clamp to avoid drawing insanely tessellated shapes)
   1504         num_segments = ImClamp(num_segments, 3, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX);
   1505     }
   1506 
   1507     // Because we are filling a closed shape we remove 1 from the count of segments/points
   1508     const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments;
   1509     if (num_segments == 12)
   1510         PathArcToFast(center, radius, 0, 12 - 1);
   1511     else
   1512         PathArcTo(center, radius, 0.0f, a_max, num_segments - 1);
   1513     PathFillConvex(col);
   1514 }
   1515 
   1516 // Guaranteed to honor 'num_segments'
   1517 void ImDrawList::AddNgon(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness)
   1518 {
   1519     if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2)
   1520         return;
   1521 
   1522     // Because we are filling a closed shape we remove 1 from the count of segments/points
   1523     const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments;
   1524     PathArcTo(center, radius - 0.5f, 0.0f, a_max, num_segments - 1);
   1525     PathStroke(col, ImDrawFlags_Closed, thickness);
   1526 }
   1527 
   1528 // Guaranteed to honor 'num_segments'
   1529 void ImDrawList::AddNgonFilled(const ImVec2& center, float radius, ImU32 col, int num_segments)
   1530 {
   1531     if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2)
   1532         return;
   1533 
   1534     // Because we are filling a closed shape we remove 1 from the count of segments/points
   1535     const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments;
   1536     PathArcTo(center, radius, 0.0f, a_max, num_segments - 1);
   1537     PathFillConvex(col);
   1538 }
   1539 
   1540 // Cubic Bezier takes 4 controls points
   1541 void ImDrawList::AddBezierCubic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments)
   1542 {
   1543     if ((col & IM_COL32_A_MASK) == 0)
   1544         return;
   1545 
   1546     PathLineTo(p1);
   1547     PathBezierCubicCurveTo(p2, p3, p4, num_segments);
   1548     PathStroke(col, 0, thickness);
   1549 }
   1550 
   1551 // Quadratic Bezier takes 3 controls points
   1552 void ImDrawList::AddBezierQuadratic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness, int num_segments)
   1553 {
   1554     if ((col & IM_COL32_A_MASK) == 0)
   1555         return;
   1556 
   1557     PathLineTo(p1);
   1558     PathBezierQuadraticCurveTo(p2, p3, num_segments);
   1559     PathStroke(col, 0, thickness);
   1560 }
   1561 
   1562 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)
   1563 {
   1564     if ((col & IM_COL32_A_MASK) == 0)
   1565         return;
   1566 
   1567     if (text_end == NULL)
   1568         text_end = text_begin + strlen(text_begin);
   1569     if (text_begin == text_end)
   1570         return;
   1571 
   1572     // Pull default font/size from the shared ImDrawListSharedData instance
   1573     if (font == NULL)
   1574         font = _Data->Font;
   1575     if (font_size == 0.0f)
   1576         font_size = _Data->FontSize;
   1577 
   1578     IM_ASSERT(font->ContainerAtlas->TexID == _CmdHeader.TextureId);  // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font.
   1579 
   1580     ImVec4 clip_rect = _CmdHeader.ClipRect;
   1581     if (cpu_fine_clip_rect)
   1582     {
   1583         clip_rect.x = ImMax(clip_rect.x, cpu_fine_clip_rect->x);
   1584         clip_rect.y = ImMax(clip_rect.y, cpu_fine_clip_rect->y);
   1585         clip_rect.z = ImMin(clip_rect.z, cpu_fine_clip_rect->z);
   1586         clip_rect.w = ImMin(clip_rect.w, cpu_fine_clip_rect->w);
   1587     }
   1588     font->RenderText(this, font_size, pos, col, clip_rect, text_begin, text_end, wrap_width, cpu_fine_clip_rect != NULL);
   1589 }
   1590 
   1591 void ImDrawList::AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end)
   1592 {
   1593     AddText(NULL, 0.0f, pos, col, text_begin, text_end);
   1594 }
   1595 
   1596 void ImDrawList::AddImage(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col)
   1597 {
   1598     if ((col & IM_COL32_A_MASK) == 0)
   1599         return;
   1600 
   1601     const bool push_texture_id = user_texture_id != _CmdHeader.TextureId;
   1602     if (push_texture_id)
   1603         PushTextureID(user_texture_id);
   1604 
   1605     PrimReserve(6, 4);
   1606     PrimRectUV(p_min, p_max, uv_min, uv_max, col);
   1607 
   1608     if (push_texture_id)
   1609         PopTextureID();
   1610 }
   1611 
   1612 void ImDrawList::AddImageQuad(ImTextureID user_texture_id, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& uv1, const ImVec2& uv2, const ImVec2& uv3, const ImVec2& uv4, ImU32 col)
   1613 {
   1614     if ((col & IM_COL32_A_MASK) == 0)
   1615         return;
   1616 
   1617     const bool push_texture_id = user_texture_id != _CmdHeader.TextureId;
   1618     if (push_texture_id)
   1619         PushTextureID(user_texture_id);
   1620 
   1621     PrimReserve(6, 4);
   1622     PrimQuadUV(p1, p2, p3, p4, uv1, uv2, uv3, uv4, col);
   1623 
   1624     if (push_texture_id)
   1625         PopTextureID();
   1626 }
   1627 
   1628 void ImDrawList::AddImageRounded(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col, float rounding, ImDrawFlags flags)
   1629 {
   1630     if ((col & IM_COL32_A_MASK) == 0)
   1631         return;
   1632 
   1633     flags = FixRectCornerFlags(flags);
   1634     if (rounding <= 0.0f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone)
   1635     {
   1636         AddImage(user_texture_id, p_min, p_max, uv_min, uv_max, col);
   1637         return;
   1638     }
   1639 
   1640     const bool push_texture_id = user_texture_id != _CmdHeader.TextureId;
   1641     if (push_texture_id)
   1642         PushTextureID(user_texture_id);
   1643 
   1644     int vert_start_idx = VtxBuffer.Size;
   1645     PathRect(p_min, p_max, rounding, flags);
   1646     PathFillConvex(col);
   1647     int vert_end_idx = VtxBuffer.Size;
   1648     ImGui::ShadeVertsLinearUV(this, vert_start_idx, vert_end_idx, p_min, p_max, uv_min, uv_max, true);
   1649 
   1650     if (push_texture_id)
   1651         PopTextureID();
   1652 }
   1653 
   1654 
   1655 //-----------------------------------------------------------------------------
   1656 // [SECTION] ImDrawListSplitter
   1657 //-----------------------------------------------------------------------------
   1658 // FIXME: This may be a little confusing, trying to be a little too low-level/optimal instead of just doing vector swap..
   1659 //-----------------------------------------------------------------------------
   1660 
   1661 void ImDrawListSplitter::ClearFreeMemory()
   1662 {
   1663     for (int i = 0; i < _Channels.Size; i++)
   1664     {
   1665         if (i == _Current)
   1666             memset(&_Channels[i], 0, sizeof(_Channels[i]));  // Current channel is a copy of CmdBuffer/IdxBuffer, don't destruct again
   1667         _Channels[i]._CmdBuffer.clear();
   1668         _Channels[i]._IdxBuffer.clear();
   1669     }
   1670     _Current = 0;
   1671     _Count = 1;
   1672     _Channels.clear();
   1673 }
   1674 
   1675 void ImDrawListSplitter::Split(ImDrawList* draw_list, int channels_count)
   1676 {
   1677     IM_UNUSED(draw_list);
   1678     IM_ASSERT(_Current == 0 && _Count <= 1 && "Nested channel splitting is not supported. Please use separate instances of ImDrawListSplitter.");
   1679     int old_channels_count = _Channels.Size;
   1680     if (old_channels_count < channels_count)
   1681     {
   1682         _Channels.reserve(channels_count); // Avoid over reserving since this is likely to stay stable
   1683         _Channels.resize(channels_count);
   1684     }
   1685     _Count = channels_count;
   1686 
   1687     // Channels[] (24/32 bytes each) hold storage that we'll swap with draw_list->_CmdBuffer/_IdxBuffer
   1688     // 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.
   1689     // When we switch to the next channel, we'll copy draw_list->_CmdBuffer/_IdxBuffer into Channels[0] and then Channels[1] into draw_list->CmdBuffer/_IdxBuffer
   1690     memset(&_Channels[0], 0, sizeof(ImDrawChannel));
   1691     for (int i = 1; i < channels_count; i++)
   1692     {
   1693         if (i >= old_channels_count)
   1694         {
   1695             IM_PLACEMENT_NEW(&_Channels[i]) ImDrawChannel();
   1696         }
   1697         else
   1698         {
   1699             _Channels[i]._CmdBuffer.resize(0);
   1700             _Channels[i]._IdxBuffer.resize(0);
   1701         }
   1702     }
   1703 }
   1704 
   1705 void ImDrawListSplitter::Merge(ImDrawList* draw_list)
   1706 {
   1707     // 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.
   1708     if (_Count <= 1)
   1709         return;
   1710 
   1711     SetCurrentChannel(draw_list, 0);
   1712     draw_list->_PopUnusedDrawCmd();
   1713 
   1714     // Calculate our final buffer sizes. Also fix the incorrect IdxOffset values in each command.
   1715     int new_cmd_buffer_count = 0;
   1716     int new_idx_buffer_count = 0;
   1717     ImDrawCmd* last_cmd = (_Count > 0 && draw_list->CmdBuffer.Size > 0) ? &draw_list->CmdBuffer.back() : NULL;
   1718     int idx_offset = last_cmd ? last_cmd->IdxOffset + last_cmd->ElemCount : 0;
   1719     for (int i = 1; i < _Count; i++)
   1720     {
   1721         ImDrawChannel& ch = _Channels[i];
   1722 
   1723         // Equivalent of PopUnusedDrawCmd() for this channel's cmdbuffer and except we don't need to test for UserCallback.
   1724         if (ch._CmdBuffer.Size > 0 && ch._CmdBuffer.back().ElemCount == 0)
   1725             ch._CmdBuffer.pop_back();
   1726 
   1727         if (ch._CmdBuffer.Size > 0 && last_cmd != NULL)
   1728         {
   1729             ImDrawCmd* next_cmd = &ch._CmdBuffer[0];
   1730             if (ImDrawCmd_HeaderCompare(last_cmd, next_cmd) == 0 && last_cmd->UserCallback == NULL && next_cmd->UserCallback == NULL)
   1731             {
   1732                 // Merge previous channel last draw command with current channel first draw command if matching.
   1733                 last_cmd->ElemCount += next_cmd->ElemCount;
   1734                 idx_offset += next_cmd->ElemCount;
   1735                 ch._CmdBuffer.erase(ch._CmdBuffer.Data); // FIXME-OPT: Improve for multiple merges.
   1736             }
   1737         }
   1738         if (ch._CmdBuffer.Size > 0)
   1739             last_cmd = &ch._CmdBuffer.back();
   1740         new_cmd_buffer_count += ch._CmdBuffer.Size;
   1741         new_idx_buffer_count += ch._IdxBuffer.Size;
   1742         for (int cmd_n = 0; cmd_n < ch._CmdBuffer.Size; cmd_n++)
   1743         {
   1744             ch._CmdBuffer.Data[cmd_n].IdxOffset = idx_offset;
   1745             idx_offset += ch._CmdBuffer.Data[cmd_n].ElemCount;
   1746         }
   1747     }
   1748     draw_list->CmdBuffer.resize(draw_list->CmdBuffer.Size + new_cmd_buffer_count);
   1749     draw_list->IdxBuffer.resize(draw_list->IdxBuffer.Size + new_idx_buffer_count);
   1750 
   1751     // Write commands and indices in order (they are fairly small structures, we don't copy vertices only indices)
   1752     ImDrawCmd* cmd_write = draw_list->CmdBuffer.Data + draw_list->CmdBuffer.Size - new_cmd_buffer_count;
   1753     ImDrawIdx* idx_write = draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size - new_idx_buffer_count;
   1754     for (int i = 1; i < _Count; i++)
   1755     {
   1756         ImDrawChannel& ch = _Channels[i];
   1757         if (int sz = ch._CmdBuffer.Size) { memcpy(cmd_write, ch._CmdBuffer.Data, sz * sizeof(ImDrawCmd)); cmd_write += sz; }
   1758         if (int sz = ch._IdxBuffer.Size) { memcpy(idx_write, ch._IdxBuffer.Data, sz * sizeof(ImDrawIdx)); idx_write += sz; }
   1759     }
   1760     draw_list->_IdxWritePtr = idx_write;
   1761 
   1762     // Ensure there's always a non-callback draw command trailing the command-buffer
   1763     if (draw_list->CmdBuffer.Size == 0 || draw_list->CmdBuffer.back().UserCallback != NULL)
   1764         draw_list->AddDrawCmd();
   1765 
   1766     // If current command is used with different settings we need to add a new command
   1767     ImDrawCmd* curr_cmd = &draw_list->CmdBuffer.Data[draw_list->CmdBuffer.Size - 1];
   1768     if (curr_cmd->ElemCount == 0)
   1769         ImDrawCmd_HeaderCopy(curr_cmd, &draw_list->_CmdHeader); // Copy ClipRect, TextureId, VtxOffset
   1770     else if (ImDrawCmd_HeaderCompare(curr_cmd, &draw_list->_CmdHeader) != 0)
   1771         draw_list->AddDrawCmd();
   1772 
   1773     _Count = 1;
   1774 }
   1775 
   1776 void ImDrawListSplitter::SetCurrentChannel(ImDrawList* draw_list, int idx)
   1777 {
   1778     IM_ASSERT(idx >= 0 && idx < _Count);
   1779     if (_Current == idx)
   1780         return;
   1781 
   1782     // Overwrite ImVector (12/16 bytes), four times. This is merely a silly optimization instead of doing .swap()
   1783     memcpy(&_Channels.Data[_Current]._CmdBuffer, &draw_list->CmdBuffer, sizeof(draw_list->CmdBuffer));
   1784     memcpy(&_Channels.Data[_Current]._IdxBuffer, &draw_list->IdxBuffer, sizeof(draw_list->IdxBuffer));
   1785     _Current = idx;
   1786     memcpy(&draw_list->CmdBuffer, &_Channels.Data[idx]._CmdBuffer, sizeof(draw_list->CmdBuffer));
   1787     memcpy(&draw_list->IdxBuffer, &_Channels.Data[idx]._IdxBuffer, sizeof(draw_list->IdxBuffer));
   1788     draw_list->_IdxWritePtr = draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size;
   1789 
   1790     // If current command is used with different settings we need to add a new command
   1791     ImDrawCmd* curr_cmd = (draw_list->CmdBuffer.Size == 0) ? NULL : &draw_list->CmdBuffer.Data[draw_list->CmdBuffer.Size - 1];
   1792     if (curr_cmd == NULL)
   1793         draw_list->AddDrawCmd();
   1794     else if (curr_cmd->ElemCount == 0)
   1795         ImDrawCmd_HeaderCopy(curr_cmd, &draw_list->_CmdHeader); // Copy ClipRect, TextureId, VtxOffset
   1796     else if (ImDrawCmd_HeaderCompare(curr_cmd, &draw_list->_CmdHeader) != 0)
   1797         draw_list->AddDrawCmd();
   1798 }
   1799 
   1800 //-----------------------------------------------------------------------------
   1801 // [SECTION] ImDrawData
   1802 //-----------------------------------------------------------------------------
   1803 
   1804 // 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!
   1805 void ImDrawData::DeIndexAllBuffers()
   1806 {
   1807     ImVector<ImDrawVert> new_vtx_buffer;
   1808     TotalVtxCount = TotalIdxCount = 0;
   1809     for (int i = 0; i < CmdListsCount; i++)
   1810     {
   1811         ImDrawList* cmd_list = CmdLists[i];
   1812         if (cmd_list->IdxBuffer.empty())
   1813             continue;
   1814         new_vtx_buffer.resize(cmd_list->IdxBuffer.Size);
   1815         for (int j = 0; j < cmd_list->IdxBuffer.Size; j++)
   1816             new_vtx_buffer[j] = cmd_list->VtxBuffer[cmd_list->IdxBuffer[j]];
   1817         cmd_list->VtxBuffer.swap(new_vtx_buffer);
   1818         cmd_list->IdxBuffer.resize(0);
   1819         TotalVtxCount += cmd_list->VtxBuffer.Size;
   1820     }
   1821 }
   1822 
   1823 // Helper to scale the ClipRect field of each ImDrawCmd.
   1824 // Use if your final output buffer is at a different scale than draw_data->DisplaySize,
   1825 // or if there is a difference between your window resolution and framebuffer resolution.
   1826 void ImDrawData::ScaleClipRects(const ImVec2& fb_scale)
   1827 {
   1828     for (int i = 0; i < CmdListsCount; i++)
   1829     {
   1830         ImDrawList* cmd_list = CmdLists[i];
   1831         for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
   1832         {
   1833             ImDrawCmd* cmd = &cmd_list->CmdBuffer[cmd_i];
   1834             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);
   1835         }
   1836     }
   1837 }
   1838 
   1839 //-----------------------------------------------------------------------------
   1840 // [SECTION] Helpers ShadeVertsXXX functions
   1841 //-----------------------------------------------------------------------------
   1842 
   1843 // Generic linear color gradient, write to RGB fields, leave A untouched.
   1844 void ImGui::ShadeVertsLinearColorGradientKeepAlpha(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1)
   1845 {
   1846     ImVec2 gradient_extent = gradient_p1 - gradient_p0;
   1847     float gradient_inv_length2 = 1.0f / ImLengthSqr(gradient_extent);
   1848     ImDrawVert* vert_start = draw_list->VtxBuffer.Data + vert_start_idx;
   1849     ImDrawVert* vert_end = draw_list->VtxBuffer.Data + vert_end_idx;
   1850     const int col0_r = (int)(col0 >> IM_COL32_R_SHIFT) & 0xFF;
   1851     const int col0_g = (int)(col0 >> IM_COL32_G_SHIFT) & 0xFF;
   1852     const int col0_b = (int)(col0 >> IM_COL32_B_SHIFT) & 0xFF;
   1853     const int col_delta_r = ((int)(col1 >> IM_COL32_R_SHIFT) & 0xFF) - col0_r;
   1854     const int col_delta_g = ((int)(col1 >> IM_COL32_G_SHIFT) & 0xFF) - col0_g;
   1855     const int col_delta_b = ((int)(col1 >> IM_COL32_B_SHIFT) & 0xFF) - col0_b;
   1856     for (ImDrawVert* vert = vert_start; vert < vert_end; vert++)
   1857     {
   1858         float d = ImDot(vert->pos - gradient_p0, gradient_extent);
   1859         float t = ImClamp(d * gradient_inv_length2, 0.0f, 1.0f);
   1860         int r = (int)(col0_r + col_delta_r * t);
   1861         int g = (int)(col0_g + col_delta_g * t);
   1862         int b = (int)(col0_b + col_delta_b * t);
   1863         vert->col = (r << IM_COL32_R_SHIFT) | (g << IM_COL32_G_SHIFT) | (b << IM_COL32_B_SHIFT) | (vert->col & IM_COL32_A_MASK);
   1864     }
   1865 }
   1866 
   1867 // Distribute UV over (a, b) rectangle
   1868 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)
   1869 {
   1870     const ImVec2 size = b - a;
   1871     const ImVec2 uv_size = uv_b - uv_a;
   1872     const ImVec2 scale = ImVec2(
   1873         size.x != 0.0f ? (uv_size.x / size.x) : 0.0f,
   1874         size.y != 0.0f ? (uv_size.y / size.y) : 0.0f);
   1875 
   1876     ImDrawVert* vert_start = draw_list->VtxBuffer.Data + vert_start_idx;
   1877     ImDrawVert* vert_end = draw_list->VtxBuffer.Data + vert_end_idx;
   1878     if (clamp)
   1879     {
   1880         const ImVec2 min = ImMin(uv_a, uv_b);
   1881         const ImVec2 max = ImMax(uv_a, uv_b);
   1882         for (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex)
   1883             vertex->uv = ImClamp(uv_a + ImMul(ImVec2(vertex->pos.x, vertex->pos.y) - a, scale), min, max);
   1884     }
   1885     else
   1886     {
   1887         for (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex)
   1888             vertex->uv = uv_a + ImMul(ImVec2(vertex->pos.x, vertex->pos.y) - a, scale);
   1889     }
   1890 }
   1891 
   1892 //-----------------------------------------------------------------------------
   1893 // [SECTION] ImFontConfig
   1894 //-----------------------------------------------------------------------------
   1895 
   1896 ImFontConfig::ImFontConfig()
   1897 {
   1898     memset(this, 0, sizeof(*this));
   1899     FontDataOwnedByAtlas = true;
   1900     OversampleH = 3; // FIXME: 2 may be a better default?
   1901     OversampleV = 1;
   1902     GlyphMaxAdvanceX = FLT_MAX;
   1903     RasterizerMultiply = 1.0f;
   1904     EllipsisChar = (ImWchar)-1;
   1905 }
   1906 
   1907 //-----------------------------------------------------------------------------
   1908 // [SECTION] ImFontAtlas
   1909 //-----------------------------------------------------------------------------
   1910 
   1911 // A work of art lies ahead! (. = white layer, X = black layer, others are blank)
   1912 // The 2x2 white texels on the top left are the ones we'll use everywhere in Dear ImGui to render filled shapes.
   1913 const int FONT_ATLAS_DEFAULT_TEX_DATA_W = 108; // Actual texture will be 2 times that + 1 spacing.
   1914 const int FONT_ATLAS_DEFAULT_TEX_DATA_H = 27;
   1915 static const char FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[FONT_ATLAS_DEFAULT_TEX_DATA_W * FONT_ATLAS_DEFAULT_TEX_DATA_H + 1] =
   1916 {
   1917     "..-         -XXXXXXX-    X    -           X           -XXXXXXX          -          XXXXXXX-     XX          "
   1918     "..-         -X.....X-   X.X   -          X.X          -X.....X          -          X.....X-    X..X         "
   1919     "---         -XXX.XXX-  X...X  -         X...X         -X....X           -           X....X-    X..X         "
   1920     "X           -  X.X  - X.....X -        X.....X        -X...X            -            X...X-    X..X         "
   1921     "XX          -  X.X  -X.......X-       X.......X       -X..X.X           -           X.X..X-    X..X         "
   1922     "X.X         -  X.X  -XXXX.XXXX-       XXXX.XXXX       -X.X X.X          -          X.X X.X-    X..XXX       "
   1923     "X..X        -  X.X  -   X.X   -          X.X          -XX   X.X         -         X.X   XX-    X..X..XXX    "
   1924     "X...X       -  X.X  -   X.X   -    XX    X.X    XX    -      X.X        -        X.X      -    X..X..X..XX  "
   1925     "X....X      -  X.X  -   X.X   -   X.X    X.X    X.X   -       X.X       -       X.X       -    X..X..X..X.X "
   1926     "X.....X     -  X.X  -   X.X   -  X..X    X.X    X..X  -        X.X      -      X.X        -XXX X..X..X..X..X"
   1927     "X......X    -  X.X  -   X.X   - X...XXXXXX.XXXXXX...X -         X.X   XX-XX   X.X         -X..XX........X..X"
   1928     "X.......X   -  X.X  -   X.X   -X.....................X-          X.X X.X-X.X X.X          -X...X...........X"
   1929     "X........X  -  X.X  -   X.X   - X...XXXXXX.XXXXXX...X -           X.X..X-X..X.X           - X..............X"
   1930     "X.........X -XXX.XXX-   X.X   -  X..X    X.X    X..X  -            X...X-X...X            -  X.............X"
   1931     "X..........X-X.....X-   X.X   -   X.X    X.X    X.X   -           X....X-X....X           -  X.............X"
   1932     "X......XXXXX-XXXXXXX-   X.X   -    XX    X.X    XX    -          X.....X-X.....X          -   X............X"
   1933     "X...X..X    ---------   X.X   -          X.X          -          XXXXXXX-XXXXXXX          -   X...........X "
   1934     "X..X X..X   -       -XXXX.XXXX-       XXXX.XXXX       -------------------------------------    X..........X "
   1935     "X.X  X..X   -       -X.......X-       X.......X       -    XX           XX    -           -    X..........X "
   1936     "XX    X..X  -       - X.....X -        X.....X        -   X.X           X.X   -           -     X........X  "
   1937     "      X..X          -  X...X  -         X...X         -  X..X           X..X  -           -     X........X  "
   1938     "       XX           -   X.X   -          X.X          - X...XXXXXXXXXXXXX...X -           -     XXXXXXXXXX  "
   1939     "------------        -    X    -           X           -X.....................X-           ------------------"
   1940     "                    ----------------------------------- X...XXXXXXXXXXXXX...X -                             "
   1941     "                                                      -  X..X           X..X  -                             "
   1942     "                                                      -   X.X           X.X   -                             "
   1943     "                                                      -    XX           XX    -                             "
   1944 };
   1945 
   1946 static const ImVec2 FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[ImGuiMouseCursor_COUNT][3] =
   1947 {
   1948     // Pos ........ Size ......... Offset ......
   1949     { ImVec2( 0,3), ImVec2(12,19), ImVec2( 0, 0) }, // ImGuiMouseCursor_Arrow
   1950     { ImVec2(13,0), ImVec2( 7,16), ImVec2( 1, 8) }, // ImGuiMouseCursor_TextInput
   1951     { ImVec2(31,0), ImVec2(23,23), ImVec2(11,11) }, // ImGuiMouseCursor_ResizeAll
   1952     { ImVec2(21,0), ImVec2( 9,23), ImVec2( 4,11) }, // ImGuiMouseCursor_ResizeNS
   1953     { ImVec2(55,18),ImVec2(23, 9), ImVec2(11, 4) }, // ImGuiMouseCursor_ResizeEW
   1954     { ImVec2(73,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNESW
   1955     { ImVec2(55,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNWSE
   1956     { ImVec2(91,0), ImVec2(17,22), ImVec2( 5, 0) }, // ImGuiMouseCursor_Hand
   1957 };
   1958 
   1959 ImFontAtlas::ImFontAtlas()
   1960 {
   1961     memset(this, 0, sizeof(*this));
   1962     TexGlyphPadding = 1;
   1963     PackIdMouseCursors = PackIdLines = -1;
   1964 }
   1965 
   1966 ImFontAtlas::~ImFontAtlas()
   1967 {
   1968     IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
   1969     Clear();
   1970 }
   1971 
   1972 void    ImFontAtlas::ClearInputData()
   1973 {
   1974     IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
   1975     for (int i = 0; i < ConfigData.Size; i++)
   1976         if (ConfigData[i].FontData && ConfigData[i].FontDataOwnedByAtlas)
   1977         {
   1978             IM_FREE(ConfigData[i].FontData);
   1979             ConfigData[i].FontData = NULL;
   1980         }
   1981 
   1982     // When clearing this we lose access to the font name and other information used to build the font.
   1983     for (int i = 0; i < Fonts.Size; i++)
   1984         if (Fonts[i]->ConfigData >= ConfigData.Data && Fonts[i]->ConfigData < ConfigData.Data + ConfigData.Size)
   1985         {
   1986             Fonts[i]->ConfigData = NULL;
   1987             Fonts[i]->ConfigDataCount = 0;
   1988         }
   1989     ConfigData.clear();
   1990     CustomRects.clear();
   1991     PackIdMouseCursors = PackIdLines = -1;
   1992 }
   1993 
   1994 void    ImFontAtlas::ClearTexData()
   1995 {
   1996     IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
   1997     if (TexPixelsAlpha8)
   1998         IM_FREE(TexPixelsAlpha8);
   1999     if (TexPixelsRGBA32)
   2000         IM_FREE(TexPixelsRGBA32);
   2001     TexPixelsAlpha8 = NULL;
   2002     TexPixelsRGBA32 = NULL;
   2003     TexPixelsUseColors = false;
   2004 }
   2005 
   2006 void    ImFontAtlas::ClearFonts()
   2007 {
   2008     IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
   2009     for (int i = 0; i < Fonts.Size; i++)
   2010         IM_DELETE(Fonts[i]);
   2011     Fonts.clear();
   2012 }
   2013 
   2014 void    ImFontAtlas::Clear()
   2015 {
   2016     ClearInputData();
   2017     ClearTexData();
   2018     ClearFonts();
   2019 }
   2020 
   2021 void    ImFontAtlas::GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel)
   2022 {
   2023     // Build atlas on demand
   2024     if (TexPixelsAlpha8 == NULL)
   2025     {
   2026         if (ConfigData.empty())
   2027             AddFontDefault();
   2028         Build();
   2029     }
   2030 
   2031     *out_pixels = TexPixelsAlpha8;
   2032     if (out_width) *out_width = TexWidth;
   2033     if (out_height) *out_height = TexHeight;
   2034     if (out_bytes_per_pixel) *out_bytes_per_pixel = 1;
   2035 }
   2036 
   2037 void    ImFontAtlas::GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel)
   2038 {
   2039     // Convert to RGBA32 format on demand
   2040     // Although it is likely to be the most commonly used format, our font rendering is 1 channel / 8 bpp
   2041     if (!TexPixelsRGBA32)
   2042     {
   2043         unsigned char* pixels = NULL;
   2044         GetTexDataAsAlpha8(&pixels, NULL, NULL);
   2045         if (pixels)
   2046         {
   2047             TexPixelsRGBA32 = (unsigned int*)IM_ALLOC((size_t)TexWidth * (size_t)TexHeight * 4);
   2048             const unsigned char* src = pixels;
   2049             unsigned int* dst = TexPixelsRGBA32;
   2050             for (int n = TexWidth * TexHeight; n > 0; n--)
   2051                 *dst++ = IM_COL32(255, 255, 255, (unsigned int)(*src++));
   2052         }
   2053     }
   2054 
   2055     *out_pixels = (unsigned char*)TexPixelsRGBA32;
   2056     if (out_width) *out_width = TexWidth;
   2057     if (out_height) *out_height = TexHeight;
   2058     if (out_bytes_per_pixel) *out_bytes_per_pixel = 4;
   2059 }
   2060 
   2061 ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg)
   2062 {
   2063     IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
   2064     IM_ASSERT(font_cfg->FontData != NULL && font_cfg->FontDataSize > 0);
   2065     IM_ASSERT(font_cfg->SizePixels > 0.0f);
   2066 
   2067     // Create new font
   2068     if (!font_cfg->MergeMode)
   2069         Fonts.push_back(IM_NEW(ImFont));
   2070     else
   2071         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.
   2072 
   2073     ConfigData.push_back(*font_cfg);
   2074     ImFontConfig& new_font_cfg = ConfigData.back();
   2075     if (new_font_cfg.DstFont == NULL)
   2076         new_font_cfg.DstFont = Fonts.back();
   2077     if (!new_font_cfg.FontDataOwnedByAtlas)
   2078     {
   2079         new_font_cfg.FontData = IM_ALLOC(new_font_cfg.FontDataSize);
   2080         new_font_cfg.FontDataOwnedByAtlas = true;
   2081         memcpy(new_font_cfg.FontData, font_cfg->FontData, (size_t)new_font_cfg.FontDataSize);
   2082     }
   2083 
   2084     if (new_font_cfg.DstFont->EllipsisChar == (ImWchar)-1)
   2085         new_font_cfg.DstFont->EllipsisChar = font_cfg->EllipsisChar;
   2086 
   2087     // Invalidate texture
   2088     ClearTexData();
   2089     return new_font_cfg.DstFont;
   2090 }
   2091 
   2092 // Default font TTF is compressed with stb_compress then base85 encoded (see misc/fonts/binary_to_compressed_c.cpp for encoder)
   2093 static unsigned int stb_decompress_length(const unsigned char* input);
   2094 static unsigned int stb_decompress(unsigned char* output, const unsigned char* input, unsigned int length);
   2095 static const char*  GetDefaultCompressedFontDataTTFBase85();
   2096 static unsigned int Decode85Byte(char c)                                    { return c >= '\\' ? c-36 : c-35; }
   2097 static void         Decode85(const unsigned char* src, unsigned char* dst)
   2098 {
   2099     while (*src)
   2100     {
   2101         unsigned int tmp = Decode85Byte(src[0]) + 85 * (Decode85Byte(src[1]) + 85 * (Decode85Byte(src[2]) + 85 * (Decode85Byte(src[3]) + 85 * Decode85Byte(src[4]))));
   2102         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.
   2103         src += 5;
   2104         dst += 4;
   2105     }
   2106 }
   2107 
   2108 // Load embedded ProggyClean.ttf at size 13, disable oversampling
   2109 ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template)
   2110 {
   2111     ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
   2112     if (!font_cfg_template)
   2113     {
   2114         font_cfg.OversampleH = font_cfg.OversampleV = 1;
   2115         font_cfg.PixelSnapH = true;
   2116     }
   2117     if (font_cfg.SizePixels <= 0.0f)
   2118         font_cfg.SizePixels = 13.0f * 1.0f;
   2119     if (font_cfg.Name[0] == '\0')
   2120         ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "ProggyClean.ttf, %dpx", (int)font_cfg.SizePixels);
   2121     font_cfg.EllipsisChar = (ImWchar)0x0085;
   2122     font_cfg.GlyphOffset.y = 1.0f * IM_FLOOR(font_cfg.SizePixels / 13.0f);  // Add +1 offset per 13 units
   2123 
   2124     const char* ttf_compressed_base85 = GetDefaultCompressedFontDataTTFBase85();
   2125     const ImWchar* glyph_ranges = font_cfg.GlyphRanges != NULL ? font_cfg.GlyphRanges : GetGlyphRangesDefault();
   2126     ImFont* font = AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, font_cfg.SizePixels, &font_cfg, glyph_ranges);
   2127     return font;
   2128 }
   2129 
   2130 ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)
   2131 {
   2132     IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
   2133     size_t data_size = 0;
   2134     void* data = ImFileLoadToMemory(filename, "rb", &data_size, 0);
   2135     if (!data)
   2136     {
   2137         IM_ASSERT_USER_ERROR(0, "Could not load font file!");
   2138         return NULL;
   2139     }
   2140     ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
   2141     if (font_cfg.Name[0] == '\0')
   2142     {
   2143         // Store a short copy of filename into into the font name for convenience
   2144         const char* p;
   2145         for (p = filename + strlen(filename); p > filename && p[-1] != '/' && p[-1] != '\\'; p--) {}
   2146         ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "%s, %.0fpx", p, size_pixels);
   2147     }
   2148     return AddFontFromMemoryTTF(data, (int)data_size, size_pixels, &font_cfg, glyph_ranges);
   2149 }
   2150 
   2151 // NB: Transfer ownership of 'ttf_data' to ImFontAtlas, unless font_cfg_template->FontDataOwnedByAtlas == false. Owned TTF buffer will be deleted after Build().
   2152 ImFont* ImFontAtlas::AddFontFromMemoryTTF(void* ttf_data, int ttf_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)
   2153 {
   2154     IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
   2155     ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
   2156     IM_ASSERT(font_cfg.FontData == NULL);
   2157     font_cfg.FontData = ttf_data;
   2158     font_cfg.FontDataSize = ttf_size;
   2159     font_cfg.SizePixels = size_pixels;
   2160     if (glyph_ranges)
   2161         font_cfg.GlyphRanges = glyph_ranges;
   2162     return AddFont(&font_cfg);
   2163 }
   2164 
   2165 ImFont* ImFontAtlas::AddFontFromMemoryCompressedTTF(const void* compressed_ttf_data, int compressed_ttf_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)
   2166 {
   2167     const unsigned int buf_decompressed_size = stb_decompress_length((const unsigned char*)compressed_ttf_data);
   2168     unsigned char* buf_decompressed_data = (unsigned char*)IM_ALLOC(buf_decompressed_size);
   2169     stb_decompress(buf_decompressed_data, (const unsigned char*)compressed_ttf_data, (unsigned int)compressed_ttf_size);
   2170 
   2171     ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
   2172     IM_ASSERT(font_cfg.FontData == NULL);
   2173     font_cfg.FontDataOwnedByAtlas = true;
   2174     return AddFontFromMemoryTTF(buf_decompressed_data, (int)buf_decompressed_size, size_pixels, &font_cfg, glyph_ranges);
   2175 }
   2176 
   2177 ImFont* ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(const char* compressed_ttf_data_base85, float size_pixels, const ImFontConfig* font_cfg, const ImWchar* glyph_ranges)
   2178 {
   2179     int compressed_ttf_size = (((int)strlen(compressed_ttf_data_base85) + 4) / 5) * 4;
   2180     void* compressed_ttf = IM_ALLOC((size_t)compressed_ttf_size);
   2181     Decode85((const unsigned char*)compressed_ttf_data_base85, (unsigned char*)compressed_ttf);
   2182     ImFont* font = AddFontFromMemoryCompressedTTF(compressed_ttf, compressed_ttf_size, size_pixels, font_cfg, glyph_ranges);
   2183     IM_FREE(compressed_ttf);
   2184     return font;
   2185 }
   2186 
   2187 int ImFontAtlas::AddCustomRectRegular(int width, int height)
   2188 {
   2189     IM_ASSERT(width > 0 && width <= 0xFFFF);
   2190     IM_ASSERT(height > 0 && height <= 0xFFFF);
   2191     ImFontAtlasCustomRect r;
   2192     r.Width = (unsigned short)width;
   2193     r.Height = (unsigned short)height;
   2194     CustomRects.push_back(r);
   2195     return CustomRects.Size - 1; // Return index
   2196 }
   2197 
   2198 int ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset)
   2199 {
   2200 #ifdef IMGUI_USE_WCHAR32
   2201     IM_ASSERT(id <= IM_UNICODE_CODEPOINT_MAX);
   2202 #endif
   2203     IM_ASSERT(font != NULL);
   2204     IM_ASSERT(width > 0 && width <= 0xFFFF);
   2205     IM_ASSERT(height > 0 && height <= 0xFFFF);
   2206     ImFontAtlasCustomRect r;
   2207     r.Width = (unsigned short)width;
   2208     r.Height = (unsigned short)height;
   2209     r.GlyphID = id;
   2210     r.GlyphAdvanceX = advance_x;
   2211     r.GlyphOffset = offset;
   2212     r.Font = font;
   2213     CustomRects.push_back(r);
   2214     return CustomRects.Size - 1; // Return index
   2215 }
   2216 
   2217 void ImFontAtlas::CalcCustomRectUV(const ImFontAtlasCustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const
   2218 {
   2219     IM_ASSERT(TexWidth > 0 && TexHeight > 0);   // Font atlas needs to be built before we can calculate UV coordinates
   2220     IM_ASSERT(rect->IsPacked());                // Make sure the rectangle has been packed
   2221     *out_uv_min = ImVec2((float)rect->X * TexUvScale.x, (float)rect->Y * TexUvScale.y);
   2222     *out_uv_max = ImVec2((float)(rect->X + rect->Width) * TexUvScale.x, (float)(rect->Y + rect->Height) * TexUvScale.y);
   2223 }
   2224 
   2225 bool ImFontAtlas::GetMouseCursorTexData(ImGuiMouseCursor cursor_type, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2])
   2226 {
   2227     if (cursor_type <= ImGuiMouseCursor_None || cursor_type >= ImGuiMouseCursor_COUNT)
   2228         return false;
   2229     if (Flags & ImFontAtlasFlags_NoMouseCursors)
   2230         return false;
   2231 
   2232     IM_ASSERT(PackIdMouseCursors != -1);
   2233     ImFontAtlasCustomRect* r = GetCustomRectByIndex(PackIdMouseCursors);
   2234     ImVec2 pos = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][0] + ImVec2((float)r->X, (float)r->Y);
   2235     ImVec2 size = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][1];
   2236     *out_size = size;
   2237     *out_offset = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][2];
   2238     out_uv_border[0] = (pos) * TexUvScale;
   2239     out_uv_border[1] = (pos + size) * TexUvScale;
   2240     pos.x += FONT_ATLAS_DEFAULT_TEX_DATA_W + 1;
   2241     out_uv_fill[0] = (pos) * TexUvScale;
   2242     out_uv_fill[1] = (pos + size) * TexUvScale;
   2243     return true;
   2244 }
   2245 
   2246 bool    ImFontAtlas::Build()
   2247 {
   2248     IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
   2249 
   2250     // Select builder
   2251     // - Note that we do not reassign to atlas->FontBuilderIO, since it is likely to point to static data which
   2252     //   may mess with some hot-reloading schemes. If you need to assign to this (for dynamic selection) AND are
   2253     //   using a hot-reloading scheme that messes up static data, store your own instance of ImFontBuilderIO somewhere
   2254     //   and point to it instead of pointing directly to return value of the GetBuilderXXX functions.
   2255     const ImFontBuilderIO* builder_io = FontBuilderIO;
   2256     if (builder_io == NULL)
   2257     {
   2258 #ifdef IMGUI_ENABLE_FREETYPE
   2259         builder_io = ImGuiFreeType::GetBuilderForFreeType();
   2260 #elif defined(IMGUI_ENABLE_STB_TRUETYPE)
   2261         builder_io = ImFontAtlasGetBuilderForStbTruetype();
   2262 #else
   2263         IM_ASSERT(0); // Invalid Build function
   2264 #endif
   2265     }
   2266 
   2267     // Build
   2268     return builder_io->FontBuilder_Build(this);
   2269 }
   2270 
   2271 void    ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_brighten_factor)
   2272 {
   2273     for (unsigned int i = 0; i < 256; i++)
   2274     {
   2275         unsigned int value = (unsigned int)(i * in_brighten_factor);
   2276         out_table[i] = value > 255 ? 255 : (value & 0xFF);
   2277     }
   2278 }
   2279 
   2280 void    ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride)
   2281 {
   2282     unsigned char* data = pixels + x + y * stride;
   2283     for (int j = h; j > 0; j--, data += stride)
   2284         for (int i = 0; i < w; i++)
   2285             data[i] = table[data[i]];
   2286 }
   2287 
   2288 #ifdef IMGUI_ENABLE_STB_TRUETYPE
   2289 // Temporary data for one source font (multiple source fonts can be merged into one destination ImFont)
   2290 // (C++03 doesn't allow instancing ImVector<> with function-local types so we declare the type here.)
   2291 struct ImFontBuildSrcData
   2292 {
   2293     stbtt_fontinfo      FontInfo;
   2294     stbtt_pack_range    PackRange;          // Hold the list of codepoints to pack (essentially points to Codepoints.Data)
   2295     stbrp_rect*         Rects;              // Rectangle to pack. We first fill in their size and the packer will give us their position.
   2296     stbtt_packedchar*   PackedChars;        // Output glyphs
   2297     const ImWchar*      SrcRanges;          // Ranges as requested by user (user is allowed to request too much, e.g. 0x0020..0xFFFF)
   2298     int                 DstIndex;           // Index into atlas->Fonts[] and dst_tmp_array[]
   2299     int                 GlyphsHighest;      // Highest requested codepoint
   2300     int                 GlyphsCount;        // Glyph count (excluding missing glyphs and glyphs already set by an earlier source font)
   2301     ImBitVector         GlyphsSet;          // Glyph bit map (random access, 1-bit per codepoint. This will be a maximum of 8KB)
   2302     ImVector<int>       GlyphsList;         // Glyph codepoints list (flattened version of GlyphsMap)
   2303 };
   2304 
   2305 // Temporary data for one destination ImFont* (multiple source fonts can be merged into one destination ImFont)
   2306 struct ImFontBuildDstData
   2307 {
   2308     int                 SrcCount;           // Number of source fonts targeting this destination font.
   2309     int                 GlyphsHighest;
   2310     int                 GlyphsCount;
   2311     ImBitVector         GlyphsSet;          // This is used to resolve collision when multiple sources are merged into a same destination font.
   2312 };
   2313 
   2314 static void UnpackBitVectorToFlatIndexList(const ImBitVector* in, ImVector<int>* out)
   2315 {
   2316     IM_ASSERT(sizeof(in->Storage.Data[0]) == sizeof(int));
   2317     const ImU32* it_begin = in->Storage.begin();
   2318     const ImU32* it_end = in->Storage.end();
   2319     for (const ImU32* it = it_begin; it < it_end; it++)
   2320         if (ImU32 entries_32 = *it)
   2321             for (ImU32 bit_n = 0; bit_n < 32; bit_n++)
   2322                 if (entries_32 & ((ImU32)1 << bit_n))
   2323                     out->push_back((int)(((it - it_begin) << 5) + bit_n));
   2324 }
   2325 
   2326 static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
   2327 {
   2328     IM_ASSERT(atlas->ConfigData.Size > 0);
   2329 
   2330     ImFontAtlasBuildInit(atlas);
   2331 
   2332     // Clear atlas
   2333     atlas->TexID = (ImTextureID)NULL;
   2334     atlas->TexWidth = atlas->TexHeight = 0;
   2335     atlas->TexUvScale = ImVec2(0.0f, 0.0f);
   2336     atlas->TexUvWhitePixel = ImVec2(0.0f, 0.0f);
   2337     atlas->ClearTexData();
   2338 
   2339     // Temporary storage for building
   2340     ImVector<ImFontBuildSrcData> src_tmp_array;
   2341     ImVector<ImFontBuildDstData> dst_tmp_array;
   2342     src_tmp_array.resize(atlas->ConfigData.Size);
   2343     dst_tmp_array.resize(atlas->Fonts.Size);
   2344     memset(src_tmp_array.Data, 0, (size_t)src_tmp_array.size_in_bytes());
   2345     memset(dst_tmp_array.Data, 0, (size_t)dst_tmp_array.size_in_bytes());
   2346 
   2347     // 1. Initialize font loading structure, check font data validity
   2348     for (int src_i = 0; src_i < atlas->ConfigData.Size; src_i++)
   2349     {
   2350         ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
   2351         ImFontConfig& cfg = atlas->ConfigData[src_i];
   2352         IM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas));
   2353 
   2354         // Find index from cfg.DstFont (we allow the user to set cfg.DstFont. Also it makes casual debugging nicer than when storing indices)
   2355         src_tmp.DstIndex = -1;
   2356         for (int output_i = 0; output_i < atlas->Fonts.Size && src_tmp.DstIndex == -1; output_i++)
   2357             if (cfg.DstFont == atlas->Fonts[output_i])
   2358                 src_tmp.DstIndex = output_i;
   2359         if (src_tmp.DstIndex == -1)
   2360         {
   2361             IM_ASSERT(src_tmp.DstIndex != -1); // cfg.DstFont not pointing within atlas->Fonts[] array?
   2362             return false;
   2363         }
   2364         // Initialize helper structure for font loading and verify that the TTF/OTF data is correct
   2365         const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)cfg.FontData, cfg.FontNo);
   2366         IM_ASSERT(font_offset >= 0 && "FontData is incorrect, or FontNo cannot be found.");
   2367         if (!stbtt_InitFont(&src_tmp.FontInfo, (unsigned char*)cfg.FontData, font_offset))
   2368             return false;
   2369 
   2370         // Measure highest codepoints
   2371         ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex];
   2372         src_tmp.SrcRanges = cfg.GlyphRanges ? cfg.GlyphRanges : atlas->GetGlyphRangesDefault();
   2373         for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
   2374             src_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]);
   2375         dst_tmp.SrcCount++;
   2376         dst_tmp.GlyphsHighest = ImMax(dst_tmp.GlyphsHighest, src_tmp.GlyphsHighest);
   2377     }
   2378 
   2379     // 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.
   2380     int total_glyphs_count = 0;
   2381     for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
   2382     {
   2383         ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
   2384         ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex];
   2385         src_tmp.GlyphsSet.Create(src_tmp.GlyphsHighest + 1);
   2386         if (dst_tmp.GlyphsSet.Storage.empty())
   2387             dst_tmp.GlyphsSet.Create(dst_tmp.GlyphsHighest + 1);
   2388 
   2389         for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
   2390             for (unsigned int codepoint = src_range[0]; codepoint <= src_range[1]; codepoint++)
   2391             {
   2392                 if (dst_tmp.GlyphsSet.TestBit(codepoint))    // Don't overwrite existing glyphs. We could make this an option for MergeMode (e.g. MergeOverwrite==true)
   2393                     continue;
   2394                 if (!stbtt_FindGlyphIndex(&src_tmp.FontInfo, codepoint))    // It is actually in the font?
   2395                     continue;
   2396 
   2397                 // Add to avail set/counters
   2398                 src_tmp.GlyphsCount++;
   2399                 dst_tmp.GlyphsCount++;
   2400                 src_tmp.GlyphsSet.SetBit(codepoint);
   2401                 dst_tmp.GlyphsSet.SetBit(codepoint);
   2402                 total_glyphs_count++;
   2403             }
   2404     }
   2405 
   2406     // 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)
   2407     for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
   2408     {
   2409         ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
   2410         src_tmp.GlyphsList.reserve(src_tmp.GlyphsCount);
   2411         UnpackBitVectorToFlatIndexList(&src_tmp.GlyphsSet, &src_tmp.GlyphsList);
   2412         src_tmp.GlyphsSet.Clear();
   2413         IM_ASSERT(src_tmp.GlyphsList.Size == src_tmp.GlyphsCount);
   2414     }
   2415     for (int dst_i = 0; dst_i < dst_tmp_array.Size; dst_i++)
   2416         dst_tmp_array[dst_i].GlyphsSet.Clear();
   2417     dst_tmp_array.clear();
   2418 
   2419     // Allocate packing character data and flag packed characters buffer as non-packed (x0=y0=x1=y1=0)
   2420     // (We technically don't need to zero-clear buf_rects, but let's do it for the sake of sanity)
   2421     ImVector<stbrp_rect> buf_rects;
   2422     ImVector<stbtt_packedchar> buf_packedchars;
   2423     buf_rects.resize(total_glyphs_count);
   2424     buf_packedchars.resize(total_glyphs_count);
   2425     memset(buf_rects.Data, 0, (size_t)buf_rects.size_in_bytes());
   2426     memset(buf_packedchars.Data, 0, (size_t)buf_packedchars.size_in_bytes());
   2427 
   2428     // 4. Gather glyphs sizes so we can pack them in our virtual canvas.
   2429     int total_surface = 0;
   2430     int buf_rects_out_n = 0;
   2431     int buf_packedchars_out_n = 0;
   2432     for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
   2433     {
   2434         ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
   2435         if (src_tmp.GlyphsCount == 0)
   2436             continue;
   2437 
   2438         src_tmp.Rects = &buf_rects[buf_rects_out_n];
   2439         src_tmp.PackedChars = &buf_packedchars[buf_packedchars_out_n];
   2440         buf_rects_out_n += src_tmp.GlyphsCount;
   2441         buf_packedchars_out_n += src_tmp.GlyphsCount;
   2442 
   2443         // Convert our ranges in the format stb_truetype wants
   2444         ImFontConfig& cfg = atlas->ConfigData[src_i];
   2445         src_tmp.PackRange.font_size = cfg.SizePixels;
   2446         src_tmp.PackRange.first_unicode_codepoint_in_range = 0;
   2447         src_tmp.PackRange.array_of_unicode_codepoints = src_tmp.GlyphsList.Data;
   2448         src_tmp.PackRange.num_chars = src_tmp.GlyphsList.Size;
   2449         src_tmp.PackRange.chardata_for_range = src_tmp.PackedChars;
   2450         src_tmp.PackRange.h_oversample = (unsigned char)cfg.OversampleH;
   2451         src_tmp.PackRange.v_oversample = (unsigned char)cfg.OversampleV;
   2452 
   2453         // Gather the sizes of all rectangles we will need to pack (this loop is based on stbtt_PackFontRangesGatherRects)
   2454         const float scale = (cfg.SizePixels > 0) ? stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels) : stbtt_ScaleForMappingEmToPixels(&src_tmp.FontInfo, -cfg.SizePixels);
   2455         const int padding = atlas->TexGlyphPadding;
   2456         for (int glyph_i = 0; glyph_i < src_tmp.GlyphsList.Size; glyph_i++)
   2457         {
   2458             int x0, y0, x1, y1;
   2459             const int glyph_index_in_font = stbtt_FindGlyphIndex(&src_tmp.FontInfo, src_tmp.GlyphsList[glyph_i]);
   2460             IM_ASSERT(glyph_index_in_font != 0);
   2461             stbtt_GetGlyphBitmapBoxSubpixel(&src_tmp.FontInfo, glyph_index_in_font, scale * cfg.OversampleH, scale * cfg.OversampleV, 0, 0, &x0, &y0, &x1, &y1);
   2462             src_tmp.Rects[glyph_i].w = (stbrp_coord)(x1 - x0 + padding + cfg.OversampleH - 1);
   2463             src_tmp.Rects[glyph_i].h = (stbrp_coord)(y1 - y0 + padding + cfg.OversampleV - 1);
   2464             total_surface += src_tmp.Rects[glyph_i].w * src_tmp.Rects[glyph_i].h;
   2465         }
   2466     }
   2467 
   2468     // We need a width for the skyline algorithm, any width!
   2469     // The exact width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height.
   2470     // User can override TexDesiredWidth and TexGlyphPadding if they wish, otherwise we use a simple heuristic to select the width based on expected surface.
   2471     const int surface_sqrt = (int)ImSqrt((float)total_surface) + 1;
   2472     atlas->TexHeight = 0;
   2473     if (atlas->TexDesiredWidth > 0)
   2474         atlas->TexWidth = atlas->TexDesiredWidth;
   2475     else
   2476         atlas->TexWidth = (surface_sqrt >= 4096 * 0.7f) ? 4096 : (surface_sqrt >= 2048 * 0.7f) ? 2048 : (surface_sqrt >= 1024 * 0.7f) ? 1024 : 512;
   2477 
   2478     // 5. Start packing
   2479     // Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values).
   2480     const int TEX_HEIGHT_MAX = 1024 * 32;
   2481     stbtt_pack_context spc = {};
   2482     stbtt_PackBegin(&spc, NULL, atlas->TexWidth, TEX_HEIGHT_MAX, 0, atlas->TexGlyphPadding, NULL);
   2483     ImFontAtlasBuildPackCustomRects(atlas, spc.pack_info);
   2484 
   2485     // 6. Pack each source font. No rendering yet, we are working with rectangles in an infinitely tall texture at this point.
   2486     for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
   2487     {
   2488         ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
   2489         if (src_tmp.GlyphsCount == 0)
   2490             continue;
   2491 
   2492         stbrp_pack_rects((stbrp_context*)spc.pack_info, src_tmp.Rects, src_tmp.GlyphsCount);
   2493 
   2494         // Extend texture height and mark missing glyphs as non-packed so we won't render them.
   2495         // 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?)
   2496         for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++)
   2497             if (src_tmp.Rects[glyph_i].was_packed)
   2498                 atlas->TexHeight = ImMax(atlas->TexHeight, src_tmp.Rects[glyph_i].y + src_tmp.Rects[glyph_i].h);
   2499     }
   2500 
   2501     // 7. Allocate texture
   2502     atlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight);
   2503     atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight);
   2504     atlas->TexPixelsAlpha8 = (unsigned char*)IM_ALLOC(atlas->TexWidth * atlas->TexHeight);
   2505     memset(atlas->TexPixelsAlpha8, 0, atlas->TexWidth * atlas->TexHeight);
   2506     spc.pixels = atlas->TexPixelsAlpha8;
   2507     spc.height = atlas->TexHeight;
   2508 
   2509     // 8. Render/rasterize font characters into the texture
   2510     for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
   2511     {
   2512         ImFontConfig& cfg = atlas->ConfigData[src_i];
   2513         ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
   2514         if (src_tmp.GlyphsCount == 0)
   2515             continue;
   2516 
   2517         stbtt_PackFontRangesRenderIntoRects(&spc, &src_tmp.FontInfo, &src_tmp.PackRange, 1, src_tmp.Rects);
   2518 
   2519         // Apply multiply operator
   2520         if (cfg.RasterizerMultiply != 1.0f)
   2521         {
   2522             unsigned char multiply_table[256];
   2523             ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply);
   2524             stbrp_rect* r = &src_tmp.Rects[0];
   2525             for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++, r++)
   2526                 if (r->was_packed)
   2527                     ImFontAtlasBuildMultiplyRectAlpha8(multiply_table, atlas->TexPixelsAlpha8, r->x, r->y, r->w, r->h, atlas->TexWidth * 1);
   2528         }
   2529         src_tmp.Rects = NULL;
   2530     }
   2531 
   2532     // End packing
   2533     stbtt_PackEnd(&spc);
   2534     buf_rects.clear();
   2535 
   2536     // 9. Setup ImFont and glyphs for runtime
   2537     for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
   2538     {
   2539         ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
   2540         if (src_tmp.GlyphsCount == 0)
   2541             continue;
   2542 
   2543         // When merging fonts with MergeMode=true:
   2544         // - We can have multiple input fonts writing into a same destination font.
   2545         // - dst_font->ConfigData is != from cfg which is our source configuration.
   2546         ImFontConfig& cfg = atlas->ConfigData[src_i];
   2547         ImFont* dst_font = cfg.DstFont;
   2548 
   2549         const float font_scale = stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels);
   2550         int unscaled_ascent, unscaled_descent, unscaled_line_gap;
   2551         stbtt_GetFontVMetrics(&src_tmp.FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap);
   2552 
   2553         const float ascent = ImFloor(unscaled_ascent * font_scale + ((unscaled_ascent > 0.0f) ? +1 : -1));
   2554         const float descent = ImFloor(unscaled_descent * font_scale + ((unscaled_descent > 0.0f) ? +1 : -1));
   2555         ImFontAtlasBuildSetupFont(atlas, dst_font, &cfg, ascent, descent);
   2556         const float font_off_x = cfg.GlyphOffset.x;
   2557         const float font_off_y = cfg.GlyphOffset.y + IM_ROUND(dst_font->Ascent);
   2558 
   2559         for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++)
   2560         {
   2561             // Register glyph
   2562             const int codepoint = src_tmp.GlyphsList[glyph_i];
   2563             const stbtt_packedchar& pc = src_tmp.PackedChars[glyph_i];
   2564             stbtt_aligned_quad q;
   2565             float unused_x = 0.0f, unused_y = 0.0f;
   2566             stbtt_GetPackedQuad(src_tmp.PackedChars, atlas->TexWidth, atlas->TexHeight, glyph_i, &unused_x, &unused_y, &q, 0);
   2567             dst_font->AddGlyph(&cfg, (ImWchar)codepoint, q.x0 + font_off_x, q.y0 + font_off_y, q.x1 + font_off_x, q.y1 + font_off_y, q.s0, q.t0, q.s1, q.t1, pc.xadvance);
   2568         }
   2569     }
   2570 
   2571     // Cleanup temporary (ImVector doesn't honor destructor)
   2572     for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
   2573         src_tmp_array[src_i].~ImFontBuildSrcData();
   2574 
   2575     ImFontAtlasBuildFinish(atlas);
   2576     return true;
   2577 }
   2578 
   2579 const ImFontBuilderIO* ImFontAtlasGetBuilderForStbTruetype()
   2580 {
   2581     static ImFontBuilderIO io;
   2582     io.FontBuilder_Build = ImFontAtlasBuildWithStbTruetype;
   2583     return &io;
   2584 }
   2585 
   2586 #endif // IMGUI_ENABLE_STB_TRUETYPE
   2587 
   2588 void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent)
   2589 {
   2590     if (!font_config->MergeMode)
   2591     {
   2592         font->ClearOutputData();
   2593         font->FontSize = font_config->SizePixels;
   2594         font->ConfigData = font_config;
   2595         font->ConfigDataCount = 0;
   2596         font->ContainerAtlas = atlas;
   2597         font->Ascent = ascent;
   2598         font->Descent = descent;
   2599     }
   2600     font->ConfigDataCount++;
   2601 }
   2602 
   2603 void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque)
   2604 {
   2605     stbrp_context* pack_context = (stbrp_context*)stbrp_context_opaque;
   2606     IM_ASSERT(pack_context != NULL);
   2607 
   2608     ImVector<ImFontAtlasCustomRect>& user_rects = atlas->CustomRects;
   2609     IM_ASSERT(user_rects.Size >= 1); // We expect at least the default custom rects to be registered, else something went wrong.
   2610 
   2611     ImVector<stbrp_rect> pack_rects;
   2612     pack_rects.resize(user_rects.Size);
   2613     memset(pack_rects.Data, 0, (size_t)pack_rects.size_in_bytes());
   2614     for (int i = 0; i < user_rects.Size; i++)
   2615     {
   2616         pack_rects[i].w = user_rects[i].Width;
   2617         pack_rects[i].h = user_rects[i].Height;
   2618     }
   2619     stbrp_pack_rects(pack_context, &pack_rects[0], pack_rects.Size);
   2620     for (int i = 0; i < pack_rects.Size; i++)
   2621         if (pack_rects[i].was_packed)
   2622         {
   2623             user_rects[i].X = pack_rects[i].x;
   2624             user_rects[i].Y = pack_rects[i].y;
   2625             IM_ASSERT(pack_rects[i].w == user_rects[i].Width && pack_rects[i].h == user_rects[i].Height);
   2626             atlas->TexHeight = ImMax(atlas->TexHeight, pack_rects[i].y + pack_rects[i].h);
   2627         }
   2628 }
   2629 
   2630 void ImFontAtlasBuildRender8bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned char in_marker_pixel_value)
   2631 {
   2632     IM_ASSERT(x >= 0 && x + w <= atlas->TexWidth);
   2633     IM_ASSERT(y >= 0 && y + h <= atlas->TexHeight);
   2634     unsigned char* out_pixel = atlas->TexPixelsAlpha8 + x + (y * atlas->TexWidth);
   2635     for (int off_y = 0; off_y < h; off_y++, out_pixel += atlas->TexWidth, in_str += w)
   2636         for (int off_x = 0; off_x < w; off_x++)
   2637             out_pixel[off_x] = (in_str[off_x] == in_marker_char) ? in_marker_pixel_value : 0x00;
   2638 }
   2639 
   2640 void ImFontAtlasBuildRender32bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned int in_marker_pixel_value)
   2641 {
   2642     IM_ASSERT(x >= 0 && x + w <= atlas->TexWidth);
   2643     IM_ASSERT(y >= 0 && y + h <= atlas->TexHeight);
   2644     unsigned int* out_pixel = atlas->TexPixelsRGBA32 + x + (y * atlas->TexWidth);
   2645     for (int off_y = 0; off_y < h; off_y++, out_pixel += atlas->TexWidth, in_str += w)
   2646         for (int off_x = 0; off_x < w; off_x++)
   2647             out_pixel[off_x] = (in_str[off_x] == in_marker_char) ? in_marker_pixel_value : IM_COL32_BLACK_TRANS;
   2648 }
   2649 
   2650 static void ImFontAtlasBuildRenderDefaultTexData(ImFontAtlas* atlas)
   2651 {
   2652     ImFontAtlasCustomRect* r = atlas->GetCustomRectByIndex(atlas->PackIdMouseCursors);
   2653     IM_ASSERT(r->IsPacked());
   2654 
   2655     const int w = atlas->TexWidth;
   2656     if (!(atlas->Flags & ImFontAtlasFlags_NoMouseCursors))
   2657     {
   2658         // Render/copy pixels
   2659         IM_ASSERT(r->Width == FONT_ATLAS_DEFAULT_TEX_DATA_W * 2 + 1 && r->Height == FONT_ATLAS_DEFAULT_TEX_DATA_H);
   2660         const int x_for_white = r->X;
   2661         const int x_for_black = r->X + FONT_ATLAS_DEFAULT_TEX_DATA_W + 1;
   2662         if (atlas->TexPixelsAlpha8 != NULL)
   2663         {
   2664             ImFontAtlasBuildRender8bppRectFromString(atlas, x_for_white, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, '.', 0xFF);
   2665             ImFontAtlasBuildRender8bppRectFromString(atlas, x_for_black, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, 'X', 0xFF);
   2666         }
   2667         else
   2668         {
   2669             ImFontAtlasBuildRender32bppRectFromString(atlas, x_for_white, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, '.', IM_COL32_WHITE);
   2670             ImFontAtlasBuildRender32bppRectFromString(atlas, x_for_black, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, 'X', IM_COL32_WHITE);
   2671         }
   2672     }
   2673     else
   2674     {
   2675         // Render 4 white pixels
   2676         IM_ASSERT(r->Width == 2 && r->Height == 2);
   2677         const int offset = (int)r->X + (int)r->Y * w;
   2678         if (atlas->TexPixelsAlpha8 != NULL)
   2679         {
   2680             atlas->TexPixelsAlpha8[offset] = atlas->TexPixelsAlpha8[offset + 1] = atlas->TexPixelsAlpha8[offset + w] = atlas->TexPixelsAlpha8[offset + w + 1] = 0xFF;
   2681         }
   2682         else
   2683         {
   2684             atlas->TexPixelsRGBA32[offset] = atlas->TexPixelsRGBA32[offset + 1] = atlas->TexPixelsRGBA32[offset + w] = atlas->TexPixelsRGBA32[offset + w + 1] = IM_COL32_WHITE;
   2685         }
   2686     }
   2687     atlas->TexUvWhitePixel = ImVec2((r->X + 0.5f) * atlas->TexUvScale.x, (r->Y + 0.5f) * atlas->TexUvScale.y);
   2688 }
   2689 
   2690 static void ImFontAtlasBuildRenderLinesTexData(ImFontAtlas* atlas)
   2691 {
   2692     if (atlas->Flags & ImFontAtlasFlags_NoBakedLines)
   2693         return;
   2694 
   2695     // This generates a triangular shape in the texture, with the various line widths stacked on top of each other to allow interpolation between them
   2696     ImFontAtlasCustomRect* r = atlas->GetCustomRectByIndex(atlas->PackIdLines);
   2697     IM_ASSERT(r->IsPacked());
   2698     for (unsigned int n = 0; n < IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1; n++) // +1 because of the zero-width row
   2699     {
   2700         // Each line consists of at least two empty pixels at the ends, with a line of solid pixels in the middle
   2701         unsigned int y = n;
   2702         unsigned int line_width = n;
   2703         unsigned int pad_left = (r->Width - line_width) / 2;
   2704         unsigned int pad_right = r->Width - (pad_left + line_width);
   2705 
   2706         // Write each slice
   2707         IM_ASSERT(pad_left + line_width + pad_right == r->Width && y < r->Height); // Make sure we're inside the texture bounds before we start writing pixels
   2708         if (atlas->TexPixelsAlpha8 != NULL)
   2709         {
   2710             unsigned char* write_ptr = &atlas->TexPixelsAlpha8[r->X + ((r->Y + y) * atlas->TexWidth)];
   2711             for (unsigned int i = 0; i < pad_left; i++)
   2712                 *(write_ptr + i) = 0x00;
   2713 
   2714             for (unsigned int i = 0; i < line_width; i++)
   2715                 *(write_ptr + pad_left + i) = 0xFF;
   2716 
   2717             for (unsigned int i = 0; i < pad_right; i++)
   2718                 *(write_ptr + pad_left + line_width + i) = 0x00;
   2719         }
   2720         else
   2721         {
   2722             unsigned int* write_ptr = &atlas->TexPixelsRGBA32[r->X + ((r->Y + y) * atlas->TexWidth)];
   2723             for (unsigned int i = 0; i < pad_left; i++)
   2724                 *(write_ptr + i) = IM_COL32_BLACK_TRANS;
   2725 
   2726             for (unsigned int i = 0; i < line_width; i++)
   2727                 *(write_ptr + pad_left + i) = IM_COL32_WHITE;
   2728 
   2729             for (unsigned int i = 0; i < pad_right; i++)
   2730                 *(write_ptr + pad_left + line_width + i) = IM_COL32_BLACK_TRANS;
   2731         }
   2732 
   2733         // Calculate UVs for this line
   2734         ImVec2 uv0 = ImVec2((float)(r->X + pad_left - 1), (float)(r->Y + y)) * atlas->TexUvScale;
   2735         ImVec2 uv1 = ImVec2((float)(r->X + pad_left + line_width + 1), (float)(r->Y + y + 1)) * atlas->TexUvScale;
   2736         float half_v = (uv0.y + uv1.y) * 0.5f; // Calculate a constant V in the middle of the row to avoid sampling artifacts
   2737         atlas->TexUvLines[n] = ImVec4(uv0.x, half_v, uv1.x, half_v);
   2738     }
   2739 }
   2740 
   2741 // Note: this is called / shared by both the stb_truetype and the FreeType builder
   2742 void ImFontAtlasBuildInit(ImFontAtlas* atlas)
   2743 {
   2744     // Register texture region for mouse cursors or standard white pixels
   2745     if (atlas->PackIdMouseCursors < 0)
   2746     {
   2747         if (!(atlas->Flags & ImFontAtlasFlags_NoMouseCursors))
   2748             atlas->PackIdMouseCursors = atlas->AddCustomRectRegular(FONT_ATLAS_DEFAULT_TEX_DATA_W * 2 + 1, FONT_ATLAS_DEFAULT_TEX_DATA_H);
   2749         else
   2750             atlas->PackIdMouseCursors = atlas->AddCustomRectRegular(2, 2);
   2751     }
   2752 
   2753     // Register texture region for thick lines
   2754     // The +2 here is to give space for the end caps, whilst height +1 is to accommodate the fact we have a zero-width row
   2755     if (atlas->PackIdLines < 0)
   2756     {
   2757         if (!(atlas->Flags & ImFontAtlasFlags_NoBakedLines))
   2758             atlas->PackIdLines = atlas->AddCustomRectRegular(IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 2, IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1);
   2759     }
   2760 }
   2761 
   2762 // This is called/shared by both the stb_truetype and the FreeType builder.
   2763 void ImFontAtlasBuildFinish(ImFontAtlas* atlas)
   2764 {
   2765     // Render into our custom data blocks
   2766     IM_ASSERT(atlas->TexPixelsAlpha8 != NULL || atlas->TexPixelsRGBA32 != NULL);
   2767     ImFontAtlasBuildRenderDefaultTexData(atlas);
   2768     ImFontAtlasBuildRenderLinesTexData(atlas);
   2769 
   2770     // Register custom rectangle glyphs
   2771     for (int i = 0; i < atlas->CustomRects.Size; i++)
   2772     {
   2773         const ImFontAtlasCustomRect* r = &atlas->CustomRects[i];
   2774         if (r->Font == NULL || r->GlyphID == 0)
   2775             continue;
   2776 
   2777         // Will ignore ImFontConfig settings: GlyphMinAdvanceX, GlyphMinAdvanceY, GlyphExtraSpacing, PixelSnapH
   2778         IM_ASSERT(r->Font->ContainerAtlas == atlas);
   2779         ImVec2 uv0, uv1;
   2780         atlas->CalcCustomRectUV(r, &uv0, &uv1);
   2781         r->Font->AddGlyph(NULL, (ImWchar)r->GlyphID, 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);
   2782     }
   2783 
   2784     // Build all fonts lookup tables
   2785     for (int i = 0; i < atlas->Fonts.Size; i++)
   2786         if (atlas->Fonts[i]->DirtyLookupTables)
   2787             atlas->Fonts[i]->BuildLookupTable();
   2788 
   2789     // Ellipsis character is required for rendering elided text. We prefer using U+2026 (horizontal ellipsis).
   2790     // However some old fonts may contain ellipsis at U+0085. Here we auto-detect most suitable ellipsis character.
   2791     // FIXME: Also note that 0x2026 is currently seldom included in our font ranges. Because of this we are more likely to use three individual dots.
   2792     for (int i = 0; i < atlas->Fonts.size(); i++)
   2793     {
   2794         ImFont* font = atlas->Fonts[i];
   2795         if (font->EllipsisChar != (ImWchar)-1)
   2796             continue;
   2797         const ImWchar ellipsis_variants[] = { (ImWchar)0x2026, (ImWchar)0x0085 };
   2798         for (int j = 0; j < IM_ARRAYSIZE(ellipsis_variants); j++)
   2799             if (font->FindGlyphNoFallback(ellipsis_variants[j]) != NULL) // Verify glyph exists
   2800             {
   2801                 font->EllipsisChar = ellipsis_variants[j];
   2802                 break;
   2803             }
   2804     }
   2805 }
   2806 
   2807 // Retrieve list of range (2 int per range, values are inclusive)
   2808 const ImWchar*   ImFontAtlas::GetGlyphRangesDefault()
   2809 {
   2810     static const ImWchar ranges[] =
   2811     {
   2812         0x0020, 0x00FF, // Basic Latin + Latin Supplement
   2813         0,
   2814     };
   2815     return &ranges[0];
   2816 }
   2817 
   2818 const ImWchar*  ImFontAtlas::GetGlyphRangesKorean()
   2819 {
   2820     static const ImWchar ranges[] =
   2821     {
   2822         0x0020, 0x00FF, // Basic Latin + Latin Supplement
   2823         0x3131, 0x3163, // Korean alphabets
   2824         0xAC00, 0xD7A3, // Korean characters
   2825         0,
   2826     };
   2827     return &ranges[0];
   2828 }
   2829 
   2830 const ImWchar*  ImFontAtlas::GetGlyphRangesChineseFull()
   2831 {
   2832     static const ImWchar ranges[] =
   2833     {
   2834         0x0020, 0x00FF, // Basic Latin + Latin Supplement
   2835         0x2000, 0x206F, // General Punctuation
   2836         0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
   2837         0x31F0, 0x31FF, // Katakana Phonetic Extensions
   2838         0xFF00, 0xFFEF, // Half-width characters
   2839         0x4e00, 0x9FAF, // CJK Ideograms
   2840         0,
   2841     };
   2842     return &ranges[0];
   2843 }
   2844 
   2845 static void UnpackAccumulativeOffsetsIntoRanges(int base_codepoint, const short* accumulative_offsets, int accumulative_offsets_count, ImWchar* out_ranges)
   2846 {
   2847     for (int n = 0; n < accumulative_offsets_count; n++, out_ranges += 2)
   2848     {
   2849         out_ranges[0] = out_ranges[1] = (ImWchar)(base_codepoint + accumulative_offsets[n]);
   2850         base_codepoint += accumulative_offsets[n];
   2851     }
   2852     out_ranges[0] = 0;
   2853 }
   2854 
   2855 //-------------------------------------------------------------------------
   2856 // [SECTION] ImFontAtlas glyph ranges helpers
   2857 //-------------------------------------------------------------------------
   2858 
   2859 const ImWchar*  ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon()
   2860 {
   2861     // Store 2500 regularly used characters for Simplified Chinese.
   2862     // 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
   2863     // This table covers 97.97% of all characters used during the month in July, 1987.
   2864     // You can use ImFontGlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters.
   2865     // (Stored as accumulative offsets from the initial unicode codepoint 0x4E00. This encoding is designed to helps us compact the source code size.)
   2866     static const short accumulative_offsets_from_0x4E00[] =
   2867     {
   2868         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,
   2869         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,
   2870         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,
   2871         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,
   2872         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,
   2873         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,
   2874         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,
   2875         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,
   2876         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,
   2877         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,
   2878         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,
   2879         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,
   2880         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,
   2881         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,
   2882         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,
   2883         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,
   2884         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,
   2885         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,
   2886         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,
   2887         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,
   2888         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,
   2889         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,
   2890         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,
   2891         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,
   2892         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,
   2893         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,
   2894         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,
   2895         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,
   2896         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,
   2897         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,
   2898         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,
   2899         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,
   2900         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,
   2901         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,
   2902         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,
   2903         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,
   2904         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,
   2905         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,
   2906         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,
   2907         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
   2908     };
   2909     static ImWchar base_ranges[] = // not zero-terminated
   2910     {
   2911         0x0020, 0x00FF, // Basic Latin + Latin Supplement
   2912         0x2000, 0x206F, // General Punctuation
   2913         0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
   2914         0x31F0, 0x31FF, // Katakana Phonetic Extensions
   2915         0xFF00, 0xFFEF  // Half-width characters
   2916     };
   2917     static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00) * 2 + 1] = { 0 };
   2918     if (!full_ranges[0])
   2919     {
   2920         memcpy(full_ranges, base_ranges, sizeof(base_ranges));
   2921         UnpackAccumulativeOffsetsIntoRanges(0x4E00, accumulative_offsets_from_0x4E00, IM_ARRAYSIZE(accumulative_offsets_from_0x4E00), full_ranges + IM_ARRAYSIZE(base_ranges));
   2922     }
   2923     return &full_ranges[0];
   2924 }
   2925 
   2926 const ImWchar*  ImFontAtlas::GetGlyphRangesJapanese()
   2927 {
   2928     // 2999 ideograms code points for Japanese
   2929     // - 2136 Joyo (meaning "for regular use" or "for common use") Kanji code points
   2930     // - 863 Jinmeiyo (meaning "for personal name") Kanji code points
   2931     // - Sourced from the character information database of the Information-technology Promotion Agency, Japan
   2932     //   - https://mojikiban.ipa.go.jp/mji/
   2933     //   - Available under the terms of the Creative Commons Attribution-ShareAlike 2.1 Japan (CC BY-SA 2.1 JP).
   2934     //     - https://creativecommons.org/licenses/by-sa/2.1/jp/deed.en
   2935     //     - https://creativecommons.org/licenses/by-sa/2.1/jp/legalcode
   2936     //   - You can generate this code by the script at:
   2937     //     - https://github.com/vaiorabbit/everyday_use_kanji
   2938     // - References:
   2939     //   - List of Joyo Kanji
   2940     //     - (Official list by the Agency for Cultural Affairs) https://www.bunka.go.jp/kokugo_nihongo/sisaku/joho/joho/kakuki/14/tosin02/index.html
   2941     //     - (Wikipedia) https://en.wikipedia.org/wiki/List_of_j%C5%8Dy%C5%8D_kanji
   2942     //   - List of Jinmeiyo Kanji
   2943     //     - (Official list by the Ministry of Justice) http://www.moj.go.jp/MINJI/minji86.html
   2944     //     - (Wikipedia) https://en.wikipedia.org/wiki/Jinmeiy%C5%8D_kanji
   2945     // - Missing 1 Joyo Kanji: U+20B9F (Kun'yomi: Shikaru, On'yomi: Shitsu,shichi), see https://github.com/ocornut/imgui/pull/3627 for details.
   2946     // You can use ImFontGlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters.
   2947     // (Stored as accumulative offsets from the initial unicode codepoint 0x4E00. This encoding is designed to helps us compact the source code size.)
   2948     static const short accumulative_offsets_from_0x4E00[] =
   2949     {
   2950         0,1,2,4,1,1,1,1,2,1,3,3,2,2,1,5,3,5,7,5,6,1,2,1,7,2,6,3,1,8,1,1,4,1,1,18,2,11,2,6,2,1,2,1,5,1,2,1,3,1,2,1,2,3,3,1,1,2,3,1,1,1,12,7,9,1,4,5,1,
   2951         1,2,1,10,1,1,9,2,2,4,5,6,9,3,1,1,1,1,9,3,18,5,2,2,2,2,1,6,3,7,1,1,1,1,2,2,4,2,1,23,2,10,4,3,5,2,4,10,2,4,13,1,6,1,9,3,1,1,6,6,7,6,3,1,2,11,3,
   2952         2,2,3,2,15,2,2,5,4,3,6,4,1,2,5,2,12,16,6,13,9,13,2,1,1,7,16,4,7,1,19,1,5,1,2,2,7,7,8,2,6,5,4,9,18,7,4,5,9,13,11,8,15,2,1,1,1,2,1,2,2,1,2,2,8,
   2953         2,9,3,3,1,1,4,4,1,1,1,4,9,1,4,3,5,5,2,7,5,3,4,8,2,1,13,2,3,3,1,14,1,1,4,5,1,3,6,1,5,2,1,1,3,3,3,3,1,1,2,7,6,6,7,1,4,7,6,1,1,1,1,1,12,3,3,9,5,
   2954         2,6,1,5,6,1,2,3,18,2,4,14,4,1,3,6,1,1,6,3,5,5,3,2,2,2,2,12,3,1,4,2,3,2,3,11,1,7,4,1,2,1,3,17,1,9,1,24,1,1,4,2,2,4,1,2,7,1,1,1,3,1,2,2,4,15,1,
   2955         1,2,1,1,2,1,5,2,5,20,2,5,9,1,10,8,7,6,1,1,1,1,1,1,6,2,1,2,8,1,1,1,1,5,1,1,3,1,1,1,1,3,1,1,12,4,1,3,1,1,1,1,1,10,3,1,7,5,13,1,2,3,4,6,1,1,30,
   2956         2,9,9,1,15,38,11,3,1,8,24,7,1,9,8,10,2,1,9,31,2,13,6,2,9,4,49,5,2,15,2,1,10,2,1,1,1,2,2,6,15,30,35,3,14,18,8,1,16,10,28,12,19,45,38,1,3,2,3,
   2957         13,2,1,7,3,6,5,3,4,3,1,5,7,8,1,5,3,18,5,3,6,1,21,4,24,9,24,40,3,14,3,21,3,2,1,2,4,2,3,1,15,15,6,5,1,1,3,1,5,6,1,9,7,3,3,2,1,4,3,8,21,5,16,4,
   2958         5,2,10,11,11,3,6,3,2,9,3,6,13,1,2,1,1,1,1,11,12,6,6,1,4,2,6,5,2,1,1,3,3,6,13,3,1,1,5,1,2,3,3,14,2,1,2,2,2,5,1,9,5,1,1,6,12,3,12,3,4,13,2,14,
   2959         2,8,1,17,5,1,16,4,2,2,21,8,9,6,23,20,12,25,19,9,38,8,3,21,40,25,33,13,4,3,1,4,1,2,4,1,2,5,26,2,1,1,2,1,3,6,2,1,1,1,1,1,1,2,3,1,1,1,9,2,3,1,1,
   2960         1,3,6,3,2,1,1,6,6,1,8,2,2,2,1,4,1,2,3,2,7,3,2,4,1,2,1,2,2,1,1,1,1,1,3,1,2,5,4,10,9,4,9,1,1,1,1,1,1,5,3,2,1,6,4,9,6,1,10,2,31,17,8,3,7,5,40,1,
   2961         7,7,1,6,5,2,10,7,8,4,15,39,25,6,28,47,18,10,7,1,3,1,1,2,1,1,1,3,3,3,1,1,1,3,4,2,1,4,1,3,6,10,7,8,6,2,2,1,3,3,2,5,8,7,9,12,2,15,1,1,4,1,2,1,1,
   2962         1,3,2,1,3,3,5,6,2,3,2,10,1,4,2,8,1,1,1,11,6,1,21,4,16,3,1,3,1,4,2,3,6,5,1,3,1,1,3,3,4,6,1,1,10,4,2,7,10,4,7,4,2,9,4,3,1,1,1,4,1,8,3,4,1,3,1,
   2963         6,1,4,2,1,4,7,2,1,8,1,4,5,1,1,2,2,4,6,2,7,1,10,1,1,3,4,11,10,8,21,4,6,1,3,5,2,1,2,28,5,5,2,3,13,1,2,3,1,4,2,1,5,20,3,8,11,1,3,3,3,1,8,10,9,2,
   2964         10,9,2,3,1,1,2,4,1,8,3,6,1,7,8,6,11,1,4,29,8,4,3,1,2,7,13,1,4,1,6,2,6,12,12,2,20,3,2,3,6,4,8,9,2,7,34,5,1,18,6,1,1,4,4,5,7,9,1,2,2,4,3,4,1,7,
   2965         2,2,2,6,2,3,25,5,3,6,1,4,6,7,4,2,1,4,2,13,6,4,4,3,1,5,3,4,4,3,2,1,1,4,1,2,1,1,3,1,11,1,6,3,1,7,3,6,2,8,8,6,9,3,4,11,3,2,10,12,2,5,11,1,6,4,5,
   2966         3,1,8,5,4,6,6,3,5,1,1,3,2,1,2,2,6,17,12,1,10,1,6,12,1,6,6,19,9,6,16,1,13,4,4,15,7,17,6,11,9,15,12,6,7,2,1,2,2,15,9,3,21,4,6,49,18,7,3,2,3,1,
   2967         6,8,2,2,6,2,9,1,3,6,4,4,1,2,16,2,5,2,1,6,2,3,5,3,1,2,5,1,2,1,9,3,1,8,6,4,8,11,3,1,1,1,1,3,1,13,8,4,1,3,2,2,1,4,1,11,1,5,2,1,5,2,5,8,6,1,1,7,
   2968         4,3,8,3,2,7,2,1,5,1,5,2,4,7,6,2,8,5,1,11,4,5,3,6,18,1,2,13,3,3,1,21,1,1,4,1,4,1,1,1,8,1,2,2,7,1,2,4,2,2,9,2,1,1,1,4,3,6,3,12,5,1,1,1,5,6,3,2,
   2969         4,8,2,2,4,2,7,1,8,9,5,2,3,2,1,3,2,13,7,14,6,5,1,1,2,1,4,2,23,2,1,1,6,3,1,4,1,15,3,1,7,3,9,14,1,3,1,4,1,1,5,8,1,3,8,3,8,15,11,4,14,4,4,2,5,5,
   2970         1,7,1,6,14,7,7,8,5,15,4,8,6,5,6,2,1,13,1,20,15,11,9,2,5,6,2,11,2,6,2,5,1,5,8,4,13,19,25,4,1,1,11,1,34,2,5,9,14,6,2,2,6,1,1,14,1,3,14,13,1,6,
   2971         12,21,14,14,6,32,17,8,32,9,28,1,2,4,11,8,3,1,14,2,5,15,1,1,1,1,3,6,4,1,3,4,11,3,1,1,11,30,1,5,1,4,1,5,8,1,1,3,2,4,3,17,35,2,6,12,17,3,1,6,2,
   2972         1,1,12,2,7,3,3,2,1,16,2,8,3,6,5,4,7,3,3,8,1,9,8,5,1,2,1,3,2,8,1,2,9,12,1,1,2,3,8,3,24,12,4,3,7,5,8,3,3,3,3,3,3,1,23,10,3,1,2,2,6,3,1,16,1,16,
   2973         22,3,10,4,11,6,9,7,7,3,6,2,2,2,4,10,2,1,1,2,8,7,1,6,4,1,3,3,3,5,10,12,12,2,3,12,8,15,1,1,16,6,6,1,5,9,11,4,11,4,2,6,12,1,17,5,13,1,4,9,5,1,11,
   2974         2,1,8,1,5,7,28,8,3,5,10,2,17,3,38,22,1,2,18,12,10,4,38,18,1,4,44,19,4,1,8,4,1,12,1,4,31,12,1,14,7,75,7,5,10,6,6,13,3,2,11,11,3,2,5,28,15,6,18,
   2975         18,5,6,4,3,16,1,7,18,7,36,3,5,3,1,7,1,9,1,10,7,2,4,2,6,2,9,7,4,3,32,12,3,7,10,2,23,16,3,1,12,3,31,4,11,1,3,8,9,5,1,30,15,6,12,3,2,2,11,19,9,
   2976         14,2,6,2,3,19,13,17,5,3,3,25,3,14,1,1,1,36,1,3,2,19,3,13,36,9,13,31,6,4,16,34,2,5,4,2,3,3,5,1,1,1,4,3,1,17,3,2,3,5,3,1,3,2,3,5,6,3,12,11,1,3,
   2977         1,2,26,7,12,7,2,14,3,3,7,7,11,25,25,28,16,4,36,1,2,1,6,2,1,9,3,27,17,4,3,4,13,4,1,3,2,2,1,10,4,2,4,6,3,8,2,1,18,1,1,24,2,2,4,33,2,3,63,7,1,6,
   2978         40,7,3,4,4,2,4,15,18,1,16,1,1,11,2,41,14,1,3,18,13,3,2,4,16,2,17,7,15,24,7,18,13,44,2,2,3,6,1,1,7,5,1,7,1,4,3,3,5,10,8,2,3,1,8,1,1,27,4,2,1,
   2979         12,1,2,1,10,6,1,6,7,5,2,3,7,11,5,11,3,6,6,2,3,15,4,9,1,1,2,1,2,11,2,8,12,8,5,4,2,3,1,5,2,2,1,14,1,12,11,4,1,11,17,17,4,3,2,5,5,7,3,1,5,9,9,8,
   2980         2,5,6,6,13,13,2,1,2,6,1,2,2,49,4,9,1,2,10,16,7,8,4,3,2,23,4,58,3,29,1,14,19,19,11,11,2,7,5,1,3,4,6,2,18,5,12,12,17,17,3,3,2,4,1,6,2,3,4,3,1,
   2981         1,1,1,5,1,1,9,1,3,1,3,6,1,8,1,1,2,6,4,14,3,1,4,11,4,1,3,32,1,2,4,13,4,1,2,4,2,1,3,1,11,1,4,2,1,4,4,6,3,5,1,6,5,7,6,3,23,3,5,3,5,3,3,13,3,9,10,
   2982         1,12,10,2,3,18,13,7,160,52,4,2,2,3,2,14,5,4,12,4,6,4,1,20,4,11,6,2,12,27,1,4,1,2,2,7,4,5,2,28,3,7,25,8,3,19,3,6,10,2,2,1,10,2,5,4,1,3,4,1,5,
   2983         3,2,6,9,3,6,2,16,3,3,16,4,5,5,3,2,1,2,16,15,8,2,6,21,2,4,1,22,5,8,1,1,21,11,2,1,11,11,19,13,12,4,2,3,2,3,6,1,8,11,1,4,2,9,5,2,1,11,2,9,1,1,2,
   2984         14,31,9,3,4,21,14,4,8,1,7,2,2,2,5,1,4,20,3,3,4,10,1,11,9,8,2,1,4,5,14,12,14,2,17,9,6,31,4,14,1,20,13,26,5,2,7,3,6,13,2,4,2,19,6,2,2,18,9,3,5,
   2985         12,12,14,4,6,2,3,6,9,5,22,4,5,25,6,4,8,5,2,6,27,2,35,2,16,3,7,8,8,6,6,5,9,17,2,20,6,19,2,13,3,1,1,1,4,17,12,2,14,7,1,4,18,12,38,33,2,10,1,1,
   2986         2,13,14,17,11,50,6,33,20,26,74,16,23,45,50,13,38,33,6,6,7,4,4,2,1,3,2,5,8,7,8,9,3,11,21,9,13,1,3,10,6,7,1,2,2,18,5,5,1,9,9,2,68,9,19,13,2,5,
   2987         1,4,4,7,4,13,3,9,10,21,17,3,26,2,1,5,2,4,5,4,1,7,4,7,3,4,2,1,6,1,1,20,4,1,9,2,2,1,3,3,2,3,2,1,1,1,20,2,3,1,6,2,3,6,2,4,8,1,3,2,10,3,5,3,4,4,
   2988         3,4,16,1,6,1,10,2,4,2,1,1,2,10,11,2,2,3,1,24,31,4,10,10,2,5,12,16,164,15,4,16,7,9,15,19,17,1,2,1,1,5,1,1,1,1,1,3,1,4,3,1,3,1,3,1,2,1,1,3,3,7,
   2989         2,8,1,2,2,2,1,3,4,3,7,8,12,92,2,10,3,1,3,14,5,25,16,42,4,7,7,4,2,21,5,27,26,27,21,25,30,31,2,1,5,13,3,22,5,6,6,11,9,12,1,5,9,7,5,5,22,60,3,5,
   2990         13,1,1,8,1,1,3,3,2,1,9,3,3,18,4,1,2,3,7,6,3,1,2,3,9,1,3,1,3,2,1,3,1,1,1,2,1,11,3,1,6,9,1,3,2,3,1,2,1,5,1,1,4,3,4,1,2,2,4,4,1,7,2,1,2,2,3,5,13,
   2991         18,3,4,14,9,9,4,16,3,7,5,8,2,6,48,28,3,1,1,4,2,14,8,2,9,2,1,15,2,4,3,2,10,16,12,8,7,1,1,3,1,1,1,2,7,4,1,6,4,38,39,16,23,7,15,15,3,2,12,7,21,
   2992         37,27,6,5,4,8,2,10,8,8,6,5,1,2,1,3,24,1,16,17,9,23,10,17,6,1,51,55,44,13,294,9,3,6,2,4,2,2,15,1,1,1,13,21,17,68,14,8,9,4,1,4,9,3,11,7,1,1,1,
   2993         5,6,3,2,1,1,1,2,3,8,1,2,2,4,1,5,5,2,1,4,3,7,13,4,1,4,1,3,1,1,1,5,5,10,1,6,1,5,2,1,5,2,4,1,4,5,7,3,18,2,9,11,32,4,3,3,2,4,7,11,16,9,11,8,13,38,
   2994         32,8,4,2,1,1,2,1,2,4,4,1,1,1,4,1,21,3,11,1,16,1,1,6,1,3,2,4,9,8,57,7,44,1,3,3,13,3,10,1,1,7,5,2,7,21,47,63,3,15,4,7,1,16,1,1,2,8,2,3,42,15,4,
   2995         1,29,7,22,10,3,78,16,12,20,18,4,67,11,5,1,3,15,6,21,31,32,27,18,13,71,35,5,142,4,10,1,2,50,19,33,16,35,37,16,19,27,7,1,133,19,1,4,8,7,20,1,4,
   2996         4,1,10,3,1,6,1,2,51,5,40,15,24,43,22928,11,1,13,154,70,3,1,1,7,4,10,1,2,1,1,2,1,2,1,2,2,1,1,2,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,
   2997         3,2,1,1,1,1,2,1,1,
   2998     };
   2999     static ImWchar base_ranges[] = // not zero-terminated
   3000     {
   3001         0x0020, 0x00FF, // Basic Latin + Latin Supplement
   3002         0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
   3003         0x31F0, 0x31FF, // Katakana Phonetic Extensions
   3004         0xFF00, 0xFFEF  // Half-width characters
   3005     };
   3006     static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00)*2 + 1] = { 0 };
   3007     if (!full_ranges[0])
   3008     {
   3009         memcpy(full_ranges, base_ranges, sizeof(base_ranges));
   3010         UnpackAccumulativeOffsetsIntoRanges(0x4E00, accumulative_offsets_from_0x4E00, IM_ARRAYSIZE(accumulative_offsets_from_0x4E00), full_ranges + IM_ARRAYSIZE(base_ranges));
   3011     }
   3012     return &full_ranges[0];
   3013 }
   3014 
   3015 const ImWchar*  ImFontAtlas::GetGlyphRangesCyrillic()
   3016 {
   3017     static const ImWchar ranges[] =
   3018     {
   3019         0x0020, 0x00FF, // Basic Latin + Latin Supplement
   3020         0x0400, 0x052F, // Cyrillic + Cyrillic Supplement
   3021         0x2DE0, 0x2DFF, // Cyrillic Extended-A
   3022         0xA640, 0xA69F, // Cyrillic Extended-B
   3023         0,
   3024     };
   3025     return &ranges[0];
   3026 }
   3027 
   3028 const ImWchar*  ImFontAtlas::GetGlyphRangesThai()
   3029 {
   3030     static const ImWchar ranges[] =
   3031     {
   3032         0x0020, 0x00FF, // Basic Latin
   3033         0x2010, 0x205E, // Punctuations
   3034         0x0E00, 0x0E7F, // Thai
   3035         0,
   3036     };
   3037     return &ranges[0];
   3038 }
   3039 
   3040 const ImWchar*  ImFontAtlas::GetGlyphRangesVietnamese()
   3041 {
   3042     static const ImWchar ranges[] =
   3043     {
   3044         0x0020, 0x00FF, // Basic Latin
   3045         0x0102, 0x0103,
   3046         0x0110, 0x0111,
   3047         0x0128, 0x0129,
   3048         0x0168, 0x0169,
   3049         0x01A0, 0x01A1,
   3050         0x01AF, 0x01B0,
   3051         0x1EA0, 0x1EF9,
   3052         0,
   3053     };
   3054     return &ranges[0];
   3055 }
   3056 
   3057 //-----------------------------------------------------------------------------
   3058 // [SECTION] ImFontGlyphRangesBuilder
   3059 //-----------------------------------------------------------------------------
   3060 
   3061 void ImFontGlyphRangesBuilder::AddText(const char* text, const char* text_end)
   3062 {
   3063     while (text_end ? (text < text_end) : *text)
   3064     {
   3065         unsigned int c = 0;
   3066         int c_len = ImTextCharFromUtf8(&c, text, text_end);
   3067         text += c_len;
   3068         if (c_len == 0)
   3069             break;
   3070         AddChar((ImWchar)c);
   3071     }
   3072 }
   3073 
   3074 void ImFontGlyphRangesBuilder::AddRanges(const ImWchar* ranges)
   3075 {
   3076     for (; ranges[0]; ranges += 2)
   3077         for (ImWchar c = ranges[0]; c <= ranges[1]; c++)
   3078             AddChar(c);
   3079 }
   3080 
   3081 void ImFontGlyphRangesBuilder::BuildRanges(ImVector<ImWchar>* out_ranges)
   3082 {
   3083     const int max_codepoint = IM_UNICODE_CODEPOINT_MAX;
   3084     for (int n = 0; n <= max_codepoint; n++)
   3085         if (GetBit(n))
   3086         {
   3087             out_ranges->push_back((ImWchar)n);
   3088             while (n < max_codepoint && GetBit(n + 1))
   3089                 n++;
   3090             out_ranges->push_back((ImWchar)n);
   3091         }
   3092     out_ranges->push_back(0);
   3093 }
   3094 
   3095 //-----------------------------------------------------------------------------
   3096 // [SECTION] ImFont
   3097 //-----------------------------------------------------------------------------
   3098 
   3099 ImFont::ImFont()
   3100 {
   3101     FontSize = 0.0f;
   3102     FallbackAdvanceX = 0.0f;
   3103     FallbackChar = (ImWchar)'?';
   3104     EllipsisChar = (ImWchar)-1;
   3105     FallbackGlyph = NULL;
   3106     ContainerAtlas = NULL;
   3107     ConfigData = NULL;
   3108     ConfigDataCount = 0;
   3109     DirtyLookupTables = false;
   3110     Scale = 1.0f;
   3111     Ascent = Descent = 0.0f;
   3112     MetricsTotalSurface = 0;
   3113     memset(Used4kPagesMap, 0, sizeof(Used4kPagesMap));
   3114 }
   3115 
   3116 ImFont::~ImFont()
   3117 {
   3118     ClearOutputData();
   3119 }
   3120 
   3121 void    ImFont::ClearOutputData()
   3122 {
   3123     FontSize = 0.0f;
   3124     FallbackAdvanceX = 0.0f;
   3125     Glyphs.clear();
   3126     IndexAdvanceX.clear();
   3127     IndexLookup.clear();
   3128     FallbackGlyph = NULL;
   3129     ContainerAtlas = NULL;
   3130     DirtyLookupTables = true;
   3131     Ascent = Descent = 0.0f;
   3132     MetricsTotalSurface = 0;
   3133 }
   3134 
   3135 void ImFont::BuildLookupTable()
   3136 {
   3137     int max_codepoint = 0;
   3138     for (int i = 0; i != Glyphs.Size; i++)
   3139         max_codepoint = ImMax(max_codepoint, (int)Glyphs[i].Codepoint);
   3140 
   3141     // Build lookup table
   3142     IM_ASSERT(Glyphs.Size < 0xFFFF); // -1 is reserved
   3143     IndexAdvanceX.clear();
   3144     IndexLookup.clear();
   3145     DirtyLookupTables = false;
   3146     memset(Used4kPagesMap, 0, sizeof(Used4kPagesMap));
   3147     GrowIndex(max_codepoint + 1);
   3148     for (int i = 0; i < Glyphs.Size; i++)
   3149     {
   3150         int codepoint = (int)Glyphs[i].Codepoint;
   3151         IndexAdvanceX[codepoint] = Glyphs[i].AdvanceX;
   3152         IndexLookup[codepoint] = (ImWchar)i;
   3153 
   3154         // Mark 4K page as used
   3155         const int page_n = codepoint / 4096;
   3156         Used4kPagesMap[page_n >> 3] |= 1 << (page_n & 7);
   3157     }
   3158 
   3159     // Create a glyph to handle TAB
   3160     // FIXME: Needs proper TAB handling but it needs to be contextualized (or we could arbitrary say that each string starts at "column 0" ?)
   3161     if (FindGlyph((ImWchar)' '))
   3162     {
   3163         if (Glyphs.back().Codepoint != '\t')   // So we can call this function multiple times (FIXME: Flaky)
   3164             Glyphs.resize(Glyphs.Size + 1);
   3165         ImFontGlyph& tab_glyph = Glyphs.back();
   3166         tab_glyph = *FindGlyph((ImWchar)' ');
   3167         tab_glyph.Codepoint = '\t';
   3168         tab_glyph.AdvanceX *= IM_TABSIZE;
   3169         IndexAdvanceX[(int)tab_glyph.Codepoint] = (float)tab_glyph.AdvanceX;
   3170         IndexLookup[(int)tab_glyph.Codepoint] = (ImWchar)(Glyphs.Size - 1);
   3171     }
   3172 
   3173     // Mark special glyphs as not visible (note that AddGlyph already mark as non-visible glyphs with zero-size polygons)
   3174     SetGlyphVisible((ImWchar)' ', false);
   3175     SetGlyphVisible((ImWchar)'\t', false);
   3176 
   3177     // Setup fall-backs
   3178     FallbackGlyph = FindGlyphNoFallback(FallbackChar);
   3179     FallbackAdvanceX = FallbackGlyph ? FallbackGlyph->AdvanceX : 0.0f;
   3180     for (int i = 0; i < max_codepoint + 1; i++)
   3181         if (IndexAdvanceX[i] < 0.0f)
   3182             IndexAdvanceX[i] = FallbackAdvanceX;
   3183 }
   3184 
   3185 // API is designed this way to avoid exposing the 4K page size
   3186 // e.g. use with IsGlyphRangeUnused(0, 255)
   3187 bool ImFont::IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last)
   3188 {
   3189     unsigned int page_begin = (c_begin / 4096);
   3190     unsigned int page_last = (c_last / 4096);
   3191     for (unsigned int page_n = page_begin; page_n <= page_last; page_n++)
   3192         if ((page_n >> 3) < sizeof(Used4kPagesMap))
   3193             if (Used4kPagesMap[page_n >> 3] & (1 << (page_n & 7)))
   3194                 return false;
   3195     return true;
   3196 }
   3197 
   3198 void ImFont::SetGlyphVisible(ImWchar c, bool visible)
   3199 {
   3200     if (ImFontGlyph* glyph = (ImFontGlyph*)(void*)FindGlyph((ImWchar)c))
   3201         glyph->Visible = visible ? 1 : 0;
   3202 }
   3203 
   3204 void ImFont::SetFallbackChar(ImWchar c)
   3205 {
   3206     FallbackChar = c;
   3207     BuildLookupTable();
   3208 }
   3209 
   3210 void ImFont::GrowIndex(int new_size)
   3211 {
   3212     IM_ASSERT(IndexAdvanceX.Size == IndexLookup.Size);
   3213     if (new_size <= IndexLookup.Size)
   3214         return;
   3215     IndexAdvanceX.resize(new_size, -1.0f);
   3216     IndexLookup.resize(new_size, (ImWchar)-1);
   3217 }
   3218 
   3219 // x0/y0/x1/y1 are offset from the character upper-left layout position, in pixels. Therefore x0/y0 are often fairly close to zero.
   3220 // 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).
   3221 // 'cfg' is not necessarily == 'this->ConfigData' because multiple source fonts+configs can be used to build one target font.
   3222 void ImFont::AddGlyph(const ImFontConfig* cfg, ImWchar codepoint, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x)
   3223 {
   3224     if (cfg != NULL)
   3225     {
   3226         // Clamp & recenter if needed
   3227         const float advance_x_original = advance_x;
   3228         advance_x = ImClamp(advance_x, cfg->GlyphMinAdvanceX, cfg->GlyphMaxAdvanceX);
   3229         if (advance_x != advance_x_original)
   3230         {
   3231             float char_off_x = cfg->PixelSnapH ? ImFloor((advance_x - advance_x_original) * 0.5f) : (advance_x - advance_x_original) * 0.5f;
   3232             x0 += char_off_x;
   3233             x1 += char_off_x;
   3234         }
   3235 
   3236         // Snap to pixel
   3237         if (cfg->PixelSnapH)
   3238             advance_x = IM_ROUND(advance_x);
   3239 
   3240         // Bake spacing
   3241         advance_x += cfg->GlyphExtraSpacing.x;
   3242     }
   3243 
   3244     Glyphs.resize(Glyphs.Size + 1);
   3245     ImFontGlyph& glyph = Glyphs.back();
   3246     glyph.Codepoint = (unsigned int)codepoint;
   3247     glyph.Visible = (x0 != x1) && (y0 != y1);
   3248     glyph.Colored = false;
   3249     glyph.X0 = x0;
   3250     glyph.Y0 = y0;
   3251     glyph.X1 = x1;
   3252     glyph.Y1 = y1;
   3253     glyph.U0 = u0;
   3254     glyph.V0 = v0;
   3255     glyph.U1 = u1;
   3256     glyph.V1 = v1;
   3257     glyph.AdvanceX = advance_x;
   3258 
   3259     // Compute rough surface usage metrics (+1 to account for average padding, +0.99 to round)
   3260     // We use (U1-U0)*TexWidth instead of X1-X0 to account for oversampling.
   3261     float pad = ContainerAtlas->TexGlyphPadding + 0.99f;
   3262     DirtyLookupTables = true;
   3263     MetricsTotalSurface += (int)((glyph.U1 - glyph.U0) * ContainerAtlas->TexWidth + pad) * (int)((glyph.V1 - glyph.V0) * ContainerAtlas->TexHeight + pad);
   3264 }
   3265 
   3266 void ImFont::AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst)
   3267 {
   3268     IM_ASSERT(IndexLookup.Size > 0);    // Currently this can only be called AFTER the font has been built, aka after calling ImFontAtlas::GetTexDataAs*() function.
   3269     unsigned int index_size = (unsigned int)IndexLookup.Size;
   3270 
   3271     if (dst < index_size && IndexLookup.Data[dst] == (ImWchar)-1 && !overwrite_dst) // 'dst' already exists
   3272         return;
   3273     if (src >= index_size && dst >= index_size) // both 'dst' and 'src' don't exist -> no-op
   3274         return;
   3275 
   3276     GrowIndex(dst + 1);
   3277     IndexLookup[dst] = (src < index_size) ? IndexLookup.Data[src] : (ImWchar)-1;
   3278     IndexAdvanceX[dst] = (src < index_size) ? IndexAdvanceX.Data[src] : 1.0f;
   3279 }
   3280 
   3281 const ImFontGlyph* ImFont::FindGlyph(ImWchar c) const
   3282 {
   3283     if (c >= (size_t)IndexLookup.Size)
   3284         return FallbackGlyph;
   3285     const ImWchar i = IndexLookup.Data[c];
   3286     if (i == (ImWchar)-1)
   3287         return FallbackGlyph;
   3288     return &Glyphs.Data[i];
   3289 }
   3290 
   3291 const ImFontGlyph* ImFont::FindGlyphNoFallback(ImWchar c) const
   3292 {
   3293     if (c >= (size_t)IndexLookup.Size)
   3294         return NULL;
   3295     const ImWchar i = IndexLookup.Data[c];
   3296     if (i == (ImWchar)-1)
   3297         return NULL;
   3298     return &Glyphs.Data[i];
   3299 }
   3300 
   3301 const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) const
   3302 {
   3303     // Simple word-wrapping for English, not full-featured. Please submit failing cases!
   3304     // 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.)
   3305 
   3306     // For references, possible wrap point marked with ^
   3307     //  "aaa bbb, ccc,ddd. eee   fff. ggg!"
   3308     //      ^    ^    ^   ^   ^__    ^    ^
   3309 
   3310     // List of hardcoded separators: .,;!?'"
   3311 
   3312     // Skip extra blanks after a line returns (that includes not counting them in width computation)
   3313     // e.g. "Hello    world" --> "Hello" "World"
   3314 
   3315     // Cut words that cannot possibly fit within one line.
   3316     // e.g.: "The tropical fish" with ~5 characters worth of width --> "The tr" "opical" "fish"
   3317 
   3318     float line_width = 0.0f;
   3319     float word_width = 0.0f;
   3320     float blank_width = 0.0f;
   3321     wrap_width /= scale; // We work with unscaled widths to avoid scaling every characters
   3322 
   3323     const char* word_end = text;
   3324     const char* prev_word_end = NULL;
   3325     bool inside_word = true;
   3326 
   3327     const char* s = text;
   3328     while (s < text_end)
   3329     {
   3330         unsigned int c = (unsigned int)*s;
   3331         const char* next_s;
   3332         if (c < 0x80)
   3333             next_s = s + 1;
   3334         else
   3335             next_s = s + ImTextCharFromUtf8(&c, s, text_end);
   3336         if (c == 0)
   3337             break;
   3338 
   3339         if (c < 32)
   3340         {
   3341             if (c == '\n')
   3342             {
   3343                 line_width = word_width = blank_width = 0.0f;
   3344                 inside_word = true;
   3345                 s = next_s;
   3346                 continue;
   3347             }
   3348             if (c == '\r')
   3349             {
   3350                 s = next_s;
   3351                 continue;
   3352             }
   3353         }
   3354 
   3355         const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX.Data[c] : FallbackAdvanceX);
   3356         if (ImCharIsBlankW(c))
   3357         {
   3358             if (inside_word)
   3359             {
   3360                 line_width += blank_width;
   3361                 blank_width = 0.0f;
   3362                 word_end = s;
   3363             }
   3364             blank_width += char_width;
   3365             inside_word = false;
   3366         }
   3367         else
   3368         {
   3369             word_width += char_width;
   3370             if (inside_word)
   3371             {
   3372                 word_end = next_s;
   3373             }
   3374             else
   3375             {
   3376                 prev_word_end = word_end;
   3377                 line_width += word_width + blank_width;
   3378                 word_width = blank_width = 0.0f;
   3379             }
   3380 
   3381             // Allow wrapping after punctuation.
   3382             inside_word = (c != '.' && c != ',' && c != ';' && c != '!' && c != '?' && c != '\"');
   3383         }
   3384 
   3385         // We ignore blank width at the end of the line (they can be skipped)
   3386         if (line_width + word_width > wrap_width)
   3387         {
   3388             // Words that cannot possibly fit within an entire line will be cut anywhere.
   3389             if (word_width < wrap_width)
   3390                 s = prev_word_end ? prev_word_end : word_end;
   3391             break;
   3392         }
   3393 
   3394         s = next_s;
   3395     }
   3396 
   3397     return s;
   3398 }
   3399 
   3400 ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end, const char** remaining) const
   3401 {
   3402     if (!text_end)
   3403         text_end = text_begin + strlen(text_begin); // FIXME-OPT: Need to avoid this.
   3404 
   3405     const float line_height = size;
   3406     const float scale = size / FontSize;
   3407 
   3408     ImVec2 text_size = ImVec2(0, 0);
   3409     float line_width = 0.0f;
   3410 
   3411     const bool word_wrap_enabled = (wrap_width > 0.0f);
   3412     const char* word_wrap_eol = NULL;
   3413 
   3414     const char* s = text_begin;
   3415     while (s < text_end)
   3416     {
   3417         if (word_wrap_enabled)
   3418         {
   3419             // 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.
   3420             if (!word_wrap_eol)
   3421             {
   3422                 word_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - line_width);
   3423                 if (word_wrap_eol == s) // Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity.
   3424                     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
   3425             }
   3426 
   3427             if (s >= word_wrap_eol)
   3428             {
   3429                 if (text_size.x < line_width)
   3430                     text_size.x = line_width;
   3431                 text_size.y += line_height;
   3432                 line_width = 0.0f;
   3433                 word_wrap_eol = NULL;
   3434 
   3435                 // Wrapping skips upcoming blanks
   3436                 while (s < text_end)
   3437                 {
   3438                     const char c = *s;
   3439                     if (ImCharIsBlankA(c)) { s++; } else if (c == '\n') { s++; break; } else { break; }
   3440                 }
   3441                 continue;
   3442             }
   3443         }
   3444 
   3445         // Decode and advance source
   3446         const char* prev_s = s;
   3447         unsigned int c = (unsigned int)*s;
   3448         if (c < 0x80)
   3449         {
   3450             s += 1;
   3451         }
   3452         else
   3453         {
   3454             s += ImTextCharFromUtf8(&c, s, text_end);
   3455             if (c == 0) // Malformed UTF-8?
   3456                 break;
   3457         }
   3458 
   3459         if (c < 32)
   3460         {
   3461             if (c == '\n')
   3462             {
   3463                 text_size.x = ImMax(text_size.x, line_width);
   3464                 text_size.y += line_height;
   3465                 line_width = 0.0f;
   3466                 continue;
   3467             }
   3468             if (c == '\r')
   3469                 continue;
   3470         }
   3471 
   3472         const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX.Data[c] : FallbackAdvanceX) * scale;
   3473         if (line_width + char_width >= max_width)
   3474         {
   3475             s = prev_s;
   3476             break;
   3477         }
   3478 
   3479         line_width += char_width;
   3480     }
   3481 
   3482     if (text_size.x < line_width)
   3483         text_size.x = line_width;
   3484 
   3485     if (line_width > 0 || text_size.y == 0.0f)
   3486         text_size.y += line_height;
   3487 
   3488     if (remaining)
   3489         *remaining = s;
   3490 
   3491     return text_size;
   3492 }
   3493 
   3494 // Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound.
   3495 void ImFont::RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, ImWchar c) const
   3496 {
   3497     const ImFontGlyph* glyph = FindGlyph(c);
   3498     if (!glyph || !glyph->Visible)
   3499         return;
   3500     if (glyph->Colored)
   3501         col |= ~IM_COL32_A_MASK;
   3502     float scale = (size >= 0.0f) ? (size / FontSize) : 1.0f;
   3503     pos.x = IM_FLOOR(pos.x);
   3504     pos.y = IM_FLOOR(pos.y);
   3505     draw_list->PrimReserve(6, 4);
   3506     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);
   3507 }
   3508 
   3509 // Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound.
   3510 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
   3511 {
   3512     if (!text_end)
   3513         text_end = text_begin + strlen(text_begin); // ImGui:: functions generally already provides a valid text_end, so this is merely to handle direct calls.
   3514 
   3515     // Align to be pixel perfect
   3516     pos.x = IM_FLOOR(pos.x);
   3517     pos.y = IM_FLOOR(pos.y);
   3518     float x = pos.x;
   3519     float y = pos.y;
   3520     if (y > clip_rect.w)
   3521         return;
   3522 
   3523     const float scale = size / FontSize;
   3524     const float line_height = FontSize * scale;
   3525     const bool word_wrap_enabled = (wrap_width > 0.0f);
   3526     const char* word_wrap_eol = NULL;
   3527 
   3528     // Fast-forward to first visible line
   3529     const char* s = text_begin;
   3530     if (y + line_height < clip_rect.y && !word_wrap_enabled)
   3531         while (y + line_height < clip_rect.y && s < text_end)
   3532         {
   3533             s = (const char*)memchr(s, '\n', text_end - s);
   3534             s = s ? s + 1 : text_end;
   3535             y += line_height;
   3536         }
   3537 
   3538     // For large text, scan for the last visible line in order to avoid over-reserving in the call to PrimReserve()
   3539     // 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)
   3540     if (text_end - s > 10000 && !word_wrap_enabled)
   3541     {
   3542         const char* s_end = s;
   3543         float y_end = y;
   3544         while (y_end < clip_rect.w && s_end < text_end)
   3545         {
   3546             s_end = (const char*)memchr(s_end, '\n', text_end - s_end);
   3547             s_end = s_end ? s_end + 1 : text_end;
   3548             y_end += line_height;
   3549         }
   3550         text_end = s_end;
   3551     }
   3552     if (s == text_end)
   3553         return;
   3554 
   3555     // Reserve vertices for remaining worse case (over-reserving is useful and easily amortized)
   3556     const int vtx_count_max = (int)(text_end - s) * 4;
   3557     const int idx_count_max = (int)(text_end - s) * 6;
   3558     const int idx_expected_size = draw_list->IdxBuffer.Size + idx_count_max;
   3559     draw_list->PrimReserve(idx_count_max, vtx_count_max);
   3560 
   3561     ImDrawVert* vtx_write = draw_list->_VtxWritePtr;
   3562     ImDrawIdx* idx_write = draw_list->_IdxWritePtr;
   3563     unsigned int vtx_current_idx = draw_list->_VtxCurrentIdx;
   3564 
   3565     const ImU32 col_untinted = col | ~IM_COL32_A_MASK;
   3566 
   3567     while (s < text_end)
   3568     {
   3569         if (word_wrap_enabled)
   3570         {
   3571             // 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.
   3572             if (!word_wrap_eol)
   3573             {
   3574                 word_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - (x - pos.x));
   3575                 if (word_wrap_eol == s) // Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity.
   3576                     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
   3577             }
   3578 
   3579             if (s >= word_wrap_eol)
   3580             {
   3581                 x = pos.x;
   3582                 y += line_height;
   3583                 word_wrap_eol = NULL;
   3584 
   3585                 // Wrapping skips upcoming blanks
   3586                 while (s < text_end)
   3587                 {
   3588                     const char c = *s;
   3589                     if (ImCharIsBlankA(c)) { s++; } else if (c == '\n') { s++; break; } else { break; }
   3590                 }
   3591                 continue;
   3592             }
   3593         }
   3594 
   3595         // Decode and advance source
   3596         unsigned int c = (unsigned int)*s;
   3597         if (c < 0x80)
   3598         {
   3599             s += 1;
   3600         }
   3601         else
   3602         {
   3603             s += ImTextCharFromUtf8(&c, s, text_end);
   3604             if (c == 0) // Malformed UTF-8?
   3605                 break;
   3606         }
   3607 
   3608         if (c < 32)
   3609         {
   3610             if (c == '\n')
   3611             {
   3612                 x = pos.x;
   3613                 y += line_height;
   3614                 if (y > clip_rect.w)
   3615                     break; // break out of main loop
   3616                 continue;
   3617             }
   3618             if (c == '\r')
   3619                 continue;
   3620         }
   3621 
   3622         const ImFontGlyph* glyph = FindGlyph((ImWchar)c);
   3623         if (glyph == NULL)
   3624             continue;
   3625 
   3626         float char_width = glyph->AdvanceX * scale;
   3627         if (glyph->Visible)
   3628         {
   3629             // 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
   3630             float x1 = x + glyph->X0 * scale;
   3631             float x2 = x + glyph->X1 * scale;
   3632             float y1 = y + glyph->Y0 * scale;
   3633             float y2 = y + glyph->Y1 * scale;
   3634             if (x1 <= clip_rect.z && x2 >= clip_rect.x)
   3635             {
   3636                 // Render a character
   3637                 float u1 = glyph->U0;
   3638                 float v1 = glyph->V0;
   3639                 float u2 = glyph->U1;
   3640                 float v2 = glyph->V1;
   3641 
   3642                 // CPU side clipping used to fit text in their frame when the frame is too small. Only does clipping for axis aligned quads.
   3643                 if (cpu_fine_clip)
   3644                 {
   3645                     if (x1 < clip_rect.x)
   3646                     {
   3647                         u1 = u1 + (1.0f - (x2 - clip_rect.x) / (x2 - x1)) * (u2 - u1);
   3648                         x1 = clip_rect.x;
   3649                     }
   3650                     if (y1 < clip_rect.y)
   3651                     {
   3652                         v1 = v1 + (1.0f - (y2 - clip_rect.y) / (y2 - y1)) * (v2 - v1);
   3653                         y1 = clip_rect.y;
   3654                     }
   3655                     if (x2 > clip_rect.z)
   3656                     {
   3657                         u2 = u1 + ((clip_rect.z - x1) / (x2 - x1)) * (u2 - u1);
   3658                         x2 = clip_rect.z;
   3659                     }
   3660                     if (y2 > clip_rect.w)
   3661                     {
   3662                         v2 = v1 + ((clip_rect.w - y1) / (y2 - y1)) * (v2 - v1);
   3663                         y2 = clip_rect.w;
   3664                     }
   3665                     if (y1 >= y2)
   3666                     {
   3667                         x += char_width;
   3668                         continue;
   3669                     }
   3670                 }
   3671 
   3672                 // Support for untinted glyphs
   3673                 ImU32 glyph_col = glyph->Colored ? col_untinted : col;
   3674 
   3675                 // We are NOT calling PrimRectUV() here because non-inlined causes too much overhead in a debug builds. Inlined here:
   3676                 {
   3677                     idx_write[0] = (ImDrawIdx)(vtx_current_idx); idx_write[1] = (ImDrawIdx)(vtx_current_idx+1); idx_write[2] = (ImDrawIdx)(vtx_current_idx+2);
   3678                     idx_write[3] = (ImDrawIdx)(vtx_current_idx); idx_write[4] = (ImDrawIdx)(vtx_current_idx+2); idx_write[5] = (ImDrawIdx)(vtx_current_idx+3);
   3679                     vtx_write[0].pos.x = x1; vtx_write[0].pos.y = y1; vtx_write[0].col = glyph_col; vtx_write[0].uv.x = u1; vtx_write[0].uv.y = v1;
   3680                     vtx_write[1].pos.x = x2; vtx_write[1].pos.y = y1; vtx_write[1].col = glyph_col; vtx_write[1].uv.x = u2; vtx_write[1].uv.y = v1;
   3681                     vtx_write[2].pos.x = x2; vtx_write[2].pos.y = y2; vtx_write[2].col = glyph_col; vtx_write[2].uv.x = u2; vtx_write[2].uv.y = v2;
   3682                     vtx_write[3].pos.x = x1; vtx_write[3].pos.y = y2; vtx_write[3].col = glyph_col; vtx_write[3].uv.x = u1; vtx_write[3].uv.y = v2;
   3683                     vtx_write += 4;
   3684                     vtx_current_idx += 4;
   3685                     idx_write += 6;
   3686                 }
   3687             }
   3688         }
   3689         x += char_width;
   3690     }
   3691 
   3692     // Give back unused vertices (clipped ones, blanks) ~ this is essentially a PrimUnreserve() action.
   3693     draw_list->VtxBuffer.Size = (int)(vtx_write - draw_list->VtxBuffer.Data); // Same as calling shrink()
   3694     draw_list->IdxBuffer.Size = (int)(idx_write - draw_list->IdxBuffer.Data);
   3695     draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 1].ElemCount -= (idx_expected_size - draw_list->IdxBuffer.Size);
   3696     draw_list->_VtxWritePtr = vtx_write;
   3697     draw_list->_IdxWritePtr = idx_write;
   3698     draw_list->_VtxCurrentIdx = vtx_current_idx;
   3699 }
   3700 
   3701 //-----------------------------------------------------------------------------
   3702 // [SECTION] ImGui Internal Render Helpers
   3703 //-----------------------------------------------------------------------------
   3704 // Vaguely redesigned to stop accessing ImGui global state:
   3705 // - RenderArrow()
   3706 // - RenderBullet()
   3707 // - RenderCheckMark()
   3708 // - RenderMouseCursor()
   3709 // - RenderArrowPointingAt()
   3710 // - RenderRectFilledRangeH()
   3711 //-----------------------------------------------------------------------------
   3712 // Function in need of a redesign (legacy mess)
   3713 // - RenderColorRectWithAlphaCheckerboard()
   3714 //-----------------------------------------------------------------------------
   3715 
   3716 // Render an arrow aimed to be aligned with text (p_min is a position in the same space text would be positioned). To e.g. denote expanded/collapsed state
   3717 void ImGui::RenderArrow(ImDrawList* draw_list, ImVec2 pos, ImU32 col, ImGuiDir dir, float scale)
   3718 {
   3719     const float h = draw_list->_Data->FontSize * 1.00f;
   3720     float r = h * 0.40f * scale;
   3721     ImVec2 center = pos + ImVec2(h * 0.50f, h * 0.50f * scale);
   3722 
   3723     ImVec2 a, b, c;
   3724     switch (dir)
   3725     {
   3726     case ImGuiDir_Up:
   3727     case ImGuiDir_Down:
   3728         if (dir == ImGuiDir_Up) r = -r;
   3729         a = ImVec2(+0.000f, +0.750f) * r;
   3730         b = ImVec2(-0.866f, -0.750f) * r;
   3731         c = ImVec2(+0.866f, -0.750f) * r;
   3732         break;
   3733     case ImGuiDir_Left:
   3734     case ImGuiDir_Right:
   3735         if (dir == ImGuiDir_Left) r = -r;
   3736         a = ImVec2(+0.750f, +0.000f) * r;
   3737         b = ImVec2(-0.750f, +0.866f) * r;
   3738         c = ImVec2(-0.750f, -0.866f) * r;
   3739         break;
   3740     case ImGuiDir_None:
   3741     case ImGuiDir_COUNT:
   3742         IM_ASSERT(0);
   3743         break;
   3744     }
   3745     draw_list->AddTriangleFilled(center + a, center + b, center + c, col);
   3746 }
   3747 
   3748 void ImGui::RenderBullet(ImDrawList* draw_list, ImVec2 pos, ImU32 col)
   3749 {
   3750     draw_list->AddCircleFilled(pos, draw_list->_Data->FontSize * 0.20f, col, 8);
   3751 }
   3752 
   3753 void ImGui::RenderCheckMark(ImDrawList* draw_list, ImVec2 pos, ImU32 col, float sz)
   3754 {
   3755     float thickness = ImMax(sz / 5.0f, 1.0f);
   3756     sz -= thickness * 0.5f;
   3757     pos += ImVec2(thickness * 0.25f, thickness * 0.25f);
   3758 
   3759     float third = sz / 3.0f;
   3760     float bx = pos.x + third;
   3761     float by = pos.y + sz - third * 0.5f;
   3762     draw_list->PathLineTo(ImVec2(bx - third, by - third));
   3763     draw_list->PathLineTo(ImVec2(bx, by));
   3764     draw_list->PathLineTo(ImVec2(bx + third * 2.0f, by - third * 2.0f));
   3765     draw_list->PathStroke(col, 0, thickness);
   3766 }
   3767 
   3768 void ImGui::RenderMouseCursor(ImDrawList* draw_list, ImVec2 pos, float scale, ImGuiMouseCursor mouse_cursor, ImU32 col_fill, ImU32 col_border, ImU32 col_shadow)
   3769 {
   3770     if (mouse_cursor == ImGuiMouseCursor_None)
   3771         return;
   3772     IM_ASSERT(mouse_cursor > ImGuiMouseCursor_None && mouse_cursor < ImGuiMouseCursor_COUNT);
   3773 
   3774     ImFontAtlas* font_atlas = draw_list->_Data->Font->ContainerAtlas;
   3775     ImVec2 offset, size, uv[4];
   3776     if (font_atlas->GetMouseCursorTexData(mouse_cursor, &offset, &size, &uv[0], &uv[2]))
   3777     {
   3778         pos -= offset;
   3779         ImTextureID tex_id = font_atlas->TexID;
   3780         draw_list->PushTextureID(tex_id);
   3781         draw_list->AddImage(tex_id, pos + ImVec2(1, 0) * scale, pos + (ImVec2(1, 0) + size) * scale,    uv[2], uv[3], col_shadow);
   3782         draw_list->AddImage(tex_id, pos + ImVec2(2, 0) * scale, pos + (ImVec2(2, 0) + size) * scale,    uv[2], uv[3], col_shadow);
   3783         draw_list->AddImage(tex_id, pos,                        pos + size * scale,                     uv[2], uv[3], col_border);
   3784         draw_list->AddImage(tex_id, pos,                        pos + size * scale,                     uv[0], uv[1], col_fill);
   3785         draw_list->PopTextureID();
   3786     }
   3787 }
   3788 
   3789 // 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.
   3790 void ImGui::RenderArrowPointingAt(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col)
   3791 {
   3792     switch (direction)
   3793     {
   3794     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;
   3795     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;
   3796     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;
   3797     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;
   3798     case ImGuiDir_None: case ImGuiDir_COUNT: break; // Fix warnings
   3799     }
   3800 }
   3801 
   3802 static inline float ImAcos01(float x)
   3803 {
   3804     if (x <= 0.0f) return IM_PI * 0.5f;
   3805     if (x >= 1.0f) return 0.0f;
   3806     return ImAcos(x);
   3807     //return (-0.69813170079773212f * x * x - 0.87266462599716477f) * x + 1.5707963267948966f; // Cheap approximation, may be enough for what we do.
   3808 }
   3809 
   3810 // FIXME: Cleanup and move code to ImDrawList.
   3811 void ImGui::RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, ImU32 col, float x_start_norm, float x_end_norm, float rounding)
   3812 {
   3813     if (x_end_norm == x_start_norm)
   3814         return;
   3815     if (x_start_norm > x_end_norm)
   3816         ImSwap(x_start_norm, x_end_norm);
   3817 
   3818     ImVec2 p0 = ImVec2(ImLerp(rect.Min.x, rect.Max.x, x_start_norm), rect.Min.y);
   3819     ImVec2 p1 = ImVec2(ImLerp(rect.Min.x, rect.Max.x, x_end_norm), rect.Max.y);
   3820     if (rounding == 0.0f)
   3821     {
   3822         draw_list->AddRectFilled(p0, p1, col, 0.0f);
   3823         return;
   3824     }
   3825 
   3826     rounding = ImClamp(ImMin((rect.Max.x - rect.Min.x) * 0.5f, (rect.Max.y - rect.Min.y) * 0.5f) - 1.0f, 0.0f, rounding);
   3827     const float inv_rounding = 1.0f / rounding;
   3828     const float arc0_b = ImAcos01(1.0f - (p0.x - rect.Min.x) * inv_rounding);
   3829     const float arc0_e = ImAcos01(1.0f - (p1.x - rect.Min.x) * inv_rounding);
   3830     const float half_pi = IM_PI * 0.5f; // We will == compare to this because we know this is the exact value ImAcos01 can return.
   3831     const float x0 = ImMax(p0.x, rect.Min.x + rounding);
   3832     if (arc0_b == arc0_e)
   3833     {
   3834         draw_list->PathLineTo(ImVec2(x0, p1.y));
   3835         draw_list->PathLineTo(ImVec2(x0, p0.y));
   3836     }
   3837     else if (arc0_b == 0.0f && arc0_e == half_pi)
   3838     {
   3839         draw_list->PathArcToFast(ImVec2(x0, p1.y - rounding), rounding, 3, 6); // BL
   3840         draw_list->PathArcToFast(ImVec2(x0, p0.y + rounding), rounding, 6, 9); // TR
   3841     }
   3842     else
   3843     {
   3844         draw_list->PathArcTo(ImVec2(x0, p1.y - rounding), rounding, IM_PI - arc0_e, IM_PI - arc0_b, 3); // BL
   3845         draw_list->PathArcTo(ImVec2(x0, p0.y + rounding), rounding, IM_PI + arc0_b, IM_PI + arc0_e, 3); // TR
   3846     }
   3847     if (p1.x > rect.Min.x + rounding)
   3848     {
   3849         const float arc1_b = ImAcos01(1.0f - (rect.Max.x - p1.x) * inv_rounding);
   3850         const float arc1_e = ImAcos01(1.0f - (rect.Max.x - p0.x) * inv_rounding);
   3851         const float x1 = ImMin(p1.x, rect.Max.x - rounding);
   3852         if (arc1_b == arc1_e)
   3853         {
   3854             draw_list->PathLineTo(ImVec2(x1, p0.y));
   3855             draw_list->PathLineTo(ImVec2(x1, p1.y));
   3856         }
   3857         else if (arc1_b == 0.0f && arc1_e == half_pi)
   3858         {
   3859             draw_list->PathArcToFast(ImVec2(x1, p0.y + rounding), rounding, 9, 12); // TR
   3860             draw_list->PathArcToFast(ImVec2(x1, p1.y - rounding), rounding, 0, 3);  // BR
   3861         }
   3862         else
   3863         {
   3864             draw_list->PathArcTo(ImVec2(x1, p0.y + rounding), rounding, -arc1_e, -arc1_b, 3); // TR
   3865             draw_list->PathArcTo(ImVec2(x1, p1.y - rounding), rounding, +arc1_b, +arc1_e, 3); // BR
   3866         }
   3867     }
   3868     draw_list->PathFillConvex(col);
   3869 }
   3870 
   3871 void ImGui::RenderRectFilledWithHole(ImDrawList* draw_list, ImRect outer, ImRect inner, ImU32 col, float rounding)
   3872 {
   3873     const bool fill_L = (inner.Min.x > outer.Min.x);
   3874     const bool fill_R = (inner.Max.x < outer.Max.x);
   3875     const bool fill_U = (inner.Min.y > outer.Min.y);
   3876     const bool fill_D = (inner.Max.y < outer.Max.y);
   3877     if (fill_L) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Min.y), ImVec2(inner.Min.x, inner.Max.y), col, rounding, (fill_U ? 0 : ImDrawFlags_RoundCornersTopLeft)  | (fill_D ? 0 : ImDrawFlags_RoundCornersBottomLeft));
   3878     if (fill_R) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Min.y), ImVec2(outer.Max.x, inner.Max.y), col, rounding, (fill_U ? 0 : ImDrawFlags_RoundCornersTopRight) | (fill_D ? 0 : ImDrawFlags_RoundCornersBottomRight));
   3879     if (fill_U) draw_list->AddRectFilled(ImVec2(inner.Min.x, outer.Min.y), ImVec2(inner.Max.x, inner.Min.y), col, rounding, (fill_L ? 0 : ImDrawFlags_RoundCornersTopLeft)  | (fill_R ? 0 : ImDrawFlags_RoundCornersTopRight));
   3880     if (fill_D) draw_list->AddRectFilled(ImVec2(inner.Min.x, inner.Max.y), ImVec2(inner.Max.x, outer.Max.y), col, rounding, (fill_L ? 0 : ImDrawFlags_RoundCornersBottomLeft)  | (fill_R ? 0 : ImDrawFlags_RoundCornersBottomRight));
   3881     if (fill_L && fill_U) draw_list->AddRectFilled(ImVec2(outer.Min.x, outer.Min.y), ImVec2(inner.Min.x, inner.Min.y), col, rounding, ImDrawFlags_RoundCornersTopLeft);
   3882     if (fill_R && fill_U) draw_list->AddRectFilled(ImVec2(inner.Max.x, outer.Min.y), ImVec2(outer.Max.x, inner.Min.y), col, rounding, ImDrawFlags_RoundCornersTopRight);
   3883     if (fill_L && fill_D) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Max.y), ImVec2(inner.Min.x, outer.Max.y), col, rounding, ImDrawFlags_RoundCornersBottomLeft);
   3884     if (fill_R && fill_D) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Max.y), ImVec2(outer.Max.x, outer.Max.y), col, rounding, ImDrawFlags_RoundCornersBottomRight);
   3885 }
   3886 
   3887 // Helper for ColorPicker4()
   3888 // NB: This is rather brittle and will show artifact when rounding this enabled if rounded corners overlap multiple cells. Caller currently responsible for avoiding that.
   3889 // Spent a non reasonable amount of time trying to getting this right for ColorButton with rounding+anti-aliasing+ImGuiColorEditFlags_HalfAlphaPreview flag + various grid sizes and offsets, and eventually gave up... probably more reasonable to disable rounding altogether.
   3890 // FIXME: uses ImGui::GetColorU32
   3891 void ImGui::RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p_min, ImVec2 p_max, ImU32 col, float grid_step, ImVec2 grid_off, float rounding, ImDrawFlags flags)
   3892 {
   3893     if ((flags & ImDrawFlags_RoundCornersMask_) == 0)
   3894         flags = ImDrawFlags_RoundCornersDefault_;
   3895     if (((col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT) < 0xFF)
   3896     {
   3897         ImU32 col_bg1 = GetColorU32(ImAlphaBlendColors(IM_COL32(204, 204, 204, 255), col));
   3898         ImU32 col_bg2 = GetColorU32(ImAlphaBlendColors(IM_COL32(128, 128, 128, 255), col));
   3899         draw_list->AddRectFilled(p_min, p_max, col_bg1, rounding, flags);
   3900 
   3901         int yi = 0;
   3902         for (float y = p_min.y + grid_off.y; y < p_max.y; y += grid_step, yi++)
   3903         {
   3904             float y1 = ImClamp(y, p_min.y, p_max.y), y2 = ImMin(y + grid_step, p_max.y);
   3905             if (y2 <= y1)
   3906                 continue;
   3907             for (float x = p_min.x + grid_off.x + (yi & 1) * grid_step; x < p_max.x; x += grid_step * 2.0f)
   3908             {
   3909                 float x1 = ImClamp(x, p_min.x, p_max.x), x2 = ImMin(x + grid_step, p_max.x);
   3910                 if (x2 <= x1)
   3911                     continue;
   3912                 ImDrawFlags cell_flags = ImDrawFlags_RoundCornersNone;
   3913                 if (y1 <= p_min.y) { if (x1 <= p_min.x) cell_flags |= ImDrawFlags_RoundCornersTopLeft; if (x2 >= p_max.x) cell_flags |= ImDrawFlags_RoundCornersTopRight; }
   3914                 if (y2 >= p_max.y) { if (x1 <= p_min.x) cell_flags |= ImDrawFlags_RoundCornersBottomLeft; if (x2 >= p_max.x) cell_flags |= ImDrawFlags_RoundCornersBottomRight; }
   3915 
   3916                 // Combine flags
   3917                 cell_flags = (flags == ImDrawFlags_RoundCornersNone || cell_flags == ImDrawFlags_RoundCornersNone) ? ImDrawFlags_RoundCornersNone : (cell_flags & flags);
   3918                 draw_list->AddRectFilled(ImVec2(x1, y1), ImVec2(x2, y2), col_bg2, rounding, cell_flags);
   3919             }
   3920         }
   3921     }
   3922     else
   3923     {
   3924         draw_list->AddRectFilled(p_min, p_max, col, rounding, flags);
   3925     }
   3926 }
   3927 
   3928 //-----------------------------------------------------------------------------
   3929 // [SECTION] Decompression code
   3930 //-----------------------------------------------------------------------------
   3931 // Compressed with stb_compress() then converted to a C array and encoded as base85.
   3932 // Use the program in misc/fonts/binary_to_compressed_c.cpp to create the array from a TTF file.
   3933 // The purpose of encoding as base85 instead of "0x00,0x01,..." style is only save on _source code_ size.
   3934 // Decompression from stb.h (public domain) by Sean Barrett https://github.com/nothings/stb/blob/master/stb.h
   3935 //-----------------------------------------------------------------------------
   3936 
   3937 static unsigned int stb_decompress_length(const unsigned char *input)
   3938 {
   3939     return (input[8] << 24) + (input[9] << 16) + (input[10] << 8) + input[11];
   3940 }
   3941 
   3942 static unsigned char *stb__barrier_out_e, *stb__barrier_out_b;
   3943 static const unsigned char *stb__barrier_in_b;
   3944 static unsigned char *stb__dout;
   3945 static void stb__match(const unsigned char *data, unsigned int length)
   3946 {
   3947     // INVERSE of memmove... write each byte before copying the next...
   3948     IM_ASSERT(stb__dout + length <= stb__barrier_out_e);
   3949     if (stb__dout + length > stb__barrier_out_e) { stb__dout += length; return; }
   3950     if (data < stb__barrier_out_b) { stb__dout = stb__barrier_out_e+1; return; }
   3951     while (length--) *stb__dout++ = *data++;
   3952 }
   3953 
   3954 static void stb__lit(const unsigned char *data, unsigned int length)
   3955 {
   3956     IM_ASSERT(stb__dout + length <= stb__barrier_out_e);
   3957     if (stb__dout + length > stb__barrier_out_e) { stb__dout += length; return; }
   3958     if (data < stb__barrier_in_b) { stb__dout = stb__barrier_out_e+1; return; }
   3959     memcpy(stb__dout, data, length);
   3960     stb__dout += length;
   3961 }
   3962 
   3963 #define stb__in2(x)   ((i[x] << 8) + i[(x)+1])
   3964 #define stb__in3(x)   ((i[x] << 16) + stb__in2((x)+1))
   3965 #define stb__in4(x)   ((i[x] << 24) + stb__in3((x)+1))
   3966 
   3967 static const unsigned char *stb_decompress_token(const unsigned char *i)
   3968 {
   3969     if (*i >= 0x20) { // use fewer if's for cases that expand small
   3970         if (*i >= 0x80)       stb__match(stb__dout-i[1]-1, i[0] - 0x80 + 1), i += 2;
   3971         else if (*i >= 0x40)  stb__match(stb__dout-(stb__in2(0) - 0x4000 + 1), i[2]+1), i += 3;
   3972         else /* *i >= 0x20 */ stb__lit(i+1, i[0] - 0x20 + 1), i += 1 + (i[0] - 0x20 + 1);
   3973     } else { // more ifs for cases that expand large, since overhead is amortized
   3974         if (*i >= 0x18)       stb__match(stb__dout-(stb__in3(0) - 0x180000 + 1), i[3]+1), i += 4;
   3975         else if (*i >= 0x10)  stb__match(stb__dout-(stb__in3(0) - 0x100000 + 1), stb__in2(3)+1), i += 5;
   3976         else if (*i >= 0x08)  stb__lit(i+2, stb__in2(0) - 0x0800 + 1), i += 2 + (stb__in2(0) - 0x0800 + 1);
   3977         else if (*i == 0x07)  stb__lit(i+3, stb__in2(1) + 1), i += 3 + (stb__in2(1) + 1);
   3978         else if (*i == 0x06)  stb__match(stb__dout-(stb__in3(1)+1), i[4]+1), i += 5;
   3979         else if (*i == 0x04)  stb__match(stb__dout-(stb__in3(1)+1), stb__in2(4)+1), i += 6;
   3980     }
   3981     return i;
   3982 }
   3983 
   3984 static unsigned int stb_adler32(unsigned int adler32, unsigned char *buffer, unsigned int buflen)
   3985 {
   3986     const unsigned long ADLER_MOD = 65521;
   3987     unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16;
   3988     unsigned long blocklen = buflen % 5552;
   3989 
   3990     unsigned long i;
   3991     while (buflen) {
   3992         for (i=0; i + 7 < blocklen; i += 8) {
   3993             s1 += buffer[0], s2 += s1;
   3994             s1 += buffer[1], s2 += s1;
   3995             s1 += buffer[2], s2 += s1;
   3996             s1 += buffer[3], s2 += s1;
   3997             s1 += buffer[4], s2 += s1;
   3998             s1 += buffer[5], s2 += s1;
   3999             s1 += buffer[6], s2 += s1;
   4000             s1 += buffer[7], s2 += s1;
   4001 
   4002             buffer += 8;
   4003         }
   4004 
   4005         for (; i < blocklen; ++i)
   4006             s1 += *buffer++, s2 += s1;
   4007 
   4008         s1 %= ADLER_MOD, s2 %= ADLER_MOD;
   4009         buflen -= blocklen;
   4010         blocklen = 5552;
   4011     }
   4012     return (unsigned int)(s2 << 16) + (unsigned int)s1;
   4013 }
   4014 
   4015 static unsigned int stb_decompress(unsigned char *output, const unsigned char *i, unsigned int /*length*/)
   4016 {
   4017     if (stb__in4(0) != 0x57bC0000) return 0;
   4018     if (stb__in4(4) != 0)          return 0; // error! stream is > 4GB
   4019     const unsigned int olen = stb_decompress_length(i);
   4020     stb__barrier_in_b = i;
   4021     stb__barrier_out_e = output + olen;
   4022     stb__barrier_out_b = output;
   4023     i += 16;
   4024 
   4025     stb__dout = output;
   4026     for (;;) {
   4027         const unsigned char *old_i = i;
   4028         i = stb_decompress_token(i);
   4029         if (i == old_i) {
   4030             if (*i == 0x05 && i[1] == 0xfa) {
   4031                 IM_ASSERT(stb__dout == output + olen);
   4032                 if (stb__dout != output + olen) return 0;
   4033                 if (stb_adler32(1, output, olen) != (unsigned int) stb__in4(2))
   4034                     return 0;
   4035                 return olen;
   4036             } else {
   4037                 IM_ASSERT(0); /* NOTREACHED */
   4038                 return 0;
   4039             }
   4040         }
   4041         IM_ASSERT(stb__dout <= output + olen);
   4042         if (stb__dout > output + olen)
   4043             return 0;
   4044     }
   4045 }
   4046 
   4047 //-----------------------------------------------------------------------------
   4048 // [SECTION] Default font data (ProggyClean.ttf)
   4049 //-----------------------------------------------------------------------------
   4050 // ProggyClean.ttf
   4051 // Copyright (c) 2004, 2005 Tristan Grimmer
   4052 // MIT license (see License.txt in http://www.upperbounds.net/download/ProggyClean.ttf.zip)
   4053 // Download and more information at http://upperbounds.net
   4054 //-----------------------------------------------------------------------------
   4055 // File: 'ProggyClean.ttf' (41208 bytes)
   4056 // Exported using misc/fonts/binary_to_compressed_c.cpp (with compression + base85 string encoding).
   4057 // The purpose of encoding as base85 instead of "0x00,0x01,..." style is only save on _source code_ size.
   4058 //-----------------------------------------------------------------------------
   4059 static const char proggy_clean_ttf_compressed_data_base85[11980 + 1] =
   4060     "7])#######hV0qs'/###[),##/l:$#Q6>##5[n42>c-TH`->>#/e>11NNV=Bv(*:.F?uu#(gRU.o0XGH`$vhLG1hxt9?W`#,5LsCp#-i>.r$<$6pD>Lb';9Crc6tgXmKVeU2cD4Eo3R/"
   4061     "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#"
   4062     "`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"
   4063     "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"
   4064     "kfimM2J,W-jXS:)r0wK#@Fge$U>`w'N7G#$#fB#$E^$#:9:hk+eOe--6x)F7*E%?76%^GMHePW-Z5l'&GiF#$956:rS?dA#fiK:)Yr+`&#0j@'DbG&#^$PG.Ll+DNa<XCMKEV*N)LN/N"
   4065     "*b=%Q6pia-Xg8I$<MR&,VdJe$<(7G;Ckl'&hF;;$<_=X(b.RS%%)###MPBuuE1V:v&cX&#2m#(&cV]`k9OhLMbn%s$G2,B$BfD3X*sp5#l,$R#]x_X1xKX%b5U*[r5iMfUo9U`N99hG)"
   4066     "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"
   4067     "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."
   4068     "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"
   4069     "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(,)"
   4070     "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#"
   4071     "'/###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"
   4072     "_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"
   4073     "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/"
   4074     "/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"
   4075     "%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&#"
   4076     "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)("
   4077     "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"
   4078     "o;#2:;%d&#x9v68C5g?ntX0X)pT`;%pB3q7mgGN)3%(P8nTd5L7GeA-GL@+%J3u2:(Yf>et`e;)f#Km8&+DC$I46>#Kr]]u-[=99tts1.qb#q72g1WJO81q+eN'03'eM>&1XxY-caEnO"
   4079     "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^-"
   4080     "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-"
   4081     "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"
   4082     "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%"
   4083     "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]"
   4084     "%(?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"
   4085     "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:"
   4086     "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("
   4087     "$/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<"
   4088     "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'?"
   4089     "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/;"
   4090     ")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"
   4091     "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("
   4092     "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"
   4093     "bIu)'Z,*[>br5fX^:FPAWr-m2KgL<LUN098kTF&#lvo58=/vjDo;.;)Ka*hLR#/k=rKbxuV`>Q_nN6'8uTG&#1T5g)uLv:873UpTLgH+#FgpH'_o1780Ph8KmxQJ8#H72L4@768@Tm&Q"
   4094     "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<-"
   4095     "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"
   4096     "sZ88+dKQ)W6>J%CL<KE>`.d*(B`-n8D9oK<Up]c$X$(,)M8Zt7/[rdkqTgl-0cuGMv'?>-XV1q['-5k'cAZ69e;D_?$ZPP&s^+7])$*$#@QYi9,5P&#9r+$%CE=68>K8r0=dSC%%(@p7"
   4097     ".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@@"
   4098     "$&)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*"
   4099     "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"
   4100     "@-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&#"
   4101     "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#"
   4102     "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"
   4103     "d=j.LQf./Ll33+(;q3L-w=8dX$#WF&uIJ@-bfI>%:_i2B5CsR8&9Z&#=mPEnm0f`<&c)QL5uJ#%u%lJj+D-r;BoF&#4DoS97h5g)E#o:&S4weDF,9^Hoe`h*L+_a*NrLW-1pG_&2UdB8"
   4104     "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&#"
   4105     "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"
   4106     ":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+"
   4107     "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*"
   4108     "$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"
   4109     ":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"
   4110     "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"
   4111     "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"
   4112     "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"
   4113     ":^#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@&]>"
   4114     "_>@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%"
   4115     "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;"
   4116     "^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:"
   4117     "+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%"
   4118     "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-"
   4119     "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*"
   4120     "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"
   4121     "8kD2)2fU/M#$e.)T4,_=8hLim[&);?UkK'-x?'(:siIfL<$pFM`i<?%W(mGDHM%>iWP,##P`%/L<eXi:@Z9C.7o=@(pXdAO/NLQ8lPl+HPOQa8wD8=^GlPa8TKI1CjhsCTSLJM'/Wl>-"
   4122     "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`"
   4123     "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]%/"
   4124     "+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"
   4125     "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"
   4126     "?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"
   4127     "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"
   4128     ">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'>"
   4129     "[%$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"
   4130     "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#"
   4131     "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$"
   4132     "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,)"
   4133     "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"
   4134     "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"
   4135     "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"
   4136     "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(#"
   4137     ";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&>"
   4138     "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#"
   4139     "d<F&#*;G##.GY##2Sl##6`($#:l:$#>xL$#B.`$#F:r$#JF.%#NR@%#R_R%#Vke%#Zww%#_-4&#3^Rh%Sflr-k'MS.o?.5/sWel/wpEM0%3'/1)K^f1-d>G21&v(35>V`39V7A4=onx4"
   4140     "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#"
   4141     "/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-#"
   4142     "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#"
   4143     "TmD<#%JSMFove:CTBEXI:<eh2g)B,3h2^G3i;#d3jD>)4kMYD4lVu`4m`:&5niUA5@(A5BA1]PBB:xlBCC=2CDLXMCEUtiCf&0g2'tN?PGT4CPGT4CPGT4CPGT4CPGT4CPGT4CPGT4CP"
   4144     "GT4CPGT4CPGT4CPGT4CPGT4CPGT4CP-qekC`.9kEg^+F$kwViFJTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5o,^<-28ZI'O?;xp"
   4145     "O?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xp;7q-#lLYI:xvD=#";
   4146 
   4147 static const char* GetDefaultCompressedFontDataTTFBase85()
   4148 {
   4149     return proggy_clean_ttf_compressed_data_base85;
   4150 }
   4151 
   4152 #endif // #ifndef IMGUI_DISABLE