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