git repos / blockattack-game

blame: source/code/Libs/imgui/imgui_draw.cpp

normal view · raw

1193b4be Poul Sander 2025-02-03 21:28 1
// dear imgui, v1.91.4
1193b4be Poul Sander 2025-02-03 21:28 2
// (drawing and font code)
1193b4be Poul Sander 2025-02-03 21:28 3
1193b4be Poul Sander 2025-02-03 21:28 4
/*
1193b4be Poul Sander 2025-02-03 21:28 5
1193b4be Poul Sander 2025-02-03 21:28 6
Index of this file:
1193b4be Poul Sander 2025-02-03 21:28 7
1193b4be Poul Sander 2025-02-03 21:28 8
// [SECTION] STB libraries implementation
1193b4be Poul Sander 2025-02-03 21:28 9
// [SECTION] Style functions
1193b4be Poul Sander 2025-02-03 21:28 10
// [SECTION] ImDrawList
1193b4be Poul Sander 2025-02-03 21:28 11
// [SECTION] ImTriangulator, ImDrawList concave polygon fill
1193b4be Poul Sander 2025-02-03 21:28 12
// [SECTION] ImDrawListSplitter
1193b4be Poul Sander 2025-02-03 21:28 13
// [SECTION] ImDrawData
1193b4be Poul Sander 2025-02-03 21:28 14
// [SECTION] Helpers ShadeVertsXXX functions
1193b4be Poul Sander 2025-02-03 21:28 15
// [SECTION] ImFontConfig
1193b4be Poul Sander 2025-02-03 21:28 16
// [SECTION] ImFontAtlas
1193b4be Poul Sander 2025-02-03 21:28 17
// [SECTION] ImFontAtlas glyph ranges helpers
1193b4be Poul Sander 2025-02-03 21:28 18
// [SECTION] ImFontGlyphRangesBuilder
1193b4be Poul Sander 2025-02-03 21:28 19
// [SECTION] ImFont
1193b4be Poul Sander 2025-02-03 21:28 20
// [SECTION] ImGui Internal Render Helpers
1193b4be Poul Sander 2025-02-03 21:28 21
// [SECTION] Decompression code
1193b4be Poul Sander 2025-02-03 21:28 22
// [SECTION] Default font data (ProggyClean.ttf)
1193b4be Poul Sander 2025-02-03 21:28 23
1193b4be Poul Sander 2025-02-03 21:28 24
*/
1193b4be Poul Sander 2025-02-03 21:28 25
1193b4be Poul Sander 2025-02-03 21:28 26
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
1193b4be Poul Sander 2025-02-03 21:28 27
#define _CRT_SECURE_NO_WARNINGS
1193b4be Poul Sander 2025-02-03 21:28 28
#endif
1193b4be Poul Sander 2025-02-03 21:28 29
1193b4be Poul Sander 2025-02-03 21:28 30
#ifndef IMGUI_DEFINE_MATH_OPERATORS
1193b4be Poul Sander 2025-02-03 21:28 31
#define IMGUI_DEFINE_MATH_OPERATORS
1193b4be Poul Sander 2025-02-03 21:28 32
#endif
1193b4be Poul Sander 2025-02-03 21:28 33
1193b4be Poul Sander 2025-02-03 21:28 34
#include "imgui.h"
1193b4be Poul Sander 2025-02-03 21:28 35
#ifndef IMGUI_DISABLE
1193b4be Poul Sander 2025-02-03 21:28 36
#include "imgui_internal.h"
1193b4be Poul Sander 2025-02-03 21:28 37
#ifdef IMGUI_ENABLE_FREETYPE
1193b4be Poul Sander 2025-02-03 21:28 38
#include "misc/freetype/imgui_freetype.h"
1193b4be Poul Sander 2025-02-03 21:28 39
#endif
1193b4be Poul Sander 2025-02-03 21:28 40
1193b4be Poul Sander 2025-02-03 21:28 41
#include <stdio.h>      // vsnprintf, sscanf, printf
1193b4be Poul Sander 2025-02-03 21:28 42
1193b4be Poul Sander 2025-02-03 21:28 43
// Visual Studio warnings
1193b4be Poul Sander 2025-02-03 21:28 44
#ifdef _MSC_VER
1193b4be Poul Sander 2025-02-03 21:28 45
#pragma warning (disable: 4127)     // condition expression is constant
1193b4be Poul Sander 2025-02-03 21:28 46
#pragma warning (disable: 4505)     // unreferenced local function has been removed (stb stuff)
1193b4be Poul Sander 2025-02-03 21:28 47
#pragma warning (disable: 4996)     // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
1193b4be Poul Sander 2025-02-03 21:28 48
#pragma warning (disable: 26451)    // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2).
1193b4be Poul Sander 2025-02-03 21:28 49
#pragma warning (disable: 26812)    // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3). [MSVC Static Analyzer)
1193b4be Poul Sander 2025-02-03 21:28 50
#endif
1193b4be Poul Sander 2025-02-03 21:28 51
1193b4be Poul Sander 2025-02-03 21:28 52
// Clang/GCC warnings with -Weverything
1193b4be Poul Sander 2025-02-03 21:28 53
#if defined(__clang__)
1193b4be Poul Sander 2025-02-03 21:28 54
#if __has_warning("-Wunknown-warning-option")
1193b4be Poul Sander 2025-02-03 21:28 55
#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!
1193b4be Poul Sander 2025-02-03 21:28 56
#endif
1193b4be Poul Sander 2025-02-03 21:28 57
#pragma clang diagnostic ignored "-Wunknown-pragmas"                // warning: unknown warning group 'xxx'
1193b4be Poul Sander 2025-02-03 21:28 58
#pragma clang diagnostic ignored "-Wold-style-cast"                 // warning: use of old-style cast                            // yes, they are more terse.
1193b4be Poul Sander 2025-02-03 21:28 59
#pragma clang diagnostic ignored "-Wfloat-equal"                    // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants ok.
1193b4be Poul Sander 2025-02-03 21:28 60
#pragma clang diagnostic ignored "-Wglobal-constructors"            // warning: declaration requires a global destructor         // similar to above, not sure what the exact difference is.
1193b4be Poul Sander 2025-02-03 21:28 61
#pragma clang diagnostic ignored "-Wsign-conversion"                // warning: implicit conversion changes signedness
1193b4be Poul Sander 2025-02-03 21:28 62
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"  // warning: zero as null pointer constant                    // some standard header variations use #define NULL 0
1193b4be Poul Sander 2025-02-03 21:28 63
#pragma clang diagnostic ignored "-Wcomma"                          // warning: possible misuse of comma operator here
1193b4be Poul Sander 2025-02-03 21:28 64
#pragma clang diagnostic ignored "-Wreserved-id-macro"              // warning: macro name is a reserved identifier
1193b4be Poul Sander 2025-02-03 21:28 65
#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.
1193b4be Poul Sander 2025-02-03 21:28 66
#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion"  // warning: implicit conversion from 'xxx' to 'float' may lose precision
1193b4be Poul Sander 2025-02-03 21:28 67
#pragma clang diagnostic ignored "-Wreserved-identifier"            // warning: identifier '_Xxx' is reserved because it starts with '_' followed by a capital letter
1193b4be Poul Sander 2025-02-03 21:28 68
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage"            // warning: 'xxx' is an unsafe pointer used for buffer access
1193b4be Poul Sander 2025-02-03 21:28 69
#elif defined(__GNUC__)
1193b4be Poul Sander 2025-02-03 21:28 70
#pragma GCC diagnostic ignored "-Wpragmas"                  // warning: unknown option after '#pragma GCC diagnostic' kind
1193b4be Poul Sander 2025-02-03 21:28 71
#pragma GCC diagnostic ignored "-Wunused-function"          // warning: 'xxxx' defined but not used
1193b4be Poul Sander 2025-02-03 21:28 72
#pragma GCC diagnostic ignored "-Wdouble-promotion"         // warning: implicit conversion from 'float' to 'double' when passing argument to function
1193b4be Poul Sander 2025-02-03 21:28 73
#pragma GCC diagnostic ignored "-Wconversion"               // warning: conversion to 'xxxx' from 'xxxx' may alter its value
1193b4be Poul Sander 2025-02-03 21:28 74
#pragma GCC diagnostic ignored "-Wstack-protector"          // warning: stack protector not protecting local variables: variable length buffer
1193b4be Poul Sander 2025-02-03 21:28 75
#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
1193b4be Poul Sander 2025-02-03 21:28 76
#endif
1193b4be Poul Sander 2025-02-03 21:28 77
1193b4be Poul Sander 2025-02-03 21:28 78
//-------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 79
// [SECTION] STB libraries implementation (for stb_truetype and stb_rect_pack)
1193b4be Poul Sander 2025-02-03 21:28 80
//-------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 81
1193b4be Poul Sander 2025-02-03 21:28 82
// Compile time options:
1193b4be Poul Sander 2025-02-03 21:28 83
//#define IMGUI_STB_NAMESPACE           ImStb
1193b4be Poul Sander 2025-02-03 21:28 84
//#define IMGUI_STB_TRUETYPE_FILENAME   "my_folder/stb_truetype.h"
1193b4be Poul Sander 2025-02-03 21:28 85
//#define IMGUI_STB_RECT_PACK_FILENAME  "my_folder/stb_rect_pack.h"
1193b4be Poul Sander 2025-02-03 21:28 86
//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
1193b4be Poul Sander 2025-02-03 21:28 87
//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
1193b4be Poul Sander 2025-02-03 21:28 88
1193b4be Poul Sander 2025-02-03 21:28 89
#ifdef IMGUI_STB_NAMESPACE
1193b4be Poul Sander 2025-02-03 21:28 90
namespace IMGUI_STB_NAMESPACE
1193b4be Poul Sander 2025-02-03 21:28 91
{
1193b4be Poul Sander 2025-02-03 21:28 92
#endif
1193b4be Poul Sander 2025-02-03 21:28 93
1193b4be Poul Sander 2025-02-03 21:28 94
#ifdef _MSC_VER
1193b4be Poul Sander 2025-02-03 21:28 95
#pragma warning (push)
1193b4be Poul Sander 2025-02-03 21:28 96
#pragma warning (disable: 4456)                             // declaration of 'xx' hides previous local declaration
1193b4be Poul Sander 2025-02-03 21:28 97
#pragma warning (disable: 6011)                             // (stb_rectpack) Dereferencing NULL pointer 'cur->next'.
1193b4be Poul Sander 2025-02-03 21:28 98
#pragma warning (disable: 6385)                             // (stb_truetype) Reading invalid data from 'buffer':  the readable size is '_Old_3`kernel_width' bytes, but '3' bytes may be read.
1193b4be Poul Sander 2025-02-03 21:28 99
#pragma warning (disable: 28182)                            // (stb_rectpack) Dereferencing NULL pointer. 'cur' contains the same NULL value as 'cur->next' did.
1193b4be Poul Sander 2025-02-03 21:28 100
#endif
1193b4be Poul Sander 2025-02-03 21:28 101
1193b4be Poul Sander 2025-02-03 21:28 102
#if defined(__clang__)
1193b4be Poul Sander 2025-02-03 21:28 103
#pragma clang diagnostic push
1193b4be Poul Sander 2025-02-03 21:28 104
#pragma clang diagnostic ignored "-Wunused-function"
1193b4be Poul Sander 2025-02-03 21:28 105
#pragma clang diagnostic ignored "-Wmissing-prototypes"
1193b4be Poul Sander 2025-02-03 21:28 106
#pragma clang diagnostic ignored "-Wimplicit-fallthrough"
1193b4be Poul Sander 2025-02-03 21:28 107
#pragma clang diagnostic ignored "-Wcast-qual"              // warning: cast from 'const xxxx *' to 'xxx *' drops const qualifier
1193b4be Poul Sander 2025-02-03 21:28 108
#endif
1193b4be Poul Sander 2025-02-03 21:28 109
1193b4be Poul Sander 2025-02-03 21:28 110
#if defined(__GNUC__)
1193b4be Poul Sander 2025-02-03 21:28 111
#pragma GCC diagnostic push
1193b4be Poul Sander 2025-02-03 21:28 112
#pragma GCC diagnostic ignored "-Wtype-limits"              // warning: comparison is always true due to limited range of data type [-Wtype-limits]
1193b4be Poul Sander 2025-02-03 21:28 113
#pragma GCC diagnostic ignored "-Wcast-qual"                // warning: cast from type 'const xxxx *' to type 'xxxx *' casts away qualifiers
1193b4be Poul Sander 2025-02-03 21:28 114
#endif
1193b4be Poul Sander 2025-02-03 21:28 115
1193b4be Poul Sander 2025-02-03 21:28 116
#ifndef STB_RECT_PACK_IMPLEMENTATION                        // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds)
1193b4be Poul Sander 2025-02-03 21:28 117
#ifndef IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION          // in case the user already have an implementation in another compilation unit
1193b4be Poul Sander 2025-02-03 21:28 118
#define STBRP_STATIC
1193b4be Poul Sander 2025-02-03 21:28 119
#define STBRP_ASSERT(x)     do { IM_ASSERT(x); } while (0)
1193b4be Poul Sander 2025-02-03 21:28 120
#define STBRP_SORT          ImQsort
1193b4be Poul Sander 2025-02-03 21:28 121
#define STB_RECT_PACK_IMPLEMENTATION
1193b4be Poul Sander 2025-02-03 21:28 122
#endif
1193b4be Poul Sander 2025-02-03 21:28 123
#ifdef IMGUI_STB_RECT_PACK_FILENAME
1193b4be Poul Sander 2025-02-03 21:28 124
#include IMGUI_STB_RECT_PACK_FILENAME
1193b4be Poul Sander 2025-02-03 21:28 125
#else
1193b4be Poul Sander 2025-02-03 21:28 126
#include "imstb_rectpack.h"
1193b4be Poul Sander 2025-02-03 21:28 127
#endif
1193b4be Poul Sander 2025-02-03 21:28 128
#endif
1193b4be Poul Sander 2025-02-03 21:28 129
1193b4be Poul Sander 2025-02-03 21:28 130
#ifdef  IMGUI_ENABLE_STB_TRUETYPE
1193b4be Poul Sander 2025-02-03 21:28 131
#ifndef STB_TRUETYPE_IMPLEMENTATION                         // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds)
1193b4be Poul Sander 2025-02-03 21:28 132
#ifndef IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION           // in case the user already have an implementation in another compilation unit
1193b4be Poul Sander 2025-02-03 21:28 133
#define STBTT_malloc(x,u)   ((void)(u), IM_ALLOC(x))
1193b4be Poul Sander 2025-02-03 21:28 134
#define STBTT_free(x,u)     ((void)(u), IM_FREE(x))
1193b4be Poul Sander 2025-02-03 21:28 135
#define STBTT_assert(x)     do { IM_ASSERT(x); } while(0)
1193b4be Poul Sander 2025-02-03 21:28 136
#define STBTT_fmod(x,y)     ImFmod(x,y)
1193b4be Poul Sander 2025-02-03 21:28 137
#define STBTT_sqrt(x)       ImSqrt(x)
1193b4be Poul Sander 2025-02-03 21:28 138
#define STBTT_pow(x,y)      ImPow(x,y)
1193b4be Poul Sander 2025-02-03 21:28 139
#define STBTT_fabs(x)       ImFabs(x)
1193b4be Poul Sander 2025-02-03 21:28 140
#define STBTT_ifloor(x)     ((int)ImFloor(x))
1193b4be Poul Sander 2025-02-03 21:28 141
#define STBTT_iceil(x)      ((int)ImCeil(x))
1193b4be Poul Sander 2025-02-03 21:28 142
#define STBTT_STATIC
1193b4be Poul Sander 2025-02-03 21:28 143
#define STB_TRUETYPE_IMPLEMENTATION
1193b4be Poul Sander 2025-02-03 21:28 144
#else
1193b4be Poul Sander 2025-02-03 21:28 145
#define STBTT_DEF extern
1193b4be Poul Sander 2025-02-03 21:28 146
#endif
1193b4be Poul Sander 2025-02-03 21:28 147
#ifdef IMGUI_STB_TRUETYPE_FILENAME
1193b4be Poul Sander 2025-02-03 21:28 148
#include IMGUI_STB_TRUETYPE_FILENAME
1193b4be Poul Sander 2025-02-03 21:28 149
#else
1193b4be Poul Sander 2025-02-03 21:28 150
#include "imstb_truetype.h"
1193b4be Poul Sander 2025-02-03 21:28 151
#endif
1193b4be Poul Sander 2025-02-03 21:28 152
#endif
1193b4be Poul Sander 2025-02-03 21:28 153
#endif // IMGUI_ENABLE_STB_TRUETYPE
1193b4be Poul Sander 2025-02-03 21:28 154
1193b4be Poul Sander 2025-02-03 21:28 155
#if defined(__GNUC__)
1193b4be Poul Sander 2025-02-03 21:28 156
#pragma GCC diagnostic pop
1193b4be Poul Sander 2025-02-03 21:28 157
#endif
1193b4be Poul Sander 2025-02-03 21:28 158
1193b4be Poul Sander 2025-02-03 21:28 159
#if defined(__clang__)
1193b4be Poul Sander 2025-02-03 21:28 160
#pragma clang diagnostic pop
1193b4be Poul Sander 2025-02-03 21:28 161
#endif
1193b4be Poul Sander 2025-02-03 21:28 162
1193b4be Poul Sander 2025-02-03 21:28 163
#if defined(_MSC_VER)
1193b4be Poul Sander 2025-02-03 21:28 164
#pragma warning (pop)
1193b4be Poul Sander 2025-02-03 21:28 165
#endif
1193b4be Poul Sander 2025-02-03 21:28 166
1193b4be Poul Sander 2025-02-03 21:28 167
#ifdef IMGUI_STB_NAMESPACE
1193b4be Poul Sander 2025-02-03 21:28 168
} // namespace ImStb
1193b4be Poul Sander 2025-02-03 21:28 169
using namespace IMGUI_STB_NAMESPACE;
1193b4be Poul Sander 2025-02-03 21:28 170
#endif
1193b4be Poul Sander 2025-02-03 21:28 171
1193b4be Poul Sander 2025-02-03 21:28 172
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 173
// [SECTION] Style functions
1193b4be Poul Sander 2025-02-03 21:28 174
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 175
1193b4be Poul Sander 2025-02-03 21:28 176
void ImGui::StyleColorsDark(ImGuiStyle* dst)
1193b4be Poul Sander 2025-02-03 21:28 177
{
1193b4be Poul Sander 2025-02-03 21:28 178
    ImGuiStyle* style = dst ? dst : &ImGui::GetStyle();
1193b4be Poul Sander 2025-02-03 21:28 179
    ImVec4* colors = style->Colors;
1193b4be Poul Sander 2025-02-03 21:28 180
1193b4be Poul Sander 2025-02-03 21:28 181
    colors[ImGuiCol_Text]                   = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 182
    colors[ImGuiCol_TextDisabled]           = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 183
    colors[ImGuiCol_WindowBg]               = ImVec4(0.06f, 0.06f, 0.06f, 0.94f);
1193b4be Poul Sander 2025-02-03 21:28 184
    colors[ImGuiCol_ChildBg]                = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
1193b4be Poul Sander 2025-02-03 21:28 185
    colors[ImGuiCol_PopupBg]                = ImVec4(0.08f, 0.08f, 0.08f, 0.94f);
1193b4be Poul Sander 2025-02-03 21:28 186
    colors[ImGuiCol_Border]                 = ImVec4(0.43f, 0.43f, 0.50f, 0.50f);
1193b4be Poul Sander 2025-02-03 21:28 187
    colors[ImGuiCol_BorderShadow]           = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
1193b4be Poul Sander 2025-02-03 21:28 188
    colors[ImGuiCol_FrameBg]                = ImVec4(0.16f, 0.29f, 0.48f, 0.54f);
1193b4be Poul Sander 2025-02-03 21:28 189
    colors[ImGuiCol_FrameBgHovered]         = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);
1193b4be Poul Sander 2025-02-03 21:28 190
    colors[ImGuiCol_FrameBgActive]          = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
1193b4be Poul Sander 2025-02-03 21:28 191
    colors[ImGuiCol_TitleBg]                = ImVec4(0.04f, 0.04f, 0.04f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 192
    colors[ImGuiCol_TitleBgActive]          = ImVec4(0.16f, 0.29f, 0.48f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 193
    colors[ImGuiCol_TitleBgCollapsed]       = ImVec4(0.00f, 0.00f, 0.00f, 0.51f);
1193b4be Poul Sander 2025-02-03 21:28 194
    colors[ImGuiCol_MenuBarBg]              = ImVec4(0.14f, 0.14f, 0.14f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 195
    colors[ImGuiCol_ScrollbarBg]            = ImVec4(0.02f, 0.02f, 0.02f, 0.53f);
1193b4be Poul Sander 2025-02-03 21:28 196
    colors[ImGuiCol_ScrollbarGrab]          = ImVec4(0.31f, 0.31f, 0.31f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 197
    colors[ImGuiCol_ScrollbarGrabHovered]   = ImVec4(0.41f, 0.41f, 0.41f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 198
    colors[ImGuiCol_ScrollbarGrabActive]    = ImVec4(0.51f, 0.51f, 0.51f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 199
    colors[ImGuiCol_CheckMark]              = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 200
    colors[ImGuiCol_SliderGrab]             = ImVec4(0.24f, 0.52f, 0.88f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 201
    colors[ImGuiCol_SliderGrabActive]       = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 202
    colors[ImGuiCol_Button]                 = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);
1193b4be Poul Sander 2025-02-03 21:28 203
    colors[ImGuiCol_ButtonHovered]          = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 204
    colors[ImGuiCol_ButtonActive]           = ImVec4(0.06f, 0.53f, 0.98f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 205
    colors[ImGuiCol_Header]                 = ImVec4(0.26f, 0.59f, 0.98f, 0.31f);
1193b4be Poul Sander 2025-02-03 21:28 206
    colors[ImGuiCol_HeaderHovered]          = ImVec4(0.26f, 0.59f, 0.98f, 0.80f);
1193b4be Poul Sander 2025-02-03 21:28 207
    colors[ImGuiCol_HeaderActive]           = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 208
    colors[ImGuiCol_Separator]              = colors[ImGuiCol_Border];
1193b4be Poul Sander 2025-02-03 21:28 209
    colors[ImGuiCol_SeparatorHovered]       = ImVec4(0.10f, 0.40f, 0.75f, 0.78f);
1193b4be Poul Sander 2025-02-03 21:28 210
    colors[ImGuiCol_SeparatorActive]        = ImVec4(0.10f, 0.40f, 0.75f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 211
    colors[ImGuiCol_ResizeGrip]             = ImVec4(0.26f, 0.59f, 0.98f, 0.20f);
1193b4be Poul Sander 2025-02-03 21:28 212
    colors[ImGuiCol_ResizeGripHovered]      = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
1193b4be Poul Sander 2025-02-03 21:28 213
    colors[ImGuiCol_ResizeGripActive]       = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
1193b4be Poul Sander 2025-02-03 21:28 214
    colors[ImGuiCol_TabHovered]             = colors[ImGuiCol_HeaderHovered];
1193b4be Poul Sander 2025-02-03 21:28 215
    colors[ImGuiCol_Tab]                    = ImLerp(colors[ImGuiCol_Header],       colors[ImGuiCol_TitleBgActive], 0.80f);
1193b4be Poul Sander 2025-02-03 21:28 216
    colors[ImGuiCol_TabSelected]            = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
1193b4be Poul Sander 2025-02-03 21:28 217
    colors[ImGuiCol_TabSelectedOverline]    = colors[ImGuiCol_HeaderActive];
1193b4be Poul Sander 2025-02-03 21:28 218
    colors[ImGuiCol_TabDimmed]              = ImLerp(colors[ImGuiCol_Tab],          colors[ImGuiCol_TitleBg], 0.80f);
1193b4be Poul Sander 2025-02-03 21:28 219
    colors[ImGuiCol_TabDimmedSelected]      = ImLerp(colors[ImGuiCol_TabSelected],  colors[ImGuiCol_TitleBg], 0.40f);
1193b4be Poul Sander 2025-02-03 21:28 220
    colors[ImGuiCol_TabDimmedSelectedOverline] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 221
    colors[ImGuiCol_DockingPreview]         = colors[ImGuiCol_HeaderActive] * ImVec4(1.0f, 1.0f, 1.0f, 0.7f);
1193b4be Poul Sander 2025-02-03 21:28 222
    colors[ImGuiCol_DockingEmptyBg]         = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 223
    colors[ImGuiCol_PlotLines]              = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 224
    colors[ImGuiCol_PlotLinesHovered]       = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 225
    colors[ImGuiCol_PlotHistogram]          = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 226
    colors[ImGuiCol_PlotHistogramHovered]   = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 227
    colors[ImGuiCol_TableHeaderBg]          = ImVec4(0.19f, 0.19f, 0.20f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 228
    colors[ImGuiCol_TableBorderStrong]      = ImVec4(0.31f, 0.31f, 0.35f, 1.00f);   // Prefer using Alpha=1.0 here
1193b4be Poul Sander 2025-02-03 21:28 229
    colors[ImGuiCol_TableBorderLight]       = ImVec4(0.23f, 0.23f, 0.25f, 1.00f);   // Prefer using Alpha=1.0 here
1193b4be Poul Sander 2025-02-03 21:28 230
    colors[ImGuiCol_TableRowBg]             = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
1193b4be Poul Sander 2025-02-03 21:28 231
    colors[ImGuiCol_TableRowBgAlt]          = ImVec4(1.00f, 1.00f, 1.00f, 0.06f);
1193b4be Poul Sander 2025-02-03 21:28 232
    colors[ImGuiCol_TextLink]               = colors[ImGuiCol_HeaderActive];
1193b4be Poul Sander 2025-02-03 21:28 233
    colors[ImGuiCol_TextSelectedBg]         = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
1193b4be Poul Sander 2025-02-03 21:28 234
    colors[ImGuiCol_DragDropTarget]         = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
1193b4be Poul Sander 2025-02-03 21:28 235
    colors[ImGuiCol_NavCursor]              = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 236
    colors[ImGuiCol_NavWindowingHighlight]  = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);
1193b4be Poul Sander 2025-02-03 21:28 237
    colors[ImGuiCol_NavWindowingDimBg]      = ImVec4(0.80f, 0.80f, 0.80f, 0.20f);
1193b4be Poul Sander 2025-02-03 21:28 238
    colors[ImGuiCol_ModalWindowDimBg]       = ImVec4(0.80f, 0.80f, 0.80f, 0.35f);
1193b4be Poul Sander 2025-02-03 21:28 239
}
1193b4be Poul Sander 2025-02-03 21:28 240
1193b4be Poul Sander 2025-02-03 21:28 241
void ImGui::StyleColorsClassic(ImGuiStyle* dst)
1193b4be Poul Sander 2025-02-03 21:28 242
{
1193b4be Poul Sander 2025-02-03 21:28 243
    ImGuiStyle* style = dst ? dst : &ImGui::GetStyle();
1193b4be Poul Sander 2025-02-03 21:28 244
    ImVec4* colors = style->Colors;
1193b4be Poul Sander 2025-02-03 21:28 245
1193b4be Poul Sander 2025-02-03 21:28 246
    colors[ImGuiCol_Text]                   = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 247
    colors[ImGuiCol_TextDisabled]           = ImVec4(0.60f, 0.60f, 0.60f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 248
    colors[ImGuiCol_WindowBg]               = ImVec4(0.00f, 0.00f, 0.00f, 0.85f);
1193b4be Poul Sander 2025-02-03 21:28 249
    colors[ImGuiCol_ChildBg]                = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
1193b4be Poul Sander 2025-02-03 21:28 250
    colors[ImGuiCol_PopupBg]                = ImVec4(0.11f, 0.11f, 0.14f, 0.92f);
1193b4be Poul Sander 2025-02-03 21:28 251
    colors[ImGuiCol_Border]                 = ImVec4(0.50f, 0.50f, 0.50f, 0.50f);
1193b4be Poul Sander 2025-02-03 21:28 252
    colors[ImGuiCol_BorderShadow]           = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
1193b4be Poul Sander 2025-02-03 21:28 253
    colors[ImGuiCol_FrameBg]                = ImVec4(0.43f, 0.43f, 0.43f, 0.39f);
1193b4be Poul Sander 2025-02-03 21:28 254
    colors[ImGuiCol_FrameBgHovered]         = ImVec4(0.47f, 0.47f, 0.69f, 0.40f);
1193b4be Poul Sander 2025-02-03 21:28 255
    colors[ImGuiCol_FrameBgActive]          = ImVec4(0.42f, 0.41f, 0.64f, 0.69f);
1193b4be Poul Sander 2025-02-03 21:28 256
    colors[ImGuiCol_TitleBg]                = ImVec4(0.27f, 0.27f, 0.54f, 0.83f);
1193b4be Poul Sander 2025-02-03 21:28 257
    colors[ImGuiCol_TitleBgActive]          = ImVec4(0.32f, 0.32f, 0.63f, 0.87f);
1193b4be Poul Sander 2025-02-03 21:28 258
    colors[ImGuiCol_TitleBgCollapsed]       = ImVec4(0.40f, 0.40f, 0.80f, 0.20f);
1193b4be Poul Sander 2025-02-03 21:28 259
    colors[ImGuiCol_MenuBarBg]              = ImVec4(0.40f, 0.40f, 0.55f, 0.80f);
1193b4be Poul Sander 2025-02-03 21:28 260
    colors[ImGuiCol_ScrollbarBg]            = ImVec4(0.20f, 0.25f, 0.30f, 0.60f);
1193b4be Poul Sander 2025-02-03 21:28 261
    colors[ImGuiCol_ScrollbarGrab]          = ImVec4(0.40f, 0.40f, 0.80f, 0.30f);
1193b4be Poul Sander 2025-02-03 21:28 262
    colors[ImGuiCol_ScrollbarGrabHovered]   = ImVec4(0.40f, 0.40f, 0.80f, 0.40f);
1193b4be Poul Sander 2025-02-03 21:28 263
    colors[ImGuiCol_ScrollbarGrabActive]    = ImVec4(0.41f, 0.39f, 0.80f, 0.60f);
1193b4be Poul Sander 2025-02-03 21:28 264
    colors[ImGuiCol_CheckMark]              = ImVec4(0.90f, 0.90f, 0.90f, 0.50f);
1193b4be Poul Sander 2025-02-03 21:28 265
    colors[ImGuiCol_SliderGrab]             = ImVec4(1.00f, 1.00f, 1.00f, 0.30f);
1193b4be Poul Sander 2025-02-03 21:28 266
    colors[ImGuiCol_SliderGrabActive]       = ImVec4(0.41f, 0.39f, 0.80f, 0.60f);
1193b4be Poul Sander 2025-02-03 21:28 267
    colors[ImGuiCol_Button]                 = ImVec4(0.35f, 0.40f, 0.61f, 0.62f);
1193b4be Poul Sander 2025-02-03 21:28 268
    colors[ImGuiCol_ButtonHovered]          = ImVec4(0.40f, 0.48f, 0.71f, 0.79f);
1193b4be Poul Sander 2025-02-03 21:28 269
    colors[ImGuiCol_ButtonActive]           = ImVec4(0.46f, 0.54f, 0.80f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 270
    colors[ImGuiCol_Header]                 = ImVec4(0.40f, 0.40f, 0.90f, 0.45f);
1193b4be Poul Sander 2025-02-03 21:28 271
    colors[ImGuiCol_HeaderHovered]          = ImVec4(0.45f, 0.45f, 0.90f, 0.80f);
1193b4be Poul Sander 2025-02-03 21:28 272
    colors[ImGuiCol_HeaderActive]           = ImVec4(0.53f, 0.53f, 0.87f, 0.80f);
1193b4be Poul Sander 2025-02-03 21:28 273
    colors[ImGuiCol_Separator]              = ImVec4(0.50f, 0.50f, 0.50f, 0.60f);
1193b4be Poul Sander 2025-02-03 21:28 274
    colors[ImGuiCol_SeparatorHovered]       = ImVec4(0.60f, 0.60f, 0.70f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 275
    colors[ImGuiCol_SeparatorActive]        = ImVec4(0.70f, 0.70f, 0.90f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 276
    colors[ImGuiCol_ResizeGrip]             = ImVec4(1.00f, 1.00f, 1.00f, 0.10f);
1193b4be Poul Sander 2025-02-03 21:28 277
    colors[ImGuiCol_ResizeGripHovered]      = ImVec4(0.78f, 0.82f, 1.00f, 0.60f);
1193b4be Poul Sander 2025-02-03 21:28 278
    colors[ImGuiCol_ResizeGripActive]       = ImVec4(0.78f, 0.82f, 1.00f, 0.90f);
1193b4be Poul Sander 2025-02-03 21:28 279
    colors[ImGuiCol_TabHovered]             = colors[ImGuiCol_HeaderHovered];
1193b4be Poul Sander 2025-02-03 21:28 280
    colors[ImGuiCol_Tab]                    = ImLerp(colors[ImGuiCol_Header],       colors[ImGuiCol_TitleBgActive], 0.80f);
1193b4be Poul Sander 2025-02-03 21:28 281
    colors[ImGuiCol_TabSelected]            = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
1193b4be Poul Sander 2025-02-03 21:28 282
    colors[ImGuiCol_TabSelectedOverline]    = colors[ImGuiCol_HeaderActive];
1193b4be Poul Sander 2025-02-03 21:28 283
    colors[ImGuiCol_TabDimmed]              = ImLerp(colors[ImGuiCol_Tab],          colors[ImGuiCol_TitleBg], 0.80f);
1193b4be Poul Sander 2025-02-03 21:28 284
    colors[ImGuiCol_TabDimmedSelected]      = ImLerp(colors[ImGuiCol_TabSelected],  colors[ImGuiCol_TitleBg], 0.40f);
1193b4be Poul Sander 2025-02-03 21:28 285
    colors[ImGuiCol_TabDimmedSelectedOverline] = colors[ImGuiCol_HeaderActive];
1193b4be Poul Sander 2025-02-03 21:28 286
    colors[ImGuiCol_DockingPreview]         = colors[ImGuiCol_Header] * ImVec4(1.0f, 1.0f, 1.0f, 0.7f);
1193b4be Poul Sander 2025-02-03 21:28 287
    colors[ImGuiCol_DockingEmptyBg]         = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 288
    colors[ImGuiCol_PlotLines]              = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 289
    colors[ImGuiCol_PlotLinesHovered]       = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 290
    colors[ImGuiCol_PlotHistogram]          = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 291
    colors[ImGuiCol_PlotHistogramHovered]   = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 292
    colors[ImGuiCol_TableHeaderBg]          = ImVec4(0.27f, 0.27f, 0.38f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 293
    colors[ImGuiCol_TableBorderStrong]      = ImVec4(0.31f, 0.31f, 0.45f, 1.00f);   // Prefer using Alpha=1.0 here
1193b4be Poul Sander 2025-02-03 21:28 294
    colors[ImGuiCol_TableBorderLight]       = ImVec4(0.26f, 0.26f, 0.28f, 1.00f);   // Prefer using Alpha=1.0 here
1193b4be Poul Sander 2025-02-03 21:28 295
    colors[ImGuiCol_TableRowBg]             = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
1193b4be Poul Sander 2025-02-03 21:28 296
    colors[ImGuiCol_TableRowBgAlt]          = ImVec4(1.00f, 1.00f, 1.00f, 0.07f);
1193b4be Poul Sander 2025-02-03 21:28 297
    colors[ImGuiCol_TextLink]               = colors[ImGuiCol_HeaderActive];
1193b4be Poul Sander 2025-02-03 21:28 298
    colors[ImGuiCol_TextSelectedBg]         = ImVec4(0.00f, 0.00f, 1.00f, 0.35f);
1193b4be Poul Sander 2025-02-03 21:28 299
    colors[ImGuiCol_DragDropTarget]         = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
1193b4be Poul Sander 2025-02-03 21:28 300
    colors[ImGuiCol_NavCursor]              = colors[ImGuiCol_HeaderHovered];
1193b4be Poul Sander 2025-02-03 21:28 301
    colors[ImGuiCol_NavWindowingHighlight]  = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);
1193b4be Poul Sander 2025-02-03 21:28 302
    colors[ImGuiCol_NavWindowingDimBg]      = ImVec4(0.80f, 0.80f, 0.80f, 0.20f);
1193b4be Poul Sander 2025-02-03 21:28 303
    colors[ImGuiCol_ModalWindowDimBg]       = ImVec4(0.20f, 0.20f, 0.20f, 0.35f);
1193b4be Poul Sander 2025-02-03 21:28 304
}
1193b4be Poul Sander 2025-02-03 21:28 305
1193b4be Poul Sander 2025-02-03 21:28 306
// Those light colors are better suited with a thicker font than the default one + FrameBorder
1193b4be Poul Sander 2025-02-03 21:28 307
void ImGui::StyleColorsLight(ImGuiStyle* dst)
1193b4be Poul Sander 2025-02-03 21:28 308
{
1193b4be Poul Sander 2025-02-03 21:28 309
    ImGuiStyle* style = dst ? dst : &ImGui::GetStyle();
1193b4be Poul Sander 2025-02-03 21:28 310
    ImVec4* colors = style->Colors;
1193b4be Poul Sander 2025-02-03 21:28 311
1193b4be Poul Sander 2025-02-03 21:28 312
    colors[ImGuiCol_Text]                   = ImVec4(0.00f, 0.00f, 0.00f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 313
    colors[ImGuiCol_TextDisabled]           = ImVec4(0.60f, 0.60f, 0.60f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 314
    colors[ImGuiCol_WindowBg]               = ImVec4(0.94f, 0.94f, 0.94f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 315
    colors[ImGuiCol_ChildBg]                = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
1193b4be Poul Sander 2025-02-03 21:28 316
    colors[ImGuiCol_PopupBg]                = ImVec4(1.00f, 1.00f, 1.00f, 0.98f);
1193b4be Poul Sander 2025-02-03 21:28 317
    colors[ImGuiCol_Border]                 = ImVec4(0.00f, 0.00f, 0.00f, 0.30f);
1193b4be Poul Sander 2025-02-03 21:28 318
    colors[ImGuiCol_BorderShadow]           = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
1193b4be Poul Sander 2025-02-03 21:28 319
    colors[ImGuiCol_FrameBg]                = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 320
    colors[ImGuiCol_FrameBgHovered]         = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);
1193b4be Poul Sander 2025-02-03 21:28 321
    colors[ImGuiCol_FrameBgActive]          = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
1193b4be Poul Sander 2025-02-03 21:28 322
    colors[ImGuiCol_TitleBg]                = ImVec4(0.96f, 0.96f, 0.96f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 323
    colors[ImGuiCol_TitleBgActive]          = ImVec4(0.82f, 0.82f, 0.82f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 324
    colors[ImGuiCol_TitleBgCollapsed]       = ImVec4(1.00f, 1.00f, 1.00f, 0.51f);
1193b4be Poul Sander 2025-02-03 21:28 325
    colors[ImGuiCol_MenuBarBg]              = ImVec4(0.86f, 0.86f, 0.86f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 326
    colors[ImGuiCol_ScrollbarBg]            = ImVec4(0.98f, 0.98f, 0.98f, 0.53f);
1193b4be Poul Sander 2025-02-03 21:28 327
    colors[ImGuiCol_ScrollbarGrab]          = ImVec4(0.69f, 0.69f, 0.69f, 0.80f);
1193b4be Poul Sander 2025-02-03 21:28 328
    colors[ImGuiCol_ScrollbarGrabHovered]   = ImVec4(0.49f, 0.49f, 0.49f, 0.80f);
1193b4be Poul Sander 2025-02-03 21:28 329
    colors[ImGuiCol_ScrollbarGrabActive]    = ImVec4(0.49f, 0.49f, 0.49f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 330
    colors[ImGuiCol_CheckMark]              = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 331
    colors[ImGuiCol_SliderGrab]             = ImVec4(0.26f, 0.59f, 0.98f, 0.78f);
1193b4be Poul Sander 2025-02-03 21:28 332
    colors[ImGuiCol_SliderGrabActive]       = ImVec4(0.46f, 0.54f, 0.80f, 0.60f);
1193b4be Poul Sander 2025-02-03 21:28 333
    colors[ImGuiCol_Button]                 = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);
1193b4be Poul Sander 2025-02-03 21:28 334
    colors[ImGuiCol_ButtonHovered]          = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 335
    colors[ImGuiCol_ButtonActive]           = ImVec4(0.06f, 0.53f, 0.98f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 336
    colors[ImGuiCol_Header]                 = ImVec4(0.26f, 0.59f, 0.98f, 0.31f);
1193b4be Poul Sander 2025-02-03 21:28 337
    colors[ImGuiCol_HeaderHovered]          = ImVec4(0.26f, 0.59f, 0.98f, 0.80f);
1193b4be Poul Sander 2025-02-03 21:28 338
    colors[ImGuiCol_HeaderActive]           = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 339
    colors[ImGuiCol_Separator]              = ImVec4(0.39f, 0.39f, 0.39f, 0.62f);
1193b4be Poul Sander 2025-02-03 21:28 340
    colors[ImGuiCol_SeparatorHovered]       = ImVec4(0.14f, 0.44f, 0.80f, 0.78f);
1193b4be Poul Sander 2025-02-03 21:28 341
    colors[ImGuiCol_SeparatorActive]        = ImVec4(0.14f, 0.44f, 0.80f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 342
    colors[ImGuiCol_ResizeGrip]             = ImVec4(0.35f, 0.35f, 0.35f, 0.17f);
1193b4be Poul Sander 2025-02-03 21:28 343
    colors[ImGuiCol_ResizeGripHovered]      = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
1193b4be Poul Sander 2025-02-03 21:28 344
    colors[ImGuiCol_ResizeGripActive]       = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
1193b4be Poul Sander 2025-02-03 21:28 345
    colors[ImGuiCol_TabHovered]             = colors[ImGuiCol_HeaderHovered];
1193b4be Poul Sander 2025-02-03 21:28 346
    colors[ImGuiCol_Tab]                    = ImLerp(colors[ImGuiCol_Header],       colors[ImGuiCol_TitleBgActive], 0.90f);
1193b4be Poul Sander 2025-02-03 21:28 347
    colors[ImGuiCol_TabSelected]            = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
1193b4be Poul Sander 2025-02-03 21:28 348
    colors[ImGuiCol_TabSelectedOverline]    = colors[ImGuiCol_HeaderActive];
1193b4be Poul Sander 2025-02-03 21:28 349
    colors[ImGuiCol_TabDimmed]              = ImLerp(colors[ImGuiCol_Tab],          colors[ImGuiCol_TitleBg], 0.80f);
1193b4be Poul Sander 2025-02-03 21:28 350
    colors[ImGuiCol_TabDimmedSelected]      = ImLerp(colors[ImGuiCol_TabSelected],  colors[ImGuiCol_TitleBg], 0.40f);
1193b4be Poul Sander 2025-02-03 21:28 351
    colors[ImGuiCol_TabDimmedSelectedOverline] = ImVec4(0.26f, 0.59f, 1.00f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 352
    colors[ImGuiCol_DockingPreview]         = colors[ImGuiCol_Header] * ImVec4(1.0f, 1.0f, 1.0f, 0.7f);
1193b4be Poul Sander 2025-02-03 21:28 353
    colors[ImGuiCol_DockingEmptyBg]         = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 354
    colors[ImGuiCol_PlotLines]              = ImVec4(0.39f, 0.39f, 0.39f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 355
    colors[ImGuiCol_PlotLinesHovered]       = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 356
    colors[ImGuiCol_PlotHistogram]          = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 357
    colors[ImGuiCol_PlotHistogramHovered]   = ImVec4(1.00f, 0.45f, 0.00f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 358
    colors[ImGuiCol_TableHeaderBg]          = ImVec4(0.78f, 0.87f, 0.98f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 359
    colors[ImGuiCol_TableBorderStrong]      = ImVec4(0.57f, 0.57f, 0.64f, 1.00f);   // Prefer using Alpha=1.0 here
1193b4be Poul Sander 2025-02-03 21:28 360
    colors[ImGuiCol_TableBorderLight]       = ImVec4(0.68f, 0.68f, 0.74f, 1.00f);   // Prefer using Alpha=1.0 here
1193b4be Poul Sander 2025-02-03 21:28 361
    colors[ImGuiCol_TableRowBg]             = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
1193b4be Poul Sander 2025-02-03 21:28 362
    colors[ImGuiCol_TableRowBgAlt]          = ImVec4(0.30f, 0.30f, 0.30f, 0.09f);
1193b4be Poul Sander 2025-02-03 21:28 363
    colors[ImGuiCol_TextLink]               = colors[ImGuiCol_HeaderActive];
1193b4be Poul Sander 2025-02-03 21:28 364
    colors[ImGuiCol_TextSelectedBg]         = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
1193b4be Poul Sander 2025-02-03 21:28 365
    colors[ImGuiCol_DragDropTarget]         = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
1193b4be Poul Sander 2025-02-03 21:28 366
    colors[ImGuiCol_NavCursor]              = colors[ImGuiCol_HeaderHovered];
1193b4be Poul Sander 2025-02-03 21:28 367
    colors[ImGuiCol_NavWindowingHighlight]  = ImVec4(0.70f, 0.70f, 0.70f, 0.70f);
1193b4be Poul Sander 2025-02-03 21:28 368
    colors[ImGuiCol_NavWindowingDimBg]      = ImVec4(0.20f, 0.20f, 0.20f, 0.20f);
1193b4be Poul Sander 2025-02-03 21:28 369
    colors[ImGuiCol_ModalWindowDimBg]       = ImVec4(0.20f, 0.20f, 0.20f, 0.35f);
1193b4be Poul Sander 2025-02-03 21:28 370
}
1193b4be Poul Sander 2025-02-03 21:28 371
1193b4be Poul Sander 2025-02-03 21:28 372
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 373
// [SECTION] ImDrawList
1193b4be Poul Sander 2025-02-03 21:28 374
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 375
1193b4be Poul Sander 2025-02-03 21:28 376
ImDrawListSharedData::ImDrawListSharedData()
1193b4be Poul Sander 2025-02-03 21:28 377
{
1193b4be Poul Sander 2025-02-03 21:28 378
    memset(this, 0, sizeof(*this));
1193b4be Poul Sander 2025-02-03 21:28 379
    for (int i = 0; i < IM_ARRAYSIZE(ArcFastVtx); i++)
1193b4be Poul Sander 2025-02-03 21:28 380
    {
1193b4be Poul Sander 2025-02-03 21:28 381
        const float a = ((float)i * 2 * IM_PI) / (float)IM_ARRAYSIZE(ArcFastVtx);
1193b4be Poul Sander 2025-02-03 21:28 382
        ArcFastVtx[i] = ImVec2(ImCos(a), ImSin(a));
1193b4be Poul Sander 2025-02-03 21:28 383
    }
1193b4be Poul Sander 2025-02-03 21:28 384
    ArcFastRadiusCutoff = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(IM_DRAWLIST_ARCFAST_SAMPLE_MAX, CircleSegmentMaxError);
1193b4be Poul Sander 2025-02-03 21:28 385
}
1193b4be Poul Sander 2025-02-03 21:28 386
1193b4be Poul Sander 2025-02-03 21:28 387
void ImDrawListSharedData::SetCircleTessellationMaxError(float max_error)
1193b4be Poul Sander 2025-02-03 21:28 388
{
1193b4be Poul Sander 2025-02-03 21:28 389
    if (CircleSegmentMaxError == max_error)
1193b4be Poul Sander 2025-02-03 21:28 390
        return;
1193b4be Poul Sander 2025-02-03 21:28 391
1193b4be Poul Sander 2025-02-03 21:28 392
    IM_ASSERT(max_error > 0.0f);
1193b4be Poul Sander 2025-02-03 21:28 393
    CircleSegmentMaxError = max_error;
1193b4be Poul Sander 2025-02-03 21:28 394
    for (int i = 0; i < IM_ARRAYSIZE(CircleSegmentCounts); i++)
1193b4be Poul Sander 2025-02-03 21:28 395
    {
1193b4be Poul Sander 2025-02-03 21:28 396
        const float radius = (float)i;
1193b4be Poul Sander 2025-02-03 21:28 397
        CircleSegmentCounts[i] = (ImU8)((i > 0) ? IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, CircleSegmentMaxError) : IM_DRAWLIST_ARCFAST_SAMPLE_MAX);
1193b4be Poul Sander 2025-02-03 21:28 398
    }
1193b4be Poul Sander 2025-02-03 21:28 399
    ArcFastRadiusCutoff = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(IM_DRAWLIST_ARCFAST_SAMPLE_MAX, CircleSegmentMaxError);
1193b4be Poul Sander 2025-02-03 21:28 400
}
1193b4be Poul Sander 2025-02-03 21:28 401
1193b4be Poul Sander 2025-02-03 21:28 402
// Initialize before use in a new frame. We always have a command ready in the buffer.
1193b4be Poul Sander 2025-02-03 21:28 403
// In the majority of cases, you would want to call PushClipRect() and PushTextureID() after this.
1193b4be Poul Sander 2025-02-03 21:28 404
void ImDrawList::_ResetForNewFrame()
1193b4be Poul Sander 2025-02-03 21:28 405
{
1193b4be Poul Sander 2025-02-03 21:28 406
    // Verify that the ImDrawCmd fields we want to memcmp() are contiguous in memory.
1193b4be Poul Sander 2025-02-03 21:28 407
    IM_STATIC_ASSERT(offsetof(ImDrawCmd, ClipRect) == 0);
1193b4be Poul Sander 2025-02-03 21:28 408
    IM_STATIC_ASSERT(offsetof(ImDrawCmd, TextureId) == sizeof(ImVec4));
1193b4be Poul Sander 2025-02-03 21:28 409
    IM_STATIC_ASSERT(offsetof(ImDrawCmd, VtxOffset) == sizeof(ImVec4) + sizeof(ImTextureID));
1193b4be Poul Sander 2025-02-03 21:28 410
    if (_Splitter._Count > 1)
1193b4be Poul Sander 2025-02-03 21:28 411
        _Splitter.Merge(this);
1193b4be Poul Sander 2025-02-03 21:28 412
1193b4be Poul Sander 2025-02-03 21:28 413
    CmdBuffer.resize(0);
1193b4be Poul Sander 2025-02-03 21:28 414
    IdxBuffer.resize(0);
1193b4be Poul Sander 2025-02-03 21:28 415
    VtxBuffer.resize(0);
1193b4be Poul Sander 2025-02-03 21:28 416
    Flags = _Data->InitialFlags;
1193b4be Poul Sander 2025-02-03 21:28 417
    memset(&_CmdHeader, 0, sizeof(_CmdHeader));
1193b4be Poul Sander 2025-02-03 21:28 418
    _VtxCurrentIdx = 0;
1193b4be Poul Sander 2025-02-03 21:28 419
    _VtxWritePtr = NULL;
1193b4be Poul Sander 2025-02-03 21:28 420
    _IdxWritePtr = NULL;
1193b4be Poul Sander 2025-02-03 21:28 421
    _ClipRectStack.resize(0);
1193b4be Poul Sander 2025-02-03 21:28 422
    _TextureIdStack.resize(0);
1193b4be Poul Sander 2025-02-03 21:28 423
    _CallbacksDataBuf.resize(0);
1193b4be Poul Sander 2025-02-03 21:28 424
    _Path.resize(0);
1193b4be Poul Sander 2025-02-03 21:28 425
    _Splitter.Clear();
1193b4be Poul Sander 2025-02-03 21:28 426
    CmdBuffer.push_back(ImDrawCmd());
1193b4be Poul Sander 2025-02-03 21:28 427
    _FringeScale = 1.0f;
1193b4be Poul Sander 2025-02-03 21:28 428
}
1193b4be Poul Sander 2025-02-03 21:28 429
1193b4be Poul Sander 2025-02-03 21:28 430
void ImDrawList::_ClearFreeMemory()
1193b4be Poul Sander 2025-02-03 21:28 431
{
1193b4be Poul Sander 2025-02-03 21:28 432
    CmdBuffer.clear();
1193b4be Poul Sander 2025-02-03 21:28 433
    IdxBuffer.clear();
1193b4be Poul Sander 2025-02-03 21:28 434
    VtxBuffer.clear();
1193b4be Poul Sander 2025-02-03 21:28 435
    Flags = ImDrawListFlags_None;
1193b4be Poul Sander 2025-02-03 21:28 436
    _VtxCurrentIdx = 0;
1193b4be Poul Sander 2025-02-03 21:28 437
    _VtxWritePtr = NULL;
1193b4be Poul Sander 2025-02-03 21:28 438
    _IdxWritePtr = NULL;
1193b4be Poul Sander 2025-02-03 21:28 439
    _ClipRectStack.clear();
1193b4be Poul Sander 2025-02-03 21:28 440
    _TextureIdStack.clear();
1193b4be Poul Sander 2025-02-03 21:28 441
    _CallbacksDataBuf.clear();
1193b4be Poul Sander 2025-02-03 21:28 442
    _Path.clear();
1193b4be Poul Sander 2025-02-03 21:28 443
    _Splitter.ClearFreeMemory();
1193b4be Poul Sander 2025-02-03 21:28 444
}
1193b4be Poul Sander 2025-02-03 21:28 445
1193b4be Poul Sander 2025-02-03 21:28 446
ImDrawList* ImDrawList::CloneOutput() const
1193b4be Poul Sander 2025-02-03 21:28 447
{
1193b4be Poul Sander 2025-02-03 21:28 448
    ImDrawList* dst = IM_NEW(ImDrawList(_Data));
1193b4be Poul Sander 2025-02-03 21:28 449
    dst->CmdBuffer = CmdBuffer;
1193b4be Poul Sander 2025-02-03 21:28 450
    dst->IdxBuffer = IdxBuffer;
1193b4be Poul Sander 2025-02-03 21:28 451
    dst->VtxBuffer = VtxBuffer;
1193b4be Poul Sander 2025-02-03 21:28 452
    dst->Flags = Flags;
1193b4be Poul Sander 2025-02-03 21:28 453
    return dst;
1193b4be Poul Sander 2025-02-03 21:28 454
}
1193b4be Poul Sander 2025-02-03 21:28 455
1193b4be Poul Sander 2025-02-03 21:28 456
void ImDrawList::AddDrawCmd()
1193b4be Poul Sander 2025-02-03 21:28 457
{
1193b4be Poul Sander 2025-02-03 21:28 458
    ImDrawCmd draw_cmd;
1193b4be Poul Sander 2025-02-03 21:28 459
    draw_cmd.ClipRect = _CmdHeader.ClipRect;    // Same as calling ImDrawCmd_HeaderCopy()
1193b4be Poul Sander 2025-02-03 21:28 460
    draw_cmd.TextureId = _CmdHeader.TextureId;
1193b4be Poul Sander 2025-02-03 21:28 461
    draw_cmd.VtxOffset = _CmdHeader.VtxOffset;
1193b4be Poul Sander 2025-02-03 21:28 462
    draw_cmd.IdxOffset = IdxBuffer.Size;
1193b4be Poul Sander 2025-02-03 21:28 463
1193b4be Poul Sander 2025-02-03 21:28 464
    IM_ASSERT(draw_cmd.ClipRect.x <= draw_cmd.ClipRect.z && draw_cmd.ClipRect.y <= draw_cmd.ClipRect.w);
1193b4be Poul Sander 2025-02-03 21:28 465
    CmdBuffer.push_back(draw_cmd);
1193b4be Poul Sander 2025-02-03 21:28 466
}
1193b4be Poul Sander 2025-02-03 21:28 467
1193b4be Poul Sander 2025-02-03 21:28 468
// Pop trailing draw command (used before merging or presenting to user)
1193b4be Poul Sander 2025-02-03 21:28 469
// 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
1193b4be Poul Sander 2025-02-03 21:28 470
void ImDrawList::_PopUnusedDrawCmd()
1193b4be Poul Sander 2025-02-03 21:28 471
{
1193b4be Poul Sander 2025-02-03 21:28 472
    while (CmdBuffer.Size > 0)
1193b4be Poul Sander 2025-02-03 21:28 473
    {
1193b4be Poul Sander 2025-02-03 21:28 474
        ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
1193b4be Poul Sander 2025-02-03 21:28 475
        if (curr_cmd->ElemCount != 0 || curr_cmd->UserCallback != NULL)
1193b4be Poul Sander 2025-02-03 21:28 476
            return;// break;
1193b4be Poul Sander 2025-02-03 21:28 477
        CmdBuffer.pop_back();
1193b4be Poul Sander 2025-02-03 21:28 478
    }
1193b4be Poul Sander 2025-02-03 21:28 479
}
1193b4be Poul Sander 2025-02-03 21:28 480
1193b4be Poul Sander 2025-02-03 21:28 481
void ImDrawList::AddCallback(ImDrawCallback callback, void* userdata, size_t userdata_size)
1193b4be Poul Sander 2025-02-03 21:28 482
{
1193b4be Poul Sander 2025-02-03 21:28 483
    IM_ASSERT_PARANOID(CmdBuffer.Size > 0);
1193b4be Poul Sander 2025-02-03 21:28 484
    ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
1193b4be Poul Sander 2025-02-03 21:28 485
    IM_ASSERT(curr_cmd->UserCallback == NULL);
1193b4be Poul Sander 2025-02-03 21:28 486
    if (curr_cmd->ElemCount != 0)
1193b4be Poul Sander 2025-02-03 21:28 487
    {
1193b4be Poul Sander 2025-02-03 21:28 488
        AddDrawCmd();
1193b4be Poul Sander 2025-02-03 21:28 489
        curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
1193b4be Poul Sander 2025-02-03 21:28 490
    }
1193b4be Poul Sander 2025-02-03 21:28 491
1193b4be Poul Sander 2025-02-03 21:28 492
    curr_cmd->UserCallback = callback;
1193b4be Poul Sander 2025-02-03 21:28 493
    if (userdata_size == 0)
1193b4be Poul Sander 2025-02-03 21:28 494
    {
1193b4be Poul Sander 2025-02-03 21:28 495
        // Store user data directly in command (no indirection)
1193b4be Poul Sander 2025-02-03 21:28 496
        curr_cmd->UserCallbackData = userdata;
1193b4be Poul Sander 2025-02-03 21:28 497
        curr_cmd->UserCallbackDataSize = 0;
1193b4be Poul Sander 2025-02-03 21:28 498
        curr_cmd->UserCallbackDataOffset = -1;
1193b4be Poul Sander 2025-02-03 21:28 499
    }
1193b4be Poul Sander 2025-02-03 21:28 500
    else
1193b4be Poul Sander 2025-02-03 21:28 501
    {
1193b4be Poul Sander 2025-02-03 21:28 502
        // Copy and store user data in a buffer
1193b4be Poul Sander 2025-02-03 21:28 503
        IM_ASSERT(userdata != NULL);
1193b4be Poul Sander 2025-02-03 21:28 504
        IM_ASSERT(userdata_size < (1u << 31));
1193b4be Poul Sander 2025-02-03 21:28 505
        curr_cmd->UserCallbackData = NULL; // Will be resolved during Render()
1193b4be Poul Sander 2025-02-03 21:28 506
        curr_cmd->UserCallbackDataSize = (int)userdata_size;
1193b4be Poul Sander 2025-02-03 21:28 507
        curr_cmd->UserCallbackDataOffset = _CallbacksDataBuf.Size;
1193b4be Poul Sander 2025-02-03 21:28 508
        _CallbacksDataBuf.resize(_CallbacksDataBuf.Size + (int)userdata_size);
1193b4be Poul Sander 2025-02-03 21:28 509
        memcpy(_CallbacksDataBuf.Data + (size_t)curr_cmd->UserCallbackDataOffset, userdata, userdata_size);
1193b4be Poul Sander 2025-02-03 21:28 510
    }
1193b4be Poul Sander 2025-02-03 21:28 511
1193b4be Poul Sander 2025-02-03 21:28 512
    AddDrawCmd(); // Force a new command after us (see comment below)
1193b4be Poul Sander 2025-02-03 21:28 513
}
1193b4be Poul Sander 2025-02-03 21:28 514
1193b4be Poul Sander 2025-02-03 21:28 515
// Compare ClipRect, TextureId and VtxOffset with a single memcmp()
1193b4be Poul Sander 2025-02-03 21:28 516
#define ImDrawCmd_HeaderSize                            (offsetof(ImDrawCmd, VtxOffset) + sizeof(unsigned int))
1193b4be Poul Sander 2025-02-03 21:28 517
#define ImDrawCmd_HeaderCompare(CMD_LHS, CMD_RHS)       (memcmp(CMD_LHS, CMD_RHS, ImDrawCmd_HeaderSize))    // Compare ClipRect, TextureId, VtxOffset
1193b4be Poul Sander 2025-02-03 21:28 518
#define ImDrawCmd_HeaderCopy(CMD_DST, CMD_SRC)          (memcpy(CMD_DST, CMD_SRC, ImDrawCmd_HeaderSize))    // Copy ClipRect, TextureId, VtxOffset
1193b4be Poul Sander 2025-02-03 21:28 519
#define ImDrawCmd_AreSequentialIdxOffset(CMD_0, CMD_1)  (CMD_0->IdxOffset + CMD_0->ElemCount == CMD_1->IdxOffset)
1193b4be Poul Sander 2025-02-03 21:28 520
1193b4be Poul Sander 2025-02-03 21:28 521
// Try to merge two last draw commands
1193b4be Poul Sander 2025-02-03 21:28 522
void ImDrawList::_TryMergeDrawCmds()
1193b4be Poul Sander 2025-02-03 21:28 523
{
1193b4be Poul Sander 2025-02-03 21:28 524
    IM_ASSERT_PARANOID(CmdBuffer.Size > 0);
1193b4be Poul Sander 2025-02-03 21:28 525
    ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
1193b4be Poul Sander 2025-02-03 21:28 526
    ImDrawCmd* prev_cmd = curr_cmd - 1;
1193b4be Poul Sander 2025-02-03 21:28 527
    if (ImDrawCmd_HeaderCompare(curr_cmd, prev_cmd) == 0 && ImDrawCmd_AreSequentialIdxOffset(prev_cmd, curr_cmd) && curr_cmd->UserCallback == NULL && prev_cmd->UserCallback == NULL)
1193b4be Poul Sander 2025-02-03 21:28 528
    {
1193b4be Poul Sander 2025-02-03 21:28 529
        prev_cmd->ElemCount += curr_cmd->ElemCount;
1193b4be Poul Sander 2025-02-03 21:28 530
        CmdBuffer.pop_back();
1193b4be Poul Sander 2025-02-03 21:28 531
    }
1193b4be Poul Sander 2025-02-03 21:28 532
}
1193b4be Poul Sander 2025-02-03 21:28 533
1193b4be Poul Sander 2025-02-03 21:28 534
// 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.
1193b4be Poul Sander 2025-02-03 21:28 535
// 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.
1193b4be Poul Sander 2025-02-03 21:28 536
void ImDrawList::_OnChangedClipRect()
1193b4be Poul Sander 2025-02-03 21:28 537
{
1193b4be Poul Sander 2025-02-03 21:28 538
    // If current command is used with different settings we need to add a new command
1193b4be Poul Sander 2025-02-03 21:28 539
    IM_ASSERT_PARANOID(CmdBuffer.Size > 0);
1193b4be Poul Sander 2025-02-03 21:28 540
    ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
1193b4be Poul Sander 2025-02-03 21:28 541
    if (curr_cmd->ElemCount != 0 && memcmp(&curr_cmd->ClipRect, &_CmdHeader.ClipRect, sizeof(ImVec4)) != 0)
1193b4be Poul Sander 2025-02-03 21:28 542
    {
1193b4be Poul Sander 2025-02-03 21:28 543
        AddDrawCmd();
1193b4be Poul Sander 2025-02-03 21:28 544
        return;
1193b4be Poul Sander 2025-02-03 21:28 545
    }
1193b4be Poul Sander 2025-02-03 21:28 546
    IM_ASSERT(curr_cmd->UserCallback == NULL);
1193b4be Poul Sander 2025-02-03 21:28 547
1193b4be Poul Sander 2025-02-03 21:28 548
    // Try to merge with previous command if it matches, else use current command
1193b4be Poul Sander 2025-02-03 21:28 549
    ImDrawCmd* prev_cmd = curr_cmd - 1;
1193b4be Poul Sander 2025-02-03 21:28 550
    if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && ImDrawCmd_AreSequentialIdxOffset(prev_cmd, curr_cmd) && prev_cmd->UserCallback == NULL)
1193b4be Poul Sander 2025-02-03 21:28 551
    {
1193b4be Poul Sander 2025-02-03 21:28 552
        CmdBuffer.pop_back();
1193b4be Poul Sander 2025-02-03 21:28 553
        return;
1193b4be Poul Sander 2025-02-03 21:28 554
    }
1193b4be Poul Sander 2025-02-03 21:28 555
    curr_cmd->ClipRect = _CmdHeader.ClipRect;
1193b4be Poul Sander 2025-02-03 21:28 556
}
1193b4be Poul Sander 2025-02-03 21:28 557
1193b4be Poul Sander 2025-02-03 21:28 558
void ImDrawList::_OnChangedTextureID()
1193b4be Poul Sander 2025-02-03 21:28 559
{
1193b4be Poul Sander 2025-02-03 21:28 560
    // If current command is used with different settings we need to add a new command
1193b4be Poul Sander 2025-02-03 21:28 561
    IM_ASSERT_PARANOID(CmdBuffer.Size > 0);
1193b4be Poul Sander 2025-02-03 21:28 562
    ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
1193b4be Poul Sander 2025-02-03 21:28 563
    if (curr_cmd->ElemCount != 0 && curr_cmd->TextureId != _CmdHeader.TextureId)
1193b4be Poul Sander 2025-02-03 21:28 564
    {
1193b4be Poul Sander 2025-02-03 21:28 565
        AddDrawCmd();
1193b4be Poul Sander 2025-02-03 21:28 566
        return;
1193b4be Poul Sander 2025-02-03 21:28 567
    }
1193b4be Poul Sander 2025-02-03 21:28 568
    IM_ASSERT(curr_cmd->UserCallback == NULL);
1193b4be Poul Sander 2025-02-03 21:28 569
1193b4be Poul Sander 2025-02-03 21:28 570
    // Try to merge with previous command if it matches, else use current command
1193b4be Poul Sander 2025-02-03 21:28 571
    ImDrawCmd* prev_cmd = curr_cmd - 1;
1193b4be Poul Sander 2025-02-03 21:28 572
    if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && ImDrawCmd_AreSequentialIdxOffset(prev_cmd, curr_cmd) && prev_cmd->UserCallback == NULL)
1193b4be Poul Sander 2025-02-03 21:28 573
    {
1193b4be Poul Sander 2025-02-03 21:28 574
        CmdBuffer.pop_back();
1193b4be Poul Sander 2025-02-03 21:28 575
        return;
1193b4be Poul Sander 2025-02-03 21:28 576
    }
1193b4be Poul Sander 2025-02-03 21:28 577
    curr_cmd->TextureId = _CmdHeader.TextureId;
1193b4be Poul Sander 2025-02-03 21:28 578
}
1193b4be Poul Sander 2025-02-03 21:28 579
1193b4be Poul Sander 2025-02-03 21:28 580
void ImDrawList::_OnChangedVtxOffset()
1193b4be Poul Sander 2025-02-03 21:28 581
{
1193b4be Poul Sander 2025-02-03 21:28 582
    // We don't need to compare curr_cmd->VtxOffset != _CmdHeader.VtxOffset because we know it'll be different at the time we call this.
1193b4be Poul Sander 2025-02-03 21:28 583
    _VtxCurrentIdx = 0;
1193b4be Poul Sander 2025-02-03 21:28 584
    IM_ASSERT_PARANOID(CmdBuffer.Size > 0);
1193b4be Poul Sander 2025-02-03 21:28 585
    ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
1193b4be Poul Sander 2025-02-03 21:28 586
    //IM_ASSERT(curr_cmd->VtxOffset != _CmdHeader.VtxOffset); // See #3349
1193b4be Poul Sander 2025-02-03 21:28 587
    if (curr_cmd->ElemCount != 0)
1193b4be Poul Sander 2025-02-03 21:28 588
    {
1193b4be Poul Sander 2025-02-03 21:28 589
        AddDrawCmd();
1193b4be Poul Sander 2025-02-03 21:28 590
        return;
1193b4be Poul Sander 2025-02-03 21:28 591
    }
1193b4be Poul Sander 2025-02-03 21:28 592
    IM_ASSERT(curr_cmd->UserCallback == NULL);
1193b4be Poul Sander 2025-02-03 21:28 593
    curr_cmd->VtxOffset = _CmdHeader.VtxOffset;
1193b4be Poul Sander 2025-02-03 21:28 594
}
1193b4be Poul Sander 2025-02-03 21:28 595
1193b4be Poul Sander 2025-02-03 21:28 596
int ImDrawList::_CalcCircleAutoSegmentCount(float radius) const
1193b4be Poul Sander 2025-02-03 21:28 597
{
1193b4be Poul Sander 2025-02-03 21:28 598
    // Automatic segment count
1193b4be Poul Sander 2025-02-03 21:28 599
    const int radius_idx = (int)(radius + 0.999999f); // ceil to never reduce accuracy
1193b4be Poul Sander 2025-02-03 21:28 600
    if (radius_idx >= 0 && radius_idx < IM_ARRAYSIZE(_Data->CircleSegmentCounts))
1193b4be Poul Sander 2025-02-03 21:28 601
        return _Data->CircleSegmentCounts[radius_idx]; // Use cached value
1193b4be Poul Sander 2025-02-03 21:28 602
    else
1193b4be Poul Sander 2025-02-03 21:28 603
        return IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, _Data->CircleSegmentMaxError);
1193b4be Poul Sander 2025-02-03 21:28 604
}
1193b4be Poul Sander 2025-02-03 21:28 605
1193b4be Poul Sander 2025-02-03 21:28 606
// 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)
1193b4be Poul Sander 2025-02-03 21:28 607
void ImDrawList::PushClipRect(const ImVec2& cr_min, const ImVec2& cr_max, bool intersect_with_current_clip_rect)
1193b4be Poul Sander 2025-02-03 21:28 608
{
1193b4be Poul Sander 2025-02-03 21:28 609
    ImVec4 cr(cr_min.x, cr_min.y, cr_max.x, cr_max.y);
1193b4be Poul Sander 2025-02-03 21:28 610
    if (intersect_with_current_clip_rect)
1193b4be Poul Sander 2025-02-03 21:28 611
    {
1193b4be Poul Sander 2025-02-03 21:28 612
        ImVec4 current = _CmdHeader.ClipRect;
1193b4be Poul Sander 2025-02-03 21:28 613
        if (cr.x < current.x) cr.x = current.x;
1193b4be Poul Sander 2025-02-03 21:28 614
        if (cr.y < current.y) cr.y = current.y;
1193b4be Poul Sander 2025-02-03 21:28 615
        if (cr.z > current.z) cr.z = current.z;
1193b4be Poul Sander 2025-02-03 21:28 616
        if (cr.w > current.w) cr.w = current.w;
1193b4be Poul Sander 2025-02-03 21:28 617
    }
1193b4be Poul Sander 2025-02-03 21:28 618
    cr.z = ImMax(cr.x, cr.z);
1193b4be Poul Sander 2025-02-03 21:28 619
    cr.w = ImMax(cr.y, cr.w);
1193b4be Poul Sander 2025-02-03 21:28 620
1193b4be Poul Sander 2025-02-03 21:28 621
    _ClipRectStack.push_back(cr);
1193b4be Poul Sander 2025-02-03 21:28 622
    _CmdHeader.ClipRect = cr;
1193b4be Poul Sander 2025-02-03 21:28 623
    _OnChangedClipRect();
1193b4be Poul Sander 2025-02-03 21:28 624
}
1193b4be Poul Sander 2025-02-03 21:28 625
1193b4be Poul Sander 2025-02-03 21:28 626
void ImDrawList::PushClipRectFullScreen()
1193b4be Poul Sander 2025-02-03 21:28 627
{
1193b4be Poul Sander 2025-02-03 21:28 628
    PushClipRect(ImVec2(_Data->ClipRectFullscreen.x, _Data->ClipRectFullscreen.y), ImVec2(_Data->ClipRectFullscreen.z, _Data->ClipRectFullscreen.w));
1193b4be Poul Sander 2025-02-03 21:28 629
}
1193b4be Poul Sander 2025-02-03 21:28 630
1193b4be Poul Sander 2025-02-03 21:28 631
void ImDrawList::PopClipRect()
1193b4be Poul Sander 2025-02-03 21:28 632
{
1193b4be Poul Sander 2025-02-03 21:28 633
    _ClipRectStack.pop_back();
1193b4be Poul Sander 2025-02-03 21:28 634
    _CmdHeader.ClipRect = (_ClipRectStack.Size == 0) ? _Data->ClipRectFullscreen : _ClipRectStack.Data[_ClipRectStack.Size - 1];
1193b4be Poul Sander 2025-02-03 21:28 635
    _OnChangedClipRect();
1193b4be Poul Sander 2025-02-03 21:28 636
}
1193b4be Poul Sander 2025-02-03 21:28 637
1193b4be Poul Sander 2025-02-03 21:28 638
void ImDrawList::PushTextureID(ImTextureID texture_id)
1193b4be Poul Sander 2025-02-03 21:28 639
{
1193b4be Poul Sander 2025-02-03 21:28 640
    _TextureIdStack.push_back(texture_id);
1193b4be Poul Sander 2025-02-03 21:28 641
    _CmdHeader.TextureId = texture_id;
1193b4be Poul Sander 2025-02-03 21:28 642
    _OnChangedTextureID();
1193b4be Poul Sander 2025-02-03 21:28 643
}
1193b4be Poul Sander 2025-02-03 21:28 644
1193b4be Poul Sander 2025-02-03 21:28 645
void ImDrawList::PopTextureID()
1193b4be Poul Sander 2025-02-03 21:28 646
{
1193b4be Poul Sander 2025-02-03 21:28 647
    _TextureIdStack.pop_back();
1193b4be Poul Sander 2025-02-03 21:28 648
    _CmdHeader.TextureId = (_TextureIdStack.Size == 0) ? (ImTextureID)NULL : _TextureIdStack.Data[_TextureIdStack.Size - 1];
1193b4be Poul Sander 2025-02-03 21:28 649
    _OnChangedTextureID();
1193b4be Poul Sander 2025-02-03 21:28 650
}
1193b4be Poul Sander 2025-02-03 21:28 651
1193b4be Poul Sander 2025-02-03 21:28 652
// This is used by ImGui::PushFont()/PopFont(). It works because we never use _TextureIdStack[] elsewhere than in PushTextureID()/PopTextureID().
1193b4be Poul Sander 2025-02-03 21:28 653
void ImDrawList::_SetTextureID(ImTextureID texture_id)
1193b4be Poul Sander 2025-02-03 21:28 654
{
1193b4be Poul Sander 2025-02-03 21:28 655
    if (_CmdHeader.TextureId == texture_id)
1193b4be Poul Sander 2025-02-03 21:28 656
        return;
1193b4be Poul Sander 2025-02-03 21:28 657
    _CmdHeader.TextureId = texture_id;
1193b4be Poul Sander 2025-02-03 21:28 658
    _OnChangedTextureID();
1193b4be Poul Sander 2025-02-03 21:28 659
}
1193b4be Poul Sander 2025-02-03 21:28 660
1193b4be Poul Sander 2025-02-03 21:28 661
// Reserve space for a number of vertices and indices.
1193b4be Poul Sander 2025-02-03 21:28 662
// You must finish filling your reserved data before calling PrimReserve() again, as it may reallocate or
1193b4be Poul Sander 2025-02-03 21:28 663
// submit the intermediate results. PrimUnreserve() can be used to release unused allocations.
1193b4be Poul Sander 2025-02-03 21:28 664
void ImDrawList::PrimReserve(int idx_count, int vtx_count)
1193b4be Poul Sander 2025-02-03 21:28 665
{
1193b4be Poul Sander 2025-02-03 21:28 666
    // Large mesh support (when enabled)
1193b4be Poul Sander 2025-02-03 21:28 667
    IM_ASSERT_PARANOID(idx_count >= 0 && vtx_count >= 0);
1193b4be Poul Sander 2025-02-03 21:28 668
    if (sizeof(ImDrawIdx) == 2 && (_VtxCurrentIdx + vtx_count >= (1 << 16)) && (Flags & ImDrawListFlags_AllowVtxOffset))
1193b4be Poul Sander 2025-02-03 21:28 669
    {
1193b4be Poul Sander 2025-02-03 21:28 670
        // FIXME: In theory we should be testing that vtx_count <64k here.
1193b4be Poul Sander 2025-02-03 21:28 671
        // In practice, RenderText() relies on reserving ahead for a worst case scenario so it is currently useful for us
1193b4be Poul Sander 2025-02-03 21:28 672
        // to not make that check until we rework the text functions to handle clipping and large horizontal lines better.
1193b4be Poul Sander 2025-02-03 21:28 673
        _CmdHeader.VtxOffset = VtxBuffer.Size;
1193b4be Poul Sander 2025-02-03 21:28 674
        _OnChangedVtxOffset();
1193b4be Poul Sander 2025-02-03 21:28 675
    }
1193b4be Poul Sander 2025-02-03 21:28 676
1193b4be Poul Sander 2025-02-03 21:28 677
    ImDrawCmd* draw_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
1193b4be Poul Sander 2025-02-03 21:28 678
    draw_cmd->ElemCount += idx_count;
1193b4be Poul Sander 2025-02-03 21:28 679
1193b4be Poul Sander 2025-02-03 21:28 680
    int vtx_buffer_old_size = VtxBuffer.Size;
1193b4be Poul Sander 2025-02-03 21:28 681
    VtxBuffer.resize(vtx_buffer_old_size + vtx_count);
1193b4be Poul Sander 2025-02-03 21:28 682
    _VtxWritePtr = VtxBuffer.Data + vtx_buffer_old_size;
1193b4be Poul Sander 2025-02-03 21:28 683
1193b4be Poul Sander 2025-02-03 21:28 684
    int idx_buffer_old_size = IdxBuffer.Size;
1193b4be Poul Sander 2025-02-03 21:28 685
    IdxBuffer.resize(idx_buffer_old_size + idx_count);
1193b4be Poul Sander 2025-02-03 21:28 686
    _IdxWritePtr = IdxBuffer.Data + idx_buffer_old_size;
1193b4be Poul Sander 2025-02-03 21:28 687
}
1193b4be Poul Sander 2025-02-03 21:28 688
1193b4be Poul Sander 2025-02-03 21:28 689
// Release the number of reserved vertices/indices from the end of the last reservation made with PrimReserve().
1193b4be Poul Sander 2025-02-03 21:28 690
void ImDrawList::PrimUnreserve(int idx_count, int vtx_count)
1193b4be Poul Sander 2025-02-03 21:28 691
{
1193b4be Poul Sander 2025-02-03 21:28 692
    IM_ASSERT_PARANOID(idx_count >= 0 && vtx_count >= 0);
1193b4be Poul Sander 2025-02-03 21:28 693
1193b4be Poul Sander 2025-02-03 21:28 694
    ImDrawCmd* draw_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
1193b4be Poul Sander 2025-02-03 21:28 695
    draw_cmd->ElemCount -= idx_count;
1193b4be Poul Sander 2025-02-03 21:28 696
    VtxBuffer.shrink(VtxBuffer.Size - vtx_count);
1193b4be Poul Sander 2025-02-03 21:28 697
    IdxBuffer.shrink(IdxBuffer.Size - idx_count);
1193b4be Poul Sander 2025-02-03 21:28 698
}
1193b4be Poul Sander 2025-02-03 21:28 699
1193b4be Poul Sander 2025-02-03 21:28 700
// Fully unrolled with inline call to keep our debug builds decently fast.
1193b4be Poul Sander 2025-02-03 21:28 701
void ImDrawList::PrimRect(const ImVec2& a, const ImVec2& c, ImU32 col)
1193b4be Poul Sander 2025-02-03 21:28 702
{
1193b4be Poul Sander 2025-02-03 21:28 703
    ImVec2 b(c.x, a.y), d(a.x, c.y), uv(_Data->TexUvWhitePixel);
1193b4be Poul Sander 2025-02-03 21:28 704
    ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx;
1193b4be Poul Sander 2025-02-03 21:28 705
    _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2);
1193b4be Poul Sander 2025-02-03 21:28 706
    _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3);
1193b4be Poul Sander 2025-02-03 21:28 707
    _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;
1193b4be Poul Sander 2025-02-03 21:28 708
    _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col;
1193b4be Poul Sander 2025-02-03 21:28 709
    _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col;
1193b4be Poul Sander 2025-02-03 21:28 710
    _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv; _VtxWritePtr[3].col = col;
1193b4be Poul Sander 2025-02-03 21:28 711
    _VtxWritePtr += 4;
1193b4be Poul Sander 2025-02-03 21:28 712
    _VtxCurrentIdx += 4;
1193b4be Poul Sander 2025-02-03 21:28 713
    _IdxWritePtr += 6;
1193b4be Poul Sander 2025-02-03 21:28 714
}
1193b4be Poul Sander 2025-02-03 21:28 715
1193b4be Poul Sander 2025-02-03 21:28 716
void ImDrawList::PrimRectUV(const ImVec2& a, const ImVec2& c, const ImVec2& uv_a, const ImVec2& uv_c, ImU32 col)
1193b4be Poul Sander 2025-02-03 21:28 717
{
1193b4be Poul Sander 2025-02-03 21:28 718
    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);
1193b4be Poul Sander 2025-02-03 21:28 719
    ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx;
1193b4be Poul Sander 2025-02-03 21:28 720
    _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2);
1193b4be Poul Sander 2025-02-03 21:28 721
    _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3);
1193b4be Poul Sander 2025-02-03 21:28 722
    _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv_a; _VtxWritePtr[0].col = col;
1193b4be Poul Sander 2025-02-03 21:28 723
    _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv_b; _VtxWritePtr[1].col = col;
1193b4be Poul Sander 2025-02-03 21:28 724
    _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv_c; _VtxWritePtr[2].col = col;
1193b4be Poul Sander 2025-02-03 21:28 725
    _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv_d; _VtxWritePtr[3].col = col;
1193b4be Poul Sander 2025-02-03 21:28 726
    _VtxWritePtr += 4;
1193b4be Poul Sander 2025-02-03 21:28 727
    _VtxCurrentIdx += 4;
1193b4be Poul Sander 2025-02-03 21:28 728
    _IdxWritePtr += 6;
1193b4be Poul Sander 2025-02-03 21:28 729
}
1193b4be Poul Sander 2025-02-03 21:28 730
1193b4be Poul Sander 2025-02-03 21:28 731
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)
1193b4be Poul Sander 2025-02-03 21:28 732
{
1193b4be Poul Sander 2025-02-03 21:28 733
    ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx;
1193b4be Poul Sander 2025-02-03 21:28 734
    _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2);
1193b4be Poul Sander 2025-02-03 21:28 735
    _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3);
1193b4be Poul Sander 2025-02-03 21:28 736
    _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv_a; _VtxWritePtr[0].col = col;
1193b4be Poul Sander 2025-02-03 21:28 737
    _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv_b; _VtxWritePtr[1].col = col;
1193b4be Poul Sander 2025-02-03 21:28 738
    _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv_c; _VtxWritePtr[2].col = col;
1193b4be Poul Sander 2025-02-03 21:28 739
    _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv_d; _VtxWritePtr[3].col = col;
1193b4be Poul Sander 2025-02-03 21:28 740
    _VtxWritePtr += 4;
1193b4be Poul Sander 2025-02-03 21:28 741
    _VtxCurrentIdx += 4;
1193b4be Poul Sander 2025-02-03 21:28 742
    _IdxWritePtr += 6;
1193b4be Poul Sander 2025-02-03 21:28 743
}
1193b4be Poul Sander 2025-02-03 21:28 744
1193b4be Poul Sander 2025-02-03 21:28 745
// On AddPolyline() and AddConvexPolyFilled() we intentionally avoid using ImVec2 and superfluous function calls to optimize debug/non-inlined builds.
1193b4be Poul Sander 2025-02-03 21:28 746
// - Those macros expects l-values and need to be used as their own statement.
1193b4be Poul Sander 2025-02-03 21:28 747
// - Those macros are intentionally not surrounded by the 'do {} while (0)' idiom because even that translates to runtime with debug compilers.
1193b4be Poul Sander 2025-02-03 21:28 748
#define IM_NORMALIZE2F_OVER_ZERO(VX,VY)     { float d2 = VX*VX + VY*VY; if (d2 > 0.0f) { float inv_len = ImRsqrt(d2); VX *= inv_len; VY *= inv_len; } } (void)0
1193b4be Poul Sander 2025-02-03 21:28 749
#define IM_FIXNORMAL2F_MAX_INVLEN2          100.0f // 500.0f (see #4053, #3366)
1193b4be Poul Sander 2025-02-03 21:28 750
#define IM_FIXNORMAL2F(VX,VY)               { float d2 = VX*VX + VY*VY; if (d2 > 0.000001f) { float inv_len2 = 1.0f / d2; if (inv_len2 > IM_FIXNORMAL2F_MAX_INVLEN2) inv_len2 = IM_FIXNORMAL2F_MAX_INVLEN2; VX *= inv_len2; VY *= inv_len2; } } (void)0
1193b4be Poul Sander 2025-02-03 21:28 751
1193b4be Poul Sander 2025-02-03 21:28 752
// TODO: Thickness anti-aliased lines cap are missing their AA fringe.
1193b4be Poul Sander 2025-02-03 21:28 753
// We avoid using the ImVec2 math operators here to reduce cost to a minimum for debug/non-inlined builds.
1193b4be Poul Sander 2025-02-03 21:28 754
void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 col, ImDrawFlags flags, float thickness)
1193b4be Poul Sander 2025-02-03 21:28 755
{
1193b4be Poul Sander 2025-02-03 21:28 756
    if (points_count < 2 || (col & IM_COL32_A_MASK) == 0)
1193b4be Poul Sander 2025-02-03 21:28 757
        return;
1193b4be Poul Sander 2025-02-03 21:28 758
1193b4be Poul Sander 2025-02-03 21:28 759
    const bool closed = (flags & ImDrawFlags_Closed) != 0;
1193b4be Poul Sander 2025-02-03 21:28 760
    const ImVec2 opaque_uv = _Data->TexUvWhitePixel;
1193b4be Poul Sander 2025-02-03 21:28 761
    const int count = closed ? points_count : points_count - 1; // The number of line segments we need to draw
1193b4be Poul Sander 2025-02-03 21:28 762
    const bool thick_line = (thickness > _FringeScale);
1193b4be Poul Sander 2025-02-03 21:28 763
1193b4be Poul Sander 2025-02-03 21:28 764
    if (Flags & ImDrawListFlags_AntiAliasedLines)
1193b4be Poul Sander 2025-02-03 21:28 765
    {
1193b4be Poul Sander 2025-02-03 21:28 766
        // Anti-aliased stroke
1193b4be Poul Sander 2025-02-03 21:28 767
        const float AA_SIZE = _FringeScale;
1193b4be Poul Sander 2025-02-03 21:28 768
        const ImU32 col_trans = col & ~IM_COL32_A_MASK;
1193b4be Poul Sander 2025-02-03 21:28 769
1193b4be Poul Sander 2025-02-03 21:28 770
        // Thicknesses <1.0 should behave like thickness 1.0
1193b4be Poul Sander 2025-02-03 21:28 771
        thickness = ImMax(thickness, 1.0f);
1193b4be Poul Sander 2025-02-03 21:28 772
        const int integer_thickness = (int)thickness;
1193b4be Poul Sander 2025-02-03 21:28 773
        const float fractional_thickness = thickness - integer_thickness;
1193b4be Poul Sander 2025-02-03 21:28 774
1193b4be Poul Sander 2025-02-03 21:28 775
        // Do we want to draw this line using a texture?
1193b4be Poul Sander 2025-02-03 21:28 776
        // - For now, only draw integer-width lines using textures to avoid issues with the way scaling occurs, could be improved.
1193b4be Poul Sander 2025-02-03 21:28 777
        // - If AA_SIZE is not 1.0f we cannot use the texture path.
1193b4be Poul Sander 2025-02-03 21:28 778
        const bool use_texture = (Flags & ImDrawListFlags_AntiAliasedLinesUseTex) && (integer_thickness < IM_DRAWLIST_TEX_LINES_WIDTH_MAX) && (fractional_thickness <= 0.00001f) && (AA_SIZE == 1.0f);
1193b4be Poul Sander 2025-02-03 21:28 779
1193b4be Poul Sander 2025-02-03 21:28 780
        // We should never hit this, because NewFrame() doesn't set ImDrawListFlags_AntiAliasedLinesUseTex unless ImFontAtlasFlags_NoBakedLines is off
1193b4be Poul Sander 2025-02-03 21:28 781
        IM_ASSERT_PARANOID(!use_texture || !(_Data->Font->ContainerAtlas->Flags & ImFontAtlasFlags_NoBakedLines));
1193b4be Poul Sander 2025-02-03 21:28 782
1193b4be Poul Sander 2025-02-03 21:28 783
        const int idx_count = use_texture ? (count * 6) : (thick_line ? count * 18 : count * 12);
1193b4be Poul Sander 2025-02-03 21:28 784
        const int vtx_count = use_texture ? (points_count * 2) : (thick_line ? points_count * 4 : points_count * 3);
1193b4be Poul Sander 2025-02-03 21:28 785
        PrimReserve(idx_count, vtx_count);
1193b4be Poul Sander 2025-02-03 21:28 786
1193b4be Poul Sander 2025-02-03 21:28 787
        // Temporary buffer
1193b4be Poul Sander 2025-02-03 21:28 788
        // 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
1193b4be Poul Sander 2025-02-03 21:28 789
        _Data->TempBuffer.reserve_discard(points_count * ((use_texture || !thick_line) ? 3 : 5));
1193b4be Poul Sander 2025-02-03 21:28 790
        ImVec2* temp_normals = _Data->TempBuffer.Data;
1193b4be Poul Sander 2025-02-03 21:28 791
        ImVec2* temp_points = temp_normals + points_count;
1193b4be Poul Sander 2025-02-03 21:28 792
1193b4be Poul Sander 2025-02-03 21:28 793
        // Calculate normals (tangents) for each line segment
1193b4be Poul Sander 2025-02-03 21:28 794
        for (int i1 = 0; i1 < count; i1++)
1193b4be Poul Sander 2025-02-03 21:28 795
        {
1193b4be Poul Sander 2025-02-03 21:28 796
            const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1;
1193b4be Poul Sander 2025-02-03 21:28 797
            float dx = points[i2].x - points[i1].x;
1193b4be Poul Sander 2025-02-03 21:28 798
            float dy = points[i2].y - points[i1].y;
1193b4be Poul Sander 2025-02-03 21:28 799
            IM_NORMALIZE2F_OVER_ZERO(dx, dy);
1193b4be Poul Sander 2025-02-03 21:28 800
            temp_normals[i1].x = dy;
1193b4be Poul Sander 2025-02-03 21:28 801
            temp_normals[i1].y = -dx;
1193b4be Poul Sander 2025-02-03 21:28 802
        }
1193b4be Poul Sander 2025-02-03 21:28 803
        if (!closed)
1193b4be Poul Sander 2025-02-03 21:28 804
            temp_normals[points_count - 1] = temp_normals[points_count - 2];
1193b4be Poul Sander 2025-02-03 21:28 805
1193b4be Poul Sander 2025-02-03 21:28 806
        // 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
1193b4be Poul Sander 2025-02-03 21:28 807
        if (use_texture || !thick_line)
1193b4be Poul Sander 2025-02-03 21:28 808
        {
1193b4be Poul Sander 2025-02-03 21:28 809
            // [PATH 1] Texture-based lines (thick or non-thick)
1193b4be Poul Sander 2025-02-03 21:28 810
            // [PATH 2] Non texture-based lines (non-thick)
1193b4be Poul Sander 2025-02-03 21:28 811
1193b4be Poul Sander 2025-02-03 21:28 812
            // The width of the geometry we need to draw - this is essentially <thickness> pixels for the line itself, plus "one pixel" for AA.
1193b4be Poul Sander 2025-02-03 21:28 813
            // - In the texture-based path, we don't use AA_SIZE here because the +1 is tied to the generated texture
1193b4be Poul Sander 2025-02-03 21:28 814
            //   (see ImFontAtlasBuildRenderLinesTexData() function), and so alternate values won't work without changes to that code.
1193b4be Poul Sander 2025-02-03 21:28 815
            // - 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
1193b4be Poul Sander 2025-02-03 21:28 816
            //   allow scaling geometry while preserving one-screen-pixel AA fringe).
1193b4be Poul Sander 2025-02-03 21:28 817
            const float half_draw_size = use_texture ? ((thickness * 0.5f) + 1) : AA_SIZE;
1193b4be Poul Sander 2025-02-03 21:28 818
1193b4be Poul Sander 2025-02-03 21:28 819
            // If line is not closed, the first and last points need to be generated differently as there are no normals to blend
1193b4be Poul Sander 2025-02-03 21:28 820
            if (!closed)
1193b4be Poul Sander 2025-02-03 21:28 821
            {
1193b4be Poul Sander 2025-02-03 21:28 822
                temp_points[0] = points[0] + temp_normals[0] * half_draw_size;
1193b4be Poul Sander 2025-02-03 21:28 823
                temp_points[1] = points[0] - temp_normals[0] * half_draw_size;
1193b4be Poul Sander 2025-02-03 21:28 824
                temp_points[(points_count-1)*2+0] = points[points_count-1] + temp_normals[points_count-1] * half_draw_size;
1193b4be Poul Sander 2025-02-03 21:28 825
                temp_points[(points_count-1)*2+1] = points[points_count-1] - temp_normals[points_count-1] * half_draw_size;
1193b4be Poul Sander 2025-02-03 21:28 826
            }
1193b4be Poul Sander 2025-02-03 21:28 827
1193b4be Poul Sander 2025-02-03 21:28 828
            // Generate the indices to form a number of triangles for each line segment, and the vertices for the line edges
1193b4be Poul Sander 2025-02-03 21:28 829
            // 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)
1193b4be Poul Sander 2025-02-03 21:28 830
            // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer.
1193b4be Poul Sander 2025-02-03 21:28 831
            unsigned int idx1 = _VtxCurrentIdx; // Vertex index for start of line segment
1193b4be Poul Sander 2025-02-03 21:28 832
            for (int i1 = 0; i1 < count; i1++) // i1 is the first point of the line segment
1193b4be Poul Sander 2025-02-03 21:28 833
            {
1193b4be Poul Sander 2025-02-03 21:28 834
                const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1; // i2 is the second point of the line segment
1193b4be Poul Sander 2025-02-03 21:28 835
                const unsigned int idx2 = ((i1 + 1) == points_count) ? _VtxCurrentIdx : (idx1 + (use_texture ? 2 : 3)); // Vertex index for end of segment
1193b4be Poul Sander 2025-02-03 21:28 836
1193b4be Poul Sander 2025-02-03 21:28 837
                // Average normals
1193b4be Poul Sander 2025-02-03 21:28 838
                float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 839
                float dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 840
                IM_FIXNORMAL2F(dm_x, dm_y);
1193b4be Poul Sander 2025-02-03 21:28 841
                dm_x *= half_draw_size; // dm_x, dm_y are offset to the outer edge of the AA area
1193b4be Poul Sander 2025-02-03 21:28 842
                dm_y *= half_draw_size;
1193b4be Poul Sander 2025-02-03 21:28 843
1193b4be Poul Sander 2025-02-03 21:28 844
                // Add temporary vertexes for the outer edges
1193b4be Poul Sander 2025-02-03 21:28 845
                ImVec2* out_vtx = &temp_points[i2 * 2];
1193b4be Poul Sander 2025-02-03 21:28 846
                out_vtx[0].x = points[i2].x + dm_x;
1193b4be Poul Sander 2025-02-03 21:28 847
                out_vtx[0].y = points[i2].y + dm_y;
1193b4be Poul Sander 2025-02-03 21:28 848
                out_vtx[1].x = points[i2].x - dm_x;
1193b4be Poul Sander 2025-02-03 21:28 849
                out_vtx[1].y = points[i2].y - dm_y;
1193b4be Poul Sander 2025-02-03 21:28 850
1193b4be Poul Sander 2025-02-03 21:28 851
                if (use_texture)
1193b4be Poul Sander 2025-02-03 21:28 852
                {
1193b4be Poul Sander 2025-02-03 21:28 853
                    // Add indices for two triangles
1193b4be Poul Sander 2025-02-03 21:28 854
                    _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 1); // Right tri
1193b4be Poul Sander 2025-02-03 21:28 855
                    _IdxWritePtr[3] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[4] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 0); // Left tri
1193b4be Poul Sander 2025-02-03 21:28 856
                    _IdxWritePtr += 6;
1193b4be Poul Sander 2025-02-03 21:28 857
                }
1193b4be Poul Sander 2025-02-03 21:28 858
                else
1193b4be Poul Sander 2025-02-03 21:28 859
                {
1193b4be Poul Sander 2025-02-03 21:28 860
                    // Add indexes for four triangles
1193b4be Poul Sander 2025-02-03 21:28 861
                    _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 2); // Right tri 1
1193b4be Poul Sander 2025-02-03 21:28 862
                    _IdxWritePtr[3] = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[4] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 0); // Right tri 2
1193b4be Poul Sander 2025-02-03 21:28 863
                    _IdxWritePtr[6] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[7] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[8] = (ImDrawIdx)(idx1 + 0); // Left tri 1
1193b4be Poul Sander 2025-02-03 21:28 864
                    _IdxWritePtr[9] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[10] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[11] = (ImDrawIdx)(idx2 + 1); // Left tri 2
1193b4be Poul Sander 2025-02-03 21:28 865
                    _IdxWritePtr += 12;
1193b4be Poul Sander 2025-02-03 21:28 866
                }
1193b4be Poul Sander 2025-02-03 21:28 867
1193b4be Poul Sander 2025-02-03 21:28 868
                idx1 = idx2;
1193b4be Poul Sander 2025-02-03 21:28 869
            }
1193b4be Poul Sander 2025-02-03 21:28 870
1193b4be Poul Sander 2025-02-03 21:28 871
            // Add vertexes for each point on the line
1193b4be Poul Sander 2025-02-03 21:28 872
            if (use_texture)
1193b4be Poul Sander 2025-02-03 21:28 873
            {
1193b4be Poul Sander 2025-02-03 21:28 874
                // If we're using textures we only need to emit the left/right edge vertices
1193b4be Poul Sander 2025-02-03 21:28 875
                ImVec4 tex_uvs = _Data->TexUvLines[integer_thickness];
1193b4be Poul Sander 2025-02-03 21:28 876
                /*if (fractional_thickness != 0.0f) // Currently always zero when use_texture==false!
1193b4be Poul Sander 2025-02-03 21:28 877
                {
1193b4be Poul Sander 2025-02-03 21:28 878
                    const ImVec4 tex_uvs_1 = _Data->TexUvLines[integer_thickness + 1];
1193b4be Poul Sander 2025-02-03 21:28 879
                    tex_uvs.x = tex_uvs.x + (tex_uvs_1.x - tex_uvs.x) * fractional_thickness; // inlined ImLerp()
1193b4be Poul Sander 2025-02-03 21:28 880
                    tex_uvs.y = tex_uvs.y + (tex_uvs_1.y - tex_uvs.y) * fractional_thickness;
1193b4be Poul Sander 2025-02-03 21:28 881
                    tex_uvs.z = tex_uvs.z + (tex_uvs_1.z - tex_uvs.z) * fractional_thickness;
1193b4be Poul Sander 2025-02-03 21:28 882
                    tex_uvs.w = tex_uvs.w + (tex_uvs_1.w - tex_uvs.w) * fractional_thickness;
1193b4be Poul Sander 2025-02-03 21:28 883
                }*/
1193b4be Poul Sander 2025-02-03 21:28 884
                ImVec2 tex_uv0(tex_uvs.x, tex_uvs.y);
1193b4be Poul Sander 2025-02-03 21:28 885
                ImVec2 tex_uv1(tex_uvs.z, tex_uvs.w);
1193b4be Poul Sander 2025-02-03 21:28 886
                for (int i = 0; i < points_count; i++)
1193b4be Poul Sander 2025-02-03 21:28 887
                {
1193b4be Poul Sander 2025-02-03 21:28 888
                    _VtxWritePtr[0].pos = temp_points[i * 2 + 0]; _VtxWritePtr[0].uv = tex_uv0; _VtxWritePtr[0].col = col; // Left-side outer edge
1193b4be Poul Sander 2025-02-03 21:28 889
                    _VtxWritePtr[1].pos = temp_points[i * 2 + 1]; _VtxWritePtr[1].uv = tex_uv1; _VtxWritePtr[1].col = col; // Right-side outer edge
1193b4be Poul Sander 2025-02-03 21:28 890
                    _VtxWritePtr += 2;
1193b4be Poul Sander 2025-02-03 21:28 891
                }
1193b4be Poul Sander 2025-02-03 21:28 892
            }
1193b4be Poul Sander 2025-02-03 21:28 893
            else
1193b4be Poul Sander 2025-02-03 21:28 894
            {
1193b4be Poul Sander 2025-02-03 21:28 895
                // If we're not using a texture, we need the center vertex as well
1193b4be Poul Sander 2025-02-03 21:28 896
                for (int i = 0; i < points_count; i++)
1193b4be Poul Sander 2025-02-03 21:28 897
                {
1193b4be Poul Sander 2025-02-03 21:28 898
                    _VtxWritePtr[0].pos = points[i];              _VtxWritePtr[0].uv = opaque_uv; _VtxWritePtr[0].col = col;       // Center of line
1193b4be Poul Sander 2025-02-03 21:28 899
                    _VtxWritePtr[1].pos = temp_points[i * 2 + 0]; _VtxWritePtr[1].uv = opaque_uv; _VtxWritePtr[1].col = col_trans; // Left-side outer edge
1193b4be Poul Sander 2025-02-03 21:28 900
                    _VtxWritePtr[2].pos = temp_points[i * 2 + 1]; _VtxWritePtr[2].uv = opaque_uv; _VtxWritePtr[2].col = col_trans; // Right-side outer edge
1193b4be Poul Sander 2025-02-03 21:28 901
                    _VtxWritePtr += 3;
1193b4be Poul Sander 2025-02-03 21:28 902
                }
1193b4be Poul Sander 2025-02-03 21:28 903
            }
1193b4be Poul Sander 2025-02-03 21:28 904
        }
1193b4be Poul Sander 2025-02-03 21:28 905
        else
1193b4be Poul Sander 2025-02-03 21:28 906
        {
1193b4be Poul Sander 2025-02-03 21:28 907
            // [PATH 2] Non texture-based lines (thick): we need to draw the solid line core and thus require four vertices per point
1193b4be Poul Sander 2025-02-03 21:28 908
            const float half_inner_thickness = (thickness - AA_SIZE) * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 909
1193b4be Poul Sander 2025-02-03 21:28 910
            // If line is not closed, the first and last points need to be generated differently as there are no normals to blend
1193b4be Poul Sander 2025-02-03 21:28 911
            if (!closed)
1193b4be Poul Sander 2025-02-03 21:28 912
            {
1193b4be Poul Sander 2025-02-03 21:28 913
                const int points_last = points_count - 1;
1193b4be Poul Sander 2025-02-03 21:28 914
                temp_points[0] = points[0] + temp_normals[0] * (half_inner_thickness + AA_SIZE);
1193b4be Poul Sander 2025-02-03 21:28 915
                temp_points[1] = points[0] + temp_normals[0] * (half_inner_thickness);
1193b4be Poul Sander 2025-02-03 21:28 916
                temp_points[2] = points[0] - temp_normals[0] * (half_inner_thickness);
1193b4be Poul Sander 2025-02-03 21:28 917
                temp_points[3] = points[0] - temp_normals[0] * (half_inner_thickness + AA_SIZE);
1193b4be Poul Sander 2025-02-03 21:28 918
                temp_points[points_last * 4 + 0] = points[points_last] + temp_normals[points_last] * (half_inner_thickness + AA_SIZE);
1193b4be Poul Sander 2025-02-03 21:28 919
                temp_points[points_last * 4 + 1] = points[points_last] + temp_normals[points_last] * (half_inner_thickness);
1193b4be Poul Sander 2025-02-03 21:28 920
                temp_points[points_last * 4 + 2] = points[points_last] - temp_normals[points_last] * (half_inner_thickness);
1193b4be Poul Sander 2025-02-03 21:28 921
                temp_points[points_last * 4 + 3] = points[points_last] - temp_normals[points_last] * (half_inner_thickness + AA_SIZE);
1193b4be Poul Sander 2025-02-03 21:28 922
            }
1193b4be Poul Sander 2025-02-03 21:28 923
1193b4be Poul Sander 2025-02-03 21:28 924
            // Generate the indices to form a number of triangles for each line segment, and the vertices for the line edges
1193b4be Poul Sander 2025-02-03 21:28 925
            // 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)
1193b4be Poul Sander 2025-02-03 21:28 926
            // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer.
1193b4be Poul Sander 2025-02-03 21:28 927
            unsigned int idx1 = _VtxCurrentIdx; // Vertex index for start of line segment
1193b4be Poul Sander 2025-02-03 21:28 928
            for (int i1 = 0; i1 < count; i1++) // i1 is the first point of the line segment
1193b4be Poul Sander 2025-02-03 21:28 929
            {
1193b4be Poul Sander 2025-02-03 21:28 930
                const int i2 = (i1 + 1) == points_count ? 0 : (i1 + 1); // i2 is the second point of the line segment
1193b4be Poul Sander 2025-02-03 21:28 931
                const unsigned int idx2 = (i1 + 1) == points_count ? _VtxCurrentIdx : (idx1 + 4); // Vertex index for end of segment
1193b4be Poul Sander 2025-02-03 21:28 932
1193b4be Poul Sander 2025-02-03 21:28 933
                // Average normals
1193b4be Poul Sander 2025-02-03 21:28 934
                float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 935
                float dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 936
                IM_FIXNORMAL2F(dm_x, dm_y);
1193b4be Poul Sander 2025-02-03 21:28 937
                float dm_out_x = dm_x * (half_inner_thickness + AA_SIZE);
1193b4be Poul Sander 2025-02-03 21:28 938
                float dm_out_y = dm_y * (half_inner_thickness + AA_SIZE);
1193b4be Poul Sander 2025-02-03 21:28 939
                float dm_in_x = dm_x * half_inner_thickness;
1193b4be Poul Sander 2025-02-03 21:28 940
                float dm_in_y = dm_y * half_inner_thickness;
1193b4be Poul Sander 2025-02-03 21:28 941
1193b4be Poul Sander 2025-02-03 21:28 942
                // Add temporary vertices
1193b4be Poul Sander 2025-02-03 21:28 943
                ImVec2* out_vtx = &temp_points[i2 * 4];
1193b4be Poul Sander 2025-02-03 21:28 944
                out_vtx[0].x = points[i2].x + dm_out_x;
1193b4be Poul Sander 2025-02-03 21:28 945
                out_vtx[0].y = points[i2].y + dm_out_y;
1193b4be Poul Sander 2025-02-03 21:28 946
                out_vtx[1].x = points[i2].x + dm_in_x;
1193b4be Poul Sander 2025-02-03 21:28 947
                out_vtx[1].y = points[i2].y + dm_in_y;
1193b4be Poul Sander 2025-02-03 21:28 948
                out_vtx[2].x = points[i2].x - dm_in_x;
1193b4be Poul Sander 2025-02-03 21:28 949
                out_vtx[2].y = points[i2].y - dm_in_y;
1193b4be Poul Sander 2025-02-03 21:28 950
                out_vtx[3].x = points[i2].x - dm_out_x;
1193b4be Poul Sander 2025-02-03 21:28 951
                out_vtx[3].y = points[i2].y - dm_out_y;
1193b4be Poul Sander 2025-02-03 21:28 952
1193b4be Poul Sander 2025-02-03 21:28 953
                // Add indexes
1193b4be Poul Sander 2025-02-03 21:28 954
                _IdxWritePtr[0]  = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[1]  = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[2]  = (ImDrawIdx)(idx1 + 2);
1193b4be Poul Sander 2025-02-03 21:28 955
                _IdxWritePtr[3]  = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[4]  = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[5]  = (ImDrawIdx)(idx2 + 1);
1193b4be Poul Sander 2025-02-03 21:28 956
                _IdxWritePtr[6]  = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[7]  = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[8]  = (ImDrawIdx)(idx1 + 0);
1193b4be Poul Sander 2025-02-03 21:28 957
                _IdxWritePtr[9]  = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[10] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[11] = (ImDrawIdx)(idx2 + 1);
1193b4be Poul Sander 2025-02-03 21:28 958
                _IdxWritePtr[12] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[13] = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[14] = (ImDrawIdx)(idx1 + 3);
1193b4be Poul Sander 2025-02-03 21:28 959
                _IdxWritePtr[15] = (ImDrawIdx)(idx1 + 3); _IdxWritePtr[16] = (ImDrawIdx)(idx2 + 3); _IdxWritePtr[17] = (ImDrawIdx)(idx2 + 2);
1193b4be Poul Sander 2025-02-03 21:28 960
                _IdxWritePtr += 18;
1193b4be Poul Sander 2025-02-03 21:28 961
1193b4be Poul Sander 2025-02-03 21:28 962
                idx1 = idx2;
1193b4be Poul Sander 2025-02-03 21:28 963
            }
1193b4be Poul Sander 2025-02-03 21:28 964
1193b4be Poul Sander 2025-02-03 21:28 965
            // Add vertices
1193b4be Poul Sander 2025-02-03 21:28 966
            for (int i = 0; i < points_count; i++)
1193b4be Poul Sander 2025-02-03 21:28 967
            {
1193b4be Poul Sander 2025-02-03 21:28 968
                _VtxWritePtr[0].pos = temp_points[i * 4 + 0]; _VtxWritePtr[0].uv = opaque_uv; _VtxWritePtr[0].col = col_trans;
1193b4be Poul Sander 2025-02-03 21:28 969
                _VtxWritePtr[1].pos = temp_points[i * 4 + 1]; _VtxWritePtr[1].uv = opaque_uv; _VtxWritePtr[1].col = col;
1193b4be Poul Sander 2025-02-03 21:28 970
                _VtxWritePtr[2].pos = temp_points[i * 4 + 2]; _VtxWritePtr[2].uv = opaque_uv; _VtxWritePtr[2].col = col;
1193b4be Poul Sander 2025-02-03 21:28 971
                _VtxWritePtr[3].pos = temp_points[i * 4 + 3]; _VtxWritePtr[3].uv = opaque_uv; _VtxWritePtr[3].col = col_trans;
1193b4be Poul Sander 2025-02-03 21:28 972
                _VtxWritePtr += 4;
1193b4be Poul Sander 2025-02-03 21:28 973
            }
1193b4be Poul Sander 2025-02-03 21:28 974
        }
1193b4be Poul Sander 2025-02-03 21:28 975
        _VtxCurrentIdx += (ImDrawIdx)vtx_count;
1193b4be Poul Sander 2025-02-03 21:28 976
    }
1193b4be Poul Sander 2025-02-03 21:28 977
    else
1193b4be Poul Sander 2025-02-03 21:28 978
    {
1193b4be Poul Sander 2025-02-03 21:28 979
        // [PATH 4] Non texture-based, Non anti-aliased lines
1193b4be Poul Sander 2025-02-03 21:28 980
        const int idx_count = count * 6;
1193b4be Poul Sander 2025-02-03 21:28 981
        const int vtx_count = count * 4;    // FIXME-OPT: Not sharing edges
1193b4be Poul Sander 2025-02-03 21:28 982
        PrimReserve(idx_count, vtx_count);
1193b4be Poul Sander 2025-02-03 21:28 983
1193b4be Poul Sander 2025-02-03 21:28 984
        for (int i1 = 0; i1 < count; i1++)
1193b4be Poul Sander 2025-02-03 21:28 985
        {
1193b4be Poul Sander 2025-02-03 21:28 986
            const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1;
1193b4be Poul Sander 2025-02-03 21:28 987
            const ImVec2& p1 = points[i1];
1193b4be Poul Sander 2025-02-03 21:28 988
            const ImVec2& p2 = points[i2];
1193b4be Poul Sander 2025-02-03 21:28 989
1193b4be Poul Sander 2025-02-03 21:28 990
            float dx = p2.x - p1.x;
1193b4be Poul Sander 2025-02-03 21:28 991
            float dy = p2.y - p1.y;
1193b4be Poul Sander 2025-02-03 21:28 992
            IM_NORMALIZE2F_OVER_ZERO(dx, dy);
1193b4be Poul Sander 2025-02-03 21:28 993
            dx *= (thickness * 0.5f);
1193b4be Poul Sander 2025-02-03 21:28 994
            dy *= (thickness * 0.5f);
1193b4be Poul Sander 2025-02-03 21:28 995
1193b4be Poul Sander 2025-02-03 21:28 996
            _VtxWritePtr[0].pos.x = p1.x + dy; _VtxWritePtr[0].pos.y = p1.y - dx; _VtxWritePtr[0].uv = opaque_uv; _VtxWritePtr[0].col = col;
1193b4be Poul Sander 2025-02-03 21:28 997
            _VtxWritePtr[1].pos.x = p2.x + dy; _VtxWritePtr[1].pos.y = p2.y - dx; _VtxWritePtr[1].uv = opaque_uv; _VtxWritePtr[1].col = col;
1193b4be Poul Sander 2025-02-03 21:28 998
            _VtxWritePtr[2].pos.x = p2.x - dy; _VtxWritePtr[2].pos.y = p2.y + dx; _VtxWritePtr[2].uv = opaque_uv; _VtxWritePtr[2].col = col;
1193b4be Poul Sander 2025-02-03 21:28 999
            _VtxWritePtr[3].pos.x = p1.x - dy; _VtxWritePtr[3].pos.y = p1.y + dx; _VtxWritePtr[3].uv = opaque_uv; _VtxWritePtr[3].col = col;
1193b4be Poul Sander 2025-02-03 21:28 1000
            _VtxWritePtr += 4;
1193b4be Poul Sander 2025-02-03 21:28 1001
1193b4be Poul Sander 2025-02-03 21:28 1002
            _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx + 1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx + 2);
1193b4be Poul Sander 2025-02-03 21:28 1003
            _IdxWritePtr[3] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[4] = (ImDrawIdx)(_VtxCurrentIdx + 2); _IdxWritePtr[5] = (ImDrawIdx)(_VtxCurrentIdx + 3);
1193b4be Poul Sander 2025-02-03 21:28 1004
            _IdxWritePtr += 6;
1193b4be Poul Sander 2025-02-03 21:28 1005
            _VtxCurrentIdx += 4;
1193b4be Poul Sander 2025-02-03 21:28 1006
        }
1193b4be Poul Sander 2025-02-03 21:28 1007
    }
1193b4be Poul Sander 2025-02-03 21:28 1008
}
1193b4be Poul Sander 2025-02-03 21:28 1009
1193b4be Poul Sander 2025-02-03 21:28 1010
// - We intentionally avoid using ImVec2 and its math operators here to reduce cost to a minimum for debug/non-inlined builds.
1193b4be Poul Sander 2025-02-03 21:28 1011
// - Filled shapes must always use clockwise winding order. The anti-aliasing fringe depends on it. Counter-clockwise shapes will have "inward" anti-aliasing.
1193b4be Poul Sander 2025-02-03 21:28 1012
void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_count, ImU32 col)
1193b4be Poul Sander 2025-02-03 21:28 1013
{
1193b4be Poul Sander 2025-02-03 21:28 1014
    if (points_count < 3 || (col & IM_COL32_A_MASK) == 0)
1193b4be Poul Sander 2025-02-03 21:28 1015
        return;
1193b4be Poul Sander 2025-02-03 21:28 1016
1193b4be Poul Sander 2025-02-03 21:28 1017
    const ImVec2 uv = _Data->TexUvWhitePixel;
1193b4be Poul Sander 2025-02-03 21:28 1018
1193b4be Poul Sander 2025-02-03 21:28 1019
    if (Flags & ImDrawListFlags_AntiAliasedFill)
1193b4be Poul Sander 2025-02-03 21:28 1020
    {
1193b4be Poul Sander 2025-02-03 21:28 1021
        // Anti-aliased Fill
1193b4be Poul Sander 2025-02-03 21:28 1022
        const float AA_SIZE = _FringeScale;
1193b4be Poul Sander 2025-02-03 21:28 1023
        const ImU32 col_trans = col & ~IM_COL32_A_MASK;
1193b4be Poul Sander 2025-02-03 21:28 1024
        const int idx_count = (points_count - 2)*3 + points_count * 6;
1193b4be Poul Sander 2025-02-03 21:28 1025
        const int vtx_count = (points_count * 2);
1193b4be Poul Sander 2025-02-03 21:28 1026
        PrimReserve(idx_count, vtx_count);
1193b4be Poul Sander 2025-02-03 21:28 1027
1193b4be Poul Sander 2025-02-03 21:28 1028
        // Add indexes for fill
1193b4be Poul Sander 2025-02-03 21:28 1029
        unsigned int vtx_inner_idx = _VtxCurrentIdx;
1193b4be Poul Sander 2025-02-03 21:28 1030
        unsigned int vtx_outer_idx = _VtxCurrentIdx + 1;
1193b4be Poul Sander 2025-02-03 21:28 1031
        for (int i = 2; i < points_count; i++)
1193b4be Poul Sander 2025-02-03 21:28 1032
        {
1193b4be Poul Sander 2025-02-03 21:28 1033
            _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + ((i - 1) << 1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_inner_idx + (i << 1));
1193b4be Poul Sander 2025-02-03 21:28 1034
            _IdxWritePtr += 3;
1193b4be Poul Sander 2025-02-03 21:28 1035
        }
1193b4be Poul Sander 2025-02-03 21:28 1036
1193b4be Poul Sander 2025-02-03 21:28 1037
        // Compute normals
1193b4be Poul Sander 2025-02-03 21:28 1038
        _Data->TempBuffer.reserve_discard(points_count);
1193b4be Poul Sander 2025-02-03 21:28 1039
        ImVec2* temp_normals = _Data->TempBuffer.Data;
1193b4be Poul Sander 2025-02-03 21:28 1040
        for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++)
1193b4be Poul Sander 2025-02-03 21:28 1041
        {
1193b4be Poul Sander 2025-02-03 21:28 1042
            const ImVec2& p0 = points[i0];
1193b4be Poul Sander 2025-02-03 21:28 1043
            const ImVec2& p1 = points[i1];
1193b4be Poul Sander 2025-02-03 21:28 1044
            float dx = p1.x - p0.x;
1193b4be Poul Sander 2025-02-03 21:28 1045
            float dy = p1.y - p0.y;
1193b4be Poul Sander 2025-02-03 21:28 1046
            IM_NORMALIZE2F_OVER_ZERO(dx, dy);
1193b4be Poul Sander 2025-02-03 21:28 1047
            temp_normals[i0].x = dy;
1193b4be Poul Sander 2025-02-03 21:28 1048
            temp_normals[i0].y = -dx;
1193b4be Poul Sander 2025-02-03 21:28 1049
        }
1193b4be Poul Sander 2025-02-03 21:28 1050
1193b4be Poul Sander 2025-02-03 21:28 1051
        for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++)
1193b4be Poul Sander 2025-02-03 21:28 1052
        {
1193b4be Poul Sander 2025-02-03 21:28 1053
            // Average normals
1193b4be Poul Sander 2025-02-03 21:28 1054
            const ImVec2& n0 = temp_normals[i0];
1193b4be Poul Sander 2025-02-03 21:28 1055
            const ImVec2& n1 = temp_normals[i1];
1193b4be Poul Sander 2025-02-03 21:28 1056
            float dm_x = (n0.x + n1.x) * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 1057
            float dm_y = (n0.y + n1.y) * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 1058
            IM_FIXNORMAL2F(dm_x, dm_y);
1193b4be Poul Sander 2025-02-03 21:28 1059
            dm_x *= AA_SIZE * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 1060
            dm_y *= AA_SIZE * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 1061
1193b4be Poul Sander 2025-02-03 21:28 1062
            // Add vertices
1193b4be Poul Sander 2025-02-03 21:28 1063
            _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
1193b4be Poul Sander 2025-02-03 21:28 1064
            _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
1193b4be Poul Sander 2025-02-03 21:28 1065
            _VtxWritePtr += 2;
1193b4be Poul Sander 2025-02-03 21:28 1066
1193b4be Poul Sander 2025-02-03 21:28 1067
            // Add indexes for fringes
1193b4be Poul Sander 2025-02-03 21:28 1068
            _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1)); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + (i0 << 1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1));
1193b4be Poul Sander 2025-02-03 21:28 1069
            _IdxWritePtr[3] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1)); _IdxWritePtr[4] = (ImDrawIdx)(vtx_outer_idx + (i1 << 1)); _IdxWritePtr[5] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1));
1193b4be Poul Sander 2025-02-03 21:28 1070
            _IdxWritePtr += 6;
1193b4be Poul Sander 2025-02-03 21:28 1071
        }
1193b4be Poul Sander 2025-02-03 21:28 1072
        _VtxCurrentIdx += (ImDrawIdx)vtx_count;
1193b4be Poul Sander 2025-02-03 21:28 1073
    }
1193b4be Poul Sander 2025-02-03 21:28 1074
    else
1193b4be Poul Sander 2025-02-03 21:28 1075
    {
1193b4be Poul Sander 2025-02-03 21:28 1076
        // Non Anti-aliased Fill
1193b4be Poul Sander 2025-02-03 21:28 1077
        const int idx_count = (points_count - 2)*3;
1193b4be Poul Sander 2025-02-03 21:28 1078
        const int vtx_count = points_count;
1193b4be Poul Sander 2025-02-03 21:28 1079
        PrimReserve(idx_count, vtx_count);
1193b4be Poul Sander 2025-02-03 21:28 1080
        for (int i = 0; i < vtx_count; i++)
1193b4be Poul Sander 2025-02-03 21:28 1081
        {
1193b4be Poul Sander 2025-02-03 21:28 1082
            _VtxWritePtr[0].pos = points[i]; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;
1193b4be Poul Sander 2025-02-03 21:28 1083
            _VtxWritePtr++;
1193b4be Poul Sander 2025-02-03 21:28 1084
        }
1193b4be Poul Sander 2025-02-03 21:28 1085
        for (int i = 2; i < points_count; i++)
1193b4be Poul Sander 2025-02-03 21:28 1086
        {
1193b4be Poul Sander 2025-02-03 21:28 1087
            _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx + i - 1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx + i);
1193b4be Poul Sander 2025-02-03 21:28 1088
            _IdxWritePtr += 3;
1193b4be Poul Sander 2025-02-03 21:28 1089
        }
1193b4be Poul Sander 2025-02-03 21:28 1090
        _VtxCurrentIdx += (ImDrawIdx)vtx_count;
1193b4be Poul Sander 2025-02-03 21:28 1091
    }
1193b4be Poul Sander 2025-02-03 21:28 1092
}
1193b4be Poul Sander 2025-02-03 21:28 1093
1193b4be Poul Sander 2025-02-03 21:28 1094
void ImDrawList::_PathArcToFastEx(const ImVec2& center, float radius, int a_min_sample, int a_max_sample, int a_step)
1193b4be Poul Sander 2025-02-03 21:28 1095
{
1193b4be Poul Sander 2025-02-03 21:28 1096
    if (radius < 0.5f)
1193b4be Poul Sander 2025-02-03 21:28 1097
    {
1193b4be Poul Sander 2025-02-03 21:28 1098
        _Path.push_back(center);
1193b4be Poul Sander 2025-02-03 21:28 1099
        return;
1193b4be Poul Sander 2025-02-03 21:28 1100
    }
1193b4be Poul Sander 2025-02-03 21:28 1101
1193b4be Poul Sander 2025-02-03 21:28 1102
    // Calculate arc auto segment step size
1193b4be Poul Sander 2025-02-03 21:28 1103
    if (a_step <= 0)
1193b4be Poul Sander 2025-02-03 21:28 1104
        a_step = IM_DRAWLIST_ARCFAST_SAMPLE_MAX / _CalcCircleAutoSegmentCount(radius);
1193b4be Poul Sander 2025-02-03 21:28 1105
1193b4be Poul Sander 2025-02-03 21:28 1106
    // Make sure we never do steps larger than one quarter of the circle
1193b4be Poul Sander 2025-02-03 21:28 1107
    a_step = ImClamp(a_step, 1, IM_DRAWLIST_ARCFAST_TABLE_SIZE / 4);
1193b4be Poul Sander 2025-02-03 21:28 1108
1193b4be Poul Sander 2025-02-03 21:28 1109
    const int sample_range = ImAbs(a_max_sample - a_min_sample);
1193b4be Poul Sander 2025-02-03 21:28 1110
    const int a_next_step = a_step;
1193b4be Poul Sander 2025-02-03 21:28 1111
1193b4be Poul Sander 2025-02-03 21:28 1112
    int samples = sample_range + 1;
1193b4be Poul Sander 2025-02-03 21:28 1113
    bool extra_max_sample = false;
1193b4be Poul Sander 2025-02-03 21:28 1114
    if (a_step > 1)
1193b4be Poul Sander 2025-02-03 21:28 1115
    {
1193b4be Poul Sander 2025-02-03 21:28 1116
        samples            = sample_range / a_step + 1;
1193b4be Poul Sander 2025-02-03 21:28 1117
        const int overstep = sample_range % a_step;
1193b4be Poul Sander 2025-02-03 21:28 1118
1193b4be Poul Sander 2025-02-03 21:28 1119
        if (overstep > 0)
1193b4be Poul Sander 2025-02-03 21:28 1120
        {
1193b4be Poul Sander 2025-02-03 21:28 1121
            extra_max_sample = true;
1193b4be Poul Sander 2025-02-03 21:28 1122
            samples++;
1193b4be Poul Sander 2025-02-03 21:28 1123
1193b4be Poul Sander 2025-02-03 21:28 1124
            // When we have overstep to avoid awkwardly looking one long line and one tiny one at the end,
1193b4be Poul Sander 2025-02-03 21:28 1125
            // distribute first step range evenly between them by reducing first step size.
1193b4be Poul Sander 2025-02-03 21:28 1126
            if (sample_range > 0)
1193b4be Poul Sander 2025-02-03 21:28 1127
                a_step -= (a_step - overstep) / 2;
1193b4be Poul Sander 2025-02-03 21:28 1128
        }
1193b4be Poul Sander 2025-02-03 21:28 1129
    }
1193b4be Poul Sander 2025-02-03 21:28 1130
1193b4be Poul Sander 2025-02-03 21:28 1131
    _Path.resize(_Path.Size + samples);
1193b4be Poul Sander 2025-02-03 21:28 1132
    ImVec2* out_ptr = _Path.Data + (_Path.Size - samples);
1193b4be Poul Sander 2025-02-03 21:28 1133
1193b4be Poul Sander 2025-02-03 21:28 1134
    int sample_index = a_min_sample;
1193b4be Poul Sander 2025-02-03 21:28 1135
    if (sample_index < 0 || sample_index >= IM_DRAWLIST_ARCFAST_SAMPLE_MAX)
1193b4be Poul Sander 2025-02-03 21:28 1136
    {
1193b4be Poul Sander 2025-02-03 21:28 1137
        sample_index = sample_index % IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
1193b4be Poul Sander 2025-02-03 21:28 1138
        if (sample_index < 0)
1193b4be Poul Sander 2025-02-03 21:28 1139
            sample_index += IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
1193b4be Poul Sander 2025-02-03 21:28 1140
    }
1193b4be Poul Sander 2025-02-03 21:28 1141
1193b4be Poul Sander 2025-02-03 21:28 1142
    if (a_max_sample >= a_min_sample)
1193b4be Poul Sander 2025-02-03 21:28 1143
    {
1193b4be Poul Sander 2025-02-03 21:28 1144
        for (int a = a_min_sample; a <= a_max_sample; a += a_step, sample_index += a_step, a_step = a_next_step)
1193b4be Poul Sander 2025-02-03 21:28 1145
        {
1193b4be Poul Sander 2025-02-03 21:28 1146
            // a_step is clamped to IM_DRAWLIST_ARCFAST_SAMPLE_MAX, so we have guaranteed that it will not wrap over range twice or more
1193b4be Poul Sander 2025-02-03 21:28 1147
            if (sample_index >= IM_DRAWLIST_ARCFAST_SAMPLE_MAX)
1193b4be Poul Sander 2025-02-03 21:28 1148
                sample_index -= IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
1193b4be Poul Sander 2025-02-03 21:28 1149
1193b4be Poul Sander 2025-02-03 21:28 1150
            const ImVec2 s = _Data->ArcFastVtx[sample_index];
1193b4be Poul Sander 2025-02-03 21:28 1151
            out_ptr->x = center.x + s.x * radius;
1193b4be Poul Sander 2025-02-03 21:28 1152
            out_ptr->y = center.y + s.y * radius;
1193b4be Poul Sander 2025-02-03 21:28 1153
            out_ptr++;
1193b4be Poul Sander 2025-02-03 21:28 1154
        }
1193b4be Poul Sander 2025-02-03 21:28 1155
    }
1193b4be Poul Sander 2025-02-03 21:28 1156
    else
1193b4be Poul Sander 2025-02-03 21:28 1157
    {
1193b4be Poul Sander 2025-02-03 21:28 1158
        for (int a = a_min_sample; a >= a_max_sample; a -= a_step, sample_index -= a_step, a_step = a_next_step)
1193b4be Poul Sander 2025-02-03 21:28 1159
        {
1193b4be Poul Sander 2025-02-03 21:28 1160
            // a_step is clamped to IM_DRAWLIST_ARCFAST_SAMPLE_MAX, so we have guaranteed that it will not wrap over range twice or more
1193b4be Poul Sander 2025-02-03 21:28 1161
            if (sample_index < 0)
1193b4be Poul Sander 2025-02-03 21:28 1162
                sample_index += IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
1193b4be Poul Sander 2025-02-03 21:28 1163
1193b4be Poul Sander 2025-02-03 21:28 1164
            const ImVec2 s = _Data->ArcFastVtx[sample_index];
1193b4be Poul Sander 2025-02-03 21:28 1165
            out_ptr->x = center.x + s.x * radius;
1193b4be Poul Sander 2025-02-03 21:28 1166
            out_ptr->y = center.y + s.y * radius;
1193b4be Poul Sander 2025-02-03 21:28 1167
            out_ptr++;
1193b4be Poul Sander 2025-02-03 21:28 1168
        }
1193b4be Poul Sander 2025-02-03 21:28 1169
    }
1193b4be Poul Sander 2025-02-03 21:28 1170
1193b4be Poul Sander 2025-02-03 21:28 1171
    if (extra_max_sample)
1193b4be Poul Sander 2025-02-03 21:28 1172
    {
1193b4be Poul Sander 2025-02-03 21:28 1173
        int normalized_max_sample = a_max_sample % IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
1193b4be Poul Sander 2025-02-03 21:28 1174
        if (normalized_max_sample < 0)
1193b4be Poul Sander 2025-02-03 21:28 1175
            normalized_max_sample += IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
1193b4be Poul Sander 2025-02-03 21:28 1176
1193b4be Poul Sander 2025-02-03 21:28 1177
        const ImVec2 s = _Data->ArcFastVtx[normalized_max_sample];
1193b4be Poul Sander 2025-02-03 21:28 1178
        out_ptr->x = center.x + s.x * radius;
1193b4be Poul Sander 2025-02-03 21:28 1179
        out_ptr->y = center.y + s.y * radius;
1193b4be Poul Sander 2025-02-03 21:28 1180
        out_ptr++;
1193b4be Poul Sander 2025-02-03 21:28 1181
    }
1193b4be Poul Sander 2025-02-03 21:28 1182
1193b4be Poul Sander 2025-02-03 21:28 1183
    IM_ASSERT_PARANOID(_Path.Data + _Path.Size == out_ptr);
1193b4be Poul Sander 2025-02-03 21:28 1184
}
1193b4be Poul Sander 2025-02-03 21:28 1185
1193b4be Poul Sander 2025-02-03 21:28 1186
void ImDrawList::_PathArcToN(const ImVec2& center, float radius, float a_min, float a_max, int num_segments)
1193b4be Poul Sander 2025-02-03 21:28 1187
{
1193b4be Poul Sander 2025-02-03 21:28 1188
    if (radius < 0.5f)
1193b4be Poul Sander 2025-02-03 21:28 1189
    {
1193b4be Poul Sander 2025-02-03 21:28 1190
        _Path.push_back(center);
1193b4be Poul Sander 2025-02-03 21:28 1191
        return;
1193b4be Poul Sander 2025-02-03 21:28 1192
    }
1193b4be Poul Sander 2025-02-03 21:28 1193
1193b4be Poul Sander 2025-02-03 21:28 1194
    // Note that we are adding a point at both a_min and a_max.
1193b4be Poul Sander 2025-02-03 21:28 1195
    // If you are trying to draw a full closed circle you don't want the overlapping points!
1193b4be Poul Sander 2025-02-03 21:28 1196
    _Path.reserve(_Path.Size + (num_segments + 1));
1193b4be Poul Sander 2025-02-03 21:28 1197
    for (int i = 0; i <= num_segments; i++)
1193b4be Poul Sander 2025-02-03 21:28 1198
    {
1193b4be Poul Sander 2025-02-03 21:28 1199
        const float a = a_min + ((float)i / (float)num_segments) * (a_max - a_min);
1193b4be Poul Sander 2025-02-03 21:28 1200
        _Path.push_back(ImVec2(center.x + ImCos(a) * radius, center.y + ImSin(a) * radius));
1193b4be Poul Sander 2025-02-03 21:28 1201
    }
1193b4be Poul Sander 2025-02-03 21:28 1202
}
1193b4be Poul Sander 2025-02-03 21:28 1203
1193b4be Poul Sander 2025-02-03 21:28 1204
// 0: East, 3: South, 6: West, 9: North, 12: East
1193b4be Poul Sander 2025-02-03 21:28 1205
void ImDrawList::PathArcToFast(const ImVec2& center, float radius, int a_min_of_12, int a_max_of_12)
1193b4be Poul Sander 2025-02-03 21:28 1206
{
1193b4be Poul Sander 2025-02-03 21:28 1207
    if (radius < 0.5f)
1193b4be Poul Sander 2025-02-03 21:28 1208
    {
1193b4be Poul Sander 2025-02-03 21:28 1209
        _Path.push_back(center);
1193b4be Poul Sander 2025-02-03 21:28 1210
        return;
1193b4be Poul Sander 2025-02-03 21:28 1211
    }
1193b4be Poul Sander 2025-02-03 21:28 1212
    _PathArcToFastEx(center, radius, a_min_of_12 * IM_DRAWLIST_ARCFAST_SAMPLE_MAX / 12, a_max_of_12 * IM_DRAWLIST_ARCFAST_SAMPLE_MAX / 12, 0);
1193b4be Poul Sander 2025-02-03 21:28 1213
}
1193b4be Poul Sander 2025-02-03 21:28 1214
1193b4be Poul Sander 2025-02-03 21:28 1215
void ImDrawList::PathArcTo(const ImVec2& center, float radius, float a_min, float a_max, int num_segments)
1193b4be Poul Sander 2025-02-03 21:28 1216
{
1193b4be Poul Sander 2025-02-03 21:28 1217
    if (radius < 0.5f)
1193b4be Poul Sander 2025-02-03 21:28 1218
    {
1193b4be Poul Sander 2025-02-03 21:28 1219
        _Path.push_back(center);
1193b4be Poul Sander 2025-02-03 21:28 1220
        return;
1193b4be Poul Sander 2025-02-03 21:28 1221
    }
1193b4be Poul Sander 2025-02-03 21:28 1222
1193b4be Poul Sander 2025-02-03 21:28 1223
    if (num_segments > 0)
1193b4be Poul Sander 2025-02-03 21:28 1224
    {
1193b4be Poul Sander 2025-02-03 21:28 1225
        _PathArcToN(center, radius, a_min, a_max, num_segments);
1193b4be Poul Sander 2025-02-03 21:28 1226
        return;
1193b4be Poul Sander 2025-02-03 21:28 1227
    }
1193b4be Poul Sander 2025-02-03 21:28 1228
1193b4be Poul Sander 2025-02-03 21:28 1229
    // Automatic segment count
1193b4be Poul Sander 2025-02-03 21:28 1230
    if (radius <= _Data->ArcFastRadiusCutoff)
1193b4be Poul Sander 2025-02-03 21:28 1231
    {
1193b4be Poul Sander 2025-02-03 21:28 1232
        const bool a_is_reverse = a_max < a_min;
1193b4be Poul Sander 2025-02-03 21:28 1233
1193b4be Poul Sander 2025-02-03 21:28 1234
        // We are going to use precomputed values for mid samples.
1193b4be Poul Sander 2025-02-03 21:28 1235
        // Determine first and last sample in lookup table that belong to the arc.
1193b4be Poul Sander 2025-02-03 21:28 1236
        const float a_min_sample_f = IM_DRAWLIST_ARCFAST_SAMPLE_MAX * a_min / (IM_PI * 2.0f);
1193b4be Poul Sander 2025-02-03 21:28 1237
        const float a_max_sample_f = IM_DRAWLIST_ARCFAST_SAMPLE_MAX * a_max / (IM_PI * 2.0f);
1193b4be Poul Sander 2025-02-03 21:28 1238
1193b4be Poul Sander 2025-02-03 21:28 1239
        const int a_min_sample = a_is_reverse ? (int)ImFloor(a_min_sample_f) : (int)ImCeil(a_min_sample_f);
1193b4be Poul Sander 2025-02-03 21:28 1240
        const int a_max_sample = a_is_reverse ? (int)ImCeil(a_max_sample_f) : (int)ImFloor(a_max_sample_f);
1193b4be Poul Sander 2025-02-03 21:28 1241
        const int a_mid_samples = a_is_reverse ? ImMax(a_min_sample - a_max_sample, 0) : ImMax(a_max_sample - a_min_sample, 0);
1193b4be Poul Sander 2025-02-03 21:28 1242
1193b4be Poul Sander 2025-02-03 21:28 1243
        const float a_min_segment_angle = a_min_sample * IM_PI * 2.0f / IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
1193b4be Poul Sander 2025-02-03 21:28 1244
        const float a_max_segment_angle = a_max_sample * IM_PI * 2.0f / IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
1193b4be Poul Sander 2025-02-03 21:28 1245
        const bool a_emit_start = ImAbs(a_min_segment_angle - a_min) >= 1e-5f;
1193b4be Poul Sander 2025-02-03 21:28 1246
        const bool a_emit_end = ImAbs(a_max - a_max_segment_angle) >= 1e-5f;
1193b4be Poul Sander 2025-02-03 21:28 1247
1193b4be Poul Sander 2025-02-03 21:28 1248
        _Path.reserve(_Path.Size + (a_mid_samples + 1 + (a_emit_start ? 1 : 0) + (a_emit_end ? 1 : 0)));
1193b4be Poul Sander 2025-02-03 21:28 1249
        if (a_emit_start)
1193b4be Poul Sander 2025-02-03 21:28 1250
            _Path.push_back(ImVec2(center.x + ImCos(a_min) * radius, center.y + ImSin(a_min) * radius));
1193b4be Poul Sander 2025-02-03 21:28 1251
        if (a_mid_samples > 0)
1193b4be Poul Sander 2025-02-03 21:28 1252
            _PathArcToFastEx(center, radius, a_min_sample, a_max_sample, 0);
1193b4be Poul Sander 2025-02-03 21:28 1253
        if (a_emit_end)
1193b4be Poul Sander 2025-02-03 21:28 1254
            _Path.push_back(ImVec2(center.x + ImCos(a_max) * radius, center.y + ImSin(a_max) * radius));
1193b4be Poul Sander 2025-02-03 21:28 1255
    }
1193b4be Poul Sander 2025-02-03 21:28 1256
    else
1193b4be Poul Sander 2025-02-03 21:28 1257
    {
1193b4be Poul Sander 2025-02-03 21:28 1258
        const float arc_length = ImAbs(a_max - a_min);
1193b4be Poul Sander 2025-02-03 21:28 1259
        const int circle_segment_count = _CalcCircleAutoSegmentCount(radius);
1193b4be Poul Sander 2025-02-03 21:28 1260
        const int arc_segment_count = ImMax((int)ImCeil(circle_segment_count * arc_length / (IM_PI * 2.0f)), (int)(2.0f * IM_PI / arc_length));
1193b4be Poul Sander 2025-02-03 21:28 1261
        _PathArcToN(center, radius, a_min, a_max, arc_segment_count);
1193b4be Poul Sander 2025-02-03 21:28 1262
    }
1193b4be Poul Sander 2025-02-03 21:28 1263
}
1193b4be Poul Sander 2025-02-03 21:28 1264
1193b4be Poul Sander 2025-02-03 21:28 1265
void ImDrawList::PathEllipticalArcTo(const ImVec2& center, const ImVec2& radius, float rot, float a_min, float a_max, int num_segments)
1193b4be Poul Sander 2025-02-03 21:28 1266
{
1193b4be Poul Sander 2025-02-03 21:28 1267
    if (num_segments <= 0)
1193b4be Poul Sander 2025-02-03 21:28 1268
        num_segments = _CalcCircleAutoSegmentCount(ImMax(radius.x, radius.y)); // A bit pessimistic, maybe there's a better computation to do here.
1193b4be Poul Sander 2025-02-03 21:28 1269
1193b4be Poul Sander 2025-02-03 21:28 1270
    _Path.reserve(_Path.Size + (num_segments + 1));
1193b4be Poul Sander 2025-02-03 21:28 1271
1193b4be Poul Sander 2025-02-03 21:28 1272
    const float cos_rot = ImCos(rot);
1193b4be Poul Sander 2025-02-03 21:28 1273
    const float sin_rot = ImSin(rot);
1193b4be Poul Sander 2025-02-03 21:28 1274
    for (int i = 0; i <= num_segments; i++)
1193b4be Poul Sander 2025-02-03 21:28 1275
    {
1193b4be Poul Sander 2025-02-03 21:28 1276
        const float a = a_min + ((float)i / (float)num_segments) * (a_max - a_min);
1193b4be Poul Sander 2025-02-03 21:28 1277
        ImVec2 point(ImCos(a) * radius.x, ImSin(a) * radius.y);
1193b4be Poul Sander 2025-02-03 21:28 1278
        const ImVec2 rel((point.x * cos_rot) - (point.y * sin_rot), (point.x * sin_rot) + (point.y * cos_rot));
1193b4be Poul Sander 2025-02-03 21:28 1279
        point.x = rel.x + center.x;
1193b4be Poul Sander 2025-02-03 21:28 1280
        point.y = rel.y + center.y;
1193b4be Poul Sander 2025-02-03 21:28 1281
        _Path.push_back(point);
1193b4be Poul Sander 2025-02-03 21:28 1282
    }
1193b4be Poul Sander 2025-02-03 21:28 1283
}
1193b4be Poul Sander 2025-02-03 21:28 1284
1193b4be Poul Sander 2025-02-03 21:28 1285
ImVec2 ImBezierCubicCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, float t)
1193b4be Poul Sander 2025-02-03 21:28 1286
{
1193b4be Poul Sander 2025-02-03 21:28 1287
    float u = 1.0f - t;
1193b4be Poul Sander 2025-02-03 21:28 1288
    float w1 = u * u * u;
1193b4be Poul Sander 2025-02-03 21:28 1289
    float w2 = 3 * u * u * t;
1193b4be Poul Sander 2025-02-03 21:28 1290
    float w3 = 3 * u * t * t;
1193b4be Poul Sander 2025-02-03 21:28 1291
    float w4 = t * t * t;
1193b4be Poul Sander 2025-02-03 21:28 1292
    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);
1193b4be Poul Sander 2025-02-03 21:28 1293
}
1193b4be Poul Sander 2025-02-03 21:28 1294
1193b4be Poul Sander 2025-02-03 21:28 1295
ImVec2 ImBezierQuadraticCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float t)
1193b4be Poul Sander 2025-02-03 21:28 1296
{
1193b4be Poul Sander 2025-02-03 21:28 1297
    float u = 1.0f - t;
1193b4be Poul Sander 2025-02-03 21:28 1298
    float w1 = u * u;
1193b4be Poul Sander 2025-02-03 21:28 1299
    float w2 = 2 * u * t;
1193b4be Poul Sander 2025-02-03 21:28 1300
    float w3 = t * t;
1193b4be Poul Sander 2025-02-03 21:28 1301
    return ImVec2(w1 * p1.x + w2 * p2.x + w3 * p3.x, w1 * p1.y + w2 * p2.y + w3 * p3.y);
1193b4be Poul Sander 2025-02-03 21:28 1302
}
1193b4be Poul Sander 2025-02-03 21:28 1303
1193b4be Poul Sander 2025-02-03 21:28 1304
// Closely mimics ImBezierCubicClosestPointCasteljau() in imgui.cpp
1193b4be Poul Sander 2025-02-03 21:28 1305
static void PathBezierCubicCurveToCasteljau(ImVector<ImVec2>* path, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float tess_tol, int level)
1193b4be Poul Sander 2025-02-03 21:28 1306
{
1193b4be Poul Sander 2025-02-03 21:28 1307
    float dx = x4 - x1;
1193b4be Poul Sander 2025-02-03 21:28 1308
    float dy = y4 - y1;
1193b4be Poul Sander 2025-02-03 21:28 1309
    float d2 = (x2 - x4) * dy - (y2 - y4) * dx;
1193b4be Poul Sander 2025-02-03 21:28 1310
    float d3 = (x3 - x4) * dy - (y3 - y4) * dx;
1193b4be Poul Sander 2025-02-03 21:28 1311
    d2 = (d2 >= 0) ? d2 : -d2;
1193b4be Poul Sander 2025-02-03 21:28 1312
    d3 = (d3 >= 0) ? d3 : -d3;
1193b4be Poul Sander 2025-02-03 21:28 1313
    if ((d2 + d3) * (d2 + d3) < tess_tol * (dx * dx + dy * dy))
1193b4be Poul Sander 2025-02-03 21:28 1314
    {
1193b4be Poul Sander 2025-02-03 21:28 1315
        path->push_back(ImVec2(x4, y4));
1193b4be Poul Sander 2025-02-03 21:28 1316
    }
1193b4be Poul Sander 2025-02-03 21:28 1317
    else if (level < 10)
1193b4be Poul Sander 2025-02-03 21:28 1318
    {
1193b4be Poul Sander 2025-02-03 21:28 1319
        float x12 = (x1 + x2) * 0.5f, y12 = (y1 + y2) * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 1320
        float x23 = (x2 + x3) * 0.5f, y23 = (y2 + y3) * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 1321
        float x34 = (x3 + x4) * 0.5f, y34 = (y3 + y4) * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 1322
        float x123 = (x12 + x23) * 0.5f, y123 = (y12 + y23) * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 1323
        float x234 = (x23 + x34) * 0.5f, y234 = (y23 + y34) * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 1324
        float x1234 = (x123 + x234) * 0.5f, y1234 = (y123 + y234) * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 1325
        PathBezierCubicCurveToCasteljau(path, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1);
1193b4be Poul Sander 2025-02-03 21:28 1326
        PathBezierCubicCurveToCasteljau(path, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1);
1193b4be Poul Sander 2025-02-03 21:28 1327
    }
1193b4be Poul Sander 2025-02-03 21:28 1328
}
1193b4be Poul Sander 2025-02-03 21:28 1329
1193b4be Poul Sander 2025-02-03 21:28 1330
static void PathBezierQuadraticCurveToCasteljau(ImVector<ImVec2>* path, float x1, float y1, float x2, float y2, float x3, float y3, float tess_tol, int level)
1193b4be Poul Sander 2025-02-03 21:28 1331
{
1193b4be Poul Sander 2025-02-03 21:28 1332
    float dx = x3 - x1, dy = y3 - y1;
1193b4be Poul Sander 2025-02-03 21:28 1333
    float det = (x2 - x3) * dy - (y2 - y3) * dx;
1193b4be Poul Sander 2025-02-03 21:28 1334
    if (det * det * 4.0f < tess_tol * (dx * dx + dy * dy))
1193b4be Poul Sander 2025-02-03 21:28 1335
    {
1193b4be Poul Sander 2025-02-03 21:28 1336
        path->push_back(ImVec2(x3, y3));
1193b4be Poul Sander 2025-02-03 21:28 1337
    }
1193b4be Poul Sander 2025-02-03 21:28 1338
    else if (level < 10)
1193b4be Poul Sander 2025-02-03 21:28 1339
    {
1193b4be Poul Sander 2025-02-03 21:28 1340
        float x12 = (x1 + x2) * 0.5f, y12 = (y1 + y2) * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 1341
        float x23 = (x2 + x3) * 0.5f, y23 = (y2 + y3) * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 1342
        float x123 = (x12 + x23) * 0.5f, y123 = (y12 + y23) * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 1343
        PathBezierQuadraticCurveToCasteljau(path, x1, y1, x12, y12, x123, y123, tess_tol, level + 1);
1193b4be Poul Sander 2025-02-03 21:28 1344
        PathBezierQuadraticCurveToCasteljau(path, x123, y123, x23, y23, x3, y3, tess_tol, level + 1);
1193b4be Poul Sander 2025-02-03 21:28 1345
    }
1193b4be Poul Sander 2025-02-03 21:28 1346
}
1193b4be Poul Sander 2025-02-03 21:28 1347
1193b4be Poul Sander 2025-02-03 21:28 1348
void ImDrawList::PathBezierCubicCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments)
1193b4be Poul Sander 2025-02-03 21:28 1349
{
1193b4be Poul Sander 2025-02-03 21:28 1350
    ImVec2 p1 = _Path.back();
1193b4be Poul Sander 2025-02-03 21:28 1351
    if (num_segments == 0)
1193b4be Poul Sander 2025-02-03 21:28 1352
    {
1193b4be Poul Sander 2025-02-03 21:28 1353
        IM_ASSERT(_Data->CurveTessellationTol > 0.0f);
1193b4be Poul Sander 2025-02-03 21:28 1354
        PathBezierCubicCurveToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, _Data->CurveTessellationTol, 0); // Auto-tessellated
1193b4be Poul Sander 2025-02-03 21:28 1355
    }
1193b4be Poul Sander 2025-02-03 21:28 1356
    else
1193b4be Poul Sander 2025-02-03 21:28 1357
    {
1193b4be Poul Sander 2025-02-03 21:28 1358
        float t_step = 1.0f / (float)num_segments;
1193b4be Poul Sander 2025-02-03 21:28 1359
        for (int i_step = 1; i_step <= num_segments; i_step++)
1193b4be Poul Sander 2025-02-03 21:28 1360
            _Path.push_back(ImBezierCubicCalc(p1, p2, p3, p4, t_step * i_step));
1193b4be Poul Sander 2025-02-03 21:28 1361
    }
1193b4be Poul Sander 2025-02-03 21:28 1362
}
1193b4be Poul Sander 2025-02-03 21:28 1363
1193b4be Poul Sander 2025-02-03 21:28 1364
void ImDrawList::PathBezierQuadraticCurveTo(const ImVec2& p2, const ImVec2& p3, int num_segments)
1193b4be Poul Sander 2025-02-03 21:28 1365
{
1193b4be Poul Sander 2025-02-03 21:28 1366
    ImVec2 p1 = _Path.back();
1193b4be Poul Sander 2025-02-03 21:28 1367
    if (num_segments == 0)
1193b4be Poul Sander 2025-02-03 21:28 1368
    {
1193b4be Poul Sander 2025-02-03 21:28 1369
        IM_ASSERT(_Data->CurveTessellationTol > 0.0f);
1193b4be Poul Sander 2025-02-03 21:28 1370
        PathBezierQuadraticCurveToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, _Data->CurveTessellationTol, 0);// Auto-tessellated
1193b4be Poul Sander 2025-02-03 21:28 1371
    }
1193b4be Poul Sander 2025-02-03 21:28 1372
    else
1193b4be Poul Sander 2025-02-03 21:28 1373
    {
1193b4be Poul Sander 2025-02-03 21:28 1374
        float t_step = 1.0f / (float)num_segments;
1193b4be Poul Sander 2025-02-03 21:28 1375
        for (int i_step = 1; i_step <= num_segments; i_step++)
1193b4be Poul Sander 2025-02-03 21:28 1376
            _Path.push_back(ImBezierQuadraticCalc(p1, p2, p3, t_step * i_step));
1193b4be Poul Sander 2025-02-03 21:28 1377
    }
1193b4be Poul Sander 2025-02-03 21:28 1378
}
1193b4be Poul Sander 2025-02-03 21:28 1379
1193b4be Poul Sander 2025-02-03 21:28 1380
static inline ImDrawFlags FixRectCornerFlags(ImDrawFlags flags)
1193b4be Poul Sander 2025-02-03 21:28 1381
{
1193b4be Poul Sander 2025-02-03 21:28 1382
    /*
1193b4be Poul Sander 2025-02-03 21:28 1383
    IM_STATIC_ASSERT(ImDrawFlags_RoundCornersTopLeft == (1 << 4));
1193b4be Poul Sander 2025-02-03 21:28 1384
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
1193b4be Poul Sander 2025-02-03 21:28 1385
    // Obsoleted in 1.82 (from February 2021). This code was stripped/simplified and mostly commented in 1.90 (from September 2023)
1193b4be Poul Sander 2025-02-03 21:28 1386
    // - Legacy Support for hard coded ~0 (used to be a suggested equivalent to ImDrawCornerFlags_All)
1193b4be Poul Sander 2025-02-03 21:28 1387
    if (flags == ~0)                    { return ImDrawFlags_RoundCornersAll; }
1193b4be Poul Sander 2025-02-03 21:28 1388
    // - Legacy Support for hard coded 0x01 to 0x0F (matching 15 out of 16 old flags combinations). Read details in older version of this code.
1193b4be Poul Sander 2025-02-03 21:28 1389
    if (flags >= 0x01 && flags <= 0x0F) { return (flags << 4); }
1193b4be Poul Sander 2025-02-03 21:28 1390
    // We cannot support hard coded 0x00 with 'float rounding > 0.0f' --> replace with ImDrawFlags_RoundCornersNone or use 'float rounding = 0.0f'
1193b4be Poul Sander 2025-02-03 21:28 1391
#endif
1193b4be Poul Sander 2025-02-03 21:28 1392
    */
1193b4be Poul Sander 2025-02-03 21:28 1393
    // If this assert triggers, please update your code replacing hardcoded values with new ImDrawFlags_RoundCorners* values.
1193b4be Poul Sander 2025-02-03 21:28 1394
    // Note that ImDrawFlags_Closed (== 0x01) is an invalid flag for AddRect(), AddRectFilled(), PathRect() etc. anyway.
1193b4be Poul Sander 2025-02-03 21:28 1395
    // See details in 1.82 Changelog as well as 2021/03/12 and 2023/09/08 entries in "API BREAKING CHANGES" section.
1193b4be Poul Sander 2025-02-03 21:28 1396
    IM_ASSERT((flags & 0x0F) == 0 && "Misuse of legacy hardcoded ImDrawCornerFlags values!");
1193b4be Poul Sander 2025-02-03 21:28 1397
1193b4be Poul Sander 2025-02-03 21:28 1398
    if ((flags & ImDrawFlags_RoundCornersMask_) == 0)
1193b4be Poul Sander 2025-02-03 21:28 1399
        flags |= ImDrawFlags_RoundCornersAll;
1193b4be Poul Sander 2025-02-03 21:28 1400
1193b4be Poul Sander 2025-02-03 21:28 1401
    return flags;
1193b4be Poul Sander 2025-02-03 21:28 1402
}
1193b4be Poul Sander 2025-02-03 21:28 1403
1193b4be Poul Sander 2025-02-03 21:28 1404
void ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, ImDrawFlags flags)
1193b4be Poul Sander 2025-02-03 21:28 1405
{
1193b4be Poul Sander 2025-02-03 21:28 1406
    if (rounding >= 0.5f)
1193b4be Poul Sander 2025-02-03 21:28 1407
    {
1193b4be Poul Sander 2025-02-03 21:28 1408
        flags = FixRectCornerFlags(flags);
1193b4be Poul Sander 2025-02-03 21:28 1409
        rounding = ImMin(rounding, ImFabs(b.x - a.x) * (((flags & ImDrawFlags_RoundCornersTop) == ImDrawFlags_RoundCornersTop) || ((flags & ImDrawFlags_RoundCornersBottom) == ImDrawFlags_RoundCornersBottom) ? 0.5f : 1.0f) - 1.0f);
1193b4be Poul Sander 2025-02-03 21:28 1410
        rounding = ImMin(rounding, ImFabs(b.y - a.y) * (((flags & ImDrawFlags_RoundCornersLeft) == ImDrawFlags_RoundCornersLeft) || ((flags & ImDrawFlags_RoundCornersRight) == ImDrawFlags_RoundCornersRight) ? 0.5f : 1.0f) - 1.0f);
1193b4be Poul Sander 2025-02-03 21:28 1411
    }
1193b4be Poul Sander 2025-02-03 21:28 1412
    if (rounding < 0.5f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone)
1193b4be Poul Sander 2025-02-03 21:28 1413
    {
1193b4be Poul Sander 2025-02-03 21:28 1414
        PathLineTo(a);
1193b4be Poul Sander 2025-02-03 21:28 1415
        PathLineTo(ImVec2(b.x, a.y));
1193b4be Poul Sander 2025-02-03 21:28 1416
        PathLineTo(b);
1193b4be Poul Sander 2025-02-03 21:28 1417
        PathLineTo(ImVec2(a.x, b.y));
1193b4be Poul Sander 2025-02-03 21:28 1418
    }
1193b4be Poul Sander 2025-02-03 21:28 1419
    else
1193b4be Poul Sander 2025-02-03 21:28 1420
    {
1193b4be Poul Sander 2025-02-03 21:28 1421
        const float rounding_tl = (flags & ImDrawFlags_RoundCornersTopLeft)     ? rounding : 0.0f;
1193b4be Poul Sander 2025-02-03 21:28 1422
        const float rounding_tr = (flags & ImDrawFlags_RoundCornersTopRight)    ? rounding : 0.0f;
1193b4be Poul Sander 2025-02-03 21:28 1423
        const float rounding_br = (flags & ImDrawFlags_RoundCornersBottomRight) ? rounding : 0.0f;
1193b4be Poul Sander 2025-02-03 21:28 1424
        const float rounding_bl = (flags & ImDrawFlags_RoundCornersBottomLeft)  ? rounding : 0.0f;
1193b4be Poul Sander 2025-02-03 21:28 1425
        PathArcToFast(ImVec2(a.x + rounding_tl, a.y + rounding_tl), rounding_tl, 6, 9);
1193b4be Poul Sander 2025-02-03 21:28 1426
        PathArcToFast(ImVec2(b.x - rounding_tr, a.y + rounding_tr), rounding_tr, 9, 12);
1193b4be Poul Sander 2025-02-03 21:28 1427
        PathArcToFast(ImVec2(b.x - rounding_br, b.y - rounding_br), rounding_br, 0, 3);
1193b4be Poul Sander 2025-02-03 21:28 1428
        PathArcToFast(ImVec2(a.x + rounding_bl, b.y - rounding_bl), rounding_bl, 3, 6);
1193b4be Poul Sander 2025-02-03 21:28 1429
    }
1193b4be Poul Sander 2025-02-03 21:28 1430
}
1193b4be Poul Sander 2025-02-03 21:28 1431
1193b4be Poul Sander 2025-02-03 21:28 1432
void ImDrawList::AddLine(const ImVec2& p1, const ImVec2& p2, ImU32 col, float thickness)
1193b4be Poul Sander 2025-02-03 21:28 1433
{
1193b4be Poul Sander 2025-02-03 21:28 1434
    if ((col & IM_COL32_A_MASK) == 0)
1193b4be Poul Sander 2025-02-03 21:28 1435
        return;
1193b4be Poul Sander 2025-02-03 21:28 1436
    PathLineTo(p1 + ImVec2(0.5f, 0.5f));
1193b4be Poul Sander 2025-02-03 21:28 1437
    PathLineTo(p2 + ImVec2(0.5f, 0.5f));
1193b4be Poul Sander 2025-02-03 21:28 1438
    PathStroke(col, 0, thickness);
1193b4be Poul Sander 2025-02-03 21:28 1439
}
1193b4be Poul Sander 2025-02-03 21:28 1440
1193b4be Poul Sander 2025-02-03 21:28 1441
// p_min = upper-left, p_max = lower-right
1193b4be Poul Sander 2025-02-03 21:28 1442
// Note we don't render 1 pixels sized rectangles properly.
1193b4be Poul Sander 2025-02-03 21:28 1443
void ImDrawList::AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, ImDrawFlags flags, float thickness)
1193b4be Poul Sander 2025-02-03 21:28 1444
{
1193b4be Poul Sander 2025-02-03 21:28 1445
    if ((col & IM_COL32_A_MASK) == 0)
1193b4be Poul Sander 2025-02-03 21:28 1446
        return;
1193b4be Poul Sander 2025-02-03 21:28 1447
    if (Flags & ImDrawListFlags_AntiAliasedLines)
1193b4be Poul Sander 2025-02-03 21:28 1448
        PathRect(p_min + ImVec2(0.50f, 0.50f), p_max - ImVec2(0.50f, 0.50f), rounding, flags);
1193b4be Poul Sander 2025-02-03 21:28 1449
    else
1193b4be Poul Sander 2025-02-03 21:28 1450
        PathRect(p_min + ImVec2(0.50f, 0.50f), p_max - ImVec2(0.49f, 0.49f), rounding, flags); // Better looking lower-right corner and rounded non-AA shapes.
1193b4be Poul Sander 2025-02-03 21:28 1451
    PathStroke(col, ImDrawFlags_Closed, thickness);
1193b4be Poul Sander 2025-02-03 21:28 1452
}
1193b4be Poul Sander 2025-02-03 21:28 1453
1193b4be Poul Sander 2025-02-03 21:28 1454
void ImDrawList::AddRectFilled(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, ImDrawFlags flags)
1193b4be Poul Sander 2025-02-03 21:28 1455
{
1193b4be Poul Sander 2025-02-03 21:28 1456
    if ((col & IM_COL32_A_MASK) == 0)
1193b4be Poul Sander 2025-02-03 21:28 1457
        return;
1193b4be Poul Sander 2025-02-03 21:28 1458
    if (rounding < 0.5f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone)
1193b4be Poul Sander 2025-02-03 21:28 1459
    {
1193b4be Poul Sander 2025-02-03 21:28 1460
        PrimReserve(6, 4);
1193b4be Poul Sander 2025-02-03 21:28 1461
        PrimRect(p_min, p_max, col);
1193b4be Poul Sander 2025-02-03 21:28 1462
    }
1193b4be Poul Sander 2025-02-03 21:28 1463
    else
1193b4be Poul Sander 2025-02-03 21:28 1464
    {
1193b4be Poul Sander 2025-02-03 21:28 1465
        PathRect(p_min, p_max, rounding, flags);
1193b4be Poul Sander 2025-02-03 21:28 1466
        PathFillConvex(col);
1193b4be Poul Sander 2025-02-03 21:28 1467
    }
1193b4be Poul Sander 2025-02-03 21:28 1468
}
1193b4be Poul Sander 2025-02-03 21:28 1469
1193b4be Poul Sander 2025-02-03 21:28 1470
// p_min = upper-left, p_max = lower-right
1193b4be Poul Sander 2025-02-03 21:28 1471
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)
1193b4be Poul Sander 2025-02-03 21:28 1472
{
1193b4be Poul Sander 2025-02-03 21:28 1473
    if (((col_upr_left | col_upr_right | col_bot_right | col_bot_left) & IM_COL32_A_MASK) == 0)
1193b4be Poul Sander 2025-02-03 21:28 1474
        return;
1193b4be Poul Sander 2025-02-03 21:28 1475
1193b4be Poul Sander 2025-02-03 21:28 1476
    const ImVec2 uv = _Data->TexUvWhitePixel;
1193b4be Poul Sander 2025-02-03 21:28 1477
    PrimReserve(6, 4);
1193b4be Poul Sander 2025-02-03 21:28 1478
    PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 1)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 2));
1193b4be Poul Sander 2025-02-03 21:28 1479
    PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 2)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 3));
1193b4be Poul Sander 2025-02-03 21:28 1480
    PrimWriteVtx(p_min, uv, col_upr_left);
1193b4be Poul Sander 2025-02-03 21:28 1481
    PrimWriteVtx(ImVec2(p_max.x, p_min.y), uv, col_upr_right);
1193b4be Poul Sander 2025-02-03 21:28 1482
    PrimWriteVtx(p_max, uv, col_bot_right);
1193b4be Poul Sander 2025-02-03 21:28 1483
    PrimWriteVtx(ImVec2(p_min.x, p_max.y), uv, col_bot_left);
1193b4be Poul Sander 2025-02-03 21:28 1484
}
1193b4be Poul Sander 2025-02-03 21:28 1485
1193b4be Poul Sander 2025-02-03 21:28 1486
void ImDrawList::AddQuad(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness)
1193b4be Poul Sander 2025-02-03 21:28 1487
{
1193b4be Poul Sander 2025-02-03 21:28 1488
    if ((col & IM_COL32_A_MASK) == 0)
1193b4be Poul Sander 2025-02-03 21:28 1489
        return;
1193b4be Poul Sander 2025-02-03 21:28 1490
1193b4be Poul Sander 2025-02-03 21:28 1491
    PathLineTo(p1);
1193b4be Poul Sander 2025-02-03 21:28 1492
    PathLineTo(p2);
1193b4be Poul Sander 2025-02-03 21:28 1493
    PathLineTo(p3);
1193b4be Poul Sander 2025-02-03 21:28 1494
    PathLineTo(p4);
1193b4be Poul Sander 2025-02-03 21:28 1495
    PathStroke(col, ImDrawFlags_Closed, thickness);
1193b4be Poul Sander 2025-02-03 21:28 1496
}
1193b4be Poul Sander 2025-02-03 21:28 1497
1193b4be Poul Sander 2025-02-03 21:28 1498
void ImDrawList::AddQuadFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col)
1193b4be Poul Sander 2025-02-03 21:28 1499
{
1193b4be Poul Sander 2025-02-03 21:28 1500
    if ((col & IM_COL32_A_MASK) == 0)
1193b4be Poul Sander 2025-02-03 21:28 1501
        return;
1193b4be Poul Sander 2025-02-03 21:28 1502
1193b4be Poul Sander 2025-02-03 21:28 1503
    PathLineTo(p1);
1193b4be Poul Sander 2025-02-03 21:28 1504
    PathLineTo(p2);
1193b4be Poul Sander 2025-02-03 21:28 1505
    PathLineTo(p3);
1193b4be Poul Sander 2025-02-03 21:28 1506
    PathLineTo(p4);
1193b4be Poul Sander 2025-02-03 21:28 1507
    PathFillConvex(col);
1193b4be Poul Sander 2025-02-03 21:28 1508
}
1193b4be Poul Sander 2025-02-03 21:28 1509
1193b4be Poul Sander 2025-02-03 21:28 1510
void ImDrawList::AddTriangle(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness)
1193b4be Poul Sander 2025-02-03 21:28 1511
{
1193b4be Poul Sander 2025-02-03 21:28 1512
    if ((col & IM_COL32_A_MASK) == 0)
1193b4be Poul Sander 2025-02-03 21:28 1513
        return;
1193b4be Poul Sander 2025-02-03 21:28 1514
1193b4be Poul Sander 2025-02-03 21:28 1515
    PathLineTo(p1);
1193b4be Poul Sander 2025-02-03 21:28 1516
    PathLineTo(p2);
1193b4be Poul Sander 2025-02-03 21:28 1517
    PathLineTo(p3);
1193b4be Poul Sander 2025-02-03 21:28 1518
    PathStroke(col, ImDrawFlags_Closed, thickness);
1193b4be Poul Sander 2025-02-03 21:28 1519
}
1193b4be Poul Sander 2025-02-03 21:28 1520
1193b4be Poul Sander 2025-02-03 21:28 1521
void ImDrawList::AddTriangleFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col)
1193b4be Poul Sander 2025-02-03 21:28 1522
{
1193b4be Poul Sander 2025-02-03 21:28 1523
    if ((col & IM_COL32_A_MASK) == 0)
1193b4be Poul Sander 2025-02-03 21:28 1524
        return;
1193b4be Poul Sander 2025-02-03 21:28 1525
1193b4be Poul Sander 2025-02-03 21:28 1526
    PathLineTo(p1);
1193b4be Poul Sander 2025-02-03 21:28 1527
    PathLineTo(p2);
1193b4be Poul Sander 2025-02-03 21:28 1528
    PathLineTo(p3);
1193b4be Poul Sander 2025-02-03 21:28 1529
    PathFillConvex(col);
1193b4be Poul Sander 2025-02-03 21:28 1530
}
1193b4be Poul Sander 2025-02-03 21:28 1531
1193b4be Poul Sander 2025-02-03 21:28 1532
void ImDrawList::AddCircle(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness)
1193b4be Poul Sander 2025-02-03 21:28 1533
{
1193b4be Poul Sander 2025-02-03 21:28 1534
    if ((col & IM_COL32_A_MASK) == 0 || radius < 0.5f)
1193b4be Poul Sander 2025-02-03 21:28 1535
        return;
1193b4be Poul Sander 2025-02-03 21:28 1536
1193b4be Poul Sander 2025-02-03 21:28 1537
    if (num_segments <= 0)
1193b4be Poul Sander 2025-02-03 21:28 1538
    {
1193b4be Poul Sander 2025-02-03 21:28 1539
        // Use arc with automatic segment count
1193b4be Poul Sander 2025-02-03 21:28 1540
        _PathArcToFastEx(center, radius - 0.5f, 0, IM_DRAWLIST_ARCFAST_SAMPLE_MAX, 0);
1193b4be Poul Sander 2025-02-03 21:28 1541
        _Path.Size--;
1193b4be Poul Sander 2025-02-03 21:28 1542
    }
1193b4be Poul Sander 2025-02-03 21:28 1543
    else
1193b4be Poul Sander 2025-02-03 21:28 1544
    {
1193b4be Poul Sander 2025-02-03 21:28 1545
        // Explicit segment count (still clamp to avoid drawing insanely tessellated shapes)
1193b4be Poul Sander 2025-02-03 21:28 1546
        num_segments = ImClamp(num_segments, 3, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX);
1193b4be Poul Sander 2025-02-03 21:28 1547
1193b4be Poul Sander 2025-02-03 21:28 1548
        // Because we are filling a closed shape we remove 1 from the count of segments/points
1193b4be Poul Sander 2025-02-03 21:28 1549
        const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments;
1193b4be Poul Sander 2025-02-03 21:28 1550
        PathArcTo(center, radius - 0.5f, 0.0f, a_max, num_segments - 1);
1193b4be Poul Sander 2025-02-03 21:28 1551
    }
1193b4be Poul Sander 2025-02-03 21:28 1552
1193b4be Poul Sander 2025-02-03 21:28 1553
    PathStroke(col, ImDrawFlags_Closed, thickness);
1193b4be Poul Sander 2025-02-03 21:28 1554
}
1193b4be Poul Sander 2025-02-03 21:28 1555
1193b4be Poul Sander 2025-02-03 21:28 1556
void ImDrawList::AddCircleFilled(const ImVec2& center, float radius, ImU32 col, int num_segments)
1193b4be Poul Sander 2025-02-03 21:28 1557
{
1193b4be Poul Sander 2025-02-03 21:28 1558
    if ((col & IM_COL32_A_MASK) == 0 || radius < 0.5f)
1193b4be Poul Sander 2025-02-03 21:28 1559
        return;
1193b4be Poul Sander 2025-02-03 21:28 1560
1193b4be Poul Sander 2025-02-03 21:28 1561
    if (num_segments <= 0)
1193b4be Poul Sander 2025-02-03 21:28 1562
    {
1193b4be Poul Sander 2025-02-03 21:28 1563
        // Use arc with automatic segment count
1193b4be Poul Sander 2025-02-03 21:28 1564
        _PathArcToFastEx(center, radius, 0, IM_DRAWLIST_ARCFAST_SAMPLE_MAX, 0);
1193b4be Poul Sander 2025-02-03 21:28 1565
        _Path.Size--;
1193b4be Poul Sander 2025-02-03 21:28 1566
    }
1193b4be Poul Sander 2025-02-03 21:28 1567
    else
1193b4be Poul Sander 2025-02-03 21:28 1568
    {
1193b4be Poul Sander 2025-02-03 21:28 1569
        // Explicit segment count (still clamp to avoid drawing insanely tessellated shapes)
1193b4be Poul Sander 2025-02-03 21:28 1570
        num_segments = ImClamp(num_segments, 3, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX);
1193b4be Poul Sander 2025-02-03 21:28 1571
1193b4be Poul Sander 2025-02-03 21:28 1572
        // Because we are filling a closed shape we remove 1 from the count of segments/points
1193b4be Poul Sander 2025-02-03 21:28 1573
        const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments;
1193b4be Poul Sander 2025-02-03 21:28 1574
        PathArcTo(center, radius, 0.0f, a_max, num_segments - 1);
1193b4be Poul Sander 2025-02-03 21:28 1575
    }
1193b4be Poul Sander 2025-02-03 21:28 1576
1193b4be Poul Sander 2025-02-03 21:28 1577
    PathFillConvex(col);
1193b4be Poul Sander 2025-02-03 21:28 1578
}
1193b4be Poul Sander 2025-02-03 21:28 1579
1193b4be Poul Sander 2025-02-03 21:28 1580
// Guaranteed to honor 'num_segments'
1193b4be Poul Sander 2025-02-03 21:28 1581
void ImDrawList::AddNgon(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness)
1193b4be Poul Sander 2025-02-03 21:28 1582
{
1193b4be Poul Sander 2025-02-03 21:28 1583
    if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2)
1193b4be Poul Sander 2025-02-03 21:28 1584
        return;
1193b4be Poul Sander 2025-02-03 21:28 1585
1193b4be Poul Sander 2025-02-03 21:28 1586
    // Because we are filling a closed shape we remove 1 from the count of segments/points
1193b4be Poul Sander 2025-02-03 21:28 1587
    const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments;
1193b4be Poul Sander 2025-02-03 21:28 1588
    PathArcTo(center, radius - 0.5f, 0.0f, a_max, num_segments - 1);
1193b4be Poul Sander 2025-02-03 21:28 1589
    PathStroke(col, ImDrawFlags_Closed, thickness);
1193b4be Poul Sander 2025-02-03 21:28 1590
}
1193b4be Poul Sander 2025-02-03 21:28 1591
1193b4be Poul Sander 2025-02-03 21:28 1592
// Guaranteed to honor 'num_segments'
1193b4be Poul Sander 2025-02-03 21:28 1593
void ImDrawList::AddNgonFilled(const ImVec2& center, float radius, ImU32 col, int num_segments)
1193b4be Poul Sander 2025-02-03 21:28 1594
{
1193b4be Poul Sander 2025-02-03 21:28 1595
    if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2)
1193b4be Poul Sander 2025-02-03 21:28 1596
        return;
1193b4be Poul Sander 2025-02-03 21:28 1597
1193b4be Poul Sander 2025-02-03 21:28 1598
    // Because we are filling a closed shape we remove 1 from the count of segments/points
1193b4be Poul Sander 2025-02-03 21:28 1599
    const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments;
1193b4be Poul Sander 2025-02-03 21:28 1600
    PathArcTo(center, radius, 0.0f, a_max, num_segments - 1);
1193b4be Poul Sander 2025-02-03 21:28 1601
    PathFillConvex(col);
1193b4be Poul Sander 2025-02-03 21:28 1602
}
1193b4be Poul Sander 2025-02-03 21:28 1603
1193b4be Poul Sander 2025-02-03 21:28 1604
// Ellipse
1193b4be Poul Sander 2025-02-03 21:28 1605
void ImDrawList::AddEllipse(const ImVec2& center, const ImVec2& radius, ImU32 col, float rot, int num_segments, float thickness)
1193b4be Poul Sander 2025-02-03 21:28 1606
{
1193b4be Poul Sander 2025-02-03 21:28 1607
    if ((col & IM_COL32_A_MASK) == 0)
1193b4be Poul Sander 2025-02-03 21:28 1608
        return;
1193b4be Poul Sander 2025-02-03 21:28 1609
1193b4be Poul Sander 2025-02-03 21:28 1610
    if (num_segments <= 0)
1193b4be Poul Sander 2025-02-03 21:28 1611
        num_segments = _CalcCircleAutoSegmentCount(ImMax(radius.x, radius.y)); // A bit pessimistic, maybe there's a better computation to do here.
1193b4be Poul Sander 2025-02-03 21:28 1612
1193b4be Poul Sander 2025-02-03 21:28 1613
    // Because we are filling a closed shape we remove 1 from the count of segments/points
1193b4be Poul Sander 2025-02-03 21:28 1614
    const float a_max = IM_PI * 2.0f * ((float)num_segments - 1.0f) / (float)num_segments;
1193b4be Poul Sander 2025-02-03 21:28 1615
    PathEllipticalArcTo(center, radius, rot, 0.0f, a_max, num_segments - 1);
1193b4be Poul Sander 2025-02-03 21:28 1616
    PathStroke(col, true, thickness);
1193b4be Poul Sander 2025-02-03 21:28 1617
}
1193b4be Poul Sander 2025-02-03 21:28 1618
1193b4be Poul Sander 2025-02-03 21:28 1619
void ImDrawList::AddEllipseFilled(const ImVec2& center, const ImVec2& radius, ImU32 col, float rot, int num_segments)
1193b4be Poul Sander 2025-02-03 21:28 1620
{
1193b4be Poul Sander 2025-02-03 21:28 1621
    if ((col & IM_COL32_A_MASK) == 0)
1193b4be Poul Sander 2025-02-03 21:28 1622
        return;
1193b4be Poul Sander 2025-02-03 21:28 1623
1193b4be Poul Sander 2025-02-03 21:28 1624
    if (num_segments <= 0)
1193b4be Poul Sander 2025-02-03 21:28 1625
        num_segments = _CalcCircleAutoSegmentCount(ImMax(radius.x, radius.y)); // A bit pessimistic, maybe there's a better computation to do here.
1193b4be Poul Sander 2025-02-03 21:28 1626
1193b4be Poul Sander 2025-02-03 21:28 1627
    // Because we are filling a closed shape we remove 1 from the count of segments/points
1193b4be Poul Sander 2025-02-03 21:28 1628
    const float a_max = IM_PI * 2.0f * ((float)num_segments - 1.0f) / (float)num_segments;
1193b4be Poul Sander 2025-02-03 21:28 1629
    PathEllipticalArcTo(center, radius, rot, 0.0f, a_max, num_segments - 1);
1193b4be Poul Sander 2025-02-03 21:28 1630
    PathFillConvex(col);
1193b4be Poul Sander 2025-02-03 21:28 1631
}
1193b4be Poul Sander 2025-02-03 21:28 1632
1193b4be Poul Sander 2025-02-03 21:28 1633
// Cubic Bezier takes 4 controls points
1193b4be Poul Sander 2025-02-03 21:28 1634
void ImDrawList::AddBezierCubic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments)
1193b4be Poul Sander 2025-02-03 21:28 1635
{
1193b4be Poul Sander 2025-02-03 21:28 1636
    if ((col & IM_COL32_A_MASK) == 0)
1193b4be Poul Sander 2025-02-03 21:28 1637
        return;
1193b4be Poul Sander 2025-02-03 21:28 1638
1193b4be Poul Sander 2025-02-03 21:28 1639
    PathLineTo(p1);
1193b4be Poul Sander 2025-02-03 21:28 1640
    PathBezierCubicCurveTo(p2, p3, p4, num_segments);
1193b4be Poul Sander 2025-02-03 21:28 1641
    PathStroke(col, 0, thickness);
1193b4be Poul Sander 2025-02-03 21:28 1642
}
1193b4be Poul Sander 2025-02-03 21:28 1643
1193b4be Poul Sander 2025-02-03 21:28 1644
// Quadratic Bezier takes 3 controls points
1193b4be Poul Sander 2025-02-03 21:28 1645
void ImDrawList::AddBezierQuadratic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness, int num_segments)
1193b4be Poul Sander 2025-02-03 21:28 1646
{
1193b4be Poul Sander 2025-02-03 21:28 1647
    if ((col & IM_COL32_A_MASK) == 0)
1193b4be Poul Sander 2025-02-03 21:28 1648
        return;
1193b4be Poul Sander 2025-02-03 21:28 1649
1193b4be Poul Sander 2025-02-03 21:28 1650
    PathLineTo(p1);
1193b4be Poul Sander 2025-02-03 21:28 1651
    PathBezierQuadraticCurveTo(p2, p3, num_segments);
1193b4be Poul Sander 2025-02-03 21:28 1652
    PathStroke(col, 0, thickness);
1193b4be Poul Sander 2025-02-03 21:28 1653
}
1193b4be Poul Sander 2025-02-03 21:28 1654
1193b4be Poul Sander 2025-02-03 21:28 1655
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)
1193b4be Poul Sander 2025-02-03 21:28 1656
{
1193b4be Poul Sander 2025-02-03 21:28 1657
    if ((col & IM_COL32_A_MASK) == 0)
1193b4be Poul Sander 2025-02-03 21:28 1658
        return;
1193b4be Poul Sander 2025-02-03 21:28 1659
1193b4be Poul Sander 2025-02-03 21:28 1660
    // Accept null ranges
1193b4be Poul Sander 2025-02-03 21:28 1661
    if (text_begin == text_end || text_begin[0] == 0)
1193b4be Poul Sander 2025-02-03 21:28 1662
        return;
1193b4be Poul Sander 2025-02-03 21:28 1663
    if (text_end == NULL)
1193b4be Poul Sander 2025-02-03 21:28 1664
        text_end = text_begin + strlen(text_begin);
1193b4be Poul Sander 2025-02-03 21:28 1665
1193b4be Poul Sander 2025-02-03 21:28 1666
    // Pull default font/size from the shared ImDrawListSharedData instance
1193b4be Poul Sander 2025-02-03 21:28 1667
    if (font == NULL)
1193b4be Poul Sander 2025-02-03 21:28 1668
        font = _Data->Font;
1193b4be Poul Sander 2025-02-03 21:28 1669
    if (font_size == 0.0f)
1193b4be Poul Sander 2025-02-03 21:28 1670
        font_size = _Data->FontSize;
1193b4be Poul Sander 2025-02-03 21:28 1671
1193b4be Poul Sander 2025-02-03 21:28 1672
    IM_ASSERT(font->ContainerAtlas->TexID == _CmdHeader.TextureId);  // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font.
1193b4be Poul Sander 2025-02-03 21:28 1673
1193b4be Poul Sander 2025-02-03 21:28 1674
    ImVec4 clip_rect = _CmdHeader.ClipRect;
1193b4be Poul Sander 2025-02-03 21:28 1675
    if (cpu_fine_clip_rect)
1193b4be Poul Sander 2025-02-03 21:28 1676
    {
1193b4be Poul Sander 2025-02-03 21:28 1677
        clip_rect.x = ImMax(clip_rect.x, cpu_fine_clip_rect->x);
1193b4be Poul Sander 2025-02-03 21:28 1678
        clip_rect.y = ImMax(clip_rect.y, cpu_fine_clip_rect->y);
1193b4be Poul Sander 2025-02-03 21:28 1679
        clip_rect.z = ImMin(clip_rect.z, cpu_fine_clip_rect->z);
1193b4be Poul Sander 2025-02-03 21:28 1680
        clip_rect.w = ImMin(clip_rect.w, cpu_fine_clip_rect->w);
1193b4be Poul Sander 2025-02-03 21:28 1681
    }
1193b4be Poul Sander 2025-02-03 21:28 1682
    font->RenderText(this, font_size, pos, col, clip_rect, text_begin, text_end, wrap_width, cpu_fine_clip_rect != NULL);
1193b4be Poul Sander 2025-02-03 21:28 1683
}
1193b4be Poul Sander 2025-02-03 21:28 1684
1193b4be Poul Sander 2025-02-03 21:28 1685
void ImDrawList::AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end)
1193b4be Poul Sander 2025-02-03 21:28 1686
{
1193b4be Poul Sander 2025-02-03 21:28 1687
    AddText(NULL, 0.0f, pos, col, text_begin, text_end);
1193b4be Poul Sander 2025-02-03 21:28 1688
}
1193b4be Poul Sander 2025-02-03 21:28 1689
1193b4be Poul Sander 2025-02-03 21:28 1690
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)
1193b4be Poul Sander 2025-02-03 21:28 1691
{
1193b4be Poul Sander 2025-02-03 21:28 1692
    if ((col & IM_COL32_A_MASK) == 0)
1193b4be Poul Sander 2025-02-03 21:28 1693
        return;
1193b4be Poul Sander 2025-02-03 21:28 1694
1193b4be Poul Sander 2025-02-03 21:28 1695
    const bool push_texture_id = user_texture_id != _CmdHeader.TextureId;
1193b4be Poul Sander 2025-02-03 21:28 1696
    if (push_texture_id)
1193b4be Poul Sander 2025-02-03 21:28 1697
        PushTextureID(user_texture_id);
1193b4be Poul Sander 2025-02-03 21:28 1698
1193b4be Poul Sander 2025-02-03 21:28 1699
    PrimReserve(6, 4);
1193b4be Poul Sander 2025-02-03 21:28 1700
    PrimRectUV(p_min, p_max, uv_min, uv_max, col);
1193b4be Poul Sander 2025-02-03 21:28 1701
1193b4be Poul Sander 2025-02-03 21:28 1702
    if (push_texture_id)
1193b4be Poul Sander 2025-02-03 21:28 1703
        PopTextureID();
1193b4be Poul Sander 2025-02-03 21:28 1704
}
1193b4be Poul Sander 2025-02-03 21:28 1705
1193b4be Poul Sander 2025-02-03 21:28 1706
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)
1193b4be Poul Sander 2025-02-03 21:28 1707
{
1193b4be Poul Sander 2025-02-03 21:28 1708
    if ((col & IM_COL32_A_MASK) == 0)
1193b4be Poul Sander 2025-02-03 21:28 1709
        return;
1193b4be Poul Sander 2025-02-03 21:28 1710
1193b4be Poul Sander 2025-02-03 21:28 1711
    const bool push_texture_id = user_texture_id != _CmdHeader.TextureId;
1193b4be Poul Sander 2025-02-03 21:28 1712
    if (push_texture_id)
1193b4be Poul Sander 2025-02-03 21:28 1713
        PushTextureID(user_texture_id);
1193b4be Poul Sander 2025-02-03 21:28 1714
1193b4be Poul Sander 2025-02-03 21:28 1715
    PrimReserve(6, 4);
1193b4be Poul Sander 2025-02-03 21:28 1716
    PrimQuadUV(p1, p2, p3, p4, uv1, uv2, uv3, uv4, col);
1193b4be Poul Sander 2025-02-03 21:28 1717
1193b4be Poul Sander 2025-02-03 21:28 1718
    if (push_texture_id)
1193b4be Poul Sander 2025-02-03 21:28 1719
        PopTextureID();
1193b4be Poul Sander 2025-02-03 21:28 1720
}
1193b4be Poul Sander 2025-02-03 21:28 1721
1193b4be Poul Sander 2025-02-03 21:28 1722
void ImDrawList::AddImageRounded(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col, float rounding, ImDrawFlags flags)
1193b4be Poul Sander 2025-02-03 21:28 1723
{
1193b4be Poul Sander 2025-02-03 21:28 1724
    if ((col & IM_COL32_A_MASK) == 0)
1193b4be Poul Sander 2025-02-03 21:28 1725
        return;
1193b4be Poul Sander 2025-02-03 21:28 1726
1193b4be Poul Sander 2025-02-03 21:28 1727
    flags = FixRectCornerFlags(flags);
1193b4be Poul Sander 2025-02-03 21:28 1728
    if (rounding < 0.5f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone)
1193b4be Poul Sander 2025-02-03 21:28 1729
    {
1193b4be Poul Sander 2025-02-03 21:28 1730
        AddImage(user_texture_id, p_min, p_max, uv_min, uv_max, col);
1193b4be Poul Sander 2025-02-03 21:28 1731
        return;
1193b4be Poul Sander 2025-02-03 21:28 1732
    }
1193b4be Poul Sander 2025-02-03 21:28 1733
1193b4be Poul Sander 2025-02-03 21:28 1734
    const bool push_texture_id = user_texture_id != _CmdHeader.TextureId;
1193b4be Poul Sander 2025-02-03 21:28 1735
    if (push_texture_id)
1193b4be Poul Sander 2025-02-03 21:28 1736
        PushTextureID(user_texture_id);
1193b4be Poul Sander 2025-02-03 21:28 1737
1193b4be Poul Sander 2025-02-03 21:28 1738
    int vert_start_idx = VtxBuffer.Size;
1193b4be Poul Sander 2025-02-03 21:28 1739
    PathRect(p_min, p_max, rounding, flags);
1193b4be Poul Sander 2025-02-03 21:28 1740
    PathFillConvex(col);
1193b4be Poul Sander 2025-02-03 21:28 1741
    int vert_end_idx = VtxBuffer.Size;
1193b4be Poul Sander 2025-02-03 21:28 1742
    ImGui::ShadeVertsLinearUV(this, vert_start_idx, vert_end_idx, p_min, p_max, uv_min, uv_max, true);
1193b4be Poul Sander 2025-02-03 21:28 1743
1193b4be Poul Sander 2025-02-03 21:28 1744
    if (push_texture_id)
1193b4be Poul Sander 2025-02-03 21:28 1745
        PopTextureID();
1193b4be Poul Sander 2025-02-03 21:28 1746
}
1193b4be Poul Sander 2025-02-03 21:28 1747
1193b4be Poul Sander 2025-02-03 21:28 1748
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 1749
// [SECTION] ImTriangulator, ImDrawList concave polygon fill
1193b4be Poul Sander 2025-02-03 21:28 1750
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 1751
// Triangulate concave polygons. Based on "Triangulation by Ear Clipping" paper, O(N^2) complexity.
1193b4be Poul Sander 2025-02-03 21:28 1752
// Reference: https://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf
1193b4be Poul Sander 2025-02-03 21:28 1753
// Provided as a convenience for user but not used by main library.
1193b4be Poul Sander 2025-02-03 21:28 1754
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 1755
// - ImTriangulator [Internal]
1193b4be Poul Sander 2025-02-03 21:28 1756
// - AddConcavePolyFilled()
1193b4be Poul Sander 2025-02-03 21:28 1757
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 1758
1193b4be Poul Sander 2025-02-03 21:28 1759
enum ImTriangulatorNodeType
1193b4be Poul Sander 2025-02-03 21:28 1760
{
1193b4be Poul Sander 2025-02-03 21:28 1761
    ImTriangulatorNodeType_Convex,
1193b4be Poul Sander 2025-02-03 21:28 1762
    ImTriangulatorNodeType_Ear,
1193b4be Poul Sander 2025-02-03 21:28 1763
    ImTriangulatorNodeType_Reflex
1193b4be Poul Sander 2025-02-03 21:28 1764
};
1193b4be Poul Sander 2025-02-03 21:28 1765
1193b4be Poul Sander 2025-02-03 21:28 1766
struct ImTriangulatorNode
1193b4be Poul Sander 2025-02-03 21:28 1767
{
1193b4be Poul Sander 2025-02-03 21:28 1768
    ImTriangulatorNodeType  Type;
1193b4be Poul Sander 2025-02-03 21:28 1769
    int                     Index;
1193b4be Poul Sander 2025-02-03 21:28 1770
    ImVec2                  Pos;
1193b4be Poul Sander 2025-02-03 21:28 1771
    ImTriangulatorNode*     Next;
1193b4be Poul Sander 2025-02-03 21:28 1772
    ImTriangulatorNode*     Prev;
1193b4be Poul Sander 2025-02-03 21:28 1773
1193b4be Poul Sander 2025-02-03 21:28 1774
    void    Unlink()        { Next->Prev = Prev; Prev->Next = Next; }
1193b4be Poul Sander 2025-02-03 21:28 1775
};
1193b4be Poul Sander 2025-02-03 21:28 1776
1193b4be Poul Sander 2025-02-03 21:28 1777
struct ImTriangulatorNodeSpan
1193b4be Poul Sander 2025-02-03 21:28 1778
{
1193b4be Poul Sander 2025-02-03 21:28 1779
    ImTriangulatorNode**    Data = NULL;
1193b4be Poul Sander 2025-02-03 21:28 1780
    int                     Size = 0;
1193b4be Poul Sander 2025-02-03 21:28 1781
1193b4be Poul Sander 2025-02-03 21:28 1782
    void    push_back(ImTriangulatorNode* node) { Data[Size++] = node; }
1193b4be Poul Sander 2025-02-03 21:28 1783
    void    find_erase_unsorted(int idx)        { for (int i = Size - 1; i >= 0; i--) if (Data[i]->Index == idx) { Data[i] = Data[Size - 1]; Size--; return; } }
1193b4be Poul Sander 2025-02-03 21:28 1784
};
1193b4be Poul Sander 2025-02-03 21:28 1785
1193b4be Poul Sander 2025-02-03 21:28 1786
struct ImTriangulator
1193b4be Poul Sander 2025-02-03 21:28 1787
{
1193b4be Poul Sander 2025-02-03 21:28 1788
    static int EstimateTriangleCount(int points_count)      { return (points_count < 3) ? 0 : points_count - 2; }
1193b4be Poul Sander 2025-02-03 21:28 1789
    static int EstimateScratchBufferSize(int points_count)  { return sizeof(ImTriangulatorNode) * points_count + sizeof(ImTriangulatorNode*) * points_count * 2; }
1193b4be Poul Sander 2025-02-03 21:28 1790
1193b4be Poul Sander 2025-02-03 21:28 1791
    void    Init(const ImVec2* points, int points_count, void* scratch_buffer);
1193b4be Poul Sander 2025-02-03 21:28 1792
    void    GetNextTriangle(unsigned int out_triangle[3]);     // Return relative indexes for next triangle
1193b4be Poul Sander 2025-02-03 21:28 1793
1193b4be Poul Sander 2025-02-03 21:28 1794
    // Internal functions
1193b4be Poul Sander 2025-02-03 21:28 1795
    void    BuildNodes(const ImVec2* points, int points_count);
1193b4be Poul Sander 2025-02-03 21:28 1796
    void    BuildReflexes();
1193b4be Poul Sander 2025-02-03 21:28 1797
    void    BuildEars();
1193b4be Poul Sander 2025-02-03 21:28 1798
    void    FlipNodeList();
1193b4be Poul Sander 2025-02-03 21:28 1799
    bool    IsEar(int i0, int i1, int i2, const ImVec2& v0, const ImVec2& v1, const ImVec2& v2) const;
1193b4be Poul Sander 2025-02-03 21:28 1800
    void    ReclassifyNode(ImTriangulatorNode* node);
1193b4be Poul Sander 2025-02-03 21:28 1801
1193b4be Poul Sander 2025-02-03 21:28 1802
    // Internal members
1193b4be Poul Sander 2025-02-03 21:28 1803
    int                     _TrianglesLeft = 0;
1193b4be Poul Sander 2025-02-03 21:28 1804
    ImTriangulatorNode*     _Nodes = NULL;
1193b4be Poul Sander 2025-02-03 21:28 1805
    ImTriangulatorNodeSpan  _Ears;
1193b4be Poul Sander 2025-02-03 21:28 1806
    ImTriangulatorNodeSpan  _Reflexes;
1193b4be Poul Sander 2025-02-03 21:28 1807
};
1193b4be Poul Sander 2025-02-03 21:28 1808
1193b4be Poul Sander 2025-02-03 21:28 1809
// Distribute storage for nodes, ears and reflexes.
1193b4be Poul Sander 2025-02-03 21:28 1810
// FIXME-OPT: if everything is convex, we could report it to caller and let it switch to an convex renderer
1193b4be Poul Sander 2025-02-03 21:28 1811
// (this would require first building reflexes to bail to convex if empty, without even building nodes)
1193b4be Poul Sander 2025-02-03 21:28 1812
void ImTriangulator::Init(const ImVec2* points, int points_count, void* scratch_buffer)
1193b4be Poul Sander 2025-02-03 21:28 1813
{
1193b4be Poul Sander 2025-02-03 21:28 1814
    IM_ASSERT(scratch_buffer != NULL && points_count >= 3);
1193b4be Poul Sander 2025-02-03 21:28 1815
    _TrianglesLeft = EstimateTriangleCount(points_count);
1193b4be Poul Sander 2025-02-03 21:28 1816
    _Nodes         = (ImTriangulatorNode*)scratch_buffer;                          // points_count x Node
1193b4be Poul Sander 2025-02-03 21:28 1817
    _Ears.Data     = (ImTriangulatorNode**)(_Nodes + points_count);                // points_count x Node*
1193b4be Poul Sander 2025-02-03 21:28 1818
    _Reflexes.Data = (ImTriangulatorNode**)(_Nodes + points_count) + points_count; // points_count x Node*
1193b4be Poul Sander 2025-02-03 21:28 1819
    BuildNodes(points, points_count);
1193b4be Poul Sander 2025-02-03 21:28 1820
    BuildReflexes();
1193b4be Poul Sander 2025-02-03 21:28 1821
    BuildEars();
1193b4be Poul Sander 2025-02-03 21:28 1822
}
1193b4be Poul Sander 2025-02-03 21:28 1823
1193b4be Poul Sander 2025-02-03 21:28 1824
void ImTriangulator::BuildNodes(const ImVec2* points, int points_count)
1193b4be Poul Sander 2025-02-03 21:28 1825
{
1193b4be Poul Sander 2025-02-03 21:28 1826
    for (int i = 0; i < points_count; i++)
1193b4be Poul Sander 2025-02-03 21:28 1827
    {
1193b4be Poul Sander 2025-02-03 21:28 1828
        _Nodes[i].Type = ImTriangulatorNodeType_Convex;
1193b4be Poul Sander 2025-02-03 21:28 1829
        _Nodes[i].Index = i;
1193b4be Poul Sander 2025-02-03 21:28 1830
        _Nodes[i].Pos = points[i];
1193b4be Poul Sander 2025-02-03 21:28 1831
        _Nodes[i].Next = _Nodes + i + 1;
1193b4be Poul Sander 2025-02-03 21:28 1832
        _Nodes[i].Prev = _Nodes + i - 1;
1193b4be Poul Sander 2025-02-03 21:28 1833
    }
1193b4be Poul Sander 2025-02-03 21:28 1834
    _Nodes[0].Prev = _Nodes + points_count - 1;
1193b4be Poul Sander 2025-02-03 21:28 1835
    _Nodes[points_count - 1].Next = _Nodes;
1193b4be Poul Sander 2025-02-03 21:28 1836
}
1193b4be Poul Sander 2025-02-03 21:28 1837
1193b4be Poul Sander 2025-02-03 21:28 1838
void ImTriangulator::BuildReflexes()
1193b4be Poul Sander 2025-02-03 21:28 1839
{
1193b4be Poul Sander 2025-02-03 21:28 1840
    ImTriangulatorNode* n1 = _Nodes;
1193b4be Poul Sander 2025-02-03 21:28 1841
    for (int i = _TrianglesLeft; i >= 0; i--, n1 = n1->Next)
1193b4be Poul Sander 2025-02-03 21:28 1842
    {
1193b4be Poul Sander 2025-02-03 21:28 1843
        if (ImTriangleIsClockwise(n1->Prev->Pos, n1->Pos, n1->Next->Pos))
1193b4be Poul Sander 2025-02-03 21:28 1844
            continue;
1193b4be Poul Sander 2025-02-03 21:28 1845
        n1->Type = ImTriangulatorNodeType_Reflex;
1193b4be Poul Sander 2025-02-03 21:28 1846
        _Reflexes.push_back(n1);
1193b4be Poul Sander 2025-02-03 21:28 1847
    }
1193b4be Poul Sander 2025-02-03 21:28 1848
}
1193b4be Poul Sander 2025-02-03 21:28 1849
1193b4be Poul Sander 2025-02-03 21:28 1850
void ImTriangulator::BuildEars()
1193b4be Poul Sander 2025-02-03 21:28 1851
{
1193b4be Poul Sander 2025-02-03 21:28 1852
    ImTriangulatorNode* n1 = _Nodes;
1193b4be Poul Sander 2025-02-03 21:28 1853
    for (int i = _TrianglesLeft; i >= 0; i--, n1 = n1->Next)
1193b4be Poul Sander 2025-02-03 21:28 1854
    {
1193b4be Poul Sander 2025-02-03 21:28 1855
        if (n1->Type != ImTriangulatorNodeType_Convex)
1193b4be Poul Sander 2025-02-03 21:28 1856
            continue;
1193b4be Poul Sander 2025-02-03 21:28 1857
        if (!IsEar(n1->Prev->Index, n1->Index, n1->Next->Index, n1->Prev->Pos, n1->Pos, n1->Next->Pos))
1193b4be Poul Sander 2025-02-03 21:28 1858
            continue;
1193b4be Poul Sander 2025-02-03 21:28 1859
        n1->Type = ImTriangulatorNodeType_Ear;
1193b4be Poul Sander 2025-02-03 21:28 1860
        _Ears.push_back(n1);
1193b4be Poul Sander 2025-02-03 21:28 1861
    }
1193b4be Poul Sander 2025-02-03 21:28 1862
}
1193b4be Poul Sander 2025-02-03 21:28 1863
1193b4be Poul Sander 2025-02-03 21:28 1864
void ImTriangulator::GetNextTriangle(unsigned int out_triangle[3])
1193b4be Poul Sander 2025-02-03 21:28 1865
{
1193b4be Poul Sander 2025-02-03 21:28 1866
    if (_Ears.Size == 0)
1193b4be Poul Sander 2025-02-03 21:28 1867
    {
1193b4be Poul Sander 2025-02-03 21:28 1868
        FlipNodeList();
1193b4be Poul Sander 2025-02-03 21:28 1869
1193b4be Poul Sander 2025-02-03 21:28 1870
        ImTriangulatorNode* node = _Nodes;
1193b4be Poul Sander 2025-02-03 21:28 1871
        for (int i = _TrianglesLeft; i >= 0; i--, node = node->Next)
1193b4be Poul Sander 2025-02-03 21:28 1872
            node->Type = ImTriangulatorNodeType_Convex;
1193b4be Poul Sander 2025-02-03 21:28 1873
        _Reflexes.Size = 0;
1193b4be Poul Sander 2025-02-03 21:28 1874
        BuildReflexes();
1193b4be Poul Sander 2025-02-03 21:28 1875
        BuildEars();
1193b4be Poul Sander 2025-02-03 21:28 1876
1193b4be Poul Sander 2025-02-03 21:28 1877
        // If we still don't have ears, it means geometry is degenerated.
1193b4be Poul Sander 2025-02-03 21:28 1878
        if (_Ears.Size == 0)
1193b4be Poul Sander 2025-02-03 21:28 1879
        {
1193b4be Poul Sander 2025-02-03 21:28 1880
            // Return first triangle available, mimicking the behavior of convex fill.
1193b4be Poul Sander 2025-02-03 21:28 1881
            IM_ASSERT(_TrianglesLeft > 0); // Geometry is degenerated
1193b4be Poul Sander 2025-02-03 21:28 1882
            _Ears.Data[0] = _Nodes;
1193b4be Poul Sander 2025-02-03 21:28 1883
            _Ears.Size    = 1;
1193b4be Poul Sander 2025-02-03 21:28 1884
        }
1193b4be Poul Sander 2025-02-03 21:28 1885
    }
1193b4be Poul Sander 2025-02-03 21:28 1886
1193b4be Poul Sander 2025-02-03 21:28 1887
    ImTriangulatorNode* ear = _Ears.Data[--_Ears.Size];
1193b4be Poul Sander 2025-02-03 21:28 1888
    out_triangle[0] = ear->Prev->Index;
1193b4be Poul Sander 2025-02-03 21:28 1889
    out_triangle[1] = ear->Index;
1193b4be Poul Sander 2025-02-03 21:28 1890
    out_triangle[2] = ear->Next->Index;
1193b4be Poul Sander 2025-02-03 21:28 1891
1193b4be Poul Sander 2025-02-03 21:28 1892
    ear->Unlink();
1193b4be Poul Sander 2025-02-03 21:28 1893
    if (ear == _Nodes)
1193b4be Poul Sander 2025-02-03 21:28 1894
        _Nodes = ear->Next;
1193b4be Poul Sander 2025-02-03 21:28 1895
1193b4be Poul Sander 2025-02-03 21:28 1896
    ReclassifyNode(ear->Prev);
1193b4be Poul Sander 2025-02-03 21:28 1897
    ReclassifyNode(ear->Next);
1193b4be Poul Sander 2025-02-03 21:28 1898
    _TrianglesLeft--;
1193b4be Poul Sander 2025-02-03 21:28 1899
}
1193b4be Poul Sander 2025-02-03 21:28 1900
1193b4be Poul Sander 2025-02-03 21:28 1901
void ImTriangulator::FlipNodeList()
1193b4be Poul Sander 2025-02-03 21:28 1902
{
1193b4be Poul Sander 2025-02-03 21:28 1903
    ImTriangulatorNode* prev = _Nodes;
1193b4be Poul Sander 2025-02-03 21:28 1904
    ImTriangulatorNode* temp = _Nodes;
1193b4be Poul Sander 2025-02-03 21:28 1905
    ImTriangulatorNode* current = _Nodes->Next;
1193b4be Poul Sander 2025-02-03 21:28 1906
    prev->Next = prev;
1193b4be Poul Sander 2025-02-03 21:28 1907
    prev->Prev = prev;
1193b4be Poul Sander 2025-02-03 21:28 1908
    while (current != _Nodes)
1193b4be Poul Sander 2025-02-03 21:28 1909
    {
1193b4be Poul Sander 2025-02-03 21:28 1910
        temp = current->Next;
1193b4be Poul Sander 2025-02-03 21:28 1911
1193b4be Poul Sander 2025-02-03 21:28 1912
        current->Next = prev;
1193b4be Poul Sander 2025-02-03 21:28 1913
        prev->Prev = current;
1193b4be Poul Sander 2025-02-03 21:28 1914
        _Nodes->Next = current;
1193b4be Poul Sander 2025-02-03 21:28 1915
        current->Prev = _Nodes;
1193b4be Poul Sander 2025-02-03 21:28 1916
1193b4be Poul Sander 2025-02-03 21:28 1917
        prev = current;
1193b4be Poul Sander 2025-02-03 21:28 1918
        current = temp;
1193b4be Poul Sander 2025-02-03 21:28 1919
    }
1193b4be Poul Sander 2025-02-03 21:28 1920
    _Nodes = prev;
1193b4be Poul Sander 2025-02-03 21:28 1921
}
1193b4be Poul Sander 2025-02-03 21:28 1922
1193b4be Poul Sander 2025-02-03 21:28 1923
// A triangle is an ear is no other vertex is inside it. We can test reflexes vertices only (see reference algorithm)
1193b4be Poul Sander 2025-02-03 21:28 1924
bool ImTriangulator::IsEar(int i0, int i1, int i2, const ImVec2& v0, const ImVec2& v1, const ImVec2& v2) const
1193b4be Poul Sander 2025-02-03 21:28 1925
{
1193b4be Poul Sander 2025-02-03 21:28 1926
    ImTriangulatorNode** p_end = _Reflexes.Data + _Reflexes.Size;
1193b4be Poul Sander 2025-02-03 21:28 1927
    for (ImTriangulatorNode** p = _Reflexes.Data; p < p_end; p++)
1193b4be Poul Sander 2025-02-03 21:28 1928
    {
1193b4be Poul Sander 2025-02-03 21:28 1929
        ImTriangulatorNode* reflex = *p;
1193b4be Poul Sander 2025-02-03 21:28 1930
        if (reflex->Index != i0 && reflex->Index != i1 && reflex->Index != i2)
1193b4be Poul Sander 2025-02-03 21:28 1931
            if (ImTriangleContainsPoint(v0, v1, v2, reflex->Pos))
1193b4be Poul Sander 2025-02-03 21:28 1932
                return false;
1193b4be Poul Sander 2025-02-03 21:28 1933
    }
1193b4be Poul Sander 2025-02-03 21:28 1934
    return true;
1193b4be Poul Sander 2025-02-03 21:28 1935
}
1193b4be Poul Sander 2025-02-03 21:28 1936
1193b4be Poul Sander 2025-02-03 21:28 1937
void ImTriangulator::ReclassifyNode(ImTriangulatorNode* n1)
1193b4be Poul Sander 2025-02-03 21:28 1938
{
1193b4be Poul Sander 2025-02-03 21:28 1939
    // Classify node
1193b4be Poul Sander 2025-02-03 21:28 1940
    ImTriangulatorNodeType type;
1193b4be Poul Sander 2025-02-03 21:28 1941
    const ImTriangulatorNode* n0 = n1->Prev;
1193b4be Poul Sander 2025-02-03 21:28 1942
    const ImTriangulatorNode* n2 = n1->Next;
1193b4be Poul Sander 2025-02-03 21:28 1943
    if (!ImTriangleIsClockwise(n0->Pos, n1->Pos, n2->Pos))
1193b4be Poul Sander 2025-02-03 21:28 1944
        type = ImTriangulatorNodeType_Reflex;
1193b4be Poul Sander 2025-02-03 21:28 1945
    else if (IsEar(n0->Index, n1->Index, n2->Index, n0->Pos, n1->Pos, n2->Pos))
1193b4be Poul Sander 2025-02-03 21:28 1946
        type = ImTriangulatorNodeType_Ear;
1193b4be Poul Sander 2025-02-03 21:28 1947
    else
1193b4be Poul Sander 2025-02-03 21:28 1948
        type = ImTriangulatorNodeType_Convex;
1193b4be Poul Sander 2025-02-03 21:28 1949
1193b4be Poul Sander 2025-02-03 21:28 1950
    // Update lists when a type changes
1193b4be Poul Sander 2025-02-03 21:28 1951
    if (type == n1->Type)
1193b4be Poul Sander 2025-02-03 21:28 1952
        return;
1193b4be Poul Sander 2025-02-03 21:28 1953
    if (n1->Type == ImTriangulatorNodeType_Reflex)
1193b4be Poul Sander 2025-02-03 21:28 1954
        _Reflexes.find_erase_unsorted(n1->Index);
1193b4be Poul Sander 2025-02-03 21:28 1955
    else if (n1->Type == ImTriangulatorNodeType_Ear)
1193b4be Poul Sander 2025-02-03 21:28 1956
        _Ears.find_erase_unsorted(n1->Index);
1193b4be Poul Sander 2025-02-03 21:28 1957
    if (type == ImTriangulatorNodeType_Reflex)
1193b4be Poul Sander 2025-02-03 21:28 1958
        _Reflexes.push_back(n1);
1193b4be Poul Sander 2025-02-03 21:28 1959
    else if (type == ImTriangulatorNodeType_Ear)
1193b4be Poul Sander 2025-02-03 21:28 1960
        _Ears.push_back(n1);
1193b4be Poul Sander 2025-02-03 21:28 1961
    n1->Type = type;
1193b4be Poul Sander 2025-02-03 21:28 1962
}
1193b4be Poul Sander 2025-02-03 21:28 1963
1193b4be Poul Sander 2025-02-03 21:28 1964
// Use ear-clipping algorithm to triangulate a simple polygon (no self-interaction, no holes).
1193b4be Poul Sander 2025-02-03 21:28 1965
// (Reminder: we don't perform any coarse clipping/culling in ImDrawList layer!
1193b4be Poul Sander 2025-02-03 21:28 1966
// It is up to caller to ensure not making costly calls that will be outside of visible area.
1193b4be Poul Sander 2025-02-03 21:28 1967
// As concave fill is noticeably more expensive than other primitives, be mindful of this...
1193b4be Poul Sander 2025-02-03 21:28 1968
// Caller can build AABB of points, and avoid filling if 'draw_list->_CmdHeader.ClipRect.Overlays(points_bb) == false')
1193b4be Poul Sander 2025-02-03 21:28 1969
void ImDrawList::AddConcavePolyFilled(const ImVec2* points, const int points_count, ImU32 col)
1193b4be Poul Sander 2025-02-03 21:28 1970
{
1193b4be Poul Sander 2025-02-03 21:28 1971
    if (points_count < 3 || (col & IM_COL32_A_MASK) == 0)
1193b4be Poul Sander 2025-02-03 21:28 1972
        return;
1193b4be Poul Sander 2025-02-03 21:28 1973
1193b4be Poul Sander 2025-02-03 21:28 1974
    const ImVec2 uv = _Data->TexUvWhitePixel;
1193b4be Poul Sander 2025-02-03 21:28 1975
    ImTriangulator triangulator;
1193b4be Poul Sander 2025-02-03 21:28 1976
    unsigned int triangle[3];
1193b4be Poul Sander 2025-02-03 21:28 1977
    if (Flags & ImDrawListFlags_AntiAliasedFill)
1193b4be Poul Sander 2025-02-03 21:28 1978
    {
1193b4be Poul Sander 2025-02-03 21:28 1979
        // Anti-aliased Fill
1193b4be Poul Sander 2025-02-03 21:28 1980
        const float AA_SIZE = _FringeScale;
1193b4be Poul Sander 2025-02-03 21:28 1981
        const ImU32 col_trans = col & ~IM_COL32_A_MASK;
1193b4be Poul Sander 2025-02-03 21:28 1982
        const int idx_count = (points_count - 2) * 3 + points_count * 6;
1193b4be Poul Sander 2025-02-03 21:28 1983
        const int vtx_count = (points_count * 2);
1193b4be Poul Sander 2025-02-03 21:28 1984
        PrimReserve(idx_count, vtx_count);
1193b4be Poul Sander 2025-02-03 21:28 1985
1193b4be Poul Sander 2025-02-03 21:28 1986
        // Add indexes for fill
1193b4be Poul Sander 2025-02-03 21:28 1987
        unsigned int vtx_inner_idx = _VtxCurrentIdx;
1193b4be Poul Sander 2025-02-03 21:28 1988
        unsigned int vtx_outer_idx = _VtxCurrentIdx + 1;
1193b4be Poul Sander 2025-02-03 21:28 1989
1193b4be Poul Sander 2025-02-03 21:28 1990
        _Data->TempBuffer.reserve_discard((ImTriangulator::EstimateScratchBufferSize(points_count) + sizeof(ImVec2)) / sizeof(ImVec2));
1193b4be Poul Sander 2025-02-03 21:28 1991
        triangulator.Init(points, points_count, _Data->TempBuffer.Data);
1193b4be Poul Sander 2025-02-03 21:28 1992
        while (triangulator._TrianglesLeft > 0)
1193b4be Poul Sander 2025-02-03 21:28 1993
        {
1193b4be Poul Sander 2025-02-03 21:28 1994
            triangulator.GetNextTriangle(triangle);
1193b4be Poul Sander 2025-02-03 21:28 1995
            _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx + (triangle[0] << 1)); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + (triangle[1] << 1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_inner_idx + (triangle[2] << 1));
1193b4be Poul Sander 2025-02-03 21:28 1996
            _IdxWritePtr += 3;
1193b4be Poul Sander 2025-02-03 21:28 1997
        }
1193b4be Poul Sander 2025-02-03 21:28 1998
1193b4be Poul Sander 2025-02-03 21:28 1999
        // Compute normals
1193b4be Poul Sander 2025-02-03 21:28 2000
        _Data->TempBuffer.reserve_discard(points_count);
1193b4be Poul Sander 2025-02-03 21:28 2001
        ImVec2* temp_normals = _Data->TempBuffer.Data;
1193b4be Poul Sander 2025-02-03 21:28 2002
        for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++)
1193b4be Poul Sander 2025-02-03 21:28 2003
        {
1193b4be Poul Sander 2025-02-03 21:28 2004
            const ImVec2& p0 = points[i0];
1193b4be Poul Sander 2025-02-03 21:28 2005
            const ImVec2& p1 = points[i1];
1193b4be Poul Sander 2025-02-03 21:28 2006
            float dx = p1.x - p0.x;
1193b4be Poul Sander 2025-02-03 21:28 2007
            float dy = p1.y - p0.y;
1193b4be Poul Sander 2025-02-03 21:28 2008
            IM_NORMALIZE2F_OVER_ZERO(dx, dy);
1193b4be Poul Sander 2025-02-03 21:28 2009
            temp_normals[i0].x = dy;
1193b4be Poul Sander 2025-02-03 21:28 2010
            temp_normals[i0].y = -dx;
1193b4be Poul Sander 2025-02-03 21:28 2011
        }
1193b4be Poul Sander 2025-02-03 21:28 2012
1193b4be Poul Sander 2025-02-03 21:28 2013
        for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++)
1193b4be Poul Sander 2025-02-03 21:28 2014
        {
1193b4be Poul Sander 2025-02-03 21:28 2015
            // Average normals
1193b4be Poul Sander 2025-02-03 21:28 2016
            const ImVec2& n0 = temp_normals[i0];
1193b4be Poul Sander 2025-02-03 21:28 2017
            const ImVec2& n1 = temp_normals[i1];
1193b4be Poul Sander 2025-02-03 21:28 2018
            float dm_x = (n0.x + n1.x) * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 2019
            float dm_y = (n0.y + n1.y) * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 2020
            IM_FIXNORMAL2F(dm_x, dm_y);
1193b4be Poul Sander 2025-02-03 21:28 2021
            dm_x *= AA_SIZE * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 2022
            dm_y *= AA_SIZE * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 2023
1193b4be Poul Sander 2025-02-03 21:28 2024
            // Add vertices
1193b4be Poul Sander 2025-02-03 21:28 2025
            _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
1193b4be Poul Sander 2025-02-03 21:28 2026
            _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
1193b4be Poul Sander 2025-02-03 21:28 2027
            _VtxWritePtr += 2;
1193b4be Poul Sander 2025-02-03 21:28 2028
1193b4be Poul Sander 2025-02-03 21:28 2029
            // Add indexes for fringes
1193b4be Poul Sander 2025-02-03 21:28 2030
            _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1)); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + (i0 << 1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1));
1193b4be Poul Sander 2025-02-03 21:28 2031
            _IdxWritePtr[3] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1)); _IdxWritePtr[4] = (ImDrawIdx)(vtx_outer_idx + (i1 << 1)); _IdxWritePtr[5] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1));
1193b4be Poul Sander 2025-02-03 21:28 2032
            _IdxWritePtr += 6;
1193b4be Poul Sander 2025-02-03 21:28 2033
        }
1193b4be Poul Sander 2025-02-03 21:28 2034
        _VtxCurrentIdx += (ImDrawIdx)vtx_count;
1193b4be Poul Sander 2025-02-03 21:28 2035
    }
1193b4be Poul Sander 2025-02-03 21:28 2036
    else
1193b4be Poul Sander 2025-02-03 21:28 2037
    {
1193b4be Poul Sander 2025-02-03 21:28 2038
        // Non Anti-aliased Fill
1193b4be Poul Sander 2025-02-03 21:28 2039
        const int idx_count = (points_count - 2) * 3;
1193b4be Poul Sander 2025-02-03 21:28 2040
        const int vtx_count = points_count;
1193b4be Poul Sander 2025-02-03 21:28 2041
        PrimReserve(idx_count, vtx_count);
1193b4be Poul Sander 2025-02-03 21:28 2042
        for (int i = 0; i < vtx_count; i++)
1193b4be Poul Sander 2025-02-03 21:28 2043
        {
1193b4be Poul Sander 2025-02-03 21:28 2044
            _VtxWritePtr[0].pos = points[i]; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;
1193b4be Poul Sander 2025-02-03 21:28 2045
            _VtxWritePtr++;
1193b4be Poul Sander 2025-02-03 21:28 2046
        }
1193b4be Poul Sander 2025-02-03 21:28 2047
        _Data->TempBuffer.reserve_discard((ImTriangulator::EstimateScratchBufferSize(points_count) + sizeof(ImVec2)) / sizeof(ImVec2));
1193b4be Poul Sander 2025-02-03 21:28 2048
        triangulator.Init(points, points_count, _Data->TempBuffer.Data);
1193b4be Poul Sander 2025-02-03 21:28 2049
        while (triangulator._TrianglesLeft > 0)
1193b4be Poul Sander 2025-02-03 21:28 2050
        {
1193b4be Poul Sander 2025-02-03 21:28 2051
            triangulator.GetNextTriangle(triangle);
1193b4be Poul Sander 2025-02-03 21:28 2052
            _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx + triangle[0]); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx + triangle[1]); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx + triangle[2]);
1193b4be Poul Sander 2025-02-03 21:28 2053
            _IdxWritePtr += 3;
1193b4be Poul Sander 2025-02-03 21:28 2054
        }
1193b4be Poul Sander 2025-02-03 21:28 2055
        _VtxCurrentIdx += (ImDrawIdx)vtx_count;
1193b4be Poul Sander 2025-02-03 21:28 2056
    }
1193b4be Poul Sander 2025-02-03 21:28 2057
}
1193b4be Poul Sander 2025-02-03 21:28 2058
1193b4be Poul Sander 2025-02-03 21:28 2059
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 2060
// [SECTION] ImDrawListSplitter
1193b4be Poul Sander 2025-02-03 21:28 2061
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 2062
// FIXME: This may be a little confusing, trying to be a little too low-level/optimal instead of just doing vector swap..
1193b4be Poul Sander 2025-02-03 21:28 2063
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 2064
1193b4be Poul Sander 2025-02-03 21:28 2065
void ImDrawListSplitter::ClearFreeMemory()
1193b4be Poul Sander 2025-02-03 21:28 2066
{
1193b4be Poul Sander 2025-02-03 21:28 2067
    for (int i = 0; i < _Channels.Size; i++)
1193b4be Poul Sander 2025-02-03 21:28 2068
    {
1193b4be Poul Sander 2025-02-03 21:28 2069
        if (i == _Current)
1193b4be Poul Sander 2025-02-03 21:28 2070
            memset(&_Channels[i], 0, sizeof(_Channels[i]));  // Current channel is a copy of CmdBuffer/IdxBuffer, don't destruct again
1193b4be Poul Sander 2025-02-03 21:28 2071
        _Channels[i]._CmdBuffer.clear();
1193b4be Poul Sander 2025-02-03 21:28 2072
        _Channels[i]._IdxBuffer.clear();
1193b4be Poul Sander 2025-02-03 21:28 2073
    }
1193b4be Poul Sander 2025-02-03 21:28 2074
    _Current = 0;
1193b4be Poul Sander 2025-02-03 21:28 2075
    _Count = 1;
1193b4be Poul Sander 2025-02-03 21:28 2076
    _Channels.clear();
1193b4be Poul Sander 2025-02-03 21:28 2077
}
1193b4be Poul Sander 2025-02-03 21:28 2078
1193b4be Poul Sander 2025-02-03 21:28 2079
void ImDrawListSplitter::Split(ImDrawList* draw_list, int channels_count)
1193b4be Poul Sander 2025-02-03 21:28 2080
{
1193b4be Poul Sander 2025-02-03 21:28 2081
    IM_UNUSED(draw_list);
1193b4be Poul Sander 2025-02-03 21:28 2082
    IM_ASSERT(_Current == 0 && _Count <= 1 && "Nested channel splitting is not supported. Please use separate instances of ImDrawListSplitter.");
1193b4be Poul Sander 2025-02-03 21:28 2083
    int old_channels_count = _Channels.Size;
1193b4be Poul Sander 2025-02-03 21:28 2084
    if (old_channels_count < channels_count)
1193b4be Poul Sander 2025-02-03 21:28 2085
    {
1193b4be Poul Sander 2025-02-03 21:28 2086
        _Channels.reserve(channels_count); // Avoid over reserving since this is likely to stay stable
1193b4be Poul Sander 2025-02-03 21:28 2087
        _Channels.resize(channels_count);
1193b4be Poul Sander 2025-02-03 21:28 2088
    }
1193b4be Poul Sander 2025-02-03 21:28 2089
    _Count = channels_count;
1193b4be Poul Sander 2025-02-03 21:28 2090
1193b4be Poul Sander 2025-02-03 21:28 2091
    // Channels[] (24/32 bytes each) hold storage that we'll swap with draw_list->_CmdBuffer/_IdxBuffer
1193b4be Poul Sander 2025-02-03 21:28 2092
    // 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.
1193b4be Poul Sander 2025-02-03 21:28 2093
    // 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
1193b4be Poul Sander 2025-02-03 21:28 2094
    memset(&_Channels[0], 0, sizeof(ImDrawChannel));
1193b4be Poul Sander 2025-02-03 21:28 2095
    for (int i = 1; i < channels_count; i++)
1193b4be Poul Sander 2025-02-03 21:28 2096
    {
1193b4be Poul Sander 2025-02-03 21:28 2097
        if (i >= old_channels_count)
1193b4be Poul Sander 2025-02-03 21:28 2098
        {
1193b4be Poul Sander 2025-02-03 21:28 2099
            IM_PLACEMENT_NEW(&_Channels[i]) ImDrawChannel();
1193b4be Poul Sander 2025-02-03 21:28 2100
        }
1193b4be Poul Sander 2025-02-03 21:28 2101
        else
1193b4be Poul Sander 2025-02-03 21:28 2102
        {
1193b4be Poul Sander 2025-02-03 21:28 2103
            _Channels[i]._CmdBuffer.resize(0);
1193b4be Poul Sander 2025-02-03 21:28 2104
            _Channels[i]._IdxBuffer.resize(0);
1193b4be Poul Sander 2025-02-03 21:28 2105
        }
1193b4be Poul Sander 2025-02-03 21:28 2106
    }
1193b4be Poul Sander 2025-02-03 21:28 2107
}
1193b4be Poul Sander 2025-02-03 21:28 2108
1193b4be Poul Sander 2025-02-03 21:28 2109
void ImDrawListSplitter::Merge(ImDrawList* draw_list)
1193b4be Poul Sander 2025-02-03 21:28 2110
{
1193b4be Poul Sander 2025-02-03 21:28 2111
    // 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.
1193b4be Poul Sander 2025-02-03 21:28 2112
    if (_Count <= 1)
1193b4be Poul Sander 2025-02-03 21:28 2113
        return;
1193b4be Poul Sander 2025-02-03 21:28 2114
1193b4be Poul Sander 2025-02-03 21:28 2115
    SetCurrentChannel(draw_list, 0);
1193b4be Poul Sander 2025-02-03 21:28 2116
    draw_list->_PopUnusedDrawCmd();
1193b4be Poul Sander 2025-02-03 21:28 2117
1193b4be Poul Sander 2025-02-03 21:28 2118
    // Calculate our final buffer sizes. Also fix the incorrect IdxOffset values in each command.
1193b4be Poul Sander 2025-02-03 21:28 2119
    int new_cmd_buffer_count = 0;
1193b4be Poul Sander 2025-02-03 21:28 2120
    int new_idx_buffer_count = 0;
1193b4be Poul Sander 2025-02-03 21:28 2121
    ImDrawCmd* last_cmd = (_Count > 0 && draw_list->CmdBuffer.Size > 0) ? &draw_list->CmdBuffer.back() : NULL;
1193b4be Poul Sander 2025-02-03 21:28 2122
    int idx_offset = last_cmd ? last_cmd->IdxOffset + last_cmd->ElemCount : 0;
1193b4be Poul Sander 2025-02-03 21:28 2123
    for (int i = 1; i < _Count; i++)
1193b4be Poul Sander 2025-02-03 21:28 2124
    {
1193b4be Poul Sander 2025-02-03 21:28 2125
        ImDrawChannel& ch = _Channels[i];
1193b4be Poul Sander 2025-02-03 21:28 2126
        if (ch._CmdBuffer.Size > 0 && ch._CmdBuffer.back().ElemCount == 0 && ch._CmdBuffer.back().UserCallback == NULL) // Equivalent of PopUnusedDrawCmd()
1193b4be Poul Sander 2025-02-03 21:28 2127
            ch._CmdBuffer.pop_back();
1193b4be Poul Sander 2025-02-03 21:28 2128
1193b4be Poul Sander 2025-02-03 21:28 2129
        if (ch._CmdBuffer.Size > 0 && last_cmd != NULL)
1193b4be Poul Sander 2025-02-03 21:28 2130
        {
1193b4be Poul Sander 2025-02-03 21:28 2131
            // Do not include ImDrawCmd_AreSequentialIdxOffset() in the compare as we rebuild IdxOffset values ourselves.
1193b4be Poul Sander 2025-02-03 21:28 2132
            // Manipulating IdxOffset (e.g. by reordering draw commands like done by RenderDimmedBackgroundBehindWindow()) is not supported within a splitter.
1193b4be Poul Sander 2025-02-03 21:28 2133
            ImDrawCmd* next_cmd = &ch._CmdBuffer[0];
1193b4be Poul Sander 2025-02-03 21:28 2134
            if (ImDrawCmd_HeaderCompare(last_cmd, next_cmd) == 0 && last_cmd->UserCallback == NULL && next_cmd->UserCallback == NULL)
1193b4be Poul Sander 2025-02-03 21:28 2135
            {
1193b4be Poul Sander 2025-02-03 21:28 2136
                // Merge previous channel last draw command with current channel first draw command if matching.
1193b4be Poul Sander 2025-02-03 21:28 2137
                last_cmd->ElemCount += next_cmd->ElemCount;
1193b4be Poul Sander 2025-02-03 21:28 2138
                idx_offset += next_cmd->ElemCount;
1193b4be Poul Sander 2025-02-03 21:28 2139
                ch._CmdBuffer.erase(ch._CmdBuffer.Data); // FIXME-OPT: Improve for multiple merges.
1193b4be Poul Sander 2025-02-03 21:28 2140
            }
1193b4be Poul Sander 2025-02-03 21:28 2141
        }
1193b4be Poul Sander 2025-02-03 21:28 2142
        if (ch._CmdBuffer.Size > 0)
1193b4be Poul Sander 2025-02-03 21:28 2143
            last_cmd = &ch._CmdBuffer.back();
1193b4be Poul Sander 2025-02-03 21:28 2144
        new_cmd_buffer_count += ch._CmdBuffer.Size;
1193b4be Poul Sander 2025-02-03 21:28 2145
        new_idx_buffer_count += ch._IdxBuffer.Size;
1193b4be Poul Sander 2025-02-03 21:28 2146
        for (int cmd_n = 0; cmd_n < ch._CmdBuffer.Size; cmd_n++)
1193b4be Poul Sander 2025-02-03 21:28 2147
        {
1193b4be Poul Sander 2025-02-03 21:28 2148
            ch._CmdBuffer.Data[cmd_n].IdxOffset = idx_offset;
1193b4be Poul Sander 2025-02-03 21:28 2149
            idx_offset += ch._CmdBuffer.Data[cmd_n].ElemCount;
1193b4be Poul Sander 2025-02-03 21:28 2150
        }
1193b4be Poul Sander 2025-02-03 21:28 2151
    }
1193b4be Poul Sander 2025-02-03 21:28 2152
    draw_list->CmdBuffer.resize(draw_list->CmdBuffer.Size + new_cmd_buffer_count);
1193b4be Poul Sander 2025-02-03 21:28 2153
    draw_list->IdxBuffer.resize(draw_list->IdxBuffer.Size + new_idx_buffer_count);
1193b4be Poul Sander 2025-02-03 21:28 2154
1193b4be Poul Sander 2025-02-03 21:28 2155
    // Write commands and indices in order (they are fairly small structures, we don't copy vertices only indices)
1193b4be Poul Sander 2025-02-03 21:28 2156
    ImDrawCmd* cmd_write = draw_list->CmdBuffer.Data + draw_list->CmdBuffer.Size - new_cmd_buffer_count;
1193b4be Poul Sander 2025-02-03 21:28 2157
    ImDrawIdx* idx_write = draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size - new_idx_buffer_count;
1193b4be Poul Sander 2025-02-03 21:28 2158
    for (int i = 1; i < _Count; i++)
1193b4be Poul Sander 2025-02-03 21:28 2159
    {
1193b4be Poul Sander 2025-02-03 21:28 2160
        ImDrawChannel& ch = _Channels[i];
1193b4be Poul Sander 2025-02-03 21:28 2161
        if (int sz = ch._CmdBuffer.Size) { memcpy(cmd_write, ch._CmdBuffer.Data, sz * sizeof(ImDrawCmd)); cmd_write += sz; }
1193b4be Poul Sander 2025-02-03 21:28 2162
        if (int sz = ch._IdxBuffer.Size) { memcpy(idx_write, ch._IdxBuffer.Data, sz * sizeof(ImDrawIdx)); idx_write += sz; }
1193b4be Poul Sander 2025-02-03 21:28 2163
    }
1193b4be Poul Sander 2025-02-03 21:28 2164
    draw_list->_IdxWritePtr = idx_write;
1193b4be Poul Sander 2025-02-03 21:28 2165
1193b4be Poul Sander 2025-02-03 21:28 2166
    // Ensure there's always a non-callback draw command trailing the command-buffer
1193b4be Poul Sander 2025-02-03 21:28 2167
    if (draw_list->CmdBuffer.Size == 0 || draw_list->CmdBuffer.back().UserCallback != NULL)
1193b4be Poul Sander 2025-02-03 21:28 2168
        draw_list->AddDrawCmd();
1193b4be Poul Sander 2025-02-03 21:28 2169
1193b4be Poul Sander 2025-02-03 21:28 2170
    // If current command is used with different settings we need to add a new command
1193b4be Poul Sander 2025-02-03 21:28 2171
    ImDrawCmd* curr_cmd = &draw_list->CmdBuffer.Data[draw_list->CmdBuffer.Size - 1];
1193b4be Poul Sander 2025-02-03 21:28 2172
    if (curr_cmd->ElemCount == 0)
1193b4be Poul Sander 2025-02-03 21:28 2173
        ImDrawCmd_HeaderCopy(curr_cmd, &draw_list->_CmdHeader); // Copy ClipRect, TextureId, VtxOffset
1193b4be Poul Sander 2025-02-03 21:28 2174
    else if (ImDrawCmd_HeaderCompare(curr_cmd, &draw_list->_CmdHeader) != 0)
1193b4be Poul Sander 2025-02-03 21:28 2175
        draw_list->AddDrawCmd();
1193b4be Poul Sander 2025-02-03 21:28 2176
1193b4be Poul Sander 2025-02-03 21:28 2177
    _Count = 1;
1193b4be Poul Sander 2025-02-03 21:28 2178
}
1193b4be Poul Sander 2025-02-03 21:28 2179
1193b4be Poul Sander 2025-02-03 21:28 2180
void ImDrawListSplitter::SetCurrentChannel(ImDrawList* draw_list, int idx)
1193b4be Poul Sander 2025-02-03 21:28 2181
{
1193b4be Poul Sander 2025-02-03 21:28 2182
    IM_ASSERT(idx >= 0 && idx < _Count);
1193b4be Poul Sander 2025-02-03 21:28 2183
    if (_Current == idx)
1193b4be Poul Sander 2025-02-03 21:28 2184
        return;
1193b4be Poul Sander 2025-02-03 21:28 2185
1193b4be Poul Sander 2025-02-03 21:28 2186
    // Overwrite ImVector (12/16 bytes), four times. This is merely a silly optimization instead of doing .swap()
1193b4be Poul Sander 2025-02-03 21:28 2187
    memcpy(&_Channels.Data[_Current]._CmdBuffer, &draw_list->CmdBuffer, sizeof(draw_list->CmdBuffer));
1193b4be Poul Sander 2025-02-03 21:28 2188
    memcpy(&_Channels.Data[_Current]._IdxBuffer, &draw_list->IdxBuffer, sizeof(draw_list->IdxBuffer));
1193b4be Poul Sander 2025-02-03 21:28 2189
    _Current = idx;
1193b4be Poul Sander 2025-02-03 21:28 2190
    memcpy(&draw_list->CmdBuffer, &_Channels.Data[idx]._CmdBuffer, sizeof(draw_list->CmdBuffer));
1193b4be Poul Sander 2025-02-03 21:28 2191
    memcpy(&draw_list->IdxBuffer, &_Channels.Data[idx]._IdxBuffer, sizeof(draw_list->IdxBuffer));
1193b4be Poul Sander 2025-02-03 21:28 2192
    draw_list->_IdxWritePtr = draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size;
1193b4be Poul Sander 2025-02-03 21:28 2193
1193b4be Poul Sander 2025-02-03 21:28 2194
    // If current command is used with different settings we need to add a new command
1193b4be Poul Sander 2025-02-03 21:28 2195
    ImDrawCmd* curr_cmd = (draw_list->CmdBuffer.Size == 0) ? NULL : &draw_list->CmdBuffer.Data[draw_list->CmdBuffer.Size - 1];
1193b4be Poul Sander 2025-02-03 21:28 2196
    if (curr_cmd == NULL)
1193b4be Poul Sander 2025-02-03 21:28 2197
        draw_list->AddDrawCmd();
1193b4be Poul Sander 2025-02-03 21:28 2198
    else if (curr_cmd->ElemCount == 0)
1193b4be Poul Sander 2025-02-03 21:28 2199
        ImDrawCmd_HeaderCopy(curr_cmd, &draw_list->_CmdHeader); // Copy ClipRect, TextureId, VtxOffset
1193b4be Poul Sander 2025-02-03 21:28 2200
    else if (ImDrawCmd_HeaderCompare(curr_cmd, &draw_list->_CmdHeader) != 0)
1193b4be Poul Sander 2025-02-03 21:28 2201
        draw_list->AddDrawCmd();
1193b4be Poul Sander 2025-02-03 21:28 2202
}
1193b4be Poul Sander 2025-02-03 21:28 2203
1193b4be Poul Sander 2025-02-03 21:28 2204
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 2205
// [SECTION] ImDrawData
1193b4be Poul Sander 2025-02-03 21:28 2206
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 2207
1193b4be Poul Sander 2025-02-03 21:28 2208
void ImDrawData::Clear()
1193b4be Poul Sander 2025-02-03 21:28 2209
{
1193b4be Poul Sander 2025-02-03 21:28 2210
    Valid = false;
1193b4be Poul Sander 2025-02-03 21:28 2211
    CmdListsCount = TotalIdxCount = TotalVtxCount = 0;
1193b4be Poul Sander 2025-02-03 21:28 2212
    CmdLists.resize(0); // The ImDrawList are NOT owned by ImDrawData but e.g. by ImGuiContext, so we don't clear them.
1193b4be Poul Sander 2025-02-03 21:28 2213
    DisplayPos = DisplaySize = FramebufferScale = ImVec2(0.0f, 0.0f);
1193b4be Poul Sander 2025-02-03 21:28 2214
    OwnerViewport = NULL;
1193b4be Poul Sander 2025-02-03 21:28 2215
}
1193b4be Poul Sander 2025-02-03 21:28 2216
1193b4be Poul Sander 2025-02-03 21:28 2217
// Important: 'out_list' is generally going to be draw_data->CmdLists, but may be another temporary list
1193b4be Poul Sander 2025-02-03 21:28 2218
// as long at it is expected that the result will be later merged into draw_data->CmdLists[].
1193b4be Poul Sander 2025-02-03 21:28 2219
void ImGui::AddDrawListToDrawDataEx(ImDrawData* draw_data, ImVector<ImDrawList*>* out_list, ImDrawList* draw_list)
1193b4be Poul Sander 2025-02-03 21:28 2220
{
1193b4be Poul Sander 2025-02-03 21:28 2221
    if (draw_list->CmdBuffer.Size == 0)
1193b4be Poul Sander 2025-02-03 21:28 2222
        return;
1193b4be Poul Sander 2025-02-03 21:28 2223
    if (draw_list->CmdBuffer.Size == 1 && draw_list->CmdBuffer[0].ElemCount == 0 && draw_list->CmdBuffer[0].UserCallback == NULL)
1193b4be Poul Sander 2025-02-03 21:28 2224
        return;
1193b4be Poul Sander 2025-02-03 21:28 2225
1193b4be Poul Sander 2025-02-03 21:28 2226
    // Draw list sanity check. Detect mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc.
1193b4be Poul Sander 2025-02-03 21:28 2227
    // May trigger for you if you are using PrimXXX functions incorrectly.
1193b4be Poul Sander 2025-02-03 21:28 2228
    IM_ASSERT(draw_list->VtxBuffer.Size == 0 || draw_list->_VtxWritePtr == draw_list->VtxBuffer.Data + draw_list->VtxBuffer.Size);
1193b4be Poul Sander 2025-02-03 21:28 2229
    IM_ASSERT(draw_list->IdxBuffer.Size == 0 || draw_list->_IdxWritePtr == draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size);
1193b4be Poul Sander 2025-02-03 21:28 2230
    if (!(draw_list->Flags & ImDrawListFlags_AllowVtxOffset))
1193b4be Poul Sander 2025-02-03 21:28 2231
        IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size);
1193b4be Poul Sander 2025-02-03 21:28 2232
1193b4be Poul Sander 2025-02-03 21:28 2233
    // Check that draw_list doesn't use more vertices than indexable (default ImDrawIdx = unsigned short = 2 bytes = 64K vertices per ImDrawList = per window)
1193b4be Poul Sander 2025-02-03 21:28 2234
    // If this assert triggers because you are drawing lots of stuff manually:
1193b4be Poul Sander 2025-02-03 21:28 2235
    // - First, make sure you are coarse clipping yourself and not trying to draw many things outside visible bounds.
1193b4be Poul Sander 2025-02-03 21:28 2236
    //   Be mindful that the lower-level ImDrawList API doesn't filter vertices. Use the Metrics/Debugger window to inspect draw list contents.
1193b4be Poul Sander 2025-02-03 21:28 2237
    // - If you want large meshes with more than 64K vertices, you can either:
1193b4be Poul Sander 2025-02-03 21:28 2238
    //   (A) Handle the ImDrawCmd::VtxOffset value in your renderer backend, and set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset'.
1193b4be Poul Sander 2025-02-03 21:28 2239
    //       Most example backends already support this from 1.71. Pre-1.71 backends won't.
1193b4be Poul Sander 2025-02-03 21:28 2240
    //       Some graphics API such as GL ES 1/2 don't have a way to offset the starting vertex so it is not supported for them.
1193b4be Poul Sander 2025-02-03 21:28 2241
    //   (B) Or handle 32-bit indices in your renderer backend, and uncomment '#define ImDrawIdx unsigned int' line in imconfig.h.
1193b4be Poul Sander 2025-02-03 21:28 2242
    //       Most example backends already support this. For example, the OpenGL example code detect index size at compile-time:
1193b4be Poul Sander 2025-02-03 21:28 2243
    //         glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset);
1193b4be Poul Sander 2025-02-03 21:28 2244
    //       Your own engine or render API may use different parameters or function calls to specify index sizes.
1193b4be Poul Sander 2025-02-03 21:28 2245
    //       2 and 4 bytes indices are generally supported by most graphics API.
1193b4be Poul Sander 2025-02-03 21:28 2246
    // - If for some reason neither of those solutions works for you, a workaround is to call BeginChild()/EndChild() before reaching
1193b4be Poul Sander 2025-02-03 21:28 2247
    //   the 64K limit to split your draw commands in multiple draw lists.
1193b4be Poul Sander 2025-02-03 21:28 2248
    if (sizeof(ImDrawIdx) == 2)
1193b4be Poul Sander 2025-02-03 21:28 2249
        IM_ASSERT(draw_list->_VtxCurrentIdx < (1 << 16) && "Too many vertices in ImDrawList using 16-bit indices. Read comment above");
1193b4be Poul Sander 2025-02-03 21:28 2250
1193b4be Poul Sander 2025-02-03 21:28 2251
    // Resolve callback data pointers
1193b4be Poul Sander 2025-02-03 21:28 2252
    if (draw_list->_CallbacksDataBuf.Size > 0)
1193b4be Poul Sander 2025-02-03 21:28 2253
        for (ImDrawCmd& cmd : draw_list->CmdBuffer)
1193b4be Poul Sander 2025-02-03 21:28 2254
            if (cmd.UserCallback != NULL && cmd.UserCallbackDataOffset != -1 && cmd.UserCallbackDataSize > 0)
1193b4be Poul Sander 2025-02-03 21:28 2255
                cmd.UserCallbackData = draw_list->_CallbacksDataBuf.Data + cmd.UserCallbackDataOffset;
1193b4be Poul Sander 2025-02-03 21:28 2256
1193b4be Poul Sander 2025-02-03 21:28 2257
    // Add to output list + records state in ImDrawData
1193b4be Poul Sander 2025-02-03 21:28 2258
    out_list->push_back(draw_list);
1193b4be Poul Sander 2025-02-03 21:28 2259
    draw_data->CmdListsCount++;
1193b4be Poul Sander 2025-02-03 21:28 2260
    draw_data->TotalVtxCount += draw_list->VtxBuffer.Size;
1193b4be Poul Sander 2025-02-03 21:28 2261
    draw_data->TotalIdxCount += draw_list->IdxBuffer.Size;
1193b4be Poul Sander 2025-02-03 21:28 2262
}
1193b4be Poul Sander 2025-02-03 21:28 2263
1193b4be Poul Sander 2025-02-03 21:28 2264
void ImDrawData::AddDrawList(ImDrawList* draw_list)
1193b4be Poul Sander 2025-02-03 21:28 2265
{
1193b4be Poul Sander 2025-02-03 21:28 2266
    IM_ASSERT(CmdLists.Size == CmdListsCount);
1193b4be Poul Sander 2025-02-03 21:28 2267
    draw_list->_PopUnusedDrawCmd();
1193b4be Poul Sander 2025-02-03 21:28 2268
    ImGui::AddDrawListToDrawDataEx(this, &CmdLists, draw_list);
1193b4be Poul Sander 2025-02-03 21:28 2269
}
1193b4be Poul Sander 2025-02-03 21:28 2270
1193b4be Poul Sander 2025-02-03 21:28 2271
// For backward compatibility: convert all buffers from indexed to de-indexed, in case you cannot render indexed. Note: this is slow and most likely a waste of resources. Always prefer indexed rendering!
1193b4be Poul Sander 2025-02-03 21:28 2272
void ImDrawData::DeIndexAllBuffers()
1193b4be Poul Sander 2025-02-03 21:28 2273
{
1193b4be Poul Sander 2025-02-03 21:28 2274
    ImVector<ImDrawVert> new_vtx_buffer;
1193b4be Poul Sander 2025-02-03 21:28 2275
    TotalVtxCount = TotalIdxCount = 0;
1193b4be Poul Sander 2025-02-03 21:28 2276
    for (int i = 0; i < CmdListsCount; i++)
1193b4be Poul Sander 2025-02-03 21:28 2277
    {
1193b4be Poul Sander 2025-02-03 21:28 2278
        ImDrawList* cmd_list = CmdLists[i];
1193b4be Poul Sander 2025-02-03 21:28 2279
        if (cmd_list->IdxBuffer.empty())
1193b4be Poul Sander 2025-02-03 21:28 2280
            continue;
1193b4be Poul Sander 2025-02-03 21:28 2281
        new_vtx_buffer.resize(cmd_list->IdxBuffer.Size);
1193b4be Poul Sander 2025-02-03 21:28 2282
        for (int j = 0; j < cmd_list->IdxBuffer.Size; j++)
1193b4be Poul Sander 2025-02-03 21:28 2283
            new_vtx_buffer[j] = cmd_list->VtxBuffer[cmd_list->IdxBuffer[j]];
1193b4be Poul Sander 2025-02-03 21:28 2284
        cmd_list->VtxBuffer.swap(new_vtx_buffer);
1193b4be Poul Sander 2025-02-03 21:28 2285
        cmd_list->IdxBuffer.resize(0);
1193b4be Poul Sander 2025-02-03 21:28 2286
        TotalVtxCount += cmd_list->VtxBuffer.Size;
1193b4be Poul Sander 2025-02-03 21:28 2287
    }
1193b4be Poul Sander 2025-02-03 21:28 2288
}
1193b4be Poul Sander 2025-02-03 21:28 2289
1193b4be Poul Sander 2025-02-03 21:28 2290
// Helper to scale the ClipRect field of each ImDrawCmd.
1193b4be Poul Sander 2025-02-03 21:28 2291
// Use if your final output buffer is at a different scale than draw_data->DisplaySize,
1193b4be Poul Sander 2025-02-03 21:28 2292
// or if there is a difference between your window resolution and framebuffer resolution.
1193b4be Poul Sander 2025-02-03 21:28 2293
void ImDrawData::ScaleClipRects(const ImVec2& fb_scale)
1193b4be Poul Sander 2025-02-03 21:28 2294
{
1193b4be Poul Sander 2025-02-03 21:28 2295
    for (ImDrawList* draw_list : CmdLists)
1193b4be Poul Sander 2025-02-03 21:28 2296
        for (ImDrawCmd& cmd : draw_list->CmdBuffer)
1193b4be Poul Sander 2025-02-03 21:28 2297
            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);
1193b4be Poul Sander 2025-02-03 21:28 2298
}
1193b4be Poul Sander 2025-02-03 21:28 2299
1193b4be Poul Sander 2025-02-03 21:28 2300
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 2301
// [SECTION] Helpers ShadeVertsXXX functions
1193b4be Poul Sander 2025-02-03 21:28 2302
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 2303
1193b4be Poul Sander 2025-02-03 21:28 2304
// Generic linear color gradient, write to RGB fields, leave A untouched.
1193b4be Poul Sander 2025-02-03 21:28 2305
void ImGui::ShadeVertsLinearColorGradientKeepAlpha(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1)
1193b4be Poul Sander 2025-02-03 21:28 2306
{
1193b4be Poul Sander 2025-02-03 21:28 2307
    ImVec2 gradient_extent = gradient_p1 - gradient_p0;
1193b4be Poul Sander 2025-02-03 21:28 2308
    float gradient_inv_length2 = 1.0f / ImLengthSqr(gradient_extent);
1193b4be Poul Sander 2025-02-03 21:28 2309
    ImDrawVert* vert_start = draw_list->VtxBuffer.Data + vert_start_idx;
1193b4be Poul Sander 2025-02-03 21:28 2310
    ImDrawVert* vert_end = draw_list->VtxBuffer.Data + vert_end_idx;
1193b4be Poul Sander 2025-02-03 21:28 2311
    const int col0_r = (int)(col0 >> IM_COL32_R_SHIFT) & 0xFF;
1193b4be Poul Sander 2025-02-03 21:28 2312
    const int col0_g = (int)(col0 >> IM_COL32_G_SHIFT) & 0xFF;
1193b4be Poul Sander 2025-02-03 21:28 2313
    const int col0_b = (int)(col0 >> IM_COL32_B_SHIFT) & 0xFF;
1193b4be Poul Sander 2025-02-03 21:28 2314
    const int col_delta_r = ((int)(col1 >> IM_COL32_R_SHIFT) & 0xFF) - col0_r;
1193b4be Poul Sander 2025-02-03 21:28 2315
    const int col_delta_g = ((int)(col1 >> IM_COL32_G_SHIFT) & 0xFF) - col0_g;
1193b4be Poul Sander 2025-02-03 21:28 2316
    const int col_delta_b = ((int)(col1 >> IM_COL32_B_SHIFT) & 0xFF) - col0_b;
1193b4be Poul Sander 2025-02-03 21:28 2317
    for (ImDrawVert* vert = vert_start; vert < vert_end; vert++)
1193b4be Poul Sander 2025-02-03 21:28 2318
    {
1193b4be Poul Sander 2025-02-03 21:28 2319
        float d = ImDot(vert->pos - gradient_p0, gradient_extent);
1193b4be Poul Sander 2025-02-03 21:28 2320
        float t = ImClamp(d * gradient_inv_length2, 0.0f, 1.0f);
1193b4be Poul Sander 2025-02-03 21:28 2321
        int r = (int)(col0_r + col_delta_r * t);
1193b4be Poul Sander 2025-02-03 21:28 2322
        int g = (int)(col0_g + col_delta_g * t);
1193b4be Poul Sander 2025-02-03 21:28 2323
        int b = (int)(col0_b + col_delta_b * t);
1193b4be Poul Sander 2025-02-03 21:28 2324
        vert->col = (r << IM_COL32_R_SHIFT) | (g << IM_COL32_G_SHIFT) | (b << IM_COL32_B_SHIFT) | (vert->col & IM_COL32_A_MASK);
1193b4be Poul Sander 2025-02-03 21:28 2325
    }
1193b4be Poul Sander 2025-02-03 21:28 2326
}
1193b4be Poul Sander 2025-02-03 21:28 2327
1193b4be Poul Sander 2025-02-03 21:28 2328
// Distribute UV over (a, b) rectangle
1193b4be Poul Sander 2025-02-03 21:28 2329
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)
1193b4be Poul Sander 2025-02-03 21:28 2330
{
1193b4be Poul Sander 2025-02-03 21:28 2331
    const ImVec2 size = b - a;
1193b4be Poul Sander 2025-02-03 21:28 2332
    const ImVec2 uv_size = uv_b - uv_a;
1193b4be Poul Sander 2025-02-03 21:28 2333
    const ImVec2 scale = ImVec2(
1193b4be Poul Sander 2025-02-03 21:28 2334
        size.x != 0.0f ? (uv_size.x / size.x) : 0.0f,
1193b4be Poul Sander 2025-02-03 21:28 2335
        size.y != 0.0f ? (uv_size.y / size.y) : 0.0f);
1193b4be Poul Sander 2025-02-03 21:28 2336
1193b4be Poul Sander 2025-02-03 21:28 2337
    ImDrawVert* vert_start = draw_list->VtxBuffer.Data + vert_start_idx;
1193b4be Poul Sander 2025-02-03 21:28 2338
    ImDrawVert* vert_end = draw_list->VtxBuffer.Data + vert_end_idx;
1193b4be Poul Sander 2025-02-03 21:28 2339
    if (clamp)
1193b4be Poul Sander 2025-02-03 21:28 2340
    {
1193b4be Poul Sander 2025-02-03 21:28 2341
        const ImVec2 min = ImMin(uv_a, uv_b);
1193b4be Poul Sander 2025-02-03 21:28 2342
        const ImVec2 max = ImMax(uv_a, uv_b);
1193b4be Poul Sander 2025-02-03 21:28 2343
        for (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex)
1193b4be Poul Sander 2025-02-03 21:28 2344
            vertex->uv = ImClamp(uv_a + ImMul(ImVec2(vertex->pos.x, vertex->pos.y) - a, scale), min, max);
1193b4be Poul Sander 2025-02-03 21:28 2345
    }
1193b4be Poul Sander 2025-02-03 21:28 2346
    else
1193b4be Poul Sander 2025-02-03 21:28 2347
    {
1193b4be Poul Sander 2025-02-03 21:28 2348
        for (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex)
1193b4be Poul Sander 2025-02-03 21:28 2349
            vertex->uv = uv_a + ImMul(ImVec2(vertex->pos.x, vertex->pos.y) - a, scale);
1193b4be Poul Sander 2025-02-03 21:28 2350
    }
1193b4be Poul Sander 2025-02-03 21:28 2351
}
1193b4be Poul Sander 2025-02-03 21:28 2352
1193b4be Poul Sander 2025-02-03 21:28 2353
void ImGui::ShadeVertsTransformPos(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, const ImVec2& pivot_in, float cos_a, float sin_a, const ImVec2& pivot_out)
1193b4be Poul Sander 2025-02-03 21:28 2354
{
1193b4be Poul Sander 2025-02-03 21:28 2355
    ImDrawVert* vert_start = draw_list->VtxBuffer.Data + vert_start_idx;
1193b4be Poul Sander 2025-02-03 21:28 2356
    ImDrawVert* vert_end = draw_list->VtxBuffer.Data + vert_end_idx;
1193b4be Poul Sander 2025-02-03 21:28 2357
    for (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex)
1193b4be Poul Sander 2025-02-03 21:28 2358
        vertex->pos = ImRotate(vertex->pos- pivot_in, cos_a, sin_a) + pivot_out;
1193b4be Poul Sander 2025-02-03 21:28 2359
}
1193b4be Poul Sander 2025-02-03 21:28 2360
1193b4be Poul Sander 2025-02-03 21:28 2361
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 2362
// [SECTION] ImFontConfig
1193b4be Poul Sander 2025-02-03 21:28 2363
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 2364
1193b4be Poul Sander 2025-02-03 21:28 2365
ImFontConfig::ImFontConfig()
1193b4be Poul Sander 2025-02-03 21:28 2366
{
1193b4be Poul Sander 2025-02-03 21:28 2367
    memset(this, 0, sizeof(*this));
1193b4be Poul Sander 2025-02-03 21:28 2368
    FontDataOwnedByAtlas = true;
1193b4be Poul Sander 2025-02-03 21:28 2369
    OversampleH = 2;
1193b4be Poul Sander 2025-02-03 21:28 2370
    OversampleV = 1;
1193b4be Poul Sander 2025-02-03 21:28 2371
    GlyphMaxAdvanceX = FLT_MAX;
1193b4be Poul Sander 2025-02-03 21:28 2372
    RasterizerMultiply = 1.0f;
1193b4be Poul Sander 2025-02-03 21:28 2373
    RasterizerDensity = 1.0f;
1193b4be Poul Sander 2025-02-03 21:28 2374
    EllipsisChar = (ImWchar)-1;
1193b4be Poul Sander 2025-02-03 21:28 2375
}
1193b4be Poul Sander 2025-02-03 21:28 2376
1193b4be Poul Sander 2025-02-03 21:28 2377
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 2378
// [SECTION] ImFontAtlas
1193b4be Poul Sander 2025-02-03 21:28 2379
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 2380
1193b4be Poul Sander 2025-02-03 21:28 2381
// A work of art lies ahead! (. = white layer, X = black layer, others are blank)
1193b4be Poul Sander 2025-02-03 21:28 2382
// The 2x2 white texels on the top left are the ones we'll use everywhere in Dear ImGui to render filled shapes.
1193b4be Poul Sander 2025-02-03 21:28 2383
// (This is used when io.MouseDrawCursor = true)
1193b4be Poul Sander 2025-02-03 21:28 2384
const int FONT_ATLAS_DEFAULT_TEX_DATA_W = 122; // Actual texture will be 2 times that + 1 spacing.
1193b4be Poul Sander 2025-02-03 21:28 2385
const int FONT_ATLAS_DEFAULT_TEX_DATA_H = 27;
1193b4be Poul Sander 2025-02-03 21:28 2386
static const char FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[FONT_ATLAS_DEFAULT_TEX_DATA_W * FONT_ATLAS_DEFAULT_TEX_DATA_H + 1] =
1193b4be Poul Sander 2025-02-03 21:28 2387
{
1193b4be Poul Sander 2025-02-03 21:28 2388
    "..-         -XXXXXXX-    X    -           X           -XXXXXXX          -          XXXXXXX-     XX          - XX       XX "
1193b4be Poul Sander 2025-02-03 21:28 2389
    "..-         -X.....X-   X.X   -          X.X          -X.....X          -          X.....X-    X..X         -X..X     X..X"
1193b4be Poul Sander 2025-02-03 21:28 2390
    "---         -XXX.XXX-  X...X  -         X...X         -X....X           -           X....X-    X..X         -X...X   X...X"
1193b4be Poul Sander 2025-02-03 21:28 2391
    "X           -  X.X  - X.....X -        X.....X        -X...X            -            X...X-    X..X         - X...X X...X "
1193b4be Poul Sander 2025-02-03 21:28 2392
    "XX          -  X.X  -X.......X-       X.......X       -X..X.X           -           X.X..X-    X..X         -  X...X...X  "
1193b4be Poul Sander 2025-02-03 21:28 2393
    "X.X         -  X.X  -XXXX.XXXX-       XXXX.XXXX       -X.X X.X          -          X.X X.X-    X..XXX       -   X.....X   "
1193b4be Poul Sander 2025-02-03 21:28 2394
    "X..X        -  X.X  -   X.X   -          X.X          -XX   X.X         -         X.X   XX-    X..X..XXX    -    X...X    "
1193b4be Poul Sander 2025-02-03 21:28 2395
    "X...X       -  X.X  -   X.X   -    XX    X.X    XX    -      X.X        -        X.X      -    X..X..X..XX  -     X.X     "
1193b4be Poul Sander 2025-02-03 21:28 2396
    "X....X      -  X.X  -   X.X   -   X.X    X.X    X.X   -       X.X       -       X.X       -    X..X..X..X.X -    X...X    "
1193b4be Poul Sander 2025-02-03 21:28 2397
    "X.....X     -  X.X  -   X.X   -  X..X    X.X    X..X  -        X.X      -      X.X        -XXX X..X..X..X..X-   X.....X   "
1193b4be Poul Sander 2025-02-03 21:28 2398
    "X......X    -  X.X  -   X.X   - X...XXXXXX.XXXXXX...X -         X.X   XX-XX   X.X         -X..XX........X..X-  X...X...X  "
1193b4be Poul Sander 2025-02-03 21:28 2399
    "X.......X   -  X.X  -   X.X   -X.....................X-          X.X X.X-X.X X.X          -X...X...........X- X...X X...X "
1193b4be Poul Sander 2025-02-03 21:28 2400
    "X........X  -  X.X  -   X.X   - X...XXXXXX.XXXXXX...X -           X.X..X-X..X.X           - X..............X-X...X   X...X"
1193b4be Poul Sander 2025-02-03 21:28 2401
    "X.........X -XXX.XXX-   X.X   -  X..X    X.X    X..X  -            X...X-X...X            -  X.............X-X..X     X..X"
1193b4be Poul Sander 2025-02-03 21:28 2402
    "X..........X-X.....X-   X.X   -   X.X    X.X    X.X   -           X....X-X....X           -  X.............X- XX       XX "
1193b4be Poul Sander 2025-02-03 21:28 2403
    "X......XXXXX-XXXXXXX-   X.X   -    XX    X.X    XX    -          X.....X-X.....X          -   X............X--------------"
1193b4be Poul Sander 2025-02-03 21:28 2404
    "X...X..X    ---------   X.X   -          X.X          -          XXXXXXX-XXXXXXX          -   X...........X -             "
1193b4be Poul Sander 2025-02-03 21:28 2405
    "X..X X..X   -       -XXXX.XXXX-       XXXX.XXXX       -------------------------------------    X..........X -             "
1193b4be Poul Sander 2025-02-03 21:28 2406
    "X.X  X..X   -       -X.......X-       X.......X       -    XX           XX    -           -    X..........X -             "
1193b4be Poul Sander 2025-02-03 21:28 2407
    "XX    X..X  -       - X.....X -        X.....X        -   X.X           X.X   -           -     X........X  -             "
1193b4be Poul Sander 2025-02-03 21:28 2408
    "      X..X  -       -  X...X  -         X...X         -  X..X           X..X  -           -     X........X  -             "
1193b4be Poul Sander 2025-02-03 21:28 2409
    "       XX   -       -   X.X   -          X.X          - X...XXXXXXXXXXXXX...X -           -     XXXXXXXXXX  -             "
1193b4be Poul Sander 2025-02-03 21:28 2410
    "-------------       -    X    -           X           -X.....................X-           -------------------             "
1193b4be Poul Sander 2025-02-03 21:28 2411
    "                    ----------------------------------- X...XXXXXXXXXXXXX...X -                                           "
1193b4be Poul Sander 2025-02-03 21:28 2412
    "                                                      -  X..X           X..X  -                                           "
1193b4be Poul Sander 2025-02-03 21:28 2413
    "                                                      -   X.X           X.X   -                                           "
1193b4be Poul Sander 2025-02-03 21:28 2414
    "                                                      -    XX           XX    -                                           "
1193b4be Poul Sander 2025-02-03 21:28 2415
};
1193b4be Poul Sander 2025-02-03 21:28 2416
1193b4be Poul Sander 2025-02-03 21:28 2417
static const ImVec2 FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[ImGuiMouseCursor_COUNT][3] =
1193b4be Poul Sander 2025-02-03 21:28 2418
{
1193b4be Poul Sander 2025-02-03 21:28 2419
    // Pos ........ Size ......... Offset ......
1193b4be Poul Sander 2025-02-03 21:28 2420
    { ImVec2( 0,3), ImVec2(12,19), ImVec2( 0, 0) }, // ImGuiMouseCursor_Arrow
1193b4be Poul Sander 2025-02-03 21:28 2421
    { ImVec2(13,0), ImVec2( 7,16), ImVec2( 1, 8) }, // ImGuiMouseCursor_TextInput
1193b4be Poul Sander 2025-02-03 21:28 2422
    { ImVec2(31,0), ImVec2(23,23), ImVec2(11,11) }, // ImGuiMouseCursor_ResizeAll
1193b4be Poul Sander 2025-02-03 21:28 2423
    { ImVec2(21,0), ImVec2( 9,23), ImVec2( 4,11) }, // ImGuiMouseCursor_ResizeNS
1193b4be Poul Sander 2025-02-03 21:28 2424
    { ImVec2(55,18),ImVec2(23, 9), ImVec2(11, 4) }, // ImGuiMouseCursor_ResizeEW
1193b4be Poul Sander 2025-02-03 21:28 2425
    { ImVec2(73,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNESW
1193b4be Poul Sander 2025-02-03 21:28 2426
    { ImVec2(55,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNWSE
1193b4be Poul Sander 2025-02-03 21:28 2427
    { ImVec2(91,0), ImVec2(17,22), ImVec2( 5, 0) }, // ImGuiMouseCursor_Hand
1193b4be Poul Sander 2025-02-03 21:28 2428
    { ImVec2(109,0),ImVec2(13,15), ImVec2( 6, 7) }, // ImGuiMouseCursor_NotAllowed
1193b4be Poul Sander 2025-02-03 21:28 2429
};
1193b4be Poul Sander 2025-02-03 21:28 2430
1193b4be Poul Sander 2025-02-03 21:28 2431
ImFontAtlas::ImFontAtlas()
1193b4be Poul Sander 2025-02-03 21:28 2432
{
1193b4be Poul Sander 2025-02-03 21:28 2433
    memset(this, 0, sizeof(*this));
1193b4be Poul Sander 2025-02-03 21:28 2434
    TexGlyphPadding = 1;
1193b4be Poul Sander 2025-02-03 21:28 2435
    PackIdMouseCursors = PackIdLines = -1;
1193b4be Poul Sander 2025-02-03 21:28 2436
}
1193b4be Poul Sander 2025-02-03 21:28 2437
1193b4be Poul Sander 2025-02-03 21:28 2438
ImFontAtlas::~ImFontAtlas()
1193b4be Poul Sander 2025-02-03 21:28 2439
{
1193b4be Poul Sander 2025-02-03 21:28 2440
    IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
1193b4be Poul Sander 2025-02-03 21:28 2441
    Clear();
1193b4be Poul Sander 2025-02-03 21:28 2442
}
1193b4be Poul Sander 2025-02-03 21:28 2443
1193b4be Poul Sander 2025-02-03 21:28 2444
void    ImFontAtlas::ClearInputData()
1193b4be Poul Sander 2025-02-03 21:28 2445
{
1193b4be Poul Sander 2025-02-03 21:28 2446
    IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
1193b4be Poul Sander 2025-02-03 21:28 2447
    for (ImFontConfig& font_cfg : ConfigData)
1193b4be Poul Sander 2025-02-03 21:28 2448
        if (font_cfg.FontData && font_cfg.FontDataOwnedByAtlas)
1193b4be Poul Sander 2025-02-03 21:28 2449
        {
1193b4be Poul Sander 2025-02-03 21:28 2450
            IM_FREE(font_cfg.FontData);
1193b4be Poul Sander 2025-02-03 21:28 2451
            font_cfg.FontData = NULL;
1193b4be Poul Sander 2025-02-03 21:28 2452
        }
1193b4be Poul Sander 2025-02-03 21:28 2453
1193b4be Poul Sander 2025-02-03 21:28 2454
    // When clearing this we lose access to the font name and other information used to build the font.
1193b4be Poul Sander 2025-02-03 21:28 2455
    for (ImFont* font : Fonts)
1193b4be Poul Sander 2025-02-03 21:28 2456
        if (font->ConfigData >= ConfigData.Data && font->ConfigData < ConfigData.Data + ConfigData.Size)
1193b4be Poul Sander 2025-02-03 21:28 2457
        {
1193b4be Poul Sander 2025-02-03 21:28 2458
            font->ConfigData = NULL;
1193b4be Poul Sander 2025-02-03 21:28 2459
            font->ConfigDataCount = 0;
1193b4be Poul Sander 2025-02-03 21:28 2460
        }
1193b4be Poul Sander 2025-02-03 21:28 2461
    ConfigData.clear();
1193b4be Poul Sander 2025-02-03 21:28 2462
    CustomRects.clear();
1193b4be Poul Sander 2025-02-03 21:28 2463
    PackIdMouseCursors = PackIdLines = -1;
1193b4be Poul Sander 2025-02-03 21:28 2464
    // Important: we leave TexReady untouched
1193b4be Poul Sander 2025-02-03 21:28 2465
}
1193b4be Poul Sander 2025-02-03 21:28 2466
1193b4be Poul Sander 2025-02-03 21:28 2467
void    ImFontAtlas::ClearTexData()
1193b4be Poul Sander 2025-02-03 21:28 2468
{
1193b4be Poul Sander 2025-02-03 21:28 2469
    IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
1193b4be Poul Sander 2025-02-03 21:28 2470
    if (TexPixelsAlpha8)
1193b4be Poul Sander 2025-02-03 21:28 2471
        IM_FREE(TexPixelsAlpha8);
1193b4be Poul Sander 2025-02-03 21:28 2472
    if (TexPixelsRGBA32)
1193b4be Poul Sander 2025-02-03 21:28 2473
        IM_FREE(TexPixelsRGBA32);
1193b4be Poul Sander 2025-02-03 21:28 2474
    TexPixelsAlpha8 = NULL;
1193b4be Poul Sander 2025-02-03 21:28 2475
    TexPixelsRGBA32 = NULL;
1193b4be Poul Sander 2025-02-03 21:28 2476
    TexPixelsUseColors = false;
1193b4be Poul Sander 2025-02-03 21:28 2477
    // Important: we leave TexReady untouched
1193b4be Poul Sander 2025-02-03 21:28 2478
}
1193b4be Poul Sander 2025-02-03 21:28 2479
1193b4be Poul Sander 2025-02-03 21:28 2480
void    ImFontAtlas::ClearFonts()
1193b4be Poul Sander 2025-02-03 21:28 2481
{
1193b4be Poul Sander 2025-02-03 21:28 2482
    IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
1193b4be Poul Sander 2025-02-03 21:28 2483
    Fonts.clear_delete();
1193b4be Poul Sander 2025-02-03 21:28 2484
    TexReady = false;
1193b4be Poul Sander 2025-02-03 21:28 2485
}
1193b4be Poul Sander 2025-02-03 21:28 2486
1193b4be Poul Sander 2025-02-03 21:28 2487
void    ImFontAtlas::Clear()
1193b4be Poul Sander 2025-02-03 21:28 2488
{
1193b4be Poul Sander 2025-02-03 21:28 2489
    ClearInputData();
1193b4be Poul Sander 2025-02-03 21:28 2490
    ClearTexData();
1193b4be Poul Sander 2025-02-03 21:28 2491
    ClearFonts();
1193b4be Poul Sander 2025-02-03 21:28 2492
}
1193b4be Poul Sander 2025-02-03 21:28 2493
1193b4be Poul Sander 2025-02-03 21:28 2494
void    ImFontAtlas::GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel)
1193b4be Poul Sander 2025-02-03 21:28 2495
{
1193b4be Poul Sander 2025-02-03 21:28 2496
    // Build atlas on demand
1193b4be Poul Sander 2025-02-03 21:28 2497
    if (TexPixelsAlpha8 == NULL)
1193b4be Poul Sander 2025-02-03 21:28 2498
        Build();
1193b4be Poul Sander 2025-02-03 21:28 2499
1193b4be Poul Sander 2025-02-03 21:28 2500
    *out_pixels = TexPixelsAlpha8;
1193b4be Poul Sander 2025-02-03 21:28 2501
    if (out_width) *out_width = TexWidth;
1193b4be Poul Sander 2025-02-03 21:28 2502
    if (out_height) *out_height = TexHeight;
1193b4be Poul Sander 2025-02-03 21:28 2503
    if (out_bytes_per_pixel) *out_bytes_per_pixel = 1;
1193b4be Poul Sander 2025-02-03 21:28 2504
}
1193b4be Poul Sander 2025-02-03 21:28 2505
1193b4be Poul Sander 2025-02-03 21:28 2506
void    ImFontAtlas::GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel)
1193b4be Poul Sander 2025-02-03 21:28 2507
{
1193b4be Poul Sander 2025-02-03 21:28 2508
    // Convert to RGBA32 format on demand
1193b4be Poul Sander 2025-02-03 21:28 2509
    // Although it is likely to be the most commonly used format, our font rendering is 1 channel / 8 bpp
1193b4be Poul Sander 2025-02-03 21:28 2510
    if (!TexPixelsRGBA32)
1193b4be Poul Sander 2025-02-03 21:28 2511
    {
1193b4be Poul Sander 2025-02-03 21:28 2512
        unsigned char* pixels = NULL;
1193b4be Poul Sander 2025-02-03 21:28 2513
        GetTexDataAsAlpha8(&pixels, NULL, NULL);
1193b4be Poul Sander 2025-02-03 21:28 2514
        if (pixels)
1193b4be Poul Sander 2025-02-03 21:28 2515
        {
1193b4be Poul Sander 2025-02-03 21:28 2516
            TexPixelsRGBA32 = (unsigned int*)IM_ALLOC((size_t)TexWidth * (size_t)TexHeight * 4);
1193b4be Poul Sander 2025-02-03 21:28 2517
            const unsigned char* src = pixels;
1193b4be Poul Sander 2025-02-03 21:28 2518
            unsigned int* dst = TexPixelsRGBA32;
1193b4be Poul Sander 2025-02-03 21:28 2519
            for (int n = TexWidth * TexHeight; n > 0; n--)
1193b4be Poul Sander 2025-02-03 21:28 2520
                *dst++ = IM_COL32(255, 255, 255, (unsigned int)(*src++));
1193b4be Poul Sander 2025-02-03 21:28 2521
        }
1193b4be Poul Sander 2025-02-03 21:28 2522
    }
1193b4be Poul Sander 2025-02-03 21:28 2523
1193b4be Poul Sander 2025-02-03 21:28 2524
    *out_pixels = (unsigned char*)TexPixelsRGBA32;
1193b4be Poul Sander 2025-02-03 21:28 2525
    if (out_width) *out_width = TexWidth;
1193b4be Poul Sander 2025-02-03 21:28 2526
    if (out_height) *out_height = TexHeight;
1193b4be Poul Sander 2025-02-03 21:28 2527
    if (out_bytes_per_pixel) *out_bytes_per_pixel = 4;
1193b4be Poul Sander 2025-02-03 21:28 2528
}
1193b4be Poul Sander 2025-02-03 21:28 2529
1193b4be Poul Sander 2025-02-03 21:28 2530
ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg)
1193b4be Poul Sander 2025-02-03 21:28 2531
{
1193b4be Poul Sander 2025-02-03 21:28 2532
    IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
1193b4be Poul Sander 2025-02-03 21:28 2533
    IM_ASSERT(font_cfg->FontData != NULL && font_cfg->FontDataSize > 0);
1193b4be Poul Sander 2025-02-03 21:28 2534
    IM_ASSERT(font_cfg->SizePixels > 0.0f && "Is ImFontConfig struct correctly initialized?");
1193b4be Poul Sander 2025-02-03 21:28 2535
    IM_ASSERT(font_cfg->OversampleH > 0 && font_cfg->OversampleV > 0 && "Is ImFontConfig struct correctly initialized?");
1193b4be Poul Sander 2025-02-03 21:28 2536
1193b4be Poul Sander 2025-02-03 21:28 2537
    // Create new font
1193b4be Poul Sander 2025-02-03 21:28 2538
    if (!font_cfg->MergeMode)
1193b4be Poul Sander 2025-02-03 21:28 2539
        Fonts.push_back(IM_NEW(ImFont));
1193b4be Poul Sander 2025-02-03 21:28 2540
    else
1193b4be Poul Sander 2025-02-03 21:28 2541
        IM_ASSERT(Fonts.Size > 0 && "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.
1193b4be Poul Sander 2025-02-03 21:28 2542
1193b4be Poul Sander 2025-02-03 21:28 2543
    ConfigData.push_back(*font_cfg);
1193b4be Poul Sander 2025-02-03 21:28 2544
    ImFontConfig& new_font_cfg = ConfigData.back();
1193b4be Poul Sander 2025-02-03 21:28 2545
    if (new_font_cfg.DstFont == NULL)
1193b4be Poul Sander 2025-02-03 21:28 2546
        new_font_cfg.DstFont = Fonts.back();
1193b4be Poul Sander 2025-02-03 21:28 2547
    if (!new_font_cfg.FontDataOwnedByAtlas)
1193b4be Poul Sander 2025-02-03 21:28 2548
    {
1193b4be Poul Sander 2025-02-03 21:28 2549
        new_font_cfg.FontData = IM_ALLOC(new_font_cfg.FontDataSize);
1193b4be Poul Sander 2025-02-03 21:28 2550
        new_font_cfg.FontDataOwnedByAtlas = true;
1193b4be Poul Sander 2025-02-03 21:28 2551
        memcpy(new_font_cfg.FontData, font_cfg->FontData, (size_t)new_font_cfg.FontDataSize);
1193b4be Poul Sander 2025-02-03 21:28 2552
    }
1193b4be Poul Sander 2025-02-03 21:28 2553
1193b4be Poul Sander 2025-02-03 21:28 2554
    if (new_font_cfg.DstFont->EllipsisChar == (ImWchar)-1)
1193b4be Poul Sander 2025-02-03 21:28 2555
        new_font_cfg.DstFont->EllipsisChar = font_cfg->EllipsisChar;
1193b4be Poul Sander 2025-02-03 21:28 2556
1193b4be Poul Sander 2025-02-03 21:28 2557
    ImFontAtlasUpdateConfigDataPointers(this);
1193b4be Poul Sander 2025-02-03 21:28 2558
1193b4be Poul Sander 2025-02-03 21:28 2559
    // Invalidate texture
1193b4be Poul Sander 2025-02-03 21:28 2560
    TexReady = false;
1193b4be Poul Sander 2025-02-03 21:28 2561
    ClearTexData();
1193b4be Poul Sander 2025-02-03 21:28 2562
    return new_font_cfg.DstFont;
1193b4be Poul Sander 2025-02-03 21:28 2563
}
1193b4be Poul Sander 2025-02-03 21:28 2564
1193b4be Poul Sander 2025-02-03 21:28 2565
// Default font TTF is compressed with stb_compress then base85 encoded (see misc/fonts/binary_to_compressed_c.cpp for encoder)
1193b4be Poul Sander 2025-02-03 21:28 2566
static unsigned int stb_decompress_length(const unsigned char* input);
1193b4be Poul Sander 2025-02-03 21:28 2567
static unsigned int stb_decompress(unsigned char* output, const unsigned char* input, unsigned int length);
1193b4be Poul Sander 2025-02-03 21:28 2568
static const char*  GetDefaultCompressedFontDataTTFBase85();
1193b4be Poul Sander 2025-02-03 21:28 2569
static unsigned int Decode85Byte(char c)                                    { return c >= '\\' ? c-36 : c-35; }
1193b4be Poul Sander 2025-02-03 21:28 2570
static void         Decode85(const unsigned char* src, unsigned char* dst)
1193b4be Poul Sander 2025-02-03 21:28 2571
{
1193b4be Poul Sander 2025-02-03 21:28 2572
    while (*src)
1193b4be Poul Sander 2025-02-03 21:28 2573
    {
1193b4be Poul Sander 2025-02-03 21:28 2574
        unsigned int tmp = Decode85Byte(src[0]) + 85 * (Decode85Byte(src[1]) + 85 * (Decode85Byte(src[2]) + 85 * (Decode85Byte(src[3]) + 85 * Decode85Byte(src[4]))));
1193b4be Poul Sander 2025-02-03 21:28 2575
        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.
1193b4be Poul Sander 2025-02-03 21:28 2576
        src += 5;
1193b4be Poul Sander 2025-02-03 21:28 2577
        dst += 4;
1193b4be Poul Sander 2025-02-03 21:28 2578
    }
1193b4be Poul Sander 2025-02-03 21:28 2579
}
1193b4be Poul Sander 2025-02-03 21:28 2580
1193b4be Poul Sander 2025-02-03 21:28 2581
// Load embedded ProggyClean.ttf at size 13, disable oversampling
1193b4be Poul Sander 2025-02-03 21:28 2582
ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template)
1193b4be Poul Sander 2025-02-03 21:28 2583
{
1193b4be Poul Sander 2025-02-03 21:28 2584
    ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
1193b4be Poul Sander 2025-02-03 21:28 2585
    if (!font_cfg_template)
1193b4be Poul Sander 2025-02-03 21:28 2586
    {
1193b4be Poul Sander 2025-02-03 21:28 2587
        font_cfg.OversampleH = font_cfg.OversampleV = 1;
1193b4be Poul Sander 2025-02-03 21:28 2588
        font_cfg.PixelSnapH = true;
1193b4be Poul Sander 2025-02-03 21:28 2589
    }
1193b4be Poul Sander 2025-02-03 21:28 2590
    if (font_cfg.SizePixels <= 0.0f)
1193b4be Poul Sander 2025-02-03 21:28 2591
        font_cfg.SizePixels = 13.0f * 1.0f;
1193b4be Poul Sander 2025-02-03 21:28 2592
    if (font_cfg.Name[0] == '\0')
1193b4be Poul Sander 2025-02-03 21:28 2593
        ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "ProggyClean.ttf, %dpx", (int)font_cfg.SizePixels);
1193b4be Poul Sander 2025-02-03 21:28 2594
    font_cfg.EllipsisChar = (ImWchar)0x0085;
1193b4be Poul Sander 2025-02-03 21:28 2595
    font_cfg.GlyphOffset.y = 1.0f * IM_TRUNC(font_cfg.SizePixels / 13.0f);  // Add +1 offset per 13 units
1193b4be Poul Sander 2025-02-03 21:28 2596
1193b4be Poul Sander 2025-02-03 21:28 2597
    const char* ttf_compressed_base85 = GetDefaultCompressedFontDataTTFBase85();
1193b4be Poul Sander 2025-02-03 21:28 2598
    const ImWchar* glyph_ranges = font_cfg.GlyphRanges != NULL ? font_cfg.GlyphRanges : GetGlyphRangesDefault();
1193b4be Poul Sander 2025-02-03 21:28 2599
    ImFont* font = AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, font_cfg.SizePixels, &font_cfg, glyph_ranges);
1193b4be Poul Sander 2025-02-03 21:28 2600
    return font;
1193b4be Poul Sander 2025-02-03 21:28 2601
}
1193b4be Poul Sander 2025-02-03 21:28 2602
1193b4be Poul Sander 2025-02-03 21:28 2603
ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)
1193b4be Poul Sander 2025-02-03 21:28 2604
{
1193b4be Poul Sander 2025-02-03 21:28 2605
    IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
1193b4be Poul Sander 2025-02-03 21:28 2606
    size_t data_size = 0;
1193b4be Poul Sander 2025-02-03 21:28 2607
    void* data = ImFileLoadToMemory(filename, "rb", &data_size, 0);
1193b4be Poul Sander 2025-02-03 21:28 2608
    if (!data)
1193b4be Poul Sander 2025-02-03 21:28 2609
    {
1193b4be Poul Sander 2025-02-03 21:28 2610
        IM_ASSERT_USER_ERROR(0, "Could not load font file!");
1193b4be Poul Sander 2025-02-03 21:28 2611
        return NULL;
1193b4be Poul Sander 2025-02-03 21:28 2612
    }
1193b4be Poul Sander 2025-02-03 21:28 2613
    ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
1193b4be Poul Sander 2025-02-03 21:28 2614
    if (font_cfg.Name[0] == '\0')
1193b4be Poul Sander 2025-02-03 21:28 2615
    {
1193b4be Poul Sander 2025-02-03 21:28 2616
        // Store a short copy of filename into into the font name for convenience
1193b4be Poul Sander 2025-02-03 21:28 2617
        const char* p;
1193b4be Poul Sander 2025-02-03 21:28 2618
        for (p = filename + strlen(filename); p > filename && p[-1] != '/' && p[-1] != '\\'; p--) {}
1193b4be Poul Sander 2025-02-03 21:28 2619
        ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "%s, %.0fpx", p, size_pixels);
1193b4be Poul Sander 2025-02-03 21:28 2620
    }
1193b4be Poul Sander 2025-02-03 21:28 2621
    return AddFontFromMemoryTTF(data, (int)data_size, size_pixels, &font_cfg, glyph_ranges);
1193b4be Poul Sander 2025-02-03 21:28 2622
}
1193b4be Poul Sander 2025-02-03 21:28 2623
1193b4be Poul Sander 2025-02-03 21:28 2624
// NB: Transfer ownership of 'ttf_data' to ImFontAtlas, unless font_cfg_template->FontDataOwnedByAtlas == false. Owned TTF buffer will be deleted after Build().
1193b4be Poul Sander 2025-02-03 21:28 2625
ImFont* ImFontAtlas::AddFontFromMemoryTTF(void* font_data, int font_data_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)
1193b4be Poul Sander 2025-02-03 21:28 2626
{
1193b4be Poul Sander 2025-02-03 21:28 2627
    IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
1193b4be Poul Sander 2025-02-03 21:28 2628
    ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
1193b4be Poul Sander 2025-02-03 21:28 2629
    IM_ASSERT(font_cfg.FontData == NULL);
1193b4be Poul Sander 2025-02-03 21:28 2630
    IM_ASSERT(font_data_size > 100 && "Incorrect value for font_data_size!"); // Heuristic to prevent accidentally passing a wrong value to font_data_size.
1193b4be Poul Sander 2025-02-03 21:28 2631
    font_cfg.FontData = font_data;
1193b4be Poul Sander 2025-02-03 21:28 2632
    font_cfg.FontDataSize = font_data_size;
1193b4be Poul Sander 2025-02-03 21:28 2633
    font_cfg.SizePixels = size_pixels > 0.0f ? size_pixels : font_cfg.SizePixels;
1193b4be Poul Sander 2025-02-03 21:28 2634
    if (glyph_ranges)
1193b4be Poul Sander 2025-02-03 21:28 2635
        font_cfg.GlyphRanges = glyph_ranges;
1193b4be Poul Sander 2025-02-03 21:28 2636
    return AddFont(&font_cfg);
1193b4be Poul Sander 2025-02-03 21:28 2637
}
1193b4be Poul Sander 2025-02-03 21:28 2638
1193b4be Poul Sander 2025-02-03 21:28 2639
ImFont* ImFontAtlas::AddFontFromMemoryCompressedTTF(const void* compressed_ttf_data, int compressed_ttf_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)
1193b4be Poul Sander 2025-02-03 21:28 2640
{
1193b4be Poul Sander 2025-02-03 21:28 2641
    const unsigned int buf_decompressed_size = stb_decompress_length((const unsigned char*)compressed_ttf_data);
1193b4be Poul Sander 2025-02-03 21:28 2642
    unsigned char* buf_decompressed_data = (unsigned char*)IM_ALLOC(buf_decompressed_size);
1193b4be Poul Sander 2025-02-03 21:28 2643
    stb_decompress(buf_decompressed_data, (const unsigned char*)compressed_ttf_data, (unsigned int)compressed_ttf_size);
1193b4be Poul Sander 2025-02-03 21:28 2644
1193b4be Poul Sander 2025-02-03 21:28 2645
    ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
1193b4be Poul Sander 2025-02-03 21:28 2646
    IM_ASSERT(font_cfg.FontData == NULL);
1193b4be Poul Sander 2025-02-03 21:28 2647
    font_cfg.FontDataOwnedByAtlas = true;
1193b4be Poul Sander 2025-02-03 21:28 2648
    return AddFontFromMemoryTTF(buf_decompressed_data, (int)buf_decompressed_size, size_pixels, &font_cfg, glyph_ranges);
1193b4be Poul Sander 2025-02-03 21:28 2649
}
1193b4be Poul Sander 2025-02-03 21:28 2650
1193b4be Poul Sander 2025-02-03 21:28 2651
ImFont* ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(const char* compressed_ttf_data_base85, float size_pixels, const ImFontConfig* font_cfg, const ImWchar* glyph_ranges)
1193b4be Poul Sander 2025-02-03 21:28 2652
{
1193b4be Poul Sander 2025-02-03 21:28 2653
    int compressed_ttf_size = (((int)strlen(compressed_ttf_data_base85) + 4) / 5) * 4;
1193b4be Poul Sander 2025-02-03 21:28 2654
    void* compressed_ttf = IM_ALLOC((size_t)compressed_ttf_size);
1193b4be Poul Sander 2025-02-03 21:28 2655
    Decode85((const unsigned char*)compressed_ttf_data_base85, (unsigned char*)compressed_ttf);
1193b4be Poul Sander 2025-02-03 21:28 2656
    ImFont* font = AddFontFromMemoryCompressedTTF(compressed_ttf, compressed_ttf_size, size_pixels, font_cfg, glyph_ranges);
1193b4be Poul Sander 2025-02-03 21:28 2657
    IM_FREE(compressed_ttf);
1193b4be Poul Sander 2025-02-03 21:28 2658
    return font;
1193b4be Poul Sander 2025-02-03 21:28 2659
}
1193b4be Poul Sander 2025-02-03 21:28 2660
1193b4be Poul Sander 2025-02-03 21:28 2661
int ImFontAtlas::AddCustomRectRegular(int width, int height)
1193b4be Poul Sander 2025-02-03 21:28 2662
{
1193b4be Poul Sander 2025-02-03 21:28 2663
    IM_ASSERT(width > 0 && width <= 0xFFFF);
1193b4be Poul Sander 2025-02-03 21:28 2664
    IM_ASSERT(height > 0 && height <= 0xFFFF);
1193b4be Poul Sander 2025-02-03 21:28 2665
    ImFontAtlasCustomRect r;
1193b4be Poul Sander 2025-02-03 21:28 2666
    r.Width = (unsigned short)width;
1193b4be Poul Sander 2025-02-03 21:28 2667
    r.Height = (unsigned short)height;
1193b4be Poul Sander 2025-02-03 21:28 2668
    CustomRects.push_back(r);
1193b4be Poul Sander 2025-02-03 21:28 2669
    return CustomRects.Size - 1; // Return index
1193b4be Poul Sander 2025-02-03 21:28 2670
}
1193b4be Poul Sander 2025-02-03 21:28 2671
1193b4be Poul Sander 2025-02-03 21:28 2672
int ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset)
1193b4be Poul Sander 2025-02-03 21:28 2673
{
1193b4be Poul Sander 2025-02-03 21:28 2674
#ifdef IMGUI_USE_WCHAR32
1193b4be Poul Sander 2025-02-03 21:28 2675
    IM_ASSERT(id <= IM_UNICODE_CODEPOINT_MAX);
1193b4be Poul Sander 2025-02-03 21:28 2676
#endif
1193b4be Poul Sander 2025-02-03 21:28 2677
    IM_ASSERT(font != NULL);
1193b4be Poul Sander 2025-02-03 21:28 2678
    IM_ASSERT(width > 0 && width <= 0xFFFF);
1193b4be Poul Sander 2025-02-03 21:28 2679
    IM_ASSERT(height > 0 && height <= 0xFFFF);
1193b4be Poul Sander 2025-02-03 21:28 2680
    ImFontAtlasCustomRect r;
1193b4be Poul Sander 2025-02-03 21:28 2681
    r.Width = (unsigned short)width;
1193b4be Poul Sander 2025-02-03 21:28 2682
    r.Height = (unsigned short)height;
1193b4be Poul Sander 2025-02-03 21:28 2683
    r.GlyphID = id;
1193b4be Poul Sander 2025-02-03 21:28 2684
    r.GlyphAdvanceX = advance_x;
1193b4be Poul Sander 2025-02-03 21:28 2685
    r.GlyphOffset = offset;
1193b4be Poul Sander 2025-02-03 21:28 2686
    r.Font = font;
1193b4be Poul Sander 2025-02-03 21:28 2687
    CustomRects.push_back(r);
1193b4be Poul Sander 2025-02-03 21:28 2688
    return CustomRects.Size - 1; // Return index
1193b4be Poul Sander 2025-02-03 21:28 2689
}
1193b4be Poul Sander 2025-02-03 21:28 2690
1193b4be Poul Sander 2025-02-03 21:28 2691
void ImFontAtlas::CalcCustomRectUV(const ImFontAtlasCustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const
1193b4be Poul Sander 2025-02-03 21:28 2692
{
1193b4be Poul Sander 2025-02-03 21:28 2693
    IM_ASSERT(TexWidth > 0 && TexHeight > 0);   // Font atlas needs to be built before we can calculate UV coordinates
1193b4be Poul Sander 2025-02-03 21:28 2694
    IM_ASSERT(rect->IsPacked());                // Make sure the rectangle has been packed
1193b4be Poul Sander 2025-02-03 21:28 2695
    *out_uv_min = ImVec2((float)rect->X * TexUvScale.x, (float)rect->Y * TexUvScale.y);
1193b4be Poul Sander 2025-02-03 21:28 2696
    *out_uv_max = ImVec2((float)(rect->X + rect->Width) * TexUvScale.x, (float)(rect->Y + rect->Height) * TexUvScale.y);
1193b4be Poul Sander 2025-02-03 21:28 2697
}
1193b4be Poul Sander 2025-02-03 21:28 2698
1193b4be Poul Sander 2025-02-03 21:28 2699
bool ImFontAtlas::GetMouseCursorTexData(ImGuiMouseCursor cursor_type, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2])
1193b4be Poul Sander 2025-02-03 21:28 2700
{
1193b4be Poul Sander 2025-02-03 21:28 2701
    if (cursor_type <= ImGuiMouseCursor_None || cursor_type >= ImGuiMouseCursor_COUNT)
1193b4be Poul Sander 2025-02-03 21:28 2702
        return false;
1193b4be Poul Sander 2025-02-03 21:28 2703
    if (Flags & ImFontAtlasFlags_NoMouseCursors)
1193b4be Poul Sander 2025-02-03 21:28 2704
        return false;
1193b4be Poul Sander 2025-02-03 21:28 2705
1193b4be Poul Sander 2025-02-03 21:28 2706
    IM_ASSERT(PackIdMouseCursors != -1);
1193b4be Poul Sander 2025-02-03 21:28 2707
    ImFontAtlasCustomRect* r = GetCustomRectByIndex(PackIdMouseCursors);
1193b4be Poul Sander 2025-02-03 21:28 2708
    ImVec2 pos = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][0] + ImVec2((float)r->X, (float)r->Y);
1193b4be Poul Sander 2025-02-03 21:28 2709
    ImVec2 size = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][1];
1193b4be Poul Sander 2025-02-03 21:28 2710
    *out_size = size;
1193b4be Poul Sander 2025-02-03 21:28 2711
    *out_offset = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][2];
1193b4be Poul Sander 2025-02-03 21:28 2712
    out_uv_border[0] = (pos) * TexUvScale;
1193b4be Poul Sander 2025-02-03 21:28 2713
    out_uv_border[1] = (pos + size) * TexUvScale;
1193b4be Poul Sander 2025-02-03 21:28 2714
    pos.x += FONT_ATLAS_DEFAULT_TEX_DATA_W + 1;
1193b4be Poul Sander 2025-02-03 21:28 2715
    out_uv_fill[0] = (pos) * TexUvScale;
1193b4be Poul Sander 2025-02-03 21:28 2716
    out_uv_fill[1] = (pos + size) * TexUvScale;
1193b4be Poul Sander 2025-02-03 21:28 2717
    return true;
1193b4be Poul Sander 2025-02-03 21:28 2718
}
1193b4be Poul Sander 2025-02-03 21:28 2719
1193b4be Poul Sander 2025-02-03 21:28 2720
bool    ImFontAtlas::Build()
1193b4be Poul Sander 2025-02-03 21:28 2721
{
1193b4be Poul Sander 2025-02-03 21:28 2722
    IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
1193b4be Poul Sander 2025-02-03 21:28 2723
1193b4be Poul Sander 2025-02-03 21:28 2724
    // Default font is none are specified
1193b4be Poul Sander 2025-02-03 21:28 2725
    if (ConfigData.Size == 0)
1193b4be Poul Sander 2025-02-03 21:28 2726
        AddFontDefault();
1193b4be Poul Sander 2025-02-03 21:28 2727
1193b4be Poul Sander 2025-02-03 21:28 2728
    // Select builder
1193b4be Poul Sander 2025-02-03 21:28 2729
    // - Note that we do not reassign to atlas->FontBuilderIO, since it is likely to point to static data which
1193b4be Poul Sander 2025-02-03 21:28 2730
    //   may mess with some hot-reloading schemes. If you need to assign to this (for dynamic selection) AND are
1193b4be Poul Sander 2025-02-03 21:28 2731
    //   using a hot-reloading scheme that messes up static data, store your own instance of ImFontBuilderIO somewhere
1193b4be Poul Sander 2025-02-03 21:28 2732
    //   and point to it instead of pointing directly to return value of the GetBuilderXXX functions.
1193b4be Poul Sander 2025-02-03 21:28 2733
    const ImFontBuilderIO* builder_io = FontBuilderIO;
1193b4be Poul Sander 2025-02-03 21:28 2734
    if (builder_io == NULL)
1193b4be Poul Sander 2025-02-03 21:28 2735
    {
1193b4be Poul Sander 2025-02-03 21:28 2736
#ifdef IMGUI_ENABLE_FREETYPE
1193b4be Poul Sander 2025-02-03 21:28 2737
        builder_io = ImGuiFreeType::GetBuilderForFreeType();
1193b4be Poul Sander 2025-02-03 21:28 2738
#elif defined(IMGUI_ENABLE_STB_TRUETYPE)
1193b4be Poul Sander 2025-02-03 21:28 2739
        builder_io = ImFontAtlasGetBuilderForStbTruetype();
1193b4be Poul Sander 2025-02-03 21:28 2740
#else
1193b4be Poul Sander 2025-02-03 21:28 2741
        IM_ASSERT(0); // Invalid Build function
1193b4be Poul Sander 2025-02-03 21:28 2742
#endif
1193b4be Poul Sander 2025-02-03 21:28 2743
    }
1193b4be Poul Sander 2025-02-03 21:28 2744
1193b4be Poul Sander 2025-02-03 21:28 2745
    // Build
1193b4be Poul Sander 2025-02-03 21:28 2746
    return builder_io->FontBuilder_Build(this);
1193b4be Poul Sander 2025-02-03 21:28 2747
}
1193b4be Poul Sander 2025-02-03 21:28 2748
1193b4be Poul Sander 2025-02-03 21:28 2749
void    ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_brighten_factor)
1193b4be Poul Sander 2025-02-03 21:28 2750
{
1193b4be Poul Sander 2025-02-03 21:28 2751
    for (unsigned int i = 0; i < 256; i++)
1193b4be Poul Sander 2025-02-03 21:28 2752
    {
1193b4be Poul Sander 2025-02-03 21:28 2753
        unsigned int value = (unsigned int)(i * in_brighten_factor);
1193b4be Poul Sander 2025-02-03 21:28 2754
        out_table[i] = value > 255 ? 255 : (value & 0xFF);
1193b4be Poul Sander 2025-02-03 21:28 2755
    }
1193b4be Poul Sander 2025-02-03 21:28 2756
}
1193b4be Poul Sander 2025-02-03 21:28 2757
1193b4be Poul Sander 2025-02-03 21:28 2758
void    ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride)
1193b4be Poul Sander 2025-02-03 21:28 2759
{
1193b4be Poul Sander 2025-02-03 21:28 2760
    IM_ASSERT_PARANOID(w <= stride);
1193b4be Poul Sander 2025-02-03 21:28 2761
    unsigned char* data = pixels + x + y * stride;
1193b4be Poul Sander 2025-02-03 21:28 2762
    for (int j = h; j > 0; j--, data += stride - w)
1193b4be Poul Sander 2025-02-03 21:28 2763
        for (int i = w; i > 0; i--, data++)
1193b4be Poul Sander 2025-02-03 21:28 2764
            *data = table[*data];
1193b4be Poul Sander 2025-02-03 21:28 2765
}
1193b4be Poul Sander 2025-02-03 21:28 2766
1193b4be Poul Sander 2025-02-03 21:28 2767
#ifdef IMGUI_ENABLE_STB_TRUETYPE
1193b4be Poul Sander 2025-02-03 21:28 2768
// Temporary data for one source font (multiple source fonts can be merged into one destination ImFont)
1193b4be Poul Sander 2025-02-03 21:28 2769
// (C++03 doesn't allow instancing ImVector<> with function-local types so we declare the type here.)
1193b4be Poul Sander 2025-02-03 21:28 2770
struct ImFontBuildSrcData
1193b4be Poul Sander 2025-02-03 21:28 2771
{
1193b4be Poul Sander 2025-02-03 21:28 2772
    stbtt_fontinfo      FontInfo;
1193b4be Poul Sander 2025-02-03 21:28 2773
    stbtt_pack_range    PackRange;          // Hold the list of codepoints to pack (essentially points to Codepoints.Data)
1193b4be Poul Sander 2025-02-03 21:28 2774
    stbrp_rect*         Rects;              // Rectangle to pack. We first fill in their size and the packer will give us their position.
1193b4be Poul Sander 2025-02-03 21:28 2775
    stbtt_packedchar*   PackedChars;        // Output glyphs
1193b4be Poul Sander 2025-02-03 21:28 2776
    const ImWchar*      SrcRanges;          // Ranges as requested by user (user is allowed to request too much, e.g. 0x0020..0xFFFF)
1193b4be Poul Sander 2025-02-03 21:28 2777
    int                 DstIndex;           // Index into atlas->Fonts[] and dst_tmp_array[]
1193b4be Poul Sander 2025-02-03 21:28 2778
    int                 GlyphsHighest;      // Highest requested codepoint
1193b4be Poul Sander 2025-02-03 21:28 2779
    int                 GlyphsCount;        // Glyph count (excluding missing glyphs and glyphs already set by an earlier source font)
1193b4be Poul Sander 2025-02-03 21:28 2780
    ImBitVector         GlyphsSet;          // Glyph bit map (random access, 1-bit per codepoint. This will be a maximum of 8KB)
1193b4be Poul Sander 2025-02-03 21:28 2781
    ImVector<int>       GlyphsList;         // Glyph codepoints list (flattened version of GlyphsSet)
1193b4be Poul Sander 2025-02-03 21:28 2782
};
1193b4be Poul Sander 2025-02-03 21:28 2783
1193b4be Poul Sander 2025-02-03 21:28 2784
// Temporary data for one destination ImFont* (multiple source fonts can be merged into one destination ImFont)
1193b4be Poul Sander 2025-02-03 21:28 2785
struct ImFontBuildDstData
1193b4be Poul Sander 2025-02-03 21:28 2786
{
1193b4be Poul Sander 2025-02-03 21:28 2787
    int                 SrcCount;           // Number of source fonts targeting this destination font.
1193b4be Poul Sander 2025-02-03 21:28 2788
    int                 GlyphsHighest;
1193b4be Poul Sander 2025-02-03 21:28 2789
    int                 GlyphsCount;
1193b4be Poul Sander 2025-02-03 21:28 2790
    ImBitVector         GlyphsSet;          // This is used to resolve collision when multiple sources are merged into a same destination font.
1193b4be Poul Sander 2025-02-03 21:28 2791
};
1193b4be Poul Sander 2025-02-03 21:28 2792
1193b4be Poul Sander 2025-02-03 21:28 2793
static void UnpackBitVectorToFlatIndexList(const ImBitVector* in, ImVector<int>* out)
1193b4be Poul Sander 2025-02-03 21:28 2794
{
1193b4be Poul Sander 2025-02-03 21:28 2795
    IM_ASSERT(sizeof(in->Storage.Data[0]) == sizeof(int));
1193b4be Poul Sander 2025-02-03 21:28 2796
    const ImU32* it_begin = in->Storage.begin();
1193b4be Poul Sander 2025-02-03 21:28 2797
    const ImU32* it_end = in->Storage.end();
1193b4be Poul Sander 2025-02-03 21:28 2798
    for (const ImU32* it = it_begin; it < it_end; it++)
1193b4be Poul Sander 2025-02-03 21:28 2799
        if (ImU32 entries_32 = *it)
1193b4be Poul Sander 2025-02-03 21:28 2800
            for (ImU32 bit_n = 0; bit_n < 32; bit_n++)
1193b4be Poul Sander 2025-02-03 21:28 2801
                if (entries_32 & ((ImU32)1 << bit_n))
1193b4be Poul Sander 2025-02-03 21:28 2802
                    out->push_back((int)(((it - it_begin) << 5) + bit_n));
1193b4be Poul Sander 2025-02-03 21:28 2803
}
1193b4be Poul Sander 2025-02-03 21:28 2804
1193b4be Poul Sander 2025-02-03 21:28 2805
static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
1193b4be Poul Sander 2025-02-03 21:28 2806
{
1193b4be Poul Sander 2025-02-03 21:28 2807
    IM_ASSERT(atlas->ConfigData.Size > 0);
1193b4be Poul Sander 2025-02-03 21:28 2808
1193b4be Poul Sander 2025-02-03 21:28 2809
    ImFontAtlasBuildInit(atlas);
1193b4be Poul Sander 2025-02-03 21:28 2810
1193b4be Poul Sander 2025-02-03 21:28 2811
    // Clear atlas
1193b4be Poul Sander 2025-02-03 21:28 2812
    atlas->TexID = (ImTextureID)NULL;
1193b4be Poul Sander 2025-02-03 21:28 2813
    atlas->TexWidth = atlas->TexHeight = 0;
1193b4be Poul Sander 2025-02-03 21:28 2814
    atlas->TexUvScale = ImVec2(0.0f, 0.0f);
1193b4be Poul Sander 2025-02-03 21:28 2815
    atlas->TexUvWhitePixel = ImVec2(0.0f, 0.0f);
1193b4be Poul Sander 2025-02-03 21:28 2816
    atlas->ClearTexData();
1193b4be Poul Sander 2025-02-03 21:28 2817
1193b4be Poul Sander 2025-02-03 21:28 2818
    // Temporary storage for building
1193b4be Poul Sander 2025-02-03 21:28 2819
    ImVector<ImFontBuildSrcData> src_tmp_array;
1193b4be Poul Sander 2025-02-03 21:28 2820
    ImVector<ImFontBuildDstData> dst_tmp_array;
1193b4be Poul Sander 2025-02-03 21:28 2821
    src_tmp_array.resize(atlas->ConfigData.Size);
1193b4be Poul Sander 2025-02-03 21:28 2822
    dst_tmp_array.resize(atlas->Fonts.Size);
1193b4be Poul Sander 2025-02-03 21:28 2823
    memset(src_tmp_array.Data, 0, (size_t)src_tmp_array.size_in_bytes());
1193b4be Poul Sander 2025-02-03 21:28 2824
    memset(dst_tmp_array.Data, 0, (size_t)dst_tmp_array.size_in_bytes());
1193b4be Poul Sander 2025-02-03 21:28 2825
1193b4be Poul Sander 2025-02-03 21:28 2826
    // 1. Initialize font loading structure, check font data validity
1193b4be Poul Sander 2025-02-03 21:28 2827
    for (int src_i = 0; src_i < atlas->ConfigData.Size; src_i++)
1193b4be Poul Sander 2025-02-03 21:28 2828
    {
1193b4be Poul Sander 2025-02-03 21:28 2829
        ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
1193b4be Poul Sander 2025-02-03 21:28 2830
        ImFontConfig& cfg = atlas->ConfigData[src_i];
1193b4be Poul Sander 2025-02-03 21:28 2831
        IM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas));
1193b4be Poul Sander 2025-02-03 21:28 2832
1193b4be Poul Sander 2025-02-03 21:28 2833
        // Find index from cfg.DstFont (we allow the user to set cfg.DstFont. Also it makes casual debugging nicer than when storing indices)
1193b4be Poul Sander 2025-02-03 21:28 2834
        src_tmp.DstIndex = -1;
1193b4be Poul Sander 2025-02-03 21:28 2835
        for (int output_i = 0; output_i < atlas->Fonts.Size && src_tmp.DstIndex == -1; output_i++)
1193b4be Poul Sander 2025-02-03 21:28 2836
            if (cfg.DstFont == atlas->Fonts[output_i])
1193b4be Poul Sander 2025-02-03 21:28 2837
                src_tmp.DstIndex = output_i;
1193b4be Poul Sander 2025-02-03 21:28 2838
        if (src_tmp.DstIndex == -1)
1193b4be Poul Sander 2025-02-03 21:28 2839
        {
1193b4be Poul Sander 2025-02-03 21:28 2840
            IM_ASSERT(src_tmp.DstIndex != -1); // cfg.DstFont not pointing within atlas->Fonts[] array?
1193b4be Poul Sander 2025-02-03 21:28 2841
            return false;
1193b4be Poul Sander 2025-02-03 21:28 2842
        }
1193b4be Poul Sander 2025-02-03 21:28 2843
        // Initialize helper structure for font loading and verify that the TTF/OTF data is correct
1193b4be Poul Sander 2025-02-03 21:28 2844
        const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)cfg.FontData, cfg.FontNo);
1193b4be Poul Sander 2025-02-03 21:28 2845
        IM_ASSERT(font_offset >= 0 && "FontData is incorrect, or FontNo cannot be found.");
1193b4be Poul Sander 2025-02-03 21:28 2846
        if (!stbtt_InitFont(&src_tmp.FontInfo, (unsigned char*)cfg.FontData, font_offset))
1193b4be Poul Sander 2025-02-03 21:28 2847
        {
1193b4be Poul Sander 2025-02-03 21:28 2848
            IM_ASSERT(0 && "stbtt_InitFont(): failed to parse FontData. It is correct and complete? Check FontDataSize.");
1193b4be Poul Sander 2025-02-03 21:28 2849
            return false;
1193b4be Poul Sander 2025-02-03 21:28 2850
        }
1193b4be Poul Sander 2025-02-03 21:28 2851
1193b4be Poul Sander 2025-02-03 21:28 2852
        // Measure highest codepoints
1193b4be Poul Sander 2025-02-03 21:28 2853
        ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex];
1193b4be Poul Sander 2025-02-03 21:28 2854
        src_tmp.SrcRanges = cfg.GlyphRanges ? cfg.GlyphRanges : atlas->GetGlyphRangesDefault();
1193b4be Poul Sander 2025-02-03 21:28 2855
        for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
1193b4be Poul Sander 2025-02-03 21:28 2856
        {
1193b4be Poul Sander 2025-02-03 21:28 2857
            // Check for valid range. This may also help detect *some* dangling pointers, because a common
1193b4be Poul Sander 2025-02-03 21:28 2858
            // user error is to setup ImFontConfig::GlyphRanges with a pointer to data that isn't persistent,
1193b4be Poul Sander 2025-02-03 21:28 2859
            // or to forget to zero-terminate the glyph range array.
1193b4be Poul Sander 2025-02-03 21:28 2860
            IM_ASSERT(src_range[0] <= src_range[1] && "Invalid range: is your glyph range array persistent? it is zero-terminated?");
1193b4be Poul Sander 2025-02-03 21:28 2861
            src_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]);
1193b4be Poul Sander 2025-02-03 21:28 2862
        }
1193b4be Poul Sander 2025-02-03 21:28 2863
        dst_tmp.SrcCount++;
1193b4be Poul Sander 2025-02-03 21:28 2864
        dst_tmp.GlyphsHighest = ImMax(dst_tmp.GlyphsHighest, src_tmp.GlyphsHighest);
1193b4be Poul Sander 2025-02-03 21:28 2865
    }
1193b4be Poul Sander 2025-02-03 21:28 2866
1193b4be Poul Sander 2025-02-03 21:28 2867
    // 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.
1193b4be Poul Sander 2025-02-03 21:28 2868
    int total_glyphs_count = 0;
1193b4be Poul Sander 2025-02-03 21:28 2869
    for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
1193b4be Poul Sander 2025-02-03 21:28 2870
    {
1193b4be Poul Sander 2025-02-03 21:28 2871
        ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
1193b4be Poul Sander 2025-02-03 21:28 2872
        ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex];
1193b4be Poul Sander 2025-02-03 21:28 2873
        src_tmp.GlyphsSet.Create(src_tmp.GlyphsHighest + 1);
1193b4be Poul Sander 2025-02-03 21:28 2874
        if (dst_tmp.GlyphsSet.Storage.empty())
1193b4be Poul Sander 2025-02-03 21:28 2875
            dst_tmp.GlyphsSet.Create(dst_tmp.GlyphsHighest + 1);
1193b4be Poul Sander 2025-02-03 21:28 2876
1193b4be Poul Sander 2025-02-03 21:28 2877
        for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
1193b4be Poul Sander 2025-02-03 21:28 2878
            for (unsigned int codepoint = src_range[0]; codepoint <= src_range[1]; codepoint++)
1193b4be Poul Sander 2025-02-03 21:28 2879
            {
1193b4be Poul Sander 2025-02-03 21:28 2880
                if (dst_tmp.GlyphsSet.TestBit(codepoint))    // Don't overwrite existing glyphs. We could make this an option for MergeMode (e.g. MergeOverwrite==true)
1193b4be Poul Sander 2025-02-03 21:28 2881
                    continue;
1193b4be Poul Sander 2025-02-03 21:28 2882
                if (!stbtt_FindGlyphIndex(&src_tmp.FontInfo, codepoint))    // It is actually in the font?
1193b4be Poul Sander 2025-02-03 21:28 2883
                    continue;
1193b4be Poul Sander 2025-02-03 21:28 2884
1193b4be Poul Sander 2025-02-03 21:28 2885
                // Add to avail set/counters
1193b4be Poul Sander 2025-02-03 21:28 2886
                src_tmp.GlyphsCount++;
1193b4be Poul Sander 2025-02-03 21:28 2887
                dst_tmp.GlyphsCount++;
1193b4be Poul Sander 2025-02-03 21:28 2888
                src_tmp.GlyphsSet.SetBit(codepoint);
1193b4be Poul Sander 2025-02-03 21:28 2889
                dst_tmp.GlyphsSet.SetBit(codepoint);
1193b4be Poul Sander 2025-02-03 21:28 2890
                total_glyphs_count++;
1193b4be Poul Sander 2025-02-03 21:28 2891
            }
1193b4be Poul Sander 2025-02-03 21:28 2892
    }
1193b4be Poul Sander 2025-02-03 21:28 2893
1193b4be Poul Sander 2025-02-03 21:28 2894
    // 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)
1193b4be Poul Sander 2025-02-03 21:28 2895
    for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
1193b4be Poul Sander 2025-02-03 21:28 2896
    {
1193b4be Poul Sander 2025-02-03 21:28 2897
        ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
1193b4be Poul Sander 2025-02-03 21:28 2898
        src_tmp.GlyphsList.reserve(src_tmp.GlyphsCount);
1193b4be Poul Sander 2025-02-03 21:28 2899
        UnpackBitVectorToFlatIndexList(&src_tmp.GlyphsSet, &src_tmp.GlyphsList);
1193b4be Poul Sander 2025-02-03 21:28 2900
        src_tmp.GlyphsSet.Clear();
1193b4be Poul Sander 2025-02-03 21:28 2901
        IM_ASSERT(src_tmp.GlyphsList.Size == src_tmp.GlyphsCount);
1193b4be Poul Sander 2025-02-03 21:28 2902
    }
1193b4be Poul Sander 2025-02-03 21:28 2903
    for (int dst_i = 0; dst_i < dst_tmp_array.Size; dst_i++)
1193b4be Poul Sander 2025-02-03 21:28 2904
        dst_tmp_array[dst_i].GlyphsSet.Clear();
1193b4be Poul Sander 2025-02-03 21:28 2905
    dst_tmp_array.clear();
1193b4be Poul Sander 2025-02-03 21:28 2906
1193b4be Poul Sander 2025-02-03 21:28 2907
    // Allocate packing character data and flag packed characters buffer as non-packed (x0=y0=x1=y1=0)
1193b4be Poul Sander 2025-02-03 21:28 2908
    // (We technically don't need to zero-clear buf_rects, but let's do it for the sake of sanity)
1193b4be Poul Sander 2025-02-03 21:28 2909
    ImVector<stbrp_rect> buf_rects;
1193b4be Poul Sander 2025-02-03 21:28 2910
    ImVector<stbtt_packedchar> buf_packedchars;
1193b4be Poul Sander 2025-02-03 21:28 2911
    buf_rects.resize(total_glyphs_count);
1193b4be Poul Sander 2025-02-03 21:28 2912
    buf_packedchars.resize(total_glyphs_count);
1193b4be Poul Sander 2025-02-03 21:28 2913
    memset(buf_rects.Data, 0, (size_t)buf_rects.size_in_bytes());
1193b4be Poul Sander 2025-02-03 21:28 2914
    memset(buf_packedchars.Data, 0, (size_t)buf_packedchars.size_in_bytes());
1193b4be Poul Sander 2025-02-03 21:28 2915
1193b4be Poul Sander 2025-02-03 21:28 2916
    // 4. Gather glyphs sizes so we can pack them in our virtual canvas.
1193b4be Poul Sander 2025-02-03 21:28 2917
    int total_surface = 0;
1193b4be Poul Sander 2025-02-03 21:28 2918
    int buf_rects_out_n = 0;
1193b4be Poul Sander 2025-02-03 21:28 2919
    int buf_packedchars_out_n = 0;
1193b4be Poul Sander 2025-02-03 21:28 2920
    for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
1193b4be Poul Sander 2025-02-03 21:28 2921
    {
1193b4be Poul Sander 2025-02-03 21:28 2922
        ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
1193b4be Poul Sander 2025-02-03 21:28 2923
        if (src_tmp.GlyphsCount == 0)
1193b4be Poul Sander 2025-02-03 21:28 2924
            continue;
1193b4be Poul Sander 2025-02-03 21:28 2925
1193b4be Poul Sander 2025-02-03 21:28 2926
        src_tmp.Rects = &buf_rects[buf_rects_out_n];
1193b4be Poul Sander 2025-02-03 21:28 2927
        src_tmp.PackedChars = &buf_packedchars[buf_packedchars_out_n];
1193b4be Poul Sander 2025-02-03 21:28 2928
        buf_rects_out_n += src_tmp.GlyphsCount;
1193b4be Poul Sander 2025-02-03 21:28 2929
        buf_packedchars_out_n += src_tmp.GlyphsCount;
1193b4be Poul Sander 2025-02-03 21:28 2930
1193b4be Poul Sander 2025-02-03 21:28 2931
        // Convert our ranges in the format stb_truetype wants
1193b4be Poul Sander 2025-02-03 21:28 2932
        ImFontConfig& cfg = atlas->ConfigData[src_i];
1193b4be Poul Sander 2025-02-03 21:28 2933
        src_tmp.PackRange.font_size = cfg.SizePixels * cfg.RasterizerDensity;
1193b4be Poul Sander 2025-02-03 21:28 2934
        src_tmp.PackRange.first_unicode_codepoint_in_range = 0;
1193b4be Poul Sander 2025-02-03 21:28 2935
        src_tmp.PackRange.array_of_unicode_codepoints = src_tmp.GlyphsList.Data;
1193b4be Poul Sander 2025-02-03 21:28 2936
        src_tmp.PackRange.num_chars = src_tmp.GlyphsList.Size;
1193b4be Poul Sander 2025-02-03 21:28 2937
        src_tmp.PackRange.chardata_for_range = src_tmp.PackedChars;
1193b4be Poul Sander 2025-02-03 21:28 2938
        src_tmp.PackRange.h_oversample = (unsigned char)cfg.OversampleH;
1193b4be Poul Sander 2025-02-03 21:28 2939
        src_tmp.PackRange.v_oversample = (unsigned char)cfg.OversampleV;
1193b4be Poul Sander 2025-02-03 21:28 2940
1193b4be Poul Sander 2025-02-03 21:28 2941
        // Gather the sizes of all rectangles we will need to pack (this loop is based on stbtt_PackFontRangesGatherRects)
1193b4be Poul Sander 2025-02-03 21:28 2942
        const float scale = (cfg.SizePixels > 0.0f) ? stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels * cfg.RasterizerDensity) : stbtt_ScaleForMappingEmToPixels(&src_tmp.FontInfo, -cfg.SizePixels * cfg.RasterizerDensity);
1193b4be Poul Sander 2025-02-03 21:28 2943
        const int padding = atlas->TexGlyphPadding;
1193b4be Poul Sander 2025-02-03 21:28 2944
        for (int glyph_i = 0; glyph_i < src_tmp.GlyphsList.Size; glyph_i++)
1193b4be Poul Sander 2025-02-03 21:28 2945
        {
1193b4be Poul Sander 2025-02-03 21:28 2946
            int x0, y0, x1, y1;
1193b4be Poul Sander 2025-02-03 21:28 2947
            const int glyph_index_in_font = stbtt_FindGlyphIndex(&src_tmp.FontInfo, src_tmp.GlyphsList[glyph_i]);
1193b4be Poul Sander 2025-02-03 21:28 2948
            IM_ASSERT(glyph_index_in_font != 0);
1193b4be Poul Sander 2025-02-03 21:28 2949
            stbtt_GetGlyphBitmapBoxSubpixel(&src_tmp.FontInfo, glyph_index_in_font, scale * cfg.OversampleH, scale * cfg.OversampleV, 0, 0, &x0, &y0, &x1, &y1);
1193b4be Poul Sander 2025-02-03 21:28 2950
            src_tmp.Rects[glyph_i].w = (stbrp_coord)(x1 - x0 + padding + cfg.OversampleH - 1);
1193b4be Poul Sander 2025-02-03 21:28 2951
            src_tmp.Rects[glyph_i].h = (stbrp_coord)(y1 - y0 + padding + cfg.OversampleV - 1);
1193b4be Poul Sander 2025-02-03 21:28 2952
            total_surface += src_tmp.Rects[glyph_i].w * src_tmp.Rects[glyph_i].h;
1193b4be Poul Sander 2025-02-03 21:28 2953
        }
1193b4be Poul Sander 2025-02-03 21:28 2954
    }
1193b4be Poul Sander 2025-02-03 21:28 2955
1193b4be Poul Sander 2025-02-03 21:28 2956
    // We need a width for the skyline algorithm, any width!
1193b4be Poul Sander 2025-02-03 21:28 2957
    // The exact width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height.
1193b4be Poul Sander 2025-02-03 21:28 2958
    // User can override TexDesiredWidth and TexGlyphPadding if they wish, otherwise we use a simple heuristic to select the width based on expected surface.
1193b4be Poul Sander 2025-02-03 21:28 2959
    const int surface_sqrt = (int)ImSqrt((float)total_surface) + 1;
1193b4be Poul Sander 2025-02-03 21:28 2960
    atlas->TexHeight = 0;
1193b4be Poul Sander 2025-02-03 21:28 2961
    if (atlas->TexDesiredWidth > 0)
1193b4be Poul Sander 2025-02-03 21:28 2962
        atlas->TexWidth = atlas->TexDesiredWidth;
1193b4be Poul Sander 2025-02-03 21:28 2963
    else
1193b4be Poul Sander 2025-02-03 21:28 2964
        atlas->TexWidth = (surface_sqrt >= 4096 * 0.7f) ? 4096 : (surface_sqrt >= 2048 * 0.7f) ? 2048 : (surface_sqrt >= 1024 * 0.7f) ? 1024 : 512;
1193b4be Poul Sander 2025-02-03 21:28 2965
1193b4be Poul Sander 2025-02-03 21:28 2966
    // 5. Start packing
1193b4be Poul Sander 2025-02-03 21:28 2967
    // Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values).
1193b4be Poul Sander 2025-02-03 21:28 2968
    const int TEX_HEIGHT_MAX = 1024 * 32;
1193b4be Poul Sander 2025-02-03 21:28 2969
    stbtt_pack_context spc = {};
1193b4be Poul Sander 2025-02-03 21:28 2970
    stbtt_PackBegin(&spc, NULL, atlas->TexWidth, TEX_HEIGHT_MAX, 0, atlas->TexGlyphPadding, NULL);
1193b4be Poul Sander 2025-02-03 21:28 2971
    ImFontAtlasBuildPackCustomRects(atlas, spc.pack_info);
1193b4be Poul Sander 2025-02-03 21:28 2972
1193b4be Poul Sander 2025-02-03 21:28 2973
    // 6. Pack each source font. No rendering yet, we are working with rectangles in an infinitely tall texture at this point.
1193b4be Poul Sander 2025-02-03 21:28 2974
    for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
1193b4be Poul Sander 2025-02-03 21:28 2975
    {
1193b4be Poul Sander 2025-02-03 21:28 2976
        ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
1193b4be Poul Sander 2025-02-03 21:28 2977
        if (src_tmp.GlyphsCount == 0)
1193b4be Poul Sander 2025-02-03 21:28 2978
            continue;
1193b4be Poul Sander 2025-02-03 21:28 2979
1193b4be Poul Sander 2025-02-03 21:28 2980
        stbrp_pack_rects((stbrp_context*)spc.pack_info, src_tmp.Rects, src_tmp.GlyphsCount);
1193b4be Poul Sander 2025-02-03 21:28 2981
1193b4be Poul Sander 2025-02-03 21:28 2982
        // Extend texture height and mark missing glyphs as non-packed so we won't render them.
1193b4be Poul Sander 2025-02-03 21:28 2983
        // 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?)
1193b4be Poul Sander 2025-02-03 21:28 2984
        for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++)
1193b4be Poul Sander 2025-02-03 21:28 2985
            if (src_tmp.Rects[glyph_i].was_packed)
1193b4be Poul Sander 2025-02-03 21:28 2986
                atlas->TexHeight = ImMax(atlas->TexHeight, src_tmp.Rects[glyph_i].y + src_tmp.Rects[glyph_i].h);
1193b4be Poul Sander 2025-02-03 21:28 2987
    }
1193b4be Poul Sander 2025-02-03 21:28 2988
1193b4be Poul Sander 2025-02-03 21:28 2989
    // 7. Allocate texture
1193b4be Poul Sander 2025-02-03 21:28 2990
    atlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight);
1193b4be Poul Sander 2025-02-03 21:28 2991
    atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight);
1193b4be Poul Sander 2025-02-03 21:28 2992
    atlas->TexPixelsAlpha8 = (unsigned char*)IM_ALLOC(atlas->TexWidth * atlas->TexHeight);
1193b4be Poul Sander 2025-02-03 21:28 2993
    memset(atlas->TexPixelsAlpha8, 0, atlas->TexWidth * atlas->TexHeight);
1193b4be Poul Sander 2025-02-03 21:28 2994
    spc.pixels = atlas->TexPixelsAlpha8;
1193b4be Poul Sander 2025-02-03 21:28 2995
    spc.height = atlas->TexHeight;
1193b4be Poul Sander 2025-02-03 21:28 2996
1193b4be Poul Sander 2025-02-03 21:28 2997
    // 8. Render/rasterize font characters into the texture
1193b4be Poul Sander 2025-02-03 21:28 2998
    for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
1193b4be Poul Sander 2025-02-03 21:28 2999
    {
1193b4be Poul Sander 2025-02-03 21:28 3000
        ImFontConfig& cfg = atlas->ConfigData[src_i];
1193b4be Poul Sander 2025-02-03 21:28 3001
        ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
1193b4be Poul Sander 2025-02-03 21:28 3002
        if (src_tmp.GlyphsCount == 0)
1193b4be Poul Sander 2025-02-03 21:28 3003
            continue;
1193b4be Poul Sander 2025-02-03 21:28 3004
1193b4be Poul Sander 2025-02-03 21:28 3005
        stbtt_PackFontRangesRenderIntoRects(&spc, &src_tmp.FontInfo, &src_tmp.PackRange, 1, src_tmp.Rects);
1193b4be Poul Sander 2025-02-03 21:28 3006
1193b4be Poul Sander 2025-02-03 21:28 3007
        // Apply multiply operator
1193b4be Poul Sander 2025-02-03 21:28 3008
        if (cfg.RasterizerMultiply != 1.0f)
1193b4be Poul Sander 2025-02-03 21:28 3009
        {
1193b4be Poul Sander 2025-02-03 21:28 3010
            unsigned char multiply_table[256];
1193b4be Poul Sander 2025-02-03 21:28 3011
            ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply);
1193b4be Poul Sander 2025-02-03 21:28 3012
            stbrp_rect* r = &src_tmp.Rects[0];
1193b4be Poul Sander 2025-02-03 21:28 3013
            for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++, r++)
1193b4be Poul Sander 2025-02-03 21:28 3014
                if (r->was_packed)
1193b4be Poul Sander 2025-02-03 21:28 3015
                    ImFontAtlasBuildMultiplyRectAlpha8(multiply_table, atlas->TexPixelsAlpha8, r->x, r->y, r->w, r->h, atlas->TexWidth * 1);
1193b4be Poul Sander 2025-02-03 21:28 3016
        }
1193b4be Poul Sander 2025-02-03 21:28 3017
        src_tmp.Rects = NULL;
1193b4be Poul Sander 2025-02-03 21:28 3018
    }
1193b4be Poul Sander 2025-02-03 21:28 3019
1193b4be Poul Sander 2025-02-03 21:28 3020
    // End packing
1193b4be Poul Sander 2025-02-03 21:28 3021
    stbtt_PackEnd(&spc);
1193b4be Poul Sander 2025-02-03 21:28 3022
    buf_rects.clear();
1193b4be Poul Sander 2025-02-03 21:28 3023
1193b4be Poul Sander 2025-02-03 21:28 3024
    // 9. Setup ImFont and glyphs for runtime
1193b4be Poul Sander 2025-02-03 21:28 3025
    for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
1193b4be Poul Sander 2025-02-03 21:28 3026
    {
1193b4be Poul Sander 2025-02-03 21:28 3027
        // When merging fonts with MergeMode=true:
1193b4be Poul Sander 2025-02-03 21:28 3028
        // - We can have multiple input fonts writing into a same destination font.
1193b4be Poul Sander 2025-02-03 21:28 3029
        // - dst_font->ConfigData is != from cfg which is our source configuration.
1193b4be Poul Sander 2025-02-03 21:28 3030
        ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
1193b4be Poul Sander 2025-02-03 21:28 3031
        ImFontConfig& cfg = atlas->ConfigData[src_i];
1193b4be Poul Sander 2025-02-03 21:28 3032
        ImFont* dst_font = cfg.DstFont;
1193b4be Poul Sander 2025-02-03 21:28 3033
1193b4be Poul Sander 2025-02-03 21:28 3034
        const float font_scale = stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels);
1193b4be Poul Sander 2025-02-03 21:28 3035
        int unscaled_ascent, unscaled_descent, unscaled_line_gap;
1193b4be Poul Sander 2025-02-03 21:28 3036
        stbtt_GetFontVMetrics(&src_tmp.FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap);
1193b4be Poul Sander 2025-02-03 21:28 3037
1193b4be Poul Sander 2025-02-03 21:28 3038
        const float ascent = ImCeil(unscaled_ascent * font_scale);
1193b4be Poul Sander 2025-02-03 21:28 3039
        const float descent = ImFloor(unscaled_descent * font_scale);
1193b4be Poul Sander 2025-02-03 21:28 3040
        ImFontAtlasBuildSetupFont(atlas, dst_font, &cfg, ascent, descent);
1193b4be Poul Sander 2025-02-03 21:28 3041
        const float font_off_x = cfg.GlyphOffset.x;
1193b4be Poul Sander 2025-02-03 21:28 3042
        const float font_off_y = cfg.GlyphOffset.y + IM_ROUND(dst_font->Ascent);
1193b4be Poul Sander 2025-02-03 21:28 3043
1193b4be Poul Sander 2025-02-03 21:28 3044
        const float inv_rasterization_scale = 1.0f / cfg.RasterizerDensity;
1193b4be Poul Sander 2025-02-03 21:28 3045
1193b4be Poul Sander 2025-02-03 21:28 3046
        for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++)
1193b4be Poul Sander 2025-02-03 21:28 3047
        {
1193b4be Poul Sander 2025-02-03 21:28 3048
            // Register glyph
1193b4be Poul Sander 2025-02-03 21:28 3049
            const int codepoint = src_tmp.GlyphsList[glyph_i];
1193b4be Poul Sander 2025-02-03 21:28 3050
            const stbtt_packedchar& pc = src_tmp.PackedChars[glyph_i];
1193b4be Poul Sander 2025-02-03 21:28 3051
            stbtt_aligned_quad q;
1193b4be Poul Sander 2025-02-03 21:28 3052
            float unused_x = 0.0f, unused_y = 0.0f;
1193b4be Poul Sander 2025-02-03 21:28 3053
            stbtt_GetPackedQuad(src_tmp.PackedChars, atlas->TexWidth, atlas->TexHeight, glyph_i, &unused_x, &unused_y, &q, 0);
1193b4be Poul Sander 2025-02-03 21:28 3054
            float x0 = q.x0 * inv_rasterization_scale + font_off_x;
1193b4be Poul Sander 2025-02-03 21:28 3055
            float y0 = q.y0 * inv_rasterization_scale + font_off_y;
1193b4be Poul Sander 2025-02-03 21:28 3056
            float x1 = q.x1 * inv_rasterization_scale + font_off_x;
1193b4be Poul Sander 2025-02-03 21:28 3057
            float y1 = q.y1 * inv_rasterization_scale + font_off_y;
1193b4be Poul Sander 2025-02-03 21:28 3058
            dst_font->AddGlyph(&cfg, (ImWchar)codepoint, x0, y0, x1, y1, q.s0, q.t0, q.s1, q.t1, pc.xadvance * inv_rasterization_scale);
1193b4be Poul Sander 2025-02-03 21:28 3059
        }
1193b4be Poul Sander 2025-02-03 21:28 3060
    }
1193b4be Poul Sander 2025-02-03 21:28 3061
1193b4be Poul Sander 2025-02-03 21:28 3062
    // Cleanup
1193b4be Poul Sander 2025-02-03 21:28 3063
    src_tmp_array.clear_destruct();
1193b4be Poul Sander 2025-02-03 21:28 3064
1193b4be Poul Sander 2025-02-03 21:28 3065
    ImFontAtlasBuildFinish(atlas);
1193b4be Poul Sander 2025-02-03 21:28 3066
    return true;
1193b4be Poul Sander 2025-02-03 21:28 3067
}
1193b4be Poul Sander 2025-02-03 21:28 3068
1193b4be Poul Sander 2025-02-03 21:28 3069
const ImFontBuilderIO* ImFontAtlasGetBuilderForStbTruetype()
1193b4be Poul Sander 2025-02-03 21:28 3070
{
1193b4be Poul Sander 2025-02-03 21:28 3071
    static ImFontBuilderIO io;
1193b4be Poul Sander 2025-02-03 21:28 3072
    io.FontBuilder_Build = ImFontAtlasBuildWithStbTruetype;
1193b4be Poul Sander 2025-02-03 21:28 3073
    return &io;
1193b4be Poul Sander 2025-02-03 21:28 3074
}
1193b4be Poul Sander 2025-02-03 21:28 3075
1193b4be Poul Sander 2025-02-03 21:28 3076
#endif // IMGUI_ENABLE_STB_TRUETYPE
1193b4be Poul Sander 2025-02-03 21:28 3077
1193b4be Poul Sander 2025-02-03 21:28 3078
void ImFontAtlasUpdateConfigDataPointers(ImFontAtlas* atlas)
1193b4be Poul Sander 2025-02-03 21:28 3079
{
1193b4be Poul Sander 2025-02-03 21:28 3080
    for (ImFontConfig& font_cfg : atlas->ConfigData)
1193b4be Poul Sander 2025-02-03 21:28 3081
    {
1193b4be Poul Sander 2025-02-03 21:28 3082
        ImFont* font = font_cfg.DstFont;
1193b4be Poul Sander 2025-02-03 21:28 3083
        if (!font_cfg.MergeMode)
1193b4be Poul Sander 2025-02-03 21:28 3084
        {
1193b4be Poul Sander 2025-02-03 21:28 3085
            font->ConfigData = &font_cfg;
1193b4be Poul Sander 2025-02-03 21:28 3086
            font->ConfigDataCount = 0;
1193b4be Poul Sander 2025-02-03 21:28 3087
        }
1193b4be Poul Sander 2025-02-03 21:28 3088
        font->ConfigDataCount++;
1193b4be Poul Sander 2025-02-03 21:28 3089
    }
1193b4be Poul Sander 2025-02-03 21:28 3090
}
1193b4be Poul Sander 2025-02-03 21:28 3091
1193b4be Poul Sander 2025-02-03 21:28 3092
void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent)
1193b4be Poul Sander 2025-02-03 21:28 3093
{
1193b4be Poul Sander 2025-02-03 21:28 3094
    if (!font_config->MergeMode)
1193b4be Poul Sander 2025-02-03 21:28 3095
    {
1193b4be Poul Sander 2025-02-03 21:28 3096
        font->ClearOutputData();
1193b4be Poul Sander 2025-02-03 21:28 3097
        font->FontSize = font_config->SizePixels;
1193b4be Poul Sander 2025-02-03 21:28 3098
        IM_ASSERT(font->ConfigData == font_config);
1193b4be Poul Sander 2025-02-03 21:28 3099
        font->ContainerAtlas = atlas;
1193b4be Poul Sander 2025-02-03 21:28 3100
        font->Ascent = ascent;
1193b4be Poul Sander 2025-02-03 21:28 3101
        font->Descent = descent;
1193b4be Poul Sander 2025-02-03 21:28 3102
    }
1193b4be Poul Sander 2025-02-03 21:28 3103
}
1193b4be Poul Sander 2025-02-03 21:28 3104
1193b4be Poul Sander 2025-02-03 21:28 3105
void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque)
1193b4be Poul Sander 2025-02-03 21:28 3106
{
1193b4be Poul Sander 2025-02-03 21:28 3107
    stbrp_context* pack_context = (stbrp_context*)stbrp_context_opaque;
1193b4be Poul Sander 2025-02-03 21:28 3108
    IM_ASSERT(pack_context != NULL);
1193b4be Poul Sander 2025-02-03 21:28 3109
1193b4be Poul Sander 2025-02-03 21:28 3110
    ImVector<ImFontAtlasCustomRect>& user_rects = atlas->CustomRects;
1193b4be Poul Sander 2025-02-03 21:28 3111
    IM_ASSERT(user_rects.Size >= 1); // We expect at least the default custom rects to be registered, else something went wrong.
1193b4be Poul Sander 2025-02-03 21:28 3112
#ifdef __GNUC__
1193b4be Poul Sander 2025-02-03 21:28 3113
    if (user_rects.Size < 1) { __builtin_unreachable(); } // Workaround for GCC bug if IM_ASSERT() is defined to conditionally throw (see #5343)
1193b4be Poul Sander 2025-02-03 21:28 3114
#endif
1193b4be Poul Sander 2025-02-03 21:28 3115
1193b4be Poul Sander 2025-02-03 21:28 3116
    ImVector<stbrp_rect> pack_rects;
1193b4be Poul Sander 2025-02-03 21:28 3117
    pack_rects.resize(user_rects.Size);
1193b4be Poul Sander 2025-02-03 21:28 3118
    memset(pack_rects.Data, 0, (size_t)pack_rects.size_in_bytes());
1193b4be Poul Sander 2025-02-03 21:28 3119
    for (int i = 0; i < user_rects.Size; i++)
1193b4be Poul Sander 2025-02-03 21:28 3120
    {
1193b4be Poul Sander 2025-02-03 21:28 3121
        pack_rects[i].w = user_rects[i].Width;
1193b4be Poul Sander 2025-02-03 21:28 3122
        pack_rects[i].h = user_rects[i].Height;
1193b4be Poul Sander 2025-02-03 21:28 3123
    }
1193b4be Poul Sander 2025-02-03 21:28 3124
    stbrp_pack_rects(pack_context, &pack_rects[0], pack_rects.Size);
1193b4be Poul Sander 2025-02-03 21:28 3125
    for (int i = 0; i < pack_rects.Size; i++)
1193b4be Poul Sander 2025-02-03 21:28 3126
        if (pack_rects[i].was_packed)
1193b4be Poul Sander 2025-02-03 21:28 3127
        {
1193b4be Poul Sander 2025-02-03 21:28 3128
            user_rects[i].X = (unsigned short)pack_rects[i].x;
1193b4be Poul Sander 2025-02-03 21:28 3129
            user_rects[i].Y = (unsigned short)pack_rects[i].y;
1193b4be Poul Sander 2025-02-03 21:28 3130
            IM_ASSERT(pack_rects[i].w == user_rects[i].Width && pack_rects[i].h == user_rects[i].Height);
1193b4be Poul Sander 2025-02-03 21:28 3131
            atlas->TexHeight = ImMax(atlas->TexHeight, pack_rects[i].y + pack_rects[i].h);
1193b4be Poul Sander 2025-02-03 21:28 3132
        }
1193b4be Poul Sander 2025-02-03 21:28 3133
}
1193b4be Poul Sander 2025-02-03 21:28 3134
1193b4be Poul Sander 2025-02-03 21:28 3135
void ImFontAtlasBuildRender8bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned char in_marker_pixel_value)
1193b4be Poul Sander 2025-02-03 21:28 3136
{
1193b4be Poul Sander 2025-02-03 21:28 3137
    IM_ASSERT(x >= 0 && x + w <= atlas->TexWidth);
1193b4be Poul Sander 2025-02-03 21:28 3138
    IM_ASSERT(y >= 0 && y + h <= atlas->TexHeight);
1193b4be Poul Sander 2025-02-03 21:28 3139
    unsigned char* out_pixel = atlas->TexPixelsAlpha8 + x + (y * atlas->TexWidth);
1193b4be Poul Sander 2025-02-03 21:28 3140
    for (int off_y = 0; off_y < h; off_y++, out_pixel += atlas->TexWidth, in_str += w)
1193b4be Poul Sander 2025-02-03 21:28 3141
        for (int off_x = 0; off_x < w; off_x++)
1193b4be Poul Sander 2025-02-03 21:28 3142
            out_pixel[off_x] = (in_str[off_x] == in_marker_char) ? in_marker_pixel_value : 0x00;
1193b4be Poul Sander 2025-02-03 21:28 3143
}
1193b4be Poul Sander 2025-02-03 21:28 3144
1193b4be Poul Sander 2025-02-03 21:28 3145
void ImFontAtlasBuildRender32bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned int in_marker_pixel_value)
1193b4be Poul Sander 2025-02-03 21:28 3146
{
1193b4be Poul Sander 2025-02-03 21:28 3147
    IM_ASSERT(x >= 0 && x + w <= atlas->TexWidth);
1193b4be Poul Sander 2025-02-03 21:28 3148
    IM_ASSERT(y >= 0 && y + h <= atlas->TexHeight);
1193b4be Poul Sander 2025-02-03 21:28 3149
    unsigned int* out_pixel = atlas->TexPixelsRGBA32 + x + (y * atlas->TexWidth);
1193b4be Poul Sander 2025-02-03 21:28 3150
    for (int off_y = 0; off_y < h; off_y++, out_pixel += atlas->TexWidth, in_str += w)
1193b4be Poul Sander 2025-02-03 21:28 3151
        for (int off_x = 0; off_x < w; off_x++)
1193b4be Poul Sander 2025-02-03 21:28 3152
            out_pixel[off_x] = (in_str[off_x] == in_marker_char) ? in_marker_pixel_value : IM_COL32_BLACK_TRANS;
1193b4be Poul Sander 2025-02-03 21:28 3153
}
1193b4be Poul Sander 2025-02-03 21:28 3154
1193b4be Poul Sander 2025-02-03 21:28 3155
static void ImFontAtlasBuildRenderDefaultTexData(ImFontAtlas* atlas)
1193b4be Poul Sander 2025-02-03 21:28 3156
{
1193b4be Poul Sander 2025-02-03 21:28 3157
    ImFontAtlasCustomRect* r = atlas->GetCustomRectByIndex(atlas->PackIdMouseCursors);
1193b4be Poul Sander 2025-02-03 21:28 3158
    IM_ASSERT(r->IsPacked());
1193b4be Poul Sander 2025-02-03 21:28 3159
1193b4be Poul Sander 2025-02-03 21:28 3160
    const int w = atlas->TexWidth;
1193b4be Poul Sander 2025-02-03 21:28 3161
    if (!(atlas->Flags & ImFontAtlasFlags_NoMouseCursors))
1193b4be Poul Sander 2025-02-03 21:28 3162
    {
1193b4be Poul Sander 2025-02-03 21:28 3163
        // Render/copy pixels
1193b4be Poul Sander 2025-02-03 21:28 3164
        IM_ASSERT(r->Width == FONT_ATLAS_DEFAULT_TEX_DATA_W * 2 + 1 && r->Height == FONT_ATLAS_DEFAULT_TEX_DATA_H);
1193b4be Poul Sander 2025-02-03 21:28 3165
        const int x_for_white = r->X;
1193b4be Poul Sander 2025-02-03 21:28 3166
        const int x_for_black = r->X + FONT_ATLAS_DEFAULT_TEX_DATA_W + 1;
1193b4be Poul Sander 2025-02-03 21:28 3167
        if (atlas->TexPixelsAlpha8 != NULL)
1193b4be Poul Sander 2025-02-03 21:28 3168
        {
1193b4be Poul Sander 2025-02-03 21:28 3169
            ImFontAtlasBuildRender8bppRectFromString(atlas, x_for_white, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, '.', 0xFF);
1193b4be Poul Sander 2025-02-03 21:28 3170
            ImFontAtlasBuildRender8bppRectFromString(atlas, x_for_black, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, 'X', 0xFF);
1193b4be Poul Sander 2025-02-03 21:28 3171
        }
1193b4be Poul Sander 2025-02-03 21:28 3172
        else
1193b4be Poul Sander 2025-02-03 21:28 3173
        {
1193b4be Poul Sander 2025-02-03 21:28 3174
            ImFontAtlasBuildRender32bppRectFromString(atlas, x_for_white, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, '.', IM_COL32_WHITE);
1193b4be Poul Sander 2025-02-03 21:28 3175
            ImFontAtlasBuildRender32bppRectFromString(atlas, x_for_black, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, 'X', IM_COL32_WHITE);
1193b4be Poul Sander 2025-02-03 21:28 3176
        }
1193b4be Poul Sander 2025-02-03 21:28 3177
    }
1193b4be Poul Sander 2025-02-03 21:28 3178
    else
1193b4be Poul Sander 2025-02-03 21:28 3179
    {
1193b4be Poul Sander 2025-02-03 21:28 3180
        // Render 4 white pixels
1193b4be Poul Sander 2025-02-03 21:28 3181
        IM_ASSERT(r->Width == 2 && r->Height == 2);
1193b4be Poul Sander 2025-02-03 21:28 3182
        const int offset = (int)r->X + (int)r->Y * w;
1193b4be Poul Sander 2025-02-03 21:28 3183
        if (atlas->TexPixelsAlpha8 != NULL)
1193b4be Poul Sander 2025-02-03 21:28 3184
        {
1193b4be Poul Sander 2025-02-03 21:28 3185
            atlas->TexPixelsAlpha8[offset] = atlas->TexPixelsAlpha8[offset + 1] = atlas->TexPixelsAlpha8[offset + w] = atlas->TexPixelsAlpha8[offset + w + 1] = 0xFF;
1193b4be Poul Sander 2025-02-03 21:28 3186
        }
1193b4be Poul Sander 2025-02-03 21:28 3187
        else
1193b4be Poul Sander 2025-02-03 21:28 3188
        {
1193b4be Poul Sander 2025-02-03 21:28 3189
            atlas->TexPixelsRGBA32[offset] = atlas->TexPixelsRGBA32[offset + 1] = atlas->TexPixelsRGBA32[offset + w] = atlas->TexPixelsRGBA32[offset + w + 1] = IM_COL32_WHITE;
1193b4be Poul Sander 2025-02-03 21:28 3190
        }
1193b4be Poul Sander 2025-02-03 21:28 3191
    }
1193b4be Poul Sander 2025-02-03 21:28 3192
    atlas->TexUvWhitePixel = ImVec2((r->X + 0.5f) * atlas->TexUvScale.x, (r->Y + 0.5f) * atlas->TexUvScale.y);
1193b4be Poul Sander 2025-02-03 21:28 3193
}
1193b4be Poul Sander 2025-02-03 21:28 3194
1193b4be Poul Sander 2025-02-03 21:28 3195
static void ImFontAtlasBuildRenderLinesTexData(ImFontAtlas* atlas)
1193b4be Poul Sander 2025-02-03 21:28 3196
{
1193b4be Poul Sander 2025-02-03 21:28 3197
    if (atlas->Flags & ImFontAtlasFlags_NoBakedLines)
1193b4be Poul Sander 2025-02-03 21:28 3198
        return;
1193b4be Poul Sander 2025-02-03 21:28 3199
1193b4be Poul Sander 2025-02-03 21:28 3200
    // This generates a triangular shape in the texture, with the various line widths stacked on top of each other to allow interpolation between them
1193b4be Poul Sander 2025-02-03 21:28 3201
    ImFontAtlasCustomRect* r = atlas->GetCustomRectByIndex(atlas->PackIdLines);
1193b4be Poul Sander 2025-02-03 21:28 3202
    IM_ASSERT(r->IsPacked());
1193b4be Poul Sander 2025-02-03 21:28 3203
    for (unsigned int n = 0; n < IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1; n++) // +1 because of the zero-width row
1193b4be Poul Sander 2025-02-03 21:28 3204
    {
1193b4be Poul Sander 2025-02-03 21:28 3205
        // Each line consists of at least two empty pixels at the ends, with a line of solid pixels in the middle
1193b4be Poul Sander 2025-02-03 21:28 3206
        unsigned int y = n;
1193b4be Poul Sander 2025-02-03 21:28 3207
        unsigned int line_width = n;
1193b4be Poul Sander 2025-02-03 21:28 3208
        unsigned int pad_left = (r->Width - line_width) / 2;
1193b4be Poul Sander 2025-02-03 21:28 3209
        unsigned int pad_right = r->Width - (pad_left + line_width);
1193b4be Poul Sander 2025-02-03 21:28 3210
1193b4be Poul Sander 2025-02-03 21:28 3211
        // Write each slice
1193b4be Poul Sander 2025-02-03 21:28 3212
        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
1193b4be Poul Sander 2025-02-03 21:28 3213
        if (atlas->TexPixelsAlpha8 != NULL)
1193b4be Poul Sander 2025-02-03 21:28 3214
        {
1193b4be Poul Sander 2025-02-03 21:28 3215
            unsigned char* write_ptr = &atlas->TexPixelsAlpha8[r->X + ((r->Y + y) * atlas->TexWidth)];
1193b4be Poul Sander 2025-02-03 21:28 3216
            for (unsigned int i = 0; i < pad_left; i++)
1193b4be Poul Sander 2025-02-03 21:28 3217
                *(write_ptr + i) = 0x00;
1193b4be Poul Sander 2025-02-03 21:28 3218
1193b4be Poul Sander 2025-02-03 21:28 3219
            for (unsigned int i = 0; i < line_width; i++)
1193b4be Poul Sander 2025-02-03 21:28 3220
                *(write_ptr + pad_left + i) = 0xFF;
1193b4be Poul Sander 2025-02-03 21:28 3221
1193b4be Poul Sander 2025-02-03 21:28 3222
            for (unsigned int i = 0; i < pad_right; i++)
1193b4be Poul Sander 2025-02-03 21:28 3223
                *(write_ptr + pad_left + line_width + i) = 0x00;
1193b4be Poul Sander 2025-02-03 21:28 3224
        }
1193b4be Poul Sander 2025-02-03 21:28 3225
        else
1193b4be Poul Sander 2025-02-03 21:28 3226
        {
1193b4be Poul Sander 2025-02-03 21:28 3227
            unsigned int* write_ptr = &atlas->TexPixelsRGBA32[r->X + ((r->Y + y) * atlas->TexWidth)];
1193b4be Poul Sander 2025-02-03 21:28 3228
            for (unsigned int i = 0; i < pad_left; i++)
1193b4be Poul Sander 2025-02-03 21:28 3229
                *(write_ptr + i) = IM_COL32(255, 255, 255, 0);
1193b4be Poul Sander 2025-02-03 21:28 3230
1193b4be Poul Sander 2025-02-03 21:28 3231
            for (unsigned int i = 0; i < line_width; i++)
1193b4be Poul Sander 2025-02-03 21:28 3232
                *(write_ptr + pad_left + i) = IM_COL32_WHITE;
1193b4be Poul Sander 2025-02-03 21:28 3233
1193b4be Poul Sander 2025-02-03 21:28 3234
            for (unsigned int i = 0; i < pad_right; i++)
1193b4be Poul Sander 2025-02-03 21:28 3235
                *(write_ptr + pad_left + line_width + i) = IM_COL32(255, 255, 255, 0);
1193b4be Poul Sander 2025-02-03 21:28 3236
        }
1193b4be Poul Sander 2025-02-03 21:28 3237
1193b4be Poul Sander 2025-02-03 21:28 3238
        // Calculate UVs for this line
1193b4be Poul Sander 2025-02-03 21:28 3239
        ImVec2 uv0 = ImVec2((float)(r->X + pad_left - 1), (float)(r->Y + y)) * atlas->TexUvScale;
1193b4be Poul Sander 2025-02-03 21:28 3240
        ImVec2 uv1 = ImVec2((float)(r->X + pad_left + line_width + 1), (float)(r->Y + y + 1)) * atlas->TexUvScale;
1193b4be Poul Sander 2025-02-03 21:28 3241
        float half_v = (uv0.y + uv1.y) * 0.5f; // Calculate a constant V in the middle of the row to avoid sampling artifacts
1193b4be Poul Sander 2025-02-03 21:28 3242
        atlas->TexUvLines[n] = ImVec4(uv0.x, half_v, uv1.x, half_v);
1193b4be Poul Sander 2025-02-03 21:28 3243
    }
1193b4be Poul Sander 2025-02-03 21:28 3244
}
1193b4be Poul Sander 2025-02-03 21:28 3245
1193b4be Poul Sander 2025-02-03 21:28 3246
// Note: this is called / shared by both the stb_truetype and the FreeType builder
1193b4be Poul Sander 2025-02-03 21:28 3247
void ImFontAtlasBuildInit(ImFontAtlas* atlas)
1193b4be Poul Sander 2025-02-03 21:28 3248
{
1193b4be Poul Sander 2025-02-03 21:28 3249
    // Round font size
1193b4be Poul Sander 2025-02-03 21:28 3250
    // - We started rounding in 1.90 WIP (18991) as our layout system currently doesn't support non-rounded font size well yet.
1193b4be Poul Sander 2025-02-03 21:28 3251
    // - Note that using io.FontGlobalScale or SetWindowFontScale(), with are legacy-ish, partially supported features, can still lead to unrounded sizes.
1193b4be Poul Sander 2025-02-03 21:28 3252
    // - We may support it better later and remove this rounding.
1193b4be Poul Sander 2025-02-03 21:28 3253
    for (ImFontConfig& cfg : atlas->ConfigData)
1193b4be Poul Sander 2025-02-03 21:28 3254
       cfg.SizePixels = ImTrunc(cfg.SizePixels);
1193b4be Poul Sander 2025-02-03 21:28 3255
1193b4be Poul Sander 2025-02-03 21:28 3256
    // Register texture region for mouse cursors or standard white pixels
1193b4be Poul Sander 2025-02-03 21:28 3257
    if (atlas->PackIdMouseCursors < 0)
1193b4be Poul Sander 2025-02-03 21:28 3258
    {
1193b4be Poul Sander 2025-02-03 21:28 3259
        if (!(atlas->Flags & ImFontAtlasFlags_NoMouseCursors))
1193b4be Poul Sander 2025-02-03 21:28 3260
            atlas->PackIdMouseCursors = atlas->AddCustomRectRegular(FONT_ATLAS_DEFAULT_TEX_DATA_W * 2 + 1, FONT_ATLAS_DEFAULT_TEX_DATA_H);
1193b4be Poul Sander 2025-02-03 21:28 3261
        else
1193b4be Poul Sander 2025-02-03 21:28 3262
            atlas->PackIdMouseCursors = atlas->AddCustomRectRegular(2, 2);
1193b4be Poul Sander 2025-02-03 21:28 3263
    }
1193b4be Poul Sander 2025-02-03 21:28 3264
1193b4be Poul Sander 2025-02-03 21:28 3265
    // Register texture region for thick lines
1193b4be Poul Sander 2025-02-03 21:28 3266
    // 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
1193b4be Poul Sander 2025-02-03 21:28 3267
    if (atlas->PackIdLines < 0)
1193b4be Poul Sander 2025-02-03 21:28 3268
    {
1193b4be Poul Sander 2025-02-03 21:28 3269
        if (!(atlas->Flags & ImFontAtlasFlags_NoBakedLines))
1193b4be Poul Sander 2025-02-03 21:28 3270
            atlas->PackIdLines = atlas->AddCustomRectRegular(IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 2, IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1);
1193b4be Poul Sander 2025-02-03 21:28 3271
    }
1193b4be Poul Sander 2025-02-03 21:28 3272
}
1193b4be Poul Sander 2025-02-03 21:28 3273
1193b4be Poul Sander 2025-02-03 21:28 3274
// This is called/shared by both the stb_truetype and the FreeType builder.
1193b4be Poul Sander 2025-02-03 21:28 3275
void ImFontAtlasBuildFinish(ImFontAtlas* atlas)
1193b4be Poul Sander 2025-02-03 21:28 3276
{
1193b4be Poul Sander 2025-02-03 21:28 3277
    // Render into our custom data blocks
1193b4be Poul Sander 2025-02-03 21:28 3278
    IM_ASSERT(atlas->TexPixelsAlpha8 != NULL || atlas->TexPixelsRGBA32 != NULL);
1193b4be Poul Sander 2025-02-03 21:28 3279
    ImFontAtlasBuildRenderDefaultTexData(atlas);
1193b4be Poul Sander 2025-02-03 21:28 3280
    ImFontAtlasBuildRenderLinesTexData(atlas);
1193b4be Poul Sander 2025-02-03 21:28 3281
1193b4be Poul Sander 2025-02-03 21:28 3282
    // Register custom rectangle glyphs
1193b4be Poul Sander 2025-02-03 21:28 3283
    for (int i = 0; i < atlas->CustomRects.Size; i++)
1193b4be Poul Sander 2025-02-03 21:28 3284
    {
1193b4be Poul Sander 2025-02-03 21:28 3285
        const ImFontAtlasCustomRect* r = &atlas->CustomRects[i];
1193b4be Poul Sander 2025-02-03 21:28 3286
        if (r->Font == NULL || r->GlyphID == 0)
1193b4be Poul Sander 2025-02-03 21:28 3287
            continue;
1193b4be Poul Sander 2025-02-03 21:28 3288
1193b4be Poul Sander 2025-02-03 21:28 3289
        // Will ignore ImFontConfig settings: GlyphMinAdvanceX, GlyphMinAdvanceY, GlyphExtraSpacing, PixelSnapH
1193b4be Poul Sander 2025-02-03 21:28 3290
        IM_ASSERT(r->Font->ContainerAtlas == atlas);
1193b4be Poul Sander 2025-02-03 21:28 3291
        ImVec2 uv0, uv1;
1193b4be Poul Sander 2025-02-03 21:28 3292
        atlas->CalcCustomRectUV(r, &uv0, &uv1);
1193b4be Poul Sander 2025-02-03 21:28 3293
        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);
1193b4be Poul Sander 2025-02-03 21:28 3294
    }
1193b4be Poul Sander 2025-02-03 21:28 3295
1193b4be Poul Sander 2025-02-03 21:28 3296
    // Build all fonts lookup tables
1193b4be Poul Sander 2025-02-03 21:28 3297
    for (ImFont* font : atlas->Fonts)
1193b4be Poul Sander 2025-02-03 21:28 3298
        if (font->DirtyLookupTables)
1193b4be Poul Sander 2025-02-03 21:28 3299
            font->BuildLookupTable();
1193b4be Poul Sander 2025-02-03 21:28 3300
1193b4be Poul Sander 2025-02-03 21:28 3301
    atlas->TexReady = true;
1193b4be Poul Sander 2025-02-03 21:28 3302
}
1193b4be Poul Sander 2025-02-03 21:28 3303
1193b4be Poul Sander 2025-02-03 21:28 3304
// Retrieve list of range (2 int per range, values are inclusive)
1193b4be Poul Sander 2025-02-03 21:28 3305
const ImWchar*   ImFontAtlas::GetGlyphRangesDefault()
1193b4be Poul Sander 2025-02-03 21:28 3306
{
1193b4be Poul Sander 2025-02-03 21:28 3307
    static const ImWchar ranges[] =
1193b4be Poul Sander 2025-02-03 21:28 3308
    {
1193b4be Poul Sander 2025-02-03 21:28 3309
        0x0020, 0x00FF, // Basic Latin + Latin Supplement
1193b4be Poul Sander 2025-02-03 21:28 3310
        0,
1193b4be Poul Sander 2025-02-03 21:28 3311
    };
1193b4be Poul Sander 2025-02-03 21:28 3312
    return &ranges[0];
1193b4be Poul Sander 2025-02-03 21:28 3313
}
1193b4be Poul Sander 2025-02-03 21:28 3314
1193b4be Poul Sander 2025-02-03 21:28 3315
const ImWchar*   ImFontAtlas::GetGlyphRangesGreek()
1193b4be Poul Sander 2025-02-03 21:28 3316
{
1193b4be Poul Sander 2025-02-03 21:28 3317
    static const ImWchar ranges[] =
1193b4be Poul Sander 2025-02-03 21:28 3318
    {
1193b4be Poul Sander 2025-02-03 21:28 3319
        0x0020, 0x00FF, // Basic Latin + Latin Supplement
1193b4be Poul Sander 2025-02-03 21:28 3320
        0x0370, 0x03FF, // Greek and Coptic
1193b4be Poul Sander 2025-02-03 21:28 3321
        0,
1193b4be Poul Sander 2025-02-03 21:28 3322
    };
1193b4be Poul Sander 2025-02-03 21:28 3323
    return &ranges[0];
1193b4be Poul Sander 2025-02-03 21:28 3324
}
1193b4be Poul Sander 2025-02-03 21:28 3325
1193b4be Poul Sander 2025-02-03 21:28 3326
const ImWchar*  ImFontAtlas::GetGlyphRangesKorean()
1193b4be Poul Sander 2025-02-03 21:28 3327
{
1193b4be Poul Sander 2025-02-03 21:28 3328
    static const ImWchar ranges[] =
1193b4be Poul Sander 2025-02-03 21:28 3329
    {
1193b4be Poul Sander 2025-02-03 21:28 3330
        0x0020, 0x00FF, // Basic Latin + Latin Supplement
1193b4be Poul Sander 2025-02-03 21:28 3331
        0x3131, 0x3163, // Korean alphabets
1193b4be Poul Sander 2025-02-03 21:28 3332
        0xAC00, 0xD7A3, // Korean characters
1193b4be Poul Sander 2025-02-03 21:28 3333
        0xFFFD, 0xFFFD, // Invalid
1193b4be Poul Sander 2025-02-03 21:28 3334
        0,
1193b4be Poul Sander 2025-02-03 21:28 3335
    };
1193b4be Poul Sander 2025-02-03 21:28 3336
    return &ranges[0];
1193b4be Poul Sander 2025-02-03 21:28 3337
}
1193b4be Poul Sander 2025-02-03 21:28 3338
1193b4be Poul Sander 2025-02-03 21:28 3339
const ImWchar*  ImFontAtlas::GetGlyphRangesChineseFull()
1193b4be Poul Sander 2025-02-03 21:28 3340
{
1193b4be Poul Sander 2025-02-03 21:28 3341
    static const ImWchar ranges[] =
1193b4be Poul Sander 2025-02-03 21:28 3342
    {
1193b4be Poul Sander 2025-02-03 21:28 3343
        0x0020, 0x00FF, // Basic Latin + Latin Supplement
1193b4be Poul Sander 2025-02-03 21:28 3344
        0x2000, 0x206F, // General Punctuation
1193b4be Poul Sander 2025-02-03 21:28 3345
        0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
1193b4be Poul Sander 2025-02-03 21:28 3346
        0x31F0, 0x31FF, // Katakana Phonetic Extensions
1193b4be Poul Sander 2025-02-03 21:28 3347
        0xFF00, 0xFFEF, // Half-width characters
1193b4be Poul Sander 2025-02-03 21:28 3348
        0xFFFD, 0xFFFD, // Invalid
1193b4be Poul Sander 2025-02-03 21:28 3349
        0x4e00, 0x9FAF, // CJK Ideograms
1193b4be Poul Sander 2025-02-03 21:28 3350
        0,
1193b4be Poul Sander 2025-02-03 21:28 3351
    };
1193b4be Poul Sander 2025-02-03 21:28 3352
    return &ranges[0];
1193b4be Poul Sander 2025-02-03 21:28 3353
}
1193b4be Poul Sander 2025-02-03 21:28 3354
1193b4be Poul Sander 2025-02-03 21:28 3355
static void UnpackAccumulativeOffsetsIntoRanges(int base_codepoint, const short* accumulative_offsets, int accumulative_offsets_count, ImWchar* out_ranges)
1193b4be Poul Sander 2025-02-03 21:28 3356
{
1193b4be Poul Sander 2025-02-03 21:28 3357
    for (int n = 0; n < accumulative_offsets_count; n++, out_ranges += 2)
1193b4be Poul Sander 2025-02-03 21:28 3358
    {
1193b4be Poul Sander 2025-02-03 21:28 3359
        out_ranges[0] = out_ranges[1] = (ImWchar)(base_codepoint + accumulative_offsets[n]);
1193b4be Poul Sander 2025-02-03 21:28 3360
        base_codepoint += accumulative_offsets[n];
1193b4be Poul Sander 2025-02-03 21:28 3361
    }
1193b4be Poul Sander 2025-02-03 21:28 3362
    out_ranges[0] = 0;
1193b4be Poul Sander 2025-02-03 21:28 3363
}
1193b4be Poul Sander 2025-02-03 21:28 3364
1193b4be Poul Sander 2025-02-03 21:28 3365
//-------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 3366
// [SECTION] ImFontAtlas glyph ranges helpers
1193b4be Poul Sander 2025-02-03 21:28 3367
//-------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 3368
1193b4be Poul Sander 2025-02-03 21:28 3369
const ImWchar*  ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon()
1193b4be Poul Sander 2025-02-03 21:28 3370
{
1193b4be Poul Sander 2025-02-03 21:28 3371
    // Store 2500 regularly used characters for Simplified Chinese.
1193b4be Poul Sander 2025-02-03 21:28 3372
    // 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
1193b4be Poul Sander 2025-02-03 21:28 3373
    // This table covers 97.97% of all characters used during the month in July, 1987.
1193b4be Poul Sander 2025-02-03 21:28 3374
    // You can use ImFontGlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters.
1193b4be Poul Sander 2025-02-03 21:28 3375
    // (Stored as accumulative offsets from the initial unicode codepoint 0x4E00. This encoding is designed to helps us compact the source code size.)
1193b4be Poul Sander 2025-02-03 21:28 3376
    static const short accumulative_offsets_from_0x4E00[] =
1193b4be Poul Sander 2025-02-03 21:28 3377
    {
1193b4be Poul Sander 2025-02-03 21:28 3378
        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,
1193b4be Poul Sander 2025-02-03 21:28 3379
        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,
1193b4be Poul Sander 2025-02-03 21:28 3380
        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,
1193b4be Poul Sander 2025-02-03 21:28 3381
        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,
1193b4be Poul Sander 2025-02-03 21:28 3382
        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,
1193b4be Poul Sander 2025-02-03 21:28 3383
        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,
1193b4be Poul Sander 2025-02-03 21:28 3384
        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,
1193b4be Poul Sander 2025-02-03 21:28 3385
        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,
1193b4be Poul Sander 2025-02-03 21:28 3386
        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,
1193b4be Poul Sander 2025-02-03 21:28 3387
        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,
1193b4be Poul Sander 2025-02-03 21:28 3388
        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,
1193b4be Poul Sander 2025-02-03 21:28 3389
        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,
1193b4be Poul Sander 2025-02-03 21:28 3390
        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,
1193b4be Poul Sander 2025-02-03 21:28 3391
        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,
1193b4be Poul Sander 2025-02-03 21:28 3392
        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,
1193b4be Poul Sander 2025-02-03 21:28 3393
        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,
1193b4be Poul Sander 2025-02-03 21:28 3394
        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,
1193b4be Poul Sander 2025-02-03 21:28 3395
        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,
1193b4be Poul Sander 2025-02-03 21:28 3396
        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,
1193b4be Poul Sander 2025-02-03 21:28 3397
        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,
1193b4be Poul Sander 2025-02-03 21:28 3398
        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,
1193b4be Poul Sander 2025-02-03 21:28 3399
        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,
1193b4be Poul Sander 2025-02-03 21:28 3400
        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,
1193b4be Poul Sander 2025-02-03 21:28 3401
        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,
1193b4be Poul Sander 2025-02-03 21:28 3402
        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,
1193b4be Poul Sander 2025-02-03 21:28 3403
        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,
1193b4be Poul Sander 2025-02-03 21:28 3404
        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,
1193b4be Poul Sander 2025-02-03 21:28 3405
        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,
1193b4be Poul Sander 2025-02-03 21:28 3406
        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,
1193b4be Poul Sander 2025-02-03 21:28 3407
        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,
1193b4be Poul Sander 2025-02-03 21:28 3408
        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,
1193b4be Poul Sander 2025-02-03 21:28 3409
        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,
1193b4be Poul Sander 2025-02-03 21:28 3410
        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,
1193b4be Poul Sander 2025-02-03 21:28 3411
        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,
1193b4be Poul Sander 2025-02-03 21:28 3412
        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,
1193b4be Poul Sander 2025-02-03 21:28 3413
        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,
1193b4be Poul Sander 2025-02-03 21:28 3414
        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,
1193b4be Poul Sander 2025-02-03 21:28 3415
        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,
1193b4be Poul Sander 2025-02-03 21:28 3416
        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,
1193b4be Poul Sander 2025-02-03 21:28 3417
        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
1193b4be Poul Sander 2025-02-03 21:28 3418
    };
1193b4be Poul Sander 2025-02-03 21:28 3419
    static ImWchar base_ranges[] = // not zero-terminated
1193b4be Poul Sander 2025-02-03 21:28 3420
    {
1193b4be Poul Sander 2025-02-03 21:28 3421
        0x0020, 0x00FF, // Basic Latin + Latin Supplement
1193b4be Poul Sander 2025-02-03 21:28 3422
        0x2000, 0x206F, // General Punctuation
1193b4be Poul Sander 2025-02-03 21:28 3423
        0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
1193b4be Poul Sander 2025-02-03 21:28 3424
        0x31F0, 0x31FF, // Katakana Phonetic Extensions
1193b4be Poul Sander 2025-02-03 21:28 3425
        0xFF00, 0xFFEF, // Half-width characters
1193b4be Poul Sander 2025-02-03 21:28 3426
        0xFFFD, 0xFFFD  // Invalid
1193b4be Poul Sander 2025-02-03 21:28 3427
    };
1193b4be Poul Sander 2025-02-03 21:28 3428
    static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00) * 2 + 1] = { 0 };
1193b4be Poul Sander 2025-02-03 21:28 3429
    if (!full_ranges[0])
1193b4be Poul Sander 2025-02-03 21:28 3430
    {
1193b4be Poul Sander 2025-02-03 21:28 3431
        memcpy(full_ranges, base_ranges, sizeof(base_ranges));
1193b4be Poul Sander 2025-02-03 21:28 3432
        UnpackAccumulativeOffsetsIntoRanges(0x4E00, accumulative_offsets_from_0x4E00, IM_ARRAYSIZE(accumulative_offsets_from_0x4E00), full_ranges + IM_ARRAYSIZE(base_ranges));
1193b4be Poul Sander 2025-02-03 21:28 3433
    }
1193b4be Poul Sander 2025-02-03 21:28 3434
    return &full_ranges[0];
1193b4be Poul Sander 2025-02-03 21:28 3435
}
1193b4be Poul Sander 2025-02-03 21:28 3436
1193b4be Poul Sander 2025-02-03 21:28 3437
const ImWchar*  ImFontAtlas::GetGlyphRangesJapanese()
1193b4be Poul Sander 2025-02-03 21:28 3438
{
1193b4be Poul Sander 2025-02-03 21:28 3439
    // 2999 ideograms code points for Japanese
1193b4be Poul Sander 2025-02-03 21:28 3440
    // - 2136 Joyo (meaning "for regular use" or "for common use") Kanji code points
1193b4be Poul Sander 2025-02-03 21:28 3441
    // - 863 Jinmeiyo (meaning "for personal name") Kanji code points
1193b4be Poul Sander 2025-02-03 21:28 3442
    // - Sourced from official information provided by the government agencies of Japan:
1193b4be Poul Sander 2025-02-03 21:28 3443
    //   - List of Joyo Kanji by the Agency for Cultural Affairs
1193b4be Poul Sander 2025-02-03 21:28 3444
    //     - https://www.bunka.go.jp/kokugo_nihongo/sisaku/joho/joho/kijun/naikaku/kanji/
1193b4be Poul Sander 2025-02-03 21:28 3445
    //   - List of Jinmeiyo Kanji by the Ministry of Justice
1193b4be Poul Sander 2025-02-03 21:28 3446
    //     - http://www.moj.go.jp/MINJI/minji86.html
1193b4be Poul Sander 2025-02-03 21:28 3447
    //   - Available under the terms of the Creative Commons Attribution 4.0 International (CC BY 4.0).
1193b4be Poul Sander 2025-02-03 21:28 3448
    //     - https://creativecommons.org/licenses/by/4.0/legalcode
1193b4be Poul Sander 2025-02-03 21:28 3449
    // - You can generate this code by the script at:
1193b4be Poul Sander 2025-02-03 21:28 3450
    //   - https://github.com/vaiorabbit/everyday_use_kanji
1193b4be Poul Sander 2025-02-03 21:28 3451
    // - References:
1193b4be Poul Sander 2025-02-03 21:28 3452
    //   - List of Joyo Kanji
1193b4be Poul Sander 2025-02-03 21:28 3453
    //     - (Wikipedia) https://en.wikipedia.org/wiki/List_of_j%C5%8Dy%C5%8D_kanji
1193b4be Poul Sander 2025-02-03 21:28 3454
    //   - List of Jinmeiyo Kanji
1193b4be Poul Sander 2025-02-03 21:28 3455
    //     - (Wikipedia) https://en.wikipedia.org/wiki/Jinmeiy%C5%8D_kanji
1193b4be Poul Sander 2025-02-03 21:28 3456
    // - Missing 1 Joyo Kanji: U+20B9F (Kun'yomi: Shikaru, On'yomi: Shitsu,shichi), see https://github.com/ocornut/imgui/pull/3627 for details.
1193b4be Poul Sander 2025-02-03 21:28 3457
    // You can use ImFontGlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters.
1193b4be Poul Sander 2025-02-03 21:28 3458
    // (Stored as accumulative offsets from the initial unicode codepoint 0x4E00. This encoding is designed to helps us compact the source code size.)
1193b4be Poul Sander 2025-02-03 21:28 3459
    static const short accumulative_offsets_from_0x4E00[] =
1193b4be Poul Sander 2025-02-03 21:28 3460
    {
1193b4be Poul Sander 2025-02-03 21:28 3461
        0,1,2,4,1,1,1,1,2,1,3,3,2,2,1,5,3,5,7,5,6,1,2,1,7,2,6,3,1,8,1,1,4,1,1,18,2,11,2,6,2,1,2,1,5,1,2,1,3,1,2,1,2,3,3,1,1,2,3,1,1,1,12,7,9,1,4,5,1,
1193b4be Poul Sander 2025-02-03 21:28 3462
        1,2,1,10,1,1,9,2,2,4,5,6,9,3,1,1,1,1,9,3,18,5,2,2,2,2,1,6,3,7,1,1,1,1,2,2,4,2,1,23,2,10,4,3,5,2,4,10,2,4,13,1,6,1,9,3,1,1,6,6,7,6,3,1,2,11,3,
1193b4be Poul Sander 2025-02-03 21:28 3463
        2,2,3,2,15,2,2,5,4,3,6,4,1,2,5,2,12,16,6,13,9,13,2,1,1,7,16,4,7,1,19,1,5,1,2,2,7,7,8,2,6,5,4,9,18,7,4,5,9,13,11,8,15,2,1,1,1,2,1,2,2,1,2,2,8,
1193b4be Poul Sander 2025-02-03 21:28 3464
        2,9,3,3,1,1,4,4,1,1,1,4,9,1,4,3,5,5,2,7,5,3,4,8,2,1,13,2,3,3,1,14,1,1,4,5,1,3,6,1,5,2,1,1,3,3,3,3,1,1,2,7,6,6,7,1,4,7,6,1,1,1,1,1,12,3,3,9,5,
1193b4be Poul Sander 2025-02-03 21:28 3465
        2,6,1,5,6,1,2,3,18,2,4,14,4,1,3,6,1,1,6,3,5,5,3,2,2,2,2,12,3,1,4,2,3,2,3,11,1,7,4,1,2,1,3,17,1,9,1,24,1,1,4,2,2,4,1,2,7,1,1,1,3,1,2,2,4,15,1,
1193b4be Poul Sander 2025-02-03 21:28 3466
        1,2,1,1,2,1,5,2,5,20,2,5,9,1,10,8,7,6,1,1,1,1,1,1,6,2,1,2,8,1,1,1,1,5,1,1,3,1,1,1,1,3,1,1,12,4,1,3,1,1,1,1,1,10,3,1,7,5,13,1,2,3,4,6,1,1,30,
1193b4be Poul Sander 2025-02-03 21:28 3467
        2,9,9,1,15,38,11,3,1,8,24,7,1,9,8,10,2,1,9,31,2,13,6,2,9,4,49,5,2,15,2,1,10,2,1,1,1,2,2,6,15,30,35,3,14,18,8,1,16,10,28,12,19,45,38,1,3,2,3,
1193b4be Poul Sander 2025-02-03 21:28 3468
        13,2,1,7,3,6,5,3,4,3,1,5,7,8,1,5,3,18,5,3,6,1,21,4,24,9,24,40,3,14,3,21,3,2,1,2,4,2,3,1,15,15,6,5,1,1,3,1,5,6,1,9,7,3,3,2,1,4,3,8,21,5,16,4,
1193b4be Poul Sander 2025-02-03 21:28 3469
        5,2,10,11,11,3,6,3,2,9,3,6,13,1,2,1,1,1,1,11,12,6,6,1,4,2,6,5,2,1,1,3,3,6,13,3,1,1,5,1,2,3,3,14,2,1,2,2,2,5,1,9,5,1,1,6,12,3,12,3,4,13,2,14,
1193b4be Poul Sander 2025-02-03 21:28 3470
        2,8,1,17,5,1,16,4,2,2,21,8,9,6,23,20,12,25,19,9,38,8,3,21,40,25,33,13,4,3,1,4,1,2,4,1,2,5,26,2,1,1,2,1,3,6,2,1,1,1,1,1,1,2,3,1,1,1,9,2,3,1,1,
1193b4be Poul Sander 2025-02-03 21:28 3471
        1,3,6,3,2,1,1,6,6,1,8,2,2,2,1,4,1,2,3,2,7,3,2,4,1,2,1,2,2,1,1,1,1,1,3,1,2,5,4,10,9,4,9,1,1,1,1,1,1,5,3,2,1,6,4,9,6,1,10,2,31,17,8,3,7,5,40,1,
1193b4be Poul Sander 2025-02-03 21:28 3472
        7,7,1,6,5,2,10,7,8,4,15,39,25,6,28,47,18,10,7,1,3,1,1,2,1,1,1,3,3,3,1,1,1,3,4,2,1,4,1,3,6,10,7,8,6,2,2,1,3,3,2,5,8,7,9,12,2,15,1,1,4,1,2,1,1,
1193b4be Poul Sander 2025-02-03 21:28 3473
        1,3,2,1,3,3,5,6,2,3,2,10,1,4,2,8,1,1,1,11,6,1,21,4,16,3,1,3,1,4,2,3,6,5,1,3,1,1,3,3,4,6,1,1,10,4,2,7,10,4,7,4,2,9,4,3,1,1,1,4,1,8,3,4,1,3,1,
1193b4be Poul Sander 2025-02-03 21:28 3474
        6,1,4,2,1,4,7,2,1,8,1,4,5,1,1,2,2,4,6,2,7,1,10,1,1,3,4,11,10,8,21,4,6,1,3,5,2,1,2,28,5,5,2,3,13,1,2,3,1,4,2,1,5,20,3,8,11,1,3,3,3,1,8,10,9,2,
1193b4be Poul Sander 2025-02-03 21:28 3475
        10,9,2,3,1,1,2,4,1,8,3,6,1,7,8,6,11,1,4,29,8,4,3,1,2,7,13,1,4,1,6,2,6,12,12,2,20,3,2,3,6,4,8,9,2,7,34,5,1,18,6,1,1,4,4,5,7,9,1,2,2,4,3,4,1,7,
1193b4be Poul Sander 2025-02-03 21:28 3476
        2,2,2,6,2,3,25,5,3,6,1,4,6,7,4,2,1,4,2,13,6,4,4,3,1,5,3,4,4,3,2,1,1,4,1,2,1,1,3,1,11,1,6,3,1,7,3,6,2,8,8,6,9,3,4,11,3,2,10,12,2,5,11,1,6,4,5,
1193b4be Poul Sander 2025-02-03 21:28 3477
        3,1,8,5,4,6,6,3,5,1,1,3,2,1,2,2,6,17,12,1,10,1,6,12,1,6,6,19,9,6,16,1,13,4,4,15,7,17,6,11,9,15,12,6,7,2,1,2,2,15,9,3,21,4,6,49,18,7,3,2,3,1,
1193b4be Poul Sander 2025-02-03 21:28 3478
        6,8,2,2,6,2,9,1,3,6,4,4,1,2,16,2,5,2,1,6,2,3,5,3,1,2,5,1,2,1,9,3,1,8,6,4,8,11,3,1,1,1,1,3,1,13,8,4,1,3,2,2,1,4,1,11,1,5,2,1,5,2,5,8,6,1,1,7,
1193b4be Poul Sander 2025-02-03 21:28 3479
        4,3,8,3,2,7,2,1,5,1,5,2,4,7,6,2,8,5,1,11,4,5,3,6,18,1,2,13,3,3,1,21,1,1,4,1,4,1,1,1,8,1,2,2,7,1,2,4,2,2,9,2,1,1,1,4,3,6,3,12,5,1,1,1,5,6,3,2,
1193b4be Poul Sander 2025-02-03 21:28 3480
        4,8,2,2,4,2,7,1,8,9,5,2,3,2,1,3,2,13,7,14,6,5,1,1,2,1,4,2,23,2,1,1,6,3,1,4,1,15,3,1,7,3,9,14,1,3,1,4,1,1,5,8,1,3,8,3,8,15,11,4,14,4,4,2,5,5,
1193b4be Poul Sander 2025-02-03 21:28 3481
        1,7,1,6,14,7,7,8,5,15,4,8,6,5,6,2,1,13,1,20,15,11,9,2,5,6,2,11,2,6,2,5,1,5,8,4,13,19,25,4,1,1,11,1,34,2,5,9,14,6,2,2,6,1,1,14,1,3,14,13,1,6,
1193b4be Poul Sander 2025-02-03 21:28 3482
        12,21,14,14,6,32,17,8,32,9,28,1,2,4,11,8,3,1,14,2,5,15,1,1,1,1,3,6,4,1,3,4,11,3,1,1,11,30,1,5,1,4,1,5,8,1,1,3,2,4,3,17,35,2,6,12,17,3,1,6,2,
1193b4be Poul Sander 2025-02-03 21:28 3483
        1,1,12,2,7,3,3,2,1,16,2,8,3,6,5,4,7,3,3,8,1,9,8,5,1,2,1,3,2,8,1,2,9,12,1,1,2,3,8,3,24,12,4,3,7,5,8,3,3,3,3,3,3,1,23,10,3,1,2,2,6,3,1,16,1,16,
1193b4be Poul Sander 2025-02-03 21:28 3484
        22,3,10,4,11,6,9,7,7,3,6,2,2,2,4,10,2,1,1,2,8,7,1,6,4,1,3,3,3,5,10,12,12,2,3,12,8,15,1,1,16,6,6,1,5,9,11,4,11,4,2,6,12,1,17,5,13,1,4,9,5,1,11,
1193b4be Poul Sander 2025-02-03 21:28 3485
        2,1,8,1,5,7,28,8,3,5,10,2,17,3,38,22,1,2,18,12,10,4,38,18,1,4,44,19,4,1,8,4,1,12,1,4,31,12,1,14,7,75,7,5,10,6,6,13,3,2,11,11,3,2,5,28,15,6,18,
1193b4be Poul Sander 2025-02-03 21:28 3486
        18,5,6,4,3,16,1,7,18,7,36,3,5,3,1,7,1,9,1,10,7,2,4,2,6,2,9,7,4,3,32,12,3,7,10,2,23,16,3,1,12,3,31,4,11,1,3,8,9,5,1,30,15,6,12,3,2,2,11,19,9,
1193b4be Poul Sander 2025-02-03 21:28 3487
        14,2,6,2,3,19,13,17,5,3,3,25,3,14,1,1,1,36,1,3,2,19,3,13,36,9,13,31,6,4,16,34,2,5,4,2,3,3,5,1,1,1,4,3,1,17,3,2,3,5,3,1,3,2,3,5,6,3,12,11,1,3,
1193b4be Poul Sander 2025-02-03 21:28 3488
        1,2,26,7,12,7,2,14,3,3,7,7,11,25,25,28,16,4,36,1,2,1,6,2,1,9,3,27,17,4,3,4,13,4,1,3,2,2,1,10,4,2,4,6,3,8,2,1,18,1,1,24,2,2,4,33,2,3,63,7,1,6,
1193b4be Poul Sander 2025-02-03 21:28 3489
        40,7,3,4,4,2,4,15,18,1,16,1,1,11,2,41,14,1,3,18,13,3,2,4,16,2,17,7,15,24,7,18,13,44,2,2,3,6,1,1,7,5,1,7,1,4,3,3,5,10,8,2,3,1,8,1,1,27,4,2,1,
1193b4be Poul Sander 2025-02-03 21:28 3490
        12,1,2,1,10,6,1,6,7,5,2,3,7,11,5,11,3,6,6,2,3,15,4,9,1,1,2,1,2,11,2,8,12,8,5,4,2,3,1,5,2,2,1,14,1,12,11,4,1,11,17,17,4,3,2,5,5,7,3,1,5,9,9,8,
1193b4be Poul Sander 2025-02-03 21:28 3491
        2,5,6,6,13,13,2,1,2,6,1,2,2,49,4,9,1,2,10,16,7,8,4,3,2,23,4,58,3,29,1,14,19,19,11,11,2,7,5,1,3,4,6,2,18,5,12,12,17,17,3,3,2,4,1,6,2,3,4,3,1,
1193b4be Poul Sander 2025-02-03 21:28 3492
        1,1,1,5,1,1,9,1,3,1,3,6,1,8,1,1,2,6,4,14,3,1,4,11,4,1,3,32,1,2,4,13,4,1,2,4,2,1,3,1,11,1,4,2,1,4,4,6,3,5,1,6,5,7,6,3,23,3,5,3,5,3,3,13,3,9,10,
1193b4be Poul Sander 2025-02-03 21:28 3493
        1,12,10,2,3,18,13,7,160,52,4,2,2,3,2,14,5,4,12,4,6,4,1,20,4,11,6,2,12,27,1,4,1,2,2,7,4,5,2,28,3,7,25,8,3,19,3,6,10,2,2,1,10,2,5,4,1,3,4,1,5,
1193b4be Poul Sander 2025-02-03 21:28 3494
        3,2,6,9,3,6,2,16,3,3,16,4,5,5,3,2,1,2,16,15,8,2,6,21,2,4,1,22,5,8,1,1,21,11,2,1,11,11,19,13,12,4,2,3,2,3,6,1,8,11,1,4,2,9,5,2,1,11,2,9,1,1,2,
1193b4be Poul Sander 2025-02-03 21:28 3495
        14,31,9,3,4,21,14,4,8,1,7,2,2,2,5,1,4,20,3,3,4,10,1,11,9,8,2,1,4,5,14,12,14,2,17,9,6,31,4,14,1,20,13,26,5,2,7,3,6,13,2,4,2,19,6,2,2,18,9,3,5,
1193b4be Poul Sander 2025-02-03 21:28 3496
        12,12,14,4,6,2,3,6,9,5,22,4,5,25,6,4,8,5,2,6,27,2,35,2,16,3,7,8,8,6,6,5,9,17,2,20,6,19,2,13,3,1,1,1,4,17,12,2,14,7,1,4,18,12,38,33,2,10,1,1,
1193b4be Poul Sander 2025-02-03 21:28 3497
        2,13,14,17,11,50,6,33,20,26,74,16,23,45,50,13,38,33,6,6,7,4,4,2,1,3,2,5,8,7,8,9,3,11,21,9,13,1,3,10,6,7,1,2,2,18,5,5,1,9,9,2,68,9,19,13,2,5,
1193b4be Poul Sander 2025-02-03 21:28 3498
        1,4,4,7,4,13,3,9,10,21,17,3,26,2,1,5,2,4,5,4,1,7,4,7,3,4,2,1,6,1,1,20,4,1,9,2,2,1,3,3,2,3,2,1,1,1,20,2,3,1,6,2,3,6,2,4,8,1,3,2,10,3,5,3,4,4,
1193b4be Poul Sander 2025-02-03 21:28 3499
        3,4,16,1,6,1,10,2,4,2,1,1,2,10,11,2,2,3,1,24,31,4,10,10,2,5,12,16,164,15,4,16,7,9,15,19,17,1,2,1,1,5,1,1,1,1,1,3,1,4,3,1,3,1,3,1,2,1,1,3,3,7,
1193b4be Poul Sander 2025-02-03 21:28 3500
        2,8,1,2,2,2,1,3,4,3,7,8,12,92,2,10,3,1,3,14,5,25,16,42,4,7,7,4,2,21,5,27,26,27,21,25,30,31,2,1,5,13,3,22,5,6,6,11,9,12,1,5,9,7,5,5,22,60,3,5,
1193b4be Poul Sander 2025-02-03 21:28 3501
        13,1,1,8,1,1,3,3,2,1,9,3,3,18,4,1,2,3,7,6,3,1,2,3,9,1,3,1,3,2,1,3,1,1,1,2,1,11,3,1,6,9,1,3,2,3,1,2,1,5,1,1,4,3,4,1,2,2,4,4,1,7,2,1,2,2,3,5,13,
1193b4be Poul Sander 2025-02-03 21:28 3502
        18,3,4,14,9,9,4,16,3,7,5,8,2,6,48,28,3,1,1,4,2,14,8,2,9,2,1,15,2,4,3,2,10,16,12,8,7,1,1,3,1,1,1,2,7,4,1,6,4,38,39,16,23,7,15,15,3,2,12,7,21,
1193b4be Poul Sander 2025-02-03 21:28 3503
        37,27,6,5,4,8,2,10,8,8,6,5,1,2,1,3,24,1,16,17,9,23,10,17,6,1,51,55,44,13,294,9,3,6,2,4,2,2,15,1,1,1,13,21,17,68,14,8,9,4,1,4,9,3,11,7,1,1,1,
1193b4be Poul Sander 2025-02-03 21:28 3504
        5,6,3,2,1,1,1,2,3,8,1,2,2,4,1,5,5,2,1,4,3,7,13,4,1,4,1,3,1,1,1,5,5,10,1,6,1,5,2,1,5,2,4,1,4,5,7,3,18,2,9,11,32,4,3,3,2,4,7,11,16,9,11,8,13,38,
1193b4be Poul Sander 2025-02-03 21:28 3505
        32,8,4,2,1,1,2,1,2,4,4,1,1,1,4,1,21,3,11,1,16,1,1,6,1,3,2,4,9,8,57,7,44,1,3,3,13,3,10,1,1,7,5,2,7,21,47,63,3,15,4,7,1,16,1,1,2,8,2,3,42,15,4,
1193b4be Poul Sander 2025-02-03 21:28 3506
        1,29,7,22,10,3,78,16,12,20,18,4,67,11,5,1,3,15,6,21,31,32,27,18,13,71,35,5,142,4,10,1,2,50,19,33,16,35,37,16,19,27,7,1,133,19,1,4,8,7,20,1,4,
1193b4be Poul Sander 2025-02-03 21:28 3507
        4,1,10,3,1,6,1,2,51,5,40,15,24,43,22928,11,1,13,154,70,3,1,1,7,4,10,1,2,1,1,2,1,2,1,2,2,1,1,2,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,
1193b4be Poul Sander 2025-02-03 21:28 3508
        3,2,1,1,1,1,2,1,1,
1193b4be Poul Sander 2025-02-03 21:28 3509
    };
1193b4be Poul Sander 2025-02-03 21:28 3510
    static ImWchar base_ranges[] = // not zero-terminated
1193b4be Poul Sander 2025-02-03 21:28 3511
    {
1193b4be Poul Sander 2025-02-03 21:28 3512
        0x0020, 0x00FF, // Basic Latin + Latin Supplement
1193b4be Poul Sander 2025-02-03 21:28 3513
        0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
1193b4be Poul Sander 2025-02-03 21:28 3514
        0x31F0, 0x31FF, // Katakana Phonetic Extensions
1193b4be Poul Sander 2025-02-03 21:28 3515
        0xFF00, 0xFFEF, // Half-width characters
1193b4be Poul Sander 2025-02-03 21:28 3516
        0xFFFD, 0xFFFD  // Invalid
1193b4be Poul Sander 2025-02-03 21:28 3517
    };
1193b4be Poul Sander 2025-02-03 21:28 3518
    static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00)*2 + 1] = { 0 };
1193b4be Poul Sander 2025-02-03 21:28 3519
    if (!full_ranges[0])
1193b4be Poul Sander 2025-02-03 21:28 3520
    {
1193b4be Poul Sander 2025-02-03 21:28 3521
        memcpy(full_ranges, base_ranges, sizeof(base_ranges));
1193b4be Poul Sander 2025-02-03 21:28 3522
        UnpackAccumulativeOffsetsIntoRanges(0x4E00, accumulative_offsets_from_0x4E00, IM_ARRAYSIZE(accumulative_offsets_from_0x4E00), full_ranges + IM_ARRAYSIZE(base_ranges));
1193b4be Poul Sander 2025-02-03 21:28 3523
    }
1193b4be Poul Sander 2025-02-03 21:28 3524
    return &full_ranges[0];
1193b4be Poul Sander 2025-02-03 21:28 3525
}
1193b4be Poul Sander 2025-02-03 21:28 3526
1193b4be Poul Sander 2025-02-03 21:28 3527
const ImWchar*  ImFontAtlas::GetGlyphRangesCyrillic()
1193b4be Poul Sander 2025-02-03 21:28 3528
{
1193b4be Poul Sander 2025-02-03 21:28 3529
    static const ImWchar ranges[] =
1193b4be Poul Sander 2025-02-03 21:28 3530
    {
1193b4be Poul Sander 2025-02-03 21:28 3531
        0x0020, 0x00FF, // Basic Latin + Latin Supplement
1193b4be Poul Sander 2025-02-03 21:28 3532
        0x0400, 0x052F, // Cyrillic + Cyrillic Supplement
1193b4be Poul Sander 2025-02-03 21:28 3533
        0x2DE0, 0x2DFF, // Cyrillic Extended-A
1193b4be Poul Sander 2025-02-03 21:28 3534
        0xA640, 0xA69F, // Cyrillic Extended-B
1193b4be Poul Sander 2025-02-03 21:28 3535
        0,
1193b4be Poul Sander 2025-02-03 21:28 3536
    };
1193b4be Poul Sander 2025-02-03 21:28 3537
    return &ranges[0];
1193b4be Poul Sander 2025-02-03 21:28 3538
}
1193b4be Poul Sander 2025-02-03 21:28 3539
1193b4be Poul Sander 2025-02-03 21:28 3540
const ImWchar*  ImFontAtlas::GetGlyphRangesThai()
1193b4be Poul Sander 2025-02-03 21:28 3541
{
1193b4be Poul Sander 2025-02-03 21:28 3542
    static const ImWchar ranges[] =
1193b4be Poul Sander 2025-02-03 21:28 3543
    {
1193b4be Poul Sander 2025-02-03 21:28 3544
        0x0020, 0x00FF, // Basic Latin
1193b4be Poul Sander 2025-02-03 21:28 3545
        0x2010, 0x205E, // Punctuations
1193b4be Poul Sander 2025-02-03 21:28 3546
        0x0E00, 0x0E7F, // Thai
1193b4be Poul Sander 2025-02-03 21:28 3547
        0,
1193b4be Poul Sander 2025-02-03 21:28 3548
    };
1193b4be Poul Sander 2025-02-03 21:28 3549
    return &ranges[0];
1193b4be Poul Sander 2025-02-03 21:28 3550
}
1193b4be Poul Sander 2025-02-03 21:28 3551
1193b4be Poul Sander 2025-02-03 21:28 3552
const ImWchar*  ImFontAtlas::GetGlyphRangesVietnamese()
1193b4be Poul Sander 2025-02-03 21:28 3553
{
1193b4be Poul Sander 2025-02-03 21:28 3554
    static const ImWchar ranges[] =
1193b4be Poul Sander 2025-02-03 21:28 3555
    {
1193b4be Poul Sander 2025-02-03 21:28 3556
        0x0020, 0x00FF, // Basic Latin
1193b4be Poul Sander 2025-02-03 21:28 3557
        0x0102, 0x0103,
1193b4be Poul Sander 2025-02-03 21:28 3558
        0x0110, 0x0111,
1193b4be Poul Sander 2025-02-03 21:28 3559
        0x0128, 0x0129,
1193b4be Poul Sander 2025-02-03 21:28 3560
        0x0168, 0x0169,
1193b4be Poul Sander 2025-02-03 21:28 3561
        0x01A0, 0x01A1,
1193b4be Poul Sander 2025-02-03 21:28 3562
        0x01AF, 0x01B0,
1193b4be Poul Sander 2025-02-03 21:28 3563
        0x1EA0, 0x1EF9,
1193b4be Poul Sander 2025-02-03 21:28 3564
        0,
1193b4be Poul Sander 2025-02-03 21:28 3565
    };
1193b4be Poul Sander 2025-02-03 21:28 3566
    return &ranges[0];
1193b4be Poul Sander 2025-02-03 21:28 3567
}
1193b4be Poul Sander 2025-02-03 21:28 3568
1193b4be Poul Sander 2025-02-03 21:28 3569
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 3570
// [SECTION] ImFontGlyphRangesBuilder
1193b4be Poul Sander 2025-02-03 21:28 3571
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 3572
1193b4be Poul Sander 2025-02-03 21:28 3573
void ImFontGlyphRangesBuilder::AddText(const char* text, const char* text_end)
1193b4be Poul Sander 2025-02-03 21:28 3574
{
1193b4be Poul Sander 2025-02-03 21:28 3575
    while (text_end ? (text < text_end) : *text)
1193b4be Poul Sander 2025-02-03 21:28 3576
    {
1193b4be Poul Sander 2025-02-03 21:28 3577
        unsigned int c = 0;
1193b4be Poul Sander 2025-02-03 21:28 3578
        int c_len = ImTextCharFromUtf8(&c, text, text_end);
1193b4be Poul Sander 2025-02-03 21:28 3579
        text += c_len;
1193b4be Poul Sander 2025-02-03 21:28 3580
        if (c_len == 0)
1193b4be Poul Sander 2025-02-03 21:28 3581
            break;
1193b4be Poul Sander 2025-02-03 21:28 3582
        AddChar((ImWchar)c);
1193b4be Poul Sander 2025-02-03 21:28 3583
    }
1193b4be Poul Sander 2025-02-03 21:28 3584
}
1193b4be Poul Sander 2025-02-03 21:28 3585
1193b4be Poul Sander 2025-02-03 21:28 3586
void ImFontGlyphRangesBuilder::AddRanges(const ImWchar* ranges)
1193b4be Poul Sander 2025-02-03 21:28 3587
{
1193b4be Poul Sander 2025-02-03 21:28 3588
    for (; ranges[0]; ranges += 2)
1193b4be Poul Sander 2025-02-03 21:28 3589
        for (unsigned int c = ranges[0]; c <= ranges[1] && c <= IM_UNICODE_CODEPOINT_MAX; c++) //-V560
1193b4be Poul Sander 2025-02-03 21:28 3590
            AddChar((ImWchar)c);
1193b4be Poul Sander 2025-02-03 21:28 3591
}
1193b4be Poul Sander 2025-02-03 21:28 3592
1193b4be Poul Sander 2025-02-03 21:28 3593
void ImFontGlyphRangesBuilder::BuildRanges(ImVector<ImWchar>* out_ranges)
1193b4be Poul Sander 2025-02-03 21:28 3594
{
1193b4be Poul Sander 2025-02-03 21:28 3595
    const int max_codepoint = IM_UNICODE_CODEPOINT_MAX;
1193b4be Poul Sander 2025-02-03 21:28 3596
    for (int n = 0; n <= max_codepoint; n++)
1193b4be Poul Sander 2025-02-03 21:28 3597
        if (GetBit(n))
1193b4be Poul Sander 2025-02-03 21:28 3598
        {
1193b4be Poul Sander 2025-02-03 21:28 3599
            out_ranges->push_back((ImWchar)n);
1193b4be Poul Sander 2025-02-03 21:28 3600
            while (n < max_codepoint && GetBit(n + 1))
1193b4be Poul Sander 2025-02-03 21:28 3601
                n++;
1193b4be Poul Sander 2025-02-03 21:28 3602
            out_ranges->push_back((ImWchar)n);
1193b4be Poul Sander 2025-02-03 21:28 3603
        }
1193b4be Poul Sander 2025-02-03 21:28 3604
    out_ranges->push_back(0);
1193b4be Poul Sander 2025-02-03 21:28 3605
}
1193b4be Poul Sander 2025-02-03 21:28 3606
1193b4be Poul Sander 2025-02-03 21:28 3607
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 3608
// [SECTION] ImFont
1193b4be Poul Sander 2025-02-03 21:28 3609
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 3610
1193b4be Poul Sander 2025-02-03 21:28 3611
ImFont::ImFont()
1193b4be Poul Sander 2025-02-03 21:28 3612
{
1193b4be Poul Sander 2025-02-03 21:28 3613
    FontSize = 0.0f;
1193b4be Poul Sander 2025-02-03 21:28 3614
    FallbackAdvanceX = 0.0f;
1193b4be Poul Sander 2025-02-03 21:28 3615
    FallbackChar = (ImWchar)-1;
1193b4be Poul Sander 2025-02-03 21:28 3616
    EllipsisChar = (ImWchar)-1;
1193b4be Poul Sander 2025-02-03 21:28 3617
    EllipsisWidth = EllipsisCharStep = 0.0f;
1193b4be Poul Sander 2025-02-03 21:28 3618
    EllipsisCharCount = 0;
1193b4be Poul Sander 2025-02-03 21:28 3619
    FallbackGlyph = NULL;
1193b4be Poul Sander 2025-02-03 21:28 3620
    ContainerAtlas = NULL;
1193b4be Poul Sander 2025-02-03 21:28 3621
    ConfigData = NULL;
1193b4be Poul Sander 2025-02-03 21:28 3622
    ConfigDataCount = 0;
1193b4be Poul Sander 2025-02-03 21:28 3623
    DirtyLookupTables = false;
1193b4be Poul Sander 2025-02-03 21:28 3624
    Scale = 1.0f;
1193b4be Poul Sander 2025-02-03 21:28 3625
    Ascent = Descent = 0.0f;
1193b4be Poul Sander 2025-02-03 21:28 3626
    MetricsTotalSurface = 0;
1193b4be Poul Sander 2025-02-03 21:28 3627
    memset(Used4kPagesMap, 0, sizeof(Used4kPagesMap));
1193b4be Poul Sander 2025-02-03 21:28 3628
}
1193b4be Poul Sander 2025-02-03 21:28 3629
1193b4be Poul Sander 2025-02-03 21:28 3630
ImFont::~ImFont()
1193b4be Poul Sander 2025-02-03 21:28 3631
{
1193b4be Poul Sander 2025-02-03 21:28 3632
    ClearOutputData();
1193b4be Poul Sander 2025-02-03 21:28 3633
}
1193b4be Poul Sander 2025-02-03 21:28 3634
1193b4be Poul Sander 2025-02-03 21:28 3635
void    ImFont::ClearOutputData()
1193b4be Poul Sander 2025-02-03 21:28 3636
{
1193b4be Poul Sander 2025-02-03 21:28 3637
    FontSize = 0.0f;
1193b4be Poul Sander 2025-02-03 21:28 3638
    FallbackAdvanceX = 0.0f;
1193b4be Poul Sander 2025-02-03 21:28 3639
    Glyphs.clear();
1193b4be Poul Sander 2025-02-03 21:28 3640
    IndexAdvanceX.clear();
1193b4be Poul Sander 2025-02-03 21:28 3641
    IndexLookup.clear();
1193b4be Poul Sander 2025-02-03 21:28 3642
    FallbackGlyph = NULL;
1193b4be Poul Sander 2025-02-03 21:28 3643
    ContainerAtlas = NULL;
1193b4be Poul Sander 2025-02-03 21:28 3644
    DirtyLookupTables = true;
1193b4be Poul Sander 2025-02-03 21:28 3645
    Ascent = Descent = 0.0f;
1193b4be Poul Sander 2025-02-03 21:28 3646
    MetricsTotalSurface = 0;
1193b4be Poul Sander 2025-02-03 21:28 3647
}
1193b4be Poul Sander 2025-02-03 21:28 3648
1193b4be Poul Sander 2025-02-03 21:28 3649
static ImWchar FindFirstExistingGlyph(ImFont* font, const ImWchar* candidate_chars, int candidate_chars_count)
1193b4be Poul Sander 2025-02-03 21:28 3650
{
1193b4be Poul Sander 2025-02-03 21:28 3651
    for (int n = 0; n < candidate_chars_count; n++)
1193b4be Poul Sander 2025-02-03 21:28 3652
        if (font->FindGlyphNoFallback(candidate_chars[n]) != NULL)
1193b4be Poul Sander 2025-02-03 21:28 3653
            return candidate_chars[n];
1193b4be Poul Sander 2025-02-03 21:28 3654
    return (ImWchar)-1;
1193b4be Poul Sander 2025-02-03 21:28 3655
}
1193b4be Poul Sander 2025-02-03 21:28 3656
1193b4be Poul Sander 2025-02-03 21:28 3657
void ImFont::BuildLookupTable()
1193b4be Poul Sander 2025-02-03 21:28 3658
{
1193b4be Poul Sander 2025-02-03 21:28 3659
    int max_codepoint = 0;
1193b4be Poul Sander 2025-02-03 21:28 3660
    for (int i = 0; i != Glyphs.Size; i++)
1193b4be Poul Sander 2025-02-03 21:28 3661
        max_codepoint = ImMax(max_codepoint, (int)Glyphs[i].Codepoint);
1193b4be Poul Sander 2025-02-03 21:28 3662
1193b4be Poul Sander 2025-02-03 21:28 3663
    // Build lookup table
1193b4be Poul Sander 2025-02-03 21:28 3664
    IM_ASSERT(Glyphs.Size > 0 && "Font has not loaded glyph!");
1193b4be Poul Sander 2025-02-03 21:28 3665
    IM_ASSERT(Glyphs.Size < 0xFFFF); // -1 is reserved
1193b4be Poul Sander 2025-02-03 21:28 3666
    IndexAdvanceX.clear();
1193b4be Poul Sander 2025-02-03 21:28 3667
    IndexLookup.clear();
1193b4be Poul Sander 2025-02-03 21:28 3668
    DirtyLookupTables = false;
1193b4be Poul Sander 2025-02-03 21:28 3669
    memset(Used4kPagesMap, 0, sizeof(Used4kPagesMap));
1193b4be Poul Sander 2025-02-03 21:28 3670
    GrowIndex(max_codepoint + 1);
1193b4be Poul Sander 2025-02-03 21:28 3671
    for (int i = 0; i < Glyphs.Size; i++)
1193b4be Poul Sander 2025-02-03 21:28 3672
    {
1193b4be Poul Sander 2025-02-03 21:28 3673
        int codepoint = (int)Glyphs[i].Codepoint;
1193b4be Poul Sander 2025-02-03 21:28 3674
        IndexAdvanceX[codepoint] = Glyphs[i].AdvanceX;
1193b4be Poul Sander 2025-02-03 21:28 3675
        IndexLookup[codepoint] = (ImWchar)i;
1193b4be Poul Sander 2025-02-03 21:28 3676
1193b4be Poul Sander 2025-02-03 21:28 3677
        // Mark 4K page as used
1193b4be Poul Sander 2025-02-03 21:28 3678
        const int page_n = codepoint / 4096;
1193b4be Poul Sander 2025-02-03 21:28 3679
        Used4kPagesMap[page_n >> 3] |= 1 << (page_n & 7);
1193b4be Poul Sander 2025-02-03 21:28 3680
    }
1193b4be Poul Sander 2025-02-03 21:28 3681
1193b4be Poul Sander 2025-02-03 21:28 3682
    // Create a glyph to handle TAB
1193b4be Poul Sander 2025-02-03 21:28 3683
    // FIXME: Needs proper TAB handling but it needs to be contextualized (or we could arbitrary say that each string starts at "column 0" ?)
1193b4be Poul Sander 2025-02-03 21:28 3684
    if (FindGlyph((ImWchar)' '))
1193b4be Poul Sander 2025-02-03 21:28 3685
    {
1193b4be Poul Sander 2025-02-03 21:28 3686
        if (Glyphs.back().Codepoint != '\t')   // So we can call this function multiple times (FIXME: Flaky)
1193b4be Poul Sander 2025-02-03 21:28 3687
            Glyphs.resize(Glyphs.Size + 1);
1193b4be Poul Sander 2025-02-03 21:28 3688
        ImFontGlyph& tab_glyph = Glyphs.back();
1193b4be Poul Sander 2025-02-03 21:28 3689
        tab_glyph = *FindGlyph((ImWchar)' ');
1193b4be Poul Sander 2025-02-03 21:28 3690
        tab_glyph.Codepoint = '\t';
1193b4be Poul Sander 2025-02-03 21:28 3691
        tab_glyph.AdvanceX *= IM_TABSIZE;
1193b4be Poul Sander 2025-02-03 21:28 3692
        IndexAdvanceX[(int)tab_glyph.Codepoint] = (float)tab_glyph.AdvanceX;
1193b4be Poul Sander 2025-02-03 21:28 3693
        IndexLookup[(int)tab_glyph.Codepoint] = (ImWchar)(Glyphs.Size - 1);
1193b4be Poul Sander 2025-02-03 21:28 3694
    }
1193b4be Poul Sander 2025-02-03 21:28 3695
1193b4be Poul Sander 2025-02-03 21:28 3696
    // Mark special glyphs as not visible (note that AddGlyph already mark as non-visible glyphs with zero-size polygons)
1193b4be Poul Sander 2025-02-03 21:28 3697
    SetGlyphVisible((ImWchar)' ', false);
1193b4be Poul Sander 2025-02-03 21:28 3698
    SetGlyphVisible((ImWchar)'\t', false);
1193b4be Poul Sander 2025-02-03 21:28 3699
1193b4be Poul Sander 2025-02-03 21:28 3700
    // Setup Fallback character
1193b4be Poul Sander 2025-02-03 21:28 3701
    const ImWchar fallback_chars[] = { (ImWchar)IM_UNICODE_CODEPOINT_INVALID, (ImWchar)'?', (ImWchar)' ' };
1193b4be Poul Sander 2025-02-03 21:28 3702
    FallbackGlyph = FindGlyphNoFallback(FallbackChar);
1193b4be Poul Sander 2025-02-03 21:28 3703
    if (FallbackGlyph == NULL)
1193b4be Poul Sander 2025-02-03 21:28 3704
    {
1193b4be Poul Sander 2025-02-03 21:28 3705
        FallbackChar = FindFirstExistingGlyph(this, fallback_chars, IM_ARRAYSIZE(fallback_chars));
1193b4be Poul Sander 2025-02-03 21:28 3706
        FallbackGlyph = FindGlyphNoFallback(FallbackChar);
1193b4be Poul Sander 2025-02-03 21:28 3707
        if (FallbackGlyph == NULL)
1193b4be Poul Sander 2025-02-03 21:28 3708
        {
1193b4be Poul Sander 2025-02-03 21:28 3709
            FallbackGlyph = &Glyphs.back();
1193b4be Poul Sander 2025-02-03 21:28 3710
            FallbackChar = (ImWchar)FallbackGlyph->Codepoint;
1193b4be Poul Sander 2025-02-03 21:28 3711
        }
1193b4be Poul Sander 2025-02-03 21:28 3712
    }
1193b4be Poul Sander 2025-02-03 21:28 3713
    FallbackAdvanceX = FallbackGlyph->AdvanceX;
1193b4be Poul Sander 2025-02-03 21:28 3714
    for (int i = 0; i < max_codepoint + 1; i++)
1193b4be Poul Sander 2025-02-03 21:28 3715
        if (IndexAdvanceX[i] < 0.0f)
1193b4be Poul Sander 2025-02-03 21:28 3716
            IndexAdvanceX[i] = FallbackAdvanceX;
1193b4be Poul Sander 2025-02-03 21:28 3717
1193b4be Poul Sander 2025-02-03 21:28 3718
    // Setup Ellipsis character. It is required for rendering elided text. We prefer using U+2026 (horizontal ellipsis).
1193b4be Poul Sander 2025-02-03 21:28 3719
    // However some old fonts may contain ellipsis at U+0085. Here we auto-detect most suitable ellipsis character.
1193b4be Poul Sander 2025-02-03 21:28 3720
    // FIXME: Note that 0x2026 is rarely included in our font ranges. Because of this we are more likely to use three individual dots.
1193b4be Poul Sander 2025-02-03 21:28 3721
    const ImWchar ellipsis_chars[] = { (ImWchar)0x2026, (ImWchar)0x0085 };
1193b4be Poul Sander 2025-02-03 21:28 3722
    const ImWchar dots_chars[] = { (ImWchar)'.', (ImWchar)0xFF0E };
1193b4be Poul Sander 2025-02-03 21:28 3723
    if (EllipsisChar == (ImWchar)-1)
1193b4be Poul Sander 2025-02-03 21:28 3724
        EllipsisChar = FindFirstExistingGlyph(this, ellipsis_chars, IM_ARRAYSIZE(ellipsis_chars));
1193b4be Poul Sander 2025-02-03 21:28 3725
    const ImWchar dot_char = FindFirstExistingGlyph(this, dots_chars, IM_ARRAYSIZE(dots_chars));
1193b4be Poul Sander 2025-02-03 21:28 3726
    if (EllipsisChar != (ImWchar)-1)
1193b4be Poul Sander 2025-02-03 21:28 3727
    {
1193b4be Poul Sander 2025-02-03 21:28 3728
        EllipsisCharCount = 1;
1193b4be Poul Sander 2025-02-03 21:28 3729
        EllipsisWidth = EllipsisCharStep = FindGlyph(EllipsisChar)->X1;
1193b4be Poul Sander 2025-02-03 21:28 3730
    }
1193b4be Poul Sander 2025-02-03 21:28 3731
    else if (dot_char != (ImWchar)-1)
1193b4be Poul Sander 2025-02-03 21:28 3732
    {
1193b4be Poul Sander 2025-02-03 21:28 3733
        const ImFontGlyph* glyph = FindGlyph(dot_char);
1193b4be Poul Sander 2025-02-03 21:28 3734
        EllipsisChar = dot_char;
1193b4be Poul Sander 2025-02-03 21:28 3735
        EllipsisCharCount = 3;
1193b4be Poul Sander 2025-02-03 21:28 3736
        EllipsisCharStep = (glyph->X1 - glyph->X0) + 1.0f;
1193b4be Poul Sander 2025-02-03 21:28 3737
        EllipsisWidth = EllipsisCharStep * 3.0f - 1.0f;
1193b4be Poul Sander 2025-02-03 21:28 3738
    }
1193b4be Poul Sander 2025-02-03 21:28 3739
}
1193b4be Poul Sander 2025-02-03 21:28 3740
1193b4be Poul Sander 2025-02-03 21:28 3741
// API is designed this way to avoid exposing the 4K page size
1193b4be Poul Sander 2025-02-03 21:28 3742
// e.g. use with IsGlyphRangeUnused(0, 255)
1193b4be Poul Sander 2025-02-03 21:28 3743
bool ImFont::IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last)
1193b4be Poul Sander 2025-02-03 21:28 3744
{
1193b4be Poul Sander 2025-02-03 21:28 3745
    unsigned int page_begin = (c_begin / 4096);
1193b4be Poul Sander 2025-02-03 21:28 3746
    unsigned int page_last = (c_last / 4096);
1193b4be Poul Sander 2025-02-03 21:28 3747
    for (unsigned int page_n = page_begin; page_n <= page_last; page_n++)
1193b4be Poul Sander 2025-02-03 21:28 3748
        if ((page_n >> 3) < sizeof(Used4kPagesMap))
1193b4be Poul Sander 2025-02-03 21:28 3749
            if (Used4kPagesMap[page_n >> 3] & (1 << (page_n & 7)))
1193b4be Poul Sander 2025-02-03 21:28 3750
                return false;
1193b4be Poul Sander 2025-02-03 21:28 3751
    return true;
1193b4be Poul Sander 2025-02-03 21:28 3752
}
1193b4be Poul Sander 2025-02-03 21:28 3753
1193b4be Poul Sander 2025-02-03 21:28 3754
void ImFont::SetGlyphVisible(ImWchar c, bool visible)
1193b4be Poul Sander 2025-02-03 21:28 3755
{
1193b4be Poul Sander 2025-02-03 21:28 3756
    if (ImFontGlyph* glyph = (ImFontGlyph*)(void*)FindGlyph((ImWchar)c))
1193b4be Poul Sander 2025-02-03 21:28 3757
        glyph->Visible = visible ? 1 : 0;
1193b4be Poul Sander 2025-02-03 21:28 3758
}
1193b4be Poul Sander 2025-02-03 21:28 3759
1193b4be Poul Sander 2025-02-03 21:28 3760
void ImFont::GrowIndex(int new_size)
1193b4be Poul Sander 2025-02-03 21:28 3761
{
1193b4be Poul Sander 2025-02-03 21:28 3762
    IM_ASSERT(IndexAdvanceX.Size == IndexLookup.Size);
1193b4be Poul Sander 2025-02-03 21:28 3763
    if (new_size <= IndexLookup.Size)
1193b4be Poul Sander 2025-02-03 21:28 3764
        return;
1193b4be Poul Sander 2025-02-03 21:28 3765
    IndexAdvanceX.resize(new_size, -1.0f);
1193b4be Poul Sander 2025-02-03 21:28 3766
    IndexLookup.resize(new_size, (ImWchar)-1);
1193b4be Poul Sander 2025-02-03 21:28 3767
}
1193b4be Poul Sander 2025-02-03 21:28 3768
1193b4be Poul Sander 2025-02-03 21:28 3769
// x0/y0/x1/y1 are offset from the character upper-left layout position, in pixels. Therefore x0/y0 are often fairly close to zero.
1193b4be Poul Sander 2025-02-03 21:28 3770
// 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).
1193b4be Poul Sander 2025-02-03 21:28 3771
// 'cfg' is not necessarily == 'this->ConfigData' because multiple source fonts+configs can be used to build one target font.
1193b4be Poul Sander 2025-02-03 21:28 3772
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)
1193b4be Poul Sander 2025-02-03 21:28 3773
{
1193b4be Poul Sander 2025-02-03 21:28 3774
    if (cfg != NULL)
1193b4be Poul Sander 2025-02-03 21:28 3775
    {
1193b4be Poul Sander 2025-02-03 21:28 3776
        // Clamp & recenter if needed
1193b4be Poul Sander 2025-02-03 21:28 3777
        const float advance_x_original = advance_x;
1193b4be Poul Sander 2025-02-03 21:28 3778
        advance_x = ImClamp(advance_x, cfg->GlyphMinAdvanceX, cfg->GlyphMaxAdvanceX);
1193b4be Poul Sander 2025-02-03 21:28 3779
        if (advance_x != advance_x_original)
1193b4be Poul Sander 2025-02-03 21:28 3780
        {
1193b4be Poul Sander 2025-02-03 21:28 3781
            float char_off_x = cfg->PixelSnapH ? ImTrunc((advance_x - advance_x_original) * 0.5f) : (advance_x - advance_x_original) * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 3782
            x0 += char_off_x;
1193b4be Poul Sander 2025-02-03 21:28 3783
            x1 += char_off_x;
1193b4be Poul Sander 2025-02-03 21:28 3784
        }
1193b4be Poul Sander 2025-02-03 21:28 3785
1193b4be Poul Sander 2025-02-03 21:28 3786
        // Snap to pixel
1193b4be Poul Sander 2025-02-03 21:28 3787
        if (cfg->PixelSnapH)
1193b4be Poul Sander 2025-02-03 21:28 3788
            advance_x = IM_ROUND(advance_x);
1193b4be Poul Sander 2025-02-03 21:28 3789
1193b4be Poul Sander 2025-02-03 21:28 3790
        // Bake spacing
1193b4be Poul Sander 2025-02-03 21:28 3791
        advance_x += cfg->GlyphExtraSpacing.x;
1193b4be Poul Sander 2025-02-03 21:28 3792
    }
1193b4be Poul Sander 2025-02-03 21:28 3793
1193b4be Poul Sander 2025-02-03 21:28 3794
    Glyphs.resize(Glyphs.Size + 1);
1193b4be Poul Sander 2025-02-03 21:28 3795
    ImFontGlyph& glyph = Glyphs.back();
1193b4be Poul Sander 2025-02-03 21:28 3796
    glyph.Codepoint = (unsigned int)codepoint;
1193b4be Poul Sander 2025-02-03 21:28 3797
    glyph.Visible = (x0 != x1) && (y0 != y1);
1193b4be Poul Sander 2025-02-03 21:28 3798
    glyph.Colored = false;
1193b4be Poul Sander 2025-02-03 21:28 3799
    glyph.X0 = x0;
1193b4be Poul Sander 2025-02-03 21:28 3800
    glyph.Y0 = y0;
1193b4be Poul Sander 2025-02-03 21:28 3801
    glyph.X1 = x1;
1193b4be Poul Sander 2025-02-03 21:28 3802
    glyph.Y1 = y1;
1193b4be Poul Sander 2025-02-03 21:28 3803
    glyph.U0 = u0;
1193b4be Poul Sander 2025-02-03 21:28 3804
    glyph.V0 = v0;
1193b4be Poul Sander 2025-02-03 21:28 3805
    glyph.U1 = u1;
1193b4be Poul Sander 2025-02-03 21:28 3806
    glyph.V1 = v1;
1193b4be Poul Sander 2025-02-03 21:28 3807
    glyph.AdvanceX = advance_x;
1193b4be Poul Sander 2025-02-03 21:28 3808
1193b4be Poul Sander 2025-02-03 21:28 3809
    // Compute rough surface usage metrics (+1 to account for average padding, +0.99 to round)
1193b4be Poul Sander 2025-02-03 21:28 3810
    // We use (U1-U0)*TexWidth instead of X1-X0 to account for oversampling.
1193b4be Poul Sander 2025-02-03 21:28 3811
    float pad = ContainerAtlas->TexGlyphPadding + 0.99f;
1193b4be Poul Sander 2025-02-03 21:28 3812
    DirtyLookupTables = true;
1193b4be Poul Sander 2025-02-03 21:28 3813
    MetricsTotalSurface += (int)((glyph.U1 - glyph.U0) * ContainerAtlas->TexWidth + pad) * (int)((glyph.V1 - glyph.V0) * ContainerAtlas->TexHeight + pad);
1193b4be Poul Sander 2025-02-03 21:28 3814
}
1193b4be Poul Sander 2025-02-03 21:28 3815
1193b4be Poul Sander 2025-02-03 21:28 3816
void ImFont::AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst)
1193b4be Poul Sander 2025-02-03 21:28 3817
{
1193b4be Poul Sander 2025-02-03 21:28 3818
    IM_ASSERT(IndexLookup.Size > 0);    // Currently this can only be called AFTER the font has been built, aka after calling ImFontAtlas::GetTexDataAs*() function.
1193b4be Poul Sander 2025-02-03 21:28 3819
    unsigned int index_size = (unsigned int)IndexLookup.Size;
1193b4be Poul Sander 2025-02-03 21:28 3820
1193b4be Poul Sander 2025-02-03 21:28 3821
    if (dst < index_size && IndexLookup.Data[dst] == (ImWchar)-1 && !overwrite_dst) // 'dst' already exists
1193b4be Poul Sander 2025-02-03 21:28 3822
        return;
1193b4be Poul Sander 2025-02-03 21:28 3823
    if (src >= index_size && dst >= index_size) // both 'dst' and 'src' don't exist -> no-op
1193b4be Poul Sander 2025-02-03 21:28 3824
        return;
1193b4be Poul Sander 2025-02-03 21:28 3825
1193b4be Poul Sander 2025-02-03 21:28 3826
    GrowIndex(dst + 1);
1193b4be Poul Sander 2025-02-03 21:28 3827
    IndexLookup[dst] = (src < index_size) ? IndexLookup.Data[src] : (ImWchar)-1;
1193b4be Poul Sander 2025-02-03 21:28 3828
    IndexAdvanceX[dst] = (src < index_size) ? IndexAdvanceX.Data[src] : 1.0f;
1193b4be Poul Sander 2025-02-03 21:28 3829
}
1193b4be Poul Sander 2025-02-03 21:28 3830
1193b4be Poul Sander 2025-02-03 21:28 3831
const ImFontGlyph* ImFont::FindGlyph(ImWchar c) const
1193b4be Poul Sander 2025-02-03 21:28 3832
{
1193b4be Poul Sander 2025-02-03 21:28 3833
    if (c >= (size_t)IndexLookup.Size)
1193b4be Poul Sander 2025-02-03 21:28 3834
        return FallbackGlyph;
1193b4be Poul Sander 2025-02-03 21:28 3835
    const ImWchar i = IndexLookup.Data[c];
1193b4be Poul Sander 2025-02-03 21:28 3836
    if (i == (ImWchar)-1)
1193b4be Poul Sander 2025-02-03 21:28 3837
        return FallbackGlyph;
1193b4be Poul Sander 2025-02-03 21:28 3838
    return &Glyphs.Data[i];
1193b4be Poul Sander 2025-02-03 21:28 3839
}
1193b4be Poul Sander 2025-02-03 21:28 3840
1193b4be Poul Sander 2025-02-03 21:28 3841
const ImFontGlyph* ImFont::FindGlyphNoFallback(ImWchar c) const
1193b4be Poul Sander 2025-02-03 21:28 3842
{
1193b4be Poul Sander 2025-02-03 21:28 3843
    if (c >= (size_t)IndexLookup.Size)
1193b4be Poul Sander 2025-02-03 21:28 3844
        return NULL;
1193b4be Poul Sander 2025-02-03 21:28 3845
    const ImWchar i = IndexLookup.Data[c];
1193b4be Poul Sander 2025-02-03 21:28 3846
    if (i == (ImWchar)-1)
1193b4be Poul Sander 2025-02-03 21:28 3847
        return NULL;
1193b4be Poul Sander 2025-02-03 21:28 3848
    return &Glyphs.Data[i];
1193b4be Poul Sander 2025-02-03 21:28 3849
}
1193b4be Poul Sander 2025-02-03 21:28 3850
1193b4be Poul Sander 2025-02-03 21:28 3851
// Wrapping skips upcoming blanks
1193b4be Poul Sander 2025-02-03 21:28 3852
static inline const char* CalcWordWrapNextLineStartA(const char* text, const char* text_end)
1193b4be Poul Sander 2025-02-03 21:28 3853
{
1193b4be Poul Sander 2025-02-03 21:28 3854
    while (text < text_end && ImCharIsBlankA(*text))
1193b4be Poul Sander 2025-02-03 21:28 3855
        text++;
1193b4be Poul Sander 2025-02-03 21:28 3856
    if (*text == '\n')
1193b4be Poul Sander 2025-02-03 21:28 3857
        text++;
1193b4be Poul Sander 2025-02-03 21:28 3858
    return text;
1193b4be Poul Sander 2025-02-03 21:28 3859
}
1193b4be Poul Sander 2025-02-03 21:28 3860
1193b4be Poul Sander 2025-02-03 21:28 3861
// Simple word-wrapping for English, not full-featured. Please submit failing cases!
1193b4be Poul Sander 2025-02-03 21:28 3862
// This will return the next location to wrap from. If no wrapping if necessary, this will fast-forward to e.g. text_end.
1193b4be Poul Sander 2025-02-03 21:28 3863
// 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.)
1193b4be Poul Sander 2025-02-03 21:28 3864
const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) const
1193b4be Poul Sander 2025-02-03 21:28 3865
{
1193b4be Poul Sander 2025-02-03 21:28 3866
    // For references, possible wrap point marked with ^
1193b4be Poul Sander 2025-02-03 21:28 3867
    //  "aaa bbb, ccc,ddd. eee   fff. ggg!"
1193b4be Poul Sander 2025-02-03 21:28 3868
    //      ^    ^    ^   ^   ^__    ^    ^
1193b4be Poul Sander 2025-02-03 21:28 3869
1193b4be Poul Sander 2025-02-03 21:28 3870
    // List of hardcoded separators: .,;!?'"
1193b4be Poul Sander 2025-02-03 21:28 3871
1193b4be Poul Sander 2025-02-03 21:28 3872
    // Skip extra blanks after a line returns (that includes not counting them in width computation)
1193b4be Poul Sander 2025-02-03 21:28 3873
    // e.g. "Hello    world" --> "Hello" "World"
1193b4be Poul Sander 2025-02-03 21:28 3874
1193b4be Poul Sander 2025-02-03 21:28 3875
    // Cut words that cannot possibly fit within one line.
1193b4be Poul Sander 2025-02-03 21:28 3876
    // e.g.: "The tropical fish" with ~5 characters worth of width --> "The tr" "opical" "fish"
1193b4be Poul Sander 2025-02-03 21:28 3877
    float line_width = 0.0f;
1193b4be Poul Sander 2025-02-03 21:28 3878
    float word_width = 0.0f;
1193b4be Poul Sander 2025-02-03 21:28 3879
    float blank_width = 0.0f;
1193b4be Poul Sander 2025-02-03 21:28 3880
    wrap_width /= scale; // We work with unscaled widths to avoid scaling every characters
1193b4be Poul Sander 2025-02-03 21:28 3881
1193b4be Poul Sander 2025-02-03 21:28 3882
    const char* word_end = text;
1193b4be Poul Sander 2025-02-03 21:28 3883
    const char* prev_word_end = NULL;
1193b4be Poul Sander 2025-02-03 21:28 3884
    bool inside_word = true;
1193b4be Poul Sander 2025-02-03 21:28 3885
1193b4be Poul Sander 2025-02-03 21:28 3886
    const char* s = text;
1193b4be Poul Sander 2025-02-03 21:28 3887
    IM_ASSERT(text_end != NULL);
1193b4be Poul Sander 2025-02-03 21:28 3888
    while (s < text_end)
1193b4be Poul Sander 2025-02-03 21:28 3889
    {
1193b4be Poul Sander 2025-02-03 21:28 3890
        unsigned int c = (unsigned int)*s;
1193b4be Poul Sander 2025-02-03 21:28 3891
        const char* next_s;
1193b4be Poul Sander 2025-02-03 21:28 3892
        if (c < 0x80)
1193b4be Poul Sander 2025-02-03 21:28 3893
            next_s = s + 1;
1193b4be Poul Sander 2025-02-03 21:28 3894
        else
1193b4be Poul Sander 2025-02-03 21:28 3895
            next_s = s + ImTextCharFromUtf8(&c, s, text_end);
1193b4be Poul Sander 2025-02-03 21:28 3896
1193b4be Poul Sander 2025-02-03 21:28 3897
        if (c < 32)
1193b4be Poul Sander 2025-02-03 21:28 3898
        {
1193b4be Poul Sander 2025-02-03 21:28 3899
            if (c == '\n')
1193b4be Poul Sander 2025-02-03 21:28 3900
            {
1193b4be Poul Sander 2025-02-03 21:28 3901
                line_width = word_width = blank_width = 0.0f;
1193b4be Poul Sander 2025-02-03 21:28 3902
                inside_word = true;
1193b4be Poul Sander 2025-02-03 21:28 3903
                s = next_s;
1193b4be Poul Sander 2025-02-03 21:28 3904
                continue;
1193b4be Poul Sander 2025-02-03 21:28 3905
            }
1193b4be Poul Sander 2025-02-03 21:28 3906
            if (c == '\r')
1193b4be Poul Sander 2025-02-03 21:28 3907
            {
1193b4be Poul Sander 2025-02-03 21:28 3908
                s = next_s;
1193b4be Poul Sander 2025-02-03 21:28 3909
                continue;
1193b4be Poul Sander 2025-02-03 21:28 3910
            }
1193b4be Poul Sander 2025-02-03 21:28 3911
        }
1193b4be Poul Sander 2025-02-03 21:28 3912
1193b4be Poul Sander 2025-02-03 21:28 3913
        const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX.Data[c] : FallbackAdvanceX);
1193b4be Poul Sander 2025-02-03 21:28 3914
        if (ImCharIsBlankW(c))
1193b4be Poul Sander 2025-02-03 21:28 3915
        {
1193b4be Poul Sander 2025-02-03 21:28 3916
            if (inside_word)
1193b4be Poul Sander 2025-02-03 21:28 3917
            {
1193b4be Poul Sander 2025-02-03 21:28 3918
                line_width += blank_width;
1193b4be Poul Sander 2025-02-03 21:28 3919
                blank_width = 0.0f;
1193b4be Poul Sander 2025-02-03 21:28 3920
                word_end = s;
1193b4be Poul Sander 2025-02-03 21:28 3921
            }
1193b4be Poul Sander 2025-02-03 21:28 3922
            blank_width += char_width;
1193b4be Poul Sander 2025-02-03 21:28 3923
            inside_word = false;
1193b4be Poul Sander 2025-02-03 21:28 3924
        }
1193b4be Poul Sander 2025-02-03 21:28 3925
        else
1193b4be Poul Sander 2025-02-03 21:28 3926
        {
1193b4be Poul Sander 2025-02-03 21:28 3927
            word_width += char_width;
1193b4be Poul Sander 2025-02-03 21:28 3928
            if (inside_word)
1193b4be Poul Sander 2025-02-03 21:28 3929
            {
1193b4be Poul Sander 2025-02-03 21:28 3930
                word_end = next_s;
1193b4be Poul Sander 2025-02-03 21:28 3931
            }
1193b4be Poul Sander 2025-02-03 21:28 3932
            else
1193b4be Poul Sander 2025-02-03 21:28 3933
            {
1193b4be Poul Sander 2025-02-03 21:28 3934
                prev_word_end = word_end;
1193b4be Poul Sander 2025-02-03 21:28 3935
                line_width += word_width + blank_width;
1193b4be Poul Sander 2025-02-03 21:28 3936
                word_width = blank_width = 0.0f;
1193b4be Poul Sander 2025-02-03 21:28 3937
            }
1193b4be Poul Sander 2025-02-03 21:28 3938
1193b4be Poul Sander 2025-02-03 21:28 3939
            // Allow wrapping after punctuation.
1193b4be Poul Sander 2025-02-03 21:28 3940
            inside_word = (c != '.' && c != ',' && c != ';' && c != '!' && c != '?' && c != '\"');
1193b4be Poul Sander 2025-02-03 21:28 3941
        }
1193b4be Poul Sander 2025-02-03 21:28 3942
1193b4be Poul Sander 2025-02-03 21:28 3943
        // We ignore blank width at the end of the line (they can be skipped)
1193b4be Poul Sander 2025-02-03 21:28 3944
        if (line_width + word_width > wrap_width)
1193b4be Poul Sander 2025-02-03 21:28 3945
        {
1193b4be Poul Sander 2025-02-03 21:28 3946
            // Words that cannot possibly fit within an entire line will be cut anywhere.
1193b4be Poul Sander 2025-02-03 21:28 3947
            if (word_width < wrap_width)
1193b4be Poul Sander 2025-02-03 21:28 3948
                s = prev_word_end ? prev_word_end : word_end;
1193b4be Poul Sander 2025-02-03 21:28 3949
            break;
1193b4be Poul Sander 2025-02-03 21:28 3950
        }
1193b4be Poul Sander 2025-02-03 21:28 3951
1193b4be Poul Sander 2025-02-03 21:28 3952
        s = next_s;
1193b4be Poul Sander 2025-02-03 21:28 3953
    }
1193b4be Poul Sander 2025-02-03 21:28 3954
1193b4be Poul Sander 2025-02-03 21:28 3955
    // Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity.
1193b4be Poul Sander 2025-02-03 21:28 3956
    // +1 may not be a character start point in UTF-8 but it's ok because caller loops use (text >= word_wrap_eol).
1193b4be Poul Sander 2025-02-03 21:28 3957
    if (s == text && text < text_end)
1193b4be Poul Sander 2025-02-03 21:28 3958
        return s + 1;
1193b4be Poul Sander 2025-02-03 21:28 3959
    return s;
1193b4be Poul Sander 2025-02-03 21:28 3960
}
1193b4be Poul Sander 2025-02-03 21:28 3961
1193b4be Poul Sander 2025-02-03 21:28 3962
ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end, const char** remaining) const
1193b4be Poul Sander 2025-02-03 21:28 3963
{
1193b4be Poul Sander 2025-02-03 21:28 3964
    if (!text_end)
1193b4be Poul Sander 2025-02-03 21:28 3965
        text_end = text_begin + strlen(text_begin); // FIXME-OPT: Need to avoid this.
1193b4be Poul Sander 2025-02-03 21:28 3966
1193b4be Poul Sander 2025-02-03 21:28 3967
    const float line_height = size;
1193b4be Poul Sander 2025-02-03 21:28 3968
    const float scale = size / FontSize;
1193b4be Poul Sander 2025-02-03 21:28 3969
1193b4be Poul Sander 2025-02-03 21:28 3970
    ImVec2 text_size = ImVec2(0, 0);
1193b4be Poul Sander 2025-02-03 21:28 3971
    float line_width = 0.0f;
1193b4be Poul Sander 2025-02-03 21:28 3972
1193b4be Poul Sander 2025-02-03 21:28 3973
    const bool word_wrap_enabled = (wrap_width > 0.0f);
1193b4be Poul Sander 2025-02-03 21:28 3974
    const char* word_wrap_eol = NULL;
1193b4be Poul Sander 2025-02-03 21:28 3975
1193b4be Poul Sander 2025-02-03 21:28 3976
    const char* s = text_begin;
1193b4be Poul Sander 2025-02-03 21:28 3977
    while (s < text_end)
1193b4be Poul Sander 2025-02-03 21:28 3978
    {
1193b4be Poul Sander 2025-02-03 21:28 3979
        if (word_wrap_enabled)
1193b4be Poul Sander 2025-02-03 21:28 3980
        {
1193b4be Poul Sander 2025-02-03 21:28 3981
            // 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.
1193b4be Poul Sander 2025-02-03 21:28 3982
            if (!word_wrap_eol)
1193b4be Poul Sander 2025-02-03 21:28 3983
                word_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - line_width);
1193b4be Poul Sander 2025-02-03 21:28 3984
1193b4be Poul Sander 2025-02-03 21:28 3985
            if (s >= word_wrap_eol)
1193b4be Poul Sander 2025-02-03 21:28 3986
            {
1193b4be Poul Sander 2025-02-03 21:28 3987
                if (text_size.x < line_width)
1193b4be Poul Sander 2025-02-03 21:28 3988
                    text_size.x = line_width;
1193b4be Poul Sander 2025-02-03 21:28 3989
                text_size.y += line_height;
1193b4be Poul Sander 2025-02-03 21:28 3990
                line_width = 0.0f;
1193b4be Poul Sander 2025-02-03 21:28 3991
                word_wrap_eol = NULL;
1193b4be Poul Sander 2025-02-03 21:28 3992
                s = CalcWordWrapNextLineStartA(s, text_end); // Wrapping skips upcoming blanks
1193b4be Poul Sander 2025-02-03 21:28 3993
                continue;
1193b4be Poul Sander 2025-02-03 21:28 3994
            }
1193b4be Poul Sander 2025-02-03 21:28 3995
        }
1193b4be Poul Sander 2025-02-03 21:28 3996
1193b4be Poul Sander 2025-02-03 21:28 3997
        // Decode and advance source
1193b4be Poul Sander 2025-02-03 21:28 3998
        const char* prev_s = s;
1193b4be Poul Sander 2025-02-03 21:28 3999
        unsigned int c = (unsigned int)*s;
1193b4be Poul Sander 2025-02-03 21:28 4000
        if (c < 0x80)
1193b4be Poul Sander 2025-02-03 21:28 4001
            s += 1;
1193b4be Poul Sander 2025-02-03 21:28 4002
        else
1193b4be Poul Sander 2025-02-03 21:28 4003
            s += ImTextCharFromUtf8(&c, s, text_end);
1193b4be Poul Sander 2025-02-03 21:28 4004
1193b4be Poul Sander 2025-02-03 21:28 4005
        if (c < 32)
1193b4be Poul Sander 2025-02-03 21:28 4006
        {
1193b4be Poul Sander 2025-02-03 21:28 4007
            if (c == '\n')
1193b4be Poul Sander 2025-02-03 21:28 4008
            {
1193b4be Poul Sander 2025-02-03 21:28 4009
                text_size.x = ImMax(text_size.x, line_width);
1193b4be Poul Sander 2025-02-03 21:28 4010
                text_size.y += line_height;
1193b4be Poul Sander 2025-02-03 21:28 4011
                line_width = 0.0f;
1193b4be Poul Sander 2025-02-03 21:28 4012
                continue;
1193b4be Poul Sander 2025-02-03 21:28 4013
            }
1193b4be Poul Sander 2025-02-03 21:28 4014
            if (c == '\r')
1193b4be Poul Sander 2025-02-03 21:28 4015
                continue;
1193b4be Poul Sander 2025-02-03 21:28 4016
        }
1193b4be Poul Sander 2025-02-03 21:28 4017
1193b4be Poul Sander 2025-02-03 21:28 4018
        const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX.Data[c] : FallbackAdvanceX) * scale;
1193b4be Poul Sander 2025-02-03 21:28 4019
        if (line_width + char_width >= max_width)
1193b4be Poul Sander 2025-02-03 21:28 4020
        {
1193b4be Poul Sander 2025-02-03 21:28 4021
            s = prev_s;
1193b4be Poul Sander 2025-02-03 21:28 4022
            break;
1193b4be Poul Sander 2025-02-03 21:28 4023
        }
1193b4be Poul Sander 2025-02-03 21:28 4024
1193b4be Poul Sander 2025-02-03 21:28 4025
        line_width += char_width;
1193b4be Poul Sander 2025-02-03 21:28 4026
    }
1193b4be Poul Sander 2025-02-03 21:28 4027
1193b4be Poul Sander 2025-02-03 21:28 4028
    if (text_size.x < line_width)
1193b4be Poul Sander 2025-02-03 21:28 4029
        text_size.x = line_width;
1193b4be Poul Sander 2025-02-03 21:28 4030
1193b4be Poul Sander 2025-02-03 21:28 4031
    if (line_width > 0 || text_size.y == 0.0f)
1193b4be Poul Sander 2025-02-03 21:28 4032
        text_size.y += line_height;
1193b4be Poul Sander 2025-02-03 21:28 4033
1193b4be Poul Sander 2025-02-03 21:28 4034
    if (remaining)
1193b4be Poul Sander 2025-02-03 21:28 4035
        *remaining = s;
1193b4be Poul Sander 2025-02-03 21:28 4036
1193b4be Poul Sander 2025-02-03 21:28 4037
    return text_size;
1193b4be Poul Sander 2025-02-03 21:28 4038
}
1193b4be Poul Sander 2025-02-03 21:28 4039
1193b4be Poul Sander 2025-02-03 21:28 4040
// Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound.
1193b4be Poul Sander 2025-02-03 21:28 4041
void ImFont::RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, ImWchar c) const
1193b4be Poul Sander 2025-02-03 21:28 4042
{
1193b4be Poul Sander 2025-02-03 21:28 4043
    const ImFontGlyph* glyph = FindGlyph(c);
1193b4be Poul Sander 2025-02-03 21:28 4044
    if (!glyph || !glyph->Visible)
1193b4be Poul Sander 2025-02-03 21:28 4045
        return;
1193b4be Poul Sander 2025-02-03 21:28 4046
    if (glyph->Colored)
1193b4be Poul Sander 2025-02-03 21:28 4047
        col |= ~IM_COL32_A_MASK;
1193b4be Poul Sander 2025-02-03 21:28 4048
    float scale = (size >= 0.0f) ? (size / FontSize) : 1.0f;
1193b4be Poul Sander 2025-02-03 21:28 4049
    float x = IM_TRUNC(pos.x);
1193b4be Poul Sander 2025-02-03 21:28 4050
    float y = IM_TRUNC(pos.y);
1193b4be Poul Sander 2025-02-03 21:28 4051
    draw_list->PrimReserve(6, 4);
1193b4be Poul Sander 2025-02-03 21:28 4052
    draw_list->PrimRectUV(ImVec2(x + glyph->X0 * scale, y + glyph->Y0 * scale), ImVec2(x + glyph->X1 * scale, y + glyph->Y1 * scale), ImVec2(glyph->U0, glyph->V0), ImVec2(glyph->U1, glyph->V1), col);
1193b4be Poul Sander 2025-02-03 21:28 4053
}
1193b4be Poul Sander 2025-02-03 21:28 4054
1193b4be Poul Sander 2025-02-03 21:28 4055
// Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound.
1193b4be Poul Sander 2025-02-03 21:28 4056
void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width, bool cpu_fine_clip) const
1193b4be Poul Sander 2025-02-03 21:28 4057
{
1193b4be Poul Sander 2025-02-03 21:28 4058
    if (!text_end)
1193b4be Poul Sander 2025-02-03 21:28 4059
        text_end = text_begin + strlen(text_begin); // ImGui:: functions generally already provides a valid text_end, so this is merely to handle direct calls.
1193b4be Poul Sander 2025-02-03 21:28 4060
1193b4be Poul Sander 2025-02-03 21:28 4061
    // Align to be pixel perfect
1193b4be Poul Sander 2025-02-03 21:28 4062
    float x = IM_TRUNC(pos.x);
1193b4be Poul Sander 2025-02-03 21:28 4063
    float y = IM_TRUNC(pos.y);
1193b4be Poul Sander 2025-02-03 21:28 4064
    if (y > clip_rect.w)
1193b4be Poul Sander 2025-02-03 21:28 4065
        return;
1193b4be Poul Sander 2025-02-03 21:28 4066
1193b4be Poul Sander 2025-02-03 21:28 4067
    const float start_x = x;
1193b4be Poul Sander 2025-02-03 21:28 4068
    const float scale = size / FontSize;
1193b4be Poul Sander 2025-02-03 21:28 4069
    const float line_height = FontSize * scale;
1193b4be Poul Sander 2025-02-03 21:28 4070
    const bool word_wrap_enabled = (wrap_width > 0.0f);
1193b4be Poul Sander 2025-02-03 21:28 4071
1193b4be Poul Sander 2025-02-03 21:28 4072
    // Fast-forward to first visible line
1193b4be Poul Sander 2025-02-03 21:28 4073
    const char* s = text_begin;
1193b4be Poul Sander 2025-02-03 21:28 4074
    if (y + line_height < clip_rect.y)
1193b4be Poul Sander 2025-02-03 21:28 4075
        while (y + line_height < clip_rect.y && s < text_end)
1193b4be Poul Sander 2025-02-03 21:28 4076
        {
1193b4be Poul Sander 2025-02-03 21:28 4077
            const char* line_end = (const char*)memchr(s, '\n', text_end - s);
1193b4be Poul Sander 2025-02-03 21:28 4078
            if (word_wrap_enabled)
1193b4be Poul Sander 2025-02-03 21:28 4079
            {
1193b4be Poul Sander 2025-02-03 21:28 4080
                // FIXME-OPT: This is not optimal as do first do a search for \n before calling CalcWordWrapPositionA().
1193b4be Poul Sander 2025-02-03 21:28 4081
                // If the specs for CalcWordWrapPositionA() were reworked to optionally return on \n we could combine both.
1193b4be Poul Sander 2025-02-03 21:28 4082
                // However it is still better than nothing performing the fast-forward!
1193b4be Poul Sander 2025-02-03 21:28 4083
                s = CalcWordWrapPositionA(scale, s, line_end ? line_end : text_end, wrap_width);
1193b4be Poul Sander 2025-02-03 21:28 4084
                s = CalcWordWrapNextLineStartA(s, text_end);
1193b4be Poul Sander 2025-02-03 21:28 4085
            }
1193b4be Poul Sander 2025-02-03 21:28 4086
            else
1193b4be Poul Sander 2025-02-03 21:28 4087
            {
1193b4be Poul Sander 2025-02-03 21:28 4088
                s = line_end ? line_end + 1 : text_end;
1193b4be Poul Sander 2025-02-03 21:28 4089
            }
1193b4be Poul Sander 2025-02-03 21:28 4090
            y += line_height;
1193b4be Poul Sander 2025-02-03 21:28 4091
        }
1193b4be Poul Sander 2025-02-03 21:28 4092
1193b4be Poul Sander 2025-02-03 21:28 4093
    // For large text, scan for the last visible line in order to avoid over-reserving in the call to PrimReserve()
1193b4be Poul Sander 2025-02-03 21:28 4094
    // 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)
1193b4be Poul Sander 2025-02-03 21:28 4095
    if (text_end - s > 10000 && !word_wrap_enabled)
1193b4be Poul Sander 2025-02-03 21:28 4096
    {
1193b4be Poul Sander 2025-02-03 21:28 4097
        const char* s_end = s;
1193b4be Poul Sander 2025-02-03 21:28 4098
        float y_end = y;
1193b4be Poul Sander 2025-02-03 21:28 4099
        while (y_end < clip_rect.w && s_end < text_end)
1193b4be Poul Sander 2025-02-03 21:28 4100
        {
1193b4be Poul Sander 2025-02-03 21:28 4101
            s_end = (const char*)memchr(s_end, '\n', text_end - s_end);
1193b4be Poul Sander 2025-02-03 21:28 4102
            s_end = s_end ? s_end + 1 : text_end;
1193b4be Poul Sander 2025-02-03 21:28 4103
            y_end += line_height;
1193b4be Poul Sander 2025-02-03 21:28 4104
        }
1193b4be Poul Sander 2025-02-03 21:28 4105
        text_end = s_end;
1193b4be Poul Sander 2025-02-03 21:28 4106
    }
1193b4be Poul Sander 2025-02-03 21:28 4107
    if (s == text_end)
1193b4be Poul Sander 2025-02-03 21:28 4108
        return;
1193b4be Poul Sander 2025-02-03 21:28 4109
1193b4be Poul Sander 2025-02-03 21:28 4110
    // Reserve vertices for remaining worse case (over-reserving is useful and easily amortized)
1193b4be Poul Sander 2025-02-03 21:28 4111
    const int vtx_count_max = (int)(text_end - s) * 4;
1193b4be Poul Sander 2025-02-03 21:28 4112
    const int idx_count_max = (int)(text_end - s) * 6;
1193b4be Poul Sander 2025-02-03 21:28 4113
    const int idx_expected_size = draw_list->IdxBuffer.Size + idx_count_max;
1193b4be Poul Sander 2025-02-03 21:28 4114
    draw_list->PrimReserve(idx_count_max, vtx_count_max);
1193b4be Poul Sander 2025-02-03 21:28 4115
    ImDrawVert*  vtx_write = draw_list->_VtxWritePtr;
1193b4be Poul Sander 2025-02-03 21:28 4116
    ImDrawIdx*   idx_write = draw_list->_IdxWritePtr;
1193b4be Poul Sander 2025-02-03 21:28 4117
    unsigned int vtx_index = draw_list->_VtxCurrentIdx;
1193b4be Poul Sander 2025-02-03 21:28 4118
1193b4be Poul Sander 2025-02-03 21:28 4119
    const ImU32 col_untinted = col | ~IM_COL32_A_MASK;
1193b4be Poul Sander 2025-02-03 21:28 4120
    const char* word_wrap_eol = NULL;
1193b4be Poul Sander 2025-02-03 21:28 4121
1193b4be Poul Sander 2025-02-03 21:28 4122
    while (s < text_end)
1193b4be Poul Sander 2025-02-03 21:28 4123
    {
1193b4be Poul Sander 2025-02-03 21:28 4124
        if (word_wrap_enabled)
1193b4be Poul Sander 2025-02-03 21:28 4125
        {
1193b4be Poul Sander 2025-02-03 21:28 4126
            // 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.
1193b4be Poul Sander 2025-02-03 21:28 4127
            if (!word_wrap_eol)
1193b4be Poul Sander 2025-02-03 21:28 4128
                word_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - (x - start_x));
1193b4be Poul Sander 2025-02-03 21:28 4129
1193b4be Poul Sander 2025-02-03 21:28 4130
            if (s >= word_wrap_eol)
1193b4be Poul Sander 2025-02-03 21:28 4131
            {
1193b4be Poul Sander 2025-02-03 21:28 4132
                x = start_x;
1193b4be Poul Sander 2025-02-03 21:28 4133
                y += line_height;
1193b4be Poul Sander 2025-02-03 21:28 4134
                if (y > clip_rect.w)
1193b4be Poul Sander 2025-02-03 21:28 4135
                    break; // break out of main loop
1193b4be Poul Sander 2025-02-03 21:28 4136
                word_wrap_eol = NULL;
1193b4be Poul Sander 2025-02-03 21:28 4137
                s = CalcWordWrapNextLineStartA(s, text_end); // Wrapping skips upcoming blanks
1193b4be Poul Sander 2025-02-03 21:28 4138
                continue;
1193b4be Poul Sander 2025-02-03 21:28 4139
            }
1193b4be Poul Sander 2025-02-03 21:28 4140
        }
1193b4be Poul Sander 2025-02-03 21:28 4141
1193b4be Poul Sander 2025-02-03 21:28 4142
        // Decode and advance source
1193b4be Poul Sander 2025-02-03 21:28 4143
        unsigned int c = (unsigned int)*s;
1193b4be Poul Sander 2025-02-03 21:28 4144
        if (c < 0x80)
1193b4be Poul Sander 2025-02-03 21:28 4145
            s += 1;
1193b4be Poul Sander 2025-02-03 21:28 4146
        else
1193b4be Poul Sander 2025-02-03 21:28 4147
            s += ImTextCharFromUtf8(&c, s, text_end);
1193b4be Poul Sander 2025-02-03 21:28 4148
1193b4be Poul Sander 2025-02-03 21:28 4149
        if (c < 32)
1193b4be Poul Sander 2025-02-03 21:28 4150
        {
1193b4be Poul Sander 2025-02-03 21:28 4151
            if (c == '\n')
1193b4be Poul Sander 2025-02-03 21:28 4152
            {
1193b4be Poul Sander 2025-02-03 21:28 4153
                x = start_x;
1193b4be Poul Sander 2025-02-03 21:28 4154
                y += line_height;
1193b4be Poul Sander 2025-02-03 21:28 4155
                if (y > clip_rect.w)
1193b4be Poul Sander 2025-02-03 21:28 4156
                    break; // break out of main loop
1193b4be Poul Sander 2025-02-03 21:28 4157
                continue;
1193b4be Poul Sander 2025-02-03 21:28 4158
            }
1193b4be Poul Sander 2025-02-03 21:28 4159
            if (c == '\r')
1193b4be Poul Sander 2025-02-03 21:28 4160
                continue;
1193b4be Poul Sander 2025-02-03 21:28 4161
        }
1193b4be Poul Sander 2025-02-03 21:28 4162
1193b4be Poul Sander 2025-02-03 21:28 4163
        const ImFontGlyph* glyph = FindGlyph((ImWchar)c);
1193b4be Poul Sander 2025-02-03 21:28 4164
        if (glyph == NULL)
1193b4be Poul Sander 2025-02-03 21:28 4165
            continue;
1193b4be Poul Sander 2025-02-03 21:28 4166
1193b4be Poul Sander 2025-02-03 21:28 4167
        float char_width = glyph->AdvanceX * scale;
1193b4be Poul Sander 2025-02-03 21:28 4168
        if (glyph->Visible)
1193b4be Poul Sander 2025-02-03 21:28 4169
        {
1193b4be Poul Sander 2025-02-03 21:28 4170
            // 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
1193b4be Poul Sander 2025-02-03 21:28 4171
            float x1 = x + glyph->X0 * scale;
1193b4be Poul Sander 2025-02-03 21:28 4172
            float x2 = x + glyph->X1 * scale;
1193b4be Poul Sander 2025-02-03 21:28 4173
            float y1 = y + glyph->Y0 * scale;
1193b4be Poul Sander 2025-02-03 21:28 4174
            float y2 = y + glyph->Y1 * scale;
1193b4be Poul Sander 2025-02-03 21:28 4175
            if (x1 <= clip_rect.z && x2 >= clip_rect.x)
1193b4be Poul Sander 2025-02-03 21:28 4176
            {
1193b4be Poul Sander 2025-02-03 21:28 4177
                // Render a character
1193b4be Poul Sander 2025-02-03 21:28 4178
                float u1 = glyph->U0;
1193b4be Poul Sander 2025-02-03 21:28 4179
                float v1 = glyph->V0;
1193b4be Poul Sander 2025-02-03 21:28 4180
                float u2 = glyph->U1;
1193b4be Poul Sander 2025-02-03 21:28 4181
                float v2 = glyph->V1;
1193b4be Poul Sander 2025-02-03 21:28 4182
1193b4be Poul Sander 2025-02-03 21:28 4183
                // CPU side clipping used to fit text in their frame when the frame is too small. Only does clipping for axis aligned quads.
1193b4be Poul Sander 2025-02-03 21:28 4184
                if (cpu_fine_clip)
1193b4be Poul Sander 2025-02-03 21:28 4185
                {
1193b4be Poul Sander 2025-02-03 21:28 4186
                    if (x1 < clip_rect.x)
1193b4be Poul Sander 2025-02-03 21:28 4187
                    {
1193b4be Poul Sander 2025-02-03 21:28 4188
                        u1 = u1 + (1.0f - (x2 - clip_rect.x) / (x2 - x1)) * (u2 - u1);
1193b4be Poul Sander 2025-02-03 21:28 4189
                        x1 = clip_rect.x;
1193b4be Poul Sander 2025-02-03 21:28 4190
                    }
1193b4be Poul Sander 2025-02-03 21:28 4191
                    if (y1 < clip_rect.y)
1193b4be Poul Sander 2025-02-03 21:28 4192
                    {
1193b4be Poul Sander 2025-02-03 21:28 4193
                        v1 = v1 + (1.0f - (y2 - clip_rect.y) / (y2 - y1)) * (v2 - v1);
1193b4be Poul Sander 2025-02-03 21:28 4194
                        y1 = clip_rect.y;
1193b4be Poul Sander 2025-02-03 21:28 4195
                    }
1193b4be Poul Sander 2025-02-03 21:28 4196
                    if (x2 > clip_rect.z)
1193b4be Poul Sander 2025-02-03 21:28 4197
                    {
1193b4be Poul Sander 2025-02-03 21:28 4198
                        u2 = u1 + ((clip_rect.z - x1) / (x2 - x1)) * (u2 - u1);
1193b4be Poul Sander 2025-02-03 21:28 4199
                        x2 = clip_rect.z;
1193b4be Poul Sander 2025-02-03 21:28 4200
                    }
1193b4be Poul Sander 2025-02-03 21:28 4201
                    if (y2 > clip_rect.w)
1193b4be Poul Sander 2025-02-03 21:28 4202
                    {
1193b4be Poul Sander 2025-02-03 21:28 4203
                        v2 = v1 + ((clip_rect.w - y1) / (y2 - y1)) * (v2 - v1);
1193b4be Poul Sander 2025-02-03 21:28 4204
                        y2 = clip_rect.w;
1193b4be Poul Sander 2025-02-03 21:28 4205
                    }
1193b4be Poul Sander 2025-02-03 21:28 4206
                    if (y1 >= y2)
1193b4be Poul Sander 2025-02-03 21:28 4207
                    {
1193b4be Poul Sander 2025-02-03 21:28 4208
                        x += char_width;
1193b4be Poul Sander 2025-02-03 21:28 4209
                        continue;
1193b4be Poul Sander 2025-02-03 21:28 4210
                    }
1193b4be Poul Sander 2025-02-03 21:28 4211
                }
1193b4be Poul Sander 2025-02-03 21:28 4212
1193b4be Poul Sander 2025-02-03 21:28 4213
                // Support for untinted glyphs
1193b4be Poul Sander 2025-02-03 21:28 4214
                ImU32 glyph_col = glyph->Colored ? col_untinted : col;
1193b4be Poul Sander 2025-02-03 21:28 4215
1193b4be Poul Sander 2025-02-03 21:28 4216
                // We are NOT calling PrimRectUV() here because non-inlined causes too much overhead in a debug builds. Inlined here:
1193b4be Poul Sander 2025-02-03 21:28 4217
                {
1193b4be Poul Sander 2025-02-03 21:28 4218
                    vtx_write[0].pos.x = x1; vtx_write[0].pos.y = y1; vtx_write[0].col = glyph_col; vtx_write[0].uv.x = u1; vtx_write[0].uv.y = v1;
1193b4be Poul Sander 2025-02-03 21:28 4219
                    vtx_write[1].pos.x = x2; vtx_write[1].pos.y = y1; vtx_write[1].col = glyph_col; vtx_write[1].uv.x = u2; vtx_write[1].uv.y = v1;
1193b4be Poul Sander 2025-02-03 21:28 4220
                    vtx_write[2].pos.x = x2; vtx_write[2].pos.y = y2; vtx_write[2].col = glyph_col; vtx_write[2].uv.x = u2; vtx_write[2].uv.y = v2;
1193b4be Poul Sander 2025-02-03 21:28 4221
                    vtx_write[3].pos.x = x1; vtx_write[3].pos.y = y2; vtx_write[3].col = glyph_col; vtx_write[3].uv.x = u1; vtx_write[3].uv.y = v2;
1193b4be Poul Sander 2025-02-03 21:28 4222
                    idx_write[0] = (ImDrawIdx)(vtx_index); idx_write[1] = (ImDrawIdx)(vtx_index + 1); idx_write[2] = (ImDrawIdx)(vtx_index + 2);
1193b4be Poul Sander 2025-02-03 21:28 4223
                    idx_write[3] = (ImDrawIdx)(vtx_index); idx_write[4] = (ImDrawIdx)(vtx_index + 2); idx_write[5] = (ImDrawIdx)(vtx_index + 3);
1193b4be Poul Sander 2025-02-03 21:28 4224
                    vtx_write += 4;
1193b4be Poul Sander 2025-02-03 21:28 4225
                    vtx_index += 4;
1193b4be Poul Sander 2025-02-03 21:28 4226
                    idx_write += 6;
1193b4be Poul Sander 2025-02-03 21:28 4227
                }
1193b4be Poul Sander 2025-02-03 21:28 4228
            }
1193b4be Poul Sander 2025-02-03 21:28 4229
        }
1193b4be Poul Sander 2025-02-03 21:28 4230
        x += char_width;
1193b4be Poul Sander 2025-02-03 21:28 4231
    }
1193b4be Poul Sander 2025-02-03 21:28 4232
1193b4be Poul Sander 2025-02-03 21:28 4233
    // Give back unused vertices (clipped ones, blanks) ~ this is essentially a PrimUnreserve() action.
1193b4be Poul Sander 2025-02-03 21:28 4234
    draw_list->VtxBuffer.Size = (int)(vtx_write - draw_list->VtxBuffer.Data); // Same as calling shrink()
1193b4be Poul Sander 2025-02-03 21:28 4235
    draw_list->IdxBuffer.Size = (int)(idx_write - draw_list->IdxBuffer.Data);
1193b4be Poul Sander 2025-02-03 21:28 4236
    draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 1].ElemCount -= (idx_expected_size - draw_list->IdxBuffer.Size);
1193b4be Poul Sander 2025-02-03 21:28 4237
    draw_list->_VtxWritePtr = vtx_write;
1193b4be Poul Sander 2025-02-03 21:28 4238
    draw_list->_IdxWritePtr = idx_write;
1193b4be Poul Sander 2025-02-03 21:28 4239
    draw_list->_VtxCurrentIdx = vtx_index;
1193b4be Poul Sander 2025-02-03 21:28 4240
}
1193b4be Poul Sander 2025-02-03 21:28 4241
1193b4be Poul Sander 2025-02-03 21:28 4242
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 4243
// [SECTION] ImGui Internal Render Helpers
1193b4be Poul Sander 2025-02-03 21:28 4244
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 4245
// Vaguely redesigned to stop accessing ImGui global state:
1193b4be Poul Sander 2025-02-03 21:28 4246
// - RenderArrow()
1193b4be Poul Sander 2025-02-03 21:28 4247
// - RenderBullet()
1193b4be Poul Sander 2025-02-03 21:28 4248
// - RenderCheckMark()
1193b4be Poul Sander 2025-02-03 21:28 4249
// - RenderArrowDockMenu()
1193b4be Poul Sander 2025-02-03 21:28 4250
// - RenderArrowPointingAt()
1193b4be Poul Sander 2025-02-03 21:28 4251
// - RenderRectFilledRangeH()
1193b4be Poul Sander 2025-02-03 21:28 4252
// - RenderRectFilledWithHole()
1193b4be Poul Sander 2025-02-03 21:28 4253
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 4254
// Function in need of a redesign (legacy mess)
1193b4be Poul Sander 2025-02-03 21:28 4255
// - RenderColorRectWithAlphaCheckerboard()
1193b4be Poul Sander 2025-02-03 21:28 4256
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 4257
1193b4be Poul Sander 2025-02-03 21:28 4258
// 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
1193b4be Poul Sander 2025-02-03 21:28 4259
void ImGui::RenderArrow(ImDrawList* draw_list, ImVec2 pos, ImU32 col, ImGuiDir dir, float scale)
1193b4be Poul Sander 2025-02-03 21:28 4260
{
1193b4be Poul Sander 2025-02-03 21:28 4261
    const float h = draw_list->_Data->FontSize * 1.00f;
1193b4be Poul Sander 2025-02-03 21:28 4262
    float r = h * 0.40f * scale;
1193b4be Poul Sander 2025-02-03 21:28 4263
    ImVec2 center = pos + ImVec2(h * 0.50f, h * 0.50f * scale);
1193b4be Poul Sander 2025-02-03 21:28 4264
1193b4be Poul Sander 2025-02-03 21:28 4265
    ImVec2 a, b, c;
1193b4be Poul Sander 2025-02-03 21:28 4266
    switch (dir)
1193b4be Poul Sander 2025-02-03 21:28 4267
    {
1193b4be Poul Sander 2025-02-03 21:28 4268
    case ImGuiDir_Up:
1193b4be Poul Sander 2025-02-03 21:28 4269
    case ImGuiDir_Down:
1193b4be Poul Sander 2025-02-03 21:28 4270
        if (dir == ImGuiDir_Up) r = -r;
1193b4be Poul Sander 2025-02-03 21:28 4271
        a = ImVec2(+0.000f, +0.750f) * r;
1193b4be Poul Sander 2025-02-03 21:28 4272
        b = ImVec2(-0.866f, -0.750f) * r;
1193b4be Poul Sander 2025-02-03 21:28 4273
        c = ImVec2(+0.866f, -0.750f) * r;
1193b4be Poul Sander 2025-02-03 21:28 4274
        break;
1193b4be Poul Sander 2025-02-03 21:28 4275
    case ImGuiDir_Left:
1193b4be Poul Sander 2025-02-03 21:28 4276
    case ImGuiDir_Right:
1193b4be Poul Sander 2025-02-03 21:28 4277
        if (dir == ImGuiDir_Left) r = -r;
1193b4be Poul Sander 2025-02-03 21:28 4278
        a = ImVec2(+0.750f, +0.000f) * r;
1193b4be Poul Sander 2025-02-03 21:28 4279
        b = ImVec2(-0.750f, +0.866f) * r;
1193b4be Poul Sander 2025-02-03 21:28 4280
        c = ImVec2(-0.750f, -0.866f) * r;
1193b4be Poul Sander 2025-02-03 21:28 4281
        break;
1193b4be Poul Sander 2025-02-03 21:28 4282
    case ImGuiDir_None:
1193b4be Poul Sander 2025-02-03 21:28 4283
    case ImGuiDir_COUNT:
1193b4be Poul Sander 2025-02-03 21:28 4284
        IM_ASSERT(0);
1193b4be Poul Sander 2025-02-03 21:28 4285
        break;
1193b4be Poul Sander 2025-02-03 21:28 4286
    }
1193b4be Poul Sander 2025-02-03 21:28 4287
    draw_list->AddTriangleFilled(center + a, center + b, center + c, col);
1193b4be Poul Sander 2025-02-03 21:28 4288
}
1193b4be Poul Sander 2025-02-03 21:28 4289
1193b4be Poul Sander 2025-02-03 21:28 4290
void ImGui::RenderBullet(ImDrawList* draw_list, ImVec2 pos, ImU32 col)
1193b4be Poul Sander 2025-02-03 21:28 4291
{
1193b4be Poul Sander 2025-02-03 21:28 4292
    // FIXME-OPT: This should be baked in font.
1193b4be Poul Sander 2025-02-03 21:28 4293
    draw_list->AddCircleFilled(pos, draw_list->_Data->FontSize * 0.20f, col, 8);
1193b4be Poul Sander 2025-02-03 21:28 4294
}
1193b4be Poul Sander 2025-02-03 21:28 4295
1193b4be Poul Sander 2025-02-03 21:28 4296
void ImGui::RenderCheckMark(ImDrawList* draw_list, ImVec2 pos, ImU32 col, float sz)
1193b4be Poul Sander 2025-02-03 21:28 4297
{
1193b4be Poul Sander 2025-02-03 21:28 4298
    float thickness = ImMax(sz / 5.0f, 1.0f);
1193b4be Poul Sander 2025-02-03 21:28 4299
    sz -= thickness * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 4300
    pos += ImVec2(thickness * 0.25f, thickness * 0.25f);
1193b4be Poul Sander 2025-02-03 21:28 4301
1193b4be Poul Sander 2025-02-03 21:28 4302
    float third = sz / 3.0f;
1193b4be Poul Sander 2025-02-03 21:28 4303
    float bx = pos.x + third;
1193b4be Poul Sander 2025-02-03 21:28 4304
    float by = pos.y + sz - third * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 4305
    draw_list->PathLineTo(ImVec2(bx - third, by - third));
1193b4be Poul Sander 2025-02-03 21:28 4306
    draw_list->PathLineTo(ImVec2(bx, by));
1193b4be Poul Sander 2025-02-03 21:28 4307
    draw_list->PathLineTo(ImVec2(bx + third * 2.0f, by - third * 2.0f));
1193b4be Poul Sander 2025-02-03 21:28 4308
    draw_list->PathStroke(col, 0, thickness);
1193b4be Poul Sander 2025-02-03 21:28 4309
}
1193b4be Poul Sander 2025-02-03 21:28 4310
1193b4be Poul Sander 2025-02-03 21:28 4311
// 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.
1193b4be Poul Sander 2025-02-03 21:28 4312
void ImGui::RenderArrowPointingAt(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col)
1193b4be Poul Sander 2025-02-03 21:28 4313
{
1193b4be Poul Sander 2025-02-03 21:28 4314
    switch (direction)
1193b4be Poul Sander 2025-02-03 21:28 4315
    {
1193b4be Poul Sander 2025-02-03 21:28 4316
    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;
1193b4be Poul Sander 2025-02-03 21:28 4317
    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;
1193b4be Poul Sander 2025-02-03 21:28 4318
    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;
1193b4be Poul Sander 2025-02-03 21:28 4319
    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;
1193b4be Poul Sander 2025-02-03 21:28 4320
    case ImGuiDir_None: case ImGuiDir_COUNT: break; // Fix warnings
1193b4be Poul Sander 2025-02-03 21:28 4321
    }
1193b4be Poul Sander 2025-02-03 21:28 4322
}
1193b4be Poul Sander 2025-02-03 21:28 4323
1193b4be Poul Sander 2025-02-03 21:28 4324
// This is less wide than RenderArrow() and we use in dock nodes instead of the regular RenderArrow() to denote a change of functionality,
1193b4be Poul Sander 2025-02-03 21:28 4325
// and because the saved space means that the left-most tab label can stay at exactly the same position as the label of a loose window.
1193b4be Poul Sander 2025-02-03 21:28 4326
void ImGui::RenderArrowDockMenu(ImDrawList* draw_list, ImVec2 p_min, float sz, ImU32 col)
1193b4be Poul Sander 2025-02-03 21:28 4327
{
1193b4be Poul Sander 2025-02-03 21:28 4328
    draw_list->AddRectFilled(p_min + ImVec2(sz * 0.20f, sz * 0.15f), p_min + ImVec2(sz * 0.80f, sz * 0.30f), col);
1193b4be Poul Sander 2025-02-03 21:28 4329
    RenderArrowPointingAt(draw_list, p_min + ImVec2(sz * 0.50f, sz * 0.85f), ImVec2(sz * 0.30f, sz * 0.40f), ImGuiDir_Down, col);
1193b4be Poul Sander 2025-02-03 21:28 4330
}
1193b4be Poul Sander 2025-02-03 21:28 4331
1193b4be Poul Sander 2025-02-03 21:28 4332
static inline float ImAcos01(float x)
1193b4be Poul Sander 2025-02-03 21:28 4333
{
1193b4be Poul Sander 2025-02-03 21:28 4334
    if (x <= 0.0f) return IM_PI * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 4335
    if (x >= 1.0f) return 0.0f;
1193b4be Poul Sander 2025-02-03 21:28 4336
    return ImAcos(x);
1193b4be Poul Sander 2025-02-03 21:28 4337
    //return (-0.69813170079773212f * x * x - 0.87266462599716477f) * x + 1.5707963267948966f; // Cheap approximation, may be enough for what we do.
1193b4be Poul Sander 2025-02-03 21:28 4338
}
1193b4be Poul Sander 2025-02-03 21:28 4339
1193b4be Poul Sander 2025-02-03 21:28 4340
// FIXME: Cleanup and move code to ImDrawList.
1193b4be Poul Sander 2025-02-03 21:28 4341
void ImGui::RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, ImU32 col, float x_start_norm, float x_end_norm, float rounding)
1193b4be Poul Sander 2025-02-03 21:28 4342
{
1193b4be Poul Sander 2025-02-03 21:28 4343
    if (x_end_norm == x_start_norm)
1193b4be Poul Sander 2025-02-03 21:28 4344
        return;
1193b4be Poul Sander 2025-02-03 21:28 4345
    if (x_start_norm > x_end_norm)
1193b4be Poul Sander 2025-02-03 21:28 4346
        ImSwap(x_start_norm, x_end_norm);
1193b4be Poul Sander 2025-02-03 21:28 4347
1193b4be Poul Sander 2025-02-03 21:28 4348
    ImVec2 p0 = ImVec2(ImLerp(rect.Min.x, rect.Max.x, x_start_norm), rect.Min.y);
1193b4be Poul Sander 2025-02-03 21:28 4349
    ImVec2 p1 = ImVec2(ImLerp(rect.Min.x, rect.Max.x, x_end_norm), rect.Max.y);
1193b4be Poul Sander 2025-02-03 21:28 4350
    if (rounding == 0.0f)
1193b4be Poul Sander 2025-02-03 21:28 4351
    {
1193b4be Poul Sander 2025-02-03 21:28 4352
        draw_list->AddRectFilled(p0, p1, col, 0.0f);
1193b4be Poul Sander 2025-02-03 21:28 4353
        return;
1193b4be Poul Sander 2025-02-03 21:28 4354
    }
1193b4be Poul Sander 2025-02-03 21:28 4355
1193b4be Poul Sander 2025-02-03 21:28 4356
    rounding = ImClamp(ImMin((rect.Max.x - rect.Min.x) * 0.5f, (rect.Max.y - rect.Min.y) * 0.5f) - 1.0f, 0.0f, rounding);
1193b4be Poul Sander 2025-02-03 21:28 4357
    const float inv_rounding = 1.0f / rounding;
1193b4be Poul Sander 2025-02-03 21:28 4358
    const float arc0_b = ImAcos01(1.0f - (p0.x - rect.Min.x) * inv_rounding);
1193b4be Poul Sander 2025-02-03 21:28 4359
    const float arc0_e = ImAcos01(1.0f - (p1.x - rect.Min.x) * inv_rounding);
1193b4be Poul Sander 2025-02-03 21:28 4360
    const float half_pi = IM_PI * 0.5f; // We will == compare to this because we know this is the exact value ImAcos01 can return.
1193b4be Poul Sander 2025-02-03 21:28 4361
    const float x0 = ImMax(p0.x, rect.Min.x + rounding);
1193b4be Poul Sander 2025-02-03 21:28 4362
    if (arc0_b == arc0_e)
1193b4be Poul Sander 2025-02-03 21:28 4363
    {
1193b4be Poul Sander 2025-02-03 21:28 4364
        draw_list->PathLineTo(ImVec2(x0, p1.y));
1193b4be Poul Sander 2025-02-03 21:28 4365
        draw_list->PathLineTo(ImVec2(x0, p0.y));
1193b4be Poul Sander 2025-02-03 21:28 4366
    }
1193b4be Poul Sander 2025-02-03 21:28 4367
    else if (arc0_b == 0.0f && arc0_e == half_pi)
1193b4be Poul Sander 2025-02-03 21:28 4368
    {
1193b4be Poul Sander 2025-02-03 21:28 4369
        draw_list->PathArcToFast(ImVec2(x0, p1.y - rounding), rounding, 3, 6); // BL
1193b4be Poul Sander 2025-02-03 21:28 4370
        draw_list->PathArcToFast(ImVec2(x0, p0.y + rounding), rounding, 6, 9); // TR
1193b4be Poul Sander 2025-02-03 21:28 4371
    }
1193b4be Poul Sander 2025-02-03 21:28 4372
    else
1193b4be Poul Sander 2025-02-03 21:28 4373
    {
1193b4be Poul Sander 2025-02-03 21:28 4374
        draw_list->PathArcTo(ImVec2(x0, p1.y - rounding), rounding, IM_PI - arc0_e, IM_PI - arc0_b); // BL
1193b4be Poul Sander 2025-02-03 21:28 4375
        draw_list->PathArcTo(ImVec2(x0, p0.y + rounding), rounding, IM_PI + arc0_b, IM_PI + arc0_e); // TR
1193b4be Poul Sander 2025-02-03 21:28 4376
    }
1193b4be Poul Sander 2025-02-03 21:28 4377
    if (p1.x > rect.Min.x + rounding)
1193b4be Poul Sander 2025-02-03 21:28 4378
    {
1193b4be Poul Sander 2025-02-03 21:28 4379
        const float arc1_b = ImAcos01(1.0f - (rect.Max.x - p1.x) * inv_rounding);
1193b4be Poul Sander 2025-02-03 21:28 4380
        const float arc1_e = ImAcos01(1.0f - (rect.Max.x - p0.x) * inv_rounding);
1193b4be Poul Sander 2025-02-03 21:28 4381
        const float x1 = ImMin(p1.x, rect.Max.x - rounding);
1193b4be Poul Sander 2025-02-03 21:28 4382
        if (arc1_b == arc1_e)
1193b4be Poul Sander 2025-02-03 21:28 4383
        {
1193b4be Poul Sander 2025-02-03 21:28 4384
            draw_list->PathLineTo(ImVec2(x1, p0.y));
1193b4be Poul Sander 2025-02-03 21:28 4385
            draw_list->PathLineTo(ImVec2(x1, p1.y));
1193b4be Poul Sander 2025-02-03 21:28 4386
        }
1193b4be Poul Sander 2025-02-03 21:28 4387
        else if (arc1_b == 0.0f && arc1_e == half_pi)
1193b4be Poul Sander 2025-02-03 21:28 4388
        {
1193b4be Poul Sander 2025-02-03 21:28 4389
            draw_list->PathArcToFast(ImVec2(x1, p0.y + rounding), rounding, 9, 12); // TR
1193b4be Poul Sander 2025-02-03 21:28 4390
            draw_list->PathArcToFast(ImVec2(x1, p1.y - rounding), rounding, 0, 3);  // BR
1193b4be Poul Sander 2025-02-03 21:28 4391
        }
1193b4be Poul Sander 2025-02-03 21:28 4392
        else
1193b4be Poul Sander 2025-02-03 21:28 4393
        {
1193b4be Poul Sander 2025-02-03 21:28 4394
            draw_list->PathArcTo(ImVec2(x1, p0.y + rounding), rounding, -arc1_e, -arc1_b); // TR
1193b4be Poul Sander 2025-02-03 21:28 4395
            draw_list->PathArcTo(ImVec2(x1, p1.y - rounding), rounding, +arc1_b, +arc1_e); // BR
1193b4be Poul Sander 2025-02-03 21:28 4396
        }
1193b4be Poul Sander 2025-02-03 21:28 4397
    }
1193b4be Poul Sander 2025-02-03 21:28 4398
    draw_list->PathFillConvex(col);
1193b4be Poul Sander 2025-02-03 21:28 4399
}
1193b4be Poul Sander 2025-02-03 21:28 4400
1193b4be Poul Sander 2025-02-03 21:28 4401
void ImGui::RenderRectFilledWithHole(ImDrawList* draw_list, const ImRect& outer, const ImRect& inner, ImU32 col, float rounding)
1193b4be Poul Sander 2025-02-03 21:28 4402
{
1193b4be Poul Sander 2025-02-03 21:28 4403
    const bool fill_L = (inner.Min.x > outer.Min.x);
1193b4be Poul Sander 2025-02-03 21:28 4404
    const bool fill_R = (inner.Max.x < outer.Max.x);
1193b4be Poul Sander 2025-02-03 21:28 4405
    const bool fill_U = (inner.Min.y > outer.Min.y);
1193b4be Poul Sander 2025-02-03 21:28 4406
    const bool fill_D = (inner.Max.y < outer.Max.y);
1193b4be Poul Sander 2025-02-03 21:28 4407
    if (fill_L) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Min.y), ImVec2(inner.Min.x, inner.Max.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_U ? 0 : ImDrawFlags_RoundCornersTopLeft)    | (fill_D ? 0 : ImDrawFlags_RoundCornersBottomLeft));
1193b4be Poul Sander 2025-02-03 21:28 4408
    if (fill_R) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Min.y), ImVec2(outer.Max.x, inner.Max.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_U ? 0 : ImDrawFlags_RoundCornersTopRight)   | (fill_D ? 0 : ImDrawFlags_RoundCornersBottomRight));
1193b4be Poul Sander 2025-02-03 21:28 4409
    if (fill_U) draw_list->AddRectFilled(ImVec2(inner.Min.x, outer.Min.y), ImVec2(inner.Max.x, inner.Min.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_L ? 0 : ImDrawFlags_RoundCornersTopLeft)    | (fill_R ? 0 : ImDrawFlags_RoundCornersTopRight));
1193b4be Poul Sander 2025-02-03 21:28 4410
    if (fill_D) draw_list->AddRectFilled(ImVec2(inner.Min.x, inner.Max.y), ImVec2(inner.Max.x, outer.Max.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_L ? 0 : ImDrawFlags_RoundCornersBottomLeft) | (fill_R ? 0 : ImDrawFlags_RoundCornersBottomRight));
1193b4be Poul Sander 2025-02-03 21:28 4411
    if (fill_L && fill_U) draw_list->AddRectFilled(ImVec2(outer.Min.x, outer.Min.y), ImVec2(inner.Min.x, inner.Min.y), col, rounding, ImDrawFlags_RoundCornersTopLeft);
1193b4be Poul Sander 2025-02-03 21:28 4412
    if (fill_R && fill_U) draw_list->AddRectFilled(ImVec2(inner.Max.x, outer.Min.y), ImVec2(outer.Max.x, inner.Min.y), col, rounding, ImDrawFlags_RoundCornersTopRight);
1193b4be Poul Sander 2025-02-03 21:28 4413
    if (fill_L && fill_D) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Max.y), ImVec2(inner.Min.x, outer.Max.y), col, rounding, ImDrawFlags_RoundCornersBottomLeft);
1193b4be Poul Sander 2025-02-03 21:28 4414
    if (fill_R && fill_D) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Max.y), ImVec2(outer.Max.x, outer.Max.y), col, rounding, ImDrawFlags_RoundCornersBottomRight);
1193b4be Poul Sander 2025-02-03 21:28 4415
}
1193b4be Poul Sander 2025-02-03 21:28 4416
1193b4be Poul Sander 2025-02-03 21:28 4417
ImDrawFlags ImGui::CalcRoundingFlagsForRectInRect(const ImRect& r_in, const ImRect& r_outer, float threshold)
1193b4be Poul Sander 2025-02-03 21:28 4418
{
1193b4be Poul Sander 2025-02-03 21:28 4419
    bool round_l = r_in.Min.x <= r_outer.Min.x + threshold;
1193b4be Poul Sander 2025-02-03 21:28 4420
    bool round_r = r_in.Max.x >= r_outer.Max.x - threshold;
1193b4be Poul Sander 2025-02-03 21:28 4421
    bool round_t = r_in.Min.y <= r_outer.Min.y + threshold;
1193b4be Poul Sander 2025-02-03 21:28 4422
    bool round_b = r_in.Max.y >= r_outer.Max.y - threshold;
1193b4be Poul Sander 2025-02-03 21:28 4423
    return ImDrawFlags_RoundCornersNone
1193b4be Poul Sander 2025-02-03 21:28 4424
        | ((round_t && round_l) ? ImDrawFlags_RoundCornersTopLeft : 0) | ((round_t && round_r) ? ImDrawFlags_RoundCornersTopRight : 0)
1193b4be Poul Sander 2025-02-03 21:28 4425
        | ((round_b && round_l) ? ImDrawFlags_RoundCornersBottomLeft : 0) | ((round_b && round_r) ? ImDrawFlags_RoundCornersBottomRight : 0);
1193b4be Poul Sander 2025-02-03 21:28 4426
}
1193b4be Poul Sander 2025-02-03 21:28 4427
1193b4be Poul Sander 2025-02-03 21:28 4428
// Helper for ColorPicker4()
1193b4be Poul Sander 2025-02-03 21:28 4429
// 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.
1193b4be Poul Sander 2025-02-03 21:28 4430
// 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.
1193b4be Poul Sander 2025-02-03 21:28 4431
// FIXME: uses ImGui::GetColorU32
1193b4be Poul Sander 2025-02-03 21:28 4432
void ImGui::RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p_min, ImVec2 p_max, ImU32 col, float grid_step, ImVec2 grid_off, float rounding, ImDrawFlags flags)
1193b4be Poul Sander 2025-02-03 21:28 4433
{
1193b4be Poul Sander 2025-02-03 21:28 4434
    if ((flags & ImDrawFlags_RoundCornersMask_) == 0)
1193b4be Poul Sander 2025-02-03 21:28 4435
        flags = ImDrawFlags_RoundCornersDefault_;
1193b4be Poul Sander 2025-02-03 21:28 4436
    if (((col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT) < 0xFF)
1193b4be Poul Sander 2025-02-03 21:28 4437
    {
1193b4be Poul Sander 2025-02-03 21:28 4438
        ImU32 col_bg1 = GetColorU32(ImAlphaBlendColors(IM_COL32(204, 204, 204, 255), col));
1193b4be Poul Sander 2025-02-03 21:28 4439
        ImU32 col_bg2 = GetColorU32(ImAlphaBlendColors(IM_COL32(128, 128, 128, 255), col));
1193b4be Poul Sander 2025-02-03 21:28 4440
        draw_list->AddRectFilled(p_min, p_max, col_bg1, rounding, flags);
1193b4be Poul Sander 2025-02-03 21:28 4441
1193b4be Poul Sander 2025-02-03 21:28 4442
        int yi = 0;
1193b4be Poul Sander 2025-02-03 21:28 4443
        for (float y = p_min.y + grid_off.y; y < p_max.y; y += grid_step, yi++)
1193b4be Poul Sander 2025-02-03 21:28 4444
        {
1193b4be Poul Sander 2025-02-03 21:28 4445
            float y1 = ImClamp(y, p_min.y, p_max.y), y2 = ImMin(y + grid_step, p_max.y);
1193b4be Poul Sander 2025-02-03 21:28 4446
            if (y2 <= y1)
1193b4be Poul Sander 2025-02-03 21:28 4447
                continue;
1193b4be Poul Sander 2025-02-03 21:28 4448
            for (float x = p_min.x + grid_off.x + (yi & 1) * grid_step; x < p_max.x; x += grid_step * 2.0f)
1193b4be Poul Sander 2025-02-03 21:28 4449
            {
1193b4be Poul Sander 2025-02-03 21:28 4450
                float x1 = ImClamp(x, p_min.x, p_max.x), x2 = ImMin(x + grid_step, p_max.x);
1193b4be Poul Sander 2025-02-03 21:28 4451
                if (x2 <= x1)
1193b4be Poul Sander 2025-02-03 21:28 4452
                    continue;
1193b4be Poul Sander 2025-02-03 21:28 4453
                ImDrawFlags cell_flags = ImDrawFlags_RoundCornersNone;
1193b4be Poul Sander 2025-02-03 21:28 4454
                if (y1 <= p_min.y) { if (x1 <= p_min.x) cell_flags |= ImDrawFlags_RoundCornersTopLeft; if (x2 >= p_max.x) cell_flags |= ImDrawFlags_RoundCornersTopRight; }
1193b4be Poul Sander 2025-02-03 21:28 4455
                if (y2 >= p_max.y) { if (x1 <= p_min.x) cell_flags |= ImDrawFlags_RoundCornersBottomLeft; if (x2 >= p_max.x) cell_flags |= ImDrawFlags_RoundCornersBottomRight; }
1193b4be Poul Sander 2025-02-03 21:28 4456
1193b4be Poul Sander 2025-02-03 21:28 4457
                // Combine flags
1193b4be Poul Sander 2025-02-03 21:28 4458
                cell_flags = (flags == ImDrawFlags_RoundCornersNone || cell_flags == ImDrawFlags_RoundCornersNone) ? ImDrawFlags_RoundCornersNone : (cell_flags & flags);
1193b4be Poul Sander 2025-02-03 21:28 4459
                draw_list->AddRectFilled(ImVec2(x1, y1), ImVec2(x2, y2), col_bg2, rounding, cell_flags);
1193b4be Poul Sander 2025-02-03 21:28 4460
            }
1193b4be Poul Sander 2025-02-03 21:28 4461
        }
1193b4be Poul Sander 2025-02-03 21:28 4462
    }
1193b4be Poul Sander 2025-02-03 21:28 4463
    else
1193b4be Poul Sander 2025-02-03 21:28 4464
    {
1193b4be Poul Sander 2025-02-03 21:28 4465
        draw_list->AddRectFilled(p_min, p_max, col, rounding, flags);
1193b4be Poul Sander 2025-02-03 21:28 4466
    }
1193b4be Poul Sander 2025-02-03 21:28 4467
}
1193b4be Poul Sander 2025-02-03 21:28 4468
1193b4be Poul Sander 2025-02-03 21:28 4469
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 4470
// [SECTION] Decompression code
1193b4be Poul Sander 2025-02-03 21:28 4471
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 4472
// Compressed with stb_compress() then converted to a C array and encoded as base85.
1193b4be Poul Sander 2025-02-03 21:28 4473
// Use the program in misc/fonts/binary_to_compressed_c.cpp to create the array from a TTF file.
1193b4be Poul Sander 2025-02-03 21:28 4474
// The purpose of encoding as base85 instead of "0x00,0x01,..." style is only save on _source code_ size.
1193b4be Poul Sander 2025-02-03 21:28 4475
// Decompression from stb.h (public domain) by Sean Barrett https://github.com/nothings/stb/blob/master/stb.h
1193b4be Poul Sander 2025-02-03 21:28 4476
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 4477
1193b4be Poul Sander 2025-02-03 21:28 4478
static unsigned int stb_decompress_length(const unsigned char *input)
1193b4be Poul Sander 2025-02-03 21:28 4479
{
1193b4be Poul Sander 2025-02-03 21:28 4480
    return (input[8] << 24) + (input[9] << 16) + (input[10] << 8) + input[11];
1193b4be Poul Sander 2025-02-03 21:28 4481
}
1193b4be Poul Sander 2025-02-03 21:28 4482
1193b4be Poul Sander 2025-02-03 21:28 4483
static unsigned char *stb__barrier_out_e, *stb__barrier_out_b;
1193b4be Poul Sander 2025-02-03 21:28 4484
static const unsigned char *stb__barrier_in_b;
1193b4be Poul Sander 2025-02-03 21:28 4485
static unsigned char *stb__dout;
1193b4be Poul Sander 2025-02-03 21:28 4486
static void stb__match(const unsigned char *data, unsigned int length)
1193b4be Poul Sander 2025-02-03 21:28 4487
{
1193b4be Poul Sander 2025-02-03 21:28 4488
    // INVERSE of memmove... write each byte before copying the next...
1193b4be Poul Sander 2025-02-03 21:28 4489
    IM_ASSERT(stb__dout + length <= stb__barrier_out_e);
1193b4be Poul Sander 2025-02-03 21:28 4490
    if (stb__dout + length > stb__barrier_out_e) { stb__dout += length; return; }
1193b4be Poul Sander 2025-02-03 21:28 4491
    if (data < stb__barrier_out_b) { stb__dout = stb__barrier_out_e+1; return; }
1193b4be Poul Sander 2025-02-03 21:28 4492
    while (length--) *stb__dout++ = *data++;
1193b4be Poul Sander 2025-02-03 21:28 4493
}
1193b4be Poul Sander 2025-02-03 21:28 4494
1193b4be Poul Sander 2025-02-03 21:28 4495
static void stb__lit(const unsigned char *data, unsigned int length)
1193b4be Poul Sander 2025-02-03 21:28 4496
{
1193b4be Poul Sander 2025-02-03 21:28 4497
    IM_ASSERT(stb__dout + length <= stb__barrier_out_e);
1193b4be Poul Sander 2025-02-03 21:28 4498
    if (stb__dout + length > stb__barrier_out_e) { stb__dout += length; return; }
1193b4be Poul Sander 2025-02-03 21:28 4499
    if (data < stb__barrier_in_b) { stb__dout = stb__barrier_out_e+1; return; }
1193b4be Poul Sander 2025-02-03 21:28 4500
    memcpy(stb__dout, data, length);
1193b4be Poul Sander 2025-02-03 21:28 4501
    stb__dout += length;
1193b4be Poul Sander 2025-02-03 21:28 4502
}
1193b4be Poul Sander 2025-02-03 21:28 4503
1193b4be Poul Sander 2025-02-03 21:28 4504
#define stb__in2(x)   ((i[x] << 8) + i[(x)+1])
1193b4be Poul Sander 2025-02-03 21:28 4505
#define stb__in3(x)   ((i[x] << 16) + stb__in2((x)+1))
1193b4be Poul Sander 2025-02-03 21:28 4506
#define stb__in4(x)   ((i[x] << 24) + stb__in3((x)+1))
1193b4be Poul Sander 2025-02-03 21:28 4507
1193b4be Poul Sander 2025-02-03 21:28 4508
static const unsigned char *stb_decompress_token(const unsigned char *i)
1193b4be Poul Sander 2025-02-03 21:28 4509
{
1193b4be Poul Sander 2025-02-03 21:28 4510
    if (*i >= 0x20) { // use fewer if's for cases that expand small
1193b4be Poul Sander 2025-02-03 21:28 4511
        if (*i >= 0x80)       stb__match(stb__dout-i[1]-1, i[0] - 0x80 + 1), i += 2;
1193b4be Poul Sander 2025-02-03 21:28 4512
        else if (*i >= 0x40)  stb__match(stb__dout-(stb__in2(0) - 0x4000 + 1), i[2]+1), i += 3;
1193b4be Poul Sander 2025-02-03 21:28 4513
        else /* *i >= 0x20 */ stb__lit(i+1, i[0] - 0x20 + 1), i += 1 + (i[0] - 0x20 + 1);
1193b4be Poul Sander 2025-02-03 21:28 4514
    } else { // more ifs for cases that expand large, since overhead is amortized
1193b4be Poul Sander 2025-02-03 21:28 4515
        if (*i >= 0x18)       stb__match(stb__dout-(stb__in3(0) - 0x180000 + 1), i[3]+1), i += 4;
1193b4be Poul Sander 2025-02-03 21:28 4516
        else if (*i >= 0x10)  stb__match(stb__dout-(stb__in3(0) - 0x100000 + 1), stb__in2(3)+1), i += 5;
1193b4be Poul Sander 2025-02-03 21:28 4517
        else if (*i >= 0x08)  stb__lit(i+2, stb__in2(0) - 0x0800 + 1), i += 2 + (stb__in2(0) - 0x0800 + 1);
1193b4be Poul Sander 2025-02-03 21:28 4518
        else if (*i == 0x07)  stb__lit(i+3, stb__in2(1) + 1), i += 3 + (stb__in2(1) + 1);
1193b4be Poul Sander 2025-02-03 21:28 4519
        else if (*i == 0x06)  stb__match(stb__dout-(stb__in3(1)+1), i[4]+1), i += 5;
1193b4be Poul Sander 2025-02-03 21:28 4520
        else if (*i == 0x04)  stb__match(stb__dout-(stb__in3(1)+1), stb__in2(4)+1), i += 6;
1193b4be Poul Sander 2025-02-03 21:28 4521
    }
1193b4be Poul Sander 2025-02-03 21:28 4522
    return i;
1193b4be Poul Sander 2025-02-03 21:28 4523
}
1193b4be Poul Sander 2025-02-03 21:28 4524
1193b4be Poul Sander 2025-02-03 21:28 4525
static unsigned int stb_adler32(unsigned int adler32, unsigned char *buffer, unsigned int buflen)
1193b4be Poul Sander 2025-02-03 21:28 4526
{
1193b4be Poul Sander 2025-02-03 21:28 4527
    const unsigned long ADLER_MOD = 65521;
1193b4be Poul Sander 2025-02-03 21:28 4528
    unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16;
1193b4be Poul Sander 2025-02-03 21:28 4529
    unsigned long blocklen = buflen % 5552;
1193b4be Poul Sander 2025-02-03 21:28 4530
1193b4be Poul Sander 2025-02-03 21:28 4531
    unsigned long i;
1193b4be Poul Sander 2025-02-03 21:28 4532
    while (buflen) {
1193b4be Poul Sander 2025-02-03 21:28 4533
        for (i=0; i + 7 < blocklen; i += 8) {
1193b4be Poul Sander 2025-02-03 21:28 4534
            s1 += buffer[0], s2 += s1;
1193b4be Poul Sander 2025-02-03 21:28 4535
            s1 += buffer[1], s2 += s1;
1193b4be Poul Sander 2025-02-03 21:28 4536
            s1 += buffer[2], s2 += s1;
1193b4be Poul Sander 2025-02-03 21:28 4537
            s1 += buffer[3], s2 += s1;
1193b4be Poul Sander 2025-02-03 21:28 4538
            s1 += buffer[4], s2 += s1;
1193b4be Poul Sander 2025-02-03 21:28 4539
            s1 += buffer[5], s2 += s1;
1193b4be Poul Sander 2025-02-03 21:28 4540
            s1 += buffer[6], s2 += s1;
1193b4be Poul Sander 2025-02-03 21:28 4541
            s1 += buffer[7], s2 += s1;
1193b4be Poul Sander 2025-02-03 21:28 4542
1193b4be Poul Sander 2025-02-03 21:28 4543
            buffer += 8;
1193b4be Poul Sander 2025-02-03 21:28 4544
        }
1193b4be Poul Sander 2025-02-03 21:28 4545
1193b4be Poul Sander 2025-02-03 21:28 4546
        for (; i < blocklen; ++i)
1193b4be Poul Sander 2025-02-03 21:28 4547
            s1 += *buffer++, s2 += s1;
1193b4be Poul Sander 2025-02-03 21:28 4548
1193b4be Poul Sander 2025-02-03 21:28 4549
        s1 %= ADLER_MOD, s2 %= ADLER_MOD;
1193b4be Poul Sander 2025-02-03 21:28 4550
        buflen -= blocklen;
1193b4be Poul Sander 2025-02-03 21:28 4551
        blocklen = 5552;
1193b4be Poul Sander 2025-02-03 21:28 4552
    }
1193b4be Poul Sander 2025-02-03 21:28 4553
    return (unsigned int)(s2 << 16) + (unsigned int)s1;
1193b4be Poul Sander 2025-02-03 21:28 4554
}
1193b4be Poul Sander 2025-02-03 21:28 4555
1193b4be Poul Sander 2025-02-03 21:28 4556
static unsigned int stb_decompress(unsigned char *output, const unsigned char *i, unsigned int /*length*/)
1193b4be Poul Sander 2025-02-03 21:28 4557
{
1193b4be Poul Sander 2025-02-03 21:28 4558
    if (stb__in4(0) != 0x57bC0000) return 0;
1193b4be Poul Sander 2025-02-03 21:28 4559
    if (stb__in4(4) != 0)          return 0; // error! stream is > 4GB
1193b4be Poul Sander 2025-02-03 21:28 4560
    const unsigned int olen = stb_decompress_length(i);
1193b4be Poul Sander 2025-02-03 21:28 4561
    stb__barrier_in_b = i;
1193b4be Poul Sander 2025-02-03 21:28 4562
    stb__barrier_out_e = output + olen;
1193b4be Poul Sander 2025-02-03 21:28 4563
    stb__barrier_out_b = output;
1193b4be Poul Sander 2025-02-03 21:28 4564
    i += 16;
1193b4be Poul Sander 2025-02-03 21:28 4565
1193b4be Poul Sander 2025-02-03 21:28 4566
    stb__dout = output;
1193b4be Poul Sander 2025-02-03 21:28 4567
    for (;;) {
1193b4be Poul Sander 2025-02-03 21:28 4568
        const unsigned char *old_i = i;
1193b4be Poul Sander 2025-02-03 21:28 4569
        i = stb_decompress_token(i);
1193b4be Poul Sander 2025-02-03 21:28 4570
        if (i == old_i) {
1193b4be Poul Sander 2025-02-03 21:28 4571
            if (*i == 0x05 && i[1] == 0xfa) {
1193b4be Poul Sander 2025-02-03 21:28 4572
                IM_ASSERT(stb__dout == output + olen);
1193b4be Poul Sander 2025-02-03 21:28 4573
                if (stb__dout != output + olen) return 0;
1193b4be Poul Sander 2025-02-03 21:28 4574
                if (stb_adler32(1, output, olen) != (unsigned int) stb__in4(2))
1193b4be Poul Sander 2025-02-03 21:28 4575
                    return 0;
1193b4be Poul Sander 2025-02-03 21:28 4576
                return olen;
1193b4be Poul Sander 2025-02-03 21:28 4577
            } else {
1193b4be Poul Sander 2025-02-03 21:28 4578
                IM_ASSERT(0); /* NOTREACHED */
1193b4be Poul Sander 2025-02-03 21:28 4579
                return 0;
1193b4be Poul Sander 2025-02-03 21:28 4580
            }
1193b4be Poul Sander 2025-02-03 21:28 4581
        }
1193b4be Poul Sander 2025-02-03 21:28 4582
        IM_ASSERT(stb__dout <= output + olen);
1193b4be Poul Sander 2025-02-03 21:28 4583
        if (stb__dout > output + olen)
1193b4be Poul Sander 2025-02-03 21:28 4584
            return 0;
1193b4be Poul Sander 2025-02-03 21:28 4585
    }
1193b4be Poul Sander 2025-02-03 21:28 4586
}
1193b4be Poul Sander 2025-02-03 21:28 4587
1193b4be Poul Sander 2025-02-03 21:28 4588
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 4589
// [SECTION] Default font data (ProggyClean.ttf)
1193b4be Poul Sander 2025-02-03 21:28 4590
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 4591
// ProggyClean.ttf
1193b4be Poul Sander 2025-02-03 21:28 4592
// Copyright (c) 2004, 2005 Tristan Grimmer
1193b4be Poul Sander 2025-02-03 21:28 4593
// MIT license (see License.txt in http://www.proggyfonts.net/index.php?menu=download)
1193b4be Poul Sander 2025-02-03 21:28 4594
// Download and more information at http://www.proggyfonts.net or http://upperboundsinteractive.com/fonts.php
1193b4be Poul Sander 2025-02-03 21:28 4595
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 4596
// File: 'ProggyClean.ttf' (41208 bytes)
1193b4be Poul Sander 2025-02-03 21:28 4597
// Exported using misc/fonts/binary_to_compressed_c.cpp (with compression + base85 string encoding).
1193b4be Poul Sander 2025-02-03 21:28 4598
// The purpose of encoding as base85 instead of "0x00,0x01,..." style is only save on _source code_ size.
1193b4be Poul Sander 2025-02-03 21:28 4599
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 4600
static const char proggy_clean_ttf_compressed_data_base85[11980 + 1] =
1193b4be Poul Sander 2025-02-03 21:28 4601
    "7])#######hV0qs'/###[),##/l:$#Q6>##5[n42>c-TH`->>#/e>11NNV=Bv(*:.F?uu#(gRU.o0XGH`$vhLG1hxt9?W`#,5LsCp#-i>.r$<$6pD>Lb';9Crc6tgXmKVeU2cD4Eo3R/"
1193b4be Poul Sander 2025-02-03 21:28 4602
    "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#"
1193b4be Poul Sander 2025-02-03 21:28 4603
    "`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"
1193b4be Poul Sander 2025-02-03 21:28 4604
    "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"
1193b4be Poul Sander 2025-02-03 21:28 4605
    "kfimM2J,W-jXS:)r0wK#@Fge$U>`w'N7G#$#fB#$E^$#:9:hk+eOe--6x)F7*E%?76%^GMHePW-Z5l'&GiF#$956:rS?dA#fiK:)Yr+`&#0j@'DbG&#^$PG.Ll+DNa<XCMKEV*N)LN/N"
1193b4be Poul Sander 2025-02-03 21:28 4606
    "*b=%Q6pia-Xg8I$<MR&,VdJe$<(7G;Ckl'&hF;;$<_=X(b.RS%%)###MPBuuE1V:v&cX&#2m#(&cV]`k9OhLMbn%s$G2,B$BfD3X*sp5#l,$R#]x_X1xKX%b5U*[r5iMfUo9U`N99hG)"
1193b4be Poul Sander 2025-02-03 21:28 4607
    "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"
1193b4be Poul Sander 2025-02-03 21:28 4608
    "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."
1193b4be Poul Sander 2025-02-03 21:28 4609
    "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"
1193b4be Poul Sander 2025-02-03 21:28 4610
    "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(,)"
1193b4be Poul Sander 2025-02-03 21:28 4611
    "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#"
1193b4be Poul Sander 2025-02-03 21:28 4612
    "'/###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"
1193b4be Poul Sander 2025-02-03 21:28 4613
    "_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"
1193b4be Poul Sander 2025-02-03 21:28 4614
    "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/"
1193b4be Poul Sander 2025-02-03 21:28 4615
    "/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"
1193b4be Poul Sander 2025-02-03 21:28 4616
    "%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&#"
1193b4be Poul Sander 2025-02-03 21:28 4617
    "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)("
1193b4be Poul Sander 2025-02-03 21:28 4618
    "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"
1193b4be Poul Sander 2025-02-03 21:28 4619
    "o;#2:;%d&#x9v68C5g?ntX0X)pT`;%pB3q7mgGN)3%(P8nTd5L7GeA-GL@+%J3u2:(Yf>et`e;)f#Km8&+DC$I46>#Kr]]u-[=99tts1.qb#q72g1WJO81q+eN'03'eM>&1XxY-caEnO"
1193b4be Poul Sander 2025-02-03 21:28 4620
    "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^-"
1193b4be Poul Sander 2025-02-03 21:28 4621
    "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-"
1193b4be Poul Sander 2025-02-03 21:28 4622
    "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"
1193b4be Poul Sander 2025-02-03 21:28 4623
    "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%"
1193b4be Poul Sander 2025-02-03 21:28 4624
    "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]"
1193b4be Poul Sander 2025-02-03 21:28 4625
    "%(?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"
1193b4be Poul Sander 2025-02-03 21:28 4626
    "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:"
1193b4be Poul Sander 2025-02-03 21:28 4627
    "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("
1193b4be Poul Sander 2025-02-03 21:28 4628
    "$/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<"
1193b4be Poul Sander 2025-02-03 21:28 4629
    "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'?"
1193b4be Poul Sander 2025-02-03 21:28 4630
    "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/;"
1193b4be Poul Sander 2025-02-03 21:28 4631
    ")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"
1193b4be Poul Sander 2025-02-03 21:28 4632
    "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("
1193b4be Poul Sander 2025-02-03 21:28 4633
    "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"
1193b4be Poul Sander 2025-02-03 21:28 4634
    "bIu)'Z,*[>br5fX^:FPAWr-m2KgL<LUN098kTF&#lvo58=/vjDo;.;)Ka*hLR#/k=rKbxuV`>Q_nN6'8uTG&#1T5g)uLv:873UpTLgH+#FgpH'_o1780Ph8KmxQJ8#H72L4@768@Tm&Q"
1193b4be Poul Sander 2025-02-03 21:28 4635
    "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<-"
1193b4be Poul Sander 2025-02-03 21:28 4636
    "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"
1193b4be Poul Sander 2025-02-03 21:28 4637
    "sZ88+dKQ)W6>J%CL<KE>`.d*(B`-n8D9oK<Up]c$X$(,)M8Zt7/[rdkqTgl-0cuGMv'?>-XV1q['-5k'cAZ69e;D_?$ZPP&s^+7])$*$#@QYi9,5P&#9r+$%CE=68>K8r0=dSC%%(@p7"
1193b4be Poul Sander 2025-02-03 21:28 4638
    ".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@@"
1193b4be Poul Sander 2025-02-03 21:28 4639
    "$&)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*"
1193b4be Poul Sander 2025-02-03 21:28 4640
    "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"
1193b4be Poul Sander 2025-02-03 21:28 4641
    "@-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&#"
1193b4be Poul Sander 2025-02-03 21:28 4642
    "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#"
1193b4be Poul Sander 2025-02-03 21:28 4643
    "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"
1193b4be Poul Sander 2025-02-03 21:28 4644
    "d=j.LQf./Ll33+(;q3L-w=8dX$#WF&uIJ@-bfI>%:_i2B5CsR8&9Z&#=mPEnm0f`<&c)QL5uJ#%u%lJj+D-r;BoF&#4DoS97h5g)E#o:&S4weDF,9^Hoe`h*L+_a*NrLW-1pG_&2UdB8"
1193b4be Poul Sander 2025-02-03 21:28 4645
    "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&#"
1193b4be Poul Sander 2025-02-03 21:28 4646
    "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"
1193b4be Poul Sander 2025-02-03 21:28 4647
    ":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+"
1193b4be Poul Sander 2025-02-03 21:28 4648
    "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*"
1193b4be Poul Sander 2025-02-03 21:28 4649
    "$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"
1193b4be Poul Sander 2025-02-03 21:28 4650
    ":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"
1193b4be Poul Sander 2025-02-03 21:28 4651
    "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"
1193b4be Poul Sander 2025-02-03 21:28 4652
    "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"
1193b4be Poul Sander 2025-02-03 21:28 4653
    "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"
1193b4be Poul Sander 2025-02-03 21:28 4654
    ":^#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@&]>"
1193b4be Poul Sander 2025-02-03 21:28 4655
    "_>@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%"
1193b4be Poul Sander 2025-02-03 21:28 4656
    "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;"
1193b4be Poul Sander 2025-02-03 21:28 4657
    "^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:"
1193b4be Poul Sander 2025-02-03 21:28 4658
    "+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%"
1193b4be Poul Sander 2025-02-03 21:28 4659
    "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-"
1193b4be Poul Sander 2025-02-03 21:28 4660
    "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*"
1193b4be Poul Sander 2025-02-03 21:28 4661
    "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"
1193b4be Poul Sander 2025-02-03 21:28 4662
    "8kD2)2fU/M#$e.)T4,_=8hLim[&);?UkK'-x?'(:siIfL<$pFM`i<?%W(mGDHM%>iWP,##P`%/L<eXi:@Z9C.7o=@(pXdAO/NLQ8lPl+HPOQa8wD8=^GlPa8TKI1CjhsCTSLJM'/Wl>-"
1193b4be Poul Sander 2025-02-03 21:28 4663
    "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`"
1193b4be Poul Sander 2025-02-03 21:28 4664
    "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]%/"
1193b4be Poul Sander 2025-02-03 21:28 4665
    "+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"
1193b4be Poul Sander 2025-02-03 21:28 4666
    "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"
1193b4be Poul Sander 2025-02-03 21:28 4667
    "?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"
1193b4be Poul Sander 2025-02-03 21:28 4668
    "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"
1193b4be Poul Sander 2025-02-03 21:28 4669
    ">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'>"
1193b4be Poul Sander 2025-02-03 21:28 4670
    "[%$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"
1193b4be Poul Sander 2025-02-03 21:28 4671
    "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#"
1193b4be Poul Sander 2025-02-03 21:28 4672
    "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$"
1193b4be Poul Sander 2025-02-03 21:28 4673
    "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,)"
1193b4be Poul Sander 2025-02-03 21:28 4674
    "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"
1193b4be Poul Sander 2025-02-03 21:28 4675
    "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"
1193b4be Poul Sander 2025-02-03 21:28 4676
    "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"
1193b4be Poul Sander 2025-02-03 21:28 4677
    "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(#"
1193b4be Poul Sander 2025-02-03 21:28 4678
    ";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&>"
1193b4be Poul Sander 2025-02-03 21:28 4679
    "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#"
1193b4be Poul Sander 2025-02-03 21:28 4680
    "d<F&#*;G##.GY##2Sl##6`($#:l:$#>xL$#B.`$#F:r$#JF.%#NR@%#R_R%#Vke%#Zww%#_-4&#3^Rh%Sflr-k'MS.o?.5/sWel/wpEM0%3'/1)K^f1-d>G21&v(35>V`39V7A4=onx4"
1193b4be Poul Sander 2025-02-03 21:28 4681
    "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#"
1193b4be Poul Sander 2025-02-03 21:28 4682
    "/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-#"
1193b4be Poul Sander 2025-02-03 21:28 4683
    "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#"
1193b4be Poul Sander 2025-02-03 21:28 4684
    "TmD<#%JSMFove:CTBEXI:<eh2g)B,3h2^G3i;#d3jD>)4kMYD4lVu`4m`:&5niUA5@(A5BA1]PBB:xlBCC=2CDLXMCEUtiCf&0g2'tN?PGT4CPGT4CPGT4CPGT4CPGT4CPGT4CPGT4CP"
1193b4be Poul Sander 2025-02-03 21:28 4685
    "GT4CPGT4CPGT4CPGT4CPGT4CPGT4CP-qekC`.9kEg^+F$kwViFJTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5o,^<-28ZI'O?;xp"
1193b4be Poul Sander 2025-02-03 21:28 4686
    "O?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xp;7q-#lLYI:xvD=#";
1193b4be Poul Sander 2025-02-03 21:28 4687
1193b4be Poul Sander 2025-02-03 21:28 4688
static const char* GetDefaultCompressedFontDataTTFBase85()
1193b4be Poul Sander 2025-02-03 21:28 4689
{
1193b4be Poul Sander 2025-02-03 21:28 4690
    return proggy_clean_ttf_compressed_data_base85;
1193b4be Poul Sander 2025-02-03 21:28 4691
}
1193b4be Poul Sander 2025-02-03 21:28 4692
1193b4be Poul Sander 2025-02-03 21:28 4693
#endif // #ifndef IMGUI_DISABLE
1970-01-01 00:00 4694