git repos / blockattack-game

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

normal view · raw

4e9e2555 Poul Sander 2025-10-05 10:15 1
// dear imgui, v1.92.3
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
4e9e2555 Poul Sander 2025-10-05 10:15 16
// [SECTION] ImFontAtlas, ImFontAtlasBuilder
4e9e2555 Poul Sander 2025-10-05 10:15 17
// [SECTION] ImFontAtlas: backend for stb_truetype
4e9e2555 Poul Sander 2025-10-05 10:15 18
// [SECTION] ImFontAtlas: glyph ranges helpers
1193b4be Poul Sander 2025-02-03 21:28 19
// [SECTION] ImFontGlyphRangesBuilder
1193b4be Poul Sander 2025-02-03 21:28 20
// [SECTION] ImFont
1193b4be Poul Sander 2025-02-03 21:28 21
// [SECTION] ImGui Internal Render Helpers
1193b4be Poul Sander 2025-02-03 21:28 22
// [SECTION] Decompression code
1193b4be Poul Sander 2025-02-03 21:28 23
// [SECTION] Default font data (ProggyClean.ttf)
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
1193b4be Poul Sander 2025-02-03 21:28 27
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
1193b4be Poul Sander 2025-02-03 21:28 28
#define _CRT_SECURE_NO_WARNINGS
1193b4be Poul Sander 2025-02-03 21:28 29
#endif
1193b4be Poul Sander 2025-02-03 21:28 30
1193b4be Poul Sander 2025-02-03 21:28 31
#ifndef IMGUI_DEFINE_MATH_OPERATORS
1193b4be Poul Sander 2025-02-03 21:28 32
#define IMGUI_DEFINE_MATH_OPERATORS
1193b4be Poul Sander 2025-02-03 21:28 33
#endif
1193b4be Poul Sander 2025-02-03 21:28 34
1193b4be Poul Sander 2025-02-03 21:28 35
#include "imgui.h"
1193b4be Poul Sander 2025-02-03 21:28 36
#ifndef IMGUI_DISABLE
1193b4be Poul Sander 2025-02-03 21:28 37
#include "imgui_internal.h"
1193b4be Poul Sander 2025-02-03 21:28 38
#ifdef IMGUI_ENABLE_FREETYPE
1193b4be Poul Sander 2025-02-03 21:28 39
#include "misc/freetype/imgui_freetype.h"
1193b4be Poul Sander 2025-02-03 21:28 40
#endif
1193b4be Poul Sander 2025-02-03 21:28 41
1193b4be Poul Sander 2025-02-03 21:28 42
#include <stdio.h>      // vsnprintf, sscanf, printf
4e9e2555 Poul Sander 2025-10-05 10:15 43
#include <stdint.h>     // intptr_t
1193b4be Poul Sander 2025-02-03 21:28 44
1193b4be Poul Sander 2025-02-03 21:28 45
// Visual Studio warnings
1193b4be Poul Sander 2025-02-03 21:28 46
#ifdef _MSC_VER
1193b4be Poul Sander 2025-02-03 21:28 47
#pragma warning (disable: 4127)     // condition expression is constant
1193b4be Poul Sander 2025-02-03 21:28 48
#pragma warning (disable: 4505)     // unreferenced local function has been removed (stb stuff)
1193b4be Poul Sander 2025-02-03 21:28 49
#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 50
#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).
4e9e2555 Poul Sander 2025-10-05 10:15 51
#pragma warning (disable: 26812)    // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3).
1193b4be Poul Sander 2025-02-03 21:28 52
#endif
1193b4be Poul Sander 2025-02-03 21:28 53
1193b4be Poul Sander 2025-02-03 21:28 54
// Clang/GCC warnings with -Weverything
1193b4be Poul Sander 2025-02-03 21:28 55
#if defined(__clang__)
1193b4be Poul Sander 2025-02-03 21:28 56
#if __has_warning("-Wunknown-warning-option")
1193b4be Poul Sander 2025-02-03 21:28 57
#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 58
#endif
1193b4be Poul Sander 2025-02-03 21:28 59
#pragma clang diagnostic ignored "-Wunknown-pragmas"                // warning: unknown warning group 'xxx'
1193b4be Poul Sander 2025-02-03 21:28 60
#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 61
#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 62
#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 63
#pragma clang diagnostic ignored "-Wsign-conversion"                // warning: implicit conversion changes signedness
1193b4be Poul Sander 2025-02-03 21:28 64
#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 65
#pragma clang diagnostic ignored "-Wcomma"                          // warning: possible misuse of comma operator here
1193b4be Poul Sander 2025-02-03 21:28 66
#pragma clang diagnostic ignored "-Wreserved-id-macro"              // warning: macro name is a reserved identifier
1193b4be Poul Sander 2025-02-03 21:28 67
#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 68
#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 69
#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 70
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage"            // warning: 'xxx' is an unsafe pointer used for buffer access
4e9e2555 Poul Sander 2025-10-05 10:15 71
#pragma clang diagnostic ignored "-Wnontrivial-memaccess"           // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type
4e9e2555 Poul Sander 2025-10-05 10:15 72
#pragma clang diagnostic ignored "-Wcast-qual"                      // warning: cast from 'const xxxx *' to 'xxx *' drops const qualifier
4e9e2555 Poul Sander 2025-10-05 10:15 73
#pragma clang diagnostic ignored "-Wswitch-default"                 // warning: 'switch' missing 'default' label
1193b4be Poul Sander 2025-02-03 21:28 74
#elif defined(__GNUC__)
4e9e2555 Poul Sander 2025-10-05 10:15 75
#pragma GCC diagnostic ignored "-Wpragmas"                          // warning: unknown option after '#pragma GCC diagnostic' kind
4e9e2555 Poul Sander 2025-10-05 10:15 76
#pragma GCC diagnostic ignored "-Wunused-function"                  // warning: 'xxxx' defined but not used
4e9e2555 Poul Sander 2025-10-05 10:15 77
#pragma GCC diagnostic ignored "-Wfloat-equal"                      // warning: comparing floating-point with '==' or '!=' is unsafe
4e9e2555 Poul Sander 2025-10-05 10:15 78
#pragma GCC diagnostic ignored "-Wdouble-promotion"                 // warning: implicit conversion from 'float' to 'double' when passing argument to function
4e9e2555 Poul Sander 2025-10-05 10:15 79
#pragma GCC diagnostic ignored "-Wconversion"                       // warning: conversion to 'xxxx' from 'xxxx' may alter its value
4e9e2555 Poul Sander 2025-10-05 10:15 80
#pragma GCC diagnostic ignored "-Wstack-protector"                  // warning: stack protector not protecting local variables: variable length buffer
4e9e2555 Poul Sander 2025-10-05 10:15 81
#pragma GCC diagnostic ignored "-Wstrict-overflow"                  // warning: assuming signed overflow does not occur when simplifying division / ..when changing X +- C1 cmp C2 to X cmp C2 -+ C1
4e9e2555 Poul Sander 2025-10-05 10:15 82
#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
4e9e2555 Poul Sander 2025-10-05 10:15 83
#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 84
#endif
1193b4be Poul Sander 2025-02-03 21:28 85
1193b4be Poul Sander 2025-02-03 21:28 86
//-------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 87
// [SECTION] STB libraries implementation (for stb_truetype and stb_rect_pack)
1193b4be Poul Sander 2025-02-03 21:28 88
//-------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 89
1193b4be Poul Sander 2025-02-03 21:28 90
// Compile time options:
1193b4be Poul Sander 2025-02-03 21:28 91
//#define IMGUI_STB_NAMESPACE           ImStb
1193b4be Poul Sander 2025-02-03 21:28 92
//#define IMGUI_STB_TRUETYPE_FILENAME   "my_folder/stb_truetype.h"
1193b4be Poul Sander 2025-02-03 21:28 93
//#define IMGUI_STB_RECT_PACK_FILENAME  "my_folder/stb_rect_pack.h"
1193b4be Poul Sander 2025-02-03 21:28 94
//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
1193b4be Poul Sander 2025-02-03 21:28 95
//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
1193b4be Poul Sander 2025-02-03 21:28 96
1193b4be Poul Sander 2025-02-03 21:28 97
#ifdef IMGUI_STB_NAMESPACE
1193b4be Poul Sander 2025-02-03 21:28 98
namespace IMGUI_STB_NAMESPACE
1193b4be Poul Sander 2025-02-03 21:28 99
{
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
#ifdef _MSC_VER
1193b4be Poul Sander 2025-02-03 21:28 103
#pragma warning (push)
1193b4be Poul Sander 2025-02-03 21:28 104
#pragma warning (disable: 4456)                             // declaration of 'xx' hides previous local declaration
1193b4be Poul Sander 2025-02-03 21:28 105
#pragma warning (disable: 6011)                             // (stb_rectpack) Dereferencing NULL pointer 'cur->next'.
1193b4be Poul Sander 2025-02-03 21:28 106
#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 107
#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 108
#endif
1193b4be Poul Sander 2025-02-03 21:28 109
1193b4be Poul Sander 2025-02-03 21:28 110
#if defined(__clang__)
1193b4be Poul Sander 2025-02-03 21:28 111
#pragma clang diagnostic push
4e9e2555 Poul Sander 2025-10-05 10:15 112
#pragma clang diagnostic ignored "-Wunused-function"        // warning: 'xxxx' defined but not used
1193b4be Poul Sander 2025-02-03 21:28 113
#pragma clang diagnostic ignored "-Wmissing-prototypes"
1193b4be Poul Sander 2025-02-03 21:28 114
#pragma clang diagnostic ignored "-Wimplicit-fallthrough"
1193b4be Poul Sander 2025-02-03 21:28 115
#endif
1193b4be Poul Sander 2025-02-03 21:28 116
1193b4be Poul Sander 2025-02-03 21:28 117
#if defined(__GNUC__)
1193b4be Poul Sander 2025-02-03 21:28 118
#pragma GCC diagnostic push
1193b4be Poul Sander 2025-02-03 21:28 119
#pragma GCC diagnostic ignored "-Wtype-limits"              // warning: comparison is always true due to limited range of data type [-Wtype-limits]
4e9e2555 Poul Sander 2025-10-05 10:15 120
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"     // warning: this statement may fall through
1193b4be Poul Sander 2025-02-03 21:28 121
#endif
1193b4be Poul Sander 2025-02-03 21:28 122
1193b4be Poul Sander 2025-02-03 21:28 123
#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 124
#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 125
#define STBRP_STATIC
1193b4be Poul Sander 2025-02-03 21:28 126
#define STBRP_ASSERT(x)     do { IM_ASSERT(x); } while (0)
1193b4be Poul Sander 2025-02-03 21:28 127
#define STBRP_SORT          ImQsort
1193b4be Poul Sander 2025-02-03 21:28 128
#define STB_RECT_PACK_IMPLEMENTATION
1193b4be Poul Sander 2025-02-03 21:28 129
#endif
1193b4be Poul Sander 2025-02-03 21:28 130
#ifdef IMGUI_STB_RECT_PACK_FILENAME
1193b4be Poul Sander 2025-02-03 21:28 131
#include IMGUI_STB_RECT_PACK_FILENAME
1193b4be Poul Sander 2025-02-03 21:28 132
#else
1193b4be Poul Sander 2025-02-03 21:28 133
#include "imstb_rectpack.h"
1193b4be Poul Sander 2025-02-03 21:28 134
#endif
1193b4be Poul Sander 2025-02-03 21:28 135
#endif
1193b4be Poul Sander 2025-02-03 21:28 136
1193b4be Poul Sander 2025-02-03 21:28 137
#ifdef  IMGUI_ENABLE_STB_TRUETYPE
1193b4be Poul Sander 2025-02-03 21:28 138
#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 139
#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 140
#define STBTT_malloc(x,u)   ((void)(u), IM_ALLOC(x))
1193b4be Poul Sander 2025-02-03 21:28 141
#define STBTT_free(x,u)     ((void)(u), IM_FREE(x))
1193b4be Poul Sander 2025-02-03 21:28 142
#define STBTT_assert(x)     do { IM_ASSERT(x); } while(0)
1193b4be Poul Sander 2025-02-03 21:28 143
#define STBTT_fmod(x,y)     ImFmod(x,y)
1193b4be Poul Sander 2025-02-03 21:28 144
#define STBTT_sqrt(x)       ImSqrt(x)
1193b4be Poul Sander 2025-02-03 21:28 145
#define STBTT_pow(x,y)      ImPow(x,y)
1193b4be Poul Sander 2025-02-03 21:28 146
#define STBTT_fabs(x)       ImFabs(x)
1193b4be Poul Sander 2025-02-03 21:28 147
#define STBTT_ifloor(x)     ((int)ImFloor(x))
1193b4be Poul Sander 2025-02-03 21:28 148
#define STBTT_iceil(x)      ((int)ImCeil(x))
4e9e2555 Poul Sander 2025-10-05 10:15 149
#define STBTT_strlen(x)     ImStrlen(x)
1193b4be Poul Sander 2025-02-03 21:28 150
#define STBTT_STATIC
1193b4be Poul Sander 2025-02-03 21:28 151
#define STB_TRUETYPE_IMPLEMENTATION
1193b4be Poul Sander 2025-02-03 21:28 152
#else
1193b4be Poul Sander 2025-02-03 21:28 153
#define STBTT_DEF extern
1193b4be Poul Sander 2025-02-03 21:28 154
#endif
1193b4be Poul Sander 2025-02-03 21:28 155
#ifdef IMGUI_STB_TRUETYPE_FILENAME
1193b4be Poul Sander 2025-02-03 21:28 156
#include IMGUI_STB_TRUETYPE_FILENAME
1193b4be Poul Sander 2025-02-03 21:28 157
#else
1193b4be Poul Sander 2025-02-03 21:28 158
#include "imstb_truetype.h"
1193b4be Poul Sander 2025-02-03 21:28 159
#endif
1193b4be Poul Sander 2025-02-03 21:28 160
#endif
1193b4be Poul Sander 2025-02-03 21:28 161
#endif // IMGUI_ENABLE_STB_TRUETYPE
1193b4be Poul Sander 2025-02-03 21:28 162
1193b4be Poul Sander 2025-02-03 21:28 163
#if defined(__GNUC__)
1193b4be Poul Sander 2025-02-03 21:28 164
#pragma GCC diagnostic 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
#if defined(__clang__)
1193b4be Poul Sander 2025-02-03 21:28 168
#pragma clang diagnostic pop
1193b4be Poul Sander 2025-02-03 21:28 169
#endif
1193b4be Poul Sander 2025-02-03 21:28 170
1193b4be Poul Sander 2025-02-03 21:28 171
#if defined(_MSC_VER)
1193b4be Poul Sander 2025-02-03 21:28 172
#pragma warning (pop)
1193b4be Poul Sander 2025-02-03 21:28 173
#endif
1193b4be Poul Sander 2025-02-03 21:28 174
1193b4be Poul Sander 2025-02-03 21:28 175
#ifdef IMGUI_STB_NAMESPACE
1193b4be Poul Sander 2025-02-03 21:28 176
} // namespace ImStb
1193b4be Poul Sander 2025-02-03 21:28 177
using namespace IMGUI_STB_NAMESPACE;
1193b4be Poul Sander 2025-02-03 21:28 178
#endif
1193b4be Poul Sander 2025-02-03 21:28 179
1193b4be Poul Sander 2025-02-03 21:28 180
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 181
// [SECTION] Style functions
1193b4be Poul Sander 2025-02-03 21:28 182
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 183
1193b4be Poul Sander 2025-02-03 21:28 184
void ImGui::StyleColorsDark(ImGuiStyle* dst)
1193b4be Poul Sander 2025-02-03 21:28 185
{
1193b4be Poul Sander 2025-02-03 21:28 186
    ImGuiStyle* style = dst ? dst : &ImGui::GetStyle();
1193b4be Poul Sander 2025-02-03 21:28 187
    ImVec4* colors = style->Colors;
1193b4be Poul Sander 2025-02-03 21:28 188
1193b4be Poul Sander 2025-02-03 21:28 189
    colors[ImGuiCol_Text]                   = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 190
    colors[ImGuiCol_TextDisabled]           = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 191
    colors[ImGuiCol_WindowBg]               = ImVec4(0.06f, 0.06f, 0.06f, 0.94f);
1193b4be Poul Sander 2025-02-03 21:28 192
    colors[ImGuiCol_ChildBg]                = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
1193b4be Poul Sander 2025-02-03 21:28 193
    colors[ImGuiCol_PopupBg]                = ImVec4(0.08f, 0.08f, 0.08f, 0.94f);
1193b4be Poul Sander 2025-02-03 21:28 194
    colors[ImGuiCol_Border]                 = ImVec4(0.43f, 0.43f, 0.50f, 0.50f);
1193b4be Poul Sander 2025-02-03 21:28 195
    colors[ImGuiCol_BorderShadow]           = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
1193b4be Poul Sander 2025-02-03 21:28 196
    colors[ImGuiCol_FrameBg]                = ImVec4(0.16f, 0.29f, 0.48f, 0.54f);
1193b4be Poul Sander 2025-02-03 21:28 197
    colors[ImGuiCol_FrameBgHovered]         = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);
1193b4be Poul Sander 2025-02-03 21:28 198
    colors[ImGuiCol_FrameBgActive]          = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
1193b4be Poul Sander 2025-02-03 21:28 199
    colors[ImGuiCol_TitleBg]                = ImVec4(0.04f, 0.04f, 0.04f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 200
    colors[ImGuiCol_TitleBgActive]          = ImVec4(0.16f, 0.29f, 0.48f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 201
    colors[ImGuiCol_TitleBgCollapsed]       = ImVec4(0.00f, 0.00f, 0.00f, 0.51f);
1193b4be Poul Sander 2025-02-03 21:28 202
    colors[ImGuiCol_MenuBarBg]              = ImVec4(0.14f, 0.14f, 0.14f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 203
    colors[ImGuiCol_ScrollbarBg]            = ImVec4(0.02f, 0.02f, 0.02f, 0.53f);
1193b4be Poul Sander 2025-02-03 21:28 204
    colors[ImGuiCol_ScrollbarGrab]          = ImVec4(0.31f, 0.31f, 0.31f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 205
    colors[ImGuiCol_ScrollbarGrabHovered]   = ImVec4(0.41f, 0.41f, 0.41f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 206
    colors[ImGuiCol_ScrollbarGrabActive]    = ImVec4(0.51f, 0.51f, 0.51f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 207
    colors[ImGuiCol_CheckMark]              = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 208
    colors[ImGuiCol_SliderGrab]             = ImVec4(0.24f, 0.52f, 0.88f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 209
    colors[ImGuiCol_SliderGrabActive]       = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 210
    colors[ImGuiCol_Button]                 = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);
1193b4be Poul Sander 2025-02-03 21:28 211
    colors[ImGuiCol_ButtonHovered]          = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 212
    colors[ImGuiCol_ButtonActive]           = ImVec4(0.06f, 0.53f, 0.98f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 213
    colors[ImGuiCol_Header]                 = ImVec4(0.26f, 0.59f, 0.98f, 0.31f);
1193b4be Poul Sander 2025-02-03 21:28 214
    colors[ImGuiCol_HeaderHovered]          = ImVec4(0.26f, 0.59f, 0.98f, 0.80f);
1193b4be Poul Sander 2025-02-03 21:28 215
    colors[ImGuiCol_HeaderActive]           = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 216
    colors[ImGuiCol_Separator]              = colors[ImGuiCol_Border];
1193b4be Poul Sander 2025-02-03 21:28 217
    colors[ImGuiCol_SeparatorHovered]       = ImVec4(0.10f, 0.40f, 0.75f, 0.78f);
1193b4be Poul Sander 2025-02-03 21:28 218
    colors[ImGuiCol_SeparatorActive]        = ImVec4(0.10f, 0.40f, 0.75f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 219
    colors[ImGuiCol_ResizeGrip]             = ImVec4(0.26f, 0.59f, 0.98f, 0.20f);
1193b4be Poul Sander 2025-02-03 21:28 220
    colors[ImGuiCol_ResizeGripHovered]      = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
1193b4be Poul Sander 2025-02-03 21:28 221
    colors[ImGuiCol_ResizeGripActive]       = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
4e9e2555 Poul Sander 2025-10-05 10:15 222
    colors[ImGuiCol_InputTextCursor]        = colors[ImGuiCol_Text];
1193b4be Poul Sander 2025-02-03 21:28 223
    colors[ImGuiCol_TabHovered]             = colors[ImGuiCol_HeaderHovered];
1193b4be Poul Sander 2025-02-03 21:28 224
    colors[ImGuiCol_Tab]                    = ImLerp(colors[ImGuiCol_Header],       colors[ImGuiCol_TitleBgActive], 0.80f);
1193b4be Poul Sander 2025-02-03 21:28 225
    colors[ImGuiCol_TabSelected]            = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
1193b4be Poul Sander 2025-02-03 21:28 226
    colors[ImGuiCol_TabSelectedOverline]    = colors[ImGuiCol_HeaderActive];
1193b4be Poul Sander 2025-02-03 21:28 227
    colors[ImGuiCol_TabDimmed]              = ImLerp(colors[ImGuiCol_Tab],          colors[ImGuiCol_TitleBg], 0.80f);
1193b4be Poul Sander 2025-02-03 21:28 228
    colors[ImGuiCol_TabDimmedSelected]      = ImLerp(colors[ImGuiCol_TabSelected],  colors[ImGuiCol_TitleBg], 0.40f);
4e9e2555 Poul Sander 2025-10-05 10:15 229
    colors[ImGuiCol_TabDimmedSelectedOverline] = ImVec4(0.50f, 0.50f, 0.50f, 0.00f);
1193b4be Poul Sander 2025-02-03 21:28 230
    colors[ImGuiCol_DockingPreview]         = colors[ImGuiCol_HeaderActive] * ImVec4(1.0f, 1.0f, 1.0f, 0.7f);
1193b4be Poul Sander 2025-02-03 21:28 231
    colors[ImGuiCol_DockingEmptyBg]         = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 232
    colors[ImGuiCol_PlotLines]              = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 233
    colors[ImGuiCol_PlotLinesHovered]       = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 234
    colors[ImGuiCol_PlotHistogram]          = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 235
    colors[ImGuiCol_PlotHistogramHovered]   = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 236
    colors[ImGuiCol_TableHeaderBg]          = ImVec4(0.19f, 0.19f, 0.20f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 237
    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 238
    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 239
    colors[ImGuiCol_TableRowBg]             = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
1193b4be Poul Sander 2025-02-03 21:28 240
    colors[ImGuiCol_TableRowBgAlt]          = ImVec4(1.00f, 1.00f, 1.00f, 0.06f);
1193b4be Poul Sander 2025-02-03 21:28 241
    colors[ImGuiCol_TextLink]               = colors[ImGuiCol_HeaderActive];
1193b4be Poul Sander 2025-02-03 21:28 242
    colors[ImGuiCol_TextSelectedBg]         = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
4e9e2555 Poul Sander 2025-10-05 10:15 243
    colors[ImGuiCol_TreeLines]              = colors[ImGuiCol_Border];
1193b4be Poul Sander 2025-02-03 21:28 244
    colors[ImGuiCol_DragDropTarget]         = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
1193b4be Poul Sander 2025-02-03 21:28 245
    colors[ImGuiCol_NavCursor]              = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 246
    colors[ImGuiCol_NavWindowingHighlight]  = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);
1193b4be Poul Sander 2025-02-03 21:28 247
    colors[ImGuiCol_NavWindowingDimBg]      = ImVec4(0.80f, 0.80f, 0.80f, 0.20f);
1193b4be Poul Sander 2025-02-03 21:28 248
    colors[ImGuiCol_ModalWindowDimBg]       = ImVec4(0.80f, 0.80f, 0.80f, 0.35f);
1193b4be Poul Sander 2025-02-03 21:28 249
}
1193b4be Poul Sander 2025-02-03 21:28 250
1193b4be Poul Sander 2025-02-03 21:28 251
void ImGui::StyleColorsClassic(ImGuiStyle* dst)
1193b4be Poul Sander 2025-02-03 21:28 252
{
1193b4be Poul Sander 2025-02-03 21:28 253
    ImGuiStyle* style = dst ? dst : &ImGui::GetStyle();
1193b4be Poul Sander 2025-02-03 21:28 254
    ImVec4* colors = style->Colors;
1193b4be Poul Sander 2025-02-03 21:28 255
1193b4be Poul Sander 2025-02-03 21:28 256
    colors[ImGuiCol_Text]                   = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 257
    colors[ImGuiCol_TextDisabled]           = ImVec4(0.60f, 0.60f, 0.60f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 258
    colors[ImGuiCol_WindowBg]               = ImVec4(0.00f, 0.00f, 0.00f, 0.85f);
1193b4be Poul Sander 2025-02-03 21:28 259
    colors[ImGuiCol_ChildBg]                = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
1193b4be Poul Sander 2025-02-03 21:28 260
    colors[ImGuiCol_PopupBg]                = ImVec4(0.11f, 0.11f, 0.14f, 0.92f);
1193b4be Poul Sander 2025-02-03 21:28 261
    colors[ImGuiCol_Border]                 = ImVec4(0.50f, 0.50f, 0.50f, 0.50f);
1193b4be Poul Sander 2025-02-03 21:28 262
    colors[ImGuiCol_BorderShadow]           = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
1193b4be Poul Sander 2025-02-03 21:28 263
    colors[ImGuiCol_FrameBg]                = ImVec4(0.43f, 0.43f, 0.43f, 0.39f);
1193b4be Poul Sander 2025-02-03 21:28 264
    colors[ImGuiCol_FrameBgHovered]         = ImVec4(0.47f, 0.47f, 0.69f, 0.40f);
1193b4be Poul Sander 2025-02-03 21:28 265
    colors[ImGuiCol_FrameBgActive]          = ImVec4(0.42f, 0.41f, 0.64f, 0.69f);
1193b4be Poul Sander 2025-02-03 21:28 266
    colors[ImGuiCol_TitleBg]                = ImVec4(0.27f, 0.27f, 0.54f, 0.83f);
1193b4be Poul Sander 2025-02-03 21:28 267
    colors[ImGuiCol_TitleBgActive]          = ImVec4(0.32f, 0.32f, 0.63f, 0.87f);
1193b4be Poul Sander 2025-02-03 21:28 268
    colors[ImGuiCol_TitleBgCollapsed]       = ImVec4(0.40f, 0.40f, 0.80f, 0.20f);
1193b4be Poul Sander 2025-02-03 21:28 269
    colors[ImGuiCol_MenuBarBg]              = ImVec4(0.40f, 0.40f, 0.55f, 0.80f);
1193b4be Poul Sander 2025-02-03 21:28 270
    colors[ImGuiCol_ScrollbarBg]            = ImVec4(0.20f, 0.25f, 0.30f, 0.60f);
1193b4be Poul Sander 2025-02-03 21:28 271
    colors[ImGuiCol_ScrollbarGrab]          = ImVec4(0.40f, 0.40f, 0.80f, 0.30f);
1193b4be Poul Sander 2025-02-03 21:28 272
    colors[ImGuiCol_ScrollbarGrabHovered]   = ImVec4(0.40f, 0.40f, 0.80f, 0.40f);
1193b4be Poul Sander 2025-02-03 21:28 273
    colors[ImGuiCol_ScrollbarGrabActive]    = ImVec4(0.41f, 0.39f, 0.80f, 0.60f);
1193b4be Poul Sander 2025-02-03 21:28 274
    colors[ImGuiCol_CheckMark]              = ImVec4(0.90f, 0.90f, 0.90f, 0.50f);
1193b4be Poul Sander 2025-02-03 21:28 275
    colors[ImGuiCol_SliderGrab]             = ImVec4(1.00f, 1.00f, 1.00f, 0.30f);
1193b4be Poul Sander 2025-02-03 21:28 276
    colors[ImGuiCol_SliderGrabActive]       = ImVec4(0.41f, 0.39f, 0.80f, 0.60f);
1193b4be Poul Sander 2025-02-03 21:28 277
    colors[ImGuiCol_Button]                 = ImVec4(0.35f, 0.40f, 0.61f, 0.62f);
1193b4be Poul Sander 2025-02-03 21:28 278
    colors[ImGuiCol_ButtonHovered]          = ImVec4(0.40f, 0.48f, 0.71f, 0.79f);
1193b4be Poul Sander 2025-02-03 21:28 279
    colors[ImGuiCol_ButtonActive]           = ImVec4(0.46f, 0.54f, 0.80f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 280
    colors[ImGuiCol_Header]                 = ImVec4(0.40f, 0.40f, 0.90f, 0.45f);
1193b4be Poul Sander 2025-02-03 21:28 281
    colors[ImGuiCol_HeaderHovered]          = ImVec4(0.45f, 0.45f, 0.90f, 0.80f);
1193b4be Poul Sander 2025-02-03 21:28 282
    colors[ImGuiCol_HeaderActive]           = ImVec4(0.53f, 0.53f, 0.87f, 0.80f);
1193b4be Poul Sander 2025-02-03 21:28 283
    colors[ImGuiCol_Separator]              = ImVec4(0.50f, 0.50f, 0.50f, 0.60f);
1193b4be Poul Sander 2025-02-03 21:28 284
    colors[ImGuiCol_SeparatorHovered]       = ImVec4(0.60f, 0.60f, 0.70f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 285
    colors[ImGuiCol_SeparatorActive]        = ImVec4(0.70f, 0.70f, 0.90f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 286
    colors[ImGuiCol_ResizeGrip]             = ImVec4(1.00f, 1.00f, 1.00f, 0.10f);
1193b4be Poul Sander 2025-02-03 21:28 287
    colors[ImGuiCol_ResizeGripHovered]      = ImVec4(0.78f, 0.82f, 1.00f, 0.60f);
1193b4be Poul Sander 2025-02-03 21:28 288
    colors[ImGuiCol_ResizeGripActive]       = ImVec4(0.78f, 0.82f, 1.00f, 0.90f);
4e9e2555 Poul Sander 2025-10-05 10:15 289
    colors[ImGuiCol_InputTextCursor]        = colors[ImGuiCol_Text];
1193b4be Poul Sander 2025-02-03 21:28 290
    colors[ImGuiCol_TabHovered]             = colors[ImGuiCol_HeaderHovered];
1193b4be Poul Sander 2025-02-03 21:28 291
    colors[ImGuiCol_Tab]                    = ImLerp(colors[ImGuiCol_Header],       colors[ImGuiCol_TitleBgActive], 0.80f);
1193b4be Poul Sander 2025-02-03 21:28 292
    colors[ImGuiCol_TabSelected]            = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
1193b4be Poul Sander 2025-02-03 21:28 293
    colors[ImGuiCol_TabSelectedOverline]    = colors[ImGuiCol_HeaderActive];
1193b4be Poul Sander 2025-02-03 21:28 294
    colors[ImGuiCol_TabDimmed]              = ImLerp(colors[ImGuiCol_Tab],          colors[ImGuiCol_TitleBg], 0.80f);
1193b4be Poul Sander 2025-02-03 21:28 295
    colors[ImGuiCol_TabDimmedSelected]      = ImLerp(colors[ImGuiCol_TabSelected],  colors[ImGuiCol_TitleBg], 0.40f);
4e9e2555 Poul Sander 2025-10-05 10:15 296
    colors[ImGuiCol_TabDimmedSelectedOverline] = ImVec4(0.53f, 0.53f, 0.87f, 0.00f);
1193b4be Poul Sander 2025-02-03 21:28 297
    colors[ImGuiCol_DockingPreview]         = colors[ImGuiCol_Header] * ImVec4(1.0f, 1.0f, 1.0f, 0.7f);
1193b4be Poul Sander 2025-02-03 21:28 298
    colors[ImGuiCol_DockingEmptyBg]         = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 299
    colors[ImGuiCol_PlotLines]              = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 300
    colors[ImGuiCol_PlotLinesHovered]       = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 301
    colors[ImGuiCol_PlotHistogram]          = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 302
    colors[ImGuiCol_PlotHistogramHovered]   = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 303
    colors[ImGuiCol_TableHeaderBg]          = ImVec4(0.27f, 0.27f, 0.38f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 304
    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 305
    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 306
    colors[ImGuiCol_TableRowBg]             = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
1193b4be Poul Sander 2025-02-03 21:28 307
    colors[ImGuiCol_TableRowBgAlt]          = ImVec4(1.00f, 1.00f, 1.00f, 0.07f);
1193b4be Poul Sander 2025-02-03 21:28 308
    colors[ImGuiCol_TextLink]               = colors[ImGuiCol_HeaderActive];
1193b4be Poul Sander 2025-02-03 21:28 309
    colors[ImGuiCol_TextSelectedBg]         = ImVec4(0.00f, 0.00f, 1.00f, 0.35f);
4e9e2555 Poul Sander 2025-10-05 10:15 310
    colors[ImGuiCol_TreeLines]              = colors[ImGuiCol_Border];
1193b4be Poul Sander 2025-02-03 21:28 311
    colors[ImGuiCol_DragDropTarget]         = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
1193b4be Poul Sander 2025-02-03 21:28 312
    colors[ImGuiCol_NavCursor]              = colors[ImGuiCol_HeaderHovered];
1193b4be Poul Sander 2025-02-03 21:28 313
    colors[ImGuiCol_NavWindowingHighlight]  = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);
1193b4be Poul Sander 2025-02-03 21:28 314
    colors[ImGuiCol_NavWindowingDimBg]      = ImVec4(0.80f, 0.80f, 0.80f, 0.20f);
1193b4be Poul Sander 2025-02-03 21:28 315
    colors[ImGuiCol_ModalWindowDimBg]       = ImVec4(0.20f, 0.20f, 0.20f, 0.35f);
1193b4be Poul Sander 2025-02-03 21:28 316
}
1193b4be Poul Sander 2025-02-03 21:28 317
1193b4be Poul Sander 2025-02-03 21:28 318
// Those light colors are better suited with a thicker font than the default one + FrameBorder
1193b4be Poul Sander 2025-02-03 21:28 319
void ImGui::StyleColorsLight(ImGuiStyle* dst)
1193b4be Poul Sander 2025-02-03 21:28 320
{
1193b4be Poul Sander 2025-02-03 21:28 321
    ImGuiStyle* style = dst ? dst : &ImGui::GetStyle();
1193b4be Poul Sander 2025-02-03 21:28 322
    ImVec4* colors = style->Colors;
1193b4be Poul Sander 2025-02-03 21:28 323
1193b4be Poul Sander 2025-02-03 21:28 324
    colors[ImGuiCol_Text]                   = ImVec4(0.00f, 0.00f, 0.00f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 325
    colors[ImGuiCol_TextDisabled]           = ImVec4(0.60f, 0.60f, 0.60f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 326
    colors[ImGuiCol_WindowBg]               = ImVec4(0.94f, 0.94f, 0.94f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 327
    colors[ImGuiCol_ChildBg]                = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
1193b4be Poul Sander 2025-02-03 21:28 328
    colors[ImGuiCol_PopupBg]                = ImVec4(1.00f, 1.00f, 1.00f, 0.98f);
1193b4be Poul Sander 2025-02-03 21:28 329
    colors[ImGuiCol_Border]                 = ImVec4(0.00f, 0.00f, 0.00f, 0.30f);
1193b4be Poul Sander 2025-02-03 21:28 330
    colors[ImGuiCol_BorderShadow]           = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
1193b4be Poul Sander 2025-02-03 21:28 331
    colors[ImGuiCol_FrameBg]                = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 332
    colors[ImGuiCol_FrameBgHovered]         = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);
1193b4be Poul Sander 2025-02-03 21:28 333
    colors[ImGuiCol_FrameBgActive]          = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
1193b4be Poul Sander 2025-02-03 21:28 334
    colors[ImGuiCol_TitleBg]                = ImVec4(0.96f, 0.96f, 0.96f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 335
    colors[ImGuiCol_TitleBgActive]          = ImVec4(0.82f, 0.82f, 0.82f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 336
    colors[ImGuiCol_TitleBgCollapsed]       = ImVec4(1.00f, 1.00f, 1.00f, 0.51f);
1193b4be Poul Sander 2025-02-03 21:28 337
    colors[ImGuiCol_MenuBarBg]              = ImVec4(0.86f, 0.86f, 0.86f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 338
    colors[ImGuiCol_ScrollbarBg]            = ImVec4(0.98f, 0.98f, 0.98f, 0.53f);
1193b4be Poul Sander 2025-02-03 21:28 339
    colors[ImGuiCol_ScrollbarGrab]          = ImVec4(0.69f, 0.69f, 0.69f, 0.80f);
1193b4be Poul Sander 2025-02-03 21:28 340
    colors[ImGuiCol_ScrollbarGrabHovered]   = ImVec4(0.49f, 0.49f, 0.49f, 0.80f);
1193b4be Poul Sander 2025-02-03 21:28 341
    colors[ImGuiCol_ScrollbarGrabActive]    = ImVec4(0.49f, 0.49f, 0.49f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 342
    colors[ImGuiCol_CheckMark]              = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 343
    colors[ImGuiCol_SliderGrab]             = ImVec4(0.26f, 0.59f, 0.98f, 0.78f);
1193b4be Poul Sander 2025-02-03 21:28 344
    colors[ImGuiCol_SliderGrabActive]       = ImVec4(0.46f, 0.54f, 0.80f, 0.60f);
1193b4be Poul Sander 2025-02-03 21:28 345
    colors[ImGuiCol_Button]                 = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);
1193b4be Poul Sander 2025-02-03 21:28 346
    colors[ImGuiCol_ButtonHovered]          = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 347
    colors[ImGuiCol_ButtonActive]           = ImVec4(0.06f, 0.53f, 0.98f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 348
    colors[ImGuiCol_Header]                 = ImVec4(0.26f, 0.59f, 0.98f, 0.31f);
1193b4be Poul Sander 2025-02-03 21:28 349
    colors[ImGuiCol_HeaderHovered]          = ImVec4(0.26f, 0.59f, 0.98f, 0.80f);
1193b4be Poul Sander 2025-02-03 21:28 350
    colors[ImGuiCol_HeaderActive]           = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 351
    colors[ImGuiCol_Separator]              = ImVec4(0.39f, 0.39f, 0.39f, 0.62f);
1193b4be Poul Sander 2025-02-03 21:28 352
    colors[ImGuiCol_SeparatorHovered]       = ImVec4(0.14f, 0.44f, 0.80f, 0.78f);
1193b4be Poul Sander 2025-02-03 21:28 353
    colors[ImGuiCol_SeparatorActive]        = ImVec4(0.14f, 0.44f, 0.80f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 354
    colors[ImGuiCol_ResizeGrip]             = ImVec4(0.35f, 0.35f, 0.35f, 0.17f);
1193b4be Poul Sander 2025-02-03 21:28 355
    colors[ImGuiCol_ResizeGripHovered]      = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
1193b4be Poul Sander 2025-02-03 21:28 356
    colors[ImGuiCol_ResizeGripActive]       = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
4e9e2555 Poul Sander 2025-10-05 10:15 357
    colors[ImGuiCol_InputTextCursor]        = colors[ImGuiCol_Text];
1193b4be Poul Sander 2025-02-03 21:28 358
    colors[ImGuiCol_TabHovered]             = colors[ImGuiCol_HeaderHovered];
1193b4be Poul Sander 2025-02-03 21:28 359
    colors[ImGuiCol_Tab]                    = ImLerp(colors[ImGuiCol_Header],       colors[ImGuiCol_TitleBgActive], 0.90f);
1193b4be Poul Sander 2025-02-03 21:28 360
    colors[ImGuiCol_TabSelected]            = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
1193b4be Poul Sander 2025-02-03 21:28 361
    colors[ImGuiCol_TabSelectedOverline]    = colors[ImGuiCol_HeaderActive];
1193b4be Poul Sander 2025-02-03 21:28 362
    colors[ImGuiCol_TabDimmed]              = ImLerp(colors[ImGuiCol_Tab],          colors[ImGuiCol_TitleBg], 0.80f);
1193b4be Poul Sander 2025-02-03 21:28 363
    colors[ImGuiCol_TabDimmedSelected]      = ImLerp(colors[ImGuiCol_TabSelected],  colors[ImGuiCol_TitleBg], 0.40f);
4e9e2555 Poul Sander 2025-10-05 10:15 364
    colors[ImGuiCol_TabDimmedSelectedOverline] = ImVec4(0.26f, 0.59f, 1.00f, 0.00f);
1193b4be Poul Sander 2025-02-03 21:28 365
    colors[ImGuiCol_DockingPreview]         = colors[ImGuiCol_Header] * ImVec4(1.0f, 1.0f, 1.0f, 0.7f);
1193b4be Poul Sander 2025-02-03 21:28 366
    colors[ImGuiCol_DockingEmptyBg]         = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 367
    colors[ImGuiCol_PlotLines]              = ImVec4(0.39f, 0.39f, 0.39f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 368
    colors[ImGuiCol_PlotLinesHovered]       = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 369
    colors[ImGuiCol_PlotHistogram]          = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 370
    colors[ImGuiCol_PlotHistogramHovered]   = ImVec4(1.00f, 0.45f, 0.00f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 371
    colors[ImGuiCol_TableHeaderBg]          = ImVec4(0.78f, 0.87f, 0.98f, 1.00f);
1193b4be Poul Sander 2025-02-03 21:28 372
    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 373
    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 374
    colors[ImGuiCol_TableRowBg]             = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
1193b4be Poul Sander 2025-02-03 21:28 375
    colors[ImGuiCol_TableRowBgAlt]          = ImVec4(0.30f, 0.30f, 0.30f, 0.09f);
1193b4be Poul Sander 2025-02-03 21:28 376
    colors[ImGuiCol_TextLink]               = colors[ImGuiCol_HeaderActive];
1193b4be Poul Sander 2025-02-03 21:28 377
    colors[ImGuiCol_TextSelectedBg]         = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
4e9e2555 Poul Sander 2025-10-05 10:15 378
    colors[ImGuiCol_TreeLines]              = colors[ImGuiCol_Border];
1193b4be Poul Sander 2025-02-03 21:28 379
    colors[ImGuiCol_DragDropTarget]         = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
1193b4be Poul Sander 2025-02-03 21:28 380
    colors[ImGuiCol_NavCursor]              = colors[ImGuiCol_HeaderHovered];
1193b4be Poul Sander 2025-02-03 21:28 381
    colors[ImGuiCol_NavWindowingHighlight]  = ImVec4(0.70f, 0.70f, 0.70f, 0.70f);
1193b4be Poul Sander 2025-02-03 21:28 382
    colors[ImGuiCol_NavWindowingDimBg]      = ImVec4(0.20f, 0.20f, 0.20f, 0.20f);
1193b4be Poul Sander 2025-02-03 21:28 383
    colors[ImGuiCol_ModalWindowDimBg]       = ImVec4(0.20f, 0.20f, 0.20f, 0.35f);
1193b4be Poul Sander 2025-02-03 21:28 384
}
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
// [SECTION] ImDrawList
1193b4be Poul Sander 2025-02-03 21:28 388
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 389
1193b4be Poul Sander 2025-02-03 21:28 390
ImDrawListSharedData::ImDrawListSharedData()
1193b4be Poul Sander 2025-02-03 21:28 391
{
1193b4be Poul Sander 2025-02-03 21:28 392
    memset(this, 0, sizeof(*this));
4e9e2555 Poul Sander 2025-10-05 10:15 393
    InitialFringeScale = 1.0f;
1193b4be Poul Sander 2025-02-03 21:28 394
    for (int i = 0; i < IM_ARRAYSIZE(ArcFastVtx); i++)
1193b4be Poul Sander 2025-02-03 21:28 395
    {
1193b4be Poul Sander 2025-02-03 21:28 396
        const float a = ((float)i * 2 * IM_PI) / (float)IM_ARRAYSIZE(ArcFastVtx);
1193b4be Poul Sander 2025-02-03 21:28 397
        ArcFastVtx[i] = ImVec2(ImCos(a), ImSin(a));
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
4e9e2555 Poul Sander 2025-10-05 10:15 402
ImDrawListSharedData::~ImDrawListSharedData()
4e9e2555 Poul Sander 2025-10-05 10:15 403
{
4e9e2555 Poul Sander 2025-10-05 10:15 404
    IM_ASSERT(DrawLists.Size == 0);
4e9e2555 Poul Sander 2025-10-05 10:15 405
}
4e9e2555 Poul Sander 2025-10-05 10:15 406
1193b4be Poul Sander 2025-02-03 21:28 407
void ImDrawListSharedData::SetCircleTessellationMaxError(float max_error)
1193b4be Poul Sander 2025-02-03 21:28 408
{
1193b4be Poul Sander 2025-02-03 21:28 409
    if (CircleSegmentMaxError == max_error)
1193b4be Poul Sander 2025-02-03 21:28 410
        return;
1193b4be Poul Sander 2025-02-03 21:28 411
1193b4be Poul Sander 2025-02-03 21:28 412
    IM_ASSERT(max_error > 0.0f);
1193b4be Poul Sander 2025-02-03 21:28 413
    CircleSegmentMaxError = max_error;
1193b4be Poul Sander 2025-02-03 21:28 414
    for (int i = 0; i < IM_ARRAYSIZE(CircleSegmentCounts); i++)
1193b4be Poul Sander 2025-02-03 21:28 415
    {
1193b4be Poul Sander 2025-02-03 21:28 416
        const float radius = (float)i;
1193b4be Poul Sander 2025-02-03 21:28 417
        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 418
    }
1193b4be Poul Sander 2025-02-03 21:28 419
    ArcFastRadiusCutoff = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(IM_DRAWLIST_ARCFAST_SAMPLE_MAX, CircleSegmentMaxError);
1193b4be Poul Sander 2025-02-03 21:28 420
}
1193b4be Poul Sander 2025-02-03 21:28 421
4e9e2555 Poul Sander 2025-10-05 10:15 422
ImDrawList::ImDrawList(ImDrawListSharedData* shared_data)
4e9e2555 Poul Sander 2025-10-05 10:15 423
{
4e9e2555 Poul Sander 2025-10-05 10:15 424
    memset(this, 0, sizeof(*this));
4e9e2555 Poul Sander 2025-10-05 10:15 425
    _SetDrawListSharedData(shared_data);
4e9e2555 Poul Sander 2025-10-05 10:15 426
}
4e9e2555 Poul Sander 2025-10-05 10:15 427
4e9e2555 Poul Sander 2025-10-05 10:15 428
ImDrawList::~ImDrawList()
4e9e2555 Poul Sander 2025-10-05 10:15 429
{
4e9e2555 Poul Sander 2025-10-05 10:15 430
    _ClearFreeMemory();
4e9e2555 Poul Sander 2025-10-05 10:15 431
    _SetDrawListSharedData(NULL);
4e9e2555 Poul Sander 2025-10-05 10:15 432
}
4e9e2555 Poul Sander 2025-10-05 10:15 433
4e9e2555 Poul Sander 2025-10-05 10:15 434
void ImDrawList::_SetDrawListSharedData(ImDrawListSharedData* data)
4e9e2555 Poul Sander 2025-10-05 10:15 435
{
4e9e2555 Poul Sander 2025-10-05 10:15 436
    if (_Data != NULL)
4e9e2555 Poul Sander 2025-10-05 10:15 437
        _Data->DrawLists.find_erase_unsorted(this);
4e9e2555 Poul Sander 2025-10-05 10:15 438
    _Data = data;
4e9e2555 Poul Sander 2025-10-05 10:15 439
    if (_Data != NULL)
4e9e2555 Poul Sander 2025-10-05 10:15 440
        _Data->DrawLists.push_back(this);
4e9e2555 Poul Sander 2025-10-05 10:15 441
}
4e9e2555 Poul Sander 2025-10-05 10:15 442
1193b4be Poul Sander 2025-02-03 21:28 443
// Initialize before use in a new frame. We always have a command ready in the buffer.
4e9e2555 Poul Sander 2025-10-05 10:15 444
// In the majority of cases, you would want to call PushClipRect() and PushTexture() after this.
1193b4be Poul Sander 2025-02-03 21:28 445
void ImDrawList::_ResetForNewFrame()
1193b4be Poul Sander 2025-02-03 21:28 446
{
1193b4be Poul Sander 2025-02-03 21:28 447
    // Verify that the ImDrawCmd fields we want to memcmp() are contiguous in memory.
1193b4be Poul Sander 2025-02-03 21:28 448
    IM_STATIC_ASSERT(offsetof(ImDrawCmd, ClipRect) == 0);
4e9e2555 Poul Sander 2025-10-05 10:15 449
    IM_STATIC_ASSERT(offsetof(ImDrawCmd, TexRef) == sizeof(ImVec4));
4e9e2555 Poul Sander 2025-10-05 10:15 450
    IM_STATIC_ASSERT(offsetof(ImDrawCmd, VtxOffset) == sizeof(ImVec4) + sizeof(ImTextureRef));
1193b4be Poul Sander 2025-02-03 21:28 451
    if (_Splitter._Count > 1)
1193b4be Poul Sander 2025-02-03 21:28 452
        _Splitter.Merge(this);
1193b4be Poul Sander 2025-02-03 21:28 453
1193b4be Poul Sander 2025-02-03 21:28 454
    CmdBuffer.resize(0);
1193b4be Poul Sander 2025-02-03 21:28 455
    IdxBuffer.resize(0);
1193b4be Poul Sander 2025-02-03 21:28 456
    VtxBuffer.resize(0);
1193b4be Poul Sander 2025-02-03 21:28 457
    Flags = _Data->InitialFlags;
1193b4be Poul Sander 2025-02-03 21:28 458
    memset(&_CmdHeader, 0, sizeof(_CmdHeader));
1193b4be Poul Sander 2025-02-03 21:28 459
    _VtxCurrentIdx = 0;
1193b4be Poul Sander 2025-02-03 21:28 460
    _VtxWritePtr = NULL;
1193b4be Poul Sander 2025-02-03 21:28 461
    _IdxWritePtr = NULL;
1193b4be Poul Sander 2025-02-03 21:28 462
    _ClipRectStack.resize(0);
4e9e2555 Poul Sander 2025-10-05 10:15 463
    _TextureStack.resize(0);
1193b4be Poul Sander 2025-02-03 21:28 464
    _CallbacksDataBuf.resize(0);
1193b4be Poul Sander 2025-02-03 21:28 465
    _Path.resize(0);
1193b4be Poul Sander 2025-02-03 21:28 466
    _Splitter.Clear();
1193b4be Poul Sander 2025-02-03 21:28 467
    CmdBuffer.push_back(ImDrawCmd());
4e9e2555 Poul Sander 2025-10-05 10:15 468
    _FringeScale = _Data->InitialFringeScale;
1193b4be Poul Sander 2025-02-03 21:28 469
}
1193b4be Poul Sander 2025-02-03 21:28 470
1193b4be Poul Sander 2025-02-03 21:28 471
void ImDrawList::_ClearFreeMemory()
1193b4be Poul Sander 2025-02-03 21:28 472
{
1193b4be Poul Sander 2025-02-03 21:28 473
    CmdBuffer.clear();
1193b4be Poul Sander 2025-02-03 21:28 474
    IdxBuffer.clear();
1193b4be Poul Sander 2025-02-03 21:28 475
    VtxBuffer.clear();
1193b4be Poul Sander 2025-02-03 21:28 476
    Flags = ImDrawListFlags_None;
1193b4be Poul Sander 2025-02-03 21:28 477
    _VtxCurrentIdx = 0;
1193b4be Poul Sander 2025-02-03 21:28 478
    _VtxWritePtr = NULL;
1193b4be Poul Sander 2025-02-03 21:28 479
    _IdxWritePtr = NULL;
1193b4be Poul Sander 2025-02-03 21:28 480
    _ClipRectStack.clear();
4e9e2555 Poul Sander 2025-10-05 10:15 481
    _TextureStack.clear();
1193b4be Poul Sander 2025-02-03 21:28 482
    _CallbacksDataBuf.clear();
1193b4be Poul Sander 2025-02-03 21:28 483
    _Path.clear();
1193b4be Poul Sander 2025-02-03 21:28 484
    _Splitter.ClearFreeMemory();
1193b4be Poul Sander 2025-02-03 21:28 485
}
1193b4be Poul Sander 2025-02-03 21:28 486
4e9e2555 Poul Sander 2025-10-05 10:15 487
// Note: For multi-threaded rendering, consider using `imgui_threaded_rendering` from https://github.com/ocornut/imgui_club
1193b4be Poul Sander 2025-02-03 21:28 488
ImDrawList* ImDrawList::CloneOutput() const
1193b4be Poul Sander 2025-02-03 21:28 489
{
4e9e2555 Poul Sander 2025-10-05 10:15 490
    ImDrawList* dst = IM_NEW(ImDrawList(NULL));
1193b4be Poul Sander 2025-02-03 21:28 491
    dst->CmdBuffer = CmdBuffer;
1193b4be Poul Sander 2025-02-03 21:28 492
    dst->IdxBuffer = IdxBuffer;
1193b4be Poul Sander 2025-02-03 21:28 493
    dst->VtxBuffer = VtxBuffer;
1193b4be Poul Sander 2025-02-03 21:28 494
    dst->Flags = Flags;
1193b4be Poul Sander 2025-02-03 21:28 495
    return dst;
1193b4be Poul Sander 2025-02-03 21:28 496
}
1193b4be Poul Sander 2025-02-03 21:28 497
1193b4be Poul Sander 2025-02-03 21:28 498
void ImDrawList::AddDrawCmd()
1193b4be Poul Sander 2025-02-03 21:28 499
{
1193b4be Poul Sander 2025-02-03 21:28 500
    ImDrawCmd draw_cmd;
1193b4be Poul Sander 2025-02-03 21:28 501
    draw_cmd.ClipRect = _CmdHeader.ClipRect;    // Same as calling ImDrawCmd_HeaderCopy()
4e9e2555 Poul Sander 2025-10-05 10:15 502
    draw_cmd.TexRef = _CmdHeader.TexRef;
1193b4be Poul Sander 2025-02-03 21:28 503
    draw_cmd.VtxOffset = _CmdHeader.VtxOffset;
1193b4be Poul Sander 2025-02-03 21:28 504
    draw_cmd.IdxOffset = IdxBuffer.Size;
1193b4be Poul Sander 2025-02-03 21:28 505
1193b4be Poul Sander 2025-02-03 21:28 506
    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 507
    CmdBuffer.push_back(draw_cmd);
1193b4be Poul Sander 2025-02-03 21:28 508
}
1193b4be Poul Sander 2025-02-03 21:28 509
1193b4be Poul Sander 2025-02-03 21:28 510
// Pop trailing draw command (used before merging or presenting to user)
1193b4be Poul Sander 2025-02-03 21:28 511
// 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 512
void ImDrawList::_PopUnusedDrawCmd()
1193b4be Poul Sander 2025-02-03 21:28 513
{
1193b4be Poul Sander 2025-02-03 21:28 514
    while (CmdBuffer.Size > 0)
1193b4be Poul Sander 2025-02-03 21:28 515
    {
1193b4be Poul Sander 2025-02-03 21:28 516
        ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
1193b4be Poul Sander 2025-02-03 21:28 517
        if (curr_cmd->ElemCount != 0 || curr_cmd->UserCallback != NULL)
1193b4be Poul Sander 2025-02-03 21:28 518
            return;// break;
1193b4be Poul Sander 2025-02-03 21:28 519
        CmdBuffer.pop_back();
1193b4be Poul Sander 2025-02-03 21:28 520
    }
1193b4be Poul Sander 2025-02-03 21:28 521
}
1193b4be Poul Sander 2025-02-03 21:28 522
1193b4be Poul Sander 2025-02-03 21:28 523
void ImDrawList::AddCallback(ImDrawCallback callback, void* userdata, size_t userdata_size)
1193b4be Poul Sander 2025-02-03 21:28 524
{
1193b4be Poul Sander 2025-02-03 21:28 525
    IM_ASSERT_PARANOID(CmdBuffer.Size > 0);
1193b4be Poul Sander 2025-02-03 21:28 526
    ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
4e9e2555 Poul Sander 2025-10-05 10:15 527
    IM_ASSERT(callback != NULL);
1193b4be Poul Sander 2025-02-03 21:28 528
    IM_ASSERT(curr_cmd->UserCallback == NULL);
1193b4be Poul Sander 2025-02-03 21:28 529
    if (curr_cmd->ElemCount != 0)
1193b4be Poul Sander 2025-02-03 21:28 530
    {
1193b4be Poul Sander 2025-02-03 21:28 531
        AddDrawCmd();
1193b4be Poul Sander 2025-02-03 21:28 532
        curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
1193b4be Poul Sander 2025-02-03 21:28 533
    }
1193b4be Poul Sander 2025-02-03 21:28 534
1193b4be Poul Sander 2025-02-03 21:28 535
    curr_cmd->UserCallback = callback;
1193b4be Poul Sander 2025-02-03 21:28 536
    if (userdata_size == 0)
1193b4be Poul Sander 2025-02-03 21:28 537
    {
1193b4be Poul Sander 2025-02-03 21:28 538
        // Store user data directly in command (no indirection)
1193b4be Poul Sander 2025-02-03 21:28 539
        curr_cmd->UserCallbackData = userdata;
1193b4be Poul Sander 2025-02-03 21:28 540
        curr_cmd->UserCallbackDataSize = 0;
1193b4be Poul Sander 2025-02-03 21:28 541
        curr_cmd->UserCallbackDataOffset = -1;
1193b4be Poul Sander 2025-02-03 21:28 542
    }
1193b4be Poul Sander 2025-02-03 21:28 543
    else
1193b4be Poul Sander 2025-02-03 21:28 544
    {
1193b4be Poul Sander 2025-02-03 21:28 545
        // Copy and store user data in a buffer
1193b4be Poul Sander 2025-02-03 21:28 546
        IM_ASSERT(userdata != NULL);
1193b4be Poul Sander 2025-02-03 21:28 547
        IM_ASSERT(userdata_size < (1u << 31));
1193b4be Poul Sander 2025-02-03 21:28 548
        curr_cmd->UserCallbackData = NULL; // Will be resolved during Render()
1193b4be Poul Sander 2025-02-03 21:28 549
        curr_cmd->UserCallbackDataSize = (int)userdata_size;
1193b4be Poul Sander 2025-02-03 21:28 550
        curr_cmd->UserCallbackDataOffset = _CallbacksDataBuf.Size;
1193b4be Poul Sander 2025-02-03 21:28 551
        _CallbacksDataBuf.resize(_CallbacksDataBuf.Size + (int)userdata_size);
1193b4be Poul Sander 2025-02-03 21:28 552
        memcpy(_CallbacksDataBuf.Data + (size_t)curr_cmd->UserCallbackDataOffset, userdata, userdata_size);
1193b4be Poul Sander 2025-02-03 21:28 553
    }
1193b4be Poul Sander 2025-02-03 21:28 554
1193b4be Poul Sander 2025-02-03 21:28 555
    AddDrawCmd(); // Force a new command after us (see comment below)
1193b4be Poul Sander 2025-02-03 21:28 556
}
1193b4be Poul Sander 2025-02-03 21:28 557
4e9e2555 Poul Sander 2025-10-05 10:15 558
// Compare ClipRect, TexRef and VtxOffset with a single memcmp()
1193b4be Poul Sander 2025-02-03 21:28 559
#define ImDrawCmd_HeaderSize                            (offsetof(ImDrawCmd, VtxOffset) + sizeof(unsigned int))
4e9e2555 Poul Sander 2025-10-05 10:15 560
#define ImDrawCmd_HeaderCompare(CMD_LHS, CMD_RHS)       (memcmp(CMD_LHS, CMD_RHS, ImDrawCmd_HeaderSize))    // Compare ClipRect, TexRef, VtxOffset
4e9e2555 Poul Sander 2025-10-05 10:15 561
#define ImDrawCmd_HeaderCopy(CMD_DST, CMD_SRC)          (memcpy(CMD_DST, CMD_SRC, ImDrawCmd_HeaderSize))    // Copy ClipRect, TexRef, VtxOffset
1193b4be Poul Sander 2025-02-03 21:28 562
#define ImDrawCmd_AreSequentialIdxOffset(CMD_0, CMD_1)  (CMD_0->IdxOffset + CMD_0->ElemCount == CMD_1->IdxOffset)
1193b4be Poul Sander 2025-02-03 21:28 563
1193b4be Poul Sander 2025-02-03 21:28 564
// Try to merge two last draw commands
1193b4be Poul Sander 2025-02-03 21:28 565
void ImDrawList::_TryMergeDrawCmds()
1193b4be Poul Sander 2025-02-03 21:28 566
{
1193b4be Poul Sander 2025-02-03 21:28 567
    IM_ASSERT_PARANOID(CmdBuffer.Size > 0);
1193b4be Poul Sander 2025-02-03 21:28 568
    ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
1193b4be Poul Sander 2025-02-03 21:28 569
    ImDrawCmd* prev_cmd = curr_cmd - 1;
1193b4be Poul Sander 2025-02-03 21:28 570
    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 571
    {
1193b4be Poul Sander 2025-02-03 21:28 572
        prev_cmd->ElemCount += curr_cmd->ElemCount;
1193b4be Poul Sander 2025-02-03 21:28 573
        CmdBuffer.pop_back();
1193b4be Poul Sander 2025-02-03 21:28 574
    }
1193b4be Poul Sander 2025-02-03 21:28 575
}
1193b4be Poul Sander 2025-02-03 21:28 576
1193b4be Poul Sander 2025-02-03 21:28 577
// 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 578
// 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 579
void ImDrawList::_OnChangedClipRect()
1193b4be Poul Sander 2025-02-03 21:28 580
{
1193b4be Poul Sander 2025-02-03 21:28 581
    // If current command is used with different settings we need to add a new command
1193b4be Poul Sander 2025-02-03 21:28 582
    IM_ASSERT_PARANOID(CmdBuffer.Size > 0);
1193b4be Poul Sander 2025-02-03 21:28 583
    ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
1193b4be Poul Sander 2025-02-03 21:28 584
    if (curr_cmd->ElemCount != 0 && memcmp(&curr_cmd->ClipRect, &_CmdHeader.ClipRect, sizeof(ImVec4)) != 0)
1193b4be Poul Sander 2025-02-03 21:28 585
    {
1193b4be Poul Sander 2025-02-03 21:28 586
        AddDrawCmd();
1193b4be Poul Sander 2025-02-03 21:28 587
        return;
1193b4be Poul Sander 2025-02-03 21:28 588
    }
1193b4be Poul Sander 2025-02-03 21:28 589
    IM_ASSERT(curr_cmd->UserCallback == NULL);
1193b4be Poul Sander 2025-02-03 21:28 590
1193b4be Poul Sander 2025-02-03 21:28 591
    // Try to merge with previous command if it matches, else use current command
1193b4be Poul Sander 2025-02-03 21:28 592
    ImDrawCmd* prev_cmd = curr_cmd - 1;
1193b4be Poul Sander 2025-02-03 21:28 593
    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 594
    {
1193b4be Poul Sander 2025-02-03 21:28 595
        CmdBuffer.pop_back();
1193b4be Poul Sander 2025-02-03 21:28 596
        return;
1193b4be Poul Sander 2025-02-03 21:28 597
    }
1193b4be Poul Sander 2025-02-03 21:28 598
    curr_cmd->ClipRect = _CmdHeader.ClipRect;
1193b4be Poul Sander 2025-02-03 21:28 599
}
1193b4be Poul Sander 2025-02-03 21:28 600
4e9e2555 Poul Sander 2025-10-05 10:15 601
void ImDrawList::_OnChangedTexture()
1193b4be Poul Sander 2025-02-03 21:28 602
{
1193b4be Poul Sander 2025-02-03 21:28 603
    // If current command is used with different settings we need to add a new command
1193b4be Poul Sander 2025-02-03 21:28 604
    IM_ASSERT_PARANOID(CmdBuffer.Size > 0);
1193b4be Poul Sander 2025-02-03 21:28 605
    ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
4e9e2555 Poul Sander 2025-10-05 10:15 606
    if (curr_cmd->ElemCount != 0 && curr_cmd->TexRef != _CmdHeader.TexRef)
1193b4be Poul Sander 2025-02-03 21:28 607
    {
1193b4be Poul Sander 2025-02-03 21:28 608
        AddDrawCmd();
1193b4be Poul Sander 2025-02-03 21:28 609
        return;
1193b4be Poul Sander 2025-02-03 21:28 610
    }
4e9e2555 Poul Sander 2025-10-05 10:15 611
4e9e2555 Poul Sander 2025-10-05 10:15 612
    // Unlike other _OnChangedXXX functions this may be called by ImFontAtlasUpdateDrawListsTextures() in more locations so we need to handle this case.
4e9e2555 Poul Sander 2025-10-05 10:15 613
    if (curr_cmd->UserCallback != NULL)
4e9e2555 Poul Sander 2025-10-05 10:15 614
        return;
1193b4be Poul Sander 2025-02-03 21:28 615
1193b4be Poul Sander 2025-02-03 21:28 616
    // Try to merge with previous command if it matches, else use current command
1193b4be Poul Sander 2025-02-03 21:28 617
    ImDrawCmd* prev_cmd = curr_cmd - 1;
1193b4be Poul Sander 2025-02-03 21:28 618
    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 619
    {
1193b4be Poul Sander 2025-02-03 21:28 620
        CmdBuffer.pop_back();
1193b4be Poul Sander 2025-02-03 21:28 621
        return;
1193b4be Poul Sander 2025-02-03 21:28 622
    }
4e9e2555 Poul Sander 2025-10-05 10:15 623
    curr_cmd->TexRef = _CmdHeader.TexRef;
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::_OnChangedVtxOffset()
1193b4be Poul Sander 2025-02-03 21:28 627
{
1193b4be Poul Sander 2025-02-03 21:28 628
    // 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 629
    _VtxCurrentIdx = 0;
1193b4be Poul Sander 2025-02-03 21:28 630
    IM_ASSERT_PARANOID(CmdBuffer.Size > 0);
1193b4be Poul Sander 2025-02-03 21:28 631
    ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
1193b4be Poul Sander 2025-02-03 21:28 632
    //IM_ASSERT(curr_cmd->VtxOffset != _CmdHeader.VtxOffset); // See #3349
1193b4be Poul Sander 2025-02-03 21:28 633
    if (curr_cmd->ElemCount != 0)
1193b4be Poul Sander 2025-02-03 21:28 634
    {
1193b4be Poul Sander 2025-02-03 21:28 635
        AddDrawCmd();
1193b4be Poul Sander 2025-02-03 21:28 636
        return;
1193b4be Poul Sander 2025-02-03 21:28 637
    }
1193b4be Poul Sander 2025-02-03 21:28 638
    IM_ASSERT(curr_cmd->UserCallback == NULL);
1193b4be Poul Sander 2025-02-03 21:28 639
    curr_cmd->VtxOffset = _CmdHeader.VtxOffset;
1193b4be Poul Sander 2025-02-03 21:28 640
}
1193b4be Poul Sander 2025-02-03 21:28 641
1193b4be Poul Sander 2025-02-03 21:28 642
int ImDrawList::_CalcCircleAutoSegmentCount(float radius) const
1193b4be Poul Sander 2025-02-03 21:28 643
{
1193b4be Poul Sander 2025-02-03 21:28 644
    // Automatic segment count
1193b4be Poul Sander 2025-02-03 21:28 645
    const int radius_idx = (int)(radius + 0.999999f); // ceil to never reduce accuracy
1193b4be Poul Sander 2025-02-03 21:28 646
    if (radius_idx >= 0 && radius_idx < IM_ARRAYSIZE(_Data->CircleSegmentCounts))
1193b4be Poul Sander 2025-02-03 21:28 647
        return _Data->CircleSegmentCounts[radius_idx]; // Use cached value
1193b4be Poul Sander 2025-02-03 21:28 648
    else
1193b4be Poul Sander 2025-02-03 21:28 649
        return IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, _Data->CircleSegmentMaxError);
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
// 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 653
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 654
{
1193b4be Poul Sander 2025-02-03 21:28 655
    ImVec4 cr(cr_min.x, cr_min.y, cr_max.x, cr_max.y);
1193b4be Poul Sander 2025-02-03 21:28 656
    if (intersect_with_current_clip_rect)
1193b4be Poul Sander 2025-02-03 21:28 657
    {
1193b4be Poul Sander 2025-02-03 21:28 658
        ImVec4 current = _CmdHeader.ClipRect;
1193b4be Poul Sander 2025-02-03 21:28 659
        if (cr.x < current.x) cr.x = current.x;
1193b4be Poul Sander 2025-02-03 21:28 660
        if (cr.y < current.y) cr.y = current.y;
1193b4be Poul Sander 2025-02-03 21:28 661
        if (cr.z > current.z) cr.z = current.z;
1193b4be Poul Sander 2025-02-03 21:28 662
        if (cr.w > current.w) cr.w = current.w;
1193b4be Poul Sander 2025-02-03 21:28 663
    }
1193b4be Poul Sander 2025-02-03 21:28 664
    cr.z = ImMax(cr.x, cr.z);
1193b4be Poul Sander 2025-02-03 21:28 665
    cr.w = ImMax(cr.y, cr.w);
1193b4be Poul Sander 2025-02-03 21:28 666
1193b4be Poul Sander 2025-02-03 21:28 667
    _ClipRectStack.push_back(cr);
1193b4be Poul Sander 2025-02-03 21:28 668
    _CmdHeader.ClipRect = cr;
1193b4be Poul Sander 2025-02-03 21:28 669
    _OnChangedClipRect();
1193b4be Poul Sander 2025-02-03 21:28 670
}
1193b4be Poul Sander 2025-02-03 21:28 671
1193b4be Poul Sander 2025-02-03 21:28 672
void ImDrawList::PushClipRectFullScreen()
1193b4be Poul Sander 2025-02-03 21:28 673
{
1193b4be Poul Sander 2025-02-03 21:28 674
    PushClipRect(ImVec2(_Data->ClipRectFullscreen.x, _Data->ClipRectFullscreen.y), ImVec2(_Data->ClipRectFullscreen.z, _Data->ClipRectFullscreen.w));
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
void ImDrawList::PopClipRect()
1193b4be Poul Sander 2025-02-03 21:28 678
{
1193b4be Poul Sander 2025-02-03 21:28 679
    _ClipRectStack.pop_back();
1193b4be Poul Sander 2025-02-03 21:28 680
    _CmdHeader.ClipRect = (_ClipRectStack.Size == 0) ? _Data->ClipRectFullscreen : _ClipRectStack.Data[_ClipRectStack.Size - 1];
1193b4be Poul Sander 2025-02-03 21:28 681
    _OnChangedClipRect();
1193b4be Poul Sander 2025-02-03 21:28 682
}
1193b4be Poul Sander 2025-02-03 21:28 683
4e9e2555 Poul Sander 2025-10-05 10:15 684
void ImDrawList::PushTexture(ImTextureRef tex_ref)
1193b4be Poul Sander 2025-02-03 21:28 685
{
4e9e2555 Poul Sander 2025-10-05 10:15 686
    _TextureStack.push_back(tex_ref);
4e9e2555 Poul Sander 2025-10-05 10:15 687
    _CmdHeader.TexRef = tex_ref;
4e9e2555 Poul Sander 2025-10-05 10:15 688
    if (tex_ref._TexData != NULL)
4e9e2555 Poul Sander 2025-10-05 10:15 689
        IM_ASSERT(tex_ref._TexData->WantDestroyNextFrame == false);
4e9e2555 Poul Sander 2025-10-05 10:15 690
    _OnChangedTexture();
1193b4be Poul Sander 2025-02-03 21:28 691
}
1193b4be Poul Sander 2025-02-03 21:28 692
4e9e2555 Poul Sander 2025-10-05 10:15 693
void ImDrawList::PopTexture()
1193b4be Poul Sander 2025-02-03 21:28 694
{
4e9e2555 Poul Sander 2025-10-05 10:15 695
    _TextureStack.pop_back();
4e9e2555 Poul Sander 2025-10-05 10:15 696
    _CmdHeader.TexRef = (_TextureStack.Size == 0) ? ImTextureRef() : _TextureStack.Data[_TextureStack.Size - 1];
4e9e2555 Poul Sander 2025-10-05 10:15 697
    _OnChangedTexture();
1193b4be Poul Sander 2025-02-03 21:28 698
}
1193b4be Poul Sander 2025-02-03 21:28 699
4e9e2555 Poul Sander 2025-10-05 10:15 700
// This is used by ImGui::PushFont()/PopFont(). It works because we never use _TextureIdStack[] elsewhere than in PushTexture()/PopTexture().
4e9e2555 Poul Sander 2025-10-05 10:15 701
void ImDrawList::_SetTexture(ImTextureRef tex_ref)
1193b4be Poul Sander 2025-02-03 21:28 702
{
4e9e2555 Poul Sander 2025-10-05 10:15 703
    if (_CmdHeader.TexRef == tex_ref)
1193b4be Poul Sander 2025-02-03 21:28 704
        return;
4e9e2555 Poul Sander 2025-10-05 10:15 705
    _CmdHeader.TexRef = tex_ref;
4e9e2555 Poul Sander 2025-10-05 10:15 706
    _TextureStack.back() = tex_ref;
4e9e2555 Poul Sander 2025-10-05 10:15 707
    _OnChangedTexture();
1193b4be Poul Sander 2025-02-03 21:28 708
}
1193b4be Poul Sander 2025-02-03 21:28 709
1193b4be Poul Sander 2025-02-03 21:28 710
// Reserve space for a number of vertices and indices.
1193b4be Poul Sander 2025-02-03 21:28 711
// You must finish filling your reserved data before calling PrimReserve() again, as it may reallocate or
1193b4be Poul Sander 2025-02-03 21:28 712
// submit the intermediate results. PrimUnreserve() can be used to release unused allocations.
1193b4be Poul Sander 2025-02-03 21:28 713
void ImDrawList::PrimReserve(int idx_count, int vtx_count)
1193b4be Poul Sander 2025-02-03 21:28 714
{
1193b4be Poul Sander 2025-02-03 21:28 715
    // Large mesh support (when enabled)
1193b4be Poul Sander 2025-02-03 21:28 716
    IM_ASSERT_PARANOID(idx_count >= 0 && vtx_count >= 0);
1193b4be Poul Sander 2025-02-03 21:28 717
    if (sizeof(ImDrawIdx) == 2 && (_VtxCurrentIdx + vtx_count >= (1 << 16)) && (Flags & ImDrawListFlags_AllowVtxOffset))
1193b4be Poul Sander 2025-02-03 21:28 718
    {
1193b4be Poul Sander 2025-02-03 21:28 719
        // FIXME: In theory we should be testing that vtx_count <64k here.
1193b4be Poul Sander 2025-02-03 21:28 720
        // 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 721
        // 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 722
        _CmdHeader.VtxOffset = VtxBuffer.Size;
1193b4be Poul Sander 2025-02-03 21:28 723
        _OnChangedVtxOffset();
1193b4be Poul Sander 2025-02-03 21:28 724
    }
1193b4be Poul Sander 2025-02-03 21:28 725
1193b4be Poul Sander 2025-02-03 21:28 726
    ImDrawCmd* draw_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
1193b4be Poul Sander 2025-02-03 21:28 727
    draw_cmd->ElemCount += idx_count;
1193b4be Poul Sander 2025-02-03 21:28 728
1193b4be Poul Sander 2025-02-03 21:28 729
    int vtx_buffer_old_size = VtxBuffer.Size;
1193b4be Poul Sander 2025-02-03 21:28 730
    VtxBuffer.resize(vtx_buffer_old_size + vtx_count);
1193b4be Poul Sander 2025-02-03 21:28 731
    _VtxWritePtr = VtxBuffer.Data + vtx_buffer_old_size;
1193b4be Poul Sander 2025-02-03 21:28 732
1193b4be Poul Sander 2025-02-03 21:28 733
    int idx_buffer_old_size = IdxBuffer.Size;
1193b4be Poul Sander 2025-02-03 21:28 734
    IdxBuffer.resize(idx_buffer_old_size + idx_count);
1193b4be Poul Sander 2025-02-03 21:28 735
    _IdxWritePtr = IdxBuffer.Data + idx_buffer_old_size;
1193b4be Poul Sander 2025-02-03 21:28 736
}
1193b4be Poul Sander 2025-02-03 21:28 737
1193b4be Poul Sander 2025-02-03 21:28 738
// 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 739
void ImDrawList::PrimUnreserve(int idx_count, int vtx_count)
1193b4be Poul Sander 2025-02-03 21:28 740
{
1193b4be Poul Sander 2025-02-03 21:28 741
    IM_ASSERT_PARANOID(idx_count >= 0 && vtx_count >= 0);
1193b4be Poul Sander 2025-02-03 21:28 742
1193b4be Poul Sander 2025-02-03 21:28 743
    ImDrawCmd* draw_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
1193b4be Poul Sander 2025-02-03 21:28 744
    draw_cmd->ElemCount -= idx_count;
1193b4be Poul Sander 2025-02-03 21:28 745
    VtxBuffer.shrink(VtxBuffer.Size - vtx_count);
1193b4be Poul Sander 2025-02-03 21:28 746
    IdxBuffer.shrink(IdxBuffer.Size - idx_count);
1193b4be Poul Sander 2025-02-03 21:28 747
}
1193b4be Poul Sander 2025-02-03 21:28 748
1193b4be Poul Sander 2025-02-03 21:28 749
// Fully unrolled with inline call to keep our debug builds decently fast.
1193b4be Poul Sander 2025-02-03 21:28 750
void ImDrawList::PrimRect(const ImVec2& a, const ImVec2& c, ImU32 col)
1193b4be Poul Sander 2025-02-03 21:28 751
{
1193b4be Poul Sander 2025-02-03 21:28 752
    ImVec2 b(c.x, a.y), d(a.x, c.y), uv(_Data->TexUvWhitePixel);
1193b4be Poul Sander 2025-02-03 21:28 753
    ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx;
1193b4be Poul Sander 2025-02-03 21:28 754
    _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2);
1193b4be Poul Sander 2025-02-03 21:28 755
    _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3);
1193b4be Poul Sander 2025-02-03 21:28 756
    _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;
1193b4be Poul Sander 2025-02-03 21:28 757
    _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col;
1193b4be Poul Sander 2025-02-03 21:28 758
    _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col;
1193b4be Poul Sander 2025-02-03 21:28 759
    _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv; _VtxWritePtr[3].col = col;
1193b4be Poul Sander 2025-02-03 21:28 760
    _VtxWritePtr += 4;
1193b4be Poul Sander 2025-02-03 21:28 761
    _VtxCurrentIdx += 4;
1193b4be Poul Sander 2025-02-03 21:28 762
    _IdxWritePtr += 6;
1193b4be Poul Sander 2025-02-03 21:28 763
}
1193b4be Poul Sander 2025-02-03 21:28 764
1193b4be Poul Sander 2025-02-03 21:28 765
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 766
{
1193b4be Poul Sander 2025-02-03 21:28 767
    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 768
    ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx;
1193b4be Poul Sander 2025-02-03 21:28 769
    _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2);
1193b4be Poul Sander 2025-02-03 21:28 770
    _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3);
1193b4be Poul Sander 2025-02-03 21:28 771
    _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv_a; _VtxWritePtr[0].col = col;
1193b4be Poul Sander 2025-02-03 21:28 772
    _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv_b; _VtxWritePtr[1].col = col;
1193b4be Poul Sander 2025-02-03 21:28 773
    _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv_c; _VtxWritePtr[2].col = col;
1193b4be Poul Sander 2025-02-03 21:28 774
    _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv_d; _VtxWritePtr[3].col = col;
1193b4be Poul Sander 2025-02-03 21:28 775
    _VtxWritePtr += 4;
1193b4be Poul Sander 2025-02-03 21:28 776
    _VtxCurrentIdx += 4;
1193b4be Poul Sander 2025-02-03 21:28 777
    _IdxWritePtr += 6;
1193b4be Poul Sander 2025-02-03 21:28 778
}
1193b4be Poul Sander 2025-02-03 21:28 779
1193b4be Poul Sander 2025-02-03 21:28 780
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 781
{
1193b4be Poul Sander 2025-02-03 21:28 782
    ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx;
1193b4be Poul Sander 2025-02-03 21:28 783
    _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2);
1193b4be Poul Sander 2025-02-03 21:28 784
    _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3);
1193b4be Poul Sander 2025-02-03 21:28 785
    _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv_a; _VtxWritePtr[0].col = col;
1193b4be Poul Sander 2025-02-03 21:28 786
    _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv_b; _VtxWritePtr[1].col = col;
1193b4be Poul Sander 2025-02-03 21:28 787
    _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv_c; _VtxWritePtr[2].col = col;
1193b4be Poul Sander 2025-02-03 21:28 788
    _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv_d; _VtxWritePtr[3].col = col;
1193b4be Poul Sander 2025-02-03 21:28 789
    _VtxWritePtr += 4;
1193b4be Poul Sander 2025-02-03 21:28 790
    _VtxCurrentIdx += 4;
1193b4be Poul Sander 2025-02-03 21:28 791
    _IdxWritePtr += 6;
1193b4be Poul Sander 2025-02-03 21:28 792
}
1193b4be Poul Sander 2025-02-03 21:28 793
1193b4be Poul Sander 2025-02-03 21:28 794
// 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 795
// - Those macros expects l-values and need to be used as their own statement.
1193b4be Poul Sander 2025-02-03 21:28 796
// - 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 797
#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 798
#define IM_FIXNORMAL2F_MAX_INVLEN2          100.0f // 500.0f (see #4053, #3366)
1193b4be Poul Sander 2025-02-03 21:28 799
#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 800
1193b4be Poul Sander 2025-02-03 21:28 801
// TODO: Thickness anti-aliased lines cap are missing their AA fringe.
1193b4be Poul Sander 2025-02-03 21:28 802
// 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 803
void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 col, ImDrawFlags flags, float thickness)
1193b4be Poul Sander 2025-02-03 21:28 804
{
1193b4be Poul Sander 2025-02-03 21:28 805
    if (points_count < 2 || (col & IM_COL32_A_MASK) == 0)
1193b4be Poul Sander 2025-02-03 21:28 806
        return;
1193b4be Poul Sander 2025-02-03 21:28 807
1193b4be Poul Sander 2025-02-03 21:28 808
    const bool closed = (flags & ImDrawFlags_Closed) != 0;
1193b4be Poul Sander 2025-02-03 21:28 809
    const ImVec2 opaque_uv = _Data->TexUvWhitePixel;
1193b4be Poul Sander 2025-02-03 21:28 810
    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 811
    const bool thick_line = (thickness > _FringeScale);
1193b4be Poul Sander 2025-02-03 21:28 812
1193b4be Poul Sander 2025-02-03 21:28 813
    if (Flags & ImDrawListFlags_AntiAliasedLines)
1193b4be Poul Sander 2025-02-03 21:28 814
    {
1193b4be Poul Sander 2025-02-03 21:28 815
        // Anti-aliased stroke
1193b4be Poul Sander 2025-02-03 21:28 816
        const float AA_SIZE = _FringeScale;
1193b4be Poul Sander 2025-02-03 21:28 817
        const ImU32 col_trans = col & ~IM_COL32_A_MASK;
1193b4be Poul Sander 2025-02-03 21:28 818
1193b4be Poul Sander 2025-02-03 21:28 819
        // Thicknesses <1.0 should behave like thickness 1.0
1193b4be Poul Sander 2025-02-03 21:28 820
        thickness = ImMax(thickness, 1.0f);
1193b4be Poul Sander 2025-02-03 21:28 821
        const int integer_thickness = (int)thickness;
1193b4be Poul Sander 2025-02-03 21:28 822
        const float fractional_thickness = thickness - integer_thickness;
1193b4be Poul Sander 2025-02-03 21:28 823
1193b4be Poul Sander 2025-02-03 21:28 824
        // Do we want to draw this line using a texture?
1193b4be Poul Sander 2025-02-03 21:28 825
        // - 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 826
        // - If AA_SIZE is not 1.0f we cannot use the texture path.
1193b4be Poul Sander 2025-02-03 21:28 827
        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 828
1193b4be Poul Sander 2025-02-03 21:28 829
        // 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 830
        IM_ASSERT_PARANOID(!use_texture || !(_Data->Font->ContainerAtlas->Flags & ImFontAtlasFlags_NoBakedLines));
1193b4be Poul Sander 2025-02-03 21:28 831
1193b4be Poul Sander 2025-02-03 21:28 832
        const int idx_count = use_texture ? (count * 6) : (thick_line ? count * 18 : count * 12);
1193b4be Poul Sander 2025-02-03 21:28 833
        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 834
        PrimReserve(idx_count, vtx_count);
1193b4be Poul Sander 2025-02-03 21:28 835
1193b4be Poul Sander 2025-02-03 21:28 836
        // Temporary buffer
1193b4be Poul Sander 2025-02-03 21:28 837
        // 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 838
        _Data->TempBuffer.reserve_discard(points_count * ((use_texture || !thick_line) ? 3 : 5));
1193b4be Poul Sander 2025-02-03 21:28 839
        ImVec2* temp_normals = _Data->TempBuffer.Data;
1193b4be Poul Sander 2025-02-03 21:28 840
        ImVec2* temp_points = temp_normals + points_count;
1193b4be Poul Sander 2025-02-03 21:28 841
1193b4be Poul Sander 2025-02-03 21:28 842
        // Calculate normals (tangents) for each line segment
1193b4be Poul Sander 2025-02-03 21:28 843
        for (int i1 = 0; i1 < count; i1++)
1193b4be Poul Sander 2025-02-03 21:28 844
        {
1193b4be Poul Sander 2025-02-03 21:28 845
            const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1;
1193b4be Poul Sander 2025-02-03 21:28 846
            float dx = points[i2].x - points[i1].x;
1193b4be Poul Sander 2025-02-03 21:28 847
            float dy = points[i2].y - points[i1].y;
1193b4be Poul Sander 2025-02-03 21:28 848
            IM_NORMALIZE2F_OVER_ZERO(dx, dy);
1193b4be Poul Sander 2025-02-03 21:28 849
            temp_normals[i1].x = dy;
1193b4be Poul Sander 2025-02-03 21:28 850
            temp_normals[i1].y = -dx;
1193b4be Poul Sander 2025-02-03 21:28 851
        }
1193b4be Poul Sander 2025-02-03 21:28 852
        if (!closed)
1193b4be Poul Sander 2025-02-03 21:28 853
            temp_normals[points_count - 1] = temp_normals[points_count - 2];
1193b4be Poul Sander 2025-02-03 21:28 854
1193b4be Poul Sander 2025-02-03 21:28 855
        // 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 856
        if (use_texture || !thick_line)
1193b4be Poul Sander 2025-02-03 21:28 857
        {
1193b4be Poul Sander 2025-02-03 21:28 858
            // [PATH 1] Texture-based lines (thick or non-thick)
1193b4be Poul Sander 2025-02-03 21:28 859
            // [PATH 2] Non texture-based lines (non-thick)
1193b4be Poul Sander 2025-02-03 21:28 860
1193b4be Poul Sander 2025-02-03 21:28 861
            // 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 862
            // - 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 863
            //   (see ImFontAtlasBuildRenderLinesTexData() function), and so alternate values won't work without changes to that code.
1193b4be Poul Sander 2025-02-03 21:28 864
            // - 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 865
            //   allow scaling geometry while preserving one-screen-pixel AA fringe).
1193b4be Poul Sander 2025-02-03 21:28 866
            const float half_draw_size = use_texture ? ((thickness * 0.5f) + 1) : AA_SIZE;
1193b4be Poul Sander 2025-02-03 21:28 867
1193b4be Poul Sander 2025-02-03 21:28 868
            // 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 869
            if (!closed)
1193b4be Poul Sander 2025-02-03 21:28 870
            {
1193b4be Poul Sander 2025-02-03 21:28 871
                temp_points[0] = points[0] + temp_normals[0] * half_draw_size;
1193b4be Poul Sander 2025-02-03 21:28 872
                temp_points[1] = points[0] - temp_normals[0] * half_draw_size;
1193b4be Poul Sander 2025-02-03 21:28 873
                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 874
                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 875
            }
1193b4be Poul Sander 2025-02-03 21:28 876
1193b4be Poul Sander 2025-02-03 21:28 877
            // 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 878
            // 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 879
            // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer.
1193b4be Poul Sander 2025-02-03 21:28 880
            unsigned int idx1 = _VtxCurrentIdx; // Vertex index for start of line segment
1193b4be Poul Sander 2025-02-03 21:28 881
            for (int i1 = 0; i1 < count; i1++) // i1 is the first point of the line segment
1193b4be Poul Sander 2025-02-03 21:28 882
            {
1193b4be Poul Sander 2025-02-03 21:28 883
                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 884
                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 885
1193b4be Poul Sander 2025-02-03 21:28 886
                // Average normals
1193b4be Poul Sander 2025-02-03 21:28 887
                float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 888
                float dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 889
                IM_FIXNORMAL2F(dm_x, dm_y);
1193b4be Poul Sander 2025-02-03 21:28 890
                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 891
                dm_y *= half_draw_size;
1193b4be Poul Sander 2025-02-03 21:28 892
4e9e2555 Poul Sander 2025-10-05 10:15 893
                // Add temporary vertices for the outer edges
1193b4be Poul Sander 2025-02-03 21:28 894
                ImVec2* out_vtx = &temp_points[i2 * 2];
1193b4be Poul Sander 2025-02-03 21:28 895
                out_vtx[0].x = points[i2].x + dm_x;
1193b4be Poul Sander 2025-02-03 21:28 896
                out_vtx[0].y = points[i2].y + dm_y;
1193b4be Poul Sander 2025-02-03 21:28 897
                out_vtx[1].x = points[i2].x - dm_x;
1193b4be Poul Sander 2025-02-03 21:28 898
                out_vtx[1].y = points[i2].y - dm_y;
1193b4be Poul Sander 2025-02-03 21:28 899
1193b4be Poul Sander 2025-02-03 21:28 900
                if (use_texture)
1193b4be Poul Sander 2025-02-03 21:28 901
                {
1193b4be Poul Sander 2025-02-03 21:28 902
                    // Add indices for two triangles
1193b4be Poul Sander 2025-02-03 21:28 903
                    _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 904
                    _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 905
                    _IdxWritePtr += 6;
1193b4be Poul Sander 2025-02-03 21:28 906
                }
1193b4be Poul Sander 2025-02-03 21:28 907
                else
1193b4be Poul Sander 2025-02-03 21:28 908
                {
1193b4be Poul Sander 2025-02-03 21:28 909
                    // Add indexes for four triangles
1193b4be Poul Sander 2025-02-03 21:28 910
                    _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 911
                    _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 912
                    _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 913
                    _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 914
                    _IdxWritePtr += 12;
1193b4be Poul Sander 2025-02-03 21:28 915
                }
1193b4be Poul Sander 2025-02-03 21:28 916
1193b4be Poul Sander 2025-02-03 21:28 917
                idx1 = idx2;
1193b4be Poul Sander 2025-02-03 21:28 918
            }
1193b4be Poul Sander 2025-02-03 21:28 919
4e9e2555 Poul Sander 2025-10-05 10:15 920
            // Add vertices for each point on the line
1193b4be Poul Sander 2025-02-03 21:28 921
            if (use_texture)
1193b4be Poul Sander 2025-02-03 21:28 922
            {
1193b4be Poul Sander 2025-02-03 21:28 923
                // If we're using textures we only need to emit the left/right edge vertices
1193b4be Poul Sander 2025-02-03 21:28 924
                ImVec4 tex_uvs = _Data->TexUvLines[integer_thickness];
1193b4be Poul Sander 2025-02-03 21:28 925
                /*if (fractional_thickness != 0.0f) // Currently always zero when use_texture==false!
1193b4be Poul Sander 2025-02-03 21:28 926
                {
1193b4be Poul Sander 2025-02-03 21:28 927
                    const ImVec4 tex_uvs_1 = _Data->TexUvLines[integer_thickness + 1];
1193b4be Poul Sander 2025-02-03 21:28 928
                    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 929
                    tex_uvs.y = tex_uvs.y + (tex_uvs_1.y - tex_uvs.y) * fractional_thickness;
1193b4be Poul Sander 2025-02-03 21:28 930
                    tex_uvs.z = tex_uvs.z + (tex_uvs_1.z - tex_uvs.z) * fractional_thickness;
1193b4be Poul Sander 2025-02-03 21:28 931
                    tex_uvs.w = tex_uvs.w + (tex_uvs_1.w - tex_uvs.w) * fractional_thickness;
1193b4be Poul Sander 2025-02-03 21:28 932
                }*/
1193b4be Poul Sander 2025-02-03 21:28 933
                ImVec2 tex_uv0(tex_uvs.x, tex_uvs.y);
1193b4be Poul Sander 2025-02-03 21:28 934
                ImVec2 tex_uv1(tex_uvs.z, tex_uvs.w);
1193b4be Poul Sander 2025-02-03 21:28 935
                for (int i = 0; i < points_count; i++)
1193b4be Poul Sander 2025-02-03 21:28 936
                {
1193b4be Poul Sander 2025-02-03 21:28 937
                    _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 938
                    _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 939
                    _VtxWritePtr += 2;
1193b4be Poul Sander 2025-02-03 21:28 940
                }
1193b4be Poul Sander 2025-02-03 21:28 941
            }
1193b4be Poul Sander 2025-02-03 21:28 942
            else
1193b4be Poul Sander 2025-02-03 21:28 943
            {
1193b4be Poul Sander 2025-02-03 21:28 944
                // If we're not using a texture, we need the center vertex as well
1193b4be Poul Sander 2025-02-03 21:28 945
                for (int i = 0; i < points_count; i++)
1193b4be Poul Sander 2025-02-03 21:28 946
                {
1193b4be Poul Sander 2025-02-03 21:28 947
                    _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 948
                    _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 949
                    _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 950
                    _VtxWritePtr += 3;
1193b4be Poul Sander 2025-02-03 21:28 951
                }
1193b4be Poul Sander 2025-02-03 21:28 952
            }
1193b4be Poul Sander 2025-02-03 21:28 953
        }
1193b4be Poul Sander 2025-02-03 21:28 954
        else
1193b4be Poul Sander 2025-02-03 21:28 955
        {
1193b4be Poul Sander 2025-02-03 21:28 956
            // [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 957
            const float half_inner_thickness = (thickness - AA_SIZE) * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 958
1193b4be Poul Sander 2025-02-03 21:28 959
            // 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 960
            if (!closed)
1193b4be Poul Sander 2025-02-03 21:28 961
            {
1193b4be Poul Sander 2025-02-03 21:28 962
                const int points_last = points_count - 1;
1193b4be Poul Sander 2025-02-03 21:28 963
                temp_points[0] = points[0] + temp_normals[0] * (half_inner_thickness + AA_SIZE);
1193b4be Poul Sander 2025-02-03 21:28 964
                temp_points[1] = points[0] + temp_normals[0] * (half_inner_thickness);
1193b4be Poul Sander 2025-02-03 21:28 965
                temp_points[2] = points[0] - temp_normals[0] * (half_inner_thickness);
1193b4be Poul Sander 2025-02-03 21:28 966
                temp_points[3] = points[0] - temp_normals[0] * (half_inner_thickness + AA_SIZE);
1193b4be Poul Sander 2025-02-03 21:28 967
                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 968
                temp_points[points_last * 4 + 1] = points[points_last] + temp_normals[points_last] * (half_inner_thickness);
1193b4be Poul Sander 2025-02-03 21:28 969
                temp_points[points_last * 4 + 2] = points[points_last] - temp_normals[points_last] * (half_inner_thickness);
1193b4be Poul Sander 2025-02-03 21:28 970
                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 971
            }
1193b4be Poul Sander 2025-02-03 21:28 972
1193b4be Poul Sander 2025-02-03 21:28 973
            // 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 974
            // 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 975
            // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer.
1193b4be Poul Sander 2025-02-03 21:28 976
            unsigned int idx1 = _VtxCurrentIdx; // Vertex index for start of line segment
1193b4be Poul Sander 2025-02-03 21:28 977
            for (int i1 = 0; i1 < count; i1++) // i1 is the first point of the line segment
1193b4be Poul Sander 2025-02-03 21:28 978
            {
1193b4be Poul Sander 2025-02-03 21:28 979
                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 980
                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 981
1193b4be Poul Sander 2025-02-03 21:28 982
                // Average normals
1193b4be Poul Sander 2025-02-03 21:28 983
                float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 984
                float dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 985
                IM_FIXNORMAL2F(dm_x, dm_y);
1193b4be Poul Sander 2025-02-03 21:28 986
                float dm_out_x = dm_x * (half_inner_thickness + AA_SIZE);
1193b4be Poul Sander 2025-02-03 21:28 987
                float dm_out_y = dm_y * (half_inner_thickness + AA_SIZE);
1193b4be Poul Sander 2025-02-03 21:28 988
                float dm_in_x = dm_x * half_inner_thickness;
1193b4be Poul Sander 2025-02-03 21:28 989
                float dm_in_y = dm_y * half_inner_thickness;
1193b4be Poul Sander 2025-02-03 21:28 990
1193b4be Poul Sander 2025-02-03 21:28 991
                // Add temporary vertices
1193b4be Poul Sander 2025-02-03 21:28 992
                ImVec2* out_vtx = &temp_points[i2 * 4];
1193b4be Poul Sander 2025-02-03 21:28 993
                out_vtx[0].x = points[i2].x + dm_out_x;
1193b4be Poul Sander 2025-02-03 21:28 994
                out_vtx[0].y = points[i2].y + dm_out_y;
1193b4be Poul Sander 2025-02-03 21:28 995
                out_vtx[1].x = points[i2].x + dm_in_x;
1193b4be Poul Sander 2025-02-03 21:28 996
                out_vtx[1].y = points[i2].y + dm_in_y;
1193b4be Poul Sander 2025-02-03 21:28 997
                out_vtx[2].x = points[i2].x - dm_in_x;
1193b4be Poul Sander 2025-02-03 21:28 998
                out_vtx[2].y = points[i2].y - dm_in_y;
1193b4be Poul Sander 2025-02-03 21:28 999
                out_vtx[3].x = points[i2].x - dm_out_x;
1193b4be Poul Sander 2025-02-03 21:28 1000
                out_vtx[3].y = points[i2].y - dm_out_y;
1193b4be Poul Sander 2025-02-03 21:28 1001
1193b4be Poul Sander 2025-02-03 21:28 1002
                // Add indexes
1193b4be Poul Sander 2025-02-03 21:28 1003
                _IdxWritePtr[0]  = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[1]  = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[2]  = (ImDrawIdx)(idx1 + 2);
1193b4be Poul Sander 2025-02-03 21:28 1004
                _IdxWritePtr[3]  = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[4]  = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[5]  = (ImDrawIdx)(idx2 + 1);
1193b4be Poul Sander 2025-02-03 21:28 1005
                _IdxWritePtr[6]  = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[7]  = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[8]  = (ImDrawIdx)(idx1 + 0);
1193b4be Poul Sander 2025-02-03 21:28 1006
                _IdxWritePtr[9]  = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[10] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[11] = (ImDrawIdx)(idx2 + 1);
1193b4be Poul Sander 2025-02-03 21:28 1007
                _IdxWritePtr[12] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[13] = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[14] = (ImDrawIdx)(idx1 + 3);
1193b4be Poul Sander 2025-02-03 21:28 1008
                _IdxWritePtr[15] = (ImDrawIdx)(idx1 + 3); _IdxWritePtr[16] = (ImDrawIdx)(idx2 + 3); _IdxWritePtr[17] = (ImDrawIdx)(idx2 + 2);
1193b4be Poul Sander 2025-02-03 21:28 1009
                _IdxWritePtr += 18;
1193b4be Poul Sander 2025-02-03 21:28 1010
1193b4be Poul Sander 2025-02-03 21:28 1011
                idx1 = idx2;
1193b4be Poul Sander 2025-02-03 21:28 1012
            }
1193b4be Poul Sander 2025-02-03 21:28 1013
1193b4be Poul Sander 2025-02-03 21:28 1014
            // Add vertices
1193b4be Poul Sander 2025-02-03 21:28 1015
            for (int i = 0; i < points_count; i++)
1193b4be Poul Sander 2025-02-03 21:28 1016
            {
1193b4be Poul Sander 2025-02-03 21:28 1017
                _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 1018
                _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 1019
                _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 1020
                _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 1021
                _VtxWritePtr += 4;
1193b4be Poul Sander 2025-02-03 21:28 1022
            }
1193b4be Poul Sander 2025-02-03 21:28 1023
        }
1193b4be Poul Sander 2025-02-03 21:28 1024
        _VtxCurrentIdx += (ImDrawIdx)vtx_count;
1193b4be Poul Sander 2025-02-03 21:28 1025
    }
1193b4be Poul Sander 2025-02-03 21:28 1026
    else
1193b4be Poul Sander 2025-02-03 21:28 1027
    {
1193b4be Poul Sander 2025-02-03 21:28 1028
        // [PATH 4] Non texture-based, Non anti-aliased lines
1193b4be Poul Sander 2025-02-03 21:28 1029
        const int idx_count = count * 6;
1193b4be Poul Sander 2025-02-03 21:28 1030
        const int vtx_count = count * 4;    // FIXME-OPT: Not sharing edges
1193b4be Poul Sander 2025-02-03 21:28 1031
        PrimReserve(idx_count, vtx_count);
1193b4be Poul Sander 2025-02-03 21:28 1032
1193b4be Poul Sander 2025-02-03 21:28 1033
        for (int i1 = 0; i1 < count; i1++)
1193b4be Poul Sander 2025-02-03 21:28 1034
        {
1193b4be Poul Sander 2025-02-03 21:28 1035
            const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1;
1193b4be Poul Sander 2025-02-03 21:28 1036
            const ImVec2& p1 = points[i1];
1193b4be Poul Sander 2025-02-03 21:28 1037
            const ImVec2& p2 = points[i2];
1193b4be Poul Sander 2025-02-03 21:28 1038
1193b4be Poul Sander 2025-02-03 21:28 1039
            float dx = p2.x - p1.x;
1193b4be Poul Sander 2025-02-03 21:28 1040
            float dy = p2.y - p1.y;
1193b4be Poul Sander 2025-02-03 21:28 1041
            IM_NORMALIZE2F_OVER_ZERO(dx, dy);
1193b4be Poul Sander 2025-02-03 21:28 1042
            dx *= (thickness * 0.5f);
1193b4be Poul Sander 2025-02-03 21:28 1043
            dy *= (thickness * 0.5f);
1193b4be Poul Sander 2025-02-03 21:28 1044
1193b4be Poul Sander 2025-02-03 21:28 1045
            _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 1046
            _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 1047
            _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 1048
            _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 1049
            _VtxWritePtr += 4;
1193b4be Poul Sander 2025-02-03 21:28 1050
1193b4be Poul Sander 2025-02-03 21:28 1051
            _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx + 1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx + 2);
1193b4be Poul Sander 2025-02-03 21:28 1052
            _IdxWritePtr[3] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[4] = (ImDrawIdx)(_VtxCurrentIdx + 2); _IdxWritePtr[5] = (ImDrawIdx)(_VtxCurrentIdx + 3);
1193b4be Poul Sander 2025-02-03 21:28 1053
            _IdxWritePtr += 6;
1193b4be Poul Sander 2025-02-03 21:28 1054
            _VtxCurrentIdx += 4;
1193b4be Poul Sander 2025-02-03 21:28 1055
        }
1193b4be Poul Sander 2025-02-03 21:28 1056
    }
1193b4be Poul Sander 2025-02-03 21:28 1057
}
1193b4be Poul Sander 2025-02-03 21:28 1058
1193b4be Poul Sander 2025-02-03 21:28 1059
// - 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 1060
// - 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 1061
void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_count, ImU32 col)
1193b4be Poul Sander 2025-02-03 21:28 1062
{
1193b4be Poul Sander 2025-02-03 21:28 1063
    if (points_count < 3 || (col & IM_COL32_A_MASK) == 0)
1193b4be Poul Sander 2025-02-03 21:28 1064
        return;
1193b4be Poul Sander 2025-02-03 21:28 1065
1193b4be Poul Sander 2025-02-03 21:28 1066
    const ImVec2 uv = _Data->TexUvWhitePixel;
1193b4be Poul Sander 2025-02-03 21:28 1067
1193b4be Poul Sander 2025-02-03 21:28 1068
    if (Flags & ImDrawListFlags_AntiAliasedFill)
1193b4be Poul Sander 2025-02-03 21:28 1069
    {
1193b4be Poul Sander 2025-02-03 21:28 1070
        // Anti-aliased Fill
1193b4be Poul Sander 2025-02-03 21:28 1071
        const float AA_SIZE = _FringeScale;
1193b4be Poul Sander 2025-02-03 21:28 1072
        const ImU32 col_trans = col & ~IM_COL32_A_MASK;
1193b4be Poul Sander 2025-02-03 21:28 1073
        const int idx_count = (points_count - 2)*3 + points_count * 6;
1193b4be Poul Sander 2025-02-03 21:28 1074
        const int vtx_count = (points_count * 2);
1193b4be Poul Sander 2025-02-03 21:28 1075
        PrimReserve(idx_count, vtx_count);
1193b4be Poul Sander 2025-02-03 21:28 1076
1193b4be Poul Sander 2025-02-03 21:28 1077
        // Add indexes for fill
1193b4be Poul Sander 2025-02-03 21:28 1078
        unsigned int vtx_inner_idx = _VtxCurrentIdx;
1193b4be Poul Sander 2025-02-03 21:28 1079
        unsigned int vtx_outer_idx = _VtxCurrentIdx + 1;
1193b4be Poul Sander 2025-02-03 21:28 1080
        for (int i = 2; i < points_count; i++)
1193b4be Poul Sander 2025-02-03 21:28 1081
        {
1193b4be Poul Sander 2025-02-03 21:28 1082
            _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 1083
            _IdxWritePtr += 3;
1193b4be Poul Sander 2025-02-03 21:28 1084
        }
1193b4be Poul Sander 2025-02-03 21:28 1085
1193b4be Poul Sander 2025-02-03 21:28 1086
        // Compute normals
1193b4be Poul Sander 2025-02-03 21:28 1087
        _Data->TempBuffer.reserve_discard(points_count);
1193b4be Poul Sander 2025-02-03 21:28 1088
        ImVec2* temp_normals = _Data->TempBuffer.Data;
1193b4be Poul Sander 2025-02-03 21:28 1089
        for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++)
1193b4be Poul Sander 2025-02-03 21:28 1090
        {
1193b4be Poul Sander 2025-02-03 21:28 1091
            const ImVec2& p0 = points[i0];
1193b4be Poul Sander 2025-02-03 21:28 1092
            const ImVec2& p1 = points[i1];
1193b4be Poul Sander 2025-02-03 21:28 1093
            float dx = p1.x - p0.x;
1193b4be Poul Sander 2025-02-03 21:28 1094
            float dy = p1.y - p0.y;
1193b4be Poul Sander 2025-02-03 21:28 1095
            IM_NORMALIZE2F_OVER_ZERO(dx, dy);
1193b4be Poul Sander 2025-02-03 21:28 1096
            temp_normals[i0].x = dy;
1193b4be Poul Sander 2025-02-03 21:28 1097
            temp_normals[i0].y = -dx;
1193b4be Poul Sander 2025-02-03 21:28 1098
        }
1193b4be Poul Sander 2025-02-03 21:28 1099
1193b4be Poul Sander 2025-02-03 21:28 1100
        for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++)
1193b4be Poul Sander 2025-02-03 21:28 1101
        {
1193b4be Poul Sander 2025-02-03 21:28 1102
            // Average normals
1193b4be Poul Sander 2025-02-03 21:28 1103
            const ImVec2& n0 = temp_normals[i0];
1193b4be Poul Sander 2025-02-03 21:28 1104
            const ImVec2& n1 = temp_normals[i1];
1193b4be Poul Sander 2025-02-03 21:28 1105
            float dm_x = (n0.x + n1.x) * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 1106
            float dm_y = (n0.y + n1.y) * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 1107
            IM_FIXNORMAL2F(dm_x, dm_y);
1193b4be Poul Sander 2025-02-03 21:28 1108
            dm_x *= AA_SIZE * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 1109
            dm_y *= AA_SIZE * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 1110
1193b4be Poul Sander 2025-02-03 21:28 1111
            // Add vertices
1193b4be Poul Sander 2025-02-03 21:28 1112
            _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 1113
            _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 1114
            _VtxWritePtr += 2;
1193b4be Poul Sander 2025-02-03 21:28 1115
1193b4be Poul Sander 2025-02-03 21:28 1116
            // Add indexes for fringes
1193b4be Poul Sander 2025-02-03 21:28 1117
            _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 1118
            _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 1119
            _IdxWritePtr += 6;
1193b4be Poul Sander 2025-02-03 21:28 1120
        }
1193b4be Poul Sander 2025-02-03 21:28 1121
        _VtxCurrentIdx += (ImDrawIdx)vtx_count;
1193b4be Poul Sander 2025-02-03 21:28 1122
    }
1193b4be Poul Sander 2025-02-03 21:28 1123
    else
1193b4be Poul Sander 2025-02-03 21:28 1124
    {
1193b4be Poul Sander 2025-02-03 21:28 1125
        // Non Anti-aliased Fill
1193b4be Poul Sander 2025-02-03 21:28 1126
        const int idx_count = (points_count - 2)*3;
1193b4be Poul Sander 2025-02-03 21:28 1127
        const int vtx_count = points_count;
1193b4be Poul Sander 2025-02-03 21:28 1128
        PrimReserve(idx_count, vtx_count);
1193b4be Poul Sander 2025-02-03 21:28 1129
        for (int i = 0; i < vtx_count; i++)
1193b4be Poul Sander 2025-02-03 21:28 1130
        {
1193b4be Poul Sander 2025-02-03 21:28 1131
            _VtxWritePtr[0].pos = points[i]; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;
1193b4be Poul Sander 2025-02-03 21:28 1132
            _VtxWritePtr++;
1193b4be Poul Sander 2025-02-03 21:28 1133
        }
1193b4be Poul Sander 2025-02-03 21:28 1134
        for (int i = 2; i < points_count; i++)
1193b4be Poul Sander 2025-02-03 21:28 1135
        {
1193b4be Poul Sander 2025-02-03 21:28 1136
            _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx + i - 1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx + i);
1193b4be Poul Sander 2025-02-03 21:28 1137
            _IdxWritePtr += 3;
1193b4be Poul Sander 2025-02-03 21:28 1138
        }
1193b4be Poul Sander 2025-02-03 21:28 1139
        _VtxCurrentIdx += (ImDrawIdx)vtx_count;
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
1193b4be Poul Sander 2025-02-03 21:28 1143
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 1144
{
1193b4be Poul Sander 2025-02-03 21:28 1145
    if (radius < 0.5f)
1193b4be Poul Sander 2025-02-03 21:28 1146
    {
1193b4be Poul Sander 2025-02-03 21:28 1147
        _Path.push_back(center);
1193b4be Poul Sander 2025-02-03 21:28 1148
        return;
1193b4be Poul Sander 2025-02-03 21:28 1149
    }
1193b4be Poul Sander 2025-02-03 21:28 1150
1193b4be Poul Sander 2025-02-03 21:28 1151
    // Calculate arc auto segment step size
1193b4be Poul Sander 2025-02-03 21:28 1152
    if (a_step <= 0)
1193b4be Poul Sander 2025-02-03 21:28 1153
        a_step = IM_DRAWLIST_ARCFAST_SAMPLE_MAX / _CalcCircleAutoSegmentCount(radius);
1193b4be Poul Sander 2025-02-03 21:28 1154
1193b4be Poul Sander 2025-02-03 21:28 1155
    // Make sure we never do steps larger than one quarter of the circle
1193b4be Poul Sander 2025-02-03 21:28 1156
    a_step = ImClamp(a_step, 1, IM_DRAWLIST_ARCFAST_TABLE_SIZE / 4);
1193b4be Poul Sander 2025-02-03 21:28 1157
1193b4be Poul Sander 2025-02-03 21:28 1158
    const int sample_range = ImAbs(a_max_sample - a_min_sample);
1193b4be Poul Sander 2025-02-03 21:28 1159
    const int a_next_step = a_step;
1193b4be Poul Sander 2025-02-03 21:28 1160
1193b4be Poul Sander 2025-02-03 21:28 1161
    int samples = sample_range + 1;
1193b4be Poul Sander 2025-02-03 21:28 1162
    bool extra_max_sample = false;
1193b4be Poul Sander 2025-02-03 21:28 1163
    if (a_step > 1)
1193b4be Poul Sander 2025-02-03 21:28 1164
    {
1193b4be Poul Sander 2025-02-03 21:28 1165
        samples            = sample_range / a_step + 1;
1193b4be Poul Sander 2025-02-03 21:28 1166
        const int overstep = sample_range % a_step;
1193b4be Poul Sander 2025-02-03 21:28 1167
1193b4be Poul Sander 2025-02-03 21:28 1168
        if (overstep > 0)
1193b4be Poul Sander 2025-02-03 21:28 1169
        {
1193b4be Poul Sander 2025-02-03 21:28 1170
            extra_max_sample = true;
1193b4be Poul Sander 2025-02-03 21:28 1171
            samples++;
1193b4be Poul Sander 2025-02-03 21:28 1172
1193b4be Poul Sander 2025-02-03 21:28 1173
            // 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 1174
            // distribute first step range evenly between them by reducing first step size.
1193b4be Poul Sander 2025-02-03 21:28 1175
            if (sample_range > 0)
1193b4be Poul Sander 2025-02-03 21:28 1176
                a_step -= (a_step - overstep) / 2;
1193b4be Poul Sander 2025-02-03 21:28 1177
        }
1193b4be Poul Sander 2025-02-03 21:28 1178
    }
1193b4be Poul Sander 2025-02-03 21:28 1179
1193b4be Poul Sander 2025-02-03 21:28 1180
    _Path.resize(_Path.Size + samples);
1193b4be Poul Sander 2025-02-03 21:28 1181
    ImVec2* out_ptr = _Path.Data + (_Path.Size - samples);
1193b4be Poul Sander 2025-02-03 21:28 1182
1193b4be Poul Sander 2025-02-03 21:28 1183
    int sample_index = a_min_sample;
1193b4be Poul Sander 2025-02-03 21:28 1184
    if (sample_index < 0 || sample_index >= IM_DRAWLIST_ARCFAST_SAMPLE_MAX)
1193b4be Poul Sander 2025-02-03 21:28 1185
    {
1193b4be Poul Sander 2025-02-03 21:28 1186
        sample_index = sample_index % IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
1193b4be Poul Sander 2025-02-03 21:28 1187
        if (sample_index < 0)
1193b4be Poul Sander 2025-02-03 21:28 1188
            sample_index += IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
1193b4be Poul Sander 2025-02-03 21:28 1189
    }
1193b4be Poul Sander 2025-02-03 21:28 1190
1193b4be Poul Sander 2025-02-03 21:28 1191
    if (a_max_sample >= a_min_sample)
1193b4be Poul Sander 2025-02-03 21:28 1192
    {
1193b4be Poul Sander 2025-02-03 21:28 1193
        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 1194
        {
1193b4be Poul Sander 2025-02-03 21:28 1195
            // 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 1196
            if (sample_index >= IM_DRAWLIST_ARCFAST_SAMPLE_MAX)
1193b4be Poul Sander 2025-02-03 21:28 1197
                sample_index -= IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
1193b4be Poul Sander 2025-02-03 21:28 1198
1193b4be Poul Sander 2025-02-03 21:28 1199
            const ImVec2 s = _Data->ArcFastVtx[sample_index];
1193b4be Poul Sander 2025-02-03 21:28 1200
            out_ptr->x = center.x + s.x * radius;
1193b4be Poul Sander 2025-02-03 21:28 1201
            out_ptr->y = center.y + s.y * radius;
1193b4be Poul Sander 2025-02-03 21:28 1202
            out_ptr++;
1193b4be Poul Sander 2025-02-03 21:28 1203
        }
1193b4be Poul Sander 2025-02-03 21:28 1204
    }
1193b4be Poul Sander 2025-02-03 21:28 1205
    else
1193b4be Poul Sander 2025-02-03 21:28 1206
    {
1193b4be Poul Sander 2025-02-03 21:28 1207
        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 1208
        {
1193b4be Poul Sander 2025-02-03 21:28 1209
            // 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 1210
            if (sample_index < 0)
1193b4be Poul Sander 2025-02-03 21:28 1211
                sample_index += IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
1193b4be Poul Sander 2025-02-03 21:28 1212
1193b4be Poul Sander 2025-02-03 21:28 1213
            const ImVec2 s = _Data->ArcFastVtx[sample_index];
1193b4be Poul Sander 2025-02-03 21:28 1214
            out_ptr->x = center.x + s.x * radius;
1193b4be Poul Sander 2025-02-03 21:28 1215
            out_ptr->y = center.y + s.y * radius;
1193b4be Poul Sander 2025-02-03 21:28 1216
            out_ptr++;
1193b4be Poul Sander 2025-02-03 21:28 1217
        }
1193b4be Poul Sander 2025-02-03 21:28 1218
    }
1193b4be Poul Sander 2025-02-03 21:28 1219
1193b4be Poul Sander 2025-02-03 21:28 1220
    if (extra_max_sample)
1193b4be Poul Sander 2025-02-03 21:28 1221
    {
1193b4be Poul Sander 2025-02-03 21:28 1222
        int normalized_max_sample = a_max_sample % IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
1193b4be Poul Sander 2025-02-03 21:28 1223
        if (normalized_max_sample < 0)
1193b4be Poul Sander 2025-02-03 21:28 1224
            normalized_max_sample += IM_DRAWLIST_ARCFAST_SAMPLE_MAX;
1193b4be Poul Sander 2025-02-03 21:28 1225
1193b4be Poul Sander 2025-02-03 21:28 1226
        const ImVec2 s = _Data->ArcFastVtx[normalized_max_sample];
1193b4be Poul Sander 2025-02-03 21:28 1227
        out_ptr->x = center.x + s.x * radius;
1193b4be Poul Sander 2025-02-03 21:28 1228
        out_ptr->y = center.y + s.y * radius;
1193b4be Poul Sander 2025-02-03 21:28 1229
        out_ptr++;
1193b4be Poul Sander 2025-02-03 21:28 1230
    }
1193b4be Poul Sander 2025-02-03 21:28 1231
1193b4be Poul Sander 2025-02-03 21:28 1232
    IM_ASSERT_PARANOID(_Path.Data + _Path.Size == out_ptr);
1193b4be Poul Sander 2025-02-03 21:28 1233
}
1193b4be Poul Sander 2025-02-03 21:28 1234
1193b4be Poul Sander 2025-02-03 21:28 1235
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 1236
{
1193b4be Poul Sander 2025-02-03 21:28 1237
    if (radius < 0.5f)
1193b4be Poul Sander 2025-02-03 21:28 1238
    {
1193b4be Poul Sander 2025-02-03 21:28 1239
        _Path.push_back(center);
1193b4be Poul Sander 2025-02-03 21:28 1240
        return;
1193b4be Poul Sander 2025-02-03 21:28 1241
    }
1193b4be Poul Sander 2025-02-03 21:28 1242
1193b4be Poul Sander 2025-02-03 21:28 1243
    // Note that we are adding a point at both a_min and a_max.
1193b4be Poul Sander 2025-02-03 21:28 1244
    // 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 1245
    _Path.reserve(_Path.Size + (num_segments + 1));
1193b4be Poul Sander 2025-02-03 21:28 1246
    for (int i = 0; i <= num_segments; i++)
1193b4be Poul Sander 2025-02-03 21:28 1247
    {
1193b4be Poul Sander 2025-02-03 21:28 1248
        const float a = a_min + ((float)i / (float)num_segments) * (a_max - a_min);
1193b4be Poul Sander 2025-02-03 21:28 1249
        _Path.push_back(ImVec2(center.x + ImCos(a) * radius, center.y + ImSin(a) * radius));
1193b4be Poul Sander 2025-02-03 21:28 1250
    }
1193b4be Poul Sander 2025-02-03 21:28 1251
}
1193b4be Poul Sander 2025-02-03 21:28 1252
1193b4be Poul Sander 2025-02-03 21:28 1253
// 0: East, 3: South, 6: West, 9: North, 12: East
1193b4be Poul Sander 2025-02-03 21:28 1254
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 1255
{
1193b4be Poul Sander 2025-02-03 21:28 1256
    if (radius < 0.5f)
1193b4be Poul Sander 2025-02-03 21:28 1257
    {
1193b4be Poul Sander 2025-02-03 21:28 1258
        _Path.push_back(center);
1193b4be Poul Sander 2025-02-03 21:28 1259
        return;
1193b4be Poul Sander 2025-02-03 21:28 1260
    }
1193b4be Poul Sander 2025-02-03 21:28 1261
    _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 1262
}
1193b4be Poul Sander 2025-02-03 21:28 1263
1193b4be Poul Sander 2025-02-03 21:28 1264
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 1265
{
1193b4be Poul Sander 2025-02-03 21:28 1266
    if (radius < 0.5f)
1193b4be Poul Sander 2025-02-03 21:28 1267
    {
1193b4be Poul Sander 2025-02-03 21:28 1268
        _Path.push_back(center);
1193b4be Poul Sander 2025-02-03 21:28 1269
        return;
1193b4be Poul Sander 2025-02-03 21:28 1270
    }
1193b4be Poul Sander 2025-02-03 21:28 1271
1193b4be Poul Sander 2025-02-03 21:28 1272
    if (num_segments > 0)
1193b4be Poul Sander 2025-02-03 21:28 1273
    {
1193b4be Poul Sander 2025-02-03 21:28 1274
        _PathArcToN(center, radius, a_min, a_max, num_segments);
1193b4be Poul Sander 2025-02-03 21:28 1275
        return;
1193b4be Poul Sander 2025-02-03 21:28 1276
    }
1193b4be Poul Sander 2025-02-03 21:28 1277
1193b4be Poul Sander 2025-02-03 21:28 1278
    // Automatic segment count
1193b4be Poul Sander 2025-02-03 21:28 1279
    if (radius <= _Data->ArcFastRadiusCutoff)
1193b4be Poul Sander 2025-02-03 21:28 1280
    {
1193b4be Poul Sander 2025-02-03 21:28 1281
        const bool a_is_reverse = a_max < a_min;
1193b4be Poul Sander 2025-02-03 21:28 1282
1193b4be Poul Sander 2025-02-03 21:28 1283
        // We are going to use precomputed values for mid samples.
1193b4be Poul Sander 2025-02-03 21:28 1284
        // Determine first and last sample in lookup table that belong to the arc.
1193b4be Poul Sander 2025-02-03 21:28 1285
        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 1286
        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 1287
1193b4be Poul Sander 2025-02-03 21:28 1288
        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 1289
        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 1290
        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 1291
1193b4be Poul Sander 2025-02-03 21:28 1292
        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 1293
        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 1294
        const bool a_emit_start = ImAbs(a_min_segment_angle - a_min) >= 1e-5f;
1193b4be Poul Sander 2025-02-03 21:28 1295
        const bool a_emit_end = ImAbs(a_max - a_max_segment_angle) >= 1e-5f;
1193b4be Poul Sander 2025-02-03 21:28 1296
1193b4be Poul Sander 2025-02-03 21:28 1297
        _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 1298
        if (a_emit_start)
1193b4be Poul Sander 2025-02-03 21:28 1299
            _Path.push_back(ImVec2(center.x + ImCos(a_min) * radius, center.y + ImSin(a_min) * radius));
1193b4be Poul Sander 2025-02-03 21:28 1300
        if (a_mid_samples > 0)
1193b4be Poul Sander 2025-02-03 21:28 1301
            _PathArcToFastEx(center, radius, a_min_sample, a_max_sample, 0);
1193b4be Poul Sander 2025-02-03 21:28 1302
        if (a_emit_end)
1193b4be Poul Sander 2025-02-03 21:28 1303
            _Path.push_back(ImVec2(center.x + ImCos(a_max) * radius, center.y + ImSin(a_max) * radius));
1193b4be Poul Sander 2025-02-03 21:28 1304
    }
1193b4be Poul Sander 2025-02-03 21:28 1305
    else
1193b4be Poul Sander 2025-02-03 21:28 1306
    {
1193b4be Poul Sander 2025-02-03 21:28 1307
        const float arc_length = ImAbs(a_max - a_min);
1193b4be Poul Sander 2025-02-03 21:28 1308
        const int circle_segment_count = _CalcCircleAutoSegmentCount(radius);
1193b4be Poul Sander 2025-02-03 21:28 1309
        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 1310
        _PathArcToN(center, radius, a_min, a_max, arc_segment_count);
1193b4be Poul Sander 2025-02-03 21:28 1311
    }
1193b4be Poul Sander 2025-02-03 21:28 1312
}
1193b4be Poul Sander 2025-02-03 21:28 1313
1193b4be Poul Sander 2025-02-03 21:28 1314
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 1315
{
1193b4be Poul Sander 2025-02-03 21:28 1316
    if (num_segments <= 0)
1193b4be Poul Sander 2025-02-03 21:28 1317
        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 1318
1193b4be Poul Sander 2025-02-03 21:28 1319
    _Path.reserve(_Path.Size + (num_segments + 1));
1193b4be Poul Sander 2025-02-03 21:28 1320
1193b4be Poul Sander 2025-02-03 21:28 1321
    const float cos_rot = ImCos(rot);
1193b4be Poul Sander 2025-02-03 21:28 1322
    const float sin_rot = ImSin(rot);
1193b4be Poul Sander 2025-02-03 21:28 1323
    for (int i = 0; i <= num_segments; i++)
1193b4be Poul Sander 2025-02-03 21:28 1324
    {
1193b4be Poul Sander 2025-02-03 21:28 1325
        const float a = a_min + ((float)i / (float)num_segments) * (a_max - a_min);
1193b4be Poul Sander 2025-02-03 21:28 1326
        ImVec2 point(ImCos(a) * radius.x, ImSin(a) * radius.y);
1193b4be Poul Sander 2025-02-03 21:28 1327
        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 1328
        point.x = rel.x + center.x;
1193b4be Poul Sander 2025-02-03 21:28 1329
        point.y = rel.y + center.y;
1193b4be Poul Sander 2025-02-03 21:28 1330
        _Path.push_back(point);
1193b4be Poul Sander 2025-02-03 21:28 1331
    }
1193b4be Poul Sander 2025-02-03 21:28 1332
}
1193b4be Poul Sander 2025-02-03 21:28 1333
1193b4be Poul Sander 2025-02-03 21:28 1334
ImVec2 ImBezierCubicCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, float t)
1193b4be Poul Sander 2025-02-03 21:28 1335
{
1193b4be Poul Sander 2025-02-03 21:28 1336
    float u = 1.0f - t;
1193b4be Poul Sander 2025-02-03 21:28 1337
    float w1 = u * u * u;
1193b4be Poul Sander 2025-02-03 21:28 1338
    float w2 = 3 * u * u * t;
1193b4be Poul Sander 2025-02-03 21:28 1339
    float w3 = 3 * u * t * t;
1193b4be Poul Sander 2025-02-03 21:28 1340
    float w4 = t * t * t;
1193b4be Poul Sander 2025-02-03 21:28 1341
    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 1342
}
1193b4be Poul Sander 2025-02-03 21:28 1343
1193b4be Poul Sander 2025-02-03 21:28 1344
ImVec2 ImBezierQuadraticCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float t)
1193b4be Poul Sander 2025-02-03 21:28 1345
{
1193b4be Poul Sander 2025-02-03 21:28 1346
    float u = 1.0f - t;
1193b4be Poul Sander 2025-02-03 21:28 1347
    float w1 = u * u;
1193b4be Poul Sander 2025-02-03 21:28 1348
    float w2 = 2 * u * t;
1193b4be Poul Sander 2025-02-03 21:28 1349
    float w3 = t * t;
1193b4be Poul Sander 2025-02-03 21:28 1350
    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 1351
}
1193b4be Poul Sander 2025-02-03 21:28 1352
1193b4be Poul Sander 2025-02-03 21:28 1353
// Closely mimics ImBezierCubicClosestPointCasteljau() in imgui.cpp
1193b4be Poul Sander 2025-02-03 21:28 1354
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 1355
{
1193b4be Poul Sander 2025-02-03 21:28 1356
    float dx = x4 - x1;
1193b4be Poul Sander 2025-02-03 21:28 1357
    float dy = y4 - y1;
1193b4be Poul Sander 2025-02-03 21:28 1358
    float d2 = (x2 - x4) * dy - (y2 - y4) * dx;
1193b4be Poul Sander 2025-02-03 21:28 1359
    float d3 = (x3 - x4) * dy - (y3 - y4) * dx;
1193b4be Poul Sander 2025-02-03 21:28 1360
    d2 = (d2 >= 0) ? d2 : -d2;
1193b4be Poul Sander 2025-02-03 21:28 1361
    d3 = (d3 >= 0) ? d3 : -d3;
1193b4be Poul Sander 2025-02-03 21:28 1362
    if ((d2 + d3) * (d2 + d3) < tess_tol * (dx * dx + dy * dy))
1193b4be Poul Sander 2025-02-03 21:28 1363
    {
1193b4be Poul Sander 2025-02-03 21:28 1364
        path->push_back(ImVec2(x4, y4));
1193b4be Poul Sander 2025-02-03 21:28 1365
    }
1193b4be Poul Sander 2025-02-03 21:28 1366
    else if (level < 10)
1193b4be Poul Sander 2025-02-03 21:28 1367
    {
1193b4be Poul Sander 2025-02-03 21:28 1368
        float x12 = (x1 + x2) * 0.5f, y12 = (y1 + y2) * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 1369
        float x23 = (x2 + x3) * 0.5f, y23 = (y2 + y3) * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 1370
        float x34 = (x3 + x4) * 0.5f, y34 = (y3 + y4) * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 1371
        float x123 = (x12 + x23) * 0.5f, y123 = (y12 + y23) * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 1372
        float x234 = (x23 + x34) * 0.5f, y234 = (y23 + y34) * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 1373
        float x1234 = (x123 + x234) * 0.5f, y1234 = (y123 + y234) * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 1374
        PathBezierCubicCurveToCasteljau(path, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1);
1193b4be Poul Sander 2025-02-03 21:28 1375
        PathBezierCubicCurveToCasteljau(path, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1);
1193b4be Poul Sander 2025-02-03 21:28 1376
    }
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
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 1380
{
1193b4be Poul Sander 2025-02-03 21:28 1381
    float dx = x3 - x1, dy = y3 - y1;
1193b4be Poul Sander 2025-02-03 21:28 1382
    float det = (x2 - x3) * dy - (y2 - y3) * dx;
1193b4be Poul Sander 2025-02-03 21:28 1383
    if (det * det * 4.0f < tess_tol * (dx * dx + dy * dy))
1193b4be Poul Sander 2025-02-03 21:28 1384
    {
1193b4be Poul Sander 2025-02-03 21:28 1385
        path->push_back(ImVec2(x3, y3));
1193b4be Poul Sander 2025-02-03 21:28 1386
    }
1193b4be Poul Sander 2025-02-03 21:28 1387
    else if (level < 10)
1193b4be Poul Sander 2025-02-03 21:28 1388
    {
1193b4be Poul Sander 2025-02-03 21:28 1389
        float x12 = (x1 + x2) * 0.5f, y12 = (y1 + y2) * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 1390
        float x23 = (x2 + x3) * 0.5f, y23 = (y2 + y3) * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 1391
        float x123 = (x12 + x23) * 0.5f, y123 = (y12 + y23) * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 1392
        PathBezierQuadraticCurveToCasteljau(path, x1, y1, x12, y12, x123, y123, tess_tol, level + 1);
1193b4be Poul Sander 2025-02-03 21:28 1393
        PathBezierQuadraticCurveToCasteljau(path, x123, y123, x23, y23, x3, y3, tess_tol, level + 1);
1193b4be Poul Sander 2025-02-03 21:28 1394
    }
1193b4be Poul Sander 2025-02-03 21:28 1395
}
1193b4be Poul Sander 2025-02-03 21:28 1396
1193b4be Poul Sander 2025-02-03 21:28 1397
void ImDrawList::PathBezierCubicCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments)
1193b4be Poul Sander 2025-02-03 21:28 1398
{
1193b4be Poul Sander 2025-02-03 21:28 1399
    ImVec2 p1 = _Path.back();
1193b4be Poul Sander 2025-02-03 21:28 1400
    if (num_segments == 0)
1193b4be Poul Sander 2025-02-03 21:28 1401
    {
1193b4be Poul Sander 2025-02-03 21:28 1402
        IM_ASSERT(_Data->CurveTessellationTol > 0.0f);
1193b4be Poul Sander 2025-02-03 21:28 1403
        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 1404
    }
1193b4be Poul Sander 2025-02-03 21:28 1405
    else
1193b4be Poul Sander 2025-02-03 21:28 1406
    {
1193b4be Poul Sander 2025-02-03 21:28 1407
        float t_step = 1.0f / (float)num_segments;
1193b4be Poul Sander 2025-02-03 21:28 1408
        for (int i_step = 1; i_step <= num_segments; i_step++)
1193b4be Poul Sander 2025-02-03 21:28 1409
            _Path.push_back(ImBezierCubicCalc(p1, p2, p3, p4, t_step * i_step));
1193b4be Poul Sander 2025-02-03 21:28 1410
    }
1193b4be Poul Sander 2025-02-03 21:28 1411
}
1193b4be Poul Sander 2025-02-03 21:28 1412
1193b4be Poul Sander 2025-02-03 21:28 1413
void ImDrawList::PathBezierQuadraticCurveTo(const ImVec2& p2, const ImVec2& p3, int num_segments)
1193b4be Poul Sander 2025-02-03 21:28 1414
{
1193b4be Poul Sander 2025-02-03 21:28 1415
    ImVec2 p1 = _Path.back();
1193b4be Poul Sander 2025-02-03 21:28 1416
    if (num_segments == 0)
1193b4be Poul Sander 2025-02-03 21:28 1417
    {
1193b4be Poul Sander 2025-02-03 21:28 1418
        IM_ASSERT(_Data->CurveTessellationTol > 0.0f);
1193b4be Poul Sander 2025-02-03 21:28 1419
        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 1420
    }
1193b4be Poul Sander 2025-02-03 21:28 1421
    else
1193b4be Poul Sander 2025-02-03 21:28 1422
    {
1193b4be Poul Sander 2025-02-03 21:28 1423
        float t_step = 1.0f / (float)num_segments;
1193b4be Poul Sander 2025-02-03 21:28 1424
        for (int i_step = 1; i_step <= num_segments; i_step++)
1193b4be Poul Sander 2025-02-03 21:28 1425
            _Path.push_back(ImBezierQuadraticCalc(p1, p2, p3, t_step * i_step));
1193b4be Poul Sander 2025-02-03 21:28 1426
    }
1193b4be Poul Sander 2025-02-03 21:28 1427
}
1193b4be Poul Sander 2025-02-03 21:28 1428
1193b4be Poul Sander 2025-02-03 21:28 1429
static inline ImDrawFlags FixRectCornerFlags(ImDrawFlags flags)
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
    IM_STATIC_ASSERT(ImDrawFlags_RoundCornersTopLeft == (1 << 4));
1193b4be Poul Sander 2025-02-03 21:28 1433
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
1193b4be Poul Sander 2025-02-03 21:28 1434
    // 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 1435
    // - Legacy Support for hard coded ~0 (used to be a suggested equivalent to ImDrawCornerFlags_All)
1193b4be Poul Sander 2025-02-03 21:28 1436
    if (flags == ~0)                    { return ImDrawFlags_RoundCornersAll; }
1193b4be Poul Sander 2025-02-03 21:28 1437
    // - 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 1438
    if (flags >= 0x01 && flags <= 0x0F) { return (flags << 4); }
1193b4be Poul Sander 2025-02-03 21:28 1439
    // 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 1440
#endif
1193b4be Poul Sander 2025-02-03 21:28 1441
    */
1193b4be Poul Sander 2025-02-03 21:28 1442
    // If this assert triggers, please update your code replacing hardcoded values with new ImDrawFlags_RoundCorners* values.
1193b4be Poul Sander 2025-02-03 21:28 1443
    // Note that ImDrawFlags_Closed (== 0x01) is an invalid flag for AddRect(), AddRectFilled(), PathRect() etc. anyway.
1193b4be Poul Sander 2025-02-03 21:28 1444
    // 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 1445
    IM_ASSERT((flags & 0x0F) == 0 && "Misuse of legacy hardcoded ImDrawCornerFlags values!");
1193b4be Poul Sander 2025-02-03 21:28 1446
1193b4be Poul Sander 2025-02-03 21:28 1447
    if ((flags & ImDrawFlags_RoundCornersMask_) == 0)
1193b4be Poul Sander 2025-02-03 21:28 1448
        flags |= ImDrawFlags_RoundCornersAll;
1193b4be Poul Sander 2025-02-03 21:28 1449
1193b4be Poul Sander 2025-02-03 21:28 1450
    return flags;
1193b4be Poul Sander 2025-02-03 21:28 1451
}
1193b4be Poul Sander 2025-02-03 21:28 1452
1193b4be Poul Sander 2025-02-03 21:28 1453
void ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, ImDrawFlags flags)
1193b4be Poul Sander 2025-02-03 21:28 1454
{
1193b4be Poul Sander 2025-02-03 21:28 1455
    if (rounding >= 0.5f)
1193b4be Poul Sander 2025-02-03 21:28 1456
    {
1193b4be Poul Sander 2025-02-03 21:28 1457
        flags = FixRectCornerFlags(flags);
1193b4be Poul Sander 2025-02-03 21:28 1458
        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 1459
        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 1460
    }
1193b4be Poul Sander 2025-02-03 21:28 1461
    if (rounding < 0.5f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone)
1193b4be Poul Sander 2025-02-03 21:28 1462
    {
1193b4be Poul Sander 2025-02-03 21:28 1463
        PathLineTo(a);
1193b4be Poul Sander 2025-02-03 21:28 1464
        PathLineTo(ImVec2(b.x, a.y));
1193b4be Poul Sander 2025-02-03 21:28 1465
        PathLineTo(b);
1193b4be Poul Sander 2025-02-03 21:28 1466
        PathLineTo(ImVec2(a.x, b.y));
1193b4be Poul Sander 2025-02-03 21:28 1467
    }
1193b4be Poul Sander 2025-02-03 21:28 1468
    else
1193b4be Poul Sander 2025-02-03 21:28 1469
    {
1193b4be Poul Sander 2025-02-03 21:28 1470
        const float rounding_tl = (flags & ImDrawFlags_RoundCornersTopLeft)     ? rounding : 0.0f;
1193b4be Poul Sander 2025-02-03 21:28 1471
        const float rounding_tr = (flags & ImDrawFlags_RoundCornersTopRight)    ? rounding : 0.0f;
1193b4be Poul Sander 2025-02-03 21:28 1472
        const float rounding_br = (flags & ImDrawFlags_RoundCornersBottomRight) ? rounding : 0.0f;
1193b4be Poul Sander 2025-02-03 21:28 1473
        const float rounding_bl = (flags & ImDrawFlags_RoundCornersBottomLeft)  ? rounding : 0.0f;
1193b4be Poul Sander 2025-02-03 21:28 1474
        PathArcToFast(ImVec2(a.x + rounding_tl, a.y + rounding_tl), rounding_tl, 6, 9);
1193b4be Poul Sander 2025-02-03 21:28 1475
        PathArcToFast(ImVec2(b.x - rounding_tr, a.y + rounding_tr), rounding_tr, 9, 12);
1193b4be Poul Sander 2025-02-03 21:28 1476
        PathArcToFast(ImVec2(b.x - rounding_br, b.y - rounding_br), rounding_br, 0, 3);
1193b4be Poul Sander 2025-02-03 21:28 1477
        PathArcToFast(ImVec2(a.x + rounding_bl, b.y - rounding_bl), rounding_bl, 3, 6);
1193b4be Poul Sander 2025-02-03 21:28 1478
    }
1193b4be Poul Sander 2025-02-03 21:28 1479
}
1193b4be Poul Sander 2025-02-03 21:28 1480
1193b4be Poul Sander 2025-02-03 21:28 1481
void ImDrawList::AddLine(const ImVec2& p1, const ImVec2& p2, ImU32 col, float thickness)
1193b4be Poul Sander 2025-02-03 21:28 1482
{
1193b4be Poul Sander 2025-02-03 21:28 1483
    if ((col & IM_COL32_A_MASK) == 0)
1193b4be Poul Sander 2025-02-03 21:28 1484
        return;
1193b4be Poul Sander 2025-02-03 21:28 1485
    PathLineTo(p1 + ImVec2(0.5f, 0.5f));
1193b4be Poul Sander 2025-02-03 21:28 1486
    PathLineTo(p2 + ImVec2(0.5f, 0.5f));
1193b4be Poul Sander 2025-02-03 21:28 1487
    PathStroke(col, 0, thickness);
1193b4be Poul Sander 2025-02-03 21:28 1488
}
1193b4be Poul Sander 2025-02-03 21:28 1489
1193b4be Poul Sander 2025-02-03 21:28 1490
// p_min = upper-left, p_max = lower-right
1193b4be Poul Sander 2025-02-03 21:28 1491
// Note we don't render 1 pixels sized rectangles properly.
1193b4be Poul Sander 2025-02-03 21:28 1492
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 1493
{
1193b4be Poul Sander 2025-02-03 21:28 1494
    if ((col & IM_COL32_A_MASK) == 0)
1193b4be Poul Sander 2025-02-03 21:28 1495
        return;
1193b4be Poul Sander 2025-02-03 21:28 1496
    if (Flags & ImDrawListFlags_AntiAliasedLines)
1193b4be Poul Sander 2025-02-03 21:28 1497
        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 1498
    else
1193b4be Poul Sander 2025-02-03 21:28 1499
        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 1500
    PathStroke(col, ImDrawFlags_Closed, thickness);
1193b4be Poul Sander 2025-02-03 21:28 1501
}
1193b4be Poul Sander 2025-02-03 21:28 1502
1193b4be Poul Sander 2025-02-03 21:28 1503
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 1504
{
1193b4be Poul Sander 2025-02-03 21:28 1505
    if ((col & IM_COL32_A_MASK) == 0)
1193b4be Poul Sander 2025-02-03 21:28 1506
        return;
1193b4be Poul Sander 2025-02-03 21:28 1507
    if (rounding < 0.5f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone)
1193b4be Poul Sander 2025-02-03 21:28 1508
    {
1193b4be Poul Sander 2025-02-03 21:28 1509
        PrimReserve(6, 4);
1193b4be Poul Sander 2025-02-03 21:28 1510
        PrimRect(p_min, p_max, col);
1193b4be Poul Sander 2025-02-03 21:28 1511
    }
1193b4be Poul Sander 2025-02-03 21:28 1512
    else
1193b4be Poul Sander 2025-02-03 21:28 1513
    {
1193b4be Poul Sander 2025-02-03 21:28 1514
        PathRect(p_min, p_max, rounding, flags);
1193b4be Poul Sander 2025-02-03 21:28 1515
        PathFillConvex(col);
1193b4be Poul Sander 2025-02-03 21:28 1516
    }
1193b4be Poul Sander 2025-02-03 21:28 1517
}
1193b4be Poul Sander 2025-02-03 21:28 1518
1193b4be Poul Sander 2025-02-03 21:28 1519
// p_min = upper-left, p_max = lower-right
1193b4be Poul Sander 2025-02-03 21:28 1520
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 1521
{
1193b4be Poul Sander 2025-02-03 21:28 1522
    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 1523
        return;
1193b4be Poul Sander 2025-02-03 21:28 1524
1193b4be Poul Sander 2025-02-03 21:28 1525
    const ImVec2 uv = _Data->TexUvWhitePixel;
1193b4be Poul Sander 2025-02-03 21:28 1526
    PrimReserve(6, 4);
1193b4be Poul Sander 2025-02-03 21:28 1527
    PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 1)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 2));
1193b4be Poul Sander 2025-02-03 21:28 1528
    PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 2)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 3));
1193b4be Poul Sander 2025-02-03 21:28 1529
    PrimWriteVtx(p_min, uv, col_upr_left);
1193b4be Poul Sander 2025-02-03 21:28 1530
    PrimWriteVtx(ImVec2(p_max.x, p_min.y), uv, col_upr_right);
1193b4be Poul Sander 2025-02-03 21:28 1531
    PrimWriteVtx(p_max, uv, col_bot_right);
1193b4be Poul Sander 2025-02-03 21:28 1532
    PrimWriteVtx(ImVec2(p_min.x, p_max.y), uv, col_bot_left);
1193b4be Poul Sander 2025-02-03 21:28 1533
}
1193b4be Poul Sander 2025-02-03 21:28 1534
1193b4be Poul Sander 2025-02-03 21:28 1535
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 1536
{
1193b4be Poul Sander 2025-02-03 21:28 1537
    if ((col & IM_COL32_A_MASK) == 0)
1193b4be Poul Sander 2025-02-03 21:28 1538
        return;
1193b4be Poul Sander 2025-02-03 21:28 1539
1193b4be Poul Sander 2025-02-03 21:28 1540
    PathLineTo(p1);
1193b4be Poul Sander 2025-02-03 21:28 1541
    PathLineTo(p2);
1193b4be Poul Sander 2025-02-03 21:28 1542
    PathLineTo(p3);
1193b4be Poul Sander 2025-02-03 21:28 1543
    PathLineTo(p4);
1193b4be Poul Sander 2025-02-03 21:28 1544
    PathStroke(col, ImDrawFlags_Closed, thickness);
1193b4be Poul Sander 2025-02-03 21:28 1545
}
1193b4be Poul Sander 2025-02-03 21:28 1546
1193b4be Poul Sander 2025-02-03 21:28 1547
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 1548
{
1193b4be Poul Sander 2025-02-03 21:28 1549
    if ((col & IM_COL32_A_MASK) == 0)
1193b4be Poul Sander 2025-02-03 21:28 1550
        return;
1193b4be Poul Sander 2025-02-03 21:28 1551
1193b4be Poul Sander 2025-02-03 21:28 1552
    PathLineTo(p1);
1193b4be Poul Sander 2025-02-03 21:28 1553
    PathLineTo(p2);
1193b4be Poul Sander 2025-02-03 21:28 1554
    PathLineTo(p3);
1193b4be Poul Sander 2025-02-03 21:28 1555
    PathLineTo(p4);
1193b4be Poul Sander 2025-02-03 21:28 1556
    PathFillConvex(col);
1193b4be Poul Sander 2025-02-03 21:28 1557
}
1193b4be Poul Sander 2025-02-03 21:28 1558
1193b4be Poul Sander 2025-02-03 21:28 1559
void ImDrawList::AddTriangle(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness)
1193b4be Poul Sander 2025-02-03 21:28 1560
{
1193b4be Poul Sander 2025-02-03 21:28 1561
    if ((col & IM_COL32_A_MASK) == 0)
1193b4be Poul Sander 2025-02-03 21:28 1562
        return;
1193b4be Poul Sander 2025-02-03 21:28 1563
1193b4be Poul Sander 2025-02-03 21:28 1564
    PathLineTo(p1);
1193b4be Poul Sander 2025-02-03 21:28 1565
    PathLineTo(p2);
1193b4be Poul Sander 2025-02-03 21:28 1566
    PathLineTo(p3);
1193b4be Poul Sander 2025-02-03 21:28 1567
    PathStroke(col, ImDrawFlags_Closed, thickness);
1193b4be Poul Sander 2025-02-03 21:28 1568
}
1193b4be Poul Sander 2025-02-03 21:28 1569
1193b4be Poul Sander 2025-02-03 21:28 1570
void ImDrawList::AddTriangleFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col)
1193b4be Poul Sander 2025-02-03 21:28 1571
{
1193b4be Poul Sander 2025-02-03 21:28 1572
    if ((col & IM_COL32_A_MASK) == 0)
1193b4be Poul Sander 2025-02-03 21:28 1573
        return;
1193b4be Poul Sander 2025-02-03 21:28 1574
1193b4be Poul Sander 2025-02-03 21:28 1575
    PathLineTo(p1);
1193b4be Poul Sander 2025-02-03 21:28 1576
    PathLineTo(p2);
1193b4be Poul Sander 2025-02-03 21:28 1577
    PathLineTo(p3);
1193b4be Poul Sander 2025-02-03 21:28 1578
    PathFillConvex(col);
1193b4be Poul Sander 2025-02-03 21:28 1579
}
1193b4be Poul Sander 2025-02-03 21:28 1580
1193b4be Poul Sander 2025-02-03 21:28 1581
void ImDrawList::AddCircle(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 || radius < 0.5f)
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
    if (num_segments <= 0)
1193b4be Poul Sander 2025-02-03 21:28 1587
    {
1193b4be Poul Sander 2025-02-03 21:28 1588
        // Use arc with automatic segment count
1193b4be Poul Sander 2025-02-03 21:28 1589
        _PathArcToFastEx(center, radius - 0.5f, 0, IM_DRAWLIST_ARCFAST_SAMPLE_MAX, 0);
1193b4be Poul Sander 2025-02-03 21:28 1590
        _Path.Size--;
1193b4be Poul Sander 2025-02-03 21:28 1591
    }
1193b4be Poul Sander 2025-02-03 21:28 1592
    else
1193b4be Poul Sander 2025-02-03 21:28 1593
    {
1193b4be Poul Sander 2025-02-03 21:28 1594
        // Explicit segment count (still clamp to avoid drawing insanely tessellated shapes)
1193b4be Poul Sander 2025-02-03 21:28 1595
        num_segments = ImClamp(num_segments, 3, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX);
1193b4be Poul Sander 2025-02-03 21:28 1596
1193b4be Poul Sander 2025-02-03 21:28 1597
        // Because we are filling a closed shape we remove 1 from the count of segments/points
1193b4be Poul Sander 2025-02-03 21:28 1598
        const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments;
1193b4be Poul Sander 2025-02-03 21:28 1599
        PathArcTo(center, radius - 0.5f, 0.0f, a_max, num_segments - 1);
1193b4be Poul Sander 2025-02-03 21:28 1600
    }
1193b4be Poul Sander 2025-02-03 21:28 1601
1193b4be Poul Sander 2025-02-03 21:28 1602
    PathStroke(col, ImDrawFlags_Closed, thickness);
1193b4be Poul Sander 2025-02-03 21:28 1603
}
1193b4be Poul Sander 2025-02-03 21:28 1604
1193b4be Poul Sander 2025-02-03 21:28 1605
void ImDrawList::AddCircleFilled(const ImVec2& center, float radius, ImU32 col, int num_segments)
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 || radius < 0.5f)
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
    {
1193b4be Poul Sander 2025-02-03 21:28 1612
        // Use arc with automatic segment count
1193b4be Poul Sander 2025-02-03 21:28 1613
        _PathArcToFastEx(center, radius, 0, IM_DRAWLIST_ARCFAST_SAMPLE_MAX, 0);
1193b4be Poul Sander 2025-02-03 21:28 1614
        _Path.Size--;
1193b4be Poul Sander 2025-02-03 21:28 1615
    }
1193b4be Poul Sander 2025-02-03 21:28 1616
    else
1193b4be Poul Sander 2025-02-03 21:28 1617
    {
1193b4be Poul Sander 2025-02-03 21:28 1618
        // Explicit segment count (still clamp to avoid drawing insanely tessellated shapes)
1193b4be Poul Sander 2025-02-03 21:28 1619
        num_segments = ImClamp(num_segments, 3, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX);
1193b4be Poul Sander 2025-02-03 21:28 1620
1193b4be Poul Sander 2025-02-03 21:28 1621
        // Because we are filling a closed shape we remove 1 from the count of segments/points
1193b4be Poul Sander 2025-02-03 21:28 1622
        const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments;
1193b4be Poul Sander 2025-02-03 21:28 1623
        PathArcTo(center, radius, 0.0f, a_max, num_segments - 1);
1193b4be Poul Sander 2025-02-03 21:28 1624
    }
1193b4be Poul Sander 2025-02-03 21:28 1625
1193b4be Poul Sander 2025-02-03 21:28 1626
    PathFillConvex(col);
1193b4be Poul Sander 2025-02-03 21:28 1627
}
1193b4be Poul Sander 2025-02-03 21:28 1628
1193b4be Poul Sander 2025-02-03 21:28 1629
// Guaranteed to honor 'num_segments'
1193b4be Poul Sander 2025-02-03 21:28 1630
void ImDrawList::AddNgon(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness)
1193b4be Poul Sander 2025-02-03 21:28 1631
{
1193b4be Poul Sander 2025-02-03 21:28 1632
    if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2)
1193b4be Poul Sander 2025-02-03 21:28 1633
        return;
1193b4be Poul Sander 2025-02-03 21:28 1634
1193b4be Poul Sander 2025-02-03 21:28 1635
    // Because we are filling a closed shape we remove 1 from the count of segments/points
1193b4be Poul Sander 2025-02-03 21:28 1636
    const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments;
1193b4be Poul Sander 2025-02-03 21:28 1637
    PathArcTo(center, radius - 0.5f, 0.0f, a_max, num_segments - 1);
1193b4be Poul Sander 2025-02-03 21:28 1638
    PathStroke(col, ImDrawFlags_Closed, thickness);
1193b4be Poul Sander 2025-02-03 21:28 1639
}
1193b4be Poul Sander 2025-02-03 21:28 1640
1193b4be Poul Sander 2025-02-03 21:28 1641
// Guaranteed to honor 'num_segments'
1193b4be Poul Sander 2025-02-03 21:28 1642
void ImDrawList::AddNgonFilled(const ImVec2& center, float radius, ImU32 col, int num_segments)
1193b4be Poul Sander 2025-02-03 21:28 1643
{
1193b4be Poul Sander 2025-02-03 21:28 1644
    if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2)
1193b4be Poul Sander 2025-02-03 21:28 1645
        return;
1193b4be Poul Sander 2025-02-03 21:28 1646
1193b4be Poul Sander 2025-02-03 21:28 1647
    // Because we are filling a closed shape we remove 1 from the count of segments/points
1193b4be Poul Sander 2025-02-03 21:28 1648
    const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments;
1193b4be Poul Sander 2025-02-03 21:28 1649
    PathArcTo(center, radius, 0.0f, a_max, num_segments - 1);
1193b4be Poul Sander 2025-02-03 21:28 1650
    PathFillConvex(col);
1193b4be Poul Sander 2025-02-03 21:28 1651
}
1193b4be Poul Sander 2025-02-03 21:28 1652
1193b4be Poul Sander 2025-02-03 21:28 1653
// Ellipse
1193b4be Poul Sander 2025-02-03 21:28 1654
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 1655
{
1193b4be Poul Sander 2025-02-03 21:28 1656
    if ((col & IM_COL32_A_MASK) == 0)
1193b4be Poul Sander 2025-02-03 21:28 1657
        return;
1193b4be Poul Sander 2025-02-03 21:28 1658
1193b4be Poul Sander 2025-02-03 21:28 1659
    if (num_segments <= 0)
1193b4be Poul Sander 2025-02-03 21:28 1660
        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 1661
1193b4be Poul Sander 2025-02-03 21:28 1662
    // Because we are filling a closed shape we remove 1 from the count of segments/points
1193b4be Poul Sander 2025-02-03 21:28 1663
    const float a_max = IM_PI * 2.0f * ((float)num_segments - 1.0f) / (float)num_segments;
1193b4be Poul Sander 2025-02-03 21:28 1664
    PathEllipticalArcTo(center, radius, rot, 0.0f, a_max, num_segments - 1);
1193b4be Poul Sander 2025-02-03 21:28 1665
    PathStroke(col, true, thickness);
1193b4be Poul Sander 2025-02-03 21:28 1666
}
1193b4be Poul Sander 2025-02-03 21:28 1667
1193b4be Poul Sander 2025-02-03 21:28 1668
void ImDrawList::AddEllipseFilled(const ImVec2& center, const ImVec2& radius, ImU32 col, float rot, int num_segments)
1193b4be Poul Sander 2025-02-03 21:28 1669
{
1193b4be Poul Sander 2025-02-03 21:28 1670
    if ((col & IM_COL32_A_MASK) == 0)
1193b4be Poul Sander 2025-02-03 21:28 1671
        return;
1193b4be Poul Sander 2025-02-03 21:28 1672
1193b4be Poul Sander 2025-02-03 21:28 1673
    if (num_segments <= 0)
1193b4be Poul Sander 2025-02-03 21:28 1674
        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 1675
1193b4be Poul Sander 2025-02-03 21:28 1676
    // Because we are filling a closed shape we remove 1 from the count of segments/points
1193b4be Poul Sander 2025-02-03 21:28 1677
    const float a_max = IM_PI * 2.0f * ((float)num_segments - 1.0f) / (float)num_segments;
1193b4be Poul Sander 2025-02-03 21:28 1678
    PathEllipticalArcTo(center, radius, rot, 0.0f, a_max, num_segments - 1);
1193b4be Poul Sander 2025-02-03 21:28 1679
    PathFillConvex(col);
1193b4be Poul Sander 2025-02-03 21:28 1680
}
1193b4be Poul Sander 2025-02-03 21:28 1681
1193b4be Poul Sander 2025-02-03 21:28 1682
// Cubic Bezier takes 4 controls points
1193b4be Poul Sander 2025-02-03 21:28 1683
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 1684
{
1193b4be Poul Sander 2025-02-03 21:28 1685
    if ((col & IM_COL32_A_MASK) == 0)
1193b4be Poul Sander 2025-02-03 21:28 1686
        return;
1193b4be Poul Sander 2025-02-03 21:28 1687
1193b4be Poul Sander 2025-02-03 21:28 1688
    PathLineTo(p1);
1193b4be Poul Sander 2025-02-03 21:28 1689
    PathBezierCubicCurveTo(p2, p3, p4, num_segments);
1193b4be Poul Sander 2025-02-03 21:28 1690
    PathStroke(col, 0, thickness);
1193b4be Poul Sander 2025-02-03 21:28 1691
}
1193b4be Poul Sander 2025-02-03 21:28 1692
1193b4be Poul Sander 2025-02-03 21:28 1693
// Quadratic Bezier takes 3 controls points
1193b4be Poul Sander 2025-02-03 21:28 1694
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 1695
{
1193b4be Poul Sander 2025-02-03 21:28 1696
    if ((col & IM_COL32_A_MASK) == 0)
1193b4be Poul Sander 2025-02-03 21:28 1697
        return;
1193b4be Poul Sander 2025-02-03 21:28 1698
1193b4be Poul Sander 2025-02-03 21:28 1699
    PathLineTo(p1);
1193b4be Poul Sander 2025-02-03 21:28 1700
    PathBezierQuadraticCurveTo(p2, p3, num_segments);
1193b4be Poul Sander 2025-02-03 21:28 1701
    PathStroke(col, 0, thickness);
1193b4be Poul Sander 2025-02-03 21:28 1702
}
1193b4be Poul Sander 2025-02-03 21:28 1703
4e9e2555 Poul Sander 2025-10-05 10:15 1704
void ImDrawList::AddText(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 1705
{
1193b4be Poul Sander 2025-02-03 21:28 1706
    if ((col & IM_COL32_A_MASK) == 0)
1193b4be Poul Sander 2025-02-03 21:28 1707
        return;
1193b4be Poul Sander 2025-02-03 21:28 1708
1193b4be Poul Sander 2025-02-03 21:28 1709
    // Accept null ranges
1193b4be Poul Sander 2025-02-03 21:28 1710
    if (text_begin == text_end || text_begin[0] == 0)
1193b4be Poul Sander 2025-02-03 21:28 1711
        return;
4e9e2555 Poul Sander 2025-10-05 10:15 1712
    // No need to strlen() here: font->RenderText() will do it and may early out.
1193b4be Poul Sander 2025-02-03 21:28 1713
1193b4be Poul Sander 2025-02-03 21:28 1714
    // Pull default font/size from the shared ImDrawListSharedData instance
1193b4be Poul Sander 2025-02-03 21:28 1715
    if (font == NULL)
1193b4be Poul Sander 2025-02-03 21:28 1716
        font = _Data->Font;
1193b4be Poul Sander 2025-02-03 21:28 1717
    if (font_size == 0.0f)
1193b4be Poul Sander 2025-02-03 21:28 1718
        font_size = _Data->FontSize;
1193b4be Poul Sander 2025-02-03 21:28 1719
1193b4be Poul Sander 2025-02-03 21:28 1720
    ImVec4 clip_rect = _CmdHeader.ClipRect;
1193b4be Poul Sander 2025-02-03 21:28 1721
    if (cpu_fine_clip_rect)
1193b4be Poul Sander 2025-02-03 21:28 1722
    {
1193b4be Poul Sander 2025-02-03 21:28 1723
        clip_rect.x = ImMax(clip_rect.x, cpu_fine_clip_rect->x);
1193b4be Poul Sander 2025-02-03 21:28 1724
        clip_rect.y = ImMax(clip_rect.y, cpu_fine_clip_rect->y);
1193b4be Poul Sander 2025-02-03 21:28 1725
        clip_rect.z = ImMin(clip_rect.z, cpu_fine_clip_rect->z);
1193b4be Poul Sander 2025-02-03 21:28 1726
        clip_rect.w = ImMin(clip_rect.w, cpu_fine_clip_rect->w);
1193b4be Poul Sander 2025-02-03 21:28 1727
    }
4e9e2555 Poul Sander 2025-10-05 10:15 1728
    font->RenderText(this, font_size, pos, col, clip_rect, text_begin, text_end, wrap_width, (cpu_fine_clip_rect != NULL) ? ImDrawTextFlags_CpuFineClip : ImDrawTextFlags_None);
1193b4be Poul Sander 2025-02-03 21:28 1729
}
1193b4be Poul Sander 2025-02-03 21:28 1730
1193b4be Poul Sander 2025-02-03 21:28 1731
void ImDrawList::AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end)
1193b4be Poul Sander 2025-02-03 21:28 1732
{
4e9e2555 Poul Sander 2025-10-05 10:15 1733
    AddText(_Data->Font, _Data->FontSize, pos, col, text_begin, text_end);
1193b4be Poul Sander 2025-02-03 21:28 1734
}
1193b4be Poul Sander 2025-02-03 21:28 1735
4e9e2555 Poul Sander 2025-10-05 10:15 1736
void ImDrawList::AddImage(ImTextureRef tex_ref, 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 1737
{
1193b4be Poul Sander 2025-02-03 21:28 1738
    if ((col & IM_COL32_A_MASK) == 0)
1193b4be Poul Sander 2025-02-03 21:28 1739
        return;
1193b4be Poul Sander 2025-02-03 21:28 1740
4e9e2555 Poul Sander 2025-10-05 10:15 1741
    const bool push_texture_id = tex_ref != _CmdHeader.TexRef;
1193b4be Poul Sander 2025-02-03 21:28 1742
    if (push_texture_id)
4e9e2555 Poul Sander 2025-10-05 10:15 1743
        PushTexture(tex_ref);
1193b4be Poul Sander 2025-02-03 21:28 1744
1193b4be Poul Sander 2025-02-03 21:28 1745
    PrimReserve(6, 4);
1193b4be Poul Sander 2025-02-03 21:28 1746
    PrimRectUV(p_min, p_max, uv_min, uv_max, col);
1193b4be Poul Sander 2025-02-03 21:28 1747
1193b4be Poul Sander 2025-02-03 21:28 1748
    if (push_texture_id)
4e9e2555 Poul Sander 2025-10-05 10:15 1749
        PopTexture();
1193b4be Poul Sander 2025-02-03 21:28 1750
}
1193b4be Poul Sander 2025-02-03 21:28 1751
4e9e2555 Poul Sander 2025-10-05 10:15 1752
void ImDrawList::AddImageQuad(ImTextureRef tex_ref, 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 1753
{
1193b4be Poul Sander 2025-02-03 21:28 1754
    if ((col & IM_COL32_A_MASK) == 0)
1193b4be Poul Sander 2025-02-03 21:28 1755
        return;
1193b4be Poul Sander 2025-02-03 21:28 1756
4e9e2555 Poul Sander 2025-10-05 10:15 1757
    const bool push_texture_id = tex_ref != _CmdHeader.TexRef;
1193b4be Poul Sander 2025-02-03 21:28 1758
    if (push_texture_id)
4e9e2555 Poul Sander 2025-10-05 10:15 1759
        PushTexture(tex_ref);
1193b4be Poul Sander 2025-02-03 21:28 1760
1193b4be Poul Sander 2025-02-03 21:28 1761
    PrimReserve(6, 4);
1193b4be Poul Sander 2025-02-03 21:28 1762
    PrimQuadUV(p1, p2, p3, p4, uv1, uv2, uv3, uv4, col);
1193b4be Poul Sander 2025-02-03 21:28 1763
1193b4be Poul Sander 2025-02-03 21:28 1764
    if (push_texture_id)
4e9e2555 Poul Sander 2025-10-05 10:15 1765
        PopTexture();
1193b4be Poul Sander 2025-02-03 21:28 1766
}
1193b4be Poul Sander 2025-02-03 21:28 1767
4e9e2555 Poul Sander 2025-10-05 10:15 1768
void ImDrawList::AddImageRounded(ImTextureRef tex_ref, 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 1769
{
1193b4be Poul Sander 2025-02-03 21:28 1770
    if ((col & IM_COL32_A_MASK) == 0)
1193b4be Poul Sander 2025-02-03 21:28 1771
        return;
1193b4be Poul Sander 2025-02-03 21:28 1772
1193b4be Poul Sander 2025-02-03 21:28 1773
    flags = FixRectCornerFlags(flags);
1193b4be Poul Sander 2025-02-03 21:28 1774
    if (rounding < 0.5f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone)
1193b4be Poul Sander 2025-02-03 21:28 1775
    {
4e9e2555 Poul Sander 2025-10-05 10:15 1776
        AddImage(tex_ref, p_min, p_max, uv_min, uv_max, col);
1193b4be Poul Sander 2025-02-03 21:28 1777
        return;
1193b4be Poul Sander 2025-02-03 21:28 1778
    }
1193b4be Poul Sander 2025-02-03 21:28 1779
4e9e2555 Poul Sander 2025-10-05 10:15 1780
    const bool push_texture_id = tex_ref != _CmdHeader.TexRef;
1193b4be Poul Sander 2025-02-03 21:28 1781
    if (push_texture_id)
4e9e2555 Poul Sander 2025-10-05 10:15 1782
        PushTexture(tex_ref);
1193b4be Poul Sander 2025-02-03 21:28 1783
1193b4be Poul Sander 2025-02-03 21:28 1784
    int vert_start_idx = VtxBuffer.Size;
1193b4be Poul Sander 2025-02-03 21:28 1785
    PathRect(p_min, p_max, rounding, flags);
1193b4be Poul Sander 2025-02-03 21:28 1786
    PathFillConvex(col);
1193b4be Poul Sander 2025-02-03 21:28 1787
    int vert_end_idx = VtxBuffer.Size;
1193b4be Poul Sander 2025-02-03 21:28 1788
    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 1789
1193b4be Poul Sander 2025-02-03 21:28 1790
    if (push_texture_id)
4e9e2555 Poul Sander 2025-10-05 10:15 1791
        PopTexture();
1193b4be Poul Sander 2025-02-03 21:28 1792
}
1193b4be Poul Sander 2025-02-03 21:28 1793
1193b4be Poul Sander 2025-02-03 21:28 1794
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 1795
// [SECTION] ImTriangulator, ImDrawList concave polygon fill
1193b4be Poul Sander 2025-02-03 21:28 1796
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 1797
// Triangulate concave polygons. Based on "Triangulation by Ear Clipping" paper, O(N^2) complexity.
1193b4be Poul Sander 2025-02-03 21:28 1798
// Reference: https://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf
1193b4be Poul Sander 2025-02-03 21:28 1799
// Provided as a convenience for user but not used by main library.
1193b4be Poul Sander 2025-02-03 21:28 1800
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 1801
// - ImTriangulator [Internal]
1193b4be Poul Sander 2025-02-03 21:28 1802
// - AddConcavePolyFilled()
1193b4be Poul Sander 2025-02-03 21:28 1803
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 1804
1193b4be Poul Sander 2025-02-03 21:28 1805
enum ImTriangulatorNodeType
1193b4be Poul Sander 2025-02-03 21:28 1806
{
1193b4be Poul Sander 2025-02-03 21:28 1807
    ImTriangulatorNodeType_Convex,
1193b4be Poul Sander 2025-02-03 21:28 1808
    ImTriangulatorNodeType_Ear,
1193b4be Poul Sander 2025-02-03 21:28 1809
    ImTriangulatorNodeType_Reflex
1193b4be Poul Sander 2025-02-03 21:28 1810
};
1193b4be Poul Sander 2025-02-03 21:28 1811
1193b4be Poul Sander 2025-02-03 21:28 1812
struct ImTriangulatorNode
1193b4be Poul Sander 2025-02-03 21:28 1813
{
1193b4be Poul Sander 2025-02-03 21:28 1814
    ImTriangulatorNodeType  Type;
1193b4be Poul Sander 2025-02-03 21:28 1815
    int                     Index;
1193b4be Poul Sander 2025-02-03 21:28 1816
    ImVec2                  Pos;
1193b4be Poul Sander 2025-02-03 21:28 1817
    ImTriangulatorNode*     Next;
1193b4be Poul Sander 2025-02-03 21:28 1818
    ImTriangulatorNode*     Prev;
1193b4be Poul Sander 2025-02-03 21:28 1819
1193b4be Poul Sander 2025-02-03 21:28 1820
    void    Unlink()        { Next->Prev = Prev; Prev->Next = Next; }
1193b4be Poul Sander 2025-02-03 21:28 1821
};
1193b4be Poul Sander 2025-02-03 21:28 1822
1193b4be Poul Sander 2025-02-03 21:28 1823
struct ImTriangulatorNodeSpan
1193b4be Poul Sander 2025-02-03 21:28 1824
{
1193b4be Poul Sander 2025-02-03 21:28 1825
    ImTriangulatorNode**    Data = NULL;
1193b4be Poul Sander 2025-02-03 21:28 1826
    int                     Size = 0;
1193b4be Poul Sander 2025-02-03 21:28 1827
1193b4be Poul Sander 2025-02-03 21:28 1828
    void    push_back(ImTriangulatorNode* node) { Data[Size++] = node; }
1193b4be Poul Sander 2025-02-03 21:28 1829
    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 1830
};
1193b4be Poul Sander 2025-02-03 21:28 1831
1193b4be Poul Sander 2025-02-03 21:28 1832
struct ImTriangulator
1193b4be Poul Sander 2025-02-03 21:28 1833
{
1193b4be Poul Sander 2025-02-03 21:28 1834
    static int EstimateTriangleCount(int points_count)      { return (points_count < 3) ? 0 : points_count - 2; }
1193b4be Poul Sander 2025-02-03 21:28 1835
    static int EstimateScratchBufferSize(int points_count)  { return sizeof(ImTriangulatorNode) * points_count + sizeof(ImTriangulatorNode*) * points_count * 2; }
1193b4be Poul Sander 2025-02-03 21:28 1836
1193b4be Poul Sander 2025-02-03 21:28 1837
    void    Init(const ImVec2* points, int points_count, void* scratch_buffer);
1193b4be Poul Sander 2025-02-03 21:28 1838
    void    GetNextTriangle(unsigned int out_triangle[3]);     // Return relative indexes for next triangle
1193b4be Poul Sander 2025-02-03 21:28 1839
1193b4be Poul Sander 2025-02-03 21:28 1840
    // Internal functions
1193b4be Poul Sander 2025-02-03 21:28 1841
    void    BuildNodes(const ImVec2* points, int points_count);
1193b4be Poul Sander 2025-02-03 21:28 1842
    void    BuildReflexes();
1193b4be Poul Sander 2025-02-03 21:28 1843
    void    BuildEars();
1193b4be Poul Sander 2025-02-03 21:28 1844
    void    FlipNodeList();
1193b4be Poul Sander 2025-02-03 21:28 1845
    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 1846
    void    ReclassifyNode(ImTriangulatorNode* node);
1193b4be Poul Sander 2025-02-03 21:28 1847
1193b4be Poul Sander 2025-02-03 21:28 1848
    // Internal members
1193b4be Poul Sander 2025-02-03 21:28 1849
    int                     _TrianglesLeft = 0;
1193b4be Poul Sander 2025-02-03 21:28 1850
    ImTriangulatorNode*     _Nodes = NULL;
1193b4be Poul Sander 2025-02-03 21:28 1851
    ImTriangulatorNodeSpan  _Ears;
1193b4be Poul Sander 2025-02-03 21:28 1852
    ImTriangulatorNodeSpan  _Reflexes;
1193b4be Poul Sander 2025-02-03 21:28 1853
};
1193b4be Poul Sander 2025-02-03 21:28 1854
1193b4be Poul Sander 2025-02-03 21:28 1855
// Distribute storage for nodes, ears and reflexes.
1193b4be Poul Sander 2025-02-03 21:28 1856
// 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 1857
// (this would require first building reflexes to bail to convex if empty, without even building nodes)
1193b4be Poul Sander 2025-02-03 21:28 1858
void ImTriangulator::Init(const ImVec2* points, int points_count, void* scratch_buffer)
1193b4be Poul Sander 2025-02-03 21:28 1859
{
1193b4be Poul Sander 2025-02-03 21:28 1860
    IM_ASSERT(scratch_buffer != NULL && points_count >= 3);
1193b4be Poul Sander 2025-02-03 21:28 1861
    _TrianglesLeft = EstimateTriangleCount(points_count);
1193b4be Poul Sander 2025-02-03 21:28 1862
    _Nodes         = (ImTriangulatorNode*)scratch_buffer;                          // points_count x Node
1193b4be Poul Sander 2025-02-03 21:28 1863
    _Ears.Data     = (ImTriangulatorNode**)(_Nodes + points_count);                // points_count x Node*
1193b4be Poul Sander 2025-02-03 21:28 1864
    _Reflexes.Data = (ImTriangulatorNode**)(_Nodes + points_count) + points_count; // points_count x Node*
1193b4be Poul Sander 2025-02-03 21:28 1865
    BuildNodes(points, points_count);
1193b4be Poul Sander 2025-02-03 21:28 1866
    BuildReflexes();
1193b4be Poul Sander 2025-02-03 21:28 1867
    BuildEars();
1193b4be Poul Sander 2025-02-03 21:28 1868
}
1193b4be Poul Sander 2025-02-03 21:28 1869
1193b4be Poul Sander 2025-02-03 21:28 1870
void ImTriangulator::BuildNodes(const ImVec2* points, int points_count)
1193b4be Poul Sander 2025-02-03 21:28 1871
{
1193b4be Poul Sander 2025-02-03 21:28 1872
    for (int i = 0; i < points_count; i++)
1193b4be Poul Sander 2025-02-03 21:28 1873
    {
1193b4be Poul Sander 2025-02-03 21:28 1874
        _Nodes[i].Type = ImTriangulatorNodeType_Convex;
1193b4be Poul Sander 2025-02-03 21:28 1875
        _Nodes[i].Index = i;
1193b4be Poul Sander 2025-02-03 21:28 1876
        _Nodes[i].Pos = points[i];
1193b4be Poul Sander 2025-02-03 21:28 1877
        _Nodes[i].Next = _Nodes + i + 1;
1193b4be Poul Sander 2025-02-03 21:28 1878
        _Nodes[i].Prev = _Nodes + i - 1;
1193b4be Poul Sander 2025-02-03 21:28 1879
    }
1193b4be Poul Sander 2025-02-03 21:28 1880
    _Nodes[0].Prev = _Nodes + points_count - 1;
1193b4be Poul Sander 2025-02-03 21:28 1881
    _Nodes[points_count - 1].Next = _Nodes;
1193b4be Poul Sander 2025-02-03 21:28 1882
}
1193b4be Poul Sander 2025-02-03 21:28 1883
1193b4be Poul Sander 2025-02-03 21:28 1884
void ImTriangulator::BuildReflexes()
1193b4be Poul Sander 2025-02-03 21:28 1885
{
1193b4be Poul Sander 2025-02-03 21:28 1886
    ImTriangulatorNode* n1 = _Nodes;
1193b4be Poul Sander 2025-02-03 21:28 1887
    for (int i = _TrianglesLeft; i >= 0; i--, n1 = n1->Next)
1193b4be Poul Sander 2025-02-03 21:28 1888
    {
1193b4be Poul Sander 2025-02-03 21:28 1889
        if (ImTriangleIsClockwise(n1->Prev->Pos, n1->Pos, n1->Next->Pos))
1193b4be Poul Sander 2025-02-03 21:28 1890
            continue;
1193b4be Poul Sander 2025-02-03 21:28 1891
        n1->Type = ImTriangulatorNodeType_Reflex;
1193b4be Poul Sander 2025-02-03 21:28 1892
        _Reflexes.push_back(n1);
1193b4be Poul Sander 2025-02-03 21:28 1893
    }
1193b4be Poul Sander 2025-02-03 21:28 1894
}
1193b4be Poul Sander 2025-02-03 21:28 1895
1193b4be Poul Sander 2025-02-03 21:28 1896
void ImTriangulator::BuildEars()
1193b4be Poul Sander 2025-02-03 21:28 1897
{
1193b4be Poul Sander 2025-02-03 21:28 1898
    ImTriangulatorNode* n1 = _Nodes;
1193b4be Poul Sander 2025-02-03 21:28 1899
    for (int i = _TrianglesLeft; i >= 0; i--, n1 = n1->Next)
1193b4be Poul Sander 2025-02-03 21:28 1900
    {
1193b4be Poul Sander 2025-02-03 21:28 1901
        if (n1->Type != ImTriangulatorNodeType_Convex)
1193b4be Poul Sander 2025-02-03 21:28 1902
            continue;
1193b4be Poul Sander 2025-02-03 21:28 1903
        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 1904
            continue;
1193b4be Poul Sander 2025-02-03 21:28 1905
        n1->Type = ImTriangulatorNodeType_Ear;
1193b4be Poul Sander 2025-02-03 21:28 1906
        _Ears.push_back(n1);
1193b4be Poul Sander 2025-02-03 21:28 1907
    }
1193b4be Poul Sander 2025-02-03 21:28 1908
}
1193b4be Poul Sander 2025-02-03 21:28 1909
1193b4be Poul Sander 2025-02-03 21:28 1910
void ImTriangulator::GetNextTriangle(unsigned int out_triangle[3])
1193b4be Poul Sander 2025-02-03 21:28 1911
{
1193b4be Poul Sander 2025-02-03 21:28 1912
    if (_Ears.Size == 0)
1193b4be Poul Sander 2025-02-03 21:28 1913
    {
1193b4be Poul Sander 2025-02-03 21:28 1914
        FlipNodeList();
1193b4be Poul Sander 2025-02-03 21:28 1915
1193b4be Poul Sander 2025-02-03 21:28 1916
        ImTriangulatorNode* node = _Nodes;
1193b4be Poul Sander 2025-02-03 21:28 1917
        for (int i = _TrianglesLeft; i >= 0; i--, node = node->Next)
1193b4be Poul Sander 2025-02-03 21:28 1918
            node->Type = ImTriangulatorNodeType_Convex;
1193b4be Poul Sander 2025-02-03 21:28 1919
        _Reflexes.Size = 0;
1193b4be Poul Sander 2025-02-03 21:28 1920
        BuildReflexes();
1193b4be Poul Sander 2025-02-03 21:28 1921
        BuildEars();
1193b4be Poul Sander 2025-02-03 21:28 1922
1193b4be Poul Sander 2025-02-03 21:28 1923
        // If we still don't have ears, it means geometry is degenerated.
1193b4be Poul Sander 2025-02-03 21:28 1924
        if (_Ears.Size == 0)
1193b4be Poul Sander 2025-02-03 21:28 1925
        {
1193b4be Poul Sander 2025-02-03 21:28 1926
            // Return first triangle available, mimicking the behavior of convex fill.
1193b4be Poul Sander 2025-02-03 21:28 1927
            IM_ASSERT(_TrianglesLeft > 0); // Geometry is degenerated
1193b4be Poul Sander 2025-02-03 21:28 1928
            _Ears.Data[0] = _Nodes;
1193b4be Poul Sander 2025-02-03 21:28 1929
            _Ears.Size    = 1;
1193b4be Poul Sander 2025-02-03 21:28 1930
        }
1193b4be Poul Sander 2025-02-03 21:28 1931
    }
1193b4be Poul Sander 2025-02-03 21:28 1932
1193b4be Poul Sander 2025-02-03 21:28 1933
    ImTriangulatorNode* ear = _Ears.Data[--_Ears.Size];
1193b4be Poul Sander 2025-02-03 21:28 1934
    out_triangle[0] = ear->Prev->Index;
1193b4be Poul Sander 2025-02-03 21:28 1935
    out_triangle[1] = ear->Index;
1193b4be Poul Sander 2025-02-03 21:28 1936
    out_triangle[2] = ear->Next->Index;
1193b4be Poul Sander 2025-02-03 21:28 1937
1193b4be Poul Sander 2025-02-03 21:28 1938
    ear->Unlink();
1193b4be Poul Sander 2025-02-03 21:28 1939
    if (ear == _Nodes)
1193b4be Poul Sander 2025-02-03 21:28 1940
        _Nodes = ear->Next;
1193b4be Poul Sander 2025-02-03 21:28 1941
1193b4be Poul Sander 2025-02-03 21:28 1942
    ReclassifyNode(ear->Prev);
1193b4be Poul Sander 2025-02-03 21:28 1943
    ReclassifyNode(ear->Next);
1193b4be Poul Sander 2025-02-03 21:28 1944
    _TrianglesLeft--;
1193b4be Poul Sander 2025-02-03 21:28 1945
}
1193b4be Poul Sander 2025-02-03 21:28 1946
1193b4be Poul Sander 2025-02-03 21:28 1947
void ImTriangulator::FlipNodeList()
1193b4be Poul Sander 2025-02-03 21:28 1948
{
1193b4be Poul Sander 2025-02-03 21:28 1949
    ImTriangulatorNode* prev = _Nodes;
1193b4be Poul Sander 2025-02-03 21:28 1950
    ImTriangulatorNode* temp = _Nodes;
1193b4be Poul Sander 2025-02-03 21:28 1951
    ImTriangulatorNode* current = _Nodes->Next;
1193b4be Poul Sander 2025-02-03 21:28 1952
    prev->Next = prev;
1193b4be Poul Sander 2025-02-03 21:28 1953
    prev->Prev = prev;
1193b4be Poul Sander 2025-02-03 21:28 1954
    while (current != _Nodes)
1193b4be Poul Sander 2025-02-03 21:28 1955
    {
1193b4be Poul Sander 2025-02-03 21:28 1956
        temp = current->Next;
1193b4be Poul Sander 2025-02-03 21:28 1957
1193b4be Poul Sander 2025-02-03 21:28 1958
        current->Next = prev;
1193b4be Poul Sander 2025-02-03 21:28 1959
        prev->Prev = current;
1193b4be Poul Sander 2025-02-03 21:28 1960
        _Nodes->Next = current;
1193b4be Poul Sander 2025-02-03 21:28 1961
        current->Prev = _Nodes;
1193b4be Poul Sander 2025-02-03 21:28 1962
1193b4be Poul Sander 2025-02-03 21:28 1963
        prev = current;
1193b4be Poul Sander 2025-02-03 21:28 1964
        current = temp;
1193b4be Poul Sander 2025-02-03 21:28 1965
    }
1193b4be Poul Sander 2025-02-03 21:28 1966
    _Nodes = prev;
1193b4be Poul Sander 2025-02-03 21:28 1967
}
1193b4be Poul Sander 2025-02-03 21:28 1968
1193b4be Poul Sander 2025-02-03 21:28 1969
// 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 1970
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 1971
{
1193b4be Poul Sander 2025-02-03 21:28 1972
    ImTriangulatorNode** p_end = _Reflexes.Data + _Reflexes.Size;
1193b4be Poul Sander 2025-02-03 21:28 1973
    for (ImTriangulatorNode** p = _Reflexes.Data; p < p_end; p++)
1193b4be Poul Sander 2025-02-03 21:28 1974
    {
1193b4be Poul Sander 2025-02-03 21:28 1975
        ImTriangulatorNode* reflex = *p;
1193b4be Poul Sander 2025-02-03 21:28 1976
        if (reflex->Index != i0 && reflex->Index != i1 && reflex->Index != i2)
1193b4be Poul Sander 2025-02-03 21:28 1977
            if (ImTriangleContainsPoint(v0, v1, v2, reflex->Pos))
1193b4be Poul Sander 2025-02-03 21:28 1978
                return false;
1193b4be Poul Sander 2025-02-03 21:28 1979
    }
1193b4be Poul Sander 2025-02-03 21:28 1980
    return true;
1193b4be Poul Sander 2025-02-03 21:28 1981
}
1193b4be Poul Sander 2025-02-03 21:28 1982
1193b4be Poul Sander 2025-02-03 21:28 1983
void ImTriangulator::ReclassifyNode(ImTriangulatorNode* n1)
1193b4be Poul Sander 2025-02-03 21:28 1984
{
1193b4be Poul Sander 2025-02-03 21:28 1985
    // Classify node
1193b4be Poul Sander 2025-02-03 21:28 1986
    ImTriangulatorNodeType type;
1193b4be Poul Sander 2025-02-03 21:28 1987
    const ImTriangulatorNode* n0 = n1->Prev;
1193b4be Poul Sander 2025-02-03 21:28 1988
    const ImTriangulatorNode* n2 = n1->Next;
1193b4be Poul Sander 2025-02-03 21:28 1989
    if (!ImTriangleIsClockwise(n0->Pos, n1->Pos, n2->Pos))
1193b4be Poul Sander 2025-02-03 21:28 1990
        type = ImTriangulatorNodeType_Reflex;
1193b4be Poul Sander 2025-02-03 21:28 1991
    else if (IsEar(n0->Index, n1->Index, n2->Index, n0->Pos, n1->Pos, n2->Pos))
1193b4be Poul Sander 2025-02-03 21:28 1992
        type = ImTriangulatorNodeType_Ear;
1193b4be Poul Sander 2025-02-03 21:28 1993
    else
1193b4be Poul Sander 2025-02-03 21:28 1994
        type = ImTriangulatorNodeType_Convex;
1193b4be Poul Sander 2025-02-03 21:28 1995
1193b4be Poul Sander 2025-02-03 21:28 1996
    // Update lists when a type changes
1193b4be Poul Sander 2025-02-03 21:28 1997
    if (type == n1->Type)
1193b4be Poul Sander 2025-02-03 21:28 1998
        return;
1193b4be Poul Sander 2025-02-03 21:28 1999
    if (n1->Type == ImTriangulatorNodeType_Reflex)
1193b4be Poul Sander 2025-02-03 21:28 2000
        _Reflexes.find_erase_unsorted(n1->Index);
1193b4be Poul Sander 2025-02-03 21:28 2001
    else if (n1->Type == ImTriangulatorNodeType_Ear)
1193b4be Poul Sander 2025-02-03 21:28 2002
        _Ears.find_erase_unsorted(n1->Index);
1193b4be Poul Sander 2025-02-03 21:28 2003
    if (type == ImTriangulatorNodeType_Reflex)
1193b4be Poul Sander 2025-02-03 21:28 2004
        _Reflexes.push_back(n1);
1193b4be Poul Sander 2025-02-03 21:28 2005
    else if (type == ImTriangulatorNodeType_Ear)
1193b4be Poul Sander 2025-02-03 21:28 2006
        _Ears.push_back(n1);
1193b4be Poul Sander 2025-02-03 21:28 2007
    n1->Type = type;
1193b4be Poul Sander 2025-02-03 21:28 2008
}
1193b4be Poul Sander 2025-02-03 21:28 2009
1193b4be Poul Sander 2025-02-03 21:28 2010
// Use ear-clipping algorithm to triangulate a simple polygon (no self-interaction, no holes).
1193b4be Poul Sander 2025-02-03 21:28 2011
// (Reminder: we don't perform any coarse clipping/culling in ImDrawList layer!
1193b4be Poul Sander 2025-02-03 21:28 2012
// 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 2013
// As concave fill is noticeably more expensive than other primitives, be mindful of this...
1193b4be Poul Sander 2025-02-03 21:28 2014
// 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 2015
void ImDrawList::AddConcavePolyFilled(const ImVec2* points, const int points_count, ImU32 col)
1193b4be Poul Sander 2025-02-03 21:28 2016
{
1193b4be Poul Sander 2025-02-03 21:28 2017
    if (points_count < 3 || (col & IM_COL32_A_MASK) == 0)
1193b4be Poul Sander 2025-02-03 21:28 2018
        return;
1193b4be Poul Sander 2025-02-03 21:28 2019
1193b4be Poul Sander 2025-02-03 21:28 2020
    const ImVec2 uv = _Data->TexUvWhitePixel;
1193b4be Poul Sander 2025-02-03 21:28 2021
    ImTriangulator triangulator;
1193b4be Poul Sander 2025-02-03 21:28 2022
    unsigned int triangle[3];
1193b4be Poul Sander 2025-02-03 21:28 2023
    if (Flags & ImDrawListFlags_AntiAliasedFill)
1193b4be Poul Sander 2025-02-03 21:28 2024
    {
1193b4be Poul Sander 2025-02-03 21:28 2025
        // Anti-aliased Fill
1193b4be Poul Sander 2025-02-03 21:28 2026
        const float AA_SIZE = _FringeScale;
1193b4be Poul Sander 2025-02-03 21:28 2027
        const ImU32 col_trans = col & ~IM_COL32_A_MASK;
1193b4be Poul Sander 2025-02-03 21:28 2028
        const int idx_count = (points_count - 2) * 3 + points_count * 6;
1193b4be Poul Sander 2025-02-03 21:28 2029
        const int vtx_count = (points_count * 2);
1193b4be Poul Sander 2025-02-03 21:28 2030
        PrimReserve(idx_count, vtx_count);
1193b4be Poul Sander 2025-02-03 21:28 2031
1193b4be Poul Sander 2025-02-03 21:28 2032
        // Add indexes for fill
1193b4be Poul Sander 2025-02-03 21:28 2033
        unsigned int vtx_inner_idx = _VtxCurrentIdx;
1193b4be Poul Sander 2025-02-03 21:28 2034
        unsigned int vtx_outer_idx = _VtxCurrentIdx + 1;
1193b4be Poul Sander 2025-02-03 21:28 2035
1193b4be Poul Sander 2025-02-03 21:28 2036
        _Data->TempBuffer.reserve_discard((ImTriangulator::EstimateScratchBufferSize(points_count) + sizeof(ImVec2)) / sizeof(ImVec2));
1193b4be Poul Sander 2025-02-03 21:28 2037
        triangulator.Init(points, points_count, _Data->TempBuffer.Data);
1193b4be Poul Sander 2025-02-03 21:28 2038
        while (triangulator._TrianglesLeft > 0)
1193b4be Poul Sander 2025-02-03 21:28 2039
        {
1193b4be Poul Sander 2025-02-03 21:28 2040
            triangulator.GetNextTriangle(triangle);
1193b4be Poul Sander 2025-02-03 21:28 2041
            _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 2042
            _IdxWritePtr += 3;
1193b4be Poul Sander 2025-02-03 21:28 2043
        }
1193b4be Poul Sander 2025-02-03 21:28 2044
1193b4be Poul Sander 2025-02-03 21:28 2045
        // Compute normals
1193b4be Poul Sander 2025-02-03 21:28 2046
        _Data->TempBuffer.reserve_discard(points_count);
1193b4be Poul Sander 2025-02-03 21:28 2047
        ImVec2* temp_normals = _Data->TempBuffer.Data;
1193b4be Poul Sander 2025-02-03 21:28 2048
        for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++)
1193b4be Poul Sander 2025-02-03 21:28 2049
        {
1193b4be Poul Sander 2025-02-03 21:28 2050
            const ImVec2& p0 = points[i0];
1193b4be Poul Sander 2025-02-03 21:28 2051
            const ImVec2& p1 = points[i1];
1193b4be Poul Sander 2025-02-03 21:28 2052
            float dx = p1.x - p0.x;
1193b4be Poul Sander 2025-02-03 21:28 2053
            float dy = p1.y - p0.y;
1193b4be Poul Sander 2025-02-03 21:28 2054
            IM_NORMALIZE2F_OVER_ZERO(dx, dy);
1193b4be Poul Sander 2025-02-03 21:28 2055
            temp_normals[i0].x = dy;
1193b4be Poul Sander 2025-02-03 21:28 2056
            temp_normals[i0].y = -dx;
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
        for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++)
1193b4be Poul Sander 2025-02-03 21:28 2060
        {
1193b4be Poul Sander 2025-02-03 21:28 2061
            // Average normals
1193b4be Poul Sander 2025-02-03 21:28 2062
            const ImVec2& n0 = temp_normals[i0];
1193b4be Poul Sander 2025-02-03 21:28 2063
            const ImVec2& n1 = temp_normals[i1];
1193b4be Poul Sander 2025-02-03 21:28 2064
            float dm_x = (n0.x + n1.x) * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 2065
            float dm_y = (n0.y + n1.y) * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 2066
            IM_FIXNORMAL2F(dm_x, dm_y);
1193b4be Poul Sander 2025-02-03 21:28 2067
            dm_x *= AA_SIZE * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 2068
            dm_y *= AA_SIZE * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 2069
1193b4be Poul Sander 2025-02-03 21:28 2070
            // Add vertices
1193b4be Poul Sander 2025-02-03 21:28 2071
            _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 2072
            _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 2073
            _VtxWritePtr += 2;
1193b4be Poul Sander 2025-02-03 21:28 2074
1193b4be Poul Sander 2025-02-03 21:28 2075
            // Add indexes for fringes
1193b4be Poul Sander 2025-02-03 21:28 2076
            _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 2077
            _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 2078
            _IdxWritePtr += 6;
1193b4be Poul Sander 2025-02-03 21:28 2079
        }
1193b4be Poul Sander 2025-02-03 21:28 2080
        _VtxCurrentIdx += (ImDrawIdx)vtx_count;
1193b4be Poul Sander 2025-02-03 21:28 2081
    }
1193b4be Poul Sander 2025-02-03 21:28 2082
    else
1193b4be Poul Sander 2025-02-03 21:28 2083
    {
1193b4be Poul Sander 2025-02-03 21:28 2084
        // Non Anti-aliased Fill
1193b4be Poul Sander 2025-02-03 21:28 2085
        const int idx_count = (points_count - 2) * 3;
1193b4be Poul Sander 2025-02-03 21:28 2086
        const int vtx_count = points_count;
1193b4be Poul Sander 2025-02-03 21:28 2087
        PrimReserve(idx_count, vtx_count);
1193b4be Poul Sander 2025-02-03 21:28 2088
        for (int i = 0; i < vtx_count; i++)
1193b4be Poul Sander 2025-02-03 21:28 2089
        {
1193b4be Poul Sander 2025-02-03 21:28 2090
            _VtxWritePtr[0].pos = points[i]; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;
1193b4be Poul Sander 2025-02-03 21:28 2091
            _VtxWritePtr++;
1193b4be Poul Sander 2025-02-03 21:28 2092
        }
1193b4be Poul Sander 2025-02-03 21:28 2093
        _Data->TempBuffer.reserve_discard((ImTriangulator::EstimateScratchBufferSize(points_count) + sizeof(ImVec2)) / sizeof(ImVec2));
1193b4be Poul Sander 2025-02-03 21:28 2094
        triangulator.Init(points, points_count, _Data->TempBuffer.Data);
1193b4be Poul Sander 2025-02-03 21:28 2095
        while (triangulator._TrianglesLeft > 0)
1193b4be Poul Sander 2025-02-03 21:28 2096
        {
1193b4be Poul Sander 2025-02-03 21:28 2097
            triangulator.GetNextTriangle(triangle);
1193b4be Poul Sander 2025-02-03 21:28 2098
            _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 2099
            _IdxWritePtr += 3;
1193b4be Poul Sander 2025-02-03 21:28 2100
        }
1193b4be Poul Sander 2025-02-03 21:28 2101
        _VtxCurrentIdx += (ImDrawIdx)vtx_count;
1193b4be Poul Sander 2025-02-03 21:28 2102
    }
1193b4be Poul Sander 2025-02-03 21:28 2103
}
1193b4be Poul Sander 2025-02-03 21:28 2104
1193b4be Poul Sander 2025-02-03 21:28 2105
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 2106
// [SECTION] ImDrawListSplitter
1193b4be Poul Sander 2025-02-03 21:28 2107
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 2108
// 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 2109
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 2110
1193b4be Poul Sander 2025-02-03 21:28 2111
void ImDrawListSplitter::ClearFreeMemory()
1193b4be Poul Sander 2025-02-03 21:28 2112
{
1193b4be Poul Sander 2025-02-03 21:28 2113
    for (int i = 0; i < _Channels.Size; i++)
1193b4be Poul Sander 2025-02-03 21:28 2114
    {
1193b4be Poul Sander 2025-02-03 21:28 2115
        if (i == _Current)
1193b4be Poul Sander 2025-02-03 21:28 2116
            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 2117
        _Channels[i]._CmdBuffer.clear();
1193b4be Poul Sander 2025-02-03 21:28 2118
        _Channels[i]._IdxBuffer.clear();
1193b4be Poul Sander 2025-02-03 21:28 2119
    }
1193b4be Poul Sander 2025-02-03 21:28 2120
    _Current = 0;
1193b4be Poul Sander 2025-02-03 21:28 2121
    _Count = 1;
1193b4be Poul Sander 2025-02-03 21:28 2122
    _Channels.clear();
1193b4be Poul Sander 2025-02-03 21:28 2123
}
1193b4be Poul Sander 2025-02-03 21:28 2124
1193b4be Poul Sander 2025-02-03 21:28 2125
void ImDrawListSplitter::Split(ImDrawList* draw_list, int channels_count)
1193b4be Poul Sander 2025-02-03 21:28 2126
{
1193b4be Poul Sander 2025-02-03 21:28 2127
    IM_UNUSED(draw_list);
1193b4be Poul Sander 2025-02-03 21:28 2128
    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 2129
    int old_channels_count = _Channels.Size;
1193b4be Poul Sander 2025-02-03 21:28 2130
    if (old_channels_count < channels_count)
1193b4be Poul Sander 2025-02-03 21:28 2131
    {
1193b4be Poul Sander 2025-02-03 21:28 2132
        _Channels.reserve(channels_count); // Avoid over reserving since this is likely to stay stable
1193b4be Poul Sander 2025-02-03 21:28 2133
        _Channels.resize(channels_count);
1193b4be Poul Sander 2025-02-03 21:28 2134
    }
1193b4be Poul Sander 2025-02-03 21:28 2135
    _Count = channels_count;
1193b4be Poul Sander 2025-02-03 21:28 2136
1193b4be Poul Sander 2025-02-03 21:28 2137
    // Channels[] (24/32 bytes each) hold storage that we'll swap with draw_list->_CmdBuffer/_IdxBuffer
1193b4be Poul Sander 2025-02-03 21:28 2138
    // 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 2139
    // 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 2140
    memset(&_Channels[0], 0, sizeof(ImDrawChannel));
1193b4be Poul Sander 2025-02-03 21:28 2141
    for (int i = 1; i < channels_count; i++)
1193b4be Poul Sander 2025-02-03 21:28 2142
    {
1193b4be Poul Sander 2025-02-03 21:28 2143
        if (i >= old_channels_count)
1193b4be Poul Sander 2025-02-03 21:28 2144
        {
1193b4be Poul Sander 2025-02-03 21:28 2145
            IM_PLACEMENT_NEW(&_Channels[i]) ImDrawChannel();
1193b4be Poul Sander 2025-02-03 21:28 2146
        }
1193b4be Poul Sander 2025-02-03 21:28 2147
        else
1193b4be Poul Sander 2025-02-03 21:28 2148
        {
1193b4be Poul Sander 2025-02-03 21:28 2149
            _Channels[i]._CmdBuffer.resize(0);
1193b4be Poul Sander 2025-02-03 21:28 2150
            _Channels[i]._IdxBuffer.resize(0);
1193b4be Poul Sander 2025-02-03 21:28 2151
        }
1193b4be Poul Sander 2025-02-03 21:28 2152
    }
1193b4be Poul Sander 2025-02-03 21:28 2153
}
1193b4be Poul Sander 2025-02-03 21:28 2154
1193b4be Poul Sander 2025-02-03 21:28 2155
void ImDrawListSplitter::Merge(ImDrawList* draw_list)
1193b4be Poul Sander 2025-02-03 21:28 2156
{
1193b4be Poul Sander 2025-02-03 21:28 2157
    // 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 2158
    if (_Count <= 1)
1193b4be Poul Sander 2025-02-03 21:28 2159
        return;
1193b4be Poul Sander 2025-02-03 21:28 2160
1193b4be Poul Sander 2025-02-03 21:28 2161
    SetCurrentChannel(draw_list, 0);
1193b4be Poul Sander 2025-02-03 21:28 2162
    draw_list->_PopUnusedDrawCmd();
1193b4be Poul Sander 2025-02-03 21:28 2163
1193b4be Poul Sander 2025-02-03 21:28 2164
    // Calculate our final buffer sizes. Also fix the incorrect IdxOffset values in each command.
1193b4be Poul Sander 2025-02-03 21:28 2165
    int new_cmd_buffer_count = 0;
1193b4be Poul Sander 2025-02-03 21:28 2166
    int new_idx_buffer_count = 0;
1193b4be Poul Sander 2025-02-03 21:28 2167
    ImDrawCmd* last_cmd = (_Count > 0 && draw_list->CmdBuffer.Size > 0) ? &draw_list->CmdBuffer.back() : NULL;
1193b4be Poul Sander 2025-02-03 21:28 2168
    int idx_offset = last_cmd ? last_cmd->IdxOffset + last_cmd->ElemCount : 0;
1193b4be Poul Sander 2025-02-03 21:28 2169
    for (int i = 1; i < _Count; i++)
1193b4be Poul Sander 2025-02-03 21:28 2170
    {
1193b4be Poul Sander 2025-02-03 21:28 2171
        ImDrawChannel& ch = _Channels[i];
1193b4be Poul Sander 2025-02-03 21:28 2172
        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 2173
            ch._CmdBuffer.pop_back();
1193b4be Poul Sander 2025-02-03 21:28 2174
1193b4be Poul Sander 2025-02-03 21:28 2175
        if (ch._CmdBuffer.Size > 0 && last_cmd != NULL)
1193b4be Poul Sander 2025-02-03 21:28 2176
        {
1193b4be Poul Sander 2025-02-03 21:28 2177
            // Do not include ImDrawCmd_AreSequentialIdxOffset() in the compare as we rebuild IdxOffset values ourselves.
1193b4be Poul Sander 2025-02-03 21:28 2178
            // 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 2179
            ImDrawCmd* next_cmd = &ch._CmdBuffer[0];
1193b4be Poul Sander 2025-02-03 21:28 2180
            if (ImDrawCmd_HeaderCompare(last_cmd, next_cmd) == 0 && last_cmd->UserCallback == NULL && next_cmd->UserCallback == NULL)
1193b4be Poul Sander 2025-02-03 21:28 2181
            {
1193b4be Poul Sander 2025-02-03 21:28 2182
                // Merge previous channel last draw command with current channel first draw command if matching.
1193b4be Poul Sander 2025-02-03 21:28 2183
                last_cmd->ElemCount += next_cmd->ElemCount;
1193b4be Poul Sander 2025-02-03 21:28 2184
                idx_offset += next_cmd->ElemCount;
1193b4be Poul Sander 2025-02-03 21:28 2185
                ch._CmdBuffer.erase(ch._CmdBuffer.Data); // FIXME-OPT: Improve for multiple merges.
1193b4be Poul Sander 2025-02-03 21:28 2186
            }
1193b4be Poul Sander 2025-02-03 21:28 2187
        }
1193b4be Poul Sander 2025-02-03 21:28 2188
        if (ch._CmdBuffer.Size > 0)
1193b4be Poul Sander 2025-02-03 21:28 2189
            last_cmd = &ch._CmdBuffer.back();
1193b4be Poul Sander 2025-02-03 21:28 2190
        new_cmd_buffer_count += ch._CmdBuffer.Size;
1193b4be Poul Sander 2025-02-03 21:28 2191
        new_idx_buffer_count += ch._IdxBuffer.Size;
1193b4be Poul Sander 2025-02-03 21:28 2192
        for (int cmd_n = 0; cmd_n < ch._CmdBuffer.Size; cmd_n++)
1193b4be Poul Sander 2025-02-03 21:28 2193
        {
1193b4be Poul Sander 2025-02-03 21:28 2194
            ch._CmdBuffer.Data[cmd_n].IdxOffset = idx_offset;
1193b4be Poul Sander 2025-02-03 21:28 2195
            idx_offset += ch._CmdBuffer.Data[cmd_n].ElemCount;
1193b4be Poul Sander 2025-02-03 21:28 2196
        }
1193b4be Poul Sander 2025-02-03 21:28 2197
    }
1193b4be Poul Sander 2025-02-03 21:28 2198
    draw_list->CmdBuffer.resize(draw_list->CmdBuffer.Size + new_cmd_buffer_count);
1193b4be Poul Sander 2025-02-03 21:28 2199
    draw_list->IdxBuffer.resize(draw_list->IdxBuffer.Size + new_idx_buffer_count);
1193b4be Poul Sander 2025-02-03 21:28 2200
1193b4be Poul Sander 2025-02-03 21:28 2201
    // 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 2202
    ImDrawCmd* cmd_write = draw_list->CmdBuffer.Data + draw_list->CmdBuffer.Size - new_cmd_buffer_count;
1193b4be Poul Sander 2025-02-03 21:28 2203
    ImDrawIdx* idx_write = draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size - new_idx_buffer_count;
1193b4be Poul Sander 2025-02-03 21:28 2204
    for (int i = 1; i < _Count; i++)
1193b4be Poul Sander 2025-02-03 21:28 2205
    {
1193b4be Poul Sander 2025-02-03 21:28 2206
        ImDrawChannel& ch = _Channels[i];
1193b4be Poul Sander 2025-02-03 21:28 2207
        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 2208
        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 2209
    }
1193b4be Poul Sander 2025-02-03 21:28 2210
    draw_list->_IdxWritePtr = idx_write;
1193b4be Poul Sander 2025-02-03 21:28 2211
1193b4be Poul Sander 2025-02-03 21:28 2212
    // Ensure there's always a non-callback draw command trailing the command-buffer
1193b4be Poul Sander 2025-02-03 21:28 2213
    if (draw_list->CmdBuffer.Size == 0 || draw_list->CmdBuffer.back().UserCallback != NULL)
1193b4be Poul Sander 2025-02-03 21:28 2214
        draw_list->AddDrawCmd();
1193b4be Poul Sander 2025-02-03 21:28 2215
1193b4be Poul Sander 2025-02-03 21:28 2216
    // If current command is used with different settings we need to add a new command
1193b4be Poul Sander 2025-02-03 21:28 2217
    ImDrawCmd* curr_cmd = &draw_list->CmdBuffer.Data[draw_list->CmdBuffer.Size - 1];
1193b4be Poul Sander 2025-02-03 21:28 2218
    if (curr_cmd->ElemCount == 0)
4e9e2555 Poul Sander 2025-10-05 10:15 2219
        ImDrawCmd_HeaderCopy(curr_cmd, &draw_list->_CmdHeader); // Copy ClipRect, TexRef, VtxOffset
1193b4be Poul Sander 2025-02-03 21:28 2220
    else if (ImDrawCmd_HeaderCompare(curr_cmd, &draw_list->_CmdHeader) != 0)
1193b4be Poul Sander 2025-02-03 21:28 2221
        draw_list->AddDrawCmd();
1193b4be Poul Sander 2025-02-03 21:28 2222
1193b4be Poul Sander 2025-02-03 21:28 2223
    _Count = 1;
1193b4be Poul Sander 2025-02-03 21:28 2224
}
1193b4be Poul Sander 2025-02-03 21:28 2225
1193b4be Poul Sander 2025-02-03 21:28 2226
void ImDrawListSplitter::SetCurrentChannel(ImDrawList* draw_list, int idx)
1193b4be Poul Sander 2025-02-03 21:28 2227
{
1193b4be Poul Sander 2025-02-03 21:28 2228
    IM_ASSERT(idx >= 0 && idx < _Count);
1193b4be Poul Sander 2025-02-03 21:28 2229
    if (_Current == idx)
1193b4be Poul Sander 2025-02-03 21:28 2230
        return;
1193b4be Poul Sander 2025-02-03 21:28 2231
1193b4be Poul Sander 2025-02-03 21:28 2232
    // 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 2233
    memcpy(&_Channels.Data[_Current]._CmdBuffer, &draw_list->CmdBuffer, sizeof(draw_list->CmdBuffer));
1193b4be Poul Sander 2025-02-03 21:28 2234
    memcpy(&_Channels.Data[_Current]._IdxBuffer, &draw_list->IdxBuffer, sizeof(draw_list->IdxBuffer));
1193b4be Poul Sander 2025-02-03 21:28 2235
    _Current = idx;
1193b4be Poul Sander 2025-02-03 21:28 2236
    memcpy(&draw_list->CmdBuffer, &_Channels.Data[idx]._CmdBuffer, sizeof(draw_list->CmdBuffer));
1193b4be Poul Sander 2025-02-03 21:28 2237
    memcpy(&draw_list->IdxBuffer, &_Channels.Data[idx]._IdxBuffer, sizeof(draw_list->IdxBuffer));
1193b4be Poul Sander 2025-02-03 21:28 2238
    draw_list->_IdxWritePtr = draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size;
1193b4be Poul Sander 2025-02-03 21:28 2239
1193b4be Poul Sander 2025-02-03 21:28 2240
    // If current command is used with different settings we need to add a new command
1193b4be Poul Sander 2025-02-03 21:28 2241
    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 2242
    if (curr_cmd == NULL)
1193b4be Poul Sander 2025-02-03 21:28 2243
        draw_list->AddDrawCmd();
1193b4be Poul Sander 2025-02-03 21:28 2244
    else if (curr_cmd->ElemCount == 0)
4e9e2555 Poul Sander 2025-10-05 10:15 2245
        ImDrawCmd_HeaderCopy(curr_cmd, &draw_list->_CmdHeader); // Copy ClipRect, TexRef, VtxOffset
1193b4be Poul Sander 2025-02-03 21:28 2246
    else if (ImDrawCmd_HeaderCompare(curr_cmd, &draw_list->_CmdHeader) != 0)
1193b4be Poul Sander 2025-02-03 21:28 2247
        draw_list->AddDrawCmd();
1193b4be Poul Sander 2025-02-03 21:28 2248
}
1193b4be Poul Sander 2025-02-03 21:28 2249
1193b4be Poul Sander 2025-02-03 21:28 2250
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 2251
// [SECTION] ImDrawData
1193b4be Poul Sander 2025-02-03 21:28 2252
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 2253
1193b4be Poul Sander 2025-02-03 21:28 2254
void ImDrawData::Clear()
1193b4be Poul Sander 2025-02-03 21:28 2255
{
1193b4be Poul Sander 2025-02-03 21:28 2256
    Valid = false;
1193b4be Poul Sander 2025-02-03 21:28 2257
    CmdListsCount = TotalIdxCount = TotalVtxCount = 0;
1193b4be Poul Sander 2025-02-03 21:28 2258
    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 2259
    DisplayPos = DisplaySize = FramebufferScale = ImVec2(0.0f, 0.0f);
1193b4be Poul Sander 2025-02-03 21:28 2260
    OwnerViewport = NULL;
4e9e2555 Poul Sander 2025-10-05 10:15 2261
    Textures = NULL;
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
// 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 2265
// 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 2266
void ImGui::AddDrawListToDrawDataEx(ImDrawData* draw_data, ImVector<ImDrawList*>* out_list, ImDrawList* draw_list)
1193b4be Poul Sander 2025-02-03 21:28 2267
{
1193b4be Poul Sander 2025-02-03 21:28 2268
    if (draw_list->CmdBuffer.Size == 0)
1193b4be Poul Sander 2025-02-03 21:28 2269
        return;
1193b4be Poul Sander 2025-02-03 21:28 2270
    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 2271
        return;
1193b4be Poul Sander 2025-02-03 21:28 2272
1193b4be Poul Sander 2025-02-03 21:28 2273
    // Draw list sanity check. Detect mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc.
1193b4be Poul Sander 2025-02-03 21:28 2274
    // May trigger for you if you are using PrimXXX functions incorrectly.
1193b4be Poul Sander 2025-02-03 21:28 2275
    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 2276
    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 2277
    if (!(draw_list->Flags & ImDrawListFlags_AllowVtxOffset))
1193b4be Poul Sander 2025-02-03 21:28 2278
        IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size);
1193b4be Poul Sander 2025-02-03 21:28 2279
1193b4be Poul Sander 2025-02-03 21:28 2280
    // 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 2281
    // If this assert triggers because you are drawing lots of stuff manually:
1193b4be Poul Sander 2025-02-03 21:28 2282
    // - 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 2283
    //   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 2284
    // - If you want large meshes with more than 64K vertices, you can either:
1193b4be Poul Sander 2025-02-03 21:28 2285
    //   (A) Handle the ImDrawCmd::VtxOffset value in your renderer backend, and set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset'.
1193b4be Poul Sander 2025-02-03 21:28 2286
    //       Most example backends already support this from 1.71. Pre-1.71 backends won't.
1193b4be Poul Sander 2025-02-03 21:28 2287
    //       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 2288
    //   (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 2289
    //       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 2290
    //         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 2291
    //       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 2292
    //       2 and 4 bytes indices are generally supported by most graphics API.
1193b4be Poul Sander 2025-02-03 21:28 2293
    // - 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 2294
    //   the 64K limit to split your draw commands in multiple draw lists.
1193b4be Poul Sander 2025-02-03 21:28 2295
    if (sizeof(ImDrawIdx) == 2)
1193b4be Poul Sander 2025-02-03 21:28 2296
        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 2297
1193b4be Poul Sander 2025-02-03 21:28 2298
    // Resolve callback data pointers
1193b4be Poul Sander 2025-02-03 21:28 2299
    if (draw_list->_CallbacksDataBuf.Size > 0)
1193b4be Poul Sander 2025-02-03 21:28 2300
        for (ImDrawCmd& cmd : draw_list->CmdBuffer)
1193b4be Poul Sander 2025-02-03 21:28 2301
            if (cmd.UserCallback != NULL && cmd.UserCallbackDataOffset != -1 && cmd.UserCallbackDataSize > 0)
1193b4be Poul Sander 2025-02-03 21:28 2302
                cmd.UserCallbackData = draw_list->_CallbacksDataBuf.Data + cmd.UserCallbackDataOffset;
1193b4be Poul Sander 2025-02-03 21:28 2303
1193b4be Poul Sander 2025-02-03 21:28 2304
    // Add to output list + records state in ImDrawData
1193b4be Poul Sander 2025-02-03 21:28 2305
    out_list->push_back(draw_list);
1193b4be Poul Sander 2025-02-03 21:28 2306
    draw_data->CmdListsCount++;
1193b4be Poul Sander 2025-02-03 21:28 2307
    draw_data->TotalVtxCount += draw_list->VtxBuffer.Size;
1193b4be Poul Sander 2025-02-03 21:28 2308
    draw_data->TotalIdxCount += draw_list->IdxBuffer.Size;
1193b4be Poul Sander 2025-02-03 21:28 2309
}
1193b4be Poul Sander 2025-02-03 21:28 2310
1193b4be Poul Sander 2025-02-03 21:28 2311
void ImDrawData::AddDrawList(ImDrawList* draw_list)
1193b4be Poul Sander 2025-02-03 21:28 2312
{
1193b4be Poul Sander 2025-02-03 21:28 2313
    IM_ASSERT(CmdLists.Size == CmdListsCount);
1193b4be Poul Sander 2025-02-03 21:28 2314
    draw_list->_PopUnusedDrawCmd();
1193b4be Poul Sander 2025-02-03 21:28 2315
    ImGui::AddDrawListToDrawDataEx(this, &CmdLists, draw_list);
1193b4be Poul Sander 2025-02-03 21:28 2316
}
1193b4be Poul Sander 2025-02-03 21:28 2317
1193b4be Poul Sander 2025-02-03 21:28 2318
// 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 2319
void ImDrawData::DeIndexAllBuffers()
1193b4be Poul Sander 2025-02-03 21:28 2320
{
1193b4be Poul Sander 2025-02-03 21:28 2321
    ImVector<ImDrawVert> new_vtx_buffer;
1193b4be Poul Sander 2025-02-03 21:28 2322
    TotalVtxCount = TotalIdxCount = 0;
4e9e2555 Poul Sander 2025-10-05 10:15 2323
    for (ImDrawList* draw_list : CmdLists)
1193b4be Poul Sander 2025-02-03 21:28 2324
    {
4e9e2555 Poul Sander 2025-10-05 10:15 2325
        if (draw_list->IdxBuffer.empty())
1193b4be Poul Sander 2025-02-03 21:28 2326
            continue;
4e9e2555 Poul Sander 2025-10-05 10:15 2327
        new_vtx_buffer.resize(draw_list->IdxBuffer.Size);
4e9e2555 Poul Sander 2025-10-05 10:15 2328
        for (int j = 0; j < draw_list->IdxBuffer.Size; j++)
4e9e2555 Poul Sander 2025-10-05 10:15 2329
            new_vtx_buffer[j] = draw_list->VtxBuffer[draw_list->IdxBuffer[j]];
4e9e2555 Poul Sander 2025-10-05 10:15 2330
        draw_list->VtxBuffer.swap(new_vtx_buffer);
4e9e2555 Poul Sander 2025-10-05 10:15 2331
        draw_list->IdxBuffer.resize(0);
4e9e2555 Poul Sander 2025-10-05 10:15 2332
        TotalVtxCount += draw_list->VtxBuffer.Size;
1193b4be Poul Sander 2025-02-03 21:28 2333
    }
1193b4be Poul Sander 2025-02-03 21:28 2334
}
1193b4be Poul Sander 2025-02-03 21:28 2335
1193b4be Poul Sander 2025-02-03 21:28 2336
// Helper to scale the ClipRect field of each ImDrawCmd.
1193b4be Poul Sander 2025-02-03 21:28 2337
// Use if your final output buffer is at a different scale than draw_data->DisplaySize,
1193b4be Poul Sander 2025-02-03 21:28 2338
// or if there is a difference between your window resolution and framebuffer resolution.
1193b4be Poul Sander 2025-02-03 21:28 2339
void ImDrawData::ScaleClipRects(const ImVec2& fb_scale)
1193b4be Poul Sander 2025-02-03 21:28 2340
{
1193b4be Poul Sander 2025-02-03 21:28 2341
    for (ImDrawList* draw_list : CmdLists)
1193b4be Poul Sander 2025-02-03 21:28 2342
        for (ImDrawCmd& cmd : draw_list->CmdBuffer)
1193b4be Poul Sander 2025-02-03 21:28 2343
            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 2344
}
1193b4be Poul Sander 2025-02-03 21:28 2345
1193b4be Poul Sander 2025-02-03 21:28 2346
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 2347
// [SECTION] Helpers ShadeVertsXXX functions
1193b4be Poul Sander 2025-02-03 21:28 2348
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 2349
1193b4be Poul Sander 2025-02-03 21:28 2350
// Generic linear color gradient, write to RGB fields, leave A untouched.
1193b4be Poul Sander 2025-02-03 21:28 2351
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 2352
{
1193b4be Poul Sander 2025-02-03 21:28 2353
    ImVec2 gradient_extent = gradient_p1 - gradient_p0;
1193b4be Poul Sander 2025-02-03 21:28 2354
    float gradient_inv_length2 = 1.0f / ImLengthSqr(gradient_extent);
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
    const int col0_r = (int)(col0 >> IM_COL32_R_SHIFT) & 0xFF;
1193b4be Poul Sander 2025-02-03 21:28 2358
    const int col0_g = (int)(col0 >> IM_COL32_G_SHIFT) & 0xFF;
1193b4be Poul Sander 2025-02-03 21:28 2359
    const int col0_b = (int)(col0 >> IM_COL32_B_SHIFT) & 0xFF;
1193b4be Poul Sander 2025-02-03 21:28 2360
    const int col_delta_r = ((int)(col1 >> IM_COL32_R_SHIFT) & 0xFF) - col0_r;
1193b4be Poul Sander 2025-02-03 21:28 2361
    const int col_delta_g = ((int)(col1 >> IM_COL32_G_SHIFT) & 0xFF) - col0_g;
1193b4be Poul Sander 2025-02-03 21:28 2362
    const int col_delta_b = ((int)(col1 >> IM_COL32_B_SHIFT) & 0xFF) - col0_b;
1193b4be Poul Sander 2025-02-03 21:28 2363
    for (ImDrawVert* vert = vert_start; vert < vert_end; vert++)
1193b4be Poul Sander 2025-02-03 21:28 2364
    {
1193b4be Poul Sander 2025-02-03 21:28 2365
        float d = ImDot(vert->pos - gradient_p0, gradient_extent);
1193b4be Poul Sander 2025-02-03 21:28 2366
        float t = ImClamp(d * gradient_inv_length2, 0.0f, 1.0f);
1193b4be Poul Sander 2025-02-03 21:28 2367
        int r = (int)(col0_r + col_delta_r * t);
1193b4be Poul Sander 2025-02-03 21:28 2368
        int g = (int)(col0_g + col_delta_g * t);
1193b4be Poul Sander 2025-02-03 21:28 2369
        int b = (int)(col0_b + col_delta_b * t);
1193b4be Poul Sander 2025-02-03 21:28 2370
        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 2371
    }
1193b4be Poul Sander 2025-02-03 21:28 2372
}
1193b4be Poul Sander 2025-02-03 21:28 2373
1193b4be Poul Sander 2025-02-03 21:28 2374
// Distribute UV over (a, b) rectangle
1193b4be Poul Sander 2025-02-03 21:28 2375
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 2376
{
1193b4be Poul Sander 2025-02-03 21:28 2377
    const ImVec2 size = b - a;
1193b4be Poul Sander 2025-02-03 21:28 2378
    const ImVec2 uv_size = uv_b - uv_a;
1193b4be Poul Sander 2025-02-03 21:28 2379
    const ImVec2 scale = ImVec2(
1193b4be Poul Sander 2025-02-03 21:28 2380
        size.x != 0.0f ? (uv_size.x / size.x) : 0.0f,
1193b4be Poul Sander 2025-02-03 21:28 2381
        size.y != 0.0f ? (uv_size.y / size.y) : 0.0f);
1193b4be Poul Sander 2025-02-03 21:28 2382
1193b4be Poul Sander 2025-02-03 21:28 2383
    ImDrawVert* vert_start = draw_list->VtxBuffer.Data + vert_start_idx;
1193b4be Poul Sander 2025-02-03 21:28 2384
    ImDrawVert* vert_end = draw_list->VtxBuffer.Data + vert_end_idx;
1193b4be Poul Sander 2025-02-03 21:28 2385
    if (clamp)
1193b4be Poul Sander 2025-02-03 21:28 2386
    {
1193b4be Poul Sander 2025-02-03 21:28 2387
        const ImVec2 min = ImMin(uv_a, uv_b);
1193b4be Poul Sander 2025-02-03 21:28 2388
        const ImVec2 max = ImMax(uv_a, uv_b);
1193b4be Poul Sander 2025-02-03 21:28 2389
        for (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex)
1193b4be Poul Sander 2025-02-03 21:28 2390
            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 2391
    }
1193b4be Poul Sander 2025-02-03 21:28 2392
    else
1193b4be Poul Sander 2025-02-03 21:28 2393
    {
1193b4be Poul Sander 2025-02-03 21:28 2394
        for (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex)
1193b4be Poul Sander 2025-02-03 21:28 2395
            vertex->uv = uv_a + ImMul(ImVec2(vertex->pos.x, vertex->pos.y) - a, scale);
1193b4be Poul Sander 2025-02-03 21:28 2396
    }
1193b4be Poul Sander 2025-02-03 21:28 2397
}
1193b4be Poul Sander 2025-02-03 21:28 2398
1193b4be Poul Sander 2025-02-03 21:28 2399
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 2400
{
1193b4be Poul Sander 2025-02-03 21:28 2401
    ImDrawVert* vert_start = draw_list->VtxBuffer.Data + vert_start_idx;
1193b4be Poul Sander 2025-02-03 21:28 2402
    ImDrawVert* vert_end = draw_list->VtxBuffer.Data + vert_end_idx;
1193b4be Poul Sander 2025-02-03 21:28 2403
    for (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex)
1193b4be Poul Sander 2025-02-03 21:28 2404
        vertex->pos = ImRotate(vertex->pos- pivot_in, cos_a, sin_a) + pivot_out;
1193b4be Poul Sander 2025-02-03 21:28 2405
}
1193b4be Poul Sander 2025-02-03 21:28 2406
1193b4be Poul Sander 2025-02-03 21:28 2407
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 2408
// [SECTION] ImFontConfig
1193b4be Poul Sander 2025-02-03 21:28 2409
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 2410
4e9e2555 Poul Sander 2025-10-05 10:15 2411
// FIXME-NEWATLAS: Oversample specification could be more dynamic. For now, favoring automatic selection.
1193b4be Poul Sander 2025-02-03 21:28 2412
ImFontConfig::ImFontConfig()
1193b4be Poul Sander 2025-02-03 21:28 2413
{
1193b4be Poul Sander 2025-02-03 21:28 2414
    memset(this, 0, sizeof(*this));
1193b4be Poul Sander 2025-02-03 21:28 2415
    FontDataOwnedByAtlas = true;
4e9e2555 Poul Sander 2025-10-05 10:15 2416
    OversampleH = 0; // Auto == 1 or 2 depending on size
4e9e2555 Poul Sander 2025-10-05 10:15 2417
    OversampleV = 0; // Auto == 1
1193b4be Poul Sander 2025-02-03 21:28 2418
    GlyphMaxAdvanceX = FLT_MAX;
1193b4be Poul Sander 2025-02-03 21:28 2419
    RasterizerMultiply = 1.0f;
1193b4be Poul Sander 2025-02-03 21:28 2420
    RasterizerDensity = 1.0f;
4e9e2555 Poul Sander 2025-10-05 10:15 2421
    EllipsisChar = 0;
4e9e2555 Poul Sander 2025-10-05 10:15 2422
}
4e9e2555 Poul Sander 2025-10-05 10:15 2423
4e9e2555 Poul Sander 2025-10-05 10:15 2424
//-----------------------------------------------------------------------------
4e9e2555 Poul Sander 2025-10-05 10:15 2425
// [SECTION] ImTextureData
4e9e2555 Poul Sander 2025-10-05 10:15 2426
//-----------------------------------------------------------------------------
4e9e2555 Poul Sander 2025-10-05 10:15 2427
// - ImTextureData::Create()
4e9e2555 Poul Sander 2025-10-05 10:15 2428
// - ImTextureData::DestroyPixels()
4e9e2555 Poul Sander 2025-10-05 10:15 2429
//-----------------------------------------------------------------------------
4e9e2555 Poul Sander 2025-10-05 10:15 2430
4e9e2555 Poul Sander 2025-10-05 10:15 2431
int ImTextureDataGetFormatBytesPerPixel(ImTextureFormat format)
4e9e2555 Poul Sander 2025-10-05 10:15 2432
{
4e9e2555 Poul Sander 2025-10-05 10:15 2433
    switch (format)
4e9e2555 Poul Sander 2025-10-05 10:15 2434
    {
4e9e2555 Poul Sander 2025-10-05 10:15 2435
    case ImTextureFormat_Alpha8: return 1;
4e9e2555 Poul Sander 2025-10-05 10:15 2436
    case ImTextureFormat_RGBA32: return 4;
4e9e2555 Poul Sander 2025-10-05 10:15 2437
    }
4e9e2555 Poul Sander 2025-10-05 10:15 2438
    IM_ASSERT(0);
4e9e2555 Poul Sander 2025-10-05 10:15 2439
    return 0;
4e9e2555 Poul Sander 2025-10-05 10:15 2440
}
4e9e2555 Poul Sander 2025-10-05 10:15 2441
4e9e2555 Poul Sander 2025-10-05 10:15 2442
const char* ImTextureDataGetStatusName(ImTextureStatus status)
4e9e2555 Poul Sander 2025-10-05 10:15 2443
{
4e9e2555 Poul Sander 2025-10-05 10:15 2444
    switch (status)
4e9e2555 Poul Sander 2025-10-05 10:15 2445
    {
4e9e2555 Poul Sander 2025-10-05 10:15 2446
    case ImTextureStatus_OK: return "OK";
4e9e2555 Poul Sander 2025-10-05 10:15 2447
    case ImTextureStatus_Destroyed: return "Destroyed";
4e9e2555 Poul Sander 2025-10-05 10:15 2448
    case ImTextureStatus_WantCreate: return "WantCreate";
4e9e2555 Poul Sander 2025-10-05 10:15 2449
    case ImTextureStatus_WantUpdates: return "WantUpdates";
4e9e2555 Poul Sander 2025-10-05 10:15 2450
    case ImTextureStatus_WantDestroy: return "WantDestroy";
4e9e2555 Poul Sander 2025-10-05 10:15 2451
    }
4e9e2555 Poul Sander 2025-10-05 10:15 2452
    return "N/A";
1193b4be Poul Sander 2025-02-03 21:28 2453
}
1193b4be Poul Sander 2025-02-03 21:28 2454
4e9e2555 Poul Sander 2025-10-05 10:15 2455
const char* ImTextureDataGetFormatName(ImTextureFormat format)
4e9e2555 Poul Sander 2025-10-05 10:15 2456
{
4e9e2555 Poul Sander 2025-10-05 10:15 2457
    switch (format)
4e9e2555 Poul Sander 2025-10-05 10:15 2458
    {
4e9e2555 Poul Sander 2025-10-05 10:15 2459
    case ImTextureFormat_Alpha8: return "Alpha8";
4e9e2555 Poul Sander 2025-10-05 10:15 2460
    case ImTextureFormat_RGBA32: return "RGBA32";
4e9e2555 Poul Sander 2025-10-05 10:15 2461
    }
4e9e2555 Poul Sander 2025-10-05 10:15 2462
    return "N/A";
4e9e2555 Poul Sander 2025-10-05 10:15 2463
}
4e9e2555 Poul Sander 2025-10-05 10:15 2464
4e9e2555 Poul Sander 2025-10-05 10:15 2465
void ImTextureData::Create(ImTextureFormat format, int w, int h)
4e9e2555 Poul Sander 2025-10-05 10:15 2466
{
4e9e2555 Poul Sander 2025-10-05 10:15 2467
    IM_ASSERT(Status == ImTextureStatus_Destroyed);
4e9e2555 Poul Sander 2025-10-05 10:15 2468
    DestroyPixels();
4e9e2555 Poul Sander 2025-10-05 10:15 2469
    Format = format;
4e9e2555 Poul Sander 2025-10-05 10:15 2470
    Status = ImTextureStatus_WantCreate;
4e9e2555 Poul Sander 2025-10-05 10:15 2471
    Width = w;
4e9e2555 Poul Sander 2025-10-05 10:15 2472
    Height = h;
4e9e2555 Poul Sander 2025-10-05 10:15 2473
    BytesPerPixel = ImTextureDataGetFormatBytesPerPixel(format);
4e9e2555 Poul Sander 2025-10-05 10:15 2474
    UseColors = false;
4e9e2555 Poul Sander 2025-10-05 10:15 2475
    Pixels = (unsigned char*)IM_ALLOC(Width * Height * BytesPerPixel);
4e9e2555 Poul Sander 2025-10-05 10:15 2476
    IM_ASSERT(Pixels != NULL);
4e9e2555 Poul Sander 2025-10-05 10:15 2477
    memset(Pixels, 0, Width * Height * BytesPerPixel);
4e9e2555 Poul Sander 2025-10-05 10:15 2478
    UsedRect.x = UsedRect.y = UsedRect.w = UsedRect.h = 0;
4e9e2555 Poul Sander 2025-10-05 10:15 2479
    UpdateRect.x = UpdateRect.y = (unsigned short)~0;
4e9e2555 Poul Sander 2025-10-05 10:15 2480
    UpdateRect.w = UpdateRect.h = 0;
4e9e2555 Poul Sander 2025-10-05 10:15 2481
}
4e9e2555 Poul Sander 2025-10-05 10:15 2482
4e9e2555 Poul Sander 2025-10-05 10:15 2483
void ImTextureData::DestroyPixels()
4e9e2555 Poul Sander 2025-10-05 10:15 2484
{
4e9e2555 Poul Sander 2025-10-05 10:15 2485
    if (Pixels)
4e9e2555 Poul Sander 2025-10-05 10:15 2486
        IM_FREE(Pixels);
4e9e2555 Poul Sander 2025-10-05 10:15 2487
    Pixels = NULL;
4e9e2555 Poul Sander 2025-10-05 10:15 2488
    UseColors = false;
4e9e2555 Poul Sander 2025-10-05 10:15 2489
}
4e9e2555 Poul Sander 2025-10-05 10:15 2490
4e9e2555 Poul Sander 2025-10-05 10:15 2491
//-----------------------------------------------------------------------------
4e9e2555 Poul Sander 2025-10-05 10:15 2492
// [SECTION] ImFontAtlas, ImFontAtlasBuilder
4e9e2555 Poul Sander 2025-10-05 10:15 2493
//-----------------------------------------------------------------------------
4e9e2555 Poul Sander 2025-10-05 10:15 2494
// - Default texture data encoded in ASCII
4e9e2555 Poul Sander 2025-10-05 10:15 2495
// - ImFontAtlas()
4e9e2555 Poul Sander 2025-10-05 10:15 2496
// - ImFontAtlas::Clear()
4e9e2555 Poul Sander 2025-10-05 10:15 2497
// - ImFontAtlas::CompactCache()
4e9e2555 Poul Sander 2025-10-05 10:15 2498
// - ImFontAtlas::ClearInputData()
4e9e2555 Poul Sander 2025-10-05 10:15 2499
// - ImFontAtlas::ClearTexData()
4e9e2555 Poul Sander 2025-10-05 10:15 2500
// - ImFontAtlas::ClearFonts()
4e9e2555 Poul Sander 2025-10-05 10:15 2501
//-----------------------------------------------------------------------------
4e9e2555 Poul Sander 2025-10-05 10:15 2502
// - ImFontAtlasUpdateNewFrame()
4e9e2555 Poul Sander 2025-10-05 10:15 2503
// - ImFontAtlasTextureBlockConvert()
4e9e2555 Poul Sander 2025-10-05 10:15 2504
// - ImFontAtlasTextureBlockPostProcess()
4e9e2555 Poul Sander 2025-10-05 10:15 2505
// - ImFontAtlasTextureBlockPostProcessMultiply()
4e9e2555 Poul Sander 2025-10-05 10:15 2506
// - ImFontAtlasTextureBlockFill()
4e9e2555 Poul Sander 2025-10-05 10:15 2507
// - ImFontAtlasTextureBlockCopy()
4e9e2555 Poul Sander 2025-10-05 10:15 2508
// - ImFontAtlasTextureBlockQueueUpload()
4e9e2555 Poul Sander 2025-10-05 10:15 2509
//-----------------------------------------------------------------------------
4e9e2555 Poul Sander 2025-10-05 10:15 2510
// - ImFontAtlas::GetTexDataAsAlpha8() [legacy]
4e9e2555 Poul Sander 2025-10-05 10:15 2511
// - ImFontAtlas::GetTexDataAsRGBA32() [legacy]
4e9e2555 Poul Sander 2025-10-05 10:15 2512
// - ImFontAtlas::Build() [legacy]
4e9e2555 Poul Sander 2025-10-05 10:15 2513
//-----------------------------------------------------------------------------
4e9e2555 Poul Sander 2025-10-05 10:15 2514
// - ImFontAtlas::AddFont()
4e9e2555 Poul Sander 2025-10-05 10:15 2515
// - ImFontAtlas::AddFontDefault()
4e9e2555 Poul Sander 2025-10-05 10:15 2516
// - ImFontAtlas::AddFontFromFileTTF()
4e9e2555 Poul Sander 2025-10-05 10:15 2517
// - ImFontAtlas::AddFontFromMemoryTTF()
4e9e2555 Poul Sander 2025-10-05 10:15 2518
// - ImFontAtlas::AddFontFromMemoryCompressedTTF()
4e9e2555 Poul Sander 2025-10-05 10:15 2519
// - ImFontAtlas::AddFontFromMemoryCompressedBase85TTF()
4e9e2555 Poul Sander 2025-10-05 10:15 2520
// - ImFontAtlas::RemoveFont()
4e9e2555 Poul Sander 2025-10-05 10:15 2521
// - ImFontAtlasBuildNotifySetFont()
1193b4be Poul Sander 2025-02-03 21:28 2522
//-----------------------------------------------------------------------------
4e9e2555 Poul Sander 2025-10-05 10:15 2523
// - ImFontAtlas::AddCustomRect()
4e9e2555 Poul Sander 2025-10-05 10:15 2524
// - ImFontAtlas::RemoveCustomRect()
4e9e2555 Poul Sander 2025-10-05 10:15 2525
// - ImFontAtlas::GetCustomRect()
4e9e2555 Poul Sander 2025-10-05 10:15 2526
// - ImFontAtlas::AddCustomRectFontGlyph() [legacy]
4e9e2555 Poul Sander 2025-10-05 10:15 2527
// - ImFontAtlas::AddCustomRectFontGlyphForSize() [legacy]
4e9e2555 Poul Sander 2025-10-05 10:15 2528
// - ImFontAtlasGetMouseCursorTexData()
4e9e2555 Poul Sander 2025-10-05 10:15 2529
//-----------------------------------------------------------------------------
4e9e2555 Poul Sander 2025-10-05 10:15 2530
// - ImFontAtlasBuildMain()
4e9e2555 Poul Sander 2025-10-05 10:15 2531
// - ImFontAtlasBuildSetupFontLoader()
4e9e2555 Poul Sander 2025-10-05 10:15 2532
// - ImFontAtlasBuildPreloadAllGlyphRanges()
4e9e2555 Poul Sander 2025-10-05 10:15 2533
// - ImFontAtlasBuildUpdatePointers()
4e9e2555 Poul Sander 2025-10-05 10:15 2534
// - ImFontAtlasBuildRenderBitmapFromString()
4e9e2555 Poul Sander 2025-10-05 10:15 2535
// - ImFontAtlasBuildUpdateBasicTexData()
4e9e2555 Poul Sander 2025-10-05 10:15 2536
// - ImFontAtlasBuildUpdateLinesTexData()
4e9e2555 Poul Sander 2025-10-05 10:15 2537
// - ImFontAtlasBuildAddFont()
4e9e2555 Poul Sander 2025-10-05 10:15 2538
// - ImFontAtlasBuildSetupFontBakedEllipsis()
4e9e2555 Poul Sander 2025-10-05 10:15 2539
// - ImFontAtlasBuildSetupFontBakedBlanks()
4e9e2555 Poul Sander 2025-10-05 10:15 2540
// - ImFontAtlasBuildSetupFontBakedFallback()
4e9e2555 Poul Sander 2025-10-05 10:15 2541
// - ImFontAtlasBuildSetupFontSpecialGlyphs()
4e9e2555 Poul Sander 2025-10-05 10:15 2542
// - ImFontAtlasBuildDiscardBakes()
4e9e2555 Poul Sander 2025-10-05 10:15 2543
// - ImFontAtlasBuildDiscardFontBakedGlyph()
4e9e2555 Poul Sander 2025-10-05 10:15 2544
// - ImFontAtlasBuildDiscardFontBaked()
4e9e2555 Poul Sander 2025-10-05 10:15 2545
// - ImFontAtlasBuildDiscardFontBakes()
4e9e2555 Poul Sander 2025-10-05 10:15 2546
//-----------------------------------------------------------------------------
4e9e2555 Poul Sander 2025-10-05 10:15 2547
// - ImFontAtlasAddDrawListSharedData()
4e9e2555 Poul Sander 2025-10-05 10:15 2548
// - ImFontAtlasRemoveDrawListSharedData()
4e9e2555 Poul Sander 2025-10-05 10:15 2549
// - ImFontAtlasUpdateDrawListsTextures()
4e9e2555 Poul Sander 2025-10-05 10:15 2550
// - ImFontAtlasUpdateDrawListsSharedData()
4e9e2555 Poul Sander 2025-10-05 10:15 2551
//-----------------------------------------------------------------------------
4e9e2555 Poul Sander 2025-10-05 10:15 2552
// - ImFontAtlasBuildSetTexture()
4e9e2555 Poul Sander 2025-10-05 10:15 2553
// - ImFontAtlasBuildAddTexture()
4e9e2555 Poul Sander 2025-10-05 10:15 2554
// - ImFontAtlasBuildMakeSpace()
4e9e2555 Poul Sander 2025-10-05 10:15 2555
// - ImFontAtlasBuildRepackTexture()
4e9e2555 Poul Sander 2025-10-05 10:15 2556
// - ImFontAtlasBuildGrowTexture()
4e9e2555 Poul Sander 2025-10-05 10:15 2557
// - ImFontAtlasBuildRepackOrGrowTexture()
4e9e2555 Poul Sander 2025-10-05 10:15 2558
// - ImFontAtlasBuildGetTextureSizeEstimate()
4e9e2555 Poul Sander 2025-10-05 10:15 2559
// - ImFontAtlasBuildCompactTexture()
4e9e2555 Poul Sander 2025-10-05 10:15 2560
// - ImFontAtlasBuildInit()
4e9e2555 Poul Sander 2025-10-05 10:15 2561
// - ImFontAtlasBuildDestroy()
4e9e2555 Poul Sander 2025-10-05 10:15 2562
//-----------------------------------------------------------------------------
4e9e2555 Poul Sander 2025-10-05 10:15 2563
// - ImFontAtlasPackInit()
4e9e2555 Poul Sander 2025-10-05 10:15 2564
// - ImFontAtlasPackAllocRectEntry()
4e9e2555 Poul Sander 2025-10-05 10:15 2565
// - ImFontAtlasPackReuseRectEntry()
4e9e2555 Poul Sander 2025-10-05 10:15 2566
// - ImFontAtlasPackDiscardRect()
4e9e2555 Poul Sander 2025-10-05 10:15 2567
// - ImFontAtlasPackAddRect()
4e9e2555 Poul Sander 2025-10-05 10:15 2568
// - ImFontAtlasPackGetRect()
4e9e2555 Poul Sander 2025-10-05 10:15 2569
//-----------------------------------------------------------------------------
4e9e2555 Poul Sander 2025-10-05 10:15 2570
// - ImFontBaked_BuildGrowIndex()
4e9e2555 Poul Sander 2025-10-05 10:15 2571
// - ImFontBaked_BuildLoadGlyph()
4e9e2555 Poul Sander 2025-10-05 10:15 2572
// - ImFontBaked_BuildLoadGlyphAdvanceX()
4e9e2555 Poul Sander 2025-10-05 10:15 2573
// - ImFontAtlasDebugLogTextureRequests()
4e9e2555 Poul Sander 2025-10-05 10:15 2574
//-----------------------------------------------------------------------------
4e9e2555 Poul Sander 2025-10-05 10:15 2575
// - ImFontAtlasGetFontLoaderForStbTruetype()
1193b4be Poul Sander 2025-02-03 21:28 2576
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 2577
1193b4be Poul Sander 2025-02-03 21:28 2578
// A work of art lies ahead! (. = white layer, X = black layer, others are blank)
1193b4be Poul Sander 2025-02-03 21:28 2579
// 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 2580
// (This is used when io.MouseDrawCursor = true)
1193b4be Poul Sander 2025-02-03 21:28 2581
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 2582
const int FONT_ATLAS_DEFAULT_TEX_DATA_H = 27;
1193b4be Poul Sander 2025-02-03 21:28 2583
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 2584
{
1193b4be Poul Sander 2025-02-03 21:28 2585
    "..-         -XXXXXXX-    X    -           X           -XXXXXXX          -          XXXXXXX-     XX          - XX       XX "
1193b4be Poul Sander 2025-02-03 21:28 2586
    "..-         -X.....X-   X.X   -          X.X          -X.....X          -          X.....X-    X..X         -X..X     X..X"
1193b4be Poul Sander 2025-02-03 21:28 2587
    "---         -XXX.XXX-  X...X  -         X...X         -X....X           -           X....X-    X..X         -X...X   X...X"
1193b4be Poul Sander 2025-02-03 21:28 2588
    "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 2589
    "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 2590
    "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 2591
    "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 2592
    "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 2593
    "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 2594
    "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 2595
    "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 2596
    "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 2597
    "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 2598
    "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 2599
    "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 2600
    "X......XXXXX-XXXXXXX-   X.X   -    XX    X.X    XX    -          X.....X-X.....X          -   X............X--------------"
1193b4be Poul Sander 2025-02-03 21:28 2601
    "X...X..X    ---------   X.X   -          X.X          -          XXXXXXX-XXXXXXX          -   X...........X -             "
1193b4be Poul Sander 2025-02-03 21:28 2602
    "X..X X..X   -       -XXXX.XXXX-       XXXX.XXXX       -------------------------------------    X..........X -             "
1193b4be Poul Sander 2025-02-03 21:28 2603
    "X.X  X..X   -       -X.......X-       X.......X       -    XX           XX    -           -    X..........X -             "
1193b4be Poul Sander 2025-02-03 21:28 2604
    "XX    X..X  -       - X.....X -        X.....X        -   X.X           X.X   -           -     X........X  -             "
1193b4be Poul Sander 2025-02-03 21:28 2605
    "      X..X  -       -  X...X  -         X...X         -  X..X           X..X  -           -     X........X  -             "
1193b4be Poul Sander 2025-02-03 21:28 2606
    "       XX   -       -   X.X   -          X.X          - X...XXXXXXXXXXXXX...X -           -     XXXXXXXXXX  -             "
1193b4be Poul Sander 2025-02-03 21:28 2607
    "-------------       -    X    -           X           -X.....................X-           -------------------             "
1193b4be Poul Sander 2025-02-03 21:28 2608
    "                    ----------------------------------- X...XXXXXXXXXXXXX...X -                                           "
1193b4be Poul Sander 2025-02-03 21:28 2609
    "                                                      -  X..X           X..X  -                                           "
1193b4be Poul Sander 2025-02-03 21:28 2610
    "                                                      -   X.X           X.X   -                                           "
1193b4be Poul Sander 2025-02-03 21:28 2611
    "                                                      -    XX           XX    -                                           "
1193b4be Poul Sander 2025-02-03 21:28 2612
};
1193b4be Poul Sander 2025-02-03 21:28 2613
1193b4be Poul Sander 2025-02-03 21:28 2614
static const ImVec2 FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[ImGuiMouseCursor_COUNT][3] =
1193b4be Poul Sander 2025-02-03 21:28 2615
{
1193b4be Poul Sander 2025-02-03 21:28 2616
    // Pos ........ Size ......... Offset ......
1193b4be Poul Sander 2025-02-03 21:28 2617
    { ImVec2( 0,3), ImVec2(12,19), ImVec2( 0, 0) }, // ImGuiMouseCursor_Arrow
1193b4be Poul Sander 2025-02-03 21:28 2618
    { ImVec2(13,0), ImVec2( 7,16), ImVec2( 1, 8) }, // ImGuiMouseCursor_TextInput
1193b4be Poul Sander 2025-02-03 21:28 2619
    { ImVec2(31,0), ImVec2(23,23), ImVec2(11,11) }, // ImGuiMouseCursor_ResizeAll
1193b4be Poul Sander 2025-02-03 21:28 2620
    { ImVec2(21,0), ImVec2( 9,23), ImVec2( 4,11) }, // ImGuiMouseCursor_ResizeNS
1193b4be Poul Sander 2025-02-03 21:28 2621
    { ImVec2(55,18),ImVec2(23, 9), ImVec2(11, 4) }, // ImGuiMouseCursor_ResizeEW
1193b4be Poul Sander 2025-02-03 21:28 2622
    { ImVec2(73,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNESW
1193b4be Poul Sander 2025-02-03 21:28 2623
    { ImVec2(55,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNWSE
1193b4be Poul Sander 2025-02-03 21:28 2624
    { ImVec2(91,0), ImVec2(17,22), ImVec2( 5, 0) }, // ImGuiMouseCursor_Hand
4e9e2555 Poul Sander 2025-10-05 10:15 2625
    { ImVec2(0,3),  ImVec2(12,19), ImVec2(0, 0) },  // ImGuiMouseCursor_Wait       // Arrow + custom code in ImGui::RenderMouseCursor()
4e9e2555 Poul Sander 2025-10-05 10:15 2626
    { ImVec2(0,3),  ImVec2(12,19), ImVec2(0, 0) },  // ImGuiMouseCursor_Progress   // Arrow + custom code in ImGui::RenderMouseCursor()
1193b4be Poul Sander 2025-02-03 21:28 2627
    { ImVec2(109,0),ImVec2(13,15), ImVec2( 6, 7) }, // ImGuiMouseCursor_NotAllowed
1193b4be Poul Sander 2025-02-03 21:28 2628
};
1193b4be Poul Sander 2025-02-03 21:28 2629
4e9e2555 Poul Sander 2025-10-05 10:15 2630
#define IM_FONTGLYPH_INDEX_UNUSED           ((ImU16)-1) // 0xFFFF
4e9e2555 Poul Sander 2025-10-05 10:15 2631
#define IM_FONTGLYPH_INDEX_NOT_FOUND        ((ImU16)-2) // 0xFFFE
4e9e2555 Poul Sander 2025-10-05 10:15 2632
1193b4be Poul Sander 2025-02-03 21:28 2633
ImFontAtlas::ImFontAtlas()
1193b4be Poul Sander 2025-02-03 21:28 2634
{
1193b4be Poul Sander 2025-02-03 21:28 2635
    memset(this, 0, sizeof(*this));
4e9e2555 Poul Sander 2025-10-05 10:15 2636
    TexDesiredFormat = ImTextureFormat_RGBA32;
1193b4be Poul Sander 2025-02-03 21:28 2637
    TexGlyphPadding = 1;
4e9e2555 Poul Sander 2025-10-05 10:15 2638
    TexMinWidth = 512;
4e9e2555 Poul Sander 2025-10-05 10:15 2639
    TexMinHeight = 128;
4e9e2555 Poul Sander 2025-10-05 10:15 2640
    TexMaxWidth = 8192;
4e9e2555 Poul Sander 2025-10-05 10:15 2641
    TexMaxHeight = 8192;
4e9e2555 Poul Sander 2025-10-05 10:15 2642
    TexRef._TexID = ImTextureID_Invalid;
4e9e2555 Poul Sander 2025-10-05 10:15 2643
    RendererHasTextures = false; // Assumed false by default, as apps can call e.g Atlas::Build() after backend init and before ImGui can update.
4e9e2555 Poul Sander 2025-10-05 10:15 2644
    TexNextUniqueID = 1;
4e9e2555 Poul Sander 2025-10-05 10:15 2645
    FontNextUniqueID = 1;
4e9e2555 Poul Sander 2025-10-05 10:15 2646
    Builder = NULL;
1193b4be Poul Sander 2025-02-03 21:28 2647
}
1193b4be Poul Sander 2025-02-03 21:28 2648
1193b4be Poul Sander 2025-02-03 21:28 2649
ImFontAtlas::~ImFontAtlas()
1193b4be Poul Sander 2025-02-03 21:28 2650
{
4e9e2555 Poul Sander 2025-10-05 10:15 2651
    IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!");
4e9e2555 Poul Sander 2025-10-05 10:15 2652
    RendererHasTextures = false; // Full Clear() is supported, but ClearTexData() only isn't.
4e9e2555 Poul Sander 2025-10-05 10:15 2653
    ClearFonts();
4e9e2555 Poul Sander 2025-10-05 10:15 2654
    ClearTexData();
4e9e2555 Poul Sander 2025-10-05 10:15 2655
    TexList.clear_delete();
4e9e2555 Poul Sander 2025-10-05 10:15 2656
    TexData = NULL;
4e9e2555 Poul Sander 2025-10-05 10:15 2657
}
4e9e2555 Poul Sander 2025-10-05 10:15 2658
4e9e2555 Poul Sander 2025-10-05 10:15 2659
void ImFontAtlas::Clear()
4e9e2555 Poul Sander 2025-10-05 10:15 2660
{
4e9e2555 Poul Sander 2025-10-05 10:15 2661
    bool backup_renderer_has_textures = RendererHasTextures;
4e9e2555 Poul Sander 2025-10-05 10:15 2662
    RendererHasTextures = false; // Full Clear() is supported, but ClearTexData() only isn't.
4e9e2555 Poul Sander 2025-10-05 10:15 2663
    ClearFonts();
4e9e2555 Poul Sander 2025-10-05 10:15 2664
    ClearTexData();
4e9e2555 Poul Sander 2025-10-05 10:15 2665
    RendererHasTextures = backup_renderer_has_textures;
1193b4be Poul Sander 2025-02-03 21:28 2666
}
1193b4be Poul Sander 2025-02-03 21:28 2667
4e9e2555 Poul Sander 2025-10-05 10:15 2668
void ImFontAtlas::CompactCache()
1193b4be Poul Sander 2025-02-03 21:28 2669
{
4e9e2555 Poul Sander 2025-10-05 10:15 2670
    ImFontAtlasTextureCompact(this);
4e9e2555 Poul Sander 2025-10-05 10:15 2671
}
4e9e2555 Poul Sander 2025-10-05 10:15 2672
4e9e2555 Poul Sander 2025-10-05 10:15 2673
void ImFontAtlas::SetFontLoader(const ImFontLoader* font_loader)
4e9e2555 Poul Sander 2025-10-05 10:15 2674
{
4e9e2555 Poul Sander 2025-10-05 10:15 2675
    ImFontAtlasBuildSetupFontLoader(this, font_loader);
4e9e2555 Poul Sander 2025-10-05 10:15 2676
}
4e9e2555 Poul Sander 2025-10-05 10:15 2677
4e9e2555 Poul Sander 2025-10-05 10:15 2678
void ImFontAtlas::ClearInputData()
4e9e2555 Poul Sander 2025-10-05 10:15 2679
{
4e9e2555 Poul Sander 2025-10-05 10:15 2680
    IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!");
1193b4be Poul Sander 2025-02-03 21:28 2681
1193b4be Poul Sander 2025-02-03 21:28 2682
    for (ImFont* font : Fonts)
4e9e2555 Poul Sander 2025-10-05 10:15 2683
        ImFontAtlasFontDestroyOutput(this, font);
4e9e2555 Poul Sander 2025-10-05 10:15 2684
    for (ImFontConfig& font_cfg : Sources)
4e9e2555 Poul Sander 2025-10-05 10:15 2685
        ImFontAtlasFontDestroySourceData(this, &font_cfg);
4e9e2555 Poul Sander 2025-10-05 10:15 2686
    for (ImFont* font : Fonts)
4e9e2555 Poul Sander 2025-10-05 10:15 2687
    {
4e9e2555 Poul Sander 2025-10-05 10:15 2688
        // When clearing this we lose access to the font name and other information used to build the font.
4e9e2555 Poul Sander 2025-10-05 10:15 2689
        font->Sources.clear();
4e9e2555 Poul Sander 2025-10-05 10:15 2690
        font->Flags |= ImFontFlags_NoLoadGlyphs;
4e9e2555 Poul Sander 2025-10-05 10:15 2691
    }
4e9e2555 Poul Sander 2025-10-05 10:15 2692
    Sources.clear();
4e9e2555 Poul Sander 2025-10-05 10:15 2693
}
4e9e2555 Poul Sander 2025-10-05 10:15 2694
4e9e2555 Poul Sander 2025-10-05 10:15 2695
// Clear CPU-side copy of the texture data.
4e9e2555 Poul Sander 2025-10-05 10:15 2696
void ImFontAtlas::ClearTexData()
4e9e2555 Poul Sander 2025-10-05 10:15 2697
{
4e9e2555 Poul Sander 2025-10-05 10:15 2698
    IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!");
4e9e2555 Poul Sander 2025-10-05 10:15 2699
    IM_ASSERT(RendererHasTextures == false && "Not supported for dynamic atlases, but you may call Clear().");
4e9e2555 Poul Sander 2025-10-05 10:15 2700
    for (ImTextureData* tex : TexList)
4e9e2555 Poul Sander 2025-10-05 10:15 2701
        tex->DestroyPixels();
4e9e2555 Poul Sander 2025-10-05 10:15 2702
    //Locked = true; // Hoped to be able to lock this down but some reload patterns may not be happy with it.
4e9e2555 Poul Sander 2025-10-05 10:15 2703
}
4e9e2555 Poul Sander 2025-10-05 10:15 2704
4e9e2555 Poul Sander 2025-10-05 10:15 2705
void ImFontAtlas::ClearFonts()
4e9e2555 Poul Sander 2025-10-05 10:15 2706
{
4e9e2555 Poul Sander 2025-10-05 10:15 2707
    // FIXME-NEWATLAS: Illegal to remove currently bound font.
4e9e2555 Poul Sander 2025-10-05 10:15 2708
    IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!");
4e9e2555 Poul Sander 2025-10-05 10:15 2709
    ImFontAtlasBuildDestroy(this);
4e9e2555 Poul Sander 2025-10-05 10:15 2710
    ClearInputData();
4e9e2555 Poul Sander 2025-10-05 10:15 2711
    Fonts.clear_delete();
4e9e2555 Poul Sander 2025-10-05 10:15 2712
    TexIsBuilt = false;
4e9e2555 Poul Sander 2025-10-05 10:15 2713
    for (ImDrawListSharedData* shared_data : DrawListSharedDatas)
4e9e2555 Poul Sander 2025-10-05 10:15 2714
        if (shared_data->FontAtlas == this)
1193b4be Poul Sander 2025-02-03 21:28 2715
        {
4e9e2555 Poul Sander 2025-10-05 10:15 2716
            shared_data->Font = NULL;
4e9e2555 Poul Sander 2025-10-05 10:15 2717
            shared_data->FontScale = shared_data->FontSize = 0.0f;
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
4e9e2555 Poul Sander 2025-10-05 10:15 2721
static void ImFontAtlasBuildUpdateRendererHasTexturesFromContext(ImFontAtlas* atlas)
1193b4be Poul Sander 2025-02-03 21:28 2722
{
4e9e2555 Poul Sander 2025-10-05 10:15 2723
    // [LEGACY] Copy back the ImGuiBackendFlags_RendererHasTextures flag from ImGui context.
4e9e2555 Poul Sander 2025-10-05 10:15 2724
    // - This is the 1% exceptional case where that dependency if useful, to bypass an issue where otherwise at the
4e9e2555 Poul Sander 2025-10-05 10:15 2725
    //   time of an early call to Build(), it would be impossible for us to tell if the backend supports texture update.
4e9e2555 Poul Sander 2025-10-05 10:15 2726
    // - Without this hack, we would have quite a pitfall as many legacy codebases have an early call to Build().
4e9e2555 Poul Sander 2025-10-05 10:15 2727
    //   Whereas conversely, the portion of people using ImDrawList without ImGui is expected to be pathologically rare.
4e9e2555 Poul Sander 2025-10-05 10:15 2728
    for (ImDrawListSharedData* shared_data : atlas->DrawListSharedDatas)
4e9e2555 Poul Sander 2025-10-05 10:15 2729
        if (ImGuiContext* imgui_ctx = shared_data->Context)
4e9e2555 Poul Sander 2025-10-05 10:15 2730
        {
4e9e2555 Poul Sander 2025-10-05 10:15 2731
            atlas->RendererHasTextures = (imgui_ctx->IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) != 0;
4e9e2555 Poul Sander 2025-10-05 10:15 2732
            break;
4e9e2555 Poul Sander 2025-10-05 10:15 2733
        }
1193b4be Poul Sander 2025-02-03 21:28 2734
}
1193b4be Poul Sander 2025-02-03 21:28 2735
4e9e2555 Poul Sander 2025-10-05 10:15 2736
// Called by NewFrame() for atlases owned by a context.
4e9e2555 Poul Sander 2025-10-05 10:15 2737
// If you manually manage font atlases, you'll need to call this yourself.
4e9e2555 Poul Sander 2025-10-05 10:15 2738
// - 'frame_count' needs to be provided because we can gc/prioritize baked fonts based on their age.
4e9e2555 Poul Sander 2025-10-05 10:15 2739
// - 'frame_count' may not match those of all imgui contexts using this atlas, as contexts may be updated as different frequencies. But generally you can use ImGui::GetFrameCount() on one of your context.
4e9e2555 Poul Sander 2025-10-05 10:15 2740
void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas, int frame_count, bool renderer_has_textures)
1193b4be Poul Sander 2025-02-03 21:28 2741
{
4e9e2555 Poul Sander 2025-10-05 10:15 2742
    IM_ASSERT(atlas->Builder == NULL || atlas->Builder->FrameCount < frame_count); // Protection against being called twice.
4e9e2555 Poul Sander 2025-10-05 10:15 2743
    atlas->RendererHasTextures = renderer_has_textures;
4e9e2555 Poul Sander 2025-10-05 10:15 2744
4e9e2555 Poul Sander 2025-10-05 10:15 2745
    // Check that font atlas was built or backend support texture reload in which case we can build now
4e9e2555 Poul Sander 2025-10-05 10:15 2746
    if (atlas->RendererHasTextures)
4e9e2555 Poul Sander 2025-10-05 10:15 2747
    {
4e9e2555 Poul Sander 2025-10-05 10:15 2748
        atlas->TexIsBuilt = true;
4e9e2555 Poul Sander 2025-10-05 10:15 2749
        if (atlas->Builder == NULL) // This will only happen if fonts were not already loaded.
4e9e2555 Poul Sander 2025-10-05 10:15 2750
            ImFontAtlasBuildMain(atlas);
4e9e2555 Poul Sander 2025-10-05 10:15 2751
    }
4e9e2555 Poul Sander 2025-10-05 10:15 2752
    // Legacy backend
4e9e2555 Poul Sander 2025-10-05 10:15 2753
    if (!atlas->RendererHasTextures)
4e9e2555 Poul Sander 2025-10-05 10:15 2754
        IM_ASSERT_USER_ERROR(atlas->TexIsBuilt, "Backend does not support ImGuiBackendFlags_RendererHasTextures, and font atlas is not built! Update backend OR make sure you called ImGui_ImplXXXX_NewFrame() function for renderer backend, which should call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8().");
4e9e2555 Poul Sander 2025-10-05 10:15 2755
    if (atlas->TexIsBuilt && atlas->Builder->PreloadedAllGlyphsRanges)
4e9e2555 Poul Sander 2025-10-05 10:15 2756
        IM_ASSERT_USER_ERROR(atlas->RendererHasTextures == false, "Called ImFontAtlas::Build() before ImGuiBackendFlags_RendererHasTextures got set! With new backends: you don't need to call Build().");
4e9e2555 Poul Sander 2025-10-05 10:15 2757
4e9e2555 Poul Sander 2025-10-05 10:15 2758
    // Clear BakedCurrent cache, this is important because it ensure the uncached path gets taken once.
4e9e2555 Poul Sander 2025-10-05 10:15 2759
    // We also rely on ImFontBaked* pointers never crossing frames.
4e9e2555 Poul Sander 2025-10-05 10:15 2760
    ImFontAtlasBuilder* builder = atlas->Builder;
4e9e2555 Poul Sander 2025-10-05 10:15 2761
    builder->FrameCount = frame_count;
4e9e2555 Poul Sander 2025-10-05 10:15 2762
    for (ImFont* font : atlas->Fonts)
4e9e2555 Poul Sander 2025-10-05 10:15 2763
        font->LastBaked = NULL;
4e9e2555 Poul Sander 2025-10-05 10:15 2764
4e9e2555 Poul Sander 2025-10-05 10:15 2765
    // Garbage collect BakedPool
4e9e2555 Poul Sander 2025-10-05 10:15 2766
    if (builder->BakedDiscardedCount > 0)
4e9e2555 Poul Sander 2025-10-05 10:15 2767
    {
4e9e2555 Poul Sander 2025-10-05 10:15 2768
        int dst_n = 0, src_n = 0;
4e9e2555 Poul Sander 2025-10-05 10:15 2769
        for (; src_n < builder->BakedPool.Size; src_n++)
4e9e2555 Poul Sander 2025-10-05 10:15 2770
        {
4e9e2555 Poul Sander 2025-10-05 10:15 2771
            ImFontBaked* p_src = &builder->BakedPool[src_n];
4e9e2555 Poul Sander 2025-10-05 10:15 2772
            if (p_src->WantDestroy)
4e9e2555 Poul Sander 2025-10-05 10:15 2773
                continue;
4e9e2555 Poul Sander 2025-10-05 10:15 2774
            ImFontBaked* p_dst = &builder->BakedPool[dst_n++];
4e9e2555 Poul Sander 2025-10-05 10:15 2775
            if (p_dst == p_src)
4e9e2555 Poul Sander 2025-10-05 10:15 2776
                continue;
4e9e2555 Poul Sander 2025-10-05 10:15 2777
            memcpy(p_dst, p_src, sizeof(ImFontBaked));
4e9e2555 Poul Sander 2025-10-05 10:15 2778
            builder->BakedMap.SetVoidPtr(p_dst->BakedId, p_dst);
4e9e2555 Poul Sander 2025-10-05 10:15 2779
        }
4e9e2555 Poul Sander 2025-10-05 10:15 2780
        IM_ASSERT(dst_n + builder->BakedDiscardedCount == src_n);
4e9e2555 Poul Sander 2025-10-05 10:15 2781
        builder->BakedPool.Size -= builder->BakedDiscardedCount;
4e9e2555 Poul Sander 2025-10-05 10:15 2782
        builder->BakedDiscardedCount = 0;
4e9e2555 Poul Sander 2025-10-05 10:15 2783
    }
4e9e2555 Poul Sander 2025-10-05 10:15 2784
4e9e2555 Poul Sander 2025-10-05 10:15 2785
    // Update texture status
4e9e2555 Poul Sander 2025-10-05 10:15 2786
    for (int tex_n = 0; tex_n < atlas->TexList.Size; tex_n++)
4e9e2555 Poul Sander 2025-10-05 10:15 2787
    {
4e9e2555 Poul Sander 2025-10-05 10:15 2788
        ImTextureData* tex = atlas->TexList[tex_n];
4e9e2555 Poul Sander 2025-10-05 10:15 2789
        bool remove_from_list = false;
4e9e2555 Poul Sander 2025-10-05 10:15 2790
        if (tex->Status == ImTextureStatus_OK)
4e9e2555 Poul Sander 2025-10-05 10:15 2791
        {
4e9e2555 Poul Sander 2025-10-05 10:15 2792
            tex->Updates.resize(0);
4e9e2555 Poul Sander 2025-10-05 10:15 2793
            tex->UpdateRect.x = tex->UpdateRect.y = (unsigned short)~0;
4e9e2555 Poul Sander 2025-10-05 10:15 2794
            tex->UpdateRect.w = tex->UpdateRect.h = 0;
4e9e2555 Poul Sander 2025-10-05 10:15 2795
        }
4e9e2555 Poul Sander 2025-10-05 10:15 2796
        if (tex->Status == ImTextureStatus_WantCreate && atlas->RendererHasTextures)
4e9e2555 Poul Sander 2025-10-05 10:15 2797
            IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == NULL && "Backend set texture's TexID/BackendUserData but did not update Status to OK.");
4e9e2555 Poul Sander 2025-10-05 10:15 2798
4e9e2555 Poul Sander 2025-10-05 10:15 2799
        if (tex->Status == ImTextureStatus_Destroyed)
4e9e2555 Poul Sander 2025-10-05 10:15 2800
        {
4e9e2555 Poul Sander 2025-10-05 10:15 2801
            IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == NULL && "Backend set texture Status to Destroyed but did not clear TexID/BackendUserData!");
4e9e2555 Poul Sander 2025-10-05 10:15 2802
            if (tex->WantDestroyNextFrame)
4e9e2555 Poul Sander 2025-10-05 10:15 2803
                remove_from_list = true; // Destroy was scheduled by us
4e9e2555 Poul Sander 2025-10-05 10:15 2804
            else
4e9e2555 Poul Sander 2025-10-05 10:15 2805
                tex->Status = ImTextureStatus_WantCreate; // Destroy was done was backend (e.g. freed resources mid-run)
4e9e2555 Poul Sander 2025-10-05 10:15 2806
        }
4e9e2555 Poul Sander 2025-10-05 10:15 2807
        else if (tex->WantDestroyNextFrame && tex->Status != ImTextureStatus_WantDestroy)
4e9e2555 Poul Sander 2025-10-05 10:15 2808
        {
4e9e2555 Poul Sander 2025-10-05 10:15 2809
            // Request destroy.
4e9e2555 Poul Sander 2025-10-05 10:15 2810
            // - Keep bool to true in order to differentiate a planned destroy vs a destroy decided by the backend.
4e9e2555 Poul Sander 2025-10-05 10:15 2811
            // - We don't destroy pixels right away, as backend may have an in-flight copy from RAM.
4e9e2555 Poul Sander 2025-10-05 10:15 2812
            IM_ASSERT(tex->Status == ImTextureStatus_OK || tex->Status == ImTextureStatus_WantCreate || tex->Status == ImTextureStatus_WantUpdates);
4e9e2555 Poul Sander 2025-10-05 10:15 2813
            tex->Status = ImTextureStatus_WantDestroy;
4e9e2555 Poul Sander 2025-10-05 10:15 2814
        }
4e9e2555 Poul Sander 2025-10-05 10:15 2815
4e9e2555 Poul Sander 2025-10-05 10:15 2816
        // The backend may need defer destroying by a few frames, to handle texture used by previous in-flight rendering.
4e9e2555 Poul Sander 2025-10-05 10:15 2817
        // We allow the texture staying in _WantDestroy state and increment a counter which the backend can use to take its decision.
4e9e2555 Poul Sander 2025-10-05 10:15 2818
        if (tex->Status == ImTextureStatus_WantDestroy)
4e9e2555 Poul Sander 2025-10-05 10:15 2819
            tex->UnusedFrames++;
4e9e2555 Poul Sander 2025-10-05 10:15 2820
4e9e2555 Poul Sander 2025-10-05 10:15 2821
        // If a texture has never reached the backend, they don't need to know about it.
4e9e2555 Poul Sander 2025-10-05 10:15 2822
        if (tex->Status == ImTextureStatus_WantDestroy && tex->TexID == ImTextureID_Invalid && tex->BackendUserData == NULL)
4e9e2555 Poul Sander 2025-10-05 10:15 2823
            remove_from_list = true;
4e9e2555 Poul Sander 2025-10-05 10:15 2824
4e9e2555 Poul Sander 2025-10-05 10:15 2825
        // Destroy and remove
4e9e2555 Poul Sander 2025-10-05 10:15 2826
        if (remove_from_list)
4e9e2555 Poul Sander 2025-10-05 10:15 2827
        {
4e9e2555 Poul Sander 2025-10-05 10:15 2828
            tex->DestroyPixels();
4e9e2555 Poul Sander 2025-10-05 10:15 2829
            IM_DELETE(tex);
4e9e2555 Poul Sander 2025-10-05 10:15 2830
            atlas->TexList.erase(atlas->TexList.begin() + tex_n);
4e9e2555 Poul Sander 2025-10-05 10:15 2831
            tex_n--;
4e9e2555 Poul Sander 2025-10-05 10:15 2832
        }
4e9e2555 Poul Sander 2025-10-05 10:15 2833
    }
1193b4be Poul Sander 2025-02-03 21:28 2834
}
1193b4be Poul Sander 2025-02-03 21:28 2835
4e9e2555 Poul Sander 2025-10-05 10:15 2836
void ImFontAtlasTextureBlockConvert(const unsigned char* src_pixels, ImTextureFormat src_fmt, int src_pitch, unsigned char* dst_pixels, ImTextureFormat dst_fmt, int dst_pitch, int w, int h)
1193b4be Poul Sander 2025-02-03 21:28 2837
{
4e9e2555 Poul Sander 2025-10-05 10:15 2838
    IM_ASSERT(src_pixels != NULL && dst_pixels != NULL);
4e9e2555 Poul Sander 2025-10-05 10:15 2839
    if (src_fmt == dst_fmt)
4e9e2555 Poul Sander 2025-10-05 10:15 2840
    {
4e9e2555 Poul Sander 2025-10-05 10:15 2841
        int line_sz = w * ImTextureDataGetFormatBytesPerPixel(src_fmt);
4e9e2555 Poul Sander 2025-10-05 10:15 2842
        for (int ny = h; ny > 0; ny--, src_pixels += src_pitch, dst_pixels += dst_pitch)
4e9e2555 Poul Sander 2025-10-05 10:15 2843
            memcpy(dst_pixels, src_pixels, line_sz);
4e9e2555 Poul Sander 2025-10-05 10:15 2844
    }
4e9e2555 Poul Sander 2025-10-05 10:15 2845
    else if (src_fmt == ImTextureFormat_Alpha8 && dst_fmt == ImTextureFormat_RGBA32)
4e9e2555 Poul Sander 2025-10-05 10:15 2846
    {
4e9e2555 Poul Sander 2025-10-05 10:15 2847
        for (int ny = h; ny > 0; ny--, src_pixels += src_pitch, dst_pixels += dst_pitch)
4e9e2555 Poul Sander 2025-10-05 10:15 2848
        {
4e9e2555 Poul Sander 2025-10-05 10:15 2849
            const ImU8* src_p = (const ImU8*)src_pixels;
4e9e2555 Poul Sander 2025-10-05 10:15 2850
            ImU32* dst_p = (ImU32*)(void*)dst_pixels;
4e9e2555 Poul Sander 2025-10-05 10:15 2851
            for (int nx = w; nx > 0; nx--)
4e9e2555 Poul Sander 2025-10-05 10:15 2852
                *dst_p++ = IM_COL32(255, 255, 255, (unsigned int)(*src_p++));
4e9e2555 Poul Sander 2025-10-05 10:15 2853
        }
4e9e2555 Poul Sander 2025-10-05 10:15 2854
    }
4e9e2555 Poul Sander 2025-10-05 10:15 2855
    else if (src_fmt == ImTextureFormat_RGBA32 && dst_fmt == ImTextureFormat_Alpha8)
4e9e2555 Poul Sander 2025-10-05 10:15 2856
    {
4e9e2555 Poul Sander 2025-10-05 10:15 2857
        for (int ny = h; ny > 0; ny--, src_pixels += src_pitch, dst_pixels += dst_pitch)
4e9e2555 Poul Sander 2025-10-05 10:15 2858
        {
4e9e2555 Poul Sander 2025-10-05 10:15 2859
            const ImU32* src_p = (const ImU32*)(void*)src_pixels;
4e9e2555 Poul Sander 2025-10-05 10:15 2860
            ImU8* dst_p = (ImU8*)dst_pixels;
4e9e2555 Poul Sander 2025-10-05 10:15 2861
            for (int nx = w; nx > 0; nx--)
4e9e2555 Poul Sander 2025-10-05 10:15 2862
                *dst_p++ = ((*src_p++) >> IM_COL32_A_SHIFT) & 0xFF;
4e9e2555 Poul Sander 2025-10-05 10:15 2863
        }
4e9e2555 Poul Sander 2025-10-05 10:15 2864
    }
4e9e2555 Poul Sander 2025-10-05 10:15 2865
    else
4e9e2555 Poul Sander 2025-10-05 10:15 2866
    {
4e9e2555 Poul Sander 2025-10-05 10:15 2867
        IM_ASSERT(0);
4e9e2555 Poul Sander 2025-10-05 10:15 2868
    }
1193b4be Poul Sander 2025-02-03 21:28 2869
}
1193b4be Poul Sander 2025-02-03 21:28 2870
4e9e2555 Poul Sander 2025-10-05 10:15 2871
// Source buffer may be written to (used for in-place mods).
4e9e2555 Poul Sander 2025-10-05 10:15 2872
// Post-process hooks may eventually be added here.
4e9e2555 Poul Sander 2025-10-05 10:15 2873
void ImFontAtlasTextureBlockPostProcess(ImFontAtlasPostProcessData* data)
1193b4be Poul Sander 2025-02-03 21:28 2874
{
4e9e2555 Poul Sander 2025-10-05 10:15 2875
    // Multiply operator (legacy)
4e9e2555 Poul Sander 2025-10-05 10:15 2876
    if (data->FontSrc->RasterizerMultiply != 1.0f)
4e9e2555 Poul Sander 2025-10-05 10:15 2877
        ImFontAtlasTextureBlockPostProcessMultiply(data, data->FontSrc->RasterizerMultiply);
4e9e2555 Poul Sander 2025-10-05 10:15 2878
}
1193b4be Poul Sander 2025-02-03 21:28 2879
4e9e2555 Poul Sander 2025-10-05 10:15 2880
void ImFontAtlasTextureBlockPostProcessMultiply(ImFontAtlasPostProcessData* data, float multiply_factor)
4e9e2555 Poul Sander 2025-10-05 10:15 2881
{
4e9e2555 Poul Sander 2025-10-05 10:15 2882
    unsigned char* pixels = (unsigned char*)data->Pixels;
4e9e2555 Poul Sander 2025-10-05 10:15 2883
    int pitch = data->Pitch;
4e9e2555 Poul Sander 2025-10-05 10:15 2884
    if (data->Format == ImTextureFormat_Alpha8)
4e9e2555 Poul Sander 2025-10-05 10:15 2885
    {
4e9e2555 Poul Sander 2025-10-05 10:15 2886
        for (int ny = data->Height; ny > 0; ny--, pixels += pitch)
4e9e2555 Poul Sander 2025-10-05 10:15 2887
        {
4e9e2555 Poul Sander 2025-10-05 10:15 2888
            ImU8* p = (ImU8*)pixels;
4e9e2555 Poul Sander 2025-10-05 10:15 2889
            for (int nx = data->Width; nx > 0; nx--, p++)
4e9e2555 Poul Sander 2025-10-05 10:15 2890
            {
4e9e2555 Poul Sander 2025-10-05 10:15 2891
                unsigned int v = ImMin((unsigned int)(*p * multiply_factor), (unsigned int)255);
4e9e2555 Poul Sander 2025-10-05 10:15 2892
                *p = (unsigned char)v;
4e9e2555 Poul Sander 2025-10-05 10:15 2893
            }
4e9e2555 Poul Sander 2025-10-05 10:15 2894
        }
4e9e2555 Poul Sander 2025-10-05 10:15 2895
    }
4e9e2555 Poul Sander 2025-10-05 10:15 2896
    else if (data->Format == ImTextureFormat_RGBA32) //-V547
4e9e2555 Poul Sander 2025-10-05 10:15 2897
    {
4e9e2555 Poul Sander 2025-10-05 10:15 2898
        for (int ny = data->Height; ny > 0; ny--, pixels += pitch)
4e9e2555 Poul Sander 2025-10-05 10:15 2899
        {
4e9e2555 Poul Sander 2025-10-05 10:15 2900
            ImU32* p = (ImU32*)(void*)pixels;
4e9e2555 Poul Sander 2025-10-05 10:15 2901
            for (int nx = data->Width; nx > 0; nx--, p++)
4e9e2555 Poul Sander 2025-10-05 10:15 2902
            {
4e9e2555 Poul Sander 2025-10-05 10:15 2903
                unsigned int a = ImMin((unsigned int)(((*p >> IM_COL32_A_SHIFT) & 0xFF) * multiply_factor), (unsigned int)255);
4e9e2555 Poul Sander 2025-10-05 10:15 2904
                *p = IM_COL32((*p >> IM_COL32_R_SHIFT) & 0xFF, (*p >> IM_COL32_G_SHIFT) & 0xFF, (*p >> IM_COL32_B_SHIFT) & 0xFF, a);
4e9e2555 Poul Sander 2025-10-05 10:15 2905
            }
4e9e2555 Poul Sander 2025-10-05 10:15 2906
        }
4e9e2555 Poul Sander 2025-10-05 10:15 2907
    }
4e9e2555 Poul Sander 2025-10-05 10:15 2908
    else
4e9e2555 Poul Sander 2025-10-05 10:15 2909
    {
4e9e2555 Poul Sander 2025-10-05 10:15 2910
        IM_ASSERT(0);
4e9e2555 Poul Sander 2025-10-05 10:15 2911
    }
1193b4be Poul Sander 2025-02-03 21:28 2912
}
1193b4be Poul Sander 2025-02-03 21:28 2913
4e9e2555 Poul Sander 2025-10-05 10:15 2914
// Fill with single color. We don't use this directly but it is convenient for anyone working on uploading custom rects.
4e9e2555 Poul Sander 2025-10-05 10:15 2915
void ImFontAtlasTextureBlockFill(ImTextureData* dst_tex, int dst_x, int dst_y, int w, int h, ImU32 col)
1193b4be Poul Sander 2025-02-03 21:28 2916
{
4e9e2555 Poul Sander 2025-10-05 10:15 2917
    if (dst_tex->Format == ImTextureFormat_Alpha8)
4e9e2555 Poul Sander 2025-10-05 10:15 2918
    {
4e9e2555 Poul Sander 2025-10-05 10:15 2919
        ImU8 col_a = (col >> IM_COL32_A_SHIFT) & 0xFF;
4e9e2555 Poul Sander 2025-10-05 10:15 2920
        for (int y = 0; y < h; y++)
4e9e2555 Poul Sander 2025-10-05 10:15 2921
            memset((ImU8*)dst_tex->GetPixelsAt(dst_x, dst_y + y), col_a, w);
4e9e2555 Poul Sander 2025-10-05 10:15 2922
    }
4e9e2555 Poul Sander 2025-10-05 10:15 2923
    else
1193b4be Poul Sander 2025-02-03 21:28 2924
    {
4e9e2555 Poul Sander 2025-10-05 10:15 2925
        for (int y = 0; y < h; y++)
1193b4be Poul Sander 2025-02-03 21:28 2926
        {
4e9e2555 Poul Sander 2025-10-05 10:15 2927
            ImU32* p = (ImU32*)(void*)dst_tex->GetPixelsAt(dst_x, dst_y + y);
4e9e2555 Poul Sander 2025-10-05 10:15 2928
            for (int x = w; x > 0; x--, p++)
4e9e2555 Poul Sander 2025-10-05 10:15 2929
                *p = col;
1193b4be Poul Sander 2025-02-03 21:28 2930
        }
1193b4be Poul Sander 2025-02-03 21:28 2931
    }
4e9e2555 Poul Sander 2025-10-05 10:15 2932
}
4e9e2555 Poul Sander 2025-10-05 10:15 2933
4e9e2555 Poul Sander 2025-10-05 10:15 2934
// Copy block from one texture to another
4e9e2555 Poul Sander 2025-10-05 10:15 2935
void ImFontAtlasTextureBlockCopy(ImTextureData* src_tex, int src_x, int src_y, ImTextureData* dst_tex, int dst_x, int dst_y, int w, int h)
4e9e2555 Poul Sander 2025-10-05 10:15 2936
{
4e9e2555 Poul Sander 2025-10-05 10:15 2937
    IM_ASSERT(src_tex->Pixels != NULL && dst_tex->Pixels != NULL);
4e9e2555 Poul Sander 2025-10-05 10:15 2938
    IM_ASSERT(src_tex->Format == dst_tex->Format);
4e9e2555 Poul Sander 2025-10-05 10:15 2939
    IM_ASSERT(src_x >= 0 && src_x + w <= src_tex->Width);
4e9e2555 Poul Sander 2025-10-05 10:15 2940
    IM_ASSERT(src_y >= 0 && src_y + h <= src_tex->Height);
4e9e2555 Poul Sander 2025-10-05 10:15 2941
    IM_ASSERT(dst_x >= 0 && dst_x + w <= dst_tex->Width);
4e9e2555 Poul Sander 2025-10-05 10:15 2942
    IM_ASSERT(dst_y >= 0 && dst_y + h <= dst_tex->Height);
4e9e2555 Poul Sander 2025-10-05 10:15 2943
    for (int y = 0; y < h; y++)
4e9e2555 Poul Sander 2025-10-05 10:15 2944
        memcpy(dst_tex->GetPixelsAt(dst_x, dst_y + y), src_tex->GetPixelsAt(src_x, src_y + y), w * dst_tex->BytesPerPixel);
4e9e2555 Poul Sander 2025-10-05 10:15 2945
}
4e9e2555 Poul Sander 2025-10-05 10:15 2946
4e9e2555 Poul Sander 2025-10-05 10:15 2947
// Queue texture block update for renderer backend
4e9e2555 Poul Sander 2025-10-05 10:15 2948
void ImFontAtlasTextureBlockQueueUpload(ImFontAtlas* atlas, ImTextureData* tex, int x, int y, int w, int h)
4e9e2555 Poul Sander 2025-10-05 10:15 2949
{
4e9e2555 Poul Sander 2025-10-05 10:15 2950
    IM_ASSERT(tex->Status != ImTextureStatus_WantDestroy && tex->Status != ImTextureStatus_Destroyed);
4e9e2555 Poul Sander 2025-10-05 10:15 2951
    IM_ASSERT(x >= 0 && x <= 0xFFFF && y >= 0 && y <= 0xFFFF && w >= 0 && x + w <= 0x10000 && h >= 0 && y + h <= 0x10000);
4e9e2555 Poul Sander 2025-10-05 10:15 2952
    IM_UNUSED(atlas);
4e9e2555 Poul Sander 2025-10-05 10:15 2953
4e9e2555 Poul Sander 2025-10-05 10:15 2954
    ImTextureRect req = { (unsigned short)x, (unsigned short)y, (unsigned short)w, (unsigned short)h };
4e9e2555 Poul Sander 2025-10-05 10:15 2955
    int new_x1 = ImMax(tex->UpdateRect.w == 0 ? 0 : tex->UpdateRect.x + tex->UpdateRect.w, req.x + req.w);
4e9e2555 Poul Sander 2025-10-05 10:15 2956
    int new_y1 = ImMax(tex->UpdateRect.h == 0 ? 0 : tex->UpdateRect.y + tex->UpdateRect.h, req.y + req.h);
4e9e2555 Poul Sander 2025-10-05 10:15 2957
    tex->UpdateRect.x = ImMin(tex->UpdateRect.x, req.x);
4e9e2555 Poul Sander 2025-10-05 10:15 2958
    tex->UpdateRect.y = ImMin(tex->UpdateRect.y, req.y);
4e9e2555 Poul Sander 2025-10-05 10:15 2959
    tex->UpdateRect.w = (unsigned short)(new_x1 - tex->UpdateRect.x);
4e9e2555 Poul Sander 2025-10-05 10:15 2960
    tex->UpdateRect.h = (unsigned short)(new_y1 - tex->UpdateRect.y);
4e9e2555 Poul Sander 2025-10-05 10:15 2961
    tex->UsedRect.x = ImMin(tex->UsedRect.x, req.x);
4e9e2555 Poul Sander 2025-10-05 10:15 2962
    tex->UsedRect.y = ImMin(tex->UsedRect.y, req.y);
4e9e2555 Poul Sander 2025-10-05 10:15 2963
    tex->UsedRect.w = (unsigned short)(ImMax(tex->UsedRect.x + tex->UsedRect.w, req.x + req.w) - tex->UsedRect.x);
4e9e2555 Poul Sander 2025-10-05 10:15 2964
    tex->UsedRect.h = (unsigned short)(ImMax(tex->UsedRect.y + tex->UsedRect.h, req.y + req.h) - tex->UsedRect.y);
4e9e2555 Poul Sander 2025-10-05 10:15 2965
    atlas->TexIsBuilt = false;
4e9e2555 Poul Sander 2025-10-05 10:15 2966
4e9e2555 Poul Sander 2025-10-05 10:15 2967
    // No need to queue if status is == ImTextureStatus_WantCreate
4e9e2555 Poul Sander 2025-10-05 10:15 2968
    if (tex->Status == ImTextureStatus_OK || tex->Status == ImTextureStatus_WantUpdates)
4e9e2555 Poul Sander 2025-10-05 10:15 2969
    {
4e9e2555 Poul Sander 2025-10-05 10:15 2970
        tex->Status = ImTextureStatus_WantUpdates;
4e9e2555 Poul Sander 2025-10-05 10:15 2971
        tex->Updates.push_back(req);
4e9e2555 Poul Sander 2025-10-05 10:15 2972
    }
4e9e2555 Poul Sander 2025-10-05 10:15 2973
}
4e9e2555 Poul Sander 2025-10-05 10:15 2974
4e9e2555 Poul Sander 2025-10-05 10:15 2975
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
4e9e2555 Poul Sander 2025-10-05 10:15 2976
static void GetTexDataAsFormat(ImFontAtlas* atlas, ImTextureFormat format, unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel)
4e9e2555 Poul Sander 2025-10-05 10:15 2977
{
4e9e2555 Poul Sander 2025-10-05 10:15 2978
    ImTextureData* tex = atlas->TexData;
4e9e2555 Poul Sander 2025-10-05 10:15 2979
    if (!atlas->TexIsBuilt || tex == NULL || tex->Pixels == NULL || atlas->TexDesiredFormat != format)
4e9e2555 Poul Sander 2025-10-05 10:15 2980
    {
4e9e2555 Poul Sander 2025-10-05 10:15 2981
        atlas->TexDesiredFormat = format;
4e9e2555 Poul Sander 2025-10-05 10:15 2982
        atlas->Build();
4e9e2555 Poul Sander 2025-10-05 10:15 2983
        tex = atlas->TexData;
4e9e2555 Poul Sander 2025-10-05 10:15 2984
    }
4e9e2555 Poul Sander 2025-10-05 10:15 2985
    if (out_pixels) { *out_pixels = (unsigned char*)tex->Pixels; };
4e9e2555 Poul Sander 2025-10-05 10:15 2986
    if (out_width) { *out_width = tex->Width; };
4e9e2555 Poul Sander 2025-10-05 10:15 2987
    if (out_height) { *out_height = tex->Height; };
4e9e2555 Poul Sander 2025-10-05 10:15 2988
    if (out_bytes_per_pixel) { *out_bytes_per_pixel = tex->BytesPerPixel; }
4e9e2555 Poul Sander 2025-10-05 10:15 2989
}
4e9e2555 Poul Sander 2025-10-05 10:15 2990
4e9e2555 Poul Sander 2025-10-05 10:15 2991
void ImFontAtlas::GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel)
4e9e2555 Poul Sander 2025-10-05 10:15 2992
{
4e9e2555 Poul Sander 2025-10-05 10:15 2993
    GetTexDataAsFormat(this, ImTextureFormat_Alpha8, out_pixels, out_width, out_height, out_bytes_per_pixel);
4e9e2555 Poul Sander 2025-10-05 10:15 2994
}
1193b4be Poul Sander 2025-02-03 21:28 2995
4e9e2555 Poul Sander 2025-10-05 10:15 2996
void ImFontAtlas::GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel)
4e9e2555 Poul Sander 2025-10-05 10:15 2997
{
4e9e2555 Poul Sander 2025-10-05 10:15 2998
    GetTexDataAsFormat(this, ImTextureFormat_RGBA32, out_pixels, out_width, out_height, out_bytes_per_pixel);
4e9e2555 Poul Sander 2025-10-05 10:15 2999
}
4e9e2555 Poul Sander 2025-10-05 10:15 3000
4e9e2555 Poul Sander 2025-10-05 10:15 3001
bool ImFontAtlas::Build()
4e9e2555 Poul Sander 2025-10-05 10:15 3002
{
4e9e2555 Poul Sander 2025-10-05 10:15 3003
    ImFontAtlasBuildMain(this);
4e9e2555 Poul Sander 2025-10-05 10:15 3004
    return true;
1193b4be Poul Sander 2025-02-03 21:28 3005
}
4e9e2555 Poul Sander 2025-10-05 10:15 3006
#endif // #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
1193b4be Poul Sander 2025-02-03 21:28 3007
4e9e2555 Poul Sander 2025-10-05 10:15 3008
ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg_in)
1193b4be Poul Sander 2025-02-03 21:28 3009
{
4e9e2555 Poul Sander 2025-10-05 10:15 3010
    // Sanity Checks
4e9e2555 Poul Sander 2025-10-05 10:15 3011
    IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!");
4e9e2555 Poul Sander 2025-10-05 10:15 3012
    IM_ASSERT((font_cfg_in->FontData != NULL && font_cfg_in->FontDataSize > 0) || (font_cfg_in->FontLoader != NULL));
4e9e2555 Poul Sander 2025-10-05 10:15 3013
    //IM_ASSERT(font_cfg_in->SizePixels > 0.0f && "Is ImFontConfig struct correctly initialized?");
4e9e2555 Poul Sander 2025-10-05 10:15 3014
    IM_ASSERT(font_cfg_in->RasterizerDensity > 0.0f && "Is ImFontConfig struct correctly initialized?");
4e9e2555 Poul Sander 2025-10-05 10:15 3015
    if (font_cfg_in->GlyphOffset.x != 0.0f || font_cfg_in->GlyphOffset.y != 0.0f || font_cfg_in->GlyphMinAdvanceX != 0.0f || font_cfg_in->GlyphMaxAdvanceX != FLT_MAX)
4e9e2555 Poul Sander 2025-10-05 10:15 3016
        IM_ASSERT(font_cfg_in->SizePixels != 0.0f && "Specifying glyph offset/advances requires a reference size to base it on.");
4e9e2555 Poul Sander 2025-10-05 10:15 3017
4e9e2555 Poul Sander 2025-10-05 10:15 3018
    // Lazily create builder on the first call to AddFont
4e9e2555 Poul Sander 2025-10-05 10:15 3019
    if (Builder == NULL)
4e9e2555 Poul Sander 2025-10-05 10:15 3020
        ImFontAtlasBuildInit(this);
1193b4be Poul Sander 2025-02-03 21:28 3021
1193b4be Poul Sander 2025-02-03 21:28 3022
    // Create new font
4e9e2555 Poul Sander 2025-10-05 10:15 3023
    ImFont* font;
4e9e2555 Poul Sander 2025-10-05 10:15 3024
    if (!font_cfg_in->MergeMode)
4e9e2555 Poul Sander 2025-10-05 10:15 3025
    {
4e9e2555 Poul Sander 2025-10-05 10:15 3026
        font = IM_NEW(ImFont)();
4e9e2555 Poul Sander 2025-10-05 10:15 3027
        font->FontId = FontNextUniqueID++;
4e9e2555 Poul Sander 2025-10-05 10:15 3028
        font->Flags = font_cfg_in->Flags;
4e9e2555 Poul Sander 2025-10-05 10:15 3029
        font->LegacySize = font_cfg_in->SizePixels;
4e9e2555 Poul Sander 2025-10-05 10:15 3030
        font->CurrentRasterizerDensity = font_cfg_in->RasterizerDensity;
4e9e2555 Poul Sander 2025-10-05 10:15 3031
        Fonts.push_back(font);
4e9e2555 Poul Sander 2025-10-05 10:15 3032
    }
1193b4be Poul Sander 2025-02-03 21:28 3033
    else
4e9e2555 Poul Sander 2025-10-05 10:15 3034
    {
1193b4be Poul Sander 2025-02-03 21:28 3035
        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.
4e9e2555 Poul Sander 2025-10-05 10:15 3036
        font = font_cfg_in->DstFont ? font_cfg_in->DstFont : Fonts.back();
4e9e2555 Poul Sander 2025-10-05 10:15 3037
    }
1193b4be Poul Sander 2025-02-03 21:28 3038
4e9e2555 Poul Sander 2025-10-05 10:15 3039
    // Add to list
4e9e2555 Poul Sander 2025-10-05 10:15 3040
    Sources.push_back(*font_cfg_in);
4e9e2555 Poul Sander 2025-10-05 10:15 3041
    ImFontConfig* font_cfg = &Sources.back();
4e9e2555 Poul Sander 2025-10-05 10:15 3042
    if (font_cfg->DstFont == NULL)
4e9e2555 Poul Sander 2025-10-05 10:15 3043
        font_cfg->DstFont = font;
4e9e2555 Poul Sander 2025-10-05 10:15 3044
    font->Sources.push_back(font_cfg);
4e9e2555 Poul Sander 2025-10-05 10:15 3045
    ImFontAtlasBuildUpdatePointers(this); // Pointers to Sources are otherwise dangling after we called Sources.push_back().
4e9e2555 Poul Sander 2025-10-05 10:15 3046
4e9e2555 Poul Sander 2025-10-05 10:15 3047
    if (font_cfg->FontDataOwnedByAtlas == false)
1193b4be Poul Sander 2025-02-03 21:28 3048
    {
4e9e2555 Poul Sander 2025-10-05 10:15 3049
        font_cfg->FontDataOwnedByAtlas = true;
4e9e2555 Poul Sander 2025-10-05 10:15 3050
        font_cfg->FontData = ImMemdup(font_cfg->FontData, (size_t)font_cfg->FontDataSize);
1193b4be Poul Sander 2025-02-03 21:28 3051
    }
1193b4be Poul Sander 2025-02-03 21:28 3052
4e9e2555 Poul Sander 2025-10-05 10:15 3053
    // Sanity check
4e9e2555 Poul Sander 2025-10-05 10:15 3054
    // We don't round cfg.SizePixels yet as relative size of merged fonts are used afterwards.
4e9e2555 Poul Sander 2025-10-05 10:15 3055
    if (font_cfg->GlyphExcludeRanges != NULL)
4e9e2555 Poul Sander 2025-10-05 10:15 3056
    {
4e9e2555 Poul Sander 2025-10-05 10:15 3057
        int size = 0;
4e9e2555 Poul Sander 2025-10-05 10:15 3058
        for (const ImWchar* p = font_cfg->GlyphExcludeRanges; p[0] != 0; p++, size++) {}
4e9e2555 Poul Sander 2025-10-05 10:15 3059
        IM_ASSERT((size & 1) == 0 && "GlyphExcludeRanges[] size must be multiple of two!");
4e9e2555 Poul Sander 2025-10-05 10:15 3060
        IM_ASSERT((size <= 64) && "GlyphExcludeRanges[] size must be small!");
4e9e2555 Poul Sander 2025-10-05 10:15 3061
        font_cfg->GlyphExcludeRanges = (ImWchar*)ImMemdup(font_cfg->GlyphExcludeRanges, sizeof(font_cfg->GlyphExcludeRanges[0]) * (size + 1));
4e9e2555 Poul Sander 2025-10-05 10:15 3062
    }
4e9e2555 Poul Sander 2025-10-05 10:15 3063
    if (font_cfg->FontLoader != NULL)
4e9e2555 Poul Sander 2025-10-05 10:15 3064
    {
4e9e2555 Poul Sander 2025-10-05 10:15 3065
        IM_ASSERT(font_cfg->FontLoader->FontBakedLoadGlyph != NULL);
4e9e2555 Poul Sander 2025-10-05 10:15 3066
        IM_ASSERT(font_cfg->FontLoader->LoaderInit == NULL && font_cfg->FontLoader->LoaderShutdown == NULL); // FIXME-NEWATLAS: Unsupported yet.
4e9e2555 Poul Sander 2025-10-05 10:15 3067
    }
4e9e2555 Poul Sander 2025-10-05 10:15 3068
    IM_ASSERT(font_cfg->FontLoaderData == NULL);
1193b4be Poul Sander 2025-02-03 21:28 3069
4e9e2555 Poul Sander 2025-10-05 10:15 3070
    if (!ImFontAtlasFontSourceInit(this, font_cfg))
4e9e2555 Poul Sander 2025-10-05 10:15 3071
    {
4e9e2555 Poul Sander 2025-10-05 10:15 3072
        // Rollback (this is a fragile/rarely exercised code-path. TestSuite's "misc_atlas_add_invalid_font" aim to test this)
4e9e2555 Poul Sander 2025-10-05 10:15 3073
        ImFontAtlasFontDestroySourceData(this, font_cfg);
4e9e2555 Poul Sander 2025-10-05 10:15 3074
        Sources.pop_back();
4e9e2555 Poul Sander 2025-10-05 10:15 3075
        font->Sources.pop_back();
4e9e2555 Poul Sander 2025-10-05 10:15 3076
        if (!font_cfg->MergeMode)
4e9e2555 Poul Sander 2025-10-05 10:15 3077
        {
4e9e2555 Poul Sander 2025-10-05 10:15 3078
            IM_DELETE(font);
4e9e2555 Poul Sander 2025-10-05 10:15 3079
            Fonts.pop_back();
4e9e2555 Poul Sander 2025-10-05 10:15 3080
        }
4e9e2555 Poul Sander 2025-10-05 10:15 3081
        return NULL;
4e9e2555 Poul Sander 2025-10-05 10:15 3082
    }
4e9e2555 Poul Sander 2025-10-05 10:15 3083
    ImFontAtlasFontSourceAddToFont(this, font, font_cfg);
1193b4be Poul Sander 2025-02-03 21:28 3084
4e9e2555 Poul Sander 2025-10-05 10:15 3085
    return font;
1193b4be Poul Sander 2025-02-03 21:28 3086
}
1193b4be Poul Sander 2025-02-03 21:28 3087
1193b4be Poul Sander 2025-02-03 21:28 3088
// 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 3089
static unsigned int stb_decompress_length(const unsigned char* input);
1193b4be Poul Sander 2025-02-03 21:28 3090
static unsigned int stb_decompress(unsigned char* output, const unsigned char* input, unsigned int length);
1193b4be Poul Sander 2025-02-03 21:28 3091
static unsigned int Decode85Byte(char c)                                    { return c >= '\\' ? c-36 : c-35; }
1193b4be Poul Sander 2025-02-03 21:28 3092
static void         Decode85(const unsigned char* src, unsigned char* dst)
1193b4be Poul Sander 2025-02-03 21:28 3093
{
1193b4be Poul Sander 2025-02-03 21:28 3094
    while (*src)
1193b4be Poul Sander 2025-02-03 21:28 3095
    {
1193b4be Poul Sander 2025-02-03 21:28 3096
        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 3097
        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 3098
        src += 5;
1193b4be Poul Sander 2025-02-03 21:28 3099
        dst += 4;
1193b4be Poul Sander 2025-02-03 21:28 3100
    }
1193b4be Poul Sander 2025-02-03 21:28 3101
}
4e9e2555 Poul Sander 2025-10-05 10:15 3102
#ifndef IMGUI_DISABLE_DEFAULT_FONT
4e9e2555 Poul Sander 2025-10-05 10:15 3103
static const char* GetDefaultCompressedFontDataTTF(int* out_size);
4e9e2555 Poul Sander 2025-10-05 10:15 3104
#endif
1193b4be Poul Sander 2025-02-03 21:28 3105
1193b4be Poul Sander 2025-02-03 21:28 3106
// Load embedded ProggyClean.ttf at size 13, disable oversampling
4e9e2555 Poul Sander 2025-10-05 10:15 3107
// If you want a similar font which may be better scaled, consider using ProggyVector from the same author!
1193b4be Poul Sander 2025-02-03 21:28 3108
ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template)
1193b4be Poul Sander 2025-02-03 21:28 3109
{
4e9e2555 Poul Sander 2025-10-05 10:15 3110
#ifndef IMGUI_DISABLE_DEFAULT_FONT
1193b4be Poul Sander 2025-02-03 21:28 3111
    ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
1193b4be Poul Sander 2025-02-03 21:28 3112
    if (!font_cfg_template)
1193b4be Poul Sander 2025-02-03 21:28 3113
    {
1193b4be Poul Sander 2025-02-03 21:28 3114
        font_cfg.OversampleH = font_cfg.OversampleV = 1;
1193b4be Poul Sander 2025-02-03 21:28 3115
        font_cfg.PixelSnapH = true;
1193b4be Poul Sander 2025-02-03 21:28 3116
    }
1193b4be Poul Sander 2025-02-03 21:28 3117
    if (font_cfg.SizePixels <= 0.0f)
1193b4be Poul Sander 2025-02-03 21:28 3118
        font_cfg.SizePixels = 13.0f * 1.0f;
1193b4be Poul Sander 2025-02-03 21:28 3119
    if (font_cfg.Name[0] == '\0')
4e9e2555 Poul Sander 2025-10-05 10:15 3120
        ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "ProggyClean.ttf");
1193b4be Poul Sander 2025-02-03 21:28 3121
    font_cfg.EllipsisChar = (ImWchar)0x0085;
4e9e2555 Poul Sander 2025-10-05 10:15 3122
    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 3123
4e9e2555 Poul Sander 2025-10-05 10:15 3124
    int ttf_compressed_size = 0;
4e9e2555 Poul Sander 2025-10-05 10:15 3125
    const char* ttf_compressed = GetDefaultCompressedFontDataTTF(&ttf_compressed_size);
4e9e2555 Poul Sander 2025-10-05 10:15 3126
    return AddFontFromMemoryCompressedTTF(ttf_compressed, ttf_compressed_size, font_cfg.SizePixels, &font_cfg);
4e9e2555 Poul Sander 2025-10-05 10:15 3127
#else
4e9e2555 Poul Sander 2025-10-05 10:15 3128
    IM_ASSERT(0 && "AddFontDefault() disabled in this build.");
4e9e2555 Poul Sander 2025-10-05 10:15 3129
    IM_UNUSED(font_cfg_template);
4e9e2555 Poul Sander 2025-10-05 10:15 3130
    return NULL;
4e9e2555 Poul Sander 2025-10-05 10:15 3131
#endif // #ifndef IMGUI_DISABLE_DEFAULT_FONT
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
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 3135
{
4e9e2555 Poul Sander 2025-10-05 10:15 3136
    IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!");
1193b4be Poul Sander 2025-02-03 21:28 3137
    size_t data_size = 0;
1193b4be Poul Sander 2025-02-03 21:28 3138
    void* data = ImFileLoadToMemory(filename, "rb", &data_size, 0);
1193b4be Poul Sander 2025-02-03 21:28 3139
    if (!data)
1193b4be Poul Sander 2025-02-03 21:28 3140
    {
4e9e2555 Poul Sander 2025-10-05 10:15 3141
        if (font_cfg_template == NULL || (font_cfg_template->Flags & ImFontFlags_NoLoadError) == 0)
4e9e2555 Poul Sander 2025-10-05 10:15 3142
        {
4e9e2555 Poul Sander 2025-10-05 10:15 3143
            IMGUI_DEBUG_LOG("While loading '%s'\n", filename);
4e9e2555 Poul Sander 2025-10-05 10:15 3144
            IM_ASSERT_USER_ERROR(0, "Could not load font file!");
4e9e2555 Poul Sander 2025-10-05 10:15 3145
        }
1193b4be Poul Sander 2025-02-03 21:28 3146
        return NULL;
1193b4be Poul Sander 2025-02-03 21:28 3147
    }
1193b4be Poul Sander 2025-02-03 21:28 3148
    ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
1193b4be Poul Sander 2025-02-03 21:28 3149
    if (font_cfg.Name[0] == '\0')
1193b4be Poul Sander 2025-02-03 21:28 3150
    {
1193b4be Poul Sander 2025-02-03 21:28 3151
        // Store a short copy of filename into into the font name for convenience
1193b4be Poul Sander 2025-02-03 21:28 3152
        const char* p;
4e9e2555 Poul Sander 2025-10-05 10:15 3153
        for (p = filename + ImStrlen(filename); p > filename && p[-1] != '/' && p[-1] != '\\'; p--) {}
4e9e2555 Poul Sander 2025-10-05 10:15 3154
        ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "%s", p);
1193b4be Poul Sander 2025-02-03 21:28 3155
    }
1193b4be Poul Sander 2025-02-03 21:28 3156
    return AddFontFromMemoryTTF(data, (int)data_size, size_pixels, &font_cfg, glyph_ranges);
1193b4be Poul Sander 2025-02-03 21:28 3157
}
1193b4be Poul Sander 2025-02-03 21:28 3158
1193b4be Poul Sander 2025-02-03 21:28 3159
// 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 3160
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 3161
{
4e9e2555 Poul Sander 2025-10-05 10:15 3162
    IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!");
1193b4be Poul Sander 2025-02-03 21:28 3163
    ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
1193b4be Poul Sander 2025-02-03 21:28 3164
    IM_ASSERT(font_cfg.FontData == NULL);
1193b4be Poul Sander 2025-02-03 21:28 3165
    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 3166
    font_cfg.FontData = font_data;
1193b4be Poul Sander 2025-02-03 21:28 3167
    font_cfg.FontDataSize = font_data_size;
1193b4be Poul Sander 2025-02-03 21:28 3168
    font_cfg.SizePixels = size_pixels > 0.0f ? size_pixels : font_cfg.SizePixels;
1193b4be Poul Sander 2025-02-03 21:28 3169
    if (glyph_ranges)
1193b4be Poul Sander 2025-02-03 21:28 3170
        font_cfg.GlyphRanges = glyph_ranges;
1193b4be Poul Sander 2025-02-03 21:28 3171
    return AddFont(&font_cfg);
1193b4be Poul Sander 2025-02-03 21:28 3172
}
1193b4be Poul Sander 2025-02-03 21:28 3173
1193b4be Poul Sander 2025-02-03 21:28 3174
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 3175
{
1193b4be Poul Sander 2025-02-03 21:28 3176
    const unsigned int buf_decompressed_size = stb_decompress_length((const unsigned char*)compressed_ttf_data);
1193b4be Poul Sander 2025-02-03 21:28 3177
    unsigned char* buf_decompressed_data = (unsigned char*)IM_ALLOC(buf_decompressed_size);
1193b4be Poul Sander 2025-02-03 21:28 3178
    stb_decompress(buf_decompressed_data, (const unsigned char*)compressed_ttf_data, (unsigned int)compressed_ttf_size);
1193b4be Poul Sander 2025-02-03 21:28 3179
1193b4be Poul Sander 2025-02-03 21:28 3180
    ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
1193b4be Poul Sander 2025-02-03 21:28 3181
    IM_ASSERT(font_cfg.FontData == NULL);
1193b4be Poul Sander 2025-02-03 21:28 3182
    font_cfg.FontDataOwnedByAtlas = true;
1193b4be Poul Sander 2025-02-03 21:28 3183
    return AddFontFromMemoryTTF(buf_decompressed_data, (int)buf_decompressed_size, size_pixels, &font_cfg, glyph_ranges);
1193b4be Poul Sander 2025-02-03 21:28 3184
}
1193b4be Poul Sander 2025-02-03 21:28 3185
1193b4be Poul Sander 2025-02-03 21:28 3186
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 3187
{
4e9e2555 Poul Sander 2025-10-05 10:15 3188
    int compressed_ttf_size = (((int)ImStrlen(compressed_ttf_data_base85) + 4) / 5) * 4;
1193b4be Poul Sander 2025-02-03 21:28 3189
    void* compressed_ttf = IM_ALLOC((size_t)compressed_ttf_size);
1193b4be Poul Sander 2025-02-03 21:28 3190
    Decode85((const unsigned char*)compressed_ttf_data_base85, (unsigned char*)compressed_ttf);
1193b4be Poul Sander 2025-02-03 21:28 3191
    ImFont* font = AddFontFromMemoryCompressedTTF(compressed_ttf, compressed_ttf_size, size_pixels, font_cfg, glyph_ranges);
1193b4be Poul Sander 2025-02-03 21:28 3192
    IM_FREE(compressed_ttf);
1193b4be Poul Sander 2025-02-03 21:28 3193
    return font;
1193b4be Poul Sander 2025-02-03 21:28 3194
}
1193b4be Poul Sander 2025-02-03 21:28 3195
4e9e2555 Poul Sander 2025-10-05 10:15 3196
// On font removal we need to remove references (otherwise we could queue removal?)
4e9e2555 Poul Sander 2025-10-05 10:15 3197
// We allow old_font == new_font which forces updating all values (e.g. sizes)
4e9e2555 Poul Sander 2025-10-05 10:15 3198
static void ImFontAtlasBuildNotifySetFont(ImFontAtlas* atlas, ImFont* old_font, ImFont* new_font)
4e9e2555 Poul Sander 2025-10-05 10:15 3199
{
4e9e2555 Poul Sander 2025-10-05 10:15 3200
    for (ImDrawListSharedData* shared_data : atlas->DrawListSharedDatas)
4e9e2555 Poul Sander 2025-10-05 10:15 3201
    {
4e9e2555 Poul Sander 2025-10-05 10:15 3202
        if (shared_data->Font == old_font)
4e9e2555 Poul Sander 2025-10-05 10:15 3203
            shared_data->Font = new_font;
4e9e2555 Poul Sander 2025-10-05 10:15 3204
        if (ImGuiContext* ctx = shared_data->Context)
4e9e2555 Poul Sander 2025-10-05 10:15 3205
        {
4e9e2555 Poul Sander 2025-10-05 10:15 3206
            if (ctx->IO.FontDefault == old_font)
4e9e2555 Poul Sander 2025-10-05 10:15 3207
                ctx->IO.FontDefault = new_font;
4e9e2555 Poul Sander 2025-10-05 10:15 3208
            if (ctx->Font == old_font)
4e9e2555 Poul Sander 2025-10-05 10:15 3209
            {
4e9e2555 Poul Sander 2025-10-05 10:15 3210
                ImGuiContext* curr_ctx = ImGui::GetCurrentContext();
4e9e2555 Poul Sander 2025-10-05 10:15 3211
                bool need_bind_ctx = ctx != curr_ctx;
4e9e2555 Poul Sander 2025-10-05 10:15 3212
                if (need_bind_ctx)
4e9e2555 Poul Sander 2025-10-05 10:15 3213
                    ImGui::SetCurrentContext(ctx);
4e9e2555 Poul Sander 2025-10-05 10:15 3214
                ImGui::SetCurrentFont(new_font, ctx->FontSizeBase, ctx->FontSize);
4e9e2555 Poul Sander 2025-10-05 10:15 3215
                if (need_bind_ctx)
4e9e2555 Poul Sander 2025-10-05 10:15 3216
                    ImGui::SetCurrentContext(curr_ctx);
4e9e2555 Poul Sander 2025-10-05 10:15 3217
            }
4e9e2555 Poul Sander 2025-10-05 10:15 3218
            for (ImFontStackData& font_stack_data : ctx->FontStack)
4e9e2555 Poul Sander 2025-10-05 10:15 3219
                if (font_stack_data.Font == old_font)
4e9e2555 Poul Sander 2025-10-05 10:15 3220
                    font_stack_data.Font = new_font;
4e9e2555 Poul Sander 2025-10-05 10:15 3221
        }
4e9e2555 Poul Sander 2025-10-05 10:15 3222
    }
4e9e2555 Poul Sander 2025-10-05 10:15 3223
}
4e9e2555 Poul Sander 2025-10-05 10:15 3224
4e9e2555 Poul Sander 2025-10-05 10:15 3225
void ImFontAtlas::RemoveFont(ImFont* font)
4e9e2555 Poul Sander 2025-10-05 10:15 3226
{
4e9e2555 Poul Sander 2025-10-05 10:15 3227
    IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!");
4e9e2555 Poul Sander 2025-10-05 10:15 3228
    font->ClearOutputData();
4e9e2555 Poul Sander 2025-10-05 10:15 3229
4e9e2555 Poul Sander 2025-10-05 10:15 3230
    ImFontAtlasFontDestroyOutput(this, font);
4e9e2555 Poul Sander 2025-10-05 10:15 3231
    for (ImFontConfig* src : font->Sources)
4e9e2555 Poul Sander 2025-10-05 10:15 3232
        ImFontAtlasFontDestroySourceData(this, src);
4e9e2555 Poul Sander 2025-10-05 10:15 3233
    for (int src_n = 0; src_n < Sources.Size; src_n++)
4e9e2555 Poul Sander 2025-10-05 10:15 3234
        if (Sources[src_n].DstFont == font)
4e9e2555 Poul Sander 2025-10-05 10:15 3235
            Sources.erase(&Sources[src_n--]);
4e9e2555 Poul Sander 2025-10-05 10:15 3236
4e9e2555 Poul Sander 2025-10-05 10:15 3237
    bool removed = Fonts.find_erase(font);
4e9e2555 Poul Sander 2025-10-05 10:15 3238
    IM_ASSERT(removed);
4e9e2555 Poul Sander 2025-10-05 10:15 3239
    IM_UNUSED(removed);
4e9e2555 Poul Sander 2025-10-05 10:15 3240
4e9e2555 Poul Sander 2025-10-05 10:15 3241
    ImFontAtlasBuildUpdatePointers(this);
4e9e2555 Poul Sander 2025-10-05 10:15 3242
4e9e2555 Poul Sander 2025-10-05 10:15 3243
    font->ContainerAtlas = NULL;
4e9e2555 Poul Sander 2025-10-05 10:15 3244
    IM_DELETE(font);
4e9e2555 Poul Sander 2025-10-05 10:15 3245
4e9e2555 Poul Sander 2025-10-05 10:15 3246
    // Notify external systems
4e9e2555 Poul Sander 2025-10-05 10:15 3247
    ImFont* new_current_font = Fonts.empty() ? NULL : Fonts[0];
4e9e2555 Poul Sander 2025-10-05 10:15 3248
    ImFontAtlasBuildNotifySetFont(this, font, new_current_font);
4e9e2555 Poul Sander 2025-10-05 10:15 3249
}
4e9e2555 Poul Sander 2025-10-05 10:15 3250
4e9e2555 Poul Sander 2025-10-05 10:15 3251
// At it is common to do an AddCustomRect() followed by a GetCustomRect(), we provide an optional 'ImFontAtlasRect* out_r = NULL' argument to retrieve the info straight away.
4e9e2555 Poul Sander 2025-10-05 10:15 3252
ImFontAtlasRectId ImFontAtlas::AddCustomRect(int width, int height, ImFontAtlasRect* out_r)
1193b4be Poul Sander 2025-02-03 21:28 3253
{
1193b4be Poul Sander 2025-02-03 21:28 3254
    IM_ASSERT(width > 0 && width <= 0xFFFF);
1193b4be Poul Sander 2025-02-03 21:28 3255
    IM_ASSERT(height > 0 && height <= 0xFFFF);
4e9e2555 Poul Sander 2025-10-05 10:15 3256
4e9e2555 Poul Sander 2025-10-05 10:15 3257
    if (Builder == NULL)
4e9e2555 Poul Sander 2025-10-05 10:15 3258
        ImFontAtlasBuildInit(this);
4e9e2555 Poul Sander 2025-10-05 10:15 3259
4e9e2555 Poul Sander 2025-10-05 10:15 3260
    ImFontAtlasRectId r_id = ImFontAtlasPackAddRect(this, width, height);
4e9e2555 Poul Sander 2025-10-05 10:15 3261
    if (r_id == ImFontAtlasRectId_Invalid)
4e9e2555 Poul Sander 2025-10-05 10:15 3262
        return ImFontAtlasRectId_Invalid;
4e9e2555 Poul Sander 2025-10-05 10:15 3263
    if (out_r != NULL)
4e9e2555 Poul Sander 2025-10-05 10:15 3264
        GetCustomRect(r_id, out_r);
4e9e2555 Poul Sander 2025-10-05 10:15 3265
4e9e2555 Poul Sander 2025-10-05 10:15 3266
    if (RendererHasTextures)
4e9e2555 Poul Sander 2025-10-05 10:15 3267
    {
4e9e2555 Poul Sander 2025-10-05 10:15 3268
        ImTextureRect* r = ImFontAtlasPackGetRect(this, r_id);
4e9e2555 Poul Sander 2025-10-05 10:15 3269
        ImFontAtlasTextureBlockQueueUpload(this, TexData, r->x, r->y, r->w, r->h);
4e9e2555 Poul Sander 2025-10-05 10:15 3270
    }
4e9e2555 Poul Sander 2025-10-05 10:15 3271
    return r_id;
4e9e2555 Poul Sander 2025-10-05 10:15 3272
}
4e9e2555 Poul Sander 2025-10-05 10:15 3273
4e9e2555 Poul Sander 2025-10-05 10:15 3274
void ImFontAtlas::RemoveCustomRect(ImFontAtlasRectId id)
4e9e2555 Poul Sander 2025-10-05 10:15 3275
{
4e9e2555 Poul Sander 2025-10-05 10:15 3276
    if (ImFontAtlasPackGetRectSafe(this, id) == NULL)
4e9e2555 Poul Sander 2025-10-05 10:15 3277
        return;
4e9e2555 Poul Sander 2025-10-05 10:15 3278
    ImFontAtlasPackDiscardRect(this, id);
1193b4be Poul Sander 2025-02-03 21:28 3279
}
1193b4be Poul Sander 2025-02-03 21:28 3280
4e9e2555 Poul Sander 2025-10-05 10:15 3281
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
4e9e2555 Poul Sander 2025-10-05 10:15 3282
// This API does not make sense anymore with scalable fonts.
4e9e2555 Poul Sander 2025-10-05 10:15 3283
// - Prefer adding a font source (ImFontConfig) using a custom/procedural loader.
4e9e2555 Poul Sander 2025-10-05 10:15 3284
// - You may use ImFontFlags_LockBakedSizes to limit an existing font to known baked sizes:
4e9e2555 Poul Sander 2025-10-05 10:15 3285
//     ImFont* myfont = io.Fonts->AddFontFromFileTTF(....);
4e9e2555 Poul Sander 2025-10-05 10:15 3286
//     myfont->GetFontBaked(16.0f);
4e9e2555 Poul Sander 2025-10-05 10:15 3287
//     myfont->Flags |= ImFontFlags_LockBakedSizes;
4e9e2555 Poul Sander 2025-10-05 10:15 3288
ImFontAtlasRectId ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar codepoint, int width, int height, float advance_x, const ImVec2& offset)
4e9e2555 Poul Sander 2025-10-05 10:15 3289
{
4e9e2555 Poul Sander 2025-10-05 10:15 3290
    float font_size = font->LegacySize;
4e9e2555 Poul Sander 2025-10-05 10:15 3291
    return AddCustomRectFontGlyphForSize(font, font_size, codepoint, width, height, advance_x, offset);
4e9e2555 Poul Sander 2025-10-05 10:15 3292
}
4e9e2555 Poul Sander 2025-10-05 10:15 3293
// FIXME: we automatically set glyph.Colored=true by default.
4e9e2555 Poul Sander 2025-10-05 10:15 3294
// If you need to alter this, you can write 'font->Glyphs.back()->Colored' after calling AddCustomRectFontGlyph().
4e9e2555 Poul Sander 2025-10-05 10:15 3295
ImFontAtlasRectId ImFontAtlas::AddCustomRectFontGlyphForSize(ImFont* font, float font_size, ImWchar codepoint, int width, int height, float advance_x, const ImVec2& offset)
1193b4be Poul Sander 2025-02-03 21:28 3296
{
1193b4be Poul Sander 2025-02-03 21:28 3297
#ifdef IMGUI_USE_WCHAR32
4e9e2555 Poul Sander 2025-10-05 10:15 3298
    IM_ASSERT(codepoint <= IM_UNICODE_CODEPOINT_MAX);
1193b4be Poul Sander 2025-02-03 21:28 3299
#endif
1193b4be Poul Sander 2025-02-03 21:28 3300
    IM_ASSERT(font != NULL);
1193b4be Poul Sander 2025-02-03 21:28 3301
    IM_ASSERT(width > 0 && width <= 0xFFFF);
1193b4be Poul Sander 2025-02-03 21:28 3302
    IM_ASSERT(height > 0 && height <= 0xFFFF);
1193b4be Poul Sander 2025-02-03 21:28 3303
4e9e2555 Poul Sander 2025-10-05 10:15 3304
    ImFontBaked* baked = font->GetFontBaked(font_size);
4e9e2555 Poul Sander 2025-10-05 10:15 3305
4e9e2555 Poul Sander 2025-10-05 10:15 3306
    ImFontAtlasRectId r_id = ImFontAtlasPackAddRect(this, width, height);
4e9e2555 Poul Sander 2025-10-05 10:15 3307
    if (r_id == ImFontAtlasRectId_Invalid)
4e9e2555 Poul Sander 2025-10-05 10:15 3308
        return ImFontAtlasRectId_Invalid;
4e9e2555 Poul Sander 2025-10-05 10:15 3309
    ImTextureRect* r = ImFontAtlasPackGetRect(this, r_id);
4e9e2555 Poul Sander 2025-10-05 10:15 3310
    if (RendererHasTextures)
4e9e2555 Poul Sander 2025-10-05 10:15 3311
        ImFontAtlasTextureBlockQueueUpload(this, TexData, r->x, r->y, r->w, r->h);
4e9e2555 Poul Sander 2025-10-05 10:15 3312
4e9e2555 Poul Sander 2025-10-05 10:15 3313
    if (baked->IsGlyphLoaded(codepoint))
4e9e2555 Poul Sander 2025-10-05 10:15 3314
        ImFontAtlasBakedDiscardFontGlyph(this, font, baked, baked->FindGlyph(codepoint));
4e9e2555 Poul Sander 2025-10-05 10:15 3315
4e9e2555 Poul Sander 2025-10-05 10:15 3316
    ImFontGlyph glyph;
4e9e2555 Poul Sander 2025-10-05 10:15 3317
    glyph.Codepoint = codepoint;
4e9e2555 Poul Sander 2025-10-05 10:15 3318
    glyph.AdvanceX = advance_x;
4e9e2555 Poul Sander 2025-10-05 10:15 3319
    glyph.X0 = offset.x;
4e9e2555 Poul Sander 2025-10-05 10:15 3320
    glyph.Y0 = offset.y;
4e9e2555 Poul Sander 2025-10-05 10:15 3321
    glyph.X1 = offset.x + r->w;
4e9e2555 Poul Sander 2025-10-05 10:15 3322
    glyph.Y1 = offset.y + r->h;
4e9e2555 Poul Sander 2025-10-05 10:15 3323
    glyph.Visible = true;
4e9e2555 Poul Sander 2025-10-05 10:15 3324
    glyph.Colored = true; // FIXME: Arbitrary
4e9e2555 Poul Sander 2025-10-05 10:15 3325
    glyph.PackId = r_id;
4e9e2555 Poul Sander 2025-10-05 10:15 3326
    ImFontAtlasBakedAddFontGlyph(this, baked, font->Sources[0], &glyph);
4e9e2555 Poul Sander 2025-10-05 10:15 3327
    return r_id;
4e9e2555 Poul Sander 2025-10-05 10:15 3328
}
4e9e2555 Poul Sander 2025-10-05 10:15 3329
#endif // #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
4e9e2555 Poul Sander 2025-10-05 10:15 3330
4e9e2555 Poul Sander 2025-10-05 10:15 3331
bool ImFontAtlas::GetCustomRect(ImFontAtlasRectId id, ImFontAtlasRect* out_r) const
4e9e2555 Poul Sander 2025-10-05 10:15 3332
{
4e9e2555 Poul Sander 2025-10-05 10:15 3333
    ImTextureRect* r = ImFontAtlasPackGetRectSafe((ImFontAtlas*)this, id);
4e9e2555 Poul Sander 2025-10-05 10:15 3334
    if (r == NULL)
4e9e2555 Poul Sander 2025-10-05 10:15 3335
        return false;
4e9e2555 Poul Sander 2025-10-05 10:15 3336
    IM_ASSERT(TexData->Width > 0 && TexData->Height > 0);   // Font atlas needs to be built before we can calculate UV coordinates
4e9e2555 Poul Sander 2025-10-05 10:15 3337
    if (out_r == NULL)
4e9e2555 Poul Sander 2025-10-05 10:15 3338
        return true;
4e9e2555 Poul Sander 2025-10-05 10:15 3339
    out_r->x = r->x;
4e9e2555 Poul Sander 2025-10-05 10:15 3340
    out_r->y = r->y;
4e9e2555 Poul Sander 2025-10-05 10:15 3341
    out_r->w = r->w;
4e9e2555 Poul Sander 2025-10-05 10:15 3342
    out_r->h = r->h;
4e9e2555 Poul Sander 2025-10-05 10:15 3343
    out_r->uv0 = ImVec2((float)(r->x), (float)(r->y)) * TexUvScale;
4e9e2555 Poul Sander 2025-10-05 10:15 3344
    out_r->uv1 = ImVec2((float)(r->x + r->w), (float)(r->y + r->h)) * TexUvScale;
4e9e2555 Poul Sander 2025-10-05 10:15 3345
    return true;
1193b4be Poul Sander 2025-02-03 21:28 3346
}
1193b4be Poul Sander 2025-02-03 21:28 3347
4e9e2555 Poul Sander 2025-10-05 10:15 3348
bool ImFontAtlasGetMouseCursorTexData(ImFontAtlas* atlas, 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 3349
{
1193b4be Poul Sander 2025-02-03 21:28 3350
    if (cursor_type <= ImGuiMouseCursor_None || cursor_type >= ImGuiMouseCursor_COUNT)
1193b4be Poul Sander 2025-02-03 21:28 3351
        return false;
4e9e2555 Poul Sander 2025-10-05 10:15 3352
    if (atlas->Flags & ImFontAtlasFlags_NoMouseCursors)
1193b4be Poul Sander 2025-02-03 21:28 3353
        return false;
1193b4be Poul Sander 2025-02-03 21:28 3354
4e9e2555 Poul Sander 2025-10-05 10:15 3355
    ImTextureRect* r = ImFontAtlasPackGetRect(atlas, atlas->Builder->PackIdMouseCursors);
4e9e2555 Poul Sander 2025-10-05 10:15 3356
    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 3357
    ImVec2 size = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][1];
1193b4be Poul Sander 2025-02-03 21:28 3358
    *out_size = size;
1193b4be Poul Sander 2025-02-03 21:28 3359
    *out_offset = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][2];
4e9e2555 Poul Sander 2025-10-05 10:15 3360
    out_uv_border[0] = (pos) * atlas->TexUvScale;
4e9e2555 Poul Sander 2025-10-05 10:15 3361
    out_uv_border[1] = (pos + size) * atlas->TexUvScale;
1193b4be Poul Sander 2025-02-03 21:28 3362
    pos.x += FONT_ATLAS_DEFAULT_TEX_DATA_W + 1;
4e9e2555 Poul Sander 2025-10-05 10:15 3363
    out_uv_fill[0] = (pos) * atlas->TexUvScale;
4e9e2555 Poul Sander 2025-10-05 10:15 3364
    out_uv_fill[1] = (pos + size) * atlas->TexUvScale;
1193b4be Poul Sander 2025-02-03 21:28 3365
    return true;
1193b4be Poul Sander 2025-02-03 21:28 3366
}
1193b4be Poul Sander 2025-02-03 21:28 3367
4e9e2555 Poul Sander 2025-10-05 10:15 3368
// When atlas->RendererHasTextures = true, this is only called if no font were loaded.
4e9e2555 Poul Sander 2025-10-05 10:15 3369
void ImFontAtlasBuildMain(ImFontAtlas* atlas)
1193b4be Poul Sander 2025-02-03 21:28 3370
{
4e9e2555 Poul Sander 2025-10-05 10:15 3371
    IM_ASSERT(!atlas->Locked && "Cannot modify a locked ImFontAtlas!");
4e9e2555 Poul Sander 2025-10-05 10:15 3372
    if (atlas->TexData && atlas->TexData->Format != atlas->TexDesiredFormat)
4e9e2555 Poul Sander 2025-10-05 10:15 3373
        ImFontAtlasBuildClear(atlas);
1193b4be Poul Sander 2025-02-03 21:28 3374
4e9e2555 Poul Sander 2025-10-05 10:15 3375
    if (atlas->Builder == NULL)
4e9e2555 Poul Sander 2025-10-05 10:15 3376
        ImFontAtlasBuildInit(atlas);
1193b4be Poul Sander 2025-02-03 21:28 3377
4e9e2555 Poul Sander 2025-10-05 10:15 3378
    // Default font is none are specified
4e9e2555 Poul Sander 2025-10-05 10:15 3379
    if (atlas->Sources.Size == 0)
4e9e2555 Poul Sander 2025-10-05 10:15 3380
        atlas->AddFontDefault();
1193b4be Poul Sander 2025-02-03 21:28 3381
4e9e2555 Poul Sander 2025-10-05 10:15 3382
    // [LEGACY] For backends not supporting RendererHasTextures: preload all glyphs
4e9e2555 Poul Sander 2025-10-05 10:15 3383
    ImFontAtlasBuildUpdateRendererHasTexturesFromContext(atlas);
4e9e2555 Poul Sander 2025-10-05 10:15 3384
    if (atlas->RendererHasTextures == false) // ~ImGuiBackendFlags_RendererHasTextures
4e9e2555 Poul Sander 2025-10-05 10:15 3385
        ImFontAtlasBuildLegacyPreloadAllGlyphRanges(atlas);
4e9e2555 Poul Sander 2025-10-05 10:15 3386
    atlas->TexIsBuilt = true;
1193b4be Poul Sander 2025-02-03 21:28 3387
}
1193b4be Poul Sander 2025-02-03 21:28 3388
4e9e2555 Poul Sander 2025-10-05 10:15 3389
void ImFontAtlasBuildGetOversampleFactors(ImFontConfig* src, ImFontBaked* baked, int* out_oversample_h, int* out_oversample_v)
1193b4be Poul Sander 2025-02-03 21:28 3390
{
4e9e2555 Poul Sander 2025-10-05 10:15 3391
    // Automatically disable horizontal oversampling over size 36
4e9e2555 Poul Sander 2025-10-05 10:15 3392
    const float raster_size = baked->Size * baked->RasterizerDensity * src->RasterizerDensity;
4e9e2555 Poul Sander 2025-10-05 10:15 3393
    *out_oversample_h = (src->OversampleH != 0) ? src->OversampleH : (raster_size > 36.0f || src->PixelSnapH) ? 1 : 2;
4e9e2555 Poul Sander 2025-10-05 10:15 3394
    *out_oversample_v = (src->OversampleV != 0) ? src->OversampleV : 1;
1193b4be Poul Sander 2025-02-03 21:28 3395
}
1193b4be Poul Sander 2025-02-03 21:28 3396
4e9e2555 Poul Sander 2025-10-05 10:15 3397
// Setup main font loader for the atlas
4e9e2555 Poul Sander 2025-10-05 10:15 3398
// Every font source (ImFontConfig) will use this unless ImFontConfig::FontLoader specify a custom loader.
4e9e2555 Poul Sander 2025-10-05 10:15 3399
void ImFontAtlasBuildSetupFontLoader(ImFontAtlas* atlas, const ImFontLoader* font_loader)
1193b4be Poul Sander 2025-02-03 21:28 3400
{
4e9e2555 Poul Sander 2025-10-05 10:15 3401
    if (atlas->FontLoader == font_loader)
4e9e2555 Poul Sander 2025-10-05 10:15 3402
        return;
4e9e2555 Poul Sander 2025-10-05 10:15 3403
    IM_ASSERT(!atlas->Locked && "Cannot modify a locked ImFontAtlas!");
1193b4be Poul Sander 2025-02-03 21:28 3404
4e9e2555 Poul Sander 2025-10-05 10:15 3405
    for (ImFont* font : atlas->Fonts)
4e9e2555 Poul Sander 2025-10-05 10:15 3406
        ImFontAtlasFontDestroyOutput(atlas, font);
4e9e2555 Poul Sander 2025-10-05 10:15 3407
    if (atlas->Builder && atlas->FontLoader && atlas->FontLoader->LoaderShutdown)
4e9e2555 Poul Sander 2025-10-05 10:15 3408
        atlas->FontLoader->LoaderShutdown(atlas);
1193b4be Poul Sander 2025-02-03 21:28 3409
4e9e2555 Poul Sander 2025-10-05 10:15 3410
    atlas->FontLoader = font_loader;
4e9e2555 Poul Sander 2025-10-05 10:15 3411
    atlas->FontLoaderName = font_loader ? font_loader->Name : "NULL";
4e9e2555 Poul Sander 2025-10-05 10:15 3412
    IM_ASSERT(atlas->FontLoaderData == NULL);
1193b4be Poul Sander 2025-02-03 21:28 3413
4e9e2555 Poul Sander 2025-10-05 10:15 3414
    if (atlas->Builder && atlas->FontLoader && atlas->FontLoader->LoaderInit)
4e9e2555 Poul Sander 2025-10-05 10:15 3415
        atlas->FontLoader->LoaderInit(atlas);
4e9e2555 Poul Sander 2025-10-05 10:15 3416
    for (ImFont* font : atlas->Fonts)
4e9e2555 Poul Sander 2025-10-05 10:15 3417
        ImFontAtlasFontInitOutput(atlas, font);
4e9e2555 Poul Sander 2025-10-05 10:15 3418
    for (ImFont* font : atlas->Fonts)
4e9e2555 Poul Sander 2025-10-05 10:15 3419
        for (ImFontConfig* src : font->Sources)
4e9e2555 Poul Sander 2025-10-05 10:15 3420
            ImFontAtlasFontSourceAddToFont(atlas, font, src);
1193b4be Poul Sander 2025-02-03 21:28 3421
}
1193b4be Poul Sander 2025-02-03 21:28 3422
4e9e2555 Poul Sander 2025-10-05 10:15 3423
// Preload all glyph ranges for legacy backends.
4e9e2555 Poul Sander 2025-10-05 10:15 3424
// This may lead to multiple texture creation which might be a little slower than before.
4e9e2555 Poul Sander 2025-10-05 10:15 3425
void ImFontAtlasBuildLegacyPreloadAllGlyphRanges(ImFontAtlas* atlas)
1193b4be Poul Sander 2025-02-03 21:28 3426
{
4e9e2555 Poul Sander 2025-10-05 10:15 3427
    atlas->Builder->PreloadedAllGlyphsRanges = true;
4e9e2555 Poul Sander 2025-10-05 10:15 3428
    for (ImFont* font : atlas->Fonts)
4e9e2555 Poul Sander 2025-10-05 10:15 3429
    {
4e9e2555 Poul Sander 2025-10-05 10:15 3430
        ImFontBaked* baked = font->GetFontBaked(font->LegacySize);
4e9e2555 Poul Sander 2025-10-05 10:15 3431
        if (font->FallbackChar != 0)
4e9e2555 Poul Sander 2025-10-05 10:15 3432
            baked->FindGlyph(font->FallbackChar);
4e9e2555 Poul Sander 2025-10-05 10:15 3433
        if (font->EllipsisChar != 0)
4e9e2555 Poul Sander 2025-10-05 10:15 3434
            baked->FindGlyph(font->EllipsisChar);
4e9e2555 Poul Sander 2025-10-05 10:15 3435
        for (ImFontConfig* src : font->Sources)
1193b4be Poul Sander 2025-02-03 21:28 3436
        {
4e9e2555 Poul Sander 2025-10-05 10:15 3437
            const ImWchar* ranges = src->GlyphRanges ? src->GlyphRanges : atlas->GetGlyphRangesDefault();
4e9e2555 Poul Sander 2025-10-05 10:15 3438
            for (; ranges[0]; ranges += 2)
4e9e2555 Poul Sander 2025-10-05 10:15 3439
                for (unsigned int c = ranges[0]; c <= ranges[1] && c <= IM_UNICODE_CODEPOINT_MAX; c++) //-V560
4e9e2555 Poul Sander 2025-10-05 10:15 3440
                    baked->FindGlyph((ImWchar)c);
1193b4be Poul Sander 2025-02-03 21:28 3441
        }
4e9e2555 Poul Sander 2025-10-05 10:15 3442
    }
4e9e2555 Poul Sander 2025-10-05 10:15 3443
}
4e9e2555 Poul Sander 2025-10-05 10:15 3444
4e9e2555 Poul Sander 2025-10-05 10:15 3445
// FIXME: May make ImFont::Sources a ImSpan<> and move ownership to ImFontAtlas
4e9e2555 Poul Sander 2025-10-05 10:15 3446
void ImFontAtlasBuildUpdatePointers(ImFontAtlas* atlas)
4e9e2555 Poul Sander 2025-10-05 10:15 3447
{
4e9e2555 Poul Sander 2025-10-05 10:15 3448
    for (ImFont* font : atlas->Fonts)
4e9e2555 Poul Sander 2025-10-05 10:15 3449
        font->Sources.resize(0);
4e9e2555 Poul Sander 2025-10-05 10:15 3450
    for (ImFontConfig& src : atlas->Sources)
4e9e2555 Poul Sander 2025-10-05 10:15 3451
        src.DstFont->Sources.push_back(&src);
4e9e2555 Poul Sander 2025-10-05 10:15 3452
}
4e9e2555 Poul Sander 2025-10-05 10:15 3453
4e9e2555 Poul Sander 2025-10-05 10:15 3454
// Render a white-colored bitmap encoded in a string
4e9e2555 Poul Sander 2025-10-05 10:15 3455
void ImFontAtlasBuildRenderBitmapFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char)
4e9e2555 Poul Sander 2025-10-05 10:15 3456
{
4e9e2555 Poul Sander 2025-10-05 10:15 3457
    ImTextureData* tex = atlas->TexData;
4e9e2555 Poul Sander 2025-10-05 10:15 3458
    IM_ASSERT(x >= 0 && x + w <= tex->Width);
4e9e2555 Poul Sander 2025-10-05 10:15 3459
    IM_ASSERT(y >= 0 && y + h <= tex->Height);
4e9e2555 Poul Sander 2025-10-05 10:15 3460
4e9e2555 Poul Sander 2025-10-05 10:15 3461
    switch (tex->Format)
4e9e2555 Poul Sander 2025-10-05 10:15 3462
    {
4e9e2555 Poul Sander 2025-10-05 10:15 3463
    case ImTextureFormat_Alpha8:
4e9e2555 Poul Sander 2025-10-05 10:15 3464
    {
4e9e2555 Poul Sander 2025-10-05 10:15 3465
        ImU8* out_p = (ImU8*)tex->GetPixelsAt(x, y);
4e9e2555 Poul Sander 2025-10-05 10:15 3466
        for (int off_y = 0; off_y < h; off_y++, out_p += tex->Width, in_str += w)
4e9e2555 Poul Sander 2025-10-05 10:15 3467
            for (int off_x = 0; off_x < w; off_x++)
4e9e2555 Poul Sander 2025-10-05 10:15 3468
                out_p[off_x] = (in_str[off_x] == in_marker_char) ? 0xFF : 0x00;
4e9e2555 Poul Sander 2025-10-05 10:15 3469
        break;
4e9e2555 Poul Sander 2025-10-05 10:15 3470
    }
4e9e2555 Poul Sander 2025-10-05 10:15 3471
    case ImTextureFormat_RGBA32:
4e9e2555 Poul Sander 2025-10-05 10:15 3472
    {
4e9e2555 Poul Sander 2025-10-05 10:15 3473
        ImU32* out_p = (ImU32*)tex->GetPixelsAt(x, y);
4e9e2555 Poul Sander 2025-10-05 10:15 3474
        for (int off_y = 0; off_y < h; off_y++, out_p += tex->Width, in_str += w)
4e9e2555 Poul Sander 2025-10-05 10:15 3475
            for (int off_x = 0; off_x < w; off_x++)
4e9e2555 Poul Sander 2025-10-05 10:15 3476
                out_p[off_x] = (in_str[off_x] == in_marker_char) ? IM_COL32_WHITE : IM_COL32_BLACK_TRANS;
4e9e2555 Poul Sander 2025-10-05 10:15 3477
        break;
4e9e2555 Poul Sander 2025-10-05 10:15 3478
    }
4e9e2555 Poul Sander 2025-10-05 10:15 3479
    }
4e9e2555 Poul Sander 2025-10-05 10:15 3480
}
4e9e2555 Poul Sander 2025-10-05 10:15 3481
4e9e2555 Poul Sander 2025-10-05 10:15 3482
static void ImFontAtlasBuildUpdateBasicTexData(ImFontAtlas* atlas)
4e9e2555 Poul Sander 2025-10-05 10:15 3483
{
4e9e2555 Poul Sander 2025-10-05 10:15 3484
    // Pack and store identifier so we can refresh UV coordinates on texture resize.
4e9e2555 Poul Sander 2025-10-05 10:15 3485
    // FIXME-NEWATLAS: User/custom rects where user code wants to store UV coordinates will need to do the same thing.
4e9e2555 Poul Sander 2025-10-05 10:15 3486
    ImFontAtlasBuilder* builder = atlas->Builder;
4e9e2555 Poul Sander 2025-10-05 10:15 3487
    ImVec2i pack_size = (atlas->Flags & ImFontAtlasFlags_NoMouseCursors) ? ImVec2i(2, 2) : ImVec2i(FONT_ATLAS_DEFAULT_TEX_DATA_W * 2 + 1, FONT_ATLAS_DEFAULT_TEX_DATA_H);
4e9e2555 Poul Sander 2025-10-05 10:15 3488
4e9e2555 Poul Sander 2025-10-05 10:15 3489
    ImFontAtlasRect r;
4e9e2555 Poul Sander 2025-10-05 10:15 3490
    bool add_and_draw = (atlas->GetCustomRect(builder->PackIdMouseCursors, &r) == false);
4e9e2555 Poul Sander 2025-10-05 10:15 3491
    if (add_and_draw)
4e9e2555 Poul Sander 2025-10-05 10:15 3492
    {
4e9e2555 Poul Sander 2025-10-05 10:15 3493
        builder->PackIdMouseCursors = atlas->AddCustomRect(pack_size.x, pack_size.y, &r);
4e9e2555 Poul Sander 2025-10-05 10:15 3494
        IM_ASSERT(builder->PackIdMouseCursors != ImFontAtlasRectId_Invalid);
4e9e2555 Poul Sander 2025-10-05 10:15 3495
4e9e2555 Poul Sander 2025-10-05 10:15 3496
        // Draw to texture
4e9e2555 Poul Sander 2025-10-05 10:15 3497
        if (atlas->Flags & ImFontAtlasFlags_NoMouseCursors)
1193b4be Poul Sander 2025-02-03 21:28 3498
        {
4e9e2555 Poul Sander 2025-10-05 10:15 3499
            // 2x2 white pixels
4e9e2555 Poul Sander 2025-10-05 10:15 3500
            ImFontAtlasBuildRenderBitmapFromString(atlas, r.x, r.y, 2, 2, "XX" "XX", 'X');
1193b4be Poul Sander 2025-02-03 21:28 3501
        }
4e9e2555 Poul Sander 2025-10-05 10:15 3502
        else
4e9e2555 Poul Sander 2025-10-05 10:15 3503
        {
4e9e2555 Poul Sander 2025-10-05 10:15 3504
            // 2x2 white pixels + mouse cursors
4e9e2555 Poul Sander 2025-10-05 10:15 3505
            const int x_for_white = r.x;
4e9e2555 Poul Sander 2025-10-05 10:15 3506
            const int x_for_black = r.x + FONT_ATLAS_DEFAULT_TEX_DATA_W + 1;
4e9e2555 Poul Sander 2025-10-05 10:15 3507
            ImFontAtlasBuildRenderBitmapFromString(atlas, x_for_white, r.y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, '.');
4e9e2555 Poul Sander 2025-10-05 10:15 3508
            ImFontAtlasBuildRenderBitmapFromString(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');
4e9e2555 Poul Sander 2025-10-05 10:15 3509
        }
4e9e2555 Poul Sander 2025-10-05 10:15 3510
    }
4e9e2555 Poul Sander 2025-10-05 10:15 3511
4e9e2555 Poul Sander 2025-10-05 10:15 3512
    // Refresh UV coordinates
4e9e2555 Poul Sander 2025-10-05 10:15 3513
    atlas->TexUvWhitePixel = ImVec2((r.x + 0.5f) * atlas->TexUvScale.x, (r.y + 0.5f) * atlas->TexUvScale.y);
4e9e2555 Poul Sander 2025-10-05 10:15 3514
}
4e9e2555 Poul Sander 2025-10-05 10:15 3515
4e9e2555 Poul Sander 2025-10-05 10:15 3516
static void ImFontAtlasBuildUpdateLinesTexData(ImFontAtlas* atlas)
4e9e2555 Poul Sander 2025-10-05 10:15 3517
{
4e9e2555 Poul Sander 2025-10-05 10:15 3518
    if (atlas->Flags & ImFontAtlasFlags_NoBakedLines)
4e9e2555 Poul Sander 2025-10-05 10:15 3519
        return;
4e9e2555 Poul Sander 2025-10-05 10:15 3520
4e9e2555 Poul Sander 2025-10-05 10:15 3521
    // Pack and store identifier so we can refresh UV coordinates on texture resize.
4e9e2555 Poul Sander 2025-10-05 10:15 3522
    ImTextureData* tex = atlas->TexData;
4e9e2555 Poul Sander 2025-10-05 10:15 3523
    ImFontAtlasBuilder* builder = atlas->Builder;
4e9e2555 Poul Sander 2025-10-05 10:15 3524
4e9e2555 Poul Sander 2025-10-05 10:15 3525
    ImFontAtlasRect r;
4e9e2555 Poul Sander 2025-10-05 10:15 3526
    bool add_and_draw = atlas->GetCustomRect(builder->PackIdLinesTexData, &r) == false;
4e9e2555 Poul Sander 2025-10-05 10:15 3527
    if (add_and_draw)
4e9e2555 Poul Sander 2025-10-05 10:15 3528
    {
4e9e2555 Poul Sander 2025-10-05 10:15 3529
        ImVec2i pack_size = ImVec2i(IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 2, IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1);
4e9e2555 Poul Sander 2025-10-05 10:15 3530
        builder->PackIdLinesTexData = atlas->AddCustomRect(pack_size.x, pack_size.y, &r);
4e9e2555 Poul Sander 2025-10-05 10:15 3531
        IM_ASSERT(builder->PackIdLinesTexData != ImFontAtlasRectId_Invalid);
4e9e2555 Poul Sander 2025-10-05 10:15 3532
    }
1193b4be Poul Sander 2025-02-03 21:28 3533
4e9e2555 Poul Sander 2025-10-05 10:15 3534
    // Register texture region for thick lines
4e9e2555 Poul Sander 2025-10-05 10:15 3535
    // 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
4e9e2555 Poul Sander 2025-10-05 10:15 3536
    // This generates a triangular shape in the texture, with the various line widths stacked on top of each other to allow interpolation between them
4e9e2555 Poul Sander 2025-10-05 10:15 3537
    for (int n = 0; n < IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1; n++) // +1 because of the zero-width row
4e9e2555 Poul Sander 2025-10-05 10:15 3538
    {
4e9e2555 Poul Sander 2025-10-05 10:15 3539
        // Each line consists of at least two empty pixels at the ends, with a line of solid pixels in the middle
4e9e2555 Poul Sander 2025-10-05 10:15 3540
        const int y = n;
4e9e2555 Poul Sander 2025-10-05 10:15 3541
        const int line_width = n;
4e9e2555 Poul Sander 2025-10-05 10:15 3542
        const int pad_left = (r.w - line_width) / 2;
4e9e2555 Poul Sander 2025-10-05 10:15 3543
        const int pad_right = r.w - (pad_left + line_width);
4e9e2555 Poul Sander 2025-10-05 10:15 3544
        IM_ASSERT(pad_left + line_width + pad_right == r.w && y < r.h); // Make sure we're inside the texture bounds before we start writing pixels
4e9e2555 Poul Sander 2025-10-05 10:15 3545
4e9e2555 Poul Sander 2025-10-05 10:15 3546
        // Write each slice
4e9e2555 Poul Sander 2025-10-05 10:15 3547
        if (add_and_draw && tex->Format == ImTextureFormat_Alpha8)
1193b4be Poul Sander 2025-02-03 21:28 3548
        {
4e9e2555 Poul Sander 2025-10-05 10:15 3549
            ImU8* write_ptr = (ImU8*)tex->GetPixelsAt(r.x, r.y + y);
4e9e2555 Poul Sander 2025-10-05 10:15 3550
            for (int i = 0; i < pad_left; i++)
4e9e2555 Poul Sander 2025-10-05 10:15 3551
                *(write_ptr + i) = 0x00;
4e9e2555 Poul Sander 2025-10-05 10:15 3552
4e9e2555 Poul Sander 2025-10-05 10:15 3553
            for (int i = 0; i < line_width; i++)
4e9e2555 Poul Sander 2025-10-05 10:15 3554
                *(write_ptr + pad_left + i) = 0xFF;
4e9e2555 Poul Sander 2025-10-05 10:15 3555
4e9e2555 Poul Sander 2025-10-05 10:15 3556
            for (int i = 0; i < pad_right; i++)
4e9e2555 Poul Sander 2025-10-05 10:15 3557
                *(write_ptr + pad_left + line_width + i) = 0x00;
4e9e2555 Poul Sander 2025-10-05 10:15 3558
        }
4e9e2555 Poul Sander 2025-10-05 10:15 3559
        else if (add_and_draw && tex->Format == ImTextureFormat_RGBA32)
4e9e2555 Poul Sander 2025-10-05 10:15 3560
        {
4e9e2555 Poul Sander 2025-10-05 10:15 3561
            ImU32* write_ptr = (ImU32*)(void*)tex->GetPixelsAt(r.x, r.y + y);
4e9e2555 Poul Sander 2025-10-05 10:15 3562
            for (int i = 0; i < pad_left; i++)
4e9e2555 Poul Sander 2025-10-05 10:15 3563
                *(write_ptr + i) = IM_COL32(255, 255, 255, 0);
4e9e2555 Poul Sander 2025-10-05 10:15 3564
4e9e2555 Poul Sander 2025-10-05 10:15 3565
            for (int i = 0; i < line_width; i++)
4e9e2555 Poul Sander 2025-10-05 10:15 3566
                *(write_ptr + pad_left + i) = IM_COL32_WHITE;
4e9e2555 Poul Sander 2025-10-05 10:15 3567
4e9e2555 Poul Sander 2025-10-05 10:15 3568
            for (int i = 0; i < pad_right; i++)
4e9e2555 Poul Sander 2025-10-05 10:15 3569
                *(write_ptr + pad_left + line_width + i) = IM_COL32(255, 255, 255, 0);
1193b4be Poul Sander 2025-02-03 21:28 3570
        }
4e9e2555 Poul Sander 2025-10-05 10:15 3571
4e9e2555 Poul Sander 2025-10-05 10:15 3572
        // Refresh UV coordinates
4e9e2555 Poul Sander 2025-10-05 10:15 3573
        ImVec2 uv0 = ImVec2((float)(r.x + pad_left - 1), (float)(r.y + y)) * atlas->TexUvScale;
4e9e2555 Poul Sander 2025-10-05 10:15 3574
        ImVec2 uv1 = ImVec2((float)(r.x + pad_left + line_width + 1), (float)(r.y + y + 1)) * atlas->TexUvScale;
4e9e2555 Poul Sander 2025-10-05 10:15 3575
        float half_v = (uv0.y + uv1.y) * 0.5f; // Calculate a constant V in the middle of the row to avoid sampling artifacts
4e9e2555 Poul Sander 2025-10-05 10:15 3576
        atlas->TexUvLines[n] = ImVec4(uv0.x, half_v, uv1.x, half_v);
1193b4be Poul Sander 2025-02-03 21:28 3577
    }
4e9e2555 Poul Sander 2025-10-05 10:15 3578
}
4e9e2555 Poul Sander 2025-10-05 10:15 3579
4e9e2555 Poul Sander 2025-10-05 10:15 3580
//-----------------------------------------------------------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 3581
4e9e2555 Poul Sander 2025-10-05 10:15 3582
// Was tempted to lazily init FontSrc but wouldn't save much + makes it more complicated to detect invalid data at AddFont()
4e9e2555 Poul Sander 2025-10-05 10:15 3583
bool ImFontAtlasFontInitOutput(ImFontAtlas* atlas, ImFont* font)
4e9e2555 Poul Sander 2025-10-05 10:15 3584
{
4e9e2555 Poul Sander 2025-10-05 10:15 3585
    bool ret = true;
4e9e2555 Poul Sander 2025-10-05 10:15 3586
    for (ImFontConfig* src : font->Sources)
4e9e2555 Poul Sander 2025-10-05 10:15 3587
        if (!ImFontAtlasFontSourceInit(atlas, src))
4e9e2555 Poul Sander 2025-10-05 10:15 3588
            ret = false;
4e9e2555 Poul Sander 2025-10-05 10:15 3589
    IM_ASSERT(ret); // Unclear how to react to this meaningfully. Assume that result will be same as initial AddFont() call.
4e9e2555 Poul Sander 2025-10-05 10:15 3590
    return ret;
4e9e2555 Poul Sander 2025-10-05 10:15 3591
}
4e9e2555 Poul Sander 2025-10-05 10:15 3592
4e9e2555 Poul Sander 2025-10-05 10:15 3593
// Keep source/input FontData
4e9e2555 Poul Sander 2025-10-05 10:15 3594
void ImFontAtlasFontDestroyOutput(ImFontAtlas* atlas, ImFont* font)
4e9e2555 Poul Sander 2025-10-05 10:15 3595
{
4e9e2555 Poul Sander 2025-10-05 10:15 3596
    font->ClearOutputData();
4e9e2555 Poul Sander 2025-10-05 10:15 3597
    for (ImFontConfig* src : font->Sources)
1193b4be Poul Sander 2025-02-03 21:28 3598
    {
4e9e2555 Poul Sander 2025-10-05 10:15 3599
        const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader;
4e9e2555 Poul Sander 2025-10-05 10:15 3600
        if (loader && loader->FontSrcDestroy != NULL)
4e9e2555 Poul Sander 2025-10-05 10:15 3601
            loader->FontSrcDestroy(atlas, src);
4e9e2555 Poul Sander 2025-10-05 10:15 3602
    }
4e9e2555 Poul Sander 2025-10-05 10:15 3603
}
4e9e2555 Poul Sander 2025-10-05 10:15 3604
4e9e2555 Poul Sander 2025-10-05 10:15 3605
//-----------------------------------------------------------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 3606
4e9e2555 Poul Sander 2025-10-05 10:15 3607
bool ImFontAtlasFontSourceInit(ImFontAtlas* atlas, ImFontConfig* src)
4e9e2555 Poul Sander 2025-10-05 10:15 3608
{
4e9e2555 Poul Sander 2025-10-05 10:15 3609
    const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader;
4e9e2555 Poul Sander 2025-10-05 10:15 3610
    if (loader->FontSrcInit != NULL && !loader->FontSrcInit(atlas, src))
4e9e2555 Poul Sander 2025-10-05 10:15 3611
        return false;
4e9e2555 Poul Sander 2025-10-05 10:15 3612
    return true;
4e9e2555 Poul Sander 2025-10-05 10:15 3613
}
4e9e2555 Poul Sander 2025-10-05 10:15 3614
4e9e2555 Poul Sander 2025-10-05 10:15 3615
void ImFontAtlasFontSourceAddToFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src)
4e9e2555 Poul Sander 2025-10-05 10:15 3616
{
4e9e2555 Poul Sander 2025-10-05 10:15 3617
    if (src->MergeMode == false)
4e9e2555 Poul Sander 2025-10-05 10:15 3618
    {
4e9e2555 Poul Sander 2025-10-05 10:15 3619
        font->ClearOutputData();
4e9e2555 Poul Sander 2025-10-05 10:15 3620
        //font->FontSize = src->SizePixels;
4e9e2555 Poul Sander 2025-10-05 10:15 3621
        font->ContainerAtlas = atlas;
4e9e2555 Poul Sander 2025-10-05 10:15 3622
        IM_ASSERT(font->Sources[0] == src);
4e9e2555 Poul Sander 2025-10-05 10:15 3623
    }
4e9e2555 Poul Sander 2025-10-05 10:15 3624
    atlas->TexIsBuilt = false; // For legacy backends
4e9e2555 Poul Sander 2025-10-05 10:15 3625
    ImFontAtlasBuildSetupFontSpecialGlyphs(atlas, font, src);
4e9e2555 Poul Sander 2025-10-05 10:15 3626
}
4e9e2555 Poul Sander 2025-10-05 10:15 3627
4e9e2555 Poul Sander 2025-10-05 10:15 3628
void ImFontAtlasFontDestroySourceData(ImFontAtlas* atlas, ImFontConfig* src)
4e9e2555 Poul Sander 2025-10-05 10:15 3629
{
4e9e2555 Poul Sander 2025-10-05 10:15 3630
    IM_UNUSED(atlas);
4e9e2555 Poul Sander 2025-10-05 10:15 3631
    if (src->FontDataOwnedByAtlas)
4e9e2555 Poul Sander 2025-10-05 10:15 3632
        IM_FREE(src->FontData);
4e9e2555 Poul Sander 2025-10-05 10:15 3633
    src->FontData = NULL;
4e9e2555 Poul Sander 2025-10-05 10:15 3634
    if (src->GlyphExcludeRanges)
4e9e2555 Poul Sander 2025-10-05 10:15 3635
        IM_FREE((void*)src->GlyphExcludeRanges);
4e9e2555 Poul Sander 2025-10-05 10:15 3636
    src->GlyphExcludeRanges = NULL;
4e9e2555 Poul Sander 2025-10-05 10:15 3637
}
4e9e2555 Poul Sander 2025-10-05 10:15 3638
4e9e2555 Poul Sander 2025-10-05 10:15 3639
// Create a compact, baked "..." if it doesn't exist, by using the ".".
4e9e2555 Poul Sander 2025-10-05 10:15 3640
// This may seem overly complicated right now but the point is to exercise and improve a technique which should be increasingly used.
4e9e2555 Poul Sander 2025-10-05 10:15 3641
// FIXME-NEWATLAS: This borrows too much from FontLoader's FontLoadGlyph() handlers and suggest that we should add further helpers.
4e9e2555 Poul Sander 2025-10-05 10:15 3642
static ImFontGlyph* ImFontAtlasBuildSetupFontBakedEllipsis(ImFontAtlas* atlas, ImFontBaked* baked)
4e9e2555 Poul Sander 2025-10-05 10:15 3643
{
4e9e2555 Poul Sander 2025-10-05 10:15 3644
    ImFont* font = baked->ContainerFont;
4e9e2555 Poul Sander 2025-10-05 10:15 3645
    IM_ASSERT(font->EllipsisChar != 0);
4e9e2555 Poul Sander 2025-10-05 10:15 3646
4e9e2555 Poul Sander 2025-10-05 10:15 3647
    const ImFontGlyph* dot_glyph = baked->FindGlyphNoFallback((ImWchar)'.');
4e9e2555 Poul Sander 2025-10-05 10:15 3648
    if (dot_glyph == NULL)
4e9e2555 Poul Sander 2025-10-05 10:15 3649
        dot_glyph = baked->FindGlyphNoFallback((ImWchar)0xFF0E);
4e9e2555 Poul Sander 2025-10-05 10:15 3650
    if (dot_glyph == NULL)
4e9e2555 Poul Sander 2025-10-05 10:15 3651
        return NULL;
4e9e2555 Poul Sander 2025-10-05 10:15 3652
    ImFontAtlasRectId dot_r_id = dot_glyph->PackId; // Deep copy to avoid invalidation of glyphs and rect pointers
4e9e2555 Poul Sander 2025-10-05 10:15 3653
    ImTextureRect* dot_r = ImFontAtlasPackGetRect(atlas, dot_r_id);
4e9e2555 Poul Sander 2025-10-05 10:15 3654
    const int dot_spacing = 1;
4e9e2555 Poul Sander 2025-10-05 10:15 3655
    const float dot_step = (dot_glyph->X1 - dot_glyph->X0) + dot_spacing;
4e9e2555 Poul Sander 2025-10-05 10:15 3656
4e9e2555 Poul Sander 2025-10-05 10:15 3657
    ImFontAtlasRectId pack_id = ImFontAtlasPackAddRect(atlas, (dot_r->w * 3 + dot_spacing * 2), dot_r->h);
4e9e2555 Poul Sander 2025-10-05 10:15 3658
    ImTextureRect* r = ImFontAtlasPackGetRect(atlas, pack_id);
4e9e2555 Poul Sander 2025-10-05 10:15 3659
4e9e2555 Poul Sander 2025-10-05 10:15 3660
    ImFontGlyph glyph_in = {};
4e9e2555 Poul Sander 2025-10-05 10:15 3661
    ImFontGlyph* glyph = &glyph_in;
4e9e2555 Poul Sander 2025-10-05 10:15 3662
    glyph->Codepoint = font->EllipsisChar;
4e9e2555 Poul Sander 2025-10-05 10:15 3663
    glyph->AdvanceX = ImMax(dot_glyph->AdvanceX, dot_glyph->X0 + dot_step * 3.0f - dot_spacing); // FIXME: Slightly odd for normally mono-space fonts but since this is used for trailing contents.
4e9e2555 Poul Sander 2025-10-05 10:15 3664
    glyph->X0 = dot_glyph->X0;
4e9e2555 Poul Sander 2025-10-05 10:15 3665
    glyph->Y0 = dot_glyph->Y0;
4e9e2555 Poul Sander 2025-10-05 10:15 3666
    glyph->X1 = dot_glyph->X0 + dot_step * 3 - dot_spacing;
4e9e2555 Poul Sander 2025-10-05 10:15 3667
    glyph->Y1 = dot_glyph->Y1;
4e9e2555 Poul Sander 2025-10-05 10:15 3668
    glyph->Visible = true;
4e9e2555 Poul Sander 2025-10-05 10:15 3669
    glyph->PackId = pack_id;
4e9e2555 Poul Sander 2025-10-05 10:15 3670
    glyph = ImFontAtlasBakedAddFontGlyph(atlas, baked, NULL, glyph);
4e9e2555 Poul Sander 2025-10-05 10:15 3671
    dot_glyph = NULL; // Invalidated
4e9e2555 Poul Sander 2025-10-05 10:15 3672
4e9e2555 Poul Sander 2025-10-05 10:15 3673
    // Copy to texture, post-process and queue update for backend
4e9e2555 Poul Sander 2025-10-05 10:15 3674
    // FIXME-NEWATLAS-V2: Dot glyph is already post-processed as this point, so this would damage it.
4e9e2555 Poul Sander 2025-10-05 10:15 3675
    dot_r = ImFontAtlasPackGetRect(atlas, dot_r_id);
4e9e2555 Poul Sander 2025-10-05 10:15 3676
    ImTextureData* tex = atlas->TexData;
4e9e2555 Poul Sander 2025-10-05 10:15 3677
    for (int n = 0; n < 3; n++)
4e9e2555 Poul Sander 2025-10-05 10:15 3678
        ImFontAtlasTextureBlockCopy(tex, dot_r->x, dot_r->y, tex, r->x + (dot_r->w + dot_spacing) * n, r->y, dot_r->w, dot_r->h);
4e9e2555 Poul Sander 2025-10-05 10:15 3679
    ImFontAtlasTextureBlockQueueUpload(atlas, tex, r->x, r->y, r->w, r->h);
4e9e2555 Poul Sander 2025-10-05 10:15 3680
4e9e2555 Poul Sander 2025-10-05 10:15 3681
    return glyph;
4e9e2555 Poul Sander 2025-10-05 10:15 3682
}
4e9e2555 Poul Sander 2025-10-05 10:15 3683
4e9e2555 Poul Sander 2025-10-05 10:15 3684
// Load fallback in order to obtain its index
4e9e2555 Poul Sander 2025-10-05 10:15 3685
// (this is called from in hot-path so we avoid extraneous parameters to minimize impact on code size)
4e9e2555 Poul Sander 2025-10-05 10:15 3686
static void ImFontAtlasBuildSetupFontBakedFallback(ImFontBaked* baked)
4e9e2555 Poul Sander 2025-10-05 10:15 3687
{
4e9e2555 Poul Sander 2025-10-05 10:15 3688
    IM_ASSERT(baked->FallbackGlyphIndex == -1);
4e9e2555 Poul Sander 2025-10-05 10:15 3689
    IM_ASSERT(baked->FallbackAdvanceX == 0.0f);
4e9e2555 Poul Sander 2025-10-05 10:15 3690
    ImFont* font = baked->ContainerFont;
4e9e2555 Poul Sander 2025-10-05 10:15 3691
    ImFontGlyph* fallback_glyph = NULL;
4e9e2555 Poul Sander 2025-10-05 10:15 3692
    if (font->FallbackChar != 0)
4e9e2555 Poul Sander 2025-10-05 10:15 3693
        fallback_glyph = baked->FindGlyphNoFallback(font->FallbackChar);
4e9e2555 Poul Sander 2025-10-05 10:15 3694
    if (fallback_glyph == NULL)
4e9e2555 Poul Sander 2025-10-05 10:15 3695
    {
4e9e2555 Poul Sander 2025-10-05 10:15 3696
        ImFontGlyph* space_glyph = baked->FindGlyphNoFallback((ImWchar)' ');
4e9e2555 Poul Sander 2025-10-05 10:15 3697
        ImFontGlyph glyph;
4e9e2555 Poul Sander 2025-10-05 10:15 3698
        glyph.Codepoint = 0;
4e9e2555 Poul Sander 2025-10-05 10:15 3699
        glyph.AdvanceX = space_glyph ? space_glyph->AdvanceX : IM_ROUND(baked->Size * 0.40f);
4e9e2555 Poul Sander 2025-10-05 10:15 3700
        fallback_glyph = ImFontAtlasBakedAddFontGlyph(font->ContainerAtlas, baked, NULL, &glyph);
4e9e2555 Poul Sander 2025-10-05 10:15 3701
    }
4e9e2555 Poul Sander 2025-10-05 10:15 3702
    baked->FallbackGlyphIndex = baked->Glyphs.index_from_ptr(fallback_glyph); // Storing index avoid need to update pointer on growth and simplify inner loop code
4e9e2555 Poul Sander 2025-10-05 10:15 3703
    baked->FallbackAdvanceX = fallback_glyph->AdvanceX;
4e9e2555 Poul Sander 2025-10-05 10:15 3704
}
4e9e2555 Poul Sander 2025-10-05 10:15 3705
4e9e2555 Poul Sander 2025-10-05 10:15 3706
static void ImFontAtlasBuildSetupFontBakedBlanks(ImFontAtlas* atlas, ImFontBaked* baked)
4e9e2555 Poul Sander 2025-10-05 10:15 3707
{
4e9e2555 Poul Sander 2025-10-05 10:15 3708
    // Mark space as always hidden (not strictly correct/necessary. but some e.g. icons fonts don't have a space. it tends to look neater in previews)
4e9e2555 Poul Sander 2025-10-05 10:15 3709
    ImFontGlyph* space_glyph = baked->FindGlyphNoFallback((ImWchar)' ');
4e9e2555 Poul Sander 2025-10-05 10:15 3710
    if (space_glyph != NULL)
4e9e2555 Poul Sander 2025-10-05 10:15 3711
        space_glyph->Visible = false;
4e9e2555 Poul Sander 2025-10-05 10:15 3712
4e9e2555 Poul Sander 2025-10-05 10:15 3713
    // Setup Tab character.
4e9e2555 Poul Sander 2025-10-05 10:15 3714
    // FIXME: Needs proper TAB handling but it needs to be contextualized (or we could arbitrary say that each string starts at "column 0" ?)
4e9e2555 Poul Sander 2025-10-05 10:15 3715
    if (baked->FindGlyphNoFallback('\t') == NULL && space_glyph != NULL)
4e9e2555 Poul Sander 2025-10-05 10:15 3716
    {
4e9e2555 Poul Sander 2025-10-05 10:15 3717
        ImFontGlyph tab_glyph;
4e9e2555 Poul Sander 2025-10-05 10:15 3718
        tab_glyph.Codepoint = '\t';
4e9e2555 Poul Sander 2025-10-05 10:15 3719
        tab_glyph.AdvanceX = space_glyph->AdvanceX * IM_TABSIZE;
4e9e2555 Poul Sander 2025-10-05 10:15 3720
        ImFontAtlasBakedAddFontGlyph(atlas, baked, NULL, &tab_glyph);
4e9e2555 Poul Sander 2025-10-05 10:15 3721
    }
4e9e2555 Poul Sander 2025-10-05 10:15 3722
}
4e9e2555 Poul Sander 2025-10-05 10:15 3723
4e9e2555 Poul Sander 2025-10-05 10:15 3724
// Load/identify special glyphs
4e9e2555 Poul Sander 2025-10-05 10:15 3725
// (note that this is called again for fonts with MergeMode)
4e9e2555 Poul Sander 2025-10-05 10:15 3726
void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src)
4e9e2555 Poul Sander 2025-10-05 10:15 3727
{
4e9e2555 Poul Sander 2025-10-05 10:15 3728
    IM_UNUSED(atlas);
4e9e2555 Poul Sander 2025-10-05 10:15 3729
    IM_ASSERT(font->Sources.contains(src));
4e9e2555 Poul Sander 2025-10-05 10:15 3730
4e9e2555 Poul Sander 2025-10-05 10:15 3731
    // Find Fallback character. Actual glyph loaded in GetFontBaked().
4e9e2555 Poul Sander 2025-10-05 10:15 3732
    const ImWchar fallback_chars[] = { font->FallbackChar, (ImWchar)IM_UNICODE_CODEPOINT_INVALID, (ImWchar)'?', (ImWchar)' ' };
4e9e2555 Poul Sander 2025-10-05 10:15 3733
    if (font->FallbackChar == 0)
4e9e2555 Poul Sander 2025-10-05 10:15 3734
        for (ImWchar candidate_char : fallback_chars)
4e9e2555 Poul Sander 2025-10-05 10:15 3735
            if (candidate_char != 0 && font->IsGlyphInFont(candidate_char))
1193b4be Poul Sander 2025-02-03 21:28 3736
            {
4e9e2555 Poul Sander 2025-10-05 10:15 3737
                font->FallbackChar = (ImWchar)candidate_char;
4e9e2555 Poul Sander 2025-10-05 10:15 3738
                break;
4e9e2555 Poul Sander 2025-10-05 10:15 3739
            }
1193b4be Poul Sander 2025-02-03 21:28 3740
4e9e2555 Poul Sander 2025-10-05 10:15 3741
    // Setup Ellipsis character. It is required for rendering elided text. We prefer using U+2026 (horizontal ellipsis).
4e9e2555 Poul Sander 2025-10-05 10:15 3742
    // However some old fonts may contain ellipsis at U+0085. Here we auto-detect most suitable ellipsis character.
4e9e2555 Poul Sander 2025-10-05 10:15 3743
    // FIXME: Note that 0x2026 is rarely included in our font ranges. Because of this we are more likely to use three individual dots.
4e9e2555 Poul Sander 2025-10-05 10:15 3744
    const ImWchar ellipsis_chars[] = { src->EllipsisChar, (ImWchar)0x2026, (ImWchar)0x0085 };
4e9e2555 Poul Sander 2025-10-05 10:15 3745
    if (font->EllipsisChar == 0)
4e9e2555 Poul Sander 2025-10-05 10:15 3746
        for (ImWchar candidate_char : ellipsis_chars)
4e9e2555 Poul Sander 2025-10-05 10:15 3747
            if (candidate_char != 0 && font->IsGlyphInFont(candidate_char))
4e9e2555 Poul Sander 2025-10-05 10:15 3748
            {
4e9e2555 Poul Sander 2025-10-05 10:15 3749
                font->EllipsisChar = candidate_char;
4e9e2555 Poul Sander 2025-10-05 10:15 3750
                break;
1193b4be Poul Sander 2025-02-03 21:28 3751
            }
4e9e2555 Poul Sander 2025-10-05 10:15 3752
    if (font->EllipsisChar == 0)
4e9e2555 Poul Sander 2025-10-05 10:15 3753
    {
4e9e2555 Poul Sander 2025-10-05 10:15 3754
        font->EllipsisChar = 0x0085;
4e9e2555 Poul Sander 2025-10-05 10:15 3755
        font->EllipsisAutoBake = true;
1193b4be Poul Sander 2025-02-03 21:28 3756
    }
4e9e2555 Poul Sander 2025-10-05 10:15 3757
}
1193b4be Poul Sander 2025-02-03 21:28 3758
4e9e2555 Poul Sander 2025-10-05 10:15 3759
void ImFontAtlasBakedDiscardFontGlyph(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked, ImFontGlyph* glyph)
4e9e2555 Poul Sander 2025-10-05 10:15 3760
{
4e9e2555 Poul Sander 2025-10-05 10:15 3761
    if (glyph->PackId != ImFontAtlasRectId_Invalid)
4e9e2555 Poul Sander 2025-10-05 10:15 3762
    {
4e9e2555 Poul Sander 2025-10-05 10:15 3763
        ImFontAtlasPackDiscardRect(atlas, glyph->PackId);
4e9e2555 Poul Sander 2025-10-05 10:15 3764
        glyph->PackId = ImFontAtlasRectId_Invalid;
4e9e2555 Poul Sander 2025-10-05 10:15 3765
    }
4e9e2555 Poul Sander 2025-10-05 10:15 3766
    ImWchar c = (ImWchar)glyph->Codepoint;
4e9e2555 Poul Sander 2025-10-05 10:15 3767
    IM_ASSERT(font->FallbackChar != c && font->EllipsisChar != c); // Unsupported for simplicity
4e9e2555 Poul Sander 2025-10-05 10:15 3768
    IM_ASSERT(glyph >= baked->Glyphs.Data && glyph < baked->Glyphs.Data + baked->Glyphs.Size);
4e9e2555 Poul Sander 2025-10-05 10:15 3769
    IM_UNUSED(font);
4e9e2555 Poul Sander 2025-10-05 10:15 3770
    baked->IndexLookup[c] = IM_FONTGLYPH_INDEX_UNUSED;
4e9e2555 Poul Sander 2025-10-05 10:15 3771
    baked->IndexAdvanceX[c] = baked->FallbackAdvanceX;
4e9e2555 Poul Sander 2025-10-05 10:15 3772
}
4e9e2555 Poul Sander 2025-10-05 10:15 3773
4e9e2555 Poul Sander 2025-10-05 10:15 3774
ImFontBaked* ImFontAtlasBakedAdd(ImFontAtlas* atlas, ImFont* font, float font_size, float font_rasterizer_density, ImGuiID baked_id)
4e9e2555 Poul Sander 2025-10-05 10:15 3775
{
4e9e2555 Poul Sander 2025-10-05 10:15 3776
    IMGUI_DEBUG_LOG_FONT("[font] Created baked %.2fpx\n", font_size);
4e9e2555 Poul Sander 2025-10-05 10:15 3777
    ImFontBaked* baked = atlas->Builder->BakedPool.push_back(ImFontBaked());
4e9e2555 Poul Sander 2025-10-05 10:15 3778
    baked->Size = font_size;
4e9e2555 Poul Sander 2025-10-05 10:15 3779
    baked->RasterizerDensity = font_rasterizer_density;
4e9e2555 Poul Sander 2025-10-05 10:15 3780
    baked->BakedId = baked_id;
4e9e2555 Poul Sander 2025-10-05 10:15 3781
    baked->ContainerFont = font;
4e9e2555 Poul Sander 2025-10-05 10:15 3782
    baked->LastUsedFrame = atlas->Builder->FrameCount;
4e9e2555 Poul Sander 2025-10-05 10:15 3783
4e9e2555 Poul Sander 2025-10-05 10:15 3784
    // Initialize backend data
4e9e2555 Poul Sander 2025-10-05 10:15 3785
    size_t loader_data_size = 0;
4e9e2555 Poul Sander 2025-10-05 10:15 3786
    for (ImFontConfig* src : font->Sources) // Cannot easily be cached as we allow changing backend
4e9e2555 Poul Sander 2025-10-05 10:15 3787
    {
4e9e2555 Poul Sander 2025-10-05 10:15 3788
        const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader;
4e9e2555 Poul Sander 2025-10-05 10:15 3789
        loader_data_size += loader->FontBakedSrcLoaderDataSize;
4e9e2555 Poul Sander 2025-10-05 10:15 3790
    }
4e9e2555 Poul Sander 2025-10-05 10:15 3791
    baked->FontLoaderDatas = (loader_data_size > 0) ? IM_ALLOC(loader_data_size) : NULL;
4e9e2555 Poul Sander 2025-10-05 10:15 3792
    char* loader_data_p = (char*)baked->FontLoaderDatas;
4e9e2555 Poul Sander 2025-10-05 10:15 3793
    for (ImFontConfig* src : font->Sources)
4e9e2555 Poul Sander 2025-10-05 10:15 3794
    {
4e9e2555 Poul Sander 2025-10-05 10:15 3795
        const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader;
4e9e2555 Poul Sander 2025-10-05 10:15 3796
        if (loader->FontBakedInit)
4e9e2555 Poul Sander 2025-10-05 10:15 3797
            loader->FontBakedInit(atlas, src, baked, loader_data_p);
4e9e2555 Poul Sander 2025-10-05 10:15 3798
        loader_data_p += loader->FontBakedSrcLoaderDataSize;
4e9e2555 Poul Sander 2025-10-05 10:15 3799
    }
4e9e2555 Poul Sander 2025-10-05 10:15 3800
4e9e2555 Poul Sander 2025-10-05 10:15 3801
    ImFontAtlasBuildSetupFontBakedBlanks(atlas, baked);
4e9e2555 Poul Sander 2025-10-05 10:15 3802
    return baked;
4e9e2555 Poul Sander 2025-10-05 10:15 3803
}
1193b4be Poul Sander 2025-02-03 21:28 3804
4e9e2555 Poul Sander 2025-10-05 10:15 3805
// FIXME-OPT: This is not a fast query. Adding a BakedCount field in Font might allow to take a shortcut for the most common case.
4e9e2555 Poul Sander 2025-10-05 10:15 3806
ImFontBaked* ImFontAtlasBakedGetClosestMatch(ImFontAtlas* atlas, ImFont* font, float font_size, float font_rasterizer_density)
4e9e2555 Poul Sander 2025-10-05 10:15 3807
{
4e9e2555 Poul Sander 2025-10-05 10:15 3808
    ImFontAtlasBuilder* builder = atlas->Builder;
4e9e2555 Poul Sander 2025-10-05 10:15 3809
    for (int step_n = 0; step_n < 2; step_n++)
4e9e2555 Poul Sander 2025-10-05 10:15 3810
    {
4e9e2555 Poul Sander 2025-10-05 10:15 3811
        ImFontBaked* closest_larger_match = NULL;
4e9e2555 Poul Sander 2025-10-05 10:15 3812
        ImFontBaked* closest_smaller_match = NULL;
4e9e2555 Poul Sander 2025-10-05 10:15 3813
        for (int baked_n = 0; baked_n < builder->BakedPool.Size; baked_n++)
1193b4be Poul Sander 2025-02-03 21:28 3814
        {
4e9e2555 Poul Sander 2025-10-05 10:15 3815
            ImFontBaked* baked = &builder->BakedPool[baked_n];
4e9e2555 Poul Sander 2025-10-05 10:15 3816
            if (baked->ContainerFont != font || baked->WantDestroy)
4e9e2555 Poul Sander 2025-10-05 10:15 3817
                continue;
4e9e2555 Poul Sander 2025-10-05 10:15 3818
            if (step_n == 0 && baked->RasterizerDensity != font_rasterizer_density) // First try with same density
4e9e2555 Poul Sander 2025-10-05 10:15 3819
                continue;
4e9e2555 Poul Sander 2025-10-05 10:15 3820
            if (baked->Size > font_size && (closest_larger_match == NULL || baked->Size < closest_larger_match->Size))
4e9e2555 Poul Sander 2025-10-05 10:15 3821
                closest_larger_match = baked;
4e9e2555 Poul Sander 2025-10-05 10:15 3822
            if (baked->Size < font_size && (closest_smaller_match == NULL || baked->Size > closest_smaller_match->Size))
4e9e2555 Poul Sander 2025-10-05 10:15 3823
                closest_smaller_match = baked;
1193b4be Poul Sander 2025-02-03 21:28 3824
        }
4e9e2555 Poul Sander 2025-10-05 10:15 3825
        if (closest_larger_match)
4e9e2555 Poul Sander 2025-10-05 10:15 3826
            if (closest_smaller_match == NULL || (closest_larger_match->Size >= font_size * 2.0f && closest_smaller_match->Size > font_size * 0.5f))
4e9e2555 Poul Sander 2025-10-05 10:15 3827
                return closest_larger_match;
4e9e2555 Poul Sander 2025-10-05 10:15 3828
        if (closest_smaller_match)
4e9e2555 Poul Sander 2025-10-05 10:15 3829
            return closest_smaller_match;
1193b4be Poul Sander 2025-02-03 21:28 3830
    }
4e9e2555 Poul Sander 2025-10-05 10:15 3831
    return NULL;
4e9e2555 Poul Sander 2025-10-05 10:15 3832
}
1193b4be Poul Sander 2025-02-03 21:28 3833
4e9e2555 Poul Sander 2025-10-05 10:15 3834
void ImFontAtlasBakedDiscard(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked)
4e9e2555 Poul Sander 2025-10-05 10:15 3835
{
4e9e2555 Poul Sander 2025-10-05 10:15 3836
    ImFontAtlasBuilder* builder = atlas->Builder;
4e9e2555 Poul Sander 2025-10-05 10:15 3837
    IMGUI_DEBUG_LOG_FONT("[font] Discard baked %.2f for \"%s\"\n", baked->Size, font->GetDebugName());
1193b4be Poul Sander 2025-02-03 21:28 3838
4e9e2555 Poul Sander 2025-10-05 10:15 3839
    for (ImFontGlyph& glyph : baked->Glyphs)
4e9e2555 Poul Sander 2025-10-05 10:15 3840
        if (glyph.PackId != ImFontAtlasRectId_Invalid)
4e9e2555 Poul Sander 2025-10-05 10:15 3841
            ImFontAtlasPackDiscardRect(atlas, glyph.PackId);
1193b4be Poul Sander 2025-02-03 21:28 3842
4e9e2555 Poul Sander 2025-10-05 10:15 3843
    char* loader_data_p = (char*)baked->FontLoaderDatas;
4e9e2555 Poul Sander 2025-10-05 10:15 3844
    for (ImFontConfig* src : font->Sources)
1193b4be Poul Sander 2025-02-03 21:28 3845
    {
4e9e2555 Poul Sander 2025-10-05 10:15 3846
        const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader;
4e9e2555 Poul Sander 2025-10-05 10:15 3847
        if (loader->FontBakedDestroy)
4e9e2555 Poul Sander 2025-10-05 10:15 3848
            loader->FontBakedDestroy(atlas, src, baked, loader_data_p);
4e9e2555 Poul Sander 2025-10-05 10:15 3849
        loader_data_p += loader->FontBakedSrcLoaderDataSize;
4e9e2555 Poul Sander 2025-10-05 10:15 3850
    }
4e9e2555 Poul Sander 2025-10-05 10:15 3851
    if (baked->FontLoaderDatas)
4e9e2555 Poul Sander 2025-10-05 10:15 3852
    {
4e9e2555 Poul Sander 2025-10-05 10:15 3853
        IM_FREE(baked->FontLoaderDatas);
4e9e2555 Poul Sander 2025-10-05 10:15 3854
        baked->FontLoaderDatas = NULL;
4e9e2555 Poul Sander 2025-10-05 10:15 3855
    }
4e9e2555 Poul Sander 2025-10-05 10:15 3856
    builder->BakedMap.SetVoidPtr(baked->BakedId, NULL);
4e9e2555 Poul Sander 2025-10-05 10:15 3857
    builder->BakedDiscardedCount++;
4e9e2555 Poul Sander 2025-10-05 10:15 3858
    baked->ClearOutputData();
4e9e2555 Poul Sander 2025-10-05 10:15 3859
    baked->WantDestroy = true;
4e9e2555 Poul Sander 2025-10-05 10:15 3860
    font->LastBaked = NULL;
4e9e2555 Poul Sander 2025-10-05 10:15 3861
}
1193b4be Poul Sander 2025-02-03 21:28 3862
4e9e2555 Poul Sander 2025-10-05 10:15 3863
// use unused_frames==0 to discard everything.
4e9e2555 Poul Sander 2025-10-05 10:15 3864
void ImFontAtlasFontDiscardBakes(ImFontAtlas* atlas, ImFont* font, int unused_frames)
4e9e2555 Poul Sander 2025-10-05 10:15 3865
{
4e9e2555 Poul Sander 2025-10-05 10:15 3866
    if (ImFontAtlasBuilder* builder = atlas->Builder) // This can be called from font destructor
4e9e2555 Poul Sander 2025-10-05 10:15 3867
        for (int baked_n = 0; baked_n < builder->BakedPool.Size; baked_n++)
4e9e2555 Poul Sander 2025-10-05 10:15 3868
        {
4e9e2555 Poul Sander 2025-10-05 10:15 3869
            ImFontBaked* baked = &builder->BakedPool[baked_n];
4e9e2555 Poul Sander 2025-10-05 10:15 3870
            if (baked->LastUsedFrame + unused_frames > atlas->Builder->FrameCount)
4e9e2555 Poul Sander 2025-10-05 10:15 3871
                continue;
4e9e2555 Poul Sander 2025-10-05 10:15 3872
            if (baked->ContainerFont != font || baked->WantDestroy)
4e9e2555 Poul Sander 2025-10-05 10:15 3873
                continue;
4e9e2555 Poul Sander 2025-10-05 10:15 3874
            ImFontAtlasBakedDiscard(atlas, font, baked);
4e9e2555 Poul Sander 2025-10-05 10:15 3875
        }
4e9e2555 Poul Sander 2025-10-05 10:15 3876
}
1193b4be Poul Sander 2025-02-03 21:28 3877
4e9e2555 Poul Sander 2025-10-05 10:15 3878
// use unused_frames==0 to discard everything.
4e9e2555 Poul Sander 2025-10-05 10:15 3879
void ImFontAtlasBuildDiscardBakes(ImFontAtlas* atlas, int unused_frames)
4e9e2555 Poul Sander 2025-10-05 10:15 3880
{
4e9e2555 Poul Sander 2025-10-05 10:15 3881
    ImFontAtlasBuilder* builder = atlas->Builder;
4e9e2555 Poul Sander 2025-10-05 10:15 3882
    for (int baked_n = 0; baked_n < builder->BakedPool.Size; baked_n++)
4e9e2555 Poul Sander 2025-10-05 10:15 3883
    {
4e9e2555 Poul Sander 2025-10-05 10:15 3884
        ImFontBaked* baked = &builder->BakedPool[baked_n];
4e9e2555 Poul Sander 2025-10-05 10:15 3885
        if (baked->LastUsedFrame + unused_frames > atlas->Builder->FrameCount)
4e9e2555 Poul Sander 2025-10-05 10:15 3886
            continue;
4e9e2555 Poul Sander 2025-10-05 10:15 3887
        if (baked->WantDestroy || (baked->ContainerFont->Flags & ImFontFlags_LockBakedSizes))
4e9e2555 Poul Sander 2025-10-05 10:15 3888
            continue;
4e9e2555 Poul Sander 2025-10-05 10:15 3889
        ImFontAtlasBakedDiscard(atlas, baked->ContainerFont, baked);
1193b4be Poul Sander 2025-02-03 21:28 3890
    }
4e9e2555 Poul Sander 2025-10-05 10:15 3891
}
1193b4be Poul Sander 2025-02-03 21:28 3892
4e9e2555 Poul Sander 2025-10-05 10:15 3893
// Those functions are designed to facilitate changing the underlying structures for ImFontAtlas to store an array of ImDrawListSharedData*
4e9e2555 Poul Sander 2025-10-05 10:15 3894
void ImFontAtlasAddDrawListSharedData(ImFontAtlas* atlas, ImDrawListSharedData* data)
4e9e2555 Poul Sander 2025-10-05 10:15 3895
{
4e9e2555 Poul Sander 2025-10-05 10:15 3896
    IM_ASSERT(!atlas->DrawListSharedDatas.contains(data));
4e9e2555 Poul Sander 2025-10-05 10:15 3897
    atlas->DrawListSharedDatas.push_back(data);
4e9e2555 Poul Sander 2025-10-05 10:15 3898
}
1193b4be Poul Sander 2025-02-03 21:28 3899
4e9e2555 Poul Sander 2025-10-05 10:15 3900
void ImFontAtlasRemoveDrawListSharedData(ImFontAtlas* atlas, ImDrawListSharedData* data)
4e9e2555 Poul Sander 2025-10-05 10:15 3901
{
4e9e2555 Poul Sander 2025-10-05 10:15 3902
    IM_ASSERT(atlas->DrawListSharedDatas.contains(data));
4e9e2555 Poul Sander 2025-10-05 10:15 3903
    atlas->DrawListSharedDatas.find_erase(data);
4e9e2555 Poul Sander 2025-10-05 10:15 3904
}
4e9e2555 Poul Sander 2025-10-05 10:15 3905
4e9e2555 Poul Sander 2025-10-05 10:15 3906
// Update texture identifier in all active draw lists
4e9e2555 Poul Sander 2025-10-05 10:15 3907
void ImFontAtlasUpdateDrawListsTextures(ImFontAtlas* atlas, ImTextureRef old_tex, ImTextureRef new_tex)
4e9e2555 Poul Sander 2025-10-05 10:15 3908
{
4e9e2555 Poul Sander 2025-10-05 10:15 3909
    for (ImDrawListSharedData* shared_data : atlas->DrawListSharedDatas)
4e9e2555 Poul Sander 2025-10-05 10:15 3910
        for (ImDrawList* draw_list : shared_data->DrawLists)
4e9e2555 Poul Sander 2025-10-05 10:15 3911
        {
4e9e2555 Poul Sander 2025-10-05 10:15 3912
            // Replace in command-buffer
4e9e2555 Poul Sander 2025-10-05 10:15 3913
            // (there is not need to replace in ImDrawListSplitter: current channel is in ImDrawList's CmdBuffer[],
4e9e2555 Poul Sander 2025-10-05 10:15 3914
            //  other channels will be on SetCurrentChannel() which already needs to compare CmdHeader anyhow)
4e9e2555 Poul Sander 2025-10-05 10:15 3915
            if (draw_list->CmdBuffer.Size > 0 && draw_list->_CmdHeader.TexRef == old_tex)
4e9e2555 Poul Sander 2025-10-05 10:15 3916
                draw_list->_SetTexture(new_tex);
4e9e2555 Poul Sander 2025-10-05 10:15 3917
4e9e2555 Poul Sander 2025-10-05 10:15 3918
            // Replace in stack
4e9e2555 Poul Sander 2025-10-05 10:15 3919
            for (ImTextureRef& stacked_tex : draw_list->_TextureStack)
4e9e2555 Poul Sander 2025-10-05 10:15 3920
                if (stacked_tex == old_tex)
4e9e2555 Poul Sander 2025-10-05 10:15 3921
                    stacked_tex = new_tex;
4e9e2555 Poul Sander 2025-10-05 10:15 3922
        }
4e9e2555 Poul Sander 2025-10-05 10:15 3923
}
4e9e2555 Poul Sander 2025-10-05 10:15 3924
4e9e2555 Poul Sander 2025-10-05 10:15 3925
// Update texture coordinates in all draw list shared context
4e9e2555 Poul Sander 2025-10-05 10:15 3926
// FIXME-NEWATLAS FIXME-OPT: Doesn't seem necessary to update for all, only one bound to current context?
4e9e2555 Poul Sander 2025-10-05 10:15 3927
void ImFontAtlasUpdateDrawListsSharedData(ImFontAtlas* atlas)
4e9e2555 Poul Sander 2025-10-05 10:15 3928
{
4e9e2555 Poul Sander 2025-10-05 10:15 3929
    for (ImDrawListSharedData* shared_data : atlas->DrawListSharedDatas)
4e9e2555 Poul Sander 2025-10-05 10:15 3930
        if (shared_data->FontAtlas == atlas)
4e9e2555 Poul Sander 2025-10-05 10:15 3931
        {
4e9e2555 Poul Sander 2025-10-05 10:15 3932
            shared_data->TexUvWhitePixel = atlas->TexUvWhitePixel;
4e9e2555 Poul Sander 2025-10-05 10:15 3933
            shared_data->TexUvLines = atlas->TexUvLines;
4e9e2555 Poul Sander 2025-10-05 10:15 3934
        }
4e9e2555 Poul Sander 2025-10-05 10:15 3935
}
4e9e2555 Poul Sander 2025-10-05 10:15 3936
4e9e2555 Poul Sander 2025-10-05 10:15 3937
// Set current texture. This is mostly called from AddTexture() + to handle a failed resize.
4e9e2555 Poul Sander 2025-10-05 10:15 3938
static void ImFontAtlasBuildSetTexture(ImFontAtlas* atlas, ImTextureData* tex)
4e9e2555 Poul Sander 2025-10-05 10:15 3939
{
4e9e2555 Poul Sander 2025-10-05 10:15 3940
    ImTextureRef old_tex_ref = atlas->TexRef;
4e9e2555 Poul Sander 2025-10-05 10:15 3941
    atlas->TexData = tex;
4e9e2555 Poul Sander 2025-10-05 10:15 3942
    atlas->TexUvScale = ImVec2(1.0f / tex->Width, 1.0f / tex->Height);
4e9e2555 Poul Sander 2025-10-05 10:15 3943
    atlas->TexRef._TexData = tex;
4e9e2555 Poul Sander 2025-10-05 10:15 3944
    //atlas->TexRef._TexID = tex->TexID; // <-- We intentionally don't do that. It would be misleading and betray promise that both fields aren't set.
4e9e2555 Poul Sander 2025-10-05 10:15 3945
    ImFontAtlasUpdateDrawListsTextures(atlas, old_tex_ref, atlas->TexRef);
4e9e2555 Poul Sander 2025-10-05 10:15 3946
}
4e9e2555 Poul Sander 2025-10-05 10:15 3947
4e9e2555 Poul Sander 2025-10-05 10:15 3948
// Create a new texture, discard previous one
4e9e2555 Poul Sander 2025-10-05 10:15 3949
ImTextureData* ImFontAtlasTextureAdd(ImFontAtlas* atlas, int w, int h)
4e9e2555 Poul Sander 2025-10-05 10:15 3950
{
4e9e2555 Poul Sander 2025-10-05 10:15 3951
    ImTextureData* old_tex = atlas->TexData;
4e9e2555 Poul Sander 2025-10-05 10:15 3952
    ImTextureData* new_tex;
4e9e2555 Poul Sander 2025-10-05 10:15 3953
4e9e2555 Poul Sander 2025-10-05 10:15 3954
    // FIXME: Cannot reuse texture because old UV may have been used already (unless we remap UV).
4e9e2555 Poul Sander 2025-10-05 10:15 3955
    /*if (old_tex != NULL && old_tex->Status == ImTextureStatus_WantCreate)
1193b4be Poul Sander 2025-02-03 21:28 3956
    {
4e9e2555 Poul Sander 2025-10-05 10:15 3957
        // Reuse texture not yet used by backend.
4e9e2555 Poul Sander 2025-10-05 10:15 3958
        IM_ASSERT(old_tex->TexID == ImTextureID_Invalid && old_tex->BackendUserData == NULL);
4e9e2555 Poul Sander 2025-10-05 10:15 3959
        old_tex->DestroyPixels();
4e9e2555 Poul Sander 2025-10-05 10:15 3960
        old_tex->Updates.clear();
4e9e2555 Poul Sander 2025-10-05 10:15 3961
        new_tex = old_tex;
4e9e2555 Poul Sander 2025-10-05 10:15 3962
        old_tex = NULL;
4e9e2555 Poul Sander 2025-10-05 10:15 3963
    }
4e9e2555 Poul Sander 2025-10-05 10:15 3964
    else*/
4e9e2555 Poul Sander 2025-10-05 10:15 3965
    {
4e9e2555 Poul Sander 2025-10-05 10:15 3966
        // Add new
4e9e2555 Poul Sander 2025-10-05 10:15 3967
        new_tex = IM_NEW(ImTextureData)();
4e9e2555 Poul Sander 2025-10-05 10:15 3968
        new_tex->UniqueID = atlas->TexNextUniqueID++;
4e9e2555 Poul Sander 2025-10-05 10:15 3969
        atlas->TexList.push_back(new_tex);
4e9e2555 Poul Sander 2025-10-05 10:15 3970
    }
4e9e2555 Poul Sander 2025-10-05 10:15 3971
    if (old_tex != NULL)
4e9e2555 Poul Sander 2025-10-05 10:15 3972
    {
4e9e2555 Poul Sander 2025-10-05 10:15 3973
        // Queue old as to destroy next frame
4e9e2555 Poul Sander 2025-10-05 10:15 3974
        old_tex->WantDestroyNextFrame = true;
4e9e2555 Poul Sander 2025-10-05 10:15 3975
        IM_ASSERT(old_tex->Status == ImTextureStatus_OK || old_tex->Status == ImTextureStatus_WantCreate || old_tex->Status == ImTextureStatus_WantUpdates);
4e9e2555 Poul Sander 2025-10-05 10:15 3976
    }
4e9e2555 Poul Sander 2025-10-05 10:15 3977
4e9e2555 Poul Sander 2025-10-05 10:15 3978
    new_tex->Create(atlas->TexDesiredFormat, w, h);
4e9e2555 Poul Sander 2025-10-05 10:15 3979
    atlas->TexIsBuilt = false;
1193b4be Poul Sander 2025-02-03 21:28 3980
4e9e2555 Poul Sander 2025-10-05 10:15 3981
    ImFontAtlasBuildSetTexture(atlas, new_tex);
1193b4be Poul Sander 2025-02-03 21:28 3982
4e9e2555 Poul Sander 2025-10-05 10:15 3983
    return new_tex;
4e9e2555 Poul Sander 2025-10-05 10:15 3984
}
4e9e2555 Poul Sander 2025-10-05 10:15 3985
4e9e2555 Poul Sander 2025-10-05 10:15 3986
#if 0
4e9e2555 Poul Sander 2025-10-05 10:15 3987
#define STB_IMAGE_WRITE_IMPLEMENTATION
4e9e2555 Poul Sander 2025-10-05 10:15 3988
#include "../stb/stb_image_write.h"
4e9e2555 Poul Sander 2025-10-05 10:15 3989
static void ImFontAtlasDebugWriteTexToDisk(ImTextureData* tex, const char* description)
4e9e2555 Poul Sander 2025-10-05 10:15 3990
{
4e9e2555 Poul Sander 2025-10-05 10:15 3991
    ImGuiContext& g = *GImGui;
4e9e2555 Poul Sander 2025-10-05 10:15 3992
    char buf[128];
4e9e2555 Poul Sander 2025-10-05 10:15 3993
    ImFormatString(buf, IM_ARRAYSIZE(buf), "[%05d] Texture #%03d - %s.png", g.FrameCount, tex->UniqueID, description);
4e9e2555 Poul Sander 2025-10-05 10:15 3994
    stbi_write_png(buf, tex->Width, tex->Height, tex->BytesPerPixel, tex->Pixels, tex->GetPitch()); // tex->BytesPerPixel is technically not component, but ok for the formats we support.
4e9e2555 Poul Sander 2025-10-05 10:15 3995
}
4e9e2555 Poul Sander 2025-10-05 10:15 3996
#endif
4e9e2555 Poul Sander 2025-10-05 10:15 3997
4e9e2555 Poul Sander 2025-10-05 10:15 3998
void ImFontAtlasTextureRepack(ImFontAtlas* atlas, int w, int h)
4e9e2555 Poul Sander 2025-10-05 10:15 3999
{
4e9e2555 Poul Sander 2025-10-05 10:15 4000
    ImFontAtlasBuilder* builder = atlas->Builder;
4e9e2555 Poul Sander 2025-10-05 10:15 4001
    builder->LockDisableResize = true;
4e9e2555 Poul Sander 2025-10-05 10:15 4002
4e9e2555 Poul Sander 2025-10-05 10:15 4003
    ImTextureData* old_tex = atlas->TexData;
4e9e2555 Poul Sander 2025-10-05 10:15 4004
    ImTextureData* new_tex = ImFontAtlasTextureAdd(atlas, w, h);
4e9e2555 Poul Sander 2025-10-05 10:15 4005
    new_tex->UseColors = old_tex->UseColors;
4e9e2555 Poul Sander 2025-10-05 10:15 4006
    IMGUI_DEBUG_LOG_FONT("[font] Texture #%03d: resize+repack %dx%d => Texture #%03d: %dx%d\n", old_tex->UniqueID, old_tex->Width, old_tex->Height, new_tex->UniqueID, new_tex->Width, new_tex->Height);
4e9e2555 Poul Sander 2025-10-05 10:15 4007
    //for (int baked_n = 0; baked_n < builder->BakedPool.Size; baked_n++)
4e9e2555 Poul Sander 2025-10-05 10:15 4008
    //    IMGUI_DEBUG_LOG_FONT("[font] - Baked %.2fpx, %d glyphs, want_destroy=%d\n", builder->BakedPool[baked_n].FontSize, builder->BakedPool[baked_n].Glyphs.Size, builder->BakedPool[baked_n].WantDestroy);
4e9e2555 Poul Sander 2025-10-05 10:15 4009
    //IMGUI_DEBUG_LOG_FONT("[font] - Old packed rects: %d, area %d px\n", builder->RectsPackedCount, builder->RectsPackedSurface);
4e9e2555 Poul Sander 2025-10-05 10:15 4010
    //ImFontAtlasDebugWriteTexToDisk(old_tex, "Before Pack");
4e9e2555 Poul Sander 2025-10-05 10:15 4011
4e9e2555 Poul Sander 2025-10-05 10:15 4012
    // Repack, lose discarded rectangle, copy pixels
4e9e2555 Poul Sander 2025-10-05 10:15 4013
    // FIXME-NEWATLAS: This is unstable because packing order is based on RectsIndex
4e9e2555 Poul Sander 2025-10-05 10:15 4014
    // FIXME-NEWATLAS-V2: Repacking in batch would be beneficial to packing heuristic, and fix stability.
4e9e2555 Poul Sander 2025-10-05 10:15 4015
    // FIXME-NEWATLAS-TESTS: Test calling RepackTexture with size too small to fits existing rects.
4e9e2555 Poul Sander 2025-10-05 10:15 4016
    ImFontAtlasPackInit(atlas);
4e9e2555 Poul Sander 2025-10-05 10:15 4017
    ImVector<ImTextureRect> old_rects;
4e9e2555 Poul Sander 2025-10-05 10:15 4018
    ImVector<ImFontAtlasRectEntry> old_index = builder->RectsIndex;
4e9e2555 Poul Sander 2025-10-05 10:15 4019
    old_rects.swap(builder->Rects);
4e9e2555 Poul Sander 2025-10-05 10:15 4020
4e9e2555 Poul Sander 2025-10-05 10:15 4021
    for (ImFontAtlasRectEntry& index_entry : builder->RectsIndex)
4e9e2555 Poul Sander 2025-10-05 10:15 4022
    {
4e9e2555 Poul Sander 2025-10-05 10:15 4023
        if (index_entry.IsUsed == false)
4e9e2555 Poul Sander 2025-10-05 10:15 4024
            continue;
4e9e2555 Poul Sander 2025-10-05 10:15 4025
        ImTextureRect& old_r = old_rects[index_entry.TargetIndex];
4e9e2555 Poul Sander 2025-10-05 10:15 4026
        if (old_r.w == 0 && old_r.h == 0)
4e9e2555 Poul Sander 2025-10-05 10:15 4027
            continue;
4e9e2555 Poul Sander 2025-10-05 10:15 4028
        ImFontAtlasRectId new_r_id = ImFontAtlasPackAddRect(atlas, old_r.w, old_r.h, &index_entry);
4e9e2555 Poul Sander 2025-10-05 10:15 4029
        if (new_r_id == ImFontAtlasRectId_Invalid)
1193b4be Poul Sander 2025-02-03 21:28 4030
        {
4e9e2555 Poul Sander 2025-10-05 10:15 4031
            // Undo, grow texture and try repacking again.
4e9e2555 Poul Sander 2025-10-05 10:15 4032
            // FIXME-NEWATLAS-TESTS: This is a very rarely exercised path! It needs to be automatically tested properly.
4e9e2555 Poul Sander 2025-10-05 10:15 4033
            IMGUI_DEBUG_LOG_FONT("[font] Texture #%03d: resize failed. Will grow.\n", new_tex->UniqueID);
4e9e2555 Poul Sander 2025-10-05 10:15 4034
            new_tex->WantDestroyNextFrame = true;
4e9e2555 Poul Sander 2025-10-05 10:15 4035
            builder->Rects.swap(old_rects);
4e9e2555 Poul Sander 2025-10-05 10:15 4036
            builder->RectsIndex = old_index;
4e9e2555 Poul Sander 2025-10-05 10:15 4037
            ImFontAtlasBuildSetTexture(atlas, old_tex);
4e9e2555 Poul Sander 2025-10-05 10:15 4038
            ImFontAtlasTextureGrow(atlas, w, h); // Recurse
4e9e2555 Poul Sander 2025-10-05 10:15 4039
            return;
1193b4be Poul Sander 2025-02-03 21:28 4040
        }
4e9e2555 Poul Sander 2025-10-05 10:15 4041
        IM_ASSERT(ImFontAtlasRectId_GetIndex(new_r_id) == builder->RectsIndex.index_from_ptr(&index_entry));
4e9e2555 Poul Sander 2025-10-05 10:15 4042
        ImTextureRect* new_r = ImFontAtlasPackGetRect(atlas, new_r_id);
4e9e2555 Poul Sander 2025-10-05 10:15 4043
        ImFontAtlasTextureBlockCopy(old_tex, old_r.x, old_r.y, new_tex, new_r->x, new_r->y, new_r->w, new_r->h);
1193b4be Poul Sander 2025-02-03 21:28 4044
    }
4e9e2555 Poul Sander 2025-10-05 10:15 4045
    IM_ASSERT(old_rects.Size == builder->Rects.Size + builder->RectsDiscardedCount);
4e9e2555 Poul Sander 2025-10-05 10:15 4046
    builder->RectsDiscardedCount = 0;
4e9e2555 Poul Sander 2025-10-05 10:15 4047
    builder->RectsDiscardedSurface = 0;
4e9e2555 Poul Sander 2025-10-05 10:15 4048
4e9e2555 Poul Sander 2025-10-05 10:15 4049
    // Patch glyphs UV
4e9e2555 Poul Sander 2025-10-05 10:15 4050
    for (int baked_n = 0; baked_n < builder->BakedPool.Size; baked_n++)
4e9e2555 Poul Sander 2025-10-05 10:15 4051
        for (ImFontGlyph& glyph : builder->BakedPool[baked_n].Glyphs)
4e9e2555 Poul Sander 2025-10-05 10:15 4052
            if (glyph.PackId != ImFontAtlasRectId_Invalid)
4e9e2555 Poul Sander 2025-10-05 10:15 4053
            {
4e9e2555 Poul Sander 2025-10-05 10:15 4054
                ImTextureRect* r = ImFontAtlasPackGetRect(atlas, glyph.PackId);
4e9e2555 Poul Sander 2025-10-05 10:15 4055
                glyph.U0 = (r->x) * atlas->TexUvScale.x;
4e9e2555 Poul Sander 2025-10-05 10:15 4056
                glyph.V0 = (r->y) * atlas->TexUvScale.y;
4e9e2555 Poul Sander 2025-10-05 10:15 4057
                glyph.U1 = (r->x + r->w) * atlas->TexUvScale.x;
4e9e2555 Poul Sander 2025-10-05 10:15 4058
                glyph.V1 = (r->y + r->h) * atlas->TexUvScale.y;
4e9e2555 Poul Sander 2025-10-05 10:15 4059
            }
4e9e2555 Poul Sander 2025-10-05 10:15 4060
4e9e2555 Poul Sander 2025-10-05 10:15 4061
    // Update other cached UV
4e9e2555 Poul Sander 2025-10-05 10:15 4062
    ImFontAtlasBuildUpdateLinesTexData(atlas);
4e9e2555 Poul Sander 2025-10-05 10:15 4063
    ImFontAtlasBuildUpdateBasicTexData(atlas);
4e9e2555 Poul Sander 2025-10-05 10:15 4064
4e9e2555 Poul Sander 2025-10-05 10:15 4065
    builder->LockDisableResize = false;
4e9e2555 Poul Sander 2025-10-05 10:15 4066
    ImFontAtlasUpdateDrawListsSharedData(atlas);
4e9e2555 Poul Sander 2025-10-05 10:15 4067
    //ImFontAtlasDebugWriteTexToDisk(new_tex, "After Pack");
4e9e2555 Poul Sander 2025-10-05 10:15 4068
}
4e9e2555 Poul Sander 2025-10-05 10:15 4069
4e9e2555 Poul Sander 2025-10-05 10:15 4070
void ImFontAtlasTextureGrow(ImFontAtlas* atlas, int old_tex_w, int old_tex_h)
4e9e2555 Poul Sander 2025-10-05 10:15 4071
{
4e9e2555 Poul Sander 2025-10-05 10:15 4072
    //ImFontAtlasDebugWriteTexToDisk(atlas->TexData, "Before Grow");
4e9e2555 Poul Sander 2025-10-05 10:15 4073
    ImFontAtlasBuilder* builder = atlas->Builder;
4e9e2555 Poul Sander 2025-10-05 10:15 4074
    if (old_tex_w == -1)
4e9e2555 Poul Sander 2025-10-05 10:15 4075
        old_tex_w = atlas->TexData->Width;
4e9e2555 Poul Sander 2025-10-05 10:15 4076
    if (old_tex_h == -1)
4e9e2555 Poul Sander 2025-10-05 10:15 4077
        old_tex_h = atlas->TexData->Height;
4e9e2555 Poul Sander 2025-10-05 10:15 4078
4e9e2555 Poul Sander 2025-10-05 10:15 4079
    // FIXME-NEWATLAS-V2: What to do when reaching limits exposed by backend?
4e9e2555 Poul Sander 2025-10-05 10:15 4080
    // FIXME-NEWATLAS-V2: Does ImFontAtlasFlags_NoPowerOfTwoHeight makes sense now? Allow 'lock' and 'compact' operations?
4e9e2555 Poul Sander 2025-10-05 10:15 4081
    IM_ASSERT(ImIsPowerOfTwo(old_tex_w) && ImIsPowerOfTwo(old_tex_h));
4e9e2555 Poul Sander 2025-10-05 10:15 4082
    IM_ASSERT(ImIsPowerOfTwo(atlas->TexMinWidth) && ImIsPowerOfTwo(atlas->TexMaxWidth) && ImIsPowerOfTwo(atlas->TexMinHeight) && ImIsPowerOfTwo(atlas->TexMaxHeight));
4e9e2555 Poul Sander 2025-10-05 10:15 4083
4e9e2555 Poul Sander 2025-10-05 10:15 4084
    // Grow texture so it follows roughly a square.
4e9e2555 Poul Sander 2025-10-05 10:15 4085
    // - Grow height before width, as width imply more packing nodes.
4e9e2555 Poul Sander 2025-10-05 10:15 4086
    // - Caller should be taking account of RectsDiscardedSurface and may not need to grow.
4e9e2555 Poul Sander 2025-10-05 10:15 4087
    int new_tex_w = (old_tex_h <= old_tex_w) ? old_tex_w : old_tex_w * 2;
4e9e2555 Poul Sander 2025-10-05 10:15 4088
    int new_tex_h = (old_tex_h <= old_tex_w) ? old_tex_h * 2 : old_tex_h;
4e9e2555 Poul Sander 2025-10-05 10:15 4089
4e9e2555 Poul Sander 2025-10-05 10:15 4090
    // Handle minimum size first (for pathologically large packed rects)
4e9e2555 Poul Sander 2025-10-05 10:15 4091
    const int pack_padding = atlas->TexGlyphPadding;
4e9e2555 Poul Sander 2025-10-05 10:15 4092
    new_tex_w = ImMax(new_tex_w, ImUpperPowerOfTwo(builder->MaxRectSize.x + pack_padding));
4e9e2555 Poul Sander 2025-10-05 10:15 4093
    new_tex_h = ImMax(new_tex_h, ImUpperPowerOfTwo(builder->MaxRectSize.y + pack_padding));
4e9e2555 Poul Sander 2025-10-05 10:15 4094
    new_tex_w = ImClamp(new_tex_w, atlas->TexMinWidth, atlas->TexMaxWidth);
4e9e2555 Poul Sander 2025-10-05 10:15 4095
    new_tex_h = ImClamp(new_tex_h, atlas->TexMinHeight, atlas->TexMaxHeight);
4e9e2555 Poul Sander 2025-10-05 10:15 4096
    if (new_tex_w == old_tex_w && new_tex_h == old_tex_h)
4e9e2555 Poul Sander 2025-10-05 10:15 4097
        return;
4e9e2555 Poul Sander 2025-10-05 10:15 4098
4e9e2555 Poul Sander 2025-10-05 10:15 4099
    ImFontAtlasTextureRepack(atlas, new_tex_w, new_tex_h);
4e9e2555 Poul Sander 2025-10-05 10:15 4100
}
1193b4be Poul Sander 2025-02-03 21:28 4101
4e9e2555 Poul Sander 2025-10-05 10:15 4102
void ImFontAtlasTextureMakeSpace(ImFontAtlas* atlas)
4e9e2555 Poul Sander 2025-10-05 10:15 4103
{
4e9e2555 Poul Sander 2025-10-05 10:15 4104
    // Can some baked contents be ditched?
4e9e2555 Poul Sander 2025-10-05 10:15 4105
    //IMGUI_DEBUG_LOG_FONT("[font] ImFontAtlasBuildMakeSpace()\n");
4e9e2555 Poul Sander 2025-10-05 10:15 4106
    ImFontAtlasBuilder* builder = atlas->Builder;
4e9e2555 Poul Sander 2025-10-05 10:15 4107
    ImFontAtlasBuildDiscardBakes(atlas, 2);
4e9e2555 Poul Sander 2025-10-05 10:15 4108
4e9e2555 Poul Sander 2025-10-05 10:15 4109
    // Currently using a heuristic for repack without growing.
4e9e2555 Poul Sander 2025-10-05 10:15 4110
    if (builder->RectsDiscardedSurface < builder->RectsPackedSurface * 0.20f)
4e9e2555 Poul Sander 2025-10-05 10:15 4111
        ImFontAtlasTextureGrow(atlas);
4e9e2555 Poul Sander 2025-10-05 10:15 4112
    else
4e9e2555 Poul Sander 2025-10-05 10:15 4113
        ImFontAtlasTextureRepack(atlas, atlas->TexData->Width, atlas->TexData->Height);
4e9e2555 Poul Sander 2025-10-05 10:15 4114
}
1193b4be Poul Sander 2025-02-03 21:28 4115
4e9e2555 Poul Sander 2025-10-05 10:15 4116
ImVec2i ImFontAtlasTextureGetSizeEstimate(ImFontAtlas* atlas)
4e9e2555 Poul Sander 2025-10-05 10:15 4117
{
4e9e2555 Poul Sander 2025-10-05 10:15 4118
    int min_w = ImUpperPowerOfTwo(atlas->TexMinWidth);
4e9e2555 Poul Sander 2025-10-05 10:15 4119
    int min_h = ImUpperPowerOfTwo(atlas->TexMinHeight);
4e9e2555 Poul Sander 2025-10-05 10:15 4120
    if (atlas->Builder == NULL || atlas->TexData == NULL || atlas->TexData->Status == ImTextureStatus_WantDestroy)
4e9e2555 Poul Sander 2025-10-05 10:15 4121
        return ImVec2i(min_w, min_h);
4e9e2555 Poul Sander 2025-10-05 10:15 4122
4e9e2555 Poul Sander 2025-10-05 10:15 4123
    ImFontAtlasBuilder* builder = atlas->Builder;
4e9e2555 Poul Sander 2025-10-05 10:15 4124
    min_w = ImMax(ImUpperPowerOfTwo(builder->MaxRectSize.x), min_w);
4e9e2555 Poul Sander 2025-10-05 10:15 4125
    min_h = ImMax(ImUpperPowerOfTwo(builder->MaxRectSize.y), min_h);
4e9e2555 Poul Sander 2025-10-05 10:15 4126
    const int surface_approx = builder->RectsPackedSurface - builder->RectsDiscardedSurface; // Expected surface after repack
4e9e2555 Poul Sander 2025-10-05 10:15 4127
    const int surface_sqrt = (int)sqrtf((float)surface_approx);
4e9e2555 Poul Sander 2025-10-05 10:15 4128
4e9e2555 Poul Sander 2025-10-05 10:15 4129
    int new_tex_w;
4e9e2555 Poul Sander 2025-10-05 10:15 4130
    int new_tex_h;
4e9e2555 Poul Sander 2025-10-05 10:15 4131
    if (min_w >= min_h)
4e9e2555 Poul Sander 2025-10-05 10:15 4132
    {
4e9e2555 Poul Sander 2025-10-05 10:15 4133
        new_tex_w = ImMax(min_w, ImUpperPowerOfTwo(surface_sqrt));
4e9e2555 Poul Sander 2025-10-05 10:15 4134
        new_tex_h = ImMax(min_h, (int)((surface_approx + new_tex_w - 1) / new_tex_w));
4e9e2555 Poul Sander 2025-10-05 10:15 4135
        if ((atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) == 0)
4e9e2555 Poul Sander 2025-10-05 10:15 4136
            new_tex_h = ImUpperPowerOfTwo(new_tex_h);
4e9e2555 Poul Sander 2025-10-05 10:15 4137
    }
4e9e2555 Poul Sander 2025-10-05 10:15 4138
    else
1193b4be Poul Sander 2025-02-03 21:28 4139
    {
4e9e2555 Poul Sander 2025-10-05 10:15 4140
        new_tex_h = ImMax(min_h, ImUpperPowerOfTwo(surface_sqrt));
4e9e2555 Poul Sander 2025-10-05 10:15 4141
        if ((atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) == 0)
4e9e2555 Poul Sander 2025-10-05 10:15 4142
            new_tex_h = ImUpperPowerOfTwo(new_tex_h);
4e9e2555 Poul Sander 2025-10-05 10:15 4143
        new_tex_w = ImMax(min_w, (int)((surface_approx + new_tex_h - 1) / new_tex_h));
4e9e2555 Poul Sander 2025-10-05 10:15 4144
    }
1193b4be Poul Sander 2025-02-03 21:28 4145
4e9e2555 Poul Sander 2025-10-05 10:15 4146
    IM_ASSERT(ImIsPowerOfTwo(new_tex_w) && ImIsPowerOfTwo(new_tex_h));
4e9e2555 Poul Sander 2025-10-05 10:15 4147
    return ImVec2i(new_tex_w, new_tex_h);
4e9e2555 Poul Sander 2025-10-05 10:15 4148
}
4e9e2555 Poul Sander 2025-10-05 10:15 4149
4e9e2555 Poul Sander 2025-10-05 10:15 4150
// Clear all output. Invalidates all AddCustomRect() return values!
4e9e2555 Poul Sander 2025-10-05 10:15 4151
void ImFontAtlasBuildClear(ImFontAtlas* atlas)
4e9e2555 Poul Sander 2025-10-05 10:15 4152
{
4e9e2555 Poul Sander 2025-10-05 10:15 4153
    ImVec2i new_tex_size = ImFontAtlasTextureGetSizeEstimate(atlas);
4e9e2555 Poul Sander 2025-10-05 10:15 4154
    ImFontAtlasBuildDestroy(atlas);
4e9e2555 Poul Sander 2025-10-05 10:15 4155
    ImFontAtlasTextureAdd(atlas, new_tex_size.x, new_tex_size.y);
4e9e2555 Poul Sander 2025-10-05 10:15 4156
    ImFontAtlasBuildInit(atlas);
4e9e2555 Poul Sander 2025-10-05 10:15 4157
    for (ImFontConfig& src : atlas->Sources)
4e9e2555 Poul Sander 2025-10-05 10:15 4158
        ImFontAtlasFontSourceInit(atlas, &src);
4e9e2555 Poul Sander 2025-10-05 10:15 4159
    for (ImFont* font : atlas->Fonts)
4e9e2555 Poul Sander 2025-10-05 10:15 4160
        for (ImFontConfig* src : font->Sources)
4e9e2555 Poul Sander 2025-10-05 10:15 4161
            ImFontAtlasFontSourceAddToFont(atlas, font, src);
4e9e2555 Poul Sander 2025-10-05 10:15 4162
}
4e9e2555 Poul Sander 2025-10-05 10:15 4163
4e9e2555 Poul Sander 2025-10-05 10:15 4164
// You should not need to call this manually!
4e9e2555 Poul Sander 2025-10-05 10:15 4165
// If you think you do, let us know and we can advise about policies auto-compact.
4e9e2555 Poul Sander 2025-10-05 10:15 4166
void ImFontAtlasTextureCompact(ImFontAtlas* atlas)
4e9e2555 Poul Sander 2025-10-05 10:15 4167
{
4e9e2555 Poul Sander 2025-10-05 10:15 4168
    ImFontAtlasBuilder* builder = atlas->Builder;
4e9e2555 Poul Sander 2025-10-05 10:15 4169
    ImFontAtlasBuildDiscardBakes(atlas, 1);
4e9e2555 Poul Sander 2025-10-05 10:15 4170
4e9e2555 Poul Sander 2025-10-05 10:15 4171
    ImTextureData* old_tex = atlas->TexData;
4e9e2555 Poul Sander 2025-10-05 10:15 4172
    ImVec2i old_tex_size = ImVec2i(old_tex->Width, old_tex->Height);
4e9e2555 Poul Sander 2025-10-05 10:15 4173
    ImVec2i new_tex_size = ImFontAtlasTextureGetSizeEstimate(atlas);
4e9e2555 Poul Sander 2025-10-05 10:15 4174
    if (builder->RectsDiscardedCount == 0 && new_tex_size.x == old_tex_size.x && new_tex_size.y == old_tex_size.y)
4e9e2555 Poul Sander 2025-10-05 10:15 4175
        return;
4e9e2555 Poul Sander 2025-10-05 10:15 4176
4e9e2555 Poul Sander 2025-10-05 10:15 4177
    ImFontAtlasTextureRepack(atlas, new_tex_size.x, new_tex_size.y);
4e9e2555 Poul Sander 2025-10-05 10:15 4178
}
4e9e2555 Poul Sander 2025-10-05 10:15 4179
4e9e2555 Poul Sander 2025-10-05 10:15 4180
// Start packing over current empty texture
4e9e2555 Poul Sander 2025-10-05 10:15 4181
void ImFontAtlasBuildInit(ImFontAtlas* atlas)
4e9e2555 Poul Sander 2025-10-05 10:15 4182
{
4e9e2555 Poul Sander 2025-10-05 10:15 4183
    // Select Backend
4e9e2555 Poul Sander 2025-10-05 10:15 4184
    // - Note that we do not reassign to atlas->FontLoader, since it is likely to point to static data which
4e9e2555 Poul Sander 2025-10-05 10:15 4185
    //   may mess with some hot-reloading schemes. If you need to assign to this (for dynamic selection) AND are
4e9e2555 Poul Sander 2025-10-05 10:15 4186
    //   using a hot-reloading scheme that messes up static data, store your own instance of FontLoader somewhere
4e9e2555 Poul Sander 2025-10-05 10:15 4187
    //   and point to it instead of pointing directly to return value of the GetFontLoaderXXX functions.
4e9e2555 Poul Sander 2025-10-05 10:15 4188
    if (atlas->FontLoader == NULL)
4e9e2555 Poul Sander 2025-10-05 10:15 4189
    {
4e9e2555 Poul Sander 2025-10-05 10:15 4190
#ifdef IMGUI_ENABLE_FREETYPE
4e9e2555 Poul Sander 2025-10-05 10:15 4191
        atlas->SetFontLoader(ImGuiFreeType::GetFontLoader());
4e9e2555 Poul Sander 2025-10-05 10:15 4192
#elif defined(IMGUI_ENABLE_STB_TRUETYPE)
4e9e2555 Poul Sander 2025-10-05 10:15 4193
        atlas->SetFontLoader(ImFontAtlasGetFontLoaderForStbTruetype());
4e9e2555 Poul Sander 2025-10-05 10:15 4194
#else
4e9e2555 Poul Sander 2025-10-05 10:15 4195
        IM_ASSERT(0); // Invalid Build function
4e9e2555 Poul Sander 2025-10-05 10:15 4196
#endif
4e9e2555 Poul Sander 2025-10-05 10:15 4197
    }
4e9e2555 Poul Sander 2025-10-05 10:15 4198
4e9e2555 Poul Sander 2025-10-05 10:15 4199
    // Create initial texture size
4e9e2555 Poul Sander 2025-10-05 10:15 4200
    if (atlas->TexData == NULL || atlas->TexData->Pixels == NULL)
4e9e2555 Poul Sander 2025-10-05 10:15 4201
        ImFontAtlasTextureAdd(atlas, ImUpperPowerOfTwo(atlas->TexMinWidth), ImUpperPowerOfTwo(atlas->TexMinHeight));
4e9e2555 Poul Sander 2025-10-05 10:15 4202
4e9e2555 Poul Sander 2025-10-05 10:15 4203
    atlas->Builder = IM_NEW(ImFontAtlasBuilder)();
4e9e2555 Poul Sander 2025-10-05 10:15 4204
    if (atlas->FontLoader->LoaderInit)
4e9e2555 Poul Sander 2025-10-05 10:15 4205
        atlas->FontLoader->LoaderInit(atlas);
4e9e2555 Poul Sander 2025-10-05 10:15 4206
4e9e2555 Poul Sander 2025-10-05 10:15 4207
    ImFontAtlasBuildUpdateRendererHasTexturesFromContext(atlas);
4e9e2555 Poul Sander 2025-10-05 10:15 4208
4e9e2555 Poul Sander 2025-10-05 10:15 4209
    ImFontAtlasPackInit(atlas);
4e9e2555 Poul Sander 2025-10-05 10:15 4210
4e9e2555 Poul Sander 2025-10-05 10:15 4211
    // Add required texture data
4e9e2555 Poul Sander 2025-10-05 10:15 4212
    ImFontAtlasBuildUpdateLinesTexData(atlas);
4e9e2555 Poul Sander 2025-10-05 10:15 4213
    ImFontAtlasBuildUpdateBasicTexData(atlas);
4e9e2555 Poul Sander 2025-10-05 10:15 4214
4e9e2555 Poul Sander 2025-10-05 10:15 4215
    // Register fonts
4e9e2555 Poul Sander 2025-10-05 10:15 4216
    ImFontAtlasBuildUpdatePointers(atlas);
1193b4be Poul Sander 2025-02-03 21:28 4217
4e9e2555 Poul Sander 2025-10-05 10:15 4218
    // Update UV coordinates etc. stored in bound ImDrawListSharedData instance
4e9e2555 Poul Sander 2025-10-05 10:15 4219
    ImFontAtlasUpdateDrawListsSharedData(atlas);
1193b4be Poul Sander 2025-02-03 21:28 4220
4e9e2555 Poul Sander 2025-10-05 10:15 4221
    //atlas->TexIsBuilt = true;
4e9e2555 Poul Sander 2025-10-05 10:15 4222
}
4e9e2555 Poul Sander 2025-10-05 10:15 4223
4e9e2555 Poul Sander 2025-10-05 10:15 4224
// Destroy builder and all cached glyphs. Do not destroy actual fonts.
4e9e2555 Poul Sander 2025-10-05 10:15 4225
void ImFontAtlasBuildDestroy(ImFontAtlas* atlas)
4e9e2555 Poul Sander 2025-10-05 10:15 4226
{
4e9e2555 Poul Sander 2025-10-05 10:15 4227
    for (ImFont* font : atlas->Fonts)
4e9e2555 Poul Sander 2025-10-05 10:15 4228
        ImFontAtlasFontDestroyOutput(atlas, font);
4e9e2555 Poul Sander 2025-10-05 10:15 4229
    if (atlas->Builder && atlas->FontLoader && atlas->FontLoader->LoaderShutdown)
4e9e2555 Poul Sander 2025-10-05 10:15 4230
    {
4e9e2555 Poul Sander 2025-10-05 10:15 4231
        atlas->FontLoader->LoaderShutdown(atlas);
4e9e2555 Poul Sander 2025-10-05 10:15 4232
        IM_ASSERT(atlas->FontLoaderData == NULL);
4e9e2555 Poul Sander 2025-10-05 10:15 4233
    }
4e9e2555 Poul Sander 2025-10-05 10:15 4234
    IM_DELETE(atlas->Builder);
4e9e2555 Poul Sander 2025-10-05 10:15 4235
    atlas->Builder = NULL;
4e9e2555 Poul Sander 2025-10-05 10:15 4236
}
4e9e2555 Poul Sander 2025-10-05 10:15 4237
4e9e2555 Poul Sander 2025-10-05 10:15 4238
void ImFontAtlasPackInit(ImFontAtlas * atlas)
4e9e2555 Poul Sander 2025-10-05 10:15 4239
{
4e9e2555 Poul Sander 2025-10-05 10:15 4240
    ImTextureData* tex = atlas->TexData;
4e9e2555 Poul Sander 2025-10-05 10:15 4241
    ImFontAtlasBuilder* builder = atlas->Builder;
4e9e2555 Poul Sander 2025-10-05 10:15 4242
4e9e2555 Poul Sander 2025-10-05 10:15 4243
    // In theory we could decide to reduce the number of nodes, e.g. halve them, and waste a little texture space, but it doesn't seem worth it.
4e9e2555 Poul Sander 2025-10-05 10:15 4244
    const int pack_node_count = tex->Width / 2;
4e9e2555 Poul Sander 2025-10-05 10:15 4245
    builder->PackNodes.resize(pack_node_count);
4e9e2555 Poul Sander 2025-10-05 10:15 4246
    IM_STATIC_ASSERT(sizeof(stbrp_context) <= sizeof(stbrp_context_opaque));
4e9e2555 Poul Sander 2025-10-05 10:15 4247
    stbrp_init_target((stbrp_context*)(void*)&builder->PackContext, tex->Width, tex->Height, builder->PackNodes.Data, builder->PackNodes.Size);
4e9e2555 Poul Sander 2025-10-05 10:15 4248
    builder->RectsPackedSurface = builder->RectsPackedCount = 0;
4e9e2555 Poul Sander 2025-10-05 10:15 4249
    builder->MaxRectSize = ImVec2i(0, 0);
4e9e2555 Poul Sander 2025-10-05 10:15 4250
    builder->MaxRectBounds = ImVec2i(0, 0);
4e9e2555 Poul Sander 2025-10-05 10:15 4251
}
4e9e2555 Poul Sander 2025-10-05 10:15 4252
4e9e2555 Poul Sander 2025-10-05 10:15 4253
// This is essentially a free-list pattern, it may be nice to wrap it into a dedicated type.
4e9e2555 Poul Sander 2025-10-05 10:15 4254
static ImFontAtlasRectId ImFontAtlasPackAllocRectEntry(ImFontAtlas* atlas, int rect_idx)
4e9e2555 Poul Sander 2025-10-05 10:15 4255
{
4e9e2555 Poul Sander 2025-10-05 10:15 4256
    ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder;
4e9e2555 Poul Sander 2025-10-05 10:15 4257
    int index_idx;
4e9e2555 Poul Sander 2025-10-05 10:15 4258
    ImFontAtlasRectEntry* index_entry;
4e9e2555 Poul Sander 2025-10-05 10:15 4259
    if (builder->RectsIndexFreeListStart < 0)
4e9e2555 Poul Sander 2025-10-05 10:15 4260
    {
4e9e2555 Poul Sander 2025-10-05 10:15 4261
        builder->RectsIndex.resize(builder->RectsIndex.Size + 1);
4e9e2555 Poul Sander 2025-10-05 10:15 4262
        index_idx = builder->RectsIndex.Size - 1;
4e9e2555 Poul Sander 2025-10-05 10:15 4263
        index_entry = &builder->RectsIndex[index_idx];
4e9e2555 Poul Sander 2025-10-05 10:15 4264
        memset(index_entry, 0, sizeof(*index_entry));
4e9e2555 Poul Sander 2025-10-05 10:15 4265
    }
4e9e2555 Poul Sander 2025-10-05 10:15 4266
    else
4e9e2555 Poul Sander 2025-10-05 10:15 4267
    {
4e9e2555 Poul Sander 2025-10-05 10:15 4268
        index_idx = builder->RectsIndexFreeListStart;
4e9e2555 Poul Sander 2025-10-05 10:15 4269
        index_entry = &builder->RectsIndex[index_idx];
4e9e2555 Poul Sander 2025-10-05 10:15 4270
        IM_ASSERT(index_entry->IsUsed == false && index_entry->Generation > 0); // Generation is incremented during DiscardRect
4e9e2555 Poul Sander 2025-10-05 10:15 4271
        builder->RectsIndexFreeListStart = index_entry->TargetIndex;
4e9e2555 Poul Sander 2025-10-05 10:15 4272
    }
4e9e2555 Poul Sander 2025-10-05 10:15 4273
    index_entry->TargetIndex = rect_idx;
4e9e2555 Poul Sander 2025-10-05 10:15 4274
    index_entry->IsUsed = 1;
4e9e2555 Poul Sander 2025-10-05 10:15 4275
    return ImFontAtlasRectId_Make(index_idx, index_entry->Generation);
4e9e2555 Poul Sander 2025-10-05 10:15 4276
}
1193b4be Poul Sander 2025-02-03 21:28 4277
4e9e2555 Poul Sander 2025-10-05 10:15 4278
// Overwrite existing entry
4e9e2555 Poul Sander 2025-10-05 10:15 4279
static ImFontAtlasRectId ImFontAtlasPackReuseRectEntry(ImFontAtlas* atlas, ImFontAtlasRectEntry* index_entry)
4e9e2555 Poul Sander 2025-10-05 10:15 4280
{
4e9e2555 Poul Sander 2025-10-05 10:15 4281
    IM_ASSERT(index_entry->IsUsed);
4e9e2555 Poul Sander 2025-10-05 10:15 4282
    index_entry->TargetIndex = atlas->Builder->Rects.Size - 1;
4e9e2555 Poul Sander 2025-10-05 10:15 4283
    int index_idx = atlas->Builder->RectsIndex.index_from_ptr(index_entry);
4e9e2555 Poul Sander 2025-10-05 10:15 4284
    return ImFontAtlasRectId_Make(index_idx, index_entry->Generation);
4e9e2555 Poul Sander 2025-10-05 10:15 4285
}
4e9e2555 Poul Sander 2025-10-05 10:15 4286
4e9e2555 Poul Sander 2025-10-05 10:15 4287
// This is expected to be called in batches and followed by a repack
4e9e2555 Poul Sander 2025-10-05 10:15 4288
void ImFontAtlasPackDiscardRect(ImFontAtlas* atlas, ImFontAtlasRectId id)
4e9e2555 Poul Sander 2025-10-05 10:15 4289
{
4e9e2555 Poul Sander 2025-10-05 10:15 4290
    IM_ASSERT(id != ImFontAtlasRectId_Invalid);
4e9e2555 Poul Sander 2025-10-05 10:15 4291
4e9e2555 Poul Sander 2025-10-05 10:15 4292
    ImTextureRect* rect = ImFontAtlasPackGetRect(atlas, id);
4e9e2555 Poul Sander 2025-10-05 10:15 4293
    if (rect == NULL)
4e9e2555 Poul Sander 2025-10-05 10:15 4294
        return;
4e9e2555 Poul Sander 2025-10-05 10:15 4295
4e9e2555 Poul Sander 2025-10-05 10:15 4296
    ImFontAtlasBuilder* builder = atlas->Builder;
4e9e2555 Poul Sander 2025-10-05 10:15 4297
    int index_idx = ImFontAtlasRectId_GetIndex(id);
4e9e2555 Poul Sander 2025-10-05 10:15 4298
    ImFontAtlasRectEntry* index_entry = &builder->RectsIndex[index_idx];
4e9e2555 Poul Sander 2025-10-05 10:15 4299
    IM_ASSERT(index_entry->IsUsed && index_entry->TargetIndex >= 0);
4e9e2555 Poul Sander 2025-10-05 10:15 4300
    index_entry->IsUsed = false;
4e9e2555 Poul Sander 2025-10-05 10:15 4301
    index_entry->TargetIndex = builder->RectsIndexFreeListStart;
4e9e2555 Poul Sander 2025-10-05 10:15 4302
    index_entry->Generation++;
4e9e2555 Poul Sander 2025-10-05 10:15 4303
    if (index_entry->Generation == 0)
4e9e2555 Poul Sander 2025-10-05 10:15 4304
        index_entry->Generation++; // Keep non-zero on overflow
4e9e2555 Poul Sander 2025-10-05 10:15 4305
4e9e2555 Poul Sander 2025-10-05 10:15 4306
    const int pack_padding = atlas->TexGlyphPadding;
4e9e2555 Poul Sander 2025-10-05 10:15 4307
    builder->RectsIndexFreeListStart = index_idx;
4e9e2555 Poul Sander 2025-10-05 10:15 4308
    builder->RectsDiscardedCount++;
4e9e2555 Poul Sander 2025-10-05 10:15 4309
    builder->RectsDiscardedSurface += (rect->w + pack_padding) * (rect->h + pack_padding);
4e9e2555 Poul Sander 2025-10-05 10:15 4310
    rect->w = rect->h = 0; // Clear rectangle so it won't be packed again
4e9e2555 Poul Sander 2025-10-05 10:15 4311
}
4e9e2555 Poul Sander 2025-10-05 10:15 4312
4e9e2555 Poul Sander 2025-10-05 10:15 4313
// Important: Calling this may recreate a new texture and therefore change atlas->TexData
4e9e2555 Poul Sander 2025-10-05 10:15 4314
// FIXME-NEWFONTS: Expose other glyph padding settings for custom alteration (e.g. drop shadows). See #7962
4e9e2555 Poul Sander 2025-10-05 10:15 4315
ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h, ImFontAtlasRectEntry* overwrite_entry)
4e9e2555 Poul Sander 2025-10-05 10:15 4316
{
4e9e2555 Poul Sander 2025-10-05 10:15 4317
    IM_ASSERT(w > 0 && w <= 0xFFFF);
4e9e2555 Poul Sander 2025-10-05 10:15 4318
    IM_ASSERT(h > 0 && h <= 0xFFFF);
4e9e2555 Poul Sander 2025-10-05 10:15 4319
4e9e2555 Poul Sander 2025-10-05 10:15 4320
    ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder;
4e9e2555 Poul Sander 2025-10-05 10:15 4321
    const int pack_padding = atlas->TexGlyphPadding;
4e9e2555 Poul Sander 2025-10-05 10:15 4322
    builder->MaxRectSize.x = ImMax(builder->MaxRectSize.x, w);
4e9e2555 Poul Sander 2025-10-05 10:15 4323
    builder->MaxRectSize.y = ImMax(builder->MaxRectSize.y, h);
4e9e2555 Poul Sander 2025-10-05 10:15 4324
4e9e2555 Poul Sander 2025-10-05 10:15 4325
    // Pack
4e9e2555 Poul Sander 2025-10-05 10:15 4326
    ImTextureRect r = { 0, 0, (unsigned short)w, (unsigned short)h };
4e9e2555 Poul Sander 2025-10-05 10:15 4327
    for (int attempts_remaining = 3; attempts_remaining >= 0; attempts_remaining--)
4e9e2555 Poul Sander 2025-10-05 10:15 4328
    {
4e9e2555 Poul Sander 2025-10-05 10:15 4329
        // Try packing
4e9e2555 Poul Sander 2025-10-05 10:15 4330
        stbrp_rect pack_r = {};
4e9e2555 Poul Sander 2025-10-05 10:15 4331
        pack_r.w = w + pack_padding;
4e9e2555 Poul Sander 2025-10-05 10:15 4332
        pack_r.h = h + pack_padding;
4e9e2555 Poul Sander 2025-10-05 10:15 4333
        stbrp_pack_rects((stbrp_context*)(void*)&builder->PackContext, &pack_r, 1);
4e9e2555 Poul Sander 2025-10-05 10:15 4334
        r.x = (unsigned short)pack_r.x;
4e9e2555 Poul Sander 2025-10-05 10:15 4335
        r.y = (unsigned short)pack_r.y;
4e9e2555 Poul Sander 2025-10-05 10:15 4336
        if (pack_r.was_packed)
4e9e2555 Poul Sander 2025-10-05 10:15 4337
            break;
4e9e2555 Poul Sander 2025-10-05 10:15 4338
4e9e2555 Poul Sander 2025-10-05 10:15 4339
        // If we ran out of attempts, return fallback
4e9e2555 Poul Sander 2025-10-05 10:15 4340
        if (attempts_remaining == 0 || builder->LockDisableResize)
1193b4be Poul Sander 2025-02-03 21:28 4341
        {
4e9e2555 Poul Sander 2025-10-05 10:15 4342
            IMGUI_DEBUG_LOG_FONT("[font] Failed packing %dx%d rectangle. Returning fallback.\n", w, h);
4e9e2555 Poul Sander 2025-10-05 10:15 4343
            return ImFontAtlasRectId_Invalid;
1193b4be Poul Sander 2025-02-03 21:28 4344
        }
4e9e2555 Poul Sander 2025-10-05 10:15 4345
4e9e2555 Poul Sander 2025-10-05 10:15 4346
        // Resize or repack atlas! (this should be a rare event)
4e9e2555 Poul Sander 2025-10-05 10:15 4347
        ImFontAtlasTextureMakeSpace(atlas);
1193b4be Poul Sander 2025-02-03 21:28 4348
    }
1193b4be Poul Sander 2025-02-03 21:28 4349
4e9e2555 Poul Sander 2025-10-05 10:15 4350
    builder->MaxRectBounds.x = ImMax(builder->MaxRectBounds.x, r.x + r.w + pack_padding);
4e9e2555 Poul Sander 2025-10-05 10:15 4351
    builder->MaxRectBounds.y = ImMax(builder->MaxRectBounds.y, r.y + r.h + pack_padding);
4e9e2555 Poul Sander 2025-10-05 10:15 4352
    builder->RectsPackedCount++;
4e9e2555 Poul Sander 2025-10-05 10:15 4353
    builder->RectsPackedSurface += (w + pack_padding) * (h + pack_padding);
1193b4be Poul Sander 2025-02-03 21:28 4354
4e9e2555 Poul Sander 2025-10-05 10:15 4355
    builder->Rects.push_back(r);
4e9e2555 Poul Sander 2025-10-05 10:15 4356
    if (overwrite_entry != NULL)
4e9e2555 Poul Sander 2025-10-05 10:15 4357
        return ImFontAtlasPackReuseRectEntry(atlas, overwrite_entry); // Write into an existing entry instead of adding one (used during repack)
4e9e2555 Poul Sander 2025-10-05 10:15 4358
    else
4e9e2555 Poul Sander 2025-10-05 10:15 4359
        return ImFontAtlasPackAllocRectEntry(atlas, builder->Rects.Size - 1);
4e9e2555 Poul Sander 2025-10-05 10:15 4360
}
4e9e2555 Poul Sander 2025-10-05 10:15 4361
4e9e2555 Poul Sander 2025-10-05 10:15 4362
// Generally for non-user facing functions: assert on invalid ID.
4e9e2555 Poul Sander 2025-10-05 10:15 4363
ImTextureRect* ImFontAtlasPackGetRect(ImFontAtlas* atlas, ImFontAtlasRectId id)
4e9e2555 Poul Sander 2025-10-05 10:15 4364
{
4e9e2555 Poul Sander 2025-10-05 10:15 4365
    IM_ASSERT(id != ImFontAtlasRectId_Invalid);
4e9e2555 Poul Sander 2025-10-05 10:15 4366
    int index_idx = ImFontAtlasRectId_GetIndex(id);
4e9e2555 Poul Sander 2025-10-05 10:15 4367
    ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder;
4e9e2555 Poul Sander 2025-10-05 10:15 4368
    ImFontAtlasRectEntry* index_entry = &builder->RectsIndex[index_idx];
4e9e2555 Poul Sander 2025-10-05 10:15 4369
    IM_ASSERT(index_entry->Generation == ImFontAtlasRectId_GetGeneration(id));
4e9e2555 Poul Sander 2025-10-05 10:15 4370
    IM_ASSERT(index_entry->IsUsed);
4e9e2555 Poul Sander 2025-10-05 10:15 4371
    return &builder->Rects[index_entry->TargetIndex];
4e9e2555 Poul Sander 2025-10-05 10:15 4372
}
4e9e2555 Poul Sander 2025-10-05 10:15 4373
4e9e2555 Poul Sander 2025-10-05 10:15 4374
// For user-facing functions: return NULL on invalid ID.
4e9e2555 Poul Sander 2025-10-05 10:15 4375
// Important: return pointer is valid until next call to AddRect(), e.g. FindGlyph(), CalcTextSize() can all potentially invalidate previous pointers.
4e9e2555 Poul Sander 2025-10-05 10:15 4376
ImTextureRect* ImFontAtlasPackGetRectSafe(ImFontAtlas* atlas, ImFontAtlasRectId id)
4e9e2555 Poul Sander 2025-10-05 10:15 4377
{
4e9e2555 Poul Sander 2025-10-05 10:15 4378
    if (id == ImFontAtlasRectId_Invalid)
4e9e2555 Poul Sander 2025-10-05 10:15 4379
        return NULL;
4e9e2555 Poul Sander 2025-10-05 10:15 4380
    int index_idx = ImFontAtlasRectId_GetIndex(id);
4e9e2555 Poul Sander 2025-10-05 10:15 4381
    if (atlas->Builder == NULL)
4e9e2555 Poul Sander 2025-10-05 10:15 4382
        ImFontAtlasBuildInit(atlas);
4e9e2555 Poul Sander 2025-10-05 10:15 4383
    ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder;
4e9e2555 Poul Sander 2025-10-05 10:15 4384
    IM_MSVC_WARNING_SUPPRESS(28182); // Static Analysis false positive "warning C28182: Dereferencing NULL pointer 'builder'"
4e9e2555 Poul Sander 2025-10-05 10:15 4385
    if (index_idx >= builder->RectsIndex.Size)
4e9e2555 Poul Sander 2025-10-05 10:15 4386
        return NULL;
4e9e2555 Poul Sander 2025-10-05 10:15 4387
    ImFontAtlasRectEntry* index_entry = &builder->RectsIndex[index_idx];
4e9e2555 Poul Sander 2025-10-05 10:15 4388
    if (index_entry->Generation != ImFontAtlasRectId_GetGeneration(id) || !index_entry->IsUsed)
4e9e2555 Poul Sander 2025-10-05 10:15 4389
        return NULL;
4e9e2555 Poul Sander 2025-10-05 10:15 4390
    return &builder->Rects[index_entry->TargetIndex];
4e9e2555 Poul Sander 2025-10-05 10:15 4391
}
4e9e2555 Poul Sander 2025-10-05 10:15 4392
4e9e2555 Poul Sander 2025-10-05 10:15 4393
// Important! This assume by ImFontConfig::GlyphExcludeRanges[] is a SMALL ARRAY (e.g. <10 entries)
4e9e2555 Poul Sander 2025-10-05 10:15 4394
// Use "Input Glyphs Overlap Detection Tool" to display a list of glyphs provided by multiple sources in order to set this array up.
4e9e2555 Poul Sander 2025-10-05 10:15 4395
static bool ImFontAtlasBuildAcceptCodepointForSource(ImFontConfig* src, ImWchar codepoint)
4e9e2555 Poul Sander 2025-10-05 10:15 4396
{
4e9e2555 Poul Sander 2025-10-05 10:15 4397
    if (const ImWchar* exclude_list = src->GlyphExcludeRanges)
4e9e2555 Poul Sander 2025-10-05 10:15 4398
        for (; exclude_list[0] != 0; exclude_list += 2)
4e9e2555 Poul Sander 2025-10-05 10:15 4399
            if (codepoint >= exclude_list[0] && codepoint <= exclude_list[1])
4e9e2555 Poul Sander 2025-10-05 10:15 4400
                return false;
1193b4be Poul Sander 2025-02-03 21:28 4401
    return true;
1193b4be Poul Sander 2025-02-03 21:28 4402
}
1193b4be Poul Sander 2025-02-03 21:28 4403
4e9e2555 Poul Sander 2025-10-05 10:15 4404
static void ImFontBaked_BuildGrowIndex(ImFontBaked* baked, int new_size)
1193b4be Poul Sander 2025-02-03 21:28 4405
{
4e9e2555 Poul Sander 2025-10-05 10:15 4406
    IM_ASSERT(baked->IndexAdvanceX.Size == baked->IndexLookup.Size);
4e9e2555 Poul Sander 2025-10-05 10:15 4407
    if (new_size <= baked->IndexLookup.Size)
4e9e2555 Poul Sander 2025-10-05 10:15 4408
        return;
4e9e2555 Poul Sander 2025-10-05 10:15 4409
    baked->IndexAdvanceX.resize(new_size, -1.0f);
4e9e2555 Poul Sander 2025-10-05 10:15 4410
    baked->IndexLookup.resize(new_size, IM_FONTGLYPH_INDEX_UNUSED);
1193b4be Poul Sander 2025-02-03 21:28 4411
}
1193b4be Poul Sander 2025-02-03 21:28 4412
4e9e2555 Poul Sander 2025-10-05 10:15 4413
static void ImFontAtlas_FontHookRemapCodepoint(ImFontAtlas* atlas, ImFont* font, ImWchar* c)
4e9e2555 Poul Sander 2025-10-05 10:15 4414
{
4e9e2555 Poul Sander 2025-10-05 10:15 4415
    IM_UNUSED(atlas);
4e9e2555 Poul Sander 2025-10-05 10:15 4416
    if (font->RemapPairs.Data.Size != 0)
4e9e2555 Poul Sander 2025-10-05 10:15 4417
        *c = (ImWchar)font->RemapPairs.GetInt((ImGuiID)*c, (int)*c);
4e9e2555 Poul Sander 2025-10-05 10:15 4418
}
1193b4be Poul Sander 2025-02-03 21:28 4419
4e9e2555 Poul Sander 2025-10-05 10:15 4420
static ImFontGlyph* ImFontBaked_BuildLoadGlyph(ImFontBaked* baked, ImWchar codepoint, float* only_load_advance_x)
1193b4be Poul Sander 2025-02-03 21:28 4421
{
4e9e2555 Poul Sander 2025-10-05 10:15 4422
    ImFont* font = baked->ContainerFont;
4e9e2555 Poul Sander 2025-10-05 10:15 4423
    ImFontAtlas* atlas = font->ContainerAtlas;
4e9e2555 Poul Sander 2025-10-05 10:15 4424
    if (atlas->Locked || (font->Flags & ImFontFlags_NoLoadGlyphs))
1193b4be Poul Sander 2025-02-03 21:28 4425
    {
4e9e2555 Poul Sander 2025-10-05 10:15 4426
        // Lazily load fallback glyph
4e9e2555 Poul Sander 2025-10-05 10:15 4427
        if (baked->FallbackGlyphIndex == -1 && baked->LoadNoFallback == 0)
4e9e2555 Poul Sander 2025-10-05 10:15 4428
            ImFontAtlasBuildSetupFontBakedFallback(baked);
4e9e2555 Poul Sander 2025-10-05 10:15 4429
        return NULL;
4e9e2555 Poul Sander 2025-10-05 10:15 4430
    }
4e9e2555 Poul Sander 2025-10-05 10:15 4431
4e9e2555 Poul Sander 2025-10-05 10:15 4432
    // User remapping hooks
4e9e2555 Poul Sander 2025-10-05 10:15 4433
    ImWchar src_codepoint = codepoint;
4e9e2555 Poul Sander 2025-10-05 10:15 4434
    ImFontAtlas_FontHookRemapCodepoint(atlas, font, &codepoint);
4e9e2555 Poul Sander 2025-10-05 10:15 4435
4e9e2555 Poul Sander 2025-10-05 10:15 4436
    //char utf8_buf[5];
4e9e2555 Poul Sander 2025-10-05 10:15 4437
    //IMGUI_DEBUG_LOG("[font] BuildLoadGlyph U+%04X (%s)\n", (unsigned int)codepoint, ImTextCharToUtf8(utf8_buf, (unsigned int)codepoint));
4e9e2555 Poul Sander 2025-10-05 10:15 4438
4e9e2555 Poul Sander 2025-10-05 10:15 4439
    // Special hook
4e9e2555 Poul Sander 2025-10-05 10:15 4440
    // FIXME-NEWATLAS: it would be nicer if this used a more standardized way of hooking
4e9e2555 Poul Sander 2025-10-05 10:15 4441
    if (codepoint == font->EllipsisChar && font->EllipsisAutoBake)
4e9e2555 Poul Sander 2025-10-05 10:15 4442
        if (ImFontGlyph* glyph = ImFontAtlasBuildSetupFontBakedEllipsis(atlas, baked))
4e9e2555 Poul Sander 2025-10-05 10:15 4443
            return glyph;
4e9e2555 Poul Sander 2025-10-05 10:15 4444
4e9e2555 Poul Sander 2025-10-05 10:15 4445
    // Call backend
4e9e2555 Poul Sander 2025-10-05 10:15 4446
    char* loader_user_data_p = (char*)baked->FontLoaderDatas;
4e9e2555 Poul Sander 2025-10-05 10:15 4447
    int src_n = 0;
4e9e2555 Poul Sander 2025-10-05 10:15 4448
    for (ImFontConfig* src : font->Sources)
4e9e2555 Poul Sander 2025-10-05 10:15 4449
    {
4e9e2555 Poul Sander 2025-10-05 10:15 4450
        const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader;
4e9e2555 Poul Sander 2025-10-05 10:15 4451
        if (!src->GlyphExcludeRanges || ImFontAtlasBuildAcceptCodepointForSource(src, codepoint))
1193b4be Poul Sander 2025-02-03 21:28 4452
        {
4e9e2555 Poul Sander 2025-10-05 10:15 4453
            if (only_load_advance_x == NULL)
4e9e2555 Poul Sander 2025-10-05 10:15 4454
            {
4e9e2555 Poul Sander 2025-10-05 10:15 4455
                ImFontGlyph glyph_buf;
4e9e2555 Poul Sander 2025-10-05 10:15 4456
                if (loader->FontBakedLoadGlyph(atlas, src, baked, loader_user_data_p, codepoint, &glyph_buf, NULL))
4e9e2555 Poul Sander 2025-10-05 10:15 4457
                {
4e9e2555 Poul Sander 2025-10-05 10:15 4458
                    // FIXME: Add hooks for e.g. #7962
4e9e2555 Poul Sander 2025-10-05 10:15 4459
                    glyph_buf.Codepoint = src_codepoint;
4e9e2555 Poul Sander 2025-10-05 10:15 4460
                    glyph_buf.SourceIdx = src_n;
4e9e2555 Poul Sander 2025-10-05 10:15 4461
                    return ImFontAtlasBakedAddFontGlyph(atlas, baked, src, &glyph_buf);
4e9e2555 Poul Sander 2025-10-05 10:15 4462
                }
4e9e2555 Poul Sander 2025-10-05 10:15 4463
            }
4e9e2555 Poul Sander 2025-10-05 10:15 4464
            else
4e9e2555 Poul Sander 2025-10-05 10:15 4465
            {
4e9e2555 Poul Sander 2025-10-05 10:15 4466
                // Special mode but only loading glyphs metrics. Will rasterize and pack later.
4e9e2555 Poul Sander 2025-10-05 10:15 4467
                if (loader->FontBakedLoadGlyph(atlas, src, baked, loader_user_data_p, codepoint, NULL, only_load_advance_x))
4e9e2555 Poul Sander 2025-10-05 10:15 4468
                {
4e9e2555 Poul Sander 2025-10-05 10:15 4469
                    ImFontAtlasBakedAddFontGlyphAdvancedX(atlas, baked, src, codepoint, *only_load_advance_x);
4e9e2555 Poul Sander 2025-10-05 10:15 4470
                    return NULL;
4e9e2555 Poul Sander 2025-10-05 10:15 4471
                }
4e9e2555 Poul Sander 2025-10-05 10:15 4472
            }
1193b4be Poul Sander 2025-02-03 21:28 4473
        }
4e9e2555 Poul Sander 2025-10-05 10:15 4474
        loader_user_data_p += loader->FontBakedSrcLoaderDataSize;
4e9e2555 Poul Sander 2025-10-05 10:15 4475
        src_n++;
4e9e2555 Poul Sander 2025-10-05 10:15 4476
    }
4e9e2555 Poul Sander 2025-10-05 10:15 4477
4e9e2555 Poul Sander 2025-10-05 10:15 4478
    // Lazily load fallback glyph
4e9e2555 Poul Sander 2025-10-05 10:15 4479
    if (baked->LoadNoFallback)
4e9e2555 Poul Sander 2025-10-05 10:15 4480
        return NULL;
4e9e2555 Poul Sander 2025-10-05 10:15 4481
    if (baked->FallbackGlyphIndex == -1)
4e9e2555 Poul Sander 2025-10-05 10:15 4482
        ImFontAtlasBuildSetupFontBakedFallback(baked);
4e9e2555 Poul Sander 2025-10-05 10:15 4483
4e9e2555 Poul Sander 2025-10-05 10:15 4484
    // Mark index as not found, so we don't attempt the search twice
4e9e2555 Poul Sander 2025-10-05 10:15 4485
    ImFontBaked_BuildGrowIndex(baked, codepoint + 1);
4e9e2555 Poul Sander 2025-10-05 10:15 4486
    baked->IndexAdvanceX[codepoint] = baked->FallbackAdvanceX;
4e9e2555 Poul Sander 2025-10-05 10:15 4487
    baked->IndexLookup[codepoint] = IM_FONTGLYPH_INDEX_NOT_FOUND;
4e9e2555 Poul Sander 2025-10-05 10:15 4488
    return NULL;
4e9e2555 Poul Sander 2025-10-05 10:15 4489
}
4e9e2555 Poul Sander 2025-10-05 10:15 4490
4e9e2555 Poul Sander 2025-10-05 10:15 4491
static float ImFontBaked_BuildLoadGlyphAdvanceX(ImFontBaked* baked, ImWchar codepoint)
4e9e2555 Poul Sander 2025-10-05 10:15 4492
{
4e9e2555 Poul Sander 2025-10-05 10:15 4493
    if (baked->Size >= IMGUI_FONT_SIZE_THRESHOLD_FOR_LOADADVANCEXONLYMODE || baked->LoadNoRenderOnLayout)
4e9e2555 Poul Sander 2025-10-05 10:15 4494
    {
4e9e2555 Poul Sander 2025-10-05 10:15 4495
        // First load AdvanceX value used by CalcTextSize() API then load the rest when loaded by drawing API.
4e9e2555 Poul Sander 2025-10-05 10:15 4496
        float only_advance_x = 0.0f;
4e9e2555 Poul Sander 2025-10-05 10:15 4497
        ImFontGlyph* glyph = ImFontBaked_BuildLoadGlyph(baked, (ImWchar)codepoint, &only_advance_x);
4e9e2555 Poul Sander 2025-10-05 10:15 4498
        return glyph ? glyph->AdvanceX : only_advance_x;
4e9e2555 Poul Sander 2025-10-05 10:15 4499
    }
4e9e2555 Poul Sander 2025-10-05 10:15 4500
    else
4e9e2555 Poul Sander 2025-10-05 10:15 4501
    {
4e9e2555 Poul Sander 2025-10-05 10:15 4502
        ImFontGlyph* glyph = ImFontBaked_BuildLoadGlyph(baked, (ImWchar)codepoint, NULL);
4e9e2555 Poul Sander 2025-10-05 10:15 4503
        return glyph ? glyph->AdvanceX : baked->FallbackAdvanceX;
1193b4be Poul Sander 2025-02-03 21:28 4504
    }
1193b4be Poul Sander 2025-02-03 21:28 4505
}
1193b4be Poul Sander 2025-02-03 21:28 4506
4e9e2555 Poul Sander 2025-10-05 10:15 4507
// The point of this indirection is to not be inlined in debug mode in order to not bloat inner loop.b
4e9e2555 Poul Sander 2025-10-05 10:15 4508
IM_MSVC_RUNTIME_CHECKS_OFF
4e9e2555 Poul Sander 2025-10-05 10:15 4509
static float BuildLoadGlyphGetAdvanceOrFallback(ImFontBaked* baked, unsigned int codepoint)
1193b4be Poul Sander 2025-02-03 21:28 4510
{
4e9e2555 Poul Sander 2025-10-05 10:15 4511
    return ImFontBaked_BuildLoadGlyphAdvanceX(baked, (ImWchar)codepoint);
1193b4be Poul Sander 2025-02-03 21:28 4512
}
4e9e2555 Poul Sander 2025-10-05 10:15 4513
IM_MSVC_RUNTIME_CHECKS_RESTORE
1193b4be Poul Sander 2025-02-03 21:28 4514
4e9e2555 Poul Sander 2025-10-05 10:15 4515
#ifndef IMGUI_DISABLE_DEBUG_TOOLS
4e9e2555 Poul Sander 2025-10-05 10:15 4516
void ImFontAtlasDebugLogTextureRequests(ImFontAtlas* atlas)
1193b4be Poul Sander 2025-02-03 21:28 4517
{
4e9e2555 Poul Sander 2025-10-05 10:15 4518
    // [DEBUG] Log texture update requests
4e9e2555 Poul Sander 2025-10-05 10:15 4519
    ImGuiContext& g = *GImGui;
4e9e2555 Poul Sander 2025-10-05 10:15 4520
    IM_UNUSED(g);
4e9e2555 Poul Sander 2025-10-05 10:15 4521
    for (ImTextureData* tex : atlas->TexList)
1193b4be Poul Sander 2025-02-03 21:28 4522
    {
4e9e2555 Poul Sander 2025-10-05 10:15 4523
        if ((g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) == 0)
4e9e2555 Poul Sander 2025-10-05 10:15 4524
            IM_ASSERT(tex->Updates.Size == 0);
4e9e2555 Poul Sander 2025-10-05 10:15 4525
        if (tex->Status == ImTextureStatus_WantCreate)
4e9e2555 Poul Sander 2025-10-05 10:15 4526
            IMGUI_DEBUG_LOG_FONT("[font] Texture #%03d: create %dx%d\n", tex->UniqueID, tex->Width, tex->Height);
4e9e2555 Poul Sander 2025-10-05 10:15 4527
        else if (tex->Status == ImTextureStatus_WantDestroy)
4e9e2555 Poul Sander 2025-10-05 10:15 4528
            IMGUI_DEBUG_LOG_FONT("[font] Texture #%03d: destroy %dx%d, texid=0x%" IM_PRIX64 ", backend_data=%p\n", tex->UniqueID, tex->Width, tex->Height, IM_TEXTUREID_TO_U64(tex->TexID), tex->BackendUserData);
4e9e2555 Poul Sander 2025-10-05 10:15 4529
        else if (tex->Status == ImTextureStatus_WantUpdates)
1193b4be Poul Sander 2025-02-03 21:28 4530
        {
4e9e2555 Poul Sander 2025-10-05 10:15 4531
            IMGUI_DEBUG_LOG_FONT("[font] Texture #%03d: update %d regions, texid=0x%" IM_PRIX64 ", backend_data=0x%" IM_PRIX64 "\n", tex->UniqueID, tex->Updates.Size, IM_TEXTUREID_TO_U64(tex->TexID), (ImU64)(intptr_t)tex->BackendUserData);
4e9e2555 Poul Sander 2025-10-05 10:15 4532
            for (const ImTextureRect& r : tex->Updates)
4e9e2555 Poul Sander 2025-10-05 10:15 4533
            {
4e9e2555 Poul Sander 2025-10-05 10:15 4534
                IM_UNUSED(r);
4e9e2555 Poul Sander 2025-10-05 10:15 4535
                IM_ASSERT(r.x >= 0 && r.y >= 0);
4e9e2555 Poul Sander 2025-10-05 10:15 4536
                IM_ASSERT(r.x + r.w <= tex->Width && r.y + r.h <= tex->Height); // In theory should subtract PackPadding but it's currently part of atlas and mid-frame change would wreck assert.
4e9e2555 Poul Sander 2025-10-05 10:15 4537
                //IMGUI_DEBUG_LOG_FONT("[font] Texture #%03d: update (% 4d..%-4d)->(% 4d..%-4d), texid=0x%" IM_PRIX64 ", backend_data=0x%" IM_PRIX64 "\n", tex->UniqueID, r.x, r.y, r.x + r.w, r.y + r.h, IM_TEXTUREID_TO_U64(tex->TexID), (ImU64)(intptr_t)tex->BackendUserData);
4e9e2555 Poul Sander 2025-10-05 10:15 4538
            }
1193b4be Poul Sander 2025-02-03 21:28 4539
        }
4e9e2555 Poul Sander 2025-10-05 10:15 4540
    }
1193b4be Poul Sander 2025-02-03 21:28 4541
}
4e9e2555 Poul Sander 2025-10-05 10:15 4542
#endif
1193b4be Poul Sander 2025-02-03 21:28 4543
4e9e2555 Poul Sander 2025-10-05 10:15 4544
//-------------------------------------------------------------------------
4e9e2555 Poul Sander 2025-10-05 10:15 4545
// [SECTION] ImFontAtlas: backend for stb_truetype
4e9e2555 Poul Sander 2025-10-05 10:15 4546
//-------------------------------------------------------------------------
4e9e2555 Poul Sander 2025-10-05 10:15 4547
// (imstb_truetype.h in included near the top of this file, when IMGUI_ENABLE_STB_TRUETYPE is set)
4e9e2555 Poul Sander 2025-10-05 10:15 4548
//-------------------------------------------------------------------------
4e9e2555 Poul Sander 2025-10-05 10:15 4549
4e9e2555 Poul Sander 2025-10-05 10:15 4550
#ifdef IMGUI_ENABLE_STB_TRUETYPE
1193b4be Poul Sander 2025-02-03 21:28 4551
4e9e2555 Poul Sander 2025-10-05 10:15 4552
// One for each ConfigData
4e9e2555 Poul Sander 2025-10-05 10:15 4553
struct ImGui_ImplStbTrueType_FontSrcData
1193b4be Poul Sander 2025-02-03 21:28 4554
{
4e9e2555 Poul Sander 2025-10-05 10:15 4555
    stbtt_fontinfo  FontInfo;
4e9e2555 Poul Sander 2025-10-05 10:15 4556
    float           ScaleFactor;
4e9e2555 Poul Sander 2025-10-05 10:15 4557
};
1193b4be Poul Sander 2025-02-03 21:28 4558
4e9e2555 Poul Sander 2025-10-05 10:15 4559
static bool ImGui_ImplStbTrueType_FontSrcInit(ImFontAtlas* atlas, ImFontConfig* src)
1193b4be Poul Sander 2025-02-03 21:28 4560
{
4e9e2555 Poul Sander 2025-10-05 10:15 4561
    IM_UNUSED(atlas);
4e9e2555 Poul Sander 2025-10-05 10:15 4562
4e9e2555 Poul Sander 2025-10-05 10:15 4563
    ImGui_ImplStbTrueType_FontSrcData* bd_font_data = IM_NEW(ImGui_ImplStbTrueType_FontSrcData);
4e9e2555 Poul Sander 2025-10-05 10:15 4564
    IM_ASSERT(src->FontLoaderData == NULL);
1193b4be Poul Sander 2025-02-03 21:28 4565
4e9e2555 Poul Sander 2025-10-05 10:15 4566
    // Initialize helper structure for font loading and verify that the TTF/OTF data is correct
4e9e2555 Poul Sander 2025-10-05 10:15 4567
    const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)src->FontData, src->FontNo);
4e9e2555 Poul Sander 2025-10-05 10:15 4568
    if (font_offset < 0)
1193b4be Poul Sander 2025-02-03 21:28 4569
    {
4e9e2555 Poul Sander 2025-10-05 10:15 4570
        IM_DELETE(bd_font_data);
4e9e2555 Poul Sander 2025-10-05 10:15 4571
        IM_ASSERT_USER_ERROR(0, "stbtt_GetFontOffsetForIndex(): FontData is incorrect, or FontNo cannot be found.");
4e9e2555 Poul Sander 2025-10-05 10:15 4572
        return false;
1193b4be Poul Sander 2025-02-03 21:28 4573
    }
4e9e2555 Poul Sander 2025-10-05 10:15 4574
    if (!stbtt_InitFont(&bd_font_data->FontInfo, (unsigned char*)src->FontData, font_offset))
1193b4be Poul Sander 2025-02-03 21:28 4575
    {
4e9e2555 Poul Sander 2025-10-05 10:15 4576
        IM_DELETE(bd_font_data);
4e9e2555 Poul Sander 2025-10-05 10:15 4577
        IM_ASSERT_USER_ERROR(0, "stbtt_InitFont(): failed to parse FontData. It is correct and complete? Check FontDataSize.");
4e9e2555 Poul Sander 2025-10-05 10:15 4578
        return false;
1193b4be Poul Sander 2025-02-03 21:28 4579
    }
4e9e2555 Poul Sander 2025-10-05 10:15 4580
    src->FontLoaderData = bd_font_data;
1193b4be Poul Sander 2025-02-03 21:28 4581
4e9e2555 Poul Sander 2025-10-05 10:15 4582
    const float ref_size = src->DstFont->Sources[0]->SizePixels;
4e9e2555 Poul Sander 2025-10-05 10:15 4583
    if (src->MergeMode && src->SizePixels == 0.0f)
4e9e2555 Poul Sander 2025-10-05 10:15 4584
        src->SizePixels = ref_size;
1193b4be Poul Sander 2025-02-03 21:28 4585
4e9e2555 Poul Sander 2025-10-05 10:15 4586
    if (src->SizePixels >= 0.0f)
4e9e2555 Poul Sander 2025-10-05 10:15 4587
        bd_font_data->ScaleFactor = stbtt_ScaleForPixelHeight(&bd_font_data->FontInfo, 1.0f);
4e9e2555 Poul Sander 2025-10-05 10:15 4588
    else
4e9e2555 Poul Sander 2025-10-05 10:15 4589
        bd_font_data->ScaleFactor = stbtt_ScaleForMappingEmToPixels(&bd_font_data->FontInfo, 1.0f);
4e9e2555 Poul Sander 2025-10-05 10:15 4590
    if (src->MergeMode && src->SizePixels != 0.0f && ref_size != 0.0f)
4e9e2555 Poul Sander 2025-10-05 10:15 4591
        bd_font_data->ScaleFactor *= src->SizePixels / ref_size; // FIXME-NEWATLAS: Should tidy up that a bit
1193b4be Poul Sander 2025-02-03 21:28 4592
4e9e2555 Poul Sander 2025-10-05 10:15 4593
    return true;
4e9e2555 Poul Sander 2025-10-05 10:15 4594
}
1193b4be Poul Sander 2025-02-03 21:28 4595
4e9e2555 Poul Sander 2025-10-05 10:15 4596
static void ImGui_ImplStbTrueType_FontSrcDestroy(ImFontAtlas* atlas, ImFontConfig* src)
4e9e2555 Poul Sander 2025-10-05 10:15 4597
{
4e9e2555 Poul Sander 2025-10-05 10:15 4598
    IM_UNUSED(atlas);
4e9e2555 Poul Sander 2025-10-05 10:15 4599
    ImGui_ImplStbTrueType_FontSrcData* bd_font_data = (ImGui_ImplStbTrueType_FontSrcData*)src->FontLoaderData;
4e9e2555 Poul Sander 2025-10-05 10:15 4600
    IM_DELETE(bd_font_data);
4e9e2555 Poul Sander 2025-10-05 10:15 4601
    src->FontLoaderData = NULL;
4e9e2555 Poul Sander 2025-10-05 10:15 4602
}
1193b4be Poul Sander 2025-02-03 21:28 4603
4e9e2555 Poul Sander 2025-10-05 10:15 4604
static bool ImGui_ImplStbTrueType_FontSrcContainsGlyph(ImFontAtlas* atlas, ImFontConfig* src, ImWchar codepoint)
4e9e2555 Poul Sander 2025-10-05 10:15 4605
{
4e9e2555 Poul Sander 2025-10-05 10:15 4606
    IM_UNUSED(atlas);
1193b4be Poul Sander 2025-02-03 21:28 4607
4e9e2555 Poul Sander 2025-10-05 10:15 4608
    ImGui_ImplStbTrueType_FontSrcData* bd_font_data = (ImGui_ImplStbTrueType_FontSrcData*)src->FontLoaderData;
4e9e2555 Poul Sander 2025-10-05 10:15 4609
    IM_ASSERT(bd_font_data != NULL);
1193b4be Poul Sander 2025-02-03 21:28 4610
4e9e2555 Poul Sander 2025-10-05 10:15 4611
    int glyph_index = stbtt_FindGlyphIndex(&bd_font_data->FontInfo, (int)codepoint);
4e9e2555 Poul Sander 2025-10-05 10:15 4612
    return glyph_index != 0;
1193b4be Poul Sander 2025-02-03 21:28 4613
}
1193b4be Poul Sander 2025-02-03 21:28 4614
4e9e2555 Poul Sander 2025-10-05 10:15 4615
static bool ImGui_ImplStbTrueType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void*)
1193b4be Poul Sander 2025-02-03 21:28 4616
{
4e9e2555 Poul Sander 2025-10-05 10:15 4617
    IM_UNUSED(atlas);
1193b4be Poul Sander 2025-02-03 21:28 4618
4e9e2555 Poul Sander 2025-10-05 10:15 4619
    ImGui_ImplStbTrueType_FontSrcData* bd_font_data = (ImGui_ImplStbTrueType_FontSrcData*)src->FontLoaderData;
4e9e2555 Poul Sander 2025-10-05 10:15 4620
    if (src->MergeMode == false)
1193b4be Poul Sander 2025-02-03 21:28 4621
    {
4e9e2555 Poul Sander 2025-10-05 10:15 4622
        // FIXME-NEWFONTS: reevaluate how to use sizing metrics
4e9e2555 Poul Sander 2025-10-05 10:15 4623
        // FIXME-NEWFONTS: make use of line gap value
4e9e2555 Poul Sander 2025-10-05 10:15 4624
        float scale_for_layout = bd_font_data->ScaleFactor * baked->Size;
4e9e2555 Poul Sander 2025-10-05 10:15 4625
        int unscaled_ascent, unscaled_descent, unscaled_line_gap;
4e9e2555 Poul Sander 2025-10-05 10:15 4626
        stbtt_GetFontVMetrics(&bd_font_data->FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap);
4e9e2555 Poul Sander 2025-10-05 10:15 4627
        baked->Ascent = ImCeil(unscaled_ascent * scale_for_layout);
4e9e2555 Poul Sander 2025-10-05 10:15 4628
        baked->Descent = ImFloor(unscaled_descent * scale_for_layout);
1193b4be Poul Sander 2025-02-03 21:28 4629
    }
4e9e2555 Poul Sander 2025-10-05 10:15 4630
    return true;
1193b4be Poul Sander 2025-02-03 21:28 4631
}
1193b4be Poul Sander 2025-02-03 21:28 4632
4e9e2555 Poul Sander 2025-10-05 10:15 4633
static bool ImGui_ImplStbTrueType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void*, ImWchar codepoint, ImFontGlyph* out_glyph, float* out_advance_x)
1193b4be Poul Sander 2025-02-03 21:28 4634
{
4e9e2555 Poul Sander 2025-10-05 10:15 4635
    // Search for first font which has the glyph
4e9e2555 Poul Sander 2025-10-05 10:15 4636
    ImGui_ImplStbTrueType_FontSrcData* bd_font_data = (ImGui_ImplStbTrueType_FontSrcData*)src->FontLoaderData;
4e9e2555 Poul Sander 2025-10-05 10:15 4637
    IM_ASSERT(bd_font_data);
4e9e2555 Poul Sander 2025-10-05 10:15 4638
    int glyph_index = stbtt_FindGlyphIndex(&bd_font_data->FontInfo, (int)codepoint);
4e9e2555 Poul Sander 2025-10-05 10:15 4639
    if (glyph_index == 0)
4e9e2555 Poul Sander 2025-10-05 10:15 4640
        return false;
1193b4be Poul Sander 2025-02-03 21:28 4641
4e9e2555 Poul Sander 2025-10-05 10:15 4642
    // Fonts unit to pixels
4e9e2555 Poul Sander 2025-10-05 10:15 4643
    int oversample_h, oversample_v;
4e9e2555 Poul Sander 2025-10-05 10:15 4644
    ImFontAtlasBuildGetOversampleFactors(src, baked, &oversample_h, &oversample_v);
4e9e2555 Poul Sander 2025-10-05 10:15 4645
    const float scale_for_layout = bd_font_data->ScaleFactor * baked->Size;
4e9e2555 Poul Sander 2025-10-05 10:15 4646
    const float rasterizer_density = src->RasterizerDensity * baked->RasterizerDensity;
4e9e2555 Poul Sander 2025-10-05 10:15 4647
    const float scale_for_raster_x = bd_font_data->ScaleFactor * baked->Size * rasterizer_density * oversample_h;
4e9e2555 Poul Sander 2025-10-05 10:15 4648
    const float scale_for_raster_y = bd_font_data->ScaleFactor * baked->Size * rasterizer_density * oversample_v;
4e9e2555 Poul Sander 2025-10-05 10:15 4649
4e9e2555 Poul Sander 2025-10-05 10:15 4650
    // Obtain size and advance
4e9e2555 Poul Sander 2025-10-05 10:15 4651
    int x0, y0, x1, y1;
4e9e2555 Poul Sander 2025-10-05 10:15 4652
    int advance, lsb;
4e9e2555 Poul Sander 2025-10-05 10:15 4653
    stbtt_GetGlyphBitmapBoxSubpixel(&bd_font_data->FontInfo, glyph_index, scale_for_raster_x, scale_for_raster_y, 0, 0, &x0, &y0, &x1, &y1);
4e9e2555 Poul Sander 2025-10-05 10:15 4654
    stbtt_GetGlyphHMetrics(&bd_font_data->FontInfo, glyph_index, &advance, &lsb);
4e9e2555 Poul Sander 2025-10-05 10:15 4655
4e9e2555 Poul Sander 2025-10-05 10:15 4656
    // Load metrics only mode
4e9e2555 Poul Sander 2025-10-05 10:15 4657
    if (out_advance_x != NULL)
1193b4be Poul Sander 2025-02-03 21:28 4658
    {
4e9e2555 Poul Sander 2025-10-05 10:15 4659
        IM_ASSERT(out_glyph == NULL);
4e9e2555 Poul Sander 2025-10-05 10:15 4660
        *out_advance_x = advance * scale_for_layout;
4e9e2555 Poul Sander 2025-10-05 10:15 4661
        return true;
4e9e2555 Poul Sander 2025-10-05 10:15 4662
    }
4e9e2555 Poul Sander 2025-10-05 10:15 4663
4e9e2555 Poul Sander 2025-10-05 10:15 4664
    // Prepare glyph
4e9e2555 Poul Sander 2025-10-05 10:15 4665
    out_glyph->Codepoint = codepoint;
4e9e2555 Poul Sander 2025-10-05 10:15 4666
    out_glyph->AdvanceX = advance * scale_for_layout;
1193b4be Poul Sander 2025-02-03 21:28 4667
4e9e2555 Poul Sander 2025-10-05 10:15 4668
    // Pack and retrieve position inside texture atlas
4e9e2555 Poul Sander 2025-10-05 10:15 4669
    // (generally based on stbtt_PackFontRangesRenderIntoRects)
4e9e2555 Poul Sander 2025-10-05 10:15 4670
    const bool is_visible = (x0 != x1 && y0 != y1);
4e9e2555 Poul Sander 2025-10-05 10:15 4671
    if (is_visible)
4e9e2555 Poul Sander 2025-10-05 10:15 4672
    {
4e9e2555 Poul Sander 2025-10-05 10:15 4673
        const int w = (x1 - x0 + oversample_h - 1);
4e9e2555 Poul Sander 2025-10-05 10:15 4674
        const int h = (y1 - y0 + oversample_v - 1);
4e9e2555 Poul Sander 2025-10-05 10:15 4675
        ImFontAtlasRectId pack_id = ImFontAtlasPackAddRect(atlas, w, h);
4e9e2555 Poul Sander 2025-10-05 10:15 4676
        if (pack_id == ImFontAtlasRectId_Invalid)
4e9e2555 Poul Sander 2025-10-05 10:15 4677
        {
4e9e2555 Poul Sander 2025-10-05 10:15 4678
            // Pathological out of memory case (TexMaxWidth/TexMaxHeight set too small?)
4e9e2555 Poul Sander 2025-10-05 10:15 4679
            IM_ASSERT(pack_id != ImFontAtlasRectId_Invalid && "Out of texture memory.");
4e9e2555 Poul Sander 2025-10-05 10:15 4680
            return false;
4e9e2555 Poul Sander 2025-10-05 10:15 4681
        }
4e9e2555 Poul Sander 2025-10-05 10:15 4682
        ImTextureRect* r = ImFontAtlasPackGetRect(atlas, pack_id);
4e9e2555 Poul Sander 2025-10-05 10:15 4683
4e9e2555 Poul Sander 2025-10-05 10:15 4684
        // Render
4e9e2555 Poul Sander 2025-10-05 10:15 4685
        stbtt_GetGlyphBitmapBox(&bd_font_data->FontInfo, glyph_index, scale_for_raster_x, scale_for_raster_y, &x0, &y0, &x1, &y1);
4e9e2555 Poul Sander 2025-10-05 10:15 4686
        ImFontAtlasBuilder* builder = atlas->Builder;
4e9e2555 Poul Sander 2025-10-05 10:15 4687
        builder->TempBuffer.resize(w * h * 1);
4e9e2555 Poul Sander 2025-10-05 10:15 4688
        unsigned char* bitmap_pixels = builder->TempBuffer.Data;
4e9e2555 Poul Sander 2025-10-05 10:15 4689
        memset(bitmap_pixels, 0, w * h * 1);
4e9e2555 Poul Sander 2025-10-05 10:15 4690
4e9e2555 Poul Sander 2025-10-05 10:15 4691
        // Render with oversampling
4e9e2555 Poul Sander 2025-10-05 10:15 4692
        // (those functions conveniently assert if pixels are not cleared, which is another safety layer)
4e9e2555 Poul Sander 2025-10-05 10:15 4693
        float sub_x, sub_y;
4e9e2555 Poul Sander 2025-10-05 10:15 4694
        stbtt_MakeGlyphBitmapSubpixelPrefilter(&bd_font_data->FontInfo, bitmap_pixels, w, h, w,
4e9e2555 Poul Sander 2025-10-05 10:15 4695
            scale_for_raster_x, scale_for_raster_y, 0, 0, oversample_h, oversample_v, &sub_x, &sub_y, glyph_index);
4e9e2555 Poul Sander 2025-10-05 10:15 4696
4e9e2555 Poul Sander 2025-10-05 10:15 4697
        const float ref_size = baked->ContainerFont->Sources[0]->SizePixels;
4e9e2555 Poul Sander 2025-10-05 10:15 4698
        const float offsets_scale = (ref_size != 0.0f) ? (baked->Size / ref_size) : 1.0f;
4e9e2555 Poul Sander 2025-10-05 10:15 4699
        float font_off_x = (src->GlyphOffset.x * offsets_scale);
4e9e2555 Poul Sander 2025-10-05 10:15 4700
        float font_off_y = (src->GlyphOffset.y * offsets_scale);
4e9e2555 Poul Sander 2025-10-05 10:15 4701
        if (src->PixelSnapH) // Snap scaled offset. This is to mitigate backward compatibility issues for GlyphOffset, but a better design would be welcome.
4e9e2555 Poul Sander 2025-10-05 10:15 4702
            font_off_x = IM_ROUND(font_off_x);
4e9e2555 Poul Sander 2025-10-05 10:15 4703
        if (src->PixelSnapV)
4e9e2555 Poul Sander 2025-10-05 10:15 4704
            font_off_y = IM_ROUND(font_off_y);
4e9e2555 Poul Sander 2025-10-05 10:15 4705
        font_off_x += sub_x;
4e9e2555 Poul Sander 2025-10-05 10:15 4706
        font_off_y += sub_y + IM_ROUND(baked->Ascent);
4e9e2555 Poul Sander 2025-10-05 10:15 4707
        float recip_h = 1.0f / (oversample_h * rasterizer_density);
4e9e2555 Poul Sander 2025-10-05 10:15 4708
        float recip_v = 1.0f / (oversample_v * rasterizer_density);
4e9e2555 Poul Sander 2025-10-05 10:15 4709
4e9e2555 Poul Sander 2025-10-05 10:15 4710
        // Register glyph
4e9e2555 Poul Sander 2025-10-05 10:15 4711
        // r->x r->y are coordinates inside texture (in pixels)
4e9e2555 Poul Sander 2025-10-05 10:15 4712
        // glyph.X0, glyph.Y0 are drawing coordinates from base text position, and accounting for oversampling.
4e9e2555 Poul Sander 2025-10-05 10:15 4713
        out_glyph->X0 = x0 * recip_h + font_off_x;
4e9e2555 Poul Sander 2025-10-05 10:15 4714
        out_glyph->Y0 = y0 * recip_v + font_off_y;
4e9e2555 Poul Sander 2025-10-05 10:15 4715
        out_glyph->X1 = (x0 + (int)r->w) * recip_h + font_off_x;
4e9e2555 Poul Sander 2025-10-05 10:15 4716
        out_glyph->Y1 = (y0 + (int)r->h) * recip_v + font_off_y;
4e9e2555 Poul Sander 2025-10-05 10:15 4717
        out_glyph->Visible = true;
4e9e2555 Poul Sander 2025-10-05 10:15 4718
        out_glyph->PackId = pack_id;
4e9e2555 Poul Sander 2025-10-05 10:15 4719
        ImFontAtlasBakedSetFontGlyphBitmap(atlas, baked, src, out_glyph, r, bitmap_pixels, ImTextureFormat_Alpha8, w);
1193b4be Poul Sander 2025-02-03 21:28 4720
    }
1193b4be Poul Sander 2025-02-03 21:28 4721
4e9e2555 Poul Sander 2025-10-05 10:15 4722
    return true;
4e9e2555 Poul Sander 2025-10-05 10:15 4723
}
1193b4be Poul Sander 2025-02-03 21:28 4724
4e9e2555 Poul Sander 2025-10-05 10:15 4725
const ImFontLoader* ImFontAtlasGetFontLoaderForStbTruetype()
4e9e2555 Poul Sander 2025-10-05 10:15 4726
{
4e9e2555 Poul Sander 2025-10-05 10:15 4727
    static ImFontLoader loader;
4e9e2555 Poul Sander 2025-10-05 10:15 4728
    loader.Name = "stb_truetype";
4e9e2555 Poul Sander 2025-10-05 10:15 4729
    loader.FontSrcInit = ImGui_ImplStbTrueType_FontSrcInit;
4e9e2555 Poul Sander 2025-10-05 10:15 4730
    loader.FontSrcDestroy = ImGui_ImplStbTrueType_FontSrcDestroy;
4e9e2555 Poul Sander 2025-10-05 10:15 4731
    loader.FontSrcContainsGlyph = ImGui_ImplStbTrueType_FontSrcContainsGlyph;
4e9e2555 Poul Sander 2025-10-05 10:15 4732
    loader.FontBakedInit = ImGui_ImplStbTrueType_FontBakedInit;
4e9e2555 Poul Sander 2025-10-05 10:15 4733
    loader.FontBakedDestroy = NULL;
4e9e2555 Poul Sander 2025-10-05 10:15 4734
    loader.FontBakedLoadGlyph = ImGui_ImplStbTrueType_FontBakedLoadGlyph;
4e9e2555 Poul Sander 2025-10-05 10:15 4735
    return &loader;
1193b4be Poul Sander 2025-02-03 21:28 4736
}
1193b4be Poul Sander 2025-02-03 21:28 4737
4e9e2555 Poul Sander 2025-10-05 10:15 4738
#endif // IMGUI_ENABLE_STB_TRUETYPE
4e9e2555 Poul Sander 2025-10-05 10:15 4739
4e9e2555 Poul Sander 2025-10-05 10:15 4740
//-------------------------------------------------------------------------
4e9e2555 Poul Sander 2025-10-05 10:15 4741
// [SECTION] ImFontAtlas: glyph ranges helpers
4e9e2555 Poul Sander 2025-10-05 10:15 4742
//-------------------------------------------------------------------------
4e9e2555 Poul Sander 2025-10-05 10:15 4743
// - GetGlyphRangesDefault()
4e9e2555 Poul Sander 2025-10-05 10:15 4744
// Obsolete functions since 1.92:
4e9e2555 Poul Sander 2025-10-05 10:15 4745
// - GetGlyphRangesGreek()
4e9e2555 Poul Sander 2025-10-05 10:15 4746
// - GetGlyphRangesKorean()
4e9e2555 Poul Sander 2025-10-05 10:15 4747
// - GetGlyphRangesChineseFull()
4e9e2555 Poul Sander 2025-10-05 10:15 4748
// - GetGlyphRangesChineseSimplifiedCommon()
4e9e2555 Poul Sander 2025-10-05 10:15 4749
// - GetGlyphRangesJapanese()
4e9e2555 Poul Sander 2025-10-05 10:15 4750
// - GetGlyphRangesCyrillic()
4e9e2555 Poul Sander 2025-10-05 10:15 4751
// - GetGlyphRangesThai()
4e9e2555 Poul Sander 2025-10-05 10:15 4752
// - GetGlyphRangesVietnamese()
4e9e2555 Poul Sander 2025-10-05 10:15 4753
//-----------------------------------------------------------------------------
4e9e2555 Poul Sander 2025-10-05 10:15 4754
1193b4be Poul Sander 2025-02-03 21:28 4755
// Retrieve list of range (2 int per range, values are inclusive)
1193b4be Poul Sander 2025-02-03 21:28 4756
const ImWchar*   ImFontAtlas::GetGlyphRangesDefault()
1193b4be Poul Sander 2025-02-03 21:28 4757
{
1193b4be Poul Sander 2025-02-03 21:28 4758
    static const ImWchar ranges[] =
1193b4be Poul Sander 2025-02-03 21:28 4759
    {
1193b4be Poul Sander 2025-02-03 21:28 4760
        0x0020, 0x00FF, // Basic Latin + Latin Supplement
1193b4be Poul Sander 2025-02-03 21:28 4761
        0,
1193b4be Poul Sander 2025-02-03 21:28 4762
    };
1193b4be Poul Sander 2025-02-03 21:28 4763
    return &ranges[0];
1193b4be Poul Sander 2025-02-03 21:28 4764
}
1193b4be Poul Sander 2025-02-03 21:28 4765
4e9e2555 Poul Sander 2025-10-05 10:15 4766
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
1193b4be Poul Sander 2025-02-03 21:28 4767
const ImWchar*   ImFontAtlas::GetGlyphRangesGreek()
1193b4be Poul Sander 2025-02-03 21:28 4768
{
1193b4be Poul Sander 2025-02-03 21:28 4769
    static const ImWchar ranges[] =
1193b4be Poul Sander 2025-02-03 21:28 4770
    {
1193b4be Poul Sander 2025-02-03 21:28 4771
        0x0020, 0x00FF, // Basic Latin + Latin Supplement
1193b4be Poul Sander 2025-02-03 21:28 4772
        0x0370, 0x03FF, // Greek and Coptic
1193b4be Poul Sander 2025-02-03 21:28 4773
        0,
1193b4be Poul Sander 2025-02-03 21:28 4774
    };
1193b4be Poul Sander 2025-02-03 21:28 4775
    return &ranges[0];
1193b4be Poul Sander 2025-02-03 21:28 4776
}
1193b4be Poul Sander 2025-02-03 21:28 4777
1193b4be Poul Sander 2025-02-03 21:28 4778
const ImWchar*  ImFontAtlas::GetGlyphRangesKorean()
1193b4be Poul Sander 2025-02-03 21:28 4779
{
1193b4be Poul Sander 2025-02-03 21:28 4780
    static const ImWchar ranges[] =
1193b4be Poul Sander 2025-02-03 21:28 4781
    {
1193b4be Poul Sander 2025-02-03 21:28 4782
        0x0020, 0x00FF, // Basic Latin + Latin Supplement
1193b4be Poul Sander 2025-02-03 21:28 4783
        0x3131, 0x3163, // Korean alphabets
1193b4be Poul Sander 2025-02-03 21:28 4784
        0xAC00, 0xD7A3, // Korean characters
1193b4be Poul Sander 2025-02-03 21:28 4785
        0xFFFD, 0xFFFD, // Invalid
1193b4be Poul Sander 2025-02-03 21:28 4786
        0,
1193b4be Poul Sander 2025-02-03 21:28 4787
    };
1193b4be Poul Sander 2025-02-03 21:28 4788
    return &ranges[0];
1193b4be Poul Sander 2025-02-03 21:28 4789
}
1193b4be Poul Sander 2025-02-03 21:28 4790
1193b4be Poul Sander 2025-02-03 21:28 4791
const ImWchar*  ImFontAtlas::GetGlyphRangesChineseFull()
1193b4be Poul Sander 2025-02-03 21:28 4792
{
1193b4be Poul Sander 2025-02-03 21:28 4793
    static const ImWchar ranges[] =
1193b4be Poul Sander 2025-02-03 21:28 4794
    {
1193b4be Poul Sander 2025-02-03 21:28 4795
        0x0020, 0x00FF, // Basic Latin + Latin Supplement
1193b4be Poul Sander 2025-02-03 21:28 4796
        0x2000, 0x206F, // General Punctuation
1193b4be Poul Sander 2025-02-03 21:28 4797
        0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
1193b4be Poul Sander 2025-02-03 21:28 4798
        0x31F0, 0x31FF, // Katakana Phonetic Extensions
1193b4be Poul Sander 2025-02-03 21:28 4799
        0xFF00, 0xFFEF, // Half-width characters
1193b4be Poul Sander 2025-02-03 21:28 4800
        0xFFFD, 0xFFFD, // Invalid
1193b4be Poul Sander 2025-02-03 21:28 4801
        0x4e00, 0x9FAF, // CJK Ideograms
1193b4be Poul Sander 2025-02-03 21:28 4802
        0,
1193b4be Poul Sander 2025-02-03 21:28 4803
    };
1193b4be Poul Sander 2025-02-03 21:28 4804
    return &ranges[0];
1193b4be Poul Sander 2025-02-03 21:28 4805
}
1193b4be Poul Sander 2025-02-03 21:28 4806
1193b4be Poul Sander 2025-02-03 21:28 4807
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 4808
{
1193b4be Poul Sander 2025-02-03 21:28 4809
    for (int n = 0; n < accumulative_offsets_count; n++, out_ranges += 2)
1193b4be Poul Sander 2025-02-03 21:28 4810
    {
1193b4be Poul Sander 2025-02-03 21:28 4811
        out_ranges[0] = out_ranges[1] = (ImWchar)(base_codepoint + accumulative_offsets[n]);
1193b4be Poul Sander 2025-02-03 21:28 4812
        base_codepoint += accumulative_offsets[n];
1193b4be Poul Sander 2025-02-03 21:28 4813
    }
1193b4be Poul Sander 2025-02-03 21:28 4814
    out_ranges[0] = 0;
1193b4be Poul Sander 2025-02-03 21:28 4815
}
1193b4be Poul Sander 2025-02-03 21:28 4816
1193b4be Poul Sander 2025-02-03 21:28 4817
const ImWchar*  ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon()
1193b4be Poul Sander 2025-02-03 21:28 4818
{
1193b4be Poul Sander 2025-02-03 21:28 4819
    // Store 2500 regularly used characters for Simplified Chinese.
1193b4be Poul Sander 2025-02-03 21:28 4820
    // 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 4821
    // This table covers 97.97% of all characters used during the month in July, 1987.
1193b4be Poul Sander 2025-02-03 21:28 4822
    // 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 4823
    // (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 4824
    static const short accumulative_offsets_from_0x4E00[] =
1193b4be Poul Sander 2025-02-03 21:28 4825
    {
1193b4be Poul Sander 2025-02-03 21:28 4826
        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 4827
        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 4828
        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 4829
        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 4830
        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 4831
        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 4832
        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 4833
        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 4834
        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 4835
        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 4836
        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 4837
        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 4838
        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 4839
        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 4840
        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 4841
        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 4842
        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 4843
        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 4844
        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 4845
        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 4846
        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 4847
        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 4848
        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 4849
        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 4850
        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 4851
        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 4852
        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 4853
        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 4854
        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 4855
        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 4856
        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 4857
        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 4858
        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 4859
        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 4860
        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 4861
        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 4862
        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 4863
        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 4864
        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 4865
        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 4866
    };
1193b4be Poul Sander 2025-02-03 21:28 4867
    static ImWchar base_ranges[] = // not zero-terminated
1193b4be Poul Sander 2025-02-03 21:28 4868
    {
1193b4be Poul Sander 2025-02-03 21:28 4869
        0x0020, 0x00FF, // Basic Latin + Latin Supplement
1193b4be Poul Sander 2025-02-03 21:28 4870
        0x2000, 0x206F, // General Punctuation
1193b4be Poul Sander 2025-02-03 21:28 4871
        0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
1193b4be Poul Sander 2025-02-03 21:28 4872
        0x31F0, 0x31FF, // Katakana Phonetic Extensions
1193b4be Poul Sander 2025-02-03 21:28 4873
        0xFF00, 0xFFEF, // Half-width characters
1193b4be Poul Sander 2025-02-03 21:28 4874
        0xFFFD, 0xFFFD  // Invalid
1193b4be Poul Sander 2025-02-03 21:28 4875
    };
1193b4be Poul Sander 2025-02-03 21:28 4876
    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 4877
    if (!full_ranges[0])
1193b4be Poul Sander 2025-02-03 21:28 4878
    {
1193b4be Poul Sander 2025-02-03 21:28 4879
        memcpy(full_ranges, base_ranges, sizeof(base_ranges));
1193b4be Poul Sander 2025-02-03 21:28 4880
        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 4881
    }
1193b4be Poul Sander 2025-02-03 21:28 4882
    return &full_ranges[0];
1193b4be Poul Sander 2025-02-03 21:28 4883
}
1193b4be Poul Sander 2025-02-03 21:28 4884
1193b4be Poul Sander 2025-02-03 21:28 4885
const ImWchar*  ImFontAtlas::GetGlyphRangesJapanese()
1193b4be Poul Sander 2025-02-03 21:28 4886
{
1193b4be Poul Sander 2025-02-03 21:28 4887
    // 2999 ideograms code points for Japanese
1193b4be Poul Sander 2025-02-03 21:28 4888
    // - 2136 Joyo (meaning "for regular use" or "for common use") Kanji code points
1193b4be Poul Sander 2025-02-03 21:28 4889
    // - 863 Jinmeiyo (meaning "for personal name") Kanji code points
1193b4be Poul Sander 2025-02-03 21:28 4890
    // - Sourced from official information provided by the government agencies of Japan:
1193b4be Poul Sander 2025-02-03 21:28 4891
    //   - List of Joyo Kanji by the Agency for Cultural Affairs
1193b4be Poul Sander 2025-02-03 21:28 4892
    //     - https://www.bunka.go.jp/kokugo_nihongo/sisaku/joho/joho/kijun/naikaku/kanji/
1193b4be Poul Sander 2025-02-03 21:28 4893
    //   - List of Jinmeiyo Kanji by the Ministry of Justice
1193b4be Poul Sander 2025-02-03 21:28 4894
    //     - http://www.moj.go.jp/MINJI/minji86.html
1193b4be Poul Sander 2025-02-03 21:28 4895
    //   - Available under the terms of the Creative Commons Attribution 4.0 International (CC BY 4.0).
1193b4be Poul Sander 2025-02-03 21:28 4896
    //     - https://creativecommons.org/licenses/by/4.0/legalcode
1193b4be Poul Sander 2025-02-03 21:28 4897
    // - You can generate this code by the script at:
1193b4be Poul Sander 2025-02-03 21:28 4898
    //   - https://github.com/vaiorabbit/everyday_use_kanji
1193b4be Poul Sander 2025-02-03 21:28 4899
    // - References:
1193b4be Poul Sander 2025-02-03 21:28 4900
    //   - List of Joyo Kanji
1193b4be Poul Sander 2025-02-03 21:28 4901
    //     - (Wikipedia) https://en.wikipedia.org/wiki/List_of_j%C5%8Dy%C5%8D_kanji
1193b4be Poul Sander 2025-02-03 21:28 4902
    //   - List of Jinmeiyo Kanji
1193b4be Poul Sander 2025-02-03 21:28 4903
    //     - (Wikipedia) https://en.wikipedia.org/wiki/Jinmeiy%C5%8D_kanji
1193b4be Poul Sander 2025-02-03 21:28 4904
    // - 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 4905
    // 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 4906
    // (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 4907
    static const short accumulative_offsets_from_0x4E00[] =
1193b4be Poul Sander 2025-02-03 21:28 4908
    {
1193b4be Poul Sander 2025-02-03 21:28 4909
        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 4910
        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 4911
        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 4912
        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 4913
        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 4914
        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 4915
        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 4916
        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 4917
        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 4918
        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 4919
        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 4920
        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 4921
        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 4922
        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 4923
        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 4924
        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 4925
        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 4926
        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 4927
        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 4928
        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 4929
        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 4930
        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 4931
        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 4932
        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 4933
        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 4934
        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 4935
        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 4936
        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 4937
        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 4938
        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 4939
        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 4940
        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 4941
        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 4942
        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 4943
        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 4944
        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 4945
        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 4946
        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 4947
        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 4948
        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 4949
        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 4950
        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 4951
        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 4952
        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 4953
        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 4954
        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 4955
        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 4956
        3,2,1,1,1,1,2,1,1,
1193b4be Poul Sander 2025-02-03 21:28 4957
    };
1193b4be Poul Sander 2025-02-03 21:28 4958
    static ImWchar base_ranges[] = // not zero-terminated
1193b4be Poul Sander 2025-02-03 21:28 4959
    {
1193b4be Poul Sander 2025-02-03 21:28 4960
        0x0020, 0x00FF, // Basic Latin + Latin Supplement
1193b4be Poul Sander 2025-02-03 21:28 4961
        0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
1193b4be Poul Sander 2025-02-03 21:28 4962
        0x31F0, 0x31FF, // Katakana Phonetic Extensions
1193b4be Poul Sander 2025-02-03 21:28 4963
        0xFF00, 0xFFEF, // Half-width characters
1193b4be Poul Sander 2025-02-03 21:28 4964
        0xFFFD, 0xFFFD  // Invalid
1193b4be Poul Sander 2025-02-03 21:28 4965
    };
1193b4be Poul Sander 2025-02-03 21:28 4966
    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 4967
    if (!full_ranges[0])
1193b4be Poul Sander 2025-02-03 21:28 4968
    {
1193b4be Poul Sander 2025-02-03 21:28 4969
        memcpy(full_ranges, base_ranges, sizeof(base_ranges));
1193b4be Poul Sander 2025-02-03 21:28 4970
        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 4971
    }
1193b4be Poul Sander 2025-02-03 21:28 4972
    return &full_ranges[0];
1193b4be Poul Sander 2025-02-03 21:28 4973
}
1193b4be Poul Sander 2025-02-03 21:28 4974
1193b4be Poul Sander 2025-02-03 21:28 4975
const ImWchar*  ImFontAtlas::GetGlyphRangesCyrillic()
1193b4be Poul Sander 2025-02-03 21:28 4976
{
1193b4be Poul Sander 2025-02-03 21:28 4977
    static const ImWchar ranges[] =
1193b4be Poul Sander 2025-02-03 21:28 4978
    {
1193b4be Poul Sander 2025-02-03 21:28 4979
        0x0020, 0x00FF, // Basic Latin + Latin Supplement
1193b4be Poul Sander 2025-02-03 21:28 4980
        0x0400, 0x052F, // Cyrillic + Cyrillic Supplement
1193b4be Poul Sander 2025-02-03 21:28 4981
        0x2DE0, 0x2DFF, // Cyrillic Extended-A
1193b4be Poul Sander 2025-02-03 21:28 4982
        0xA640, 0xA69F, // Cyrillic Extended-B
1193b4be Poul Sander 2025-02-03 21:28 4983
        0,
1193b4be Poul Sander 2025-02-03 21:28 4984
    };
1193b4be Poul Sander 2025-02-03 21:28 4985
    return &ranges[0];
1193b4be Poul Sander 2025-02-03 21:28 4986
}
1193b4be Poul Sander 2025-02-03 21:28 4987
1193b4be Poul Sander 2025-02-03 21:28 4988
const ImWchar*  ImFontAtlas::GetGlyphRangesThai()
1193b4be Poul Sander 2025-02-03 21:28 4989
{
1193b4be Poul Sander 2025-02-03 21:28 4990
    static const ImWchar ranges[] =
1193b4be Poul Sander 2025-02-03 21:28 4991
    {
1193b4be Poul Sander 2025-02-03 21:28 4992
        0x0020, 0x00FF, // Basic Latin
1193b4be Poul Sander 2025-02-03 21:28 4993
        0x2010, 0x205E, // Punctuations
1193b4be Poul Sander 2025-02-03 21:28 4994
        0x0E00, 0x0E7F, // Thai
1193b4be Poul Sander 2025-02-03 21:28 4995
        0,
1193b4be Poul Sander 2025-02-03 21:28 4996
    };
1193b4be Poul Sander 2025-02-03 21:28 4997
    return &ranges[0];
1193b4be Poul Sander 2025-02-03 21:28 4998
}
1193b4be Poul Sander 2025-02-03 21:28 4999
1193b4be Poul Sander 2025-02-03 21:28 5000
const ImWchar*  ImFontAtlas::GetGlyphRangesVietnamese()
1193b4be Poul Sander 2025-02-03 21:28 5001
{
1193b4be Poul Sander 2025-02-03 21:28 5002
    static const ImWchar ranges[] =
1193b4be Poul Sander 2025-02-03 21:28 5003
    {
1193b4be Poul Sander 2025-02-03 21:28 5004
        0x0020, 0x00FF, // Basic Latin
1193b4be Poul Sander 2025-02-03 21:28 5005
        0x0102, 0x0103,
1193b4be Poul Sander 2025-02-03 21:28 5006
        0x0110, 0x0111,
1193b4be Poul Sander 2025-02-03 21:28 5007
        0x0128, 0x0129,
1193b4be Poul Sander 2025-02-03 21:28 5008
        0x0168, 0x0169,
1193b4be Poul Sander 2025-02-03 21:28 5009
        0x01A0, 0x01A1,
1193b4be Poul Sander 2025-02-03 21:28 5010
        0x01AF, 0x01B0,
1193b4be Poul Sander 2025-02-03 21:28 5011
        0x1EA0, 0x1EF9,
1193b4be Poul Sander 2025-02-03 21:28 5012
        0,
1193b4be Poul Sander 2025-02-03 21:28 5013
    };
1193b4be Poul Sander 2025-02-03 21:28 5014
    return &ranges[0];
1193b4be Poul Sander 2025-02-03 21:28 5015
}
4e9e2555 Poul Sander 2025-10-05 10:15 5016
#endif // #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
1193b4be Poul Sander 2025-02-03 21:28 5017
1193b4be Poul Sander 2025-02-03 21:28 5018
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 5019
// [SECTION] ImFontGlyphRangesBuilder
1193b4be Poul Sander 2025-02-03 21:28 5020
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 5021
1193b4be Poul Sander 2025-02-03 21:28 5022
void ImFontGlyphRangesBuilder::AddText(const char* text, const char* text_end)
1193b4be Poul Sander 2025-02-03 21:28 5023
{
1193b4be Poul Sander 2025-02-03 21:28 5024
    while (text_end ? (text < text_end) : *text)
1193b4be Poul Sander 2025-02-03 21:28 5025
    {
1193b4be Poul Sander 2025-02-03 21:28 5026
        unsigned int c = 0;
1193b4be Poul Sander 2025-02-03 21:28 5027
        int c_len = ImTextCharFromUtf8(&c, text, text_end);
1193b4be Poul Sander 2025-02-03 21:28 5028
        text += c_len;
1193b4be Poul Sander 2025-02-03 21:28 5029
        if (c_len == 0)
1193b4be Poul Sander 2025-02-03 21:28 5030
            break;
1193b4be Poul Sander 2025-02-03 21:28 5031
        AddChar((ImWchar)c);
1193b4be Poul Sander 2025-02-03 21:28 5032
    }
1193b4be Poul Sander 2025-02-03 21:28 5033
}
1193b4be Poul Sander 2025-02-03 21:28 5034
1193b4be Poul Sander 2025-02-03 21:28 5035
void ImFontGlyphRangesBuilder::AddRanges(const ImWchar* ranges)
1193b4be Poul Sander 2025-02-03 21:28 5036
{
1193b4be Poul Sander 2025-02-03 21:28 5037
    for (; ranges[0]; ranges += 2)
1193b4be Poul Sander 2025-02-03 21:28 5038
        for (unsigned int c = ranges[0]; c <= ranges[1] && c <= IM_UNICODE_CODEPOINT_MAX; c++) //-V560
1193b4be Poul Sander 2025-02-03 21:28 5039
            AddChar((ImWchar)c);
1193b4be Poul Sander 2025-02-03 21:28 5040
}
1193b4be Poul Sander 2025-02-03 21:28 5041
1193b4be Poul Sander 2025-02-03 21:28 5042
void ImFontGlyphRangesBuilder::BuildRanges(ImVector<ImWchar>* out_ranges)
1193b4be Poul Sander 2025-02-03 21:28 5043
{
1193b4be Poul Sander 2025-02-03 21:28 5044
    const int max_codepoint = IM_UNICODE_CODEPOINT_MAX;
1193b4be Poul Sander 2025-02-03 21:28 5045
    for (int n = 0; n <= max_codepoint; n++)
1193b4be Poul Sander 2025-02-03 21:28 5046
        if (GetBit(n))
1193b4be Poul Sander 2025-02-03 21:28 5047
        {
1193b4be Poul Sander 2025-02-03 21:28 5048
            out_ranges->push_back((ImWchar)n);
1193b4be Poul Sander 2025-02-03 21:28 5049
            while (n < max_codepoint && GetBit(n + 1))
1193b4be Poul Sander 2025-02-03 21:28 5050
                n++;
1193b4be Poul Sander 2025-02-03 21:28 5051
            out_ranges->push_back((ImWchar)n);
1193b4be Poul Sander 2025-02-03 21:28 5052
        }
1193b4be Poul Sander 2025-02-03 21:28 5053
    out_ranges->push_back(0);
1193b4be Poul Sander 2025-02-03 21:28 5054
}
1193b4be Poul Sander 2025-02-03 21:28 5055
1193b4be Poul Sander 2025-02-03 21:28 5056
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 5057
// [SECTION] ImFont
1193b4be Poul Sander 2025-02-03 21:28 5058
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 5059
4e9e2555 Poul Sander 2025-10-05 10:15 5060
ImFontBaked::ImFontBaked()
1193b4be Poul Sander 2025-02-03 21:28 5061
{
4e9e2555 Poul Sander 2025-10-05 10:15 5062
    memset(this, 0, sizeof(*this));
4e9e2555 Poul Sander 2025-10-05 10:15 5063
    FallbackGlyphIndex = -1;
1193b4be Poul Sander 2025-02-03 21:28 5064
}
1193b4be Poul Sander 2025-02-03 21:28 5065
4e9e2555 Poul Sander 2025-10-05 10:15 5066
void ImFontBaked::ClearOutputData()
1193b4be Poul Sander 2025-02-03 21:28 5067
{
1193b4be Poul Sander 2025-02-03 21:28 5068
    FallbackAdvanceX = 0.0f;
1193b4be Poul Sander 2025-02-03 21:28 5069
    Glyphs.clear();
1193b4be Poul Sander 2025-02-03 21:28 5070
    IndexAdvanceX.clear();
1193b4be Poul Sander 2025-02-03 21:28 5071
    IndexLookup.clear();
4e9e2555 Poul Sander 2025-10-05 10:15 5072
    FallbackGlyphIndex = -1;
1193b4be Poul Sander 2025-02-03 21:28 5073
    Ascent = Descent = 0.0f;
1193b4be Poul Sander 2025-02-03 21:28 5074
    MetricsTotalSurface = 0;
1193b4be Poul Sander 2025-02-03 21:28 5075
}
1193b4be Poul Sander 2025-02-03 21:28 5076
4e9e2555 Poul Sander 2025-10-05 10:15 5077
ImFont::ImFont()
1193b4be Poul Sander 2025-02-03 21:28 5078
{
4e9e2555 Poul Sander 2025-10-05 10:15 5079
    memset(this, 0, sizeof(*this));
4e9e2555 Poul Sander 2025-10-05 10:15 5080
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
4e9e2555 Poul Sander 2025-10-05 10:15 5081
    Scale = 1.0f;
4e9e2555 Poul Sander 2025-10-05 10:15 5082
#endif
1193b4be Poul Sander 2025-02-03 21:28 5083
}
1193b4be Poul Sander 2025-02-03 21:28 5084
4e9e2555 Poul Sander 2025-10-05 10:15 5085
ImFont::~ImFont()
1193b4be Poul Sander 2025-02-03 21:28 5086
{
4e9e2555 Poul Sander 2025-10-05 10:15 5087
    ClearOutputData();
4e9e2555 Poul Sander 2025-10-05 10:15 5088
}
1193b4be Poul Sander 2025-02-03 21:28 5089
4e9e2555 Poul Sander 2025-10-05 10:15 5090
void ImFont::ClearOutputData()
4e9e2555 Poul Sander 2025-10-05 10:15 5091
{
4e9e2555 Poul Sander 2025-10-05 10:15 5092
    if (ImFontAtlas* atlas = ContainerAtlas)
4e9e2555 Poul Sander 2025-10-05 10:15 5093
        ImFontAtlasFontDiscardBakes(atlas, this, 0);
4e9e2555 Poul Sander 2025-10-05 10:15 5094
    FallbackChar = EllipsisChar = 0;
4e9e2555 Poul Sander 2025-10-05 10:15 5095
    memset(Used8kPagesMap, 0, sizeof(Used8kPagesMap));
4e9e2555 Poul Sander 2025-10-05 10:15 5096
    LastBaked = NULL;
4e9e2555 Poul Sander 2025-10-05 10:15 5097
}
1193b4be Poul Sander 2025-02-03 21:28 5098
4e9e2555 Poul Sander 2025-10-05 10:15 5099
// API is designed this way to avoid exposing the 8K page size
4e9e2555 Poul Sander 2025-10-05 10:15 5100
// e.g. use with IsGlyphRangeUnused(0, 255)
4e9e2555 Poul Sander 2025-10-05 10:15 5101
bool ImFont::IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last)
4e9e2555 Poul Sander 2025-10-05 10:15 5102
{
4e9e2555 Poul Sander 2025-10-05 10:15 5103
    unsigned int page_begin = (c_begin / 8192);
4e9e2555 Poul Sander 2025-10-05 10:15 5104
    unsigned int page_last = (c_last / 8192);
4e9e2555 Poul Sander 2025-10-05 10:15 5105
    for (unsigned int page_n = page_begin; page_n <= page_last; page_n++)
4e9e2555 Poul Sander 2025-10-05 10:15 5106
        if ((page_n >> 3) < sizeof(Used8kPagesMap))
4e9e2555 Poul Sander 2025-10-05 10:15 5107
            if (Used8kPagesMap[page_n >> 3] & (1 << (page_n & 7)))
4e9e2555 Poul Sander 2025-10-05 10:15 5108
                return false;
4e9e2555 Poul Sander 2025-10-05 10:15 5109
    return true;
4e9e2555 Poul Sander 2025-10-05 10:15 5110
}
1193b4be Poul Sander 2025-02-03 21:28 5111
4e9e2555 Poul Sander 2025-10-05 10:15 5112
// x0/y0/x1/y1 are offset from the character upper-left layout position, in pixels. Therefore x0/y0 are often fairly close to zero.
4e9e2555 Poul Sander 2025-10-05 10:15 5113
// 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).
4e9e2555 Poul Sander 2025-10-05 10:15 5114
// - 'src' is not necessarily == 'this->Sources' because multiple source fonts+configs can be used to build one target font.
4e9e2555 Poul Sander 2025-10-05 10:15 5115
ImFontGlyph* ImFontAtlasBakedAddFontGlyph(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* src, const ImFontGlyph* in_glyph)
4e9e2555 Poul Sander 2025-10-05 10:15 5116
{
4e9e2555 Poul Sander 2025-10-05 10:15 5117
    int glyph_idx = baked->Glyphs.Size;
4e9e2555 Poul Sander 2025-10-05 10:15 5118
    baked->Glyphs.push_back(*in_glyph);
4e9e2555 Poul Sander 2025-10-05 10:15 5119
    ImFontGlyph* glyph = &baked->Glyphs[glyph_idx];
4e9e2555 Poul Sander 2025-10-05 10:15 5120
    IM_ASSERT(baked->Glyphs.Size < 0xFFFE); // IndexLookup[] hold 16-bit values and -1/-2 are reserved.
4e9e2555 Poul Sander 2025-10-05 10:15 5121
4e9e2555 Poul Sander 2025-10-05 10:15 5122
    // Set UV from packed rectangle
4e9e2555 Poul Sander 2025-10-05 10:15 5123
    if (glyph->PackId != ImFontAtlasRectId_Invalid)
1193b4be Poul Sander 2025-02-03 21:28 5124
    {
4e9e2555 Poul Sander 2025-10-05 10:15 5125
        ImTextureRect* r = ImFontAtlasPackGetRect(atlas, glyph->PackId);
4e9e2555 Poul Sander 2025-10-05 10:15 5126
        IM_ASSERT(glyph->U0 == 0.0f && glyph->V0 == 0.0f && glyph->U1 == 0.0f && glyph->V1 == 0.0f);
4e9e2555 Poul Sander 2025-10-05 10:15 5127
        glyph->U0 = (r->x) * atlas->TexUvScale.x;
4e9e2555 Poul Sander 2025-10-05 10:15 5128
        glyph->V0 = (r->y) * atlas->TexUvScale.y;
4e9e2555 Poul Sander 2025-10-05 10:15 5129
        glyph->U1 = (r->x + r->w) * atlas->TexUvScale.x;
4e9e2555 Poul Sander 2025-10-05 10:15 5130
        glyph->V1 = (r->y + r->h) * atlas->TexUvScale.y;
4e9e2555 Poul Sander 2025-10-05 10:15 5131
        baked->MetricsTotalSurface += r->w * r->h;
1193b4be Poul Sander 2025-02-03 21:28 5132
    }
1193b4be Poul Sander 2025-02-03 21:28 5133
4e9e2555 Poul Sander 2025-10-05 10:15 5134
    if (src != NULL)
1193b4be Poul Sander 2025-02-03 21:28 5135
    {
4e9e2555 Poul Sander 2025-10-05 10:15 5136
        // Clamp & recenter if needed
4e9e2555 Poul Sander 2025-10-05 10:15 5137
        const float ref_size = baked->ContainerFont->Sources[0]->SizePixels;
4e9e2555 Poul Sander 2025-10-05 10:15 5138
        const float offsets_scale = (ref_size != 0.0f) ? (baked->Size / ref_size) : 1.0f;
4e9e2555 Poul Sander 2025-10-05 10:15 5139
        float advance_x = ImClamp(glyph->AdvanceX, src->GlyphMinAdvanceX * offsets_scale, src->GlyphMaxAdvanceX * offsets_scale);
4e9e2555 Poul Sander 2025-10-05 10:15 5140
        if (advance_x != glyph->AdvanceX)
1193b4be Poul Sander 2025-02-03 21:28 5141
        {
4e9e2555 Poul Sander 2025-10-05 10:15 5142
            float char_off_x = src->PixelSnapH ? ImTrunc((advance_x - glyph->AdvanceX) * 0.5f) : (advance_x - glyph->AdvanceX) * 0.5f;
4e9e2555 Poul Sander 2025-10-05 10:15 5143
            glyph->X0 += char_off_x;
4e9e2555 Poul Sander 2025-10-05 10:15 5144
            glyph->X1 += char_off_x;
1193b4be Poul Sander 2025-02-03 21:28 5145
        }
1193b4be Poul Sander 2025-02-03 21:28 5146
4e9e2555 Poul Sander 2025-10-05 10:15 5147
        // Snap to pixel
4e9e2555 Poul Sander 2025-10-05 10:15 5148
        if (src->PixelSnapH)
4e9e2555 Poul Sander 2025-10-05 10:15 5149
            advance_x = IM_ROUND(advance_x);
4e9e2555 Poul Sander 2025-10-05 10:15 5150
4e9e2555 Poul Sander 2025-10-05 10:15 5151
        // Bake spacing
4e9e2555 Poul Sander 2025-10-05 10:15 5152
        glyph->AdvanceX = advance_x + src->GlyphExtraAdvanceX;
1193b4be Poul Sander 2025-02-03 21:28 5153
    }
4e9e2555 Poul Sander 2025-10-05 10:15 5154
    if (glyph->Colored)
4e9e2555 Poul Sander 2025-10-05 10:15 5155
        atlas->TexPixelsUseColors = atlas->TexData->UseColors = true;
4e9e2555 Poul Sander 2025-10-05 10:15 5156
4e9e2555 Poul Sander 2025-10-05 10:15 5157
    // Update lookup tables
4e9e2555 Poul Sander 2025-10-05 10:15 5158
    const int codepoint = glyph->Codepoint;
4e9e2555 Poul Sander 2025-10-05 10:15 5159
    ImFontBaked_BuildGrowIndex(baked, codepoint + 1);
4e9e2555 Poul Sander 2025-10-05 10:15 5160
    baked->IndexAdvanceX[codepoint] = glyph->AdvanceX;
4e9e2555 Poul Sander 2025-10-05 10:15 5161
    baked->IndexLookup[codepoint] = (ImU16)glyph_idx;
4e9e2555 Poul Sander 2025-10-05 10:15 5162
    const int page_n = codepoint / 8192;
4e9e2555 Poul Sander 2025-10-05 10:15 5163
    baked->ContainerFont->Used8kPagesMap[page_n >> 3] |= 1 << (page_n & 7);
4e9e2555 Poul Sander 2025-10-05 10:15 5164
4e9e2555 Poul Sander 2025-10-05 10:15 5165
    return glyph;
4e9e2555 Poul Sander 2025-10-05 10:15 5166
}
4e9e2555 Poul Sander 2025-10-05 10:15 5167
4e9e2555 Poul Sander 2025-10-05 10:15 5168
// FIXME: Code is duplicated with code above.
4e9e2555 Poul Sander 2025-10-05 10:15 5169
void ImFontAtlasBakedAddFontGlyphAdvancedX(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* src, ImWchar codepoint, float advance_x)
4e9e2555 Poul Sander 2025-10-05 10:15 5170
{
4e9e2555 Poul Sander 2025-10-05 10:15 5171
    IM_UNUSED(atlas);
4e9e2555 Poul Sander 2025-10-05 10:15 5172
    if (src != NULL)
1193b4be Poul Sander 2025-02-03 21:28 5173
    {
4e9e2555 Poul Sander 2025-10-05 10:15 5174
        // Clamp & recenter if needed
4e9e2555 Poul Sander 2025-10-05 10:15 5175
        const float ref_size = baked->ContainerFont->Sources[0]->SizePixels;
4e9e2555 Poul Sander 2025-10-05 10:15 5176
        const float offsets_scale = (ref_size != 0.0f) ? (baked->Size / ref_size) : 1.0f;
4e9e2555 Poul Sander 2025-10-05 10:15 5177
        advance_x = ImClamp(advance_x, src->GlyphMinAdvanceX * offsets_scale, src->GlyphMaxAdvanceX * offsets_scale);
4e9e2555 Poul Sander 2025-10-05 10:15 5178
4e9e2555 Poul Sander 2025-10-05 10:15 5179
        // Snap to pixel
4e9e2555 Poul Sander 2025-10-05 10:15 5180
        if (src->PixelSnapH)
4e9e2555 Poul Sander 2025-10-05 10:15 5181
            advance_x = IM_ROUND(advance_x);
4e9e2555 Poul Sander 2025-10-05 10:15 5182
4e9e2555 Poul Sander 2025-10-05 10:15 5183
        // Bake spacing
4e9e2555 Poul Sander 2025-10-05 10:15 5184
        advance_x += src->GlyphExtraAdvanceX;
1193b4be Poul Sander 2025-02-03 21:28 5185
    }
4e9e2555 Poul Sander 2025-10-05 10:15 5186
4e9e2555 Poul Sander 2025-10-05 10:15 5187
    ImFontBaked_BuildGrowIndex(baked, codepoint + 1);
4e9e2555 Poul Sander 2025-10-05 10:15 5188
    baked->IndexAdvanceX[codepoint] = advance_x;
1193b4be Poul Sander 2025-02-03 21:28 5189
}
1193b4be Poul Sander 2025-02-03 21:28 5190
4e9e2555 Poul Sander 2025-10-05 10:15 5191
// Copy to texture, post-process and queue update for backend
4e9e2555 Poul Sander 2025-10-05 10:15 5192
void ImFontAtlasBakedSetFontGlyphBitmap(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* src, ImFontGlyph* glyph, ImTextureRect* r, const unsigned char* src_pixels, ImTextureFormat src_fmt, int src_pitch)
1193b4be Poul Sander 2025-02-03 21:28 5193
{
4e9e2555 Poul Sander 2025-10-05 10:15 5194
    ImTextureData* tex = atlas->TexData;
4e9e2555 Poul Sander 2025-10-05 10:15 5195
    IM_ASSERT(r->x + r->w <= tex->Width && r->y + r->h <= tex->Height);
4e9e2555 Poul Sander 2025-10-05 10:15 5196
    ImFontAtlasTextureBlockConvert(src_pixels, src_fmt, src_pitch, (unsigned char*)tex->GetPixelsAt(r->x, r->y), tex->Format, tex->GetPitch(), r->w, r->h);
4e9e2555 Poul Sander 2025-10-05 10:15 5197
    ImFontAtlasPostProcessData pp_data = { atlas, baked->ContainerFont, src, baked, glyph, tex->GetPixelsAt(r->x, r->y), tex->Format, tex->GetPitch(), r->w, r->h };
4e9e2555 Poul Sander 2025-10-05 10:15 5198
    ImFontAtlasTextureBlockPostProcess(&pp_data);
4e9e2555 Poul Sander 2025-10-05 10:15 5199
    ImFontAtlasTextureBlockQueueUpload(atlas, tex, r->x, r->y, r->w, r->h);
1193b4be Poul Sander 2025-02-03 21:28 5200
}
1193b4be Poul Sander 2025-02-03 21:28 5201
4e9e2555 Poul Sander 2025-10-05 10:15 5202
void ImFont::AddRemapChar(ImWchar from_codepoint, ImWchar to_codepoint)
1193b4be Poul Sander 2025-02-03 21:28 5203
{
4e9e2555 Poul Sander 2025-10-05 10:15 5204
    RemapPairs.SetInt((ImGuiID)from_codepoint, (int)to_codepoint);
1193b4be Poul Sander 2025-02-03 21:28 5205
}
1193b4be Poul Sander 2025-02-03 21:28 5206
4e9e2555 Poul Sander 2025-10-05 10:15 5207
// Find glyph, load if necessary, return fallback if missing
4e9e2555 Poul Sander 2025-10-05 10:15 5208
ImFontGlyph* ImFontBaked::FindGlyph(ImWchar c)
1193b4be Poul Sander 2025-02-03 21:28 5209
{
4e9e2555 Poul Sander 2025-10-05 10:15 5210
    if (c < (size_t)IndexLookup.Size) IM_LIKELY
4e9e2555 Poul Sander 2025-10-05 10:15 5211
    {
4e9e2555 Poul Sander 2025-10-05 10:15 5212
        const int i = (int)IndexLookup.Data[c];
4e9e2555 Poul Sander 2025-10-05 10:15 5213
        if (i == IM_FONTGLYPH_INDEX_NOT_FOUND)
4e9e2555 Poul Sander 2025-10-05 10:15 5214
            return &Glyphs.Data[FallbackGlyphIndex];
4e9e2555 Poul Sander 2025-10-05 10:15 5215
        if (i != IM_FONTGLYPH_INDEX_UNUSED)
4e9e2555 Poul Sander 2025-10-05 10:15 5216
            return &Glyphs.Data[i];
4e9e2555 Poul Sander 2025-10-05 10:15 5217
    }
4e9e2555 Poul Sander 2025-10-05 10:15 5218
    ImFontGlyph* glyph = ImFontBaked_BuildLoadGlyph(this, c, NULL);
4e9e2555 Poul Sander 2025-10-05 10:15 5219
    return glyph ? glyph : &Glyphs.Data[FallbackGlyphIndex];
1193b4be Poul Sander 2025-02-03 21:28 5220
}
1193b4be Poul Sander 2025-02-03 21:28 5221
4e9e2555 Poul Sander 2025-10-05 10:15 5222
// Attempt to load but when missing, return NULL instead of FallbackGlyph
4e9e2555 Poul Sander 2025-10-05 10:15 5223
ImFontGlyph* ImFontBaked::FindGlyphNoFallback(ImWchar c)
1193b4be Poul Sander 2025-02-03 21:28 5224
{
4e9e2555 Poul Sander 2025-10-05 10:15 5225
    if (c < (size_t)IndexLookup.Size) IM_LIKELY
1193b4be Poul Sander 2025-02-03 21:28 5226
    {
4e9e2555 Poul Sander 2025-10-05 10:15 5227
        const int i = (int)IndexLookup.Data[c];
4e9e2555 Poul Sander 2025-10-05 10:15 5228
        if (i == IM_FONTGLYPH_INDEX_NOT_FOUND)
4e9e2555 Poul Sander 2025-10-05 10:15 5229
            return NULL;
4e9e2555 Poul Sander 2025-10-05 10:15 5230
        if (i != IM_FONTGLYPH_INDEX_UNUSED)
4e9e2555 Poul Sander 2025-10-05 10:15 5231
            return &Glyphs.Data[i];
4e9e2555 Poul Sander 2025-10-05 10:15 5232
    }
4e9e2555 Poul Sander 2025-10-05 10:15 5233
    LoadNoFallback = true; // This is actually a rare call, not done in hot-loop, so we prioritize not adding extra cruft to ImFontBaked_BuildLoadGlyph() call sites.
4e9e2555 Poul Sander 2025-10-05 10:15 5234
    ImFontGlyph* glyph = ImFontBaked_BuildLoadGlyph(this, c, NULL);
4e9e2555 Poul Sander 2025-10-05 10:15 5235
    LoadNoFallback = false;
4e9e2555 Poul Sander 2025-10-05 10:15 5236
    return glyph;
1193b4be Poul Sander 2025-02-03 21:28 5237
}
1193b4be Poul Sander 2025-02-03 21:28 5238
4e9e2555 Poul Sander 2025-10-05 10:15 5239
bool ImFontBaked::IsGlyphLoaded(ImWchar c)
1193b4be Poul Sander 2025-02-03 21:28 5240
{
4e9e2555 Poul Sander 2025-10-05 10:15 5241
    if (c < (size_t)IndexLookup.Size) IM_LIKELY
4e9e2555 Poul Sander 2025-10-05 10:15 5242
    {
4e9e2555 Poul Sander 2025-10-05 10:15 5243
        const int i = (int)IndexLookup.Data[c];
4e9e2555 Poul Sander 2025-10-05 10:15 5244
        if (i == IM_FONTGLYPH_INDEX_NOT_FOUND)
4e9e2555 Poul Sander 2025-10-05 10:15 5245
            return false;
4e9e2555 Poul Sander 2025-10-05 10:15 5246
        if (i != IM_FONTGLYPH_INDEX_UNUSED)
4e9e2555 Poul Sander 2025-10-05 10:15 5247
            return true;
4e9e2555 Poul Sander 2025-10-05 10:15 5248
    }
4e9e2555 Poul Sander 2025-10-05 10:15 5249
    return false;
4e9e2555 Poul Sander 2025-10-05 10:15 5250
}
1193b4be Poul Sander 2025-02-03 21:28 5251
4e9e2555 Poul Sander 2025-10-05 10:15 5252
// This is not fast query
4e9e2555 Poul Sander 2025-10-05 10:15 5253
bool ImFont::IsGlyphInFont(ImWchar c)
4e9e2555 Poul Sander 2025-10-05 10:15 5254
{
4e9e2555 Poul Sander 2025-10-05 10:15 5255
    ImFontAtlas* atlas = ContainerAtlas;
4e9e2555 Poul Sander 2025-10-05 10:15 5256
    ImFontAtlas_FontHookRemapCodepoint(atlas, this, &c);
4e9e2555 Poul Sander 2025-10-05 10:15 5257
    for (ImFontConfig* src : Sources)
4e9e2555 Poul Sander 2025-10-05 10:15 5258
    {
4e9e2555 Poul Sander 2025-10-05 10:15 5259
        const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader;
4e9e2555 Poul Sander 2025-10-05 10:15 5260
        if (loader->FontSrcContainsGlyph != NULL && loader->FontSrcContainsGlyph(atlas, src, c))
4e9e2555 Poul Sander 2025-10-05 10:15 5261
            return true;
4e9e2555 Poul Sander 2025-10-05 10:15 5262
    }
4e9e2555 Poul Sander 2025-10-05 10:15 5263
    return false;
4e9e2555 Poul Sander 2025-10-05 10:15 5264
}
1193b4be Poul Sander 2025-02-03 21:28 5265
4e9e2555 Poul Sander 2025-10-05 10:15 5266
// This is manually inlined in CalcTextSizeA() and CalcWordWrapPosition(), with a non-inline call to BuildLoadGlyphGetAdvanceOrFallback().
4e9e2555 Poul Sander 2025-10-05 10:15 5267
IM_MSVC_RUNTIME_CHECKS_OFF
4e9e2555 Poul Sander 2025-10-05 10:15 5268
float ImFontBaked::GetCharAdvance(ImWchar c)
4e9e2555 Poul Sander 2025-10-05 10:15 5269
{
4e9e2555 Poul Sander 2025-10-05 10:15 5270
    if ((int)c < IndexAdvanceX.Size)
4e9e2555 Poul Sander 2025-10-05 10:15 5271
    {
4e9e2555 Poul Sander 2025-10-05 10:15 5272
        // Missing glyphs fitting inside index will have stored FallbackAdvanceX already.
4e9e2555 Poul Sander 2025-10-05 10:15 5273
        const float x = IndexAdvanceX.Data[c];
4e9e2555 Poul Sander 2025-10-05 10:15 5274
        if (x >= 0.0f)
4e9e2555 Poul Sander 2025-10-05 10:15 5275
            return x;
4e9e2555 Poul Sander 2025-10-05 10:15 5276
    }
4e9e2555 Poul Sander 2025-10-05 10:15 5277
    return ImFontBaked_BuildLoadGlyphAdvanceX(this, c);
1193b4be Poul Sander 2025-02-03 21:28 5278
}
4e9e2555 Poul Sander 2025-10-05 10:15 5279
IM_MSVC_RUNTIME_CHECKS_RESTORE
1193b4be Poul Sander 2025-02-03 21:28 5280
4e9e2555 Poul Sander 2025-10-05 10:15 5281
ImGuiID ImFontAtlasBakedGetId(ImGuiID font_id, float baked_size, float rasterizer_density)
1193b4be Poul Sander 2025-02-03 21:28 5282
{
4e9e2555 Poul Sander 2025-10-05 10:15 5283
    struct { ImGuiID FontId; float BakedSize; float RasterizerDensity; } hashed_data;
4e9e2555 Poul Sander 2025-10-05 10:15 5284
    hashed_data.FontId = font_id;
4e9e2555 Poul Sander 2025-10-05 10:15 5285
    hashed_data.BakedSize = baked_size;
4e9e2555 Poul Sander 2025-10-05 10:15 5286
    hashed_data.RasterizerDensity = rasterizer_density;
4e9e2555 Poul Sander 2025-10-05 10:15 5287
    return ImHashData(&hashed_data, sizeof(hashed_data));
1193b4be Poul Sander 2025-02-03 21:28 5288
}
1193b4be Poul Sander 2025-02-03 21:28 5289
4e9e2555 Poul Sander 2025-10-05 10:15 5290
// ImFontBaked pointers are valid for the entire frame but shall never be kept between frames.
4e9e2555 Poul Sander 2025-10-05 10:15 5291
ImFontBaked* ImFont::GetFontBaked(float size, float density)
1193b4be Poul Sander 2025-02-03 21:28 5292
{
4e9e2555 Poul Sander 2025-10-05 10:15 5293
    ImFontBaked* baked = LastBaked;
4e9e2555 Poul Sander 2025-10-05 10:15 5294
4e9e2555 Poul Sander 2025-10-05 10:15 5295
    // Round font size
4e9e2555 Poul Sander 2025-10-05 10:15 5296
    // - ImGui::PushFont() will already round, but other paths calling GetFontBaked() directly also needs it (e.g. ImFontAtlasBuildPreloadAllGlyphRanges)
4e9e2555 Poul Sander 2025-10-05 10:15 5297
    size = ImGui::GetRoundedFontSize(size);
4e9e2555 Poul Sander 2025-10-05 10:15 5298
4e9e2555 Poul Sander 2025-10-05 10:15 5299
    if (density < 0.0f)
4e9e2555 Poul Sander 2025-10-05 10:15 5300
        density = CurrentRasterizerDensity;
4e9e2555 Poul Sander 2025-10-05 10:15 5301
    if (baked && baked->Size == size && baked->RasterizerDensity == density)
4e9e2555 Poul Sander 2025-10-05 10:15 5302
        return baked;
4e9e2555 Poul Sander 2025-10-05 10:15 5303
4e9e2555 Poul Sander 2025-10-05 10:15 5304
    ImFontAtlas* atlas = ContainerAtlas;
4e9e2555 Poul Sander 2025-10-05 10:15 5305
    ImFontAtlasBuilder* builder = atlas->Builder;
4e9e2555 Poul Sander 2025-10-05 10:15 5306
    baked = ImFontAtlasBakedGetOrAdd(atlas, this, size, density);
4e9e2555 Poul Sander 2025-10-05 10:15 5307
    if (baked == NULL)
1193b4be Poul Sander 2025-02-03 21:28 5308
        return NULL;
4e9e2555 Poul Sander 2025-10-05 10:15 5309
    baked->LastUsedFrame = builder->FrameCount;
4e9e2555 Poul Sander 2025-10-05 10:15 5310
    LastBaked = baked;
4e9e2555 Poul Sander 2025-10-05 10:15 5311
    return baked;
1193b4be Poul Sander 2025-02-03 21:28 5312
}
1193b4be Poul Sander 2025-02-03 21:28 5313
4e9e2555 Poul Sander 2025-10-05 10:15 5314
ImFontBaked* ImFontAtlasBakedGetOrAdd(ImFontAtlas* atlas, ImFont* font, float font_size, float font_rasterizer_density)
1193b4be Poul Sander 2025-02-03 21:28 5315
{
4e9e2555 Poul Sander 2025-10-05 10:15 5316
    // FIXME-NEWATLAS: Design for picking a nearest size based on some criteria?
4e9e2555 Poul Sander 2025-10-05 10:15 5317
    // FIXME-NEWATLAS: Altering font density won't work right away.
4e9e2555 Poul Sander 2025-10-05 10:15 5318
    IM_ASSERT(font_size > 0.0f && font_rasterizer_density > 0.0f);
4e9e2555 Poul Sander 2025-10-05 10:15 5319
    ImGuiID baked_id = ImFontAtlasBakedGetId(font->FontId, font_size, font_rasterizer_density);
4e9e2555 Poul Sander 2025-10-05 10:15 5320
    ImFontAtlasBuilder* builder = atlas->Builder;
4e9e2555 Poul Sander 2025-10-05 10:15 5321
    ImFontBaked** p_baked_in_map = (ImFontBaked**)builder->BakedMap.GetVoidPtrRef(baked_id);
4e9e2555 Poul Sander 2025-10-05 10:15 5322
    ImFontBaked* baked = *p_baked_in_map;
4e9e2555 Poul Sander 2025-10-05 10:15 5323
    if (baked != NULL)
4e9e2555 Poul Sander 2025-10-05 10:15 5324
    {
4e9e2555 Poul Sander 2025-10-05 10:15 5325
        IM_ASSERT(baked->Size == font_size && baked->ContainerFont == font && baked->BakedId == baked_id);
4e9e2555 Poul Sander 2025-10-05 10:15 5326
        return baked;
4e9e2555 Poul Sander 2025-10-05 10:15 5327
    }
4e9e2555 Poul Sander 2025-10-05 10:15 5328
4e9e2555 Poul Sander 2025-10-05 10:15 5329
    // If atlas is locked, find closest match
4e9e2555 Poul Sander 2025-10-05 10:15 5330
    // FIXME-OPT: This is not an optimal query.
4e9e2555 Poul Sander 2025-10-05 10:15 5331
    if ((font->Flags & ImFontFlags_LockBakedSizes) || atlas->Locked)
4e9e2555 Poul Sander 2025-10-05 10:15 5332
    {
4e9e2555 Poul Sander 2025-10-05 10:15 5333
        baked = ImFontAtlasBakedGetClosestMatch(atlas, font, font_size, font_rasterizer_density);
4e9e2555 Poul Sander 2025-10-05 10:15 5334
        if (baked != NULL)
4e9e2555 Poul Sander 2025-10-05 10:15 5335
            return baked;
4e9e2555 Poul Sander 2025-10-05 10:15 5336
        if (atlas->Locked)
4e9e2555 Poul Sander 2025-10-05 10:15 5337
        {
4e9e2555 Poul Sander 2025-10-05 10:15 5338
            IM_ASSERT(!atlas->Locked && "Cannot use dynamic font size with a locked ImFontAtlas!"); // Locked because rendering backend does not support ImGuiBackendFlags_RendererHasTextures!
4e9e2555 Poul Sander 2025-10-05 10:15 5339
            return NULL;
4e9e2555 Poul Sander 2025-10-05 10:15 5340
        }
4e9e2555 Poul Sander 2025-10-05 10:15 5341
    }
4e9e2555 Poul Sander 2025-10-05 10:15 5342
4e9e2555 Poul Sander 2025-10-05 10:15 5343
    // Create new
4e9e2555 Poul Sander 2025-10-05 10:15 5344
    baked = ImFontAtlasBakedAdd(atlas, font, font_size, font_rasterizer_density, baked_id);
4e9e2555 Poul Sander 2025-10-05 10:15 5345
    *p_baked_in_map = baked; // To avoid 'builder->BakedMap.SetVoidPtr(baked_id, baked);' while we can.
4e9e2555 Poul Sander 2025-10-05 10:15 5346
    return baked;
4e9e2555 Poul Sander 2025-10-05 10:15 5347
}
4e9e2555 Poul Sander 2025-10-05 10:15 5348
4e9e2555 Poul Sander 2025-10-05 10:15 5349
// Trim trailing space and find beginning of next line
4e9e2555 Poul Sander 2025-10-05 10:15 5350
const char* ImTextCalcWordWrapNextLineStart(const char* text, const char* text_end, ImDrawTextFlags flags)
4e9e2555 Poul Sander 2025-10-05 10:15 5351
{
4e9e2555 Poul Sander 2025-10-05 10:15 5352
    if ((flags & ImDrawTextFlags_WrapKeepBlanks) == 0)
4e9e2555 Poul Sander 2025-10-05 10:15 5353
        while (text < text_end && ImCharIsBlankA(*text))
4e9e2555 Poul Sander 2025-10-05 10:15 5354
            text++;
1193b4be Poul Sander 2025-02-03 21:28 5355
    if (*text == '\n')
1193b4be Poul Sander 2025-02-03 21:28 5356
        text++;
1193b4be Poul Sander 2025-02-03 21:28 5357
    return text;
1193b4be Poul Sander 2025-02-03 21:28 5358
}
1193b4be Poul Sander 2025-02-03 21:28 5359
1193b4be Poul Sander 2025-02-03 21:28 5360
// Simple word-wrapping for English, not full-featured. Please submit failing cases!
1193b4be Poul Sander 2025-02-03 21:28 5361
// 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 5362
// 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.)
4e9e2555 Poul Sander 2025-10-05 10:15 5363
const char* ImFontCalcWordWrapPositionEx(ImFont* font, float size, const char* text, const char* text_end, float wrap_width, ImDrawTextFlags flags)
1193b4be Poul Sander 2025-02-03 21:28 5364
{
1193b4be Poul Sander 2025-02-03 21:28 5365
    // For references, possible wrap point marked with ^
1193b4be Poul Sander 2025-02-03 21:28 5366
    //  "aaa bbb, ccc,ddd. eee   fff. ggg!"
1193b4be Poul Sander 2025-02-03 21:28 5367
    //      ^    ^    ^   ^   ^__    ^    ^
1193b4be Poul Sander 2025-02-03 21:28 5368
1193b4be Poul Sander 2025-02-03 21:28 5369
    // List of hardcoded separators: .,;!?'"
1193b4be Poul Sander 2025-02-03 21:28 5370
1193b4be Poul Sander 2025-02-03 21:28 5371
    // Skip extra blanks after a line returns (that includes not counting them in width computation)
1193b4be Poul Sander 2025-02-03 21:28 5372
    // e.g. "Hello    world" --> "Hello" "World"
1193b4be Poul Sander 2025-02-03 21:28 5373
1193b4be Poul Sander 2025-02-03 21:28 5374
    // Cut words that cannot possibly fit within one line.
1193b4be Poul Sander 2025-02-03 21:28 5375
    // e.g.: "The tropical fish" with ~5 characters worth of width --> "The tr" "opical" "fish"
4e9e2555 Poul Sander 2025-10-05 10:15 5376
4e9e2555 Poul Sander 2025-10-05 10:15 5377
    ImFontBaked* baked = font->GetFontBaked(size);
4e9e2555 Poul Sander 2025-10-05 10:15 5378
    const float scale = size / baked->Size;
4e9e2555 Poul Sander 2025-10-05 10:15 5379
1193b4be Poul Sander 2025-02-03 21:28 5380
    float line_width = 0.0f;
1193b4be Poul Sander 2025-02-03 21:28 5381
    float word_width = 0.0f;
1193b4be Poul Sander 2025-02-03 21:28 5382
    float blank_width = 0.0f;
1193b4be Poul Sander 2025-02-03 21:28 5383
    wrap_width /= scale; // We work with unscaled widths to avoid scaling every characters
1193b4be Poul Sander 2025-02-03 21:28 5384
1193b4be Poul Sander 2025-02-03 21:28 5385
    const char* word_end = text;
1193b4be Poul Sander 2025-02-03 21:28 5386
    const char* prev_word_end = NULL;
1193b4be Poul Sander 2025-02-03 21:28 5387
    bool inside_word = true;
1193b4be Poul Sander 2025-02-03 21:28 5388
1193b4be Poul Sander 2025-02-03 21:28 5389
    const char* s = text;
1193b4be Poul Sander 2025-02-03 21:28 5390
    IM_ASSERT(text_end != NULL);
1193b4be Poul Sander 2025-02-03 21:28 5391
    while (s < text_end)
1193b4be Poul Sander 2025-02-03 21:28 5392
    {
1193b4be Poul Sander 2025-02-03 21:28 5393
        unsigned int c = (unsigned int)*s;
1193b4be Poul Sander 2025-02-03 21:28 5394
        const char* next_s;
1193b4be Poul Sander 2025-02-03 21:28 5395
        if (c < 0x80)
1193b4be Poul Sander 2025-02-03 21:28 5396
            next_s = s + 1;
1193b4be Poul Sander 2025-02-03 21:28 5397
        else
1193b4be Poul Sander 2025-02-03 21:28 5398
            next_s = s + ImTextCharFromUtf8(&c, s, text_end);
1193b4be Poul Sander 2025-02-03 21:28 5399
1193b4be Poul Sander 2025-02-03 21:28 5400
        if (c < 32)
1193b4be Poul Sander 2025-02-03 21:28 5401
        {
1193b4be Poul Sander 2025-02-03 21:28 5402
            if (c == '\n')
4e9e2555 Poul Sander 2025-10-05 10:15 5403
                return s; // Direct return, skip "Wrap_width is too small to fit anything" path.
1193b4be Poul Sander 2025-02-03 21:28 5404
            if (c == '\r')
1193b4be Poul Sander 2025-02-03 21:28 5405
            {
1193b4be Poul Sander 2025-02-03 21:28 5406
                s = next_s;
1193b4be Poul Sander 2025-02-03 21:28 5407
                continue;
1193b4be Poul Sander 2025-02-03 21:28 5408
            }
1193b4be Poul Sander 2025-02-03 21:28 5409
        }
1193b4be Poul Sander 2025-02-03 21:28 5410
4e9e2555 Poul Sander 2025-10-05 10:15 5411
        // Optimized inline version of 'float char_width = GetCharAdvance((ImWchar)c);'
4e9e2555 Poul Sander 2025-10-05 10:15 5412
        float char_width = (c < (unsigned int)baked->IndexAdvanceX.Size) ? baked->IndexAdvanceX.Data[c] : -1.0f;
4e9e2555 Poul Sander 2025-10-05 10:15 5413
        if (char_width < 0.0f)
4e9e2555 Poul Sander 2025-10-05 10:15 5414
            char_width = BuildLoadGlyphGetAdvanceOrFallback(baked, c);
4e9e2555 Poul Sander 2025-10-05 10:15 5415
1193b4be Poul Sander 2025-02-03 21:28 5416
        if (ImCharIsBlankW(c))
1193b4be Poul Sander 2025-02-03 21:28 5417
        {
1193b4be Poul Sander 2025-02-03 21:28 5418
            if (inside_word)
1193b4be Poul Sander 2025-02-03 21:28 5419
            {
1193b4be Poul Sander 2025-02-03 21:28 5420
                line_width += blank_width;
1193b4be Poul Sander 2025-02-03 21:28 5421
                blank_width = 0.0f;
1193b4be Poul Sander 2025-02-03 21:28 5422
                word_end = s;
1193b4be Poul Sander 2025-02-03 21:28 5423
            }
1193b4be Poul Sander 2025-02-03 21:28 5424
            blank_width += char_width;
1193b4be Poul Sander 2025-02-03 21:28 5425
            inside_word = false;
1193b4be Poul Sander 2025-02-03 21:28 5426
        }
1193b4be Poul Sander 2025-02-03 21:28 5427
        else
1193b4be Poul Sander 2025-02-03 21:28 5428
        {
1193b4be Poul Sander 2025-02-03 21:28 5429
            word_width += char_width;
1193b4be Poul Sander 2025-02-03 21:28 5430
            if (inside_word)
1193b4be Poul Sander 2025-02-03 21:28 5431
            {
1193b4be Poul Sander 2025-02-03 21:28 5432
                word_end = next_s;
1193b4be Poul Sander 2025-02-03 21:28 5433
            }
1193b4be Poul Sander 2025-02-03 21:28 5434
            else
1193b4be Poul Sander 2025-02-03 21:28 5435
            {
1193b4be Poul Sander 2025-02-03 21:28 5436
                prev_word_end = word_end;
1193b4be Poul Sander 2025-02-03 21:28 5437
                line_width += word_width + blank_width;
4e9e2555 Poul Sander 2025-10-05 10:15 5438
                if ((flags & ImDrawTextFlags_WrapKeepBlanks) && line_width <= wrap_width)
4e9e2555 Poul Sander 2025-10-05 10:15 5439
                    prev_word_end = s;
1193b4be Poul Sander 2025-02-03 21:28 5440
                word_width = blank_width = 0.0f;
1193b4be Poul Sander 2025-02-03 21:28 5441
            }
1193b4be Poul Sander 2025-02-03 21:28 5442
1193b4be Poul Sander 2025-02-03 21:28 5443
            // Allow wrapping after punctuation.
4e9e2555 Poul Sander 2025-10-05 10:15 5444
            inside_word = (c != '.' && c != ',' && c != ';' && c != '!' && c != '?' && c != '\"' && c != 0x3001 && c != 0x3002);
1193b4be Poul Sander 2025-02-03 21:28 5445
        }
1193b4be Poul Sander 2025-02-03 21:28 5446
1193b4be Poul Sander 2025-02-03 21:28 5447
        // We ignore blank width at the end of the line (they can be skipped)
1193b4be Poul Sander 2025-02-03 21:28 5448
        if (line_width + word_width > wrap_width)
1193b4be Poul Sander 2025-02-03 21:28 5449
        {
1193b4be Poul Sander 2025-02-03 21:28 5450
            // Words that cannot possibly fit within an entire line will be cut anywhere.
1193b4be Poul Sander 2025-02-03 21:28 5451
            if (word_width < wrap_width)
1193b4be Poul Sander 2025-02-03 21:28 5452
                s = prev_word_end ? prev_word_end : word_end;
1193b4be Poul Sander 2025-02-03 21:28 5453
            break;
1193b4be Poul Sander 2025-02-03 21:28 5454
        }
1193b4be Poul Sander 2025-02-03 21:28 5455
1193b4be Poul Sander 2025-02-03 21:28 5456
        s = next_s;
1193b4be Poul Sander 2025-02-03 21:28 5457
    }
1193b4be Poul Sander 2025-02-03 21:28 5458
1193b4be Poul Sander 2025-02-03 21:28 5459
    // 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 5460
    // +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 5461
    if (s == text && text < text_end)
4e9e2555 Poul Sander 2025-10-05 10:15 5462
        return s + ImTextCountUtf8BytesFromChar(s, text_end);
1193b4be Poul Sander 2025-02-03 21:28 5463
    return s;
1193b4be Poul Sander 2025-02-03 21:28 5464
}
1193b4be Poul Sander 2025-02-03 21:28 5465
4e9e2555 Poul Sander 2025-10-05 10:15 5466
const char* ImFont::CalcWordWrapPosition(float size, const char* text, const char* text_end, float wrap_width)
4e9e2555 Poul Sander 2025-10-05 10:15 5467
{
4e9e2555 Poul Sander 2025-10-05 10:15 5468
    return ImFontCalcWordWrapPositionEx(this, size, text, text_end, wrap_width, ImDrawTextFlags_None);
4e9e2555 Poul Sander 2025-10-05 10:15 5469
}
4e9e2555 Poul Sander 2025-10-05 10:15 5470
4e9e2555 Poul Sander 2025-10-05 10:15 5471
ImVec2 ImFontCalcTextSizeEx(ImFont* font, float size, float max_width, float wrap_width, const char* text_begin, const char* text_end_display, const char* text_end, const char** out_remaining, ImVec2* out_offset, ImDrawTextFlags flags)
1193b4be Poul Sander 2025-02-03 21:28 5472
{
1193b4be Poul Sander 2025-02-03 21:28 5473
    if (!text_end)
4e9e2555 Poul Sander 2025-10-05 10:15 5474
        text_end = text_begin + ImStrlen(text_begin); // FIXME-OPT: Need to avoid this.
4e9e2555 Poul Sander 2025-10-05 10:15 5475
    if (!text_end_display)
4e9e2555 Poul Sander 2025-10-05 10:15 5476
        text_end_display = text_end;
1193b4be Poul Sander 2025-02-03 21:28 5477
4e9e2555 Poul Sander 2025-10-05 10:15 5478
    ImFontBaked* baked = font->GetFontBaked(size);
1193b4be Poul Sander 2025-02-03 21:28 5479
    const float line_height = size;
4e9e2555 Poul Sander 2025-10-05 10:15 5480
    const float scale = line_height / baked->Size;
1193b4be Poul Sander 2025-02-03 21:28 5481
1193b4be Poul Sander 2025-02-03 21:28 5482
    ImVec2 text_size = ImVec2(0, 0);
1193b4be Poul Sander 2025-02-03 21:28 5483
    float line_width = 0.0f;
1193b4be Poul Sander 2025-02-03 21:28 5484
1193b4be Poul Sander 2025-02-03 21:28 5485
    const bool word_wrap_enabled = (wrap_width > 0.0f);
1193b4be Poul Sander 2025-02-03 21:28 5486
    const char* word_wrap_eol = NULL;
1193b4be Poul Sander 2025-02-03 21:28 5487
1193b4be Poul Sander 2025-02-03 21:28 5488
    const char* s = text_begin;
4e9e2555 Poul Sander 2025-10-05 10:15 5489
    while (s < text_end_display)
1193b4be Poul Sander 2025-02-03 21:28 5490
    {
4e9e2555 Poul Sander 2025-10-05 10:15 5491
        // Word-wrapping
1193b4be Poul Sander 2025-02-03 21:28 5492
        if (word_wrap_enabled)
1193b4be Poul Sander 2025-02-03 21:28 5493
        {
1193b4be Poul Sander 2025-02-03 21:28 5494
            // 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 5495
            if (!word_wrap_eol)
4e9e2555 Poul Sander 2025-10-05 10:15 5496
                word_wrap_eol = ImFontCalcWordWrapPositionEx(font, size, s, text_end, wrap_width - line_width, flags);
1193b4be Poul Sander 2025-02-03 21:28 5497
1193b4be Poul Sander 2025-02-03 21:28 5498
            if (s >= word_wrap_eol)
1193b4be Poul Sander 2025-02-03 21:28 5499
            {
1193b4be Poul Sander 2025-02-03 21:28 5500
                if (text_size.x < line_width)
1193b4be Poul Sander 2025-02-03 21:28 5501
                    text_size.x = line_width;
1193b4be Poul Sander 2025-02-03 21:28 5502
                text_size.y += line_height;
1193b4be Poul Sander 2025-02-03 21:28 5503
                line_width = 0.0f;
4e9e2555 Poul Sander 2025-10-05 10:15 5504
                s = ImTextCalcWordWrapNextLineStart(s, text_end, flags); // Wrapping skips upcoming blanks
4e9e2555 Poul Sander 2025-10-05 10:15 5505
                if (flags & ImDrawTextFlags_StopOnNewLine)
4e9e2555 Poul Sander 2025-10-05 10:15 5506
                    break;
1193b4be Poul Sander 2025-02-03 21:28 5507
                word_wrap_eol = NULL;
1193b4be Poul Sander 2025-02-03 21:28 5508
                continue;
1193b4be Poul Sander 2025-02-03 21:28 5509
            }
1193b4be Poul Sander 2025-02-03 21:28 5510
        }
1193b4be Poul Sander 2025-02-03 21:28 5511
1193b4be Poul Sander 2025-02-03 21:28 5512
        // Decode and advance source
1193b4be Poul Sander 2025-02-03 21:28 5513
        const char* prev_s = s;
1193b4be Poul Sander 2025-02-03 21:28 5514
        unsigned int c = (unsigned int)*s;
1193b4be Poul Sander 2025-02-03 21:28 5515
        if (c < 0x80)
1193b4be Poul Sander 2025-02-03 21:28 5516
            s += 1;
1193b4be Poul Sander 2025-02-03 21:28 5517
        else
1193b4be Poul Sander 2025-02-03 21:28 5518
            s += ImTextCharFromUtf8(&c, s, text_end);
1193b4be Poul Sander 2025-02-03 21:28 5519
4e9e2555 Poul Sander 2025-10-05 10:15 5520
        if (c == '\n')
1193b4be Poul Sander 2025-02-03 21:28 5521
        {
4e9e2555 Poul Sander 2025-10-05 10:15 5522
            text_size.x = ImMax(text_size.x, line_width);
4e9e2555 Poul Sander 2025-10-05 10:15 5523
            text_size.y += line_height;
4e9e2555 Poul Sander 2025-10-05 10:15 5524
            line_width = 0.0f;
4e9e2555 Poul Sander 2025-10-05 10:15 5525
            if (flags & ImDrawTextFlags_StopOnNewLine)
4e9e2555 Poul Sander 2025-10-05 10:15 5526
                break;
4e9e2555 Poul Sander 2025-10-05 10:15 5527
            continue;
1193b4be Poul Sander 2025-02-03 21:28 5528
        }
4e9e2555 Poul Sander 2025-10-05 10:15 5529
        if (c == '\r')
4e9e2555 Poul Sander 2025-10-05 10:15 5530
            continue;
4e9e2555 Poul Sander 2025-10-05 10:15 5531
4e9e2555 Poul Sander 2025-10-05 10:15 5532
        // Optimized inline version of 'float char_width = GetCharAdvance((ImWchar)c);'
4e9e2555 Poul Sander 2025-10-05 10:15 5533
        float char_width = (c < (unsigned int)baked->IndexAdvanceX.Size) ? baked->IndexAdvanceX.Data[c] : -1.0f;
4e9e2555 Poul Sander 2025-10-05 10:15 5534
        if (char_width < 0.0f)
4e9e2555 Poul Sander 2025-10-05 10:15 5535
            char_width = BuildLoadGlyphGetAdvanceOrFallback(baked, c);
4e9e2555 Poul Sander 2025-10-05 10:15 5536
        char_width *= scale;
1193b4be Poul Sander 2025-02-03 21:28 5537
1193b4be Poul Sander 2025-02-03 21:28 5538
        if (line_width + char_width >= max_width)
1193b4be Poul Sander 2025-02-03 21:28 5539
        {
1193b4be Poul Sander 2025-02-03 21:28 5540
            s = prev_s;
1193b4be Poul Sander 2025-02-03 21:28 5541
            break;
1193b4be Poul Sander 2025-02-03 21:28 5542
        }
1193b4be Poul Sander 2025-02-03 21:28 5543
1193b4be Poul Sander 2025-02-03 21:28 5544
        line_width += char_width;
1193b4be Poul Sander 2025-02-03 21:28 5545
    }
1193b4be Poul Sander 2025-02-03 21:28 5546
1193b4be Poul Sander 2025-02-03 21:28 5547
    if (text_size.x < line_width)
1193b4be Poul Sander 2025-02-03 21:28 5548
        text_size.x = line_width;
1193b4be Poul Sander 2025-02-03 21:28 5549
4e9e2555 Poul Sander 2025-10-05 10:15 5550
    if (out_offset != NULL)
4e9e2555 Poul Sander 2025-10-05 10:15 5551
        *out_offset = ImVec2(line_width, text_size.y + line_height);  // offset allow for the possibility of sitting after a trailing \n
4e9e2555 Poul Sander 2025-10-05 10:15 5552
4e9e2555 Poul Sander 2025-10-05 10:15 5553
    if (line_width > 0 || text_size.y == 0.0f)                        // whereas size.y will ignore the trailing \n
1193b4be Poul Sander 2025-02-03 21:28 5554
        text_size.y += line_height;
1193b4be Poul Sander 2025-02-03 21:28 5555
4e9e2555 Poul Sander 2025-10-05 10:15 5556
    if (out_remaining != NULL)
4e9e2555 Poul Sander 2025-10-05 10:15 5557
        *out_remaining = s;
1193b4be Poul Sander 2025-02-03 21:28 5558
1193b4be Poul Sander 2025-02-03 21:28 5559
    return text_size;
1193b4be Poul Sander 2025-02-03 21:28 5560
}
1193b4be Poul Sander 2025-02-03 21:28 5561
4e9e2555 Poul Sander 2025-10-05 10:15 5562
ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end, const char** out_remaining)
4e9e2555 Poul Sander 2025-10-05 10:15 5563
{
4e9e2555 Poul Sander 2025-10-05 10:15 5564
    return ImFontCalcTextSizeEx(this, size, max_width, wrap_width, text_begin, text_end, text_end, out_remaining, NULL, ImDrawTextFlags_None);
4e9e2555 Poul Sander 2025-10-05 10:15 5565
}
4e9e2555 Poul Sander 2025-10-05 10:15 5566
1193b4be Poul Sander 2025-02-03 21:28 5567
// Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound.
4e9e2555 Poul Sander 2025-10-05 10:15 5568
void ImFont::RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, ImWchar c, const ImVec4* cpu_fine_clip)
1193b4be Poul Sander 2025-02-03 21:28 5569
{
4e9e2555 Poul Sander 2025-10-05 10:15 5570
    ImFontBaked* baked = GetFontBaked(size);
4e9e2555 Poul Sander 2025-10-05 10:15 5571
    const ImFontGlyph* glyph = baked->FindGlyph(c);
1193b4be Poul Sander 2025-02-03 21:28 5572
    if (!glyph || !glyph->Visible)
1193b4be Poul Sander 2025-02-03 21:28 5573
        return;
1193b4be Poul Sander 2025-02-03 21:28 5574
    if (glyph->Colored)
1193b4be Poul Sander 2025-02-03 21:28 5575
        col |= ~IM_COL32_A_MASK;
4e9e2555 Poul Sander 2025-10-05 10:15 5576
    float scale = (size >= 0.0f) ? (size / baked->Size) : 1.0f;
1193b4be Poul Sander 2025-02-03 21:28 5577
    float x = IM_TRUNC(pos.x);
1193b4be Poul Sander 2025-02-03 21:28 5578
    float y = IM_TRUNC(pos.y);
4e9e2555 Poul Sander 2025-10-05 10:15 5579
4e9e2555 Poul Sander 2025-10-05 10:15 5580
    float x1 = x + glyph->X0 * scale;
4e9e2555 Poul Sander 2025-10-05 10:15 5581
    float x2 = x + glyph->X1 * scale;
4e9e2555 Poul Sander 2025-10-05 10:15 5582
    if (cpu_fine_clip && (x1 > cpu_fine_clip->z || x2 < cpu_fine_clip->x))
4e9e2555 Poul Sander 2025-10-05 10:15 5583
        return;
4e9e2555 Poul Sander 2025-10-05 10:15 5584
    float y1 = y + glyph->Y0 * scale;
4e9e2555 Poul Sander 2025-10-05 10:15 5585
    float y2 = y + glyph->Y1 * scale;
4e9e2555 Poul Sander 2025-10-05 10:15 5586
    float u1 = glyph->U0;
4e9e2555 Poul Sander 2025-10-05 10:15 5587
    float v1 = glyph->V0;
4e9e2555 Poul Sander 2025-10-05 10:15 5588
    float u2 = glyph->U1;
4e9e2555 Poul Sander 2025-10-05 10:15 5589
    float v2 = glyph->V1;
4e9e2555 Poul Sander 2025-10-05 10:15 5590
4e9e2555 Poul Sander 2025-10-05 10:15 5591
    // Always CPU fine clip. Code extracted from RenderText().
4e9e2555 Poul Sander 2025-10-05 10:15 5592
    // CPU side clipping used to fit text in their frame when the frame is too small. Only does clipping for axis aligned quads.
4e9e2555 Poul Sander 2025-10-05 10:15 5593
    if (cpu_fine_clip != NULL)
4e9e2555 Poul Sander 2025-10-05 10:15 5594
    {
4e9e2555 Poul Sander 2025-10-05 10:15 5595
        if (x1 < cpu_fine_clip->x) { u1 = u1 + (1.0f - (x2 - cpu_fine_clip->x) / (x2 - x1)) * (u2 - u1); x1 = cpu_fine_clip->x; }
4e9e2555 Poul Sander 2025-10-05 10:15 5596
        if (y1 < cpu_fine_clip->y) { v1 = v1 + (1.0f - (y2 - cpu_fine_clip->y) / (y2 - y1)) * (v2 - v1); y1 = cpu_fine_clip->y; }
4e9e2555 Poul Sander 2025-10-05 10:15 5597
        if (x2 > cpu_fine_clip->z) { u2 = u1 + ((cpu_fine_clip->z - x1) / (x2 - x1)) * (u2 - u1); x2 = cpu_fine_clip->z; }
4e9e2555 Poul Sander 2025-10-05 10:15 5598
        if (y2 > cpu_fine_clip->w) { v2 = v1 + ((cpu_fine_clip->w - y1) / (y2 - y1)) * (v2 - v1); y2 = cpu_fine_clip->w; }
4e9e2555 Poul Sander 2025-10-05 10:15 5599
        if (y1 >= y2)
4e9e2555 Poul Sander 2025-10-05 10:15 5600
            return;
4e9e2555 Poul Sander 2025-10-05 10:15 5601
    }
1193b4be Poul Sander 2025-02-03 21:28 5602
    draw_list->PrimReserve(6, 4);
4e9e2555 Poul Sander 2025-10-05 10:15 5603
    draw_list->PrimRectUV(ImVec2(x1, y1), ImVec2(x2, y2), ImVec2(u1, v1), ImVec2(u2, v2), col);
1193b4be Poul Sander 2025-02-03 21:28 5604
}
1193b4be Poul Sander 2025-02-03 21:28 5605
1193b4be Poul Sander 2025-02-03 21:28 5606
// Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound.
4e9e2555 Poul Sander 2025-10-05 10:15 5607
// DO NOT CALL DIRECTLY THIS WILL CHANGE WIDLY IN 2025-2025. Use ImDrawList::AddText().
4e9e2555 Poul Sander 2025-10-05 10:15 5608
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, ImDrawTextFlags flags)
1193b4be Poul Sander 2025-02-03 21:28 5609
{
1193b4be Poul Sander 2025-02-03 21:28 5610
    // Align to be pixel perfect
4e9e2555 Poul Sander 2025-10-05 10:15 5611
begin:
1193b4be Poul Sander 2025-02-03 21:28 5612
    float x = IM_TRUNC(pos.x);
1193b4be Poul Sander 2025-02-03 21:28 5613
    float y = IM_TRUNC(pos.y);
1193b4be Poul Sander 2025-02-03 21:28 5614
    if (y > clip_rect.w)
1193b4be Poul Sander 2025-02-03 21:28 5615
        return;
1193b4be Poul Sander 2025-02-03 21:28 5616
4e9e2555 Poul Sander 2025-10-05 10:15 5617
    if (!text_end)
4e9e2555 Poul Sander 2025-10-05 10:15 5618
        text_end = text_begin + ImStrlen(text_begin); // ImGui:: functions generally already provides a valid text_end, so this is merely to handle direct calls.
4e9e2555 Poul Sander 2025-10-05 10:15 5619
4e9e2555 Poul Sander 2025-10-05 10:15 5620
    const float line_height = size;
4e9e2555 Poul Sander 2025-10-05 10:15 5621
    ImFontBaked* baked = GetFontBaked(size);
4e9e2555 Poul Sander 2025-10-05 10:15 5622
4e9e2555 Poul Sander 2025-10-05 10:15 5623
    const float scale = size / baked->Size;
4e9e2555 Poul Sander 2025-10-05 10:15 5624
    const float origin_x = x;
1193b4be Poul Sander 2025-02-03 21:28 5625
    const bool word_wrap_enabled = (wrap_width > 0.0f);
1193b4be Poul Sander 2025-02-03 21:28 5626
1193b4be Poul Sander 2025-02-03 21:28 5627
    // Fast-forward to first visible line
1193b4be Poul Sander 2025-02-03 21:28 5628
    const char* s = text_begin;
1193b4be Poul Sander 2025-02-03 21:28 5629
    if (y + line_height < clip_rect.y)
1193b4be Poul Sander 2025-02-03 21:28 5630
        while (y + line_height < clip_rect.y && s < text_end)
1193b4be Poul Sander 2025-02-03 21:28 5631
        {
4e9e2555 Poul Sander 2025-10-05 10:15 5632
            const char* line_end = (const char*)ImMemchr(s, '\n', text_end - s);
1193b4be Poul Sander 2025-02-03 21:28 5633
            if (word_wrap_enabled)
1193b4be Poul Sander 2025-02-03 21:28 5634
            {
4e9e2555 Poul Sander 2025-10-05 10:15 5635
                // FIXME-OPT: This is not optimal as do first do a search for \n before calling CalcWordWrapPosition().
4e9e2555 Poul Sander 2025-10-05 10:15 5636
                // If the specs for CalcWordWrapPosition() were reworked to optionally return on \n we could combine both.
1193b4be Poul Sander 2025-02-03 21:28 5637
                // However it is still better than nothing performing the fast-forward!
4e9e2555 Poul Sander 2025-10-05 10:15 5638
                s = ImFontCalcWordWrapPositionEx(this, size, s, line_end ? line_end : text_end, wrap_width, flags);
4e9e2555 Poul Sander 2025-10-05 10:15 5639
                s = ImTextCalcWordWrapNextLineStart(s, text_end, flags);
1193b4be Poul Sander 2025-02-03 21:28 5640
            }
1193b4be Poul Sander 2025-02-03 21:28 5641
            else
1193b4be Poul Sander 2025-02-03 21:28 5642
            {
1193b4be Poul Sander 2025-02-03 21:28 5643
                s = line_end ? line_end + 1 : text_end;
1193b4be Poul Sander 2025-02-03 21:28 5644
            }
1193b4be Poul Sander 2025-02-03 21:28 5645
            y += line_height;
1193b4be Poul Sander 2025-02-03 21:28 5646
        }
1193b4be Poul Sander 2025-02-03 21:28 5647
1193b4be Poul Sander 2025-02-03 21:28 5648
    // 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 5649
    // 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 5650
    if (text_end - s > 10000 && !word_wrap_enabled)
1193b4be Poul Sander 2025-02-03 21:28 5651
    {
1193b4be Poul Sander 2025-02-03 21:28 5652
        const char* s_end = s;
1193b4be Poul Sander 2025-02-03 21:28 5653
        float y_end = y;
1193b4be Poul Sander 2025-02-03 21:28 5654
        while (y_end < clip_rect.w && s_end < text_end)
1193b4be Poul Sander 2025-02-03 21:28 5655
        {
4e9e2555 Poul Sander 2025-10-05 10:15 5656
            s_end = (const char*)ImMemchr(s_end, '\n', text_end - s_end);
1193b4be Poul Sander 2025-02-03 21:28 5657
            s_end = s_end ? s_end + 1 : text_end;
1193b4be Poul Sander 2025-02-03 21:28 5658
            y_end += line_height;
1193b4be Poul Sander 2025-02-03 21:28 5659
        }
1193b4be Poul Sander 2025-02-03 21:28 5660
        text_end = s_end;
1193b4be Poul Sander 2025-02-03 21:28 5661
    }
1193b4be Poul Sander 2025-02-03 21:28 5662
    if (s == text_end)
1193b4be Poul Sander 2025-02-03 21:28 5663
        return;
1193b4be Poul Sander 2025-02-03 21:28 5664
1193b4be Poul Sander 2025-02-03 21:28 5665
    // Reserve vertices for remaining worse case (over-reserving is useful and easily amortized)
1193b4be Poul Sander 2025-02-03 21:28 5666
    const int vtx_count_max = (int)(text_end - s) * 4;
1193b4be Poul Sander 2025-02-03 21:28 5667
    const int idx_count_max = (int)(text_end - s) * 6;
1193b4be Poul Sander 2025-02-03 21:28 5668
    const int idx_expected_size = draw_list->IdxBuffer.Size + idx_count_max;
1193b4be Poul Sander 2025-02-03 21:28 5669
    draw_list->PrimReserve(idx_count_max, vtx_count_max);
1193b4be Poul Sander 2025-02-03 21:28 5670
    ImDrawVert*  vtx_write = draw_list->_VtxWritePtr;
1193b4be Poul Sander 2025-02-03 21:28 5671
    ImDrawIdx*   idx_write = draw_list->_IdxWritePtr;
1193b4be Poul Sander 2025-02-03 21:28 5672
    unsigned int vtx_index = draw_list->_VtxCurrentIdx;
4e9e2555 Poul Sander 2025-10-05 10:15 5673
    const int cmd_count = draw_list->CmdBuffer.Size;
4e9e2555 Poul Sander 2025-10-05 10:15 5674
    const bool cpu_fine_clip = (flags & ImDrawTextFlags_CpuFineClip) != 0;
1193b4be Poul Sander 2025-02-03 21:28 5675
1193b4be Poul Sander 2025-02-03 21:28 5676
    const ImU32 col_untinted = col | ~IM_COL32_A_MASK;
1193b4be Poul Sander 2025-02-03 21:28 5677
    const char* word_wrap_eol = NULL;
1193b4be Poul Sander 2025-02-03 21:28 5678
1193b4be Poul Sander 2025-02-03 21:28 5679
    while (s < text_end)
1193b4be Poul Sander 2025-02-03 21:28 5680
    {
1193b4be Poul Sander 2025-02-03 21:28 5681
        if (word_wrap_enabled)
1193b4be Poul Sander 2025-02-03 21:28 5682
        {
1193b4be Poul Sander 2025-02-03 21:28 5683
            // 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 5684
            if (!word_wrap_eol)
4e9e2555 Poul Sander 2025-10-05 10:15 5685
                word_wrap_eol = ImFontCalcWordWrapPositionEx(this, size, s, text_end, wrap_width - (x - origin_x), flags);
1193b4be Poul Sander 2025-02-03 21:28 5686
1193b4be Poul Sander 2025-02-03 21:28 5687
            if (s >= word_wrap_eol)
1193b4be Poul Sander 2025-02-03 21:28 5688
            {
4e9e2555 Poul Sander 2025-10-05 10:15 5689
                x = origin_x;
1193b4be Poul Sander 2025-02-03 21:28 5690
                y += line_height;
1193b4be Poul Sander 2025-02-03 21:28 5691
                if (y > clip_rect.w)
1193b4be Poul Sander 2025-02-03 21:28 5692
                    break; // break out of main loop
1193b4be Poul Sander 2025-02-03 21:28 5693
                word_wrap_eol = NULL;
4e9e2555 Poul Sander 2025-10-05 10:15 5694
                s = ImTextCalcWordWrapNextLineStart(s, text_end, flags); // Wrapping skips upcoming blanks
1193b4be Poul Sander 2025-02-03 21:28 5695
                continue;
1193b4be Poul Sander 2025-02-03 21:28 5696
            }
1193b4be Poul Sander 2025-02-03 21:28 5697
        }
1193b4be Poul Sander 2025-02-03 21:28 5698
1193b4be Poul Sander 2025-02-03 21:28 5699
        // Decode and advance source
1193b4be Poul Sander 2025-02-03 21:28 5700
        unsigned int c = (unsigned int)*s;
1193b4be Poul Sander 2025-02-03 21:28 5701
        if (c < 0x80)
1193b4be Poul Sander 2025-02-03 21:28 5702
            s += 1;
1193b4be Poul Sander 2025-02-03 21:28 5703
        else
1193b4be Poul Sander 2025-02-03 21:28 5704
            s += ImTextCharFromUtf8(&c, s, text_end);
1193b4be Poul Sander 2025-02-03 21:28 5705
1193b4be Poul Sander 2025-02-03 21:28 5706
        if (c < 32)
1193b4be Poul Sander 2025-02-03 21:28 5707
        {
1193b4be Poul Sander 2025-02-03 21:28 5708
            if (c == '\n')
1193b4be Poul Sander 2025-02-03 21:28 5709
            {
4e9e2555 Poul Sander 2025-10-05 10:15 5710
                x = origin_x;
1193b4be Poul Sander 2025-02-03 21:28 5711
                y += line_height;
1193b4be Poul Sander 2025-02-03 21:28 5712
                if (y > clip_rect.w)
1193b4be Poul Sander 2025-02-03 21:28 5713
                    break; // break out of main loop
1193b4be Poul Sander 2025-02-03 21:28 5714
                continue;
1193b4be Poul Sander 2025-02-03 21:28 5715
            }
1193b4be Poul Sander 2025-02-03 21:28 5716
            if (c == '\r')
1193b4be Poul Sander 2025-02-03 21:28 5717
                continue;
1193b4be Poul Sander 2025-02-03 21:28 5718
        }
1193b4be Poul Sander 2025-02-03 21:28 5719
4e9e2555 Poul Sander 2025-10-05 10:15 5720
        const ImFontGlyph* glyph = baked->FindGlyph((ImWchar)c);
4e9e2555 Poul Sander 2025-10-05 10:15 5721
        //if (glyph == NULL)
4e9e2555 Poul Sander 2025-10-05 10:15 5722
        //    continue;
1193b4be Poul Sander 2025-02-03 21:28 5723
1193b4be Poul Sander 2025-02-03 21:28 5724
        float char_width = glyph->AdvanceX * scale;
1193b4be Poul Sander 2025-02-03 21:28 5725
        if (glyph->Visible)
1193b4be Poul Sander 2025-02-03 21:28 5726
        {
1193b4be Poul Sander 2025-02-03 21:28 5727
            // 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 5728
            float x1 = x + glyph->X0 * scale;
1193b4be Poul Sander 2025-02-03 21:28 5729
            float x2 = x + glyph->X1 * scale;
1193b4be Poul Sander 2025-02-03 21:28 5730
            float y1 = y + glyph->Y0 * scale;
1193b4be Poul Sander 2025-02-03 21:28 5731
            float y2 = y + glyph->Y1 * scale;
1193b4be Poul Sander 2025-02-03 21:28 5732
            if (x1 <= clip_rect.z && x2 >= clip_rect.x)
1193b4be Poul Sander 2025-02-03 21:28 5733
            {
1193b4be Poul Sander 2025-02-03 21:28 5734
                // Render a character
1193b4be Poul Sander 2025-02-03 21:28 5735
                float u1 = glyph->U0;
1193b4be Poul Sander 2025-02-03 21:28 5736
                float v1 = glyph->V0;
1193b4be Poul Sander 2025-02-03 21:28 5737
                float u2 = glyph->U1;
1193b4be Poul Sander 2025-02-03 21:28 5738
                float v2 = glyph->V1;
1193b4be Poul Sander 2025-02-03 21:28 5739
1193b4be Poul Sander 2025-02-03 21:28 5740
                // 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 5741
                if (cpu_fine_clip)
1193b4be Poul Sander 2025-02-03 21:28 5742
                {
1193b4be Poul Sander 2025-02-03 21:28 5743
                    if (x1 < clip_rect.x)
1193b4be Poul Sander 2025-02-03 21:28 5744
                    {
1193b4be Poul Sander 2025-02-03 21:28 5745
                        u1 = u1 + (1.0f - (x2 - clip_rect.x) / (x2 - x1)) * (u2 - u1);
1193b4be Poul Sander 2025-02-03 21:28 5746
                        x1 = clip_rect.x;
1193b4be Poul Sander 2025-02-03 21:28 5747
                    }
1193b4be Poul Sander 2025-02-03 21:28 5748
                    if (y1 < clip_rect.y)
1193b4be Poul Sander 2025-02-03 21:28 5749
                    {
1193b4be Poul Sander 2025-02-03 21:28 5750
                        v1 = v1 + (1.0f - (y2 - clip_rect.y) / (y2 - y1)) * (v2 - v1);
1193b4be Poul Sander 2025-02-03 21:28 5751
                        y1 = clip_rect.y;
1193b4be Poul Sander 2025-02-03 21:28 5752
                    }
1193b4be Poul Sander 2025-02-03 21:28 5753
                    if (x2 > clip_rect.z)
1193b4be Poul Sander 2025-02-03 21:28 5754
                    {
1193b4be Poul Sander 2025-02-03 21:28 5755
                        u2 = u1 + ((clip_rect.z - x1) / (x2 - x1)) * (u2 - u1);
1193b4be Poul Sander 2025-02-03 21:28 5756
                        x2 = clip_rect.z;
1193b4be Poul Sander 2025-02-03 21:28 5757
                    }
1193b4be Poul Sander 2025-02-03 21:28 5758
                    if (y2 > clip_rect.w)
1193b4be Poul Sander 2025-02-03 21:28 5759
                    {
1193b4be Poul Sander 2025-02-03 21:28 5760
                        v2 = v1 + ((clip_rect.w - y1) / (y2 - y1)) * (v2 - v1);
1193b4be Poul Sander 2025-02-03 21:28 5761
                        y2 = clip_rect.w;
1193b4be Poul Sander 2025-02-03 21:28 5762
                    }
1193b4be Poul Sander 2025-02-03 21:28 5763
                    if (y1 >= y2)
1193b4be Poul Sander 2025-02-03 21:28 5764
                    {
1193b4be Poul Sander 2025-02-03 21:28 5765
                        x += char_width;
1193b4be Poul Sander 2025-02-03 21:28 5766
                        continue;
1193b4be Poul Sander 2025-02-03 21:28 5767
                    }
1193b4be Poul Sander 2025-02-03 21:28 5768
                }
1193b4be Poul Sander 2025-02-03 21:28 5769
1193b4be Poul Sander 2025-02-03 21:28 5770
                // Support for untinted glyphs
1193b4be Poul Sander 2025-02-03 21:28 5771
                ImU32 glyph_col = glyph->Colored ? col_untinted : col;
1193b4be Poul Sander 2025-02-03 21:28 5772
1193b4be Poul Sander 2025-02-03 21:28 5773
                // 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 5774
                {
1193b4be Poul Sander 2025-02-03 21:28 5775
                    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 5776
                    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 5777
                    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 5778
                    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 5779
                    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 5780
                    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 5781
                    vtx_write += 4;
1193b4be Poul Sander 2025-02-03 21:28 5782
                    vtx_index += 4;
1193b4be Poul Sander 2025-02-03 21:28 5783
                    idx_write += 6;
1193b4be Poul Sander 2025-02-03 21:28 5784
                }
1193b4be Poul Sander 2025-02-03 21:28 5785
            }
1193b4be Poul Sander 2025-02-03 21:28 5786
        }
1193b4be Poul Sander 2025-02-03 21:28 5787
        x += char_width;
1193b4be Poul Sander 2025-02-03 21:28 5788
    }
1193b4be Poul Sander 2025-02-03 21:28 5789
4e9e2555 Poul Sander 2025-10-05 10:15 5790
    // Edge case: calling RenderText() with unloaded glyphs triggering texture change. It doesn't happen via ImGui:: calls because CalcTextSize() is always used.
4e9e2555 Poul Sander 2025-10-05 10:15 5791
    if (cmd_count != draw_list->CmdBuffer.Size) //-V547
4e9e2555 Poul Sander 2025-10-05 10:15 5792
    {
4e9e2555 Poul Sander 2025-10-05 10:15 5793
        IM_ASSERT(draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 1].ElemCount == 0);
4e9e2555 Poul Sander 2025-10-05 10:15 5794
        draw_list->CmdBuffer.pop_back();
4e9e2555 Poul Sander 2025-10-05 10:15 5795
        draw_list->PrimUnreserve(idx_count_max, vtx_count_max);
4e9e2555 Poul Sander 2025-10-05 10:15 5796
        draw_list->AddDrawCmd();
4e9e2555 Poul Sander 2025-10-05 10:15 5797
        //IMGUI_DEBUG_LOG("RenderText: cancel and retry to missing glyphs.\n"); // [DEBUG]
4e9e2555 Poul Sander 2025-10-05 10:15 5798
        //draw_list->AddRectFilled(pos, pos + ImVec2(10, 10), IM_COL32(255, 0, 0, 255)); // [DEBUG]
4e9e2555 Poul Sander 2025-10-05 10:15 5799
        goto begin;
4e9e2555 Poul Sander 2025-10-05 10:15 5800
        //RenderText(draw_list, size, pos, col, clip_rect, text_begin, text_end, wrap_width, cpu_fine_clip); // FIXME-OPT: Would a 'goto begin' be better for code-gen?
4e9e2555 Poul Sander 2025-10-05 10:15 5801
        //return;
4e9e2555 Poul Sander 2025-10-05 10:15 5802
    }
4e9e2555 Poul Sander 2025-10-05 10:15 5803
1193b4be Poul Sander 2025-02-03 21:28 5804
    // Give back unused vertices (clipped ones, blanks) ~ this is essentially a PrimUnreserve() action.
1193b4be Poul Sander 2025-02-03 21:28 5805
    draw_list->VtxBuffer.Size = (int)(vtx_write - draw_list->VtxBuffer.Data); // Same as calling shrink()
1193b4be Poul Sander 2025-02-03 21:28 5806
    draw_list->IdxBuffer.Size = (int)(idx_write - draw_list->IdxBuffer.Data);
1193b4be Poul Sander 2025-02-03 21:28 5807
    draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 1].ElemCount -= (idx_expected_size - draw_list->IdxBuffer.Size);
1193b4be Poul Sander 2025-02-03 21:28 5808
    draw_list->_VtxWritePtr = vtx_write;
1193b4be Poul Sander 2025-02-03 21:28 5809
    draw_list->_IdxWritePtr = idx_write;
1193b4be Poul Sander 2025-02-03 21:28 5810
    draw_list->_VtxCurrentIdx = vtx_index;
1193b4be Poul Sander 2025-02-03 21:28 5811
}
1193b4be Poul Sander 2025-02-03 21:28 5812
1193b4be Poul Sander 2025-02-03 21:28 5813
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 5814
// [SECTION] ImGui Internal Render Helpers
1193b4be Poul Sander 2025-02-03 21:28 5815
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 5816
// Vaguely redesigned to stop accessing ImGui global state:
1193b4be Poul Sander 2025-02-03 21:28 5817
// - RenderArrow()
1193b4be Poul Sander 2025-02-03 21:28 5818
// - RenderBullet()
1193b4be Poul Sander 2025-02-03 21:28 5819
// - RenderCheckMark()
1193b4be Poul Sander 2025-02-03 21:28 5820
// - RenderArrowDockMenu()
1193b4be Poul Sander 2025-02-03 21:28 5821
// - RenderArrowPointingAt()
1193b4be Poul Sander 2025-02-03 21:28 5822
// - RenderRectFilledRangeH()
1193b4be Poul Sander 2025-02-03 21:28 5823
// - RenderRectFilledWithHole()
1193b4be Poul Sander 2025-02-03 21:28 5824
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 5825
// Function in need of a redesign (legacy mess)
1193b4be Poul Sander 2025-02-03 21:28 5826
// - RenderColorRectWithAlphaCheckerboard()
1193b4be Poul Sander 2025-02-03 21:28 5827
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 5828
1193b4be Poul Sander 2025-02-03 21:28 5829
// 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 5830
void ImGui::RenderArrow(ImDrawList* draw_list, ImVec2 pos, ImU32 col, ImGuiDir dir, float scale)
1193b4be Poul Sander 2025-02-03 21:28 5831
{
1193b4be Poul Sander 2025-02-03 21:28 5832
    const float h = draw_list->_Data->FontSize * 1.00f;
1193b4be Poul Sander 2025-02-03 21:28 5833
    float r = h * 0.40f * scale;
1193b4be Poul Sander 2025-02-03 21:28 5834
    ImVec2 center = pos + ImVec2(h * 0.50f, h * 0.50f * scale);
1193b4be Poul Sander 2025-02-03 21:28 5835
1193b4be Poul Sander 2025-02-03 21:28 5836
    ImVec2 a, b, c;
1193b4be Poul Sander 2025-02-03 21:28 5837
    switch (dir)
1193b4be Poul Sander 2025-02-03 21:28 5838
    {
1193b4be Poul Sander 2025-02-03 21:28 5839
    case ImGuiDir_Up:
1193b4be Poul Sander 2025-02-03 21:28 5840
    case ImGuiDir_Down:
1193b4be Poul Sander 2025-02-03 21:28 5841
        if (dir == ImGuiDir_Up) r = -r;
1193b4be Poul Sander 2025-02-03 21:28 5842
        a = ImVec2(+0.000f, +0.750f) * r;
1193b4be Poul Sander 2025-02-03 21:28 5843
        b = ImVec2(-0.866f, -0.750f) * r;
1193b4be Poul Sander 2025-02-03 21:28 5844
        c = ImVec2(+0.866f, -0.750f) * r;
1193b4be Poul Sander 2025-02-03 21:28 5845
        break;
1193b4be Poul Sander 2025-02-03 21:28 5846
    case ImGuiDir_Left:
1193b4be Poul Sander 2025-02-03 21:28 5847
    case ImGuiDir_Right:
1193b4be Poul Sander 2025-02-03 21:28 5848
        if (dir == ImGuiDir_Left) r = -r;
1193b4be Poul Sander 2025-02-03 21:28 5849
        a = ImVec2(+0.750f, +0.000f) * r;
1193b4be Poul Sander 2025-02-03 21:28 5850
        b = ImVec2(-0.750f, +0.866f) * r;
1193b4be Poul Sander 2025-02-03 21:28 5851
        c = ImVec2(-0.750f, -0.866f) * r;
1193b4be Poul Sander 2025-02-03 21:28 5852
        break;
1193b4be Poul Sander 2025-02-03 21:28 5853
    case ImGuiDir_None:
1193b4be Poul Sander 2025-02-03 21:28 5854
    case ImGuiDir_COUNT:
1193b4be Poul Sander 2025-02-03 21:28 5855
        IM_ASSERT(0);
1193b4be Poul Sander 2025-02-03 21:28 5856
        break;
1193b4be Poul Sander 2025-02-03 21:28 5857
    }
1193b4be Poul Sander 2025-02-03 21:28 5858
    draw_list->AddTriangleFilled(center + a, center + b, center + c, col);
1193b4be Poul Sander 2025-02-03 21:28 5859
}
1193b4be Poul Sander 2025-02-03 21:28 5860
1193b4be Poul Sander 2025-02-03 21:28 5861
void ImGui::RenderBullet(ImDrawList* draw_list, ImVec2 pos, ImU32 col)
1193b4be Poul Sander 2025-02-03 21:28 5862
{
4e9e2555 Poul Sander 2025-10-05 10:15 5863
    // FIXME-OPT: This should be baked in font now that it's easier.
4e9e2555 Poul Sander 2025-10-05 10:15 5864
    float font_size = draw_list->_Data->FontSize;
4e9e2555 Poul Sander 2025-10-05 10:15 5865
    draw_list->AddCircleFilled(pos, font_size * 0.20f, col, (font_size < 22) ? 8 : (font_size < 40) ? 12 : 0); // Hardcode optimal/nice tessellation threshold
1193b4be Poul Sander 2025-02-03 21:28 5866
}
1193b4be Poul Sander 2025-02-03 21:28 5867
1193b4be Poul Sander 2025-02-03 21:28 5868
void ImGui::RenderCheckMark(ImDrawList* draw_list, ImVec2 pos, ImU32 col, float sz)
1193b4be Poul Sander 2025-02-03 21:28 5869
{
1193b4be Poul Sander 2025-02-03 21:28 5870
    float thickness = ImMax(sz / 5.0f, 1.0f);
1193b4be Poul Sander 2025-02-03 21:28 5871
    sz -= thickness * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 5872
    pos += ImVec2(thickness * 0.25f, thickness * 0.25f);
1193b4be Poul Sander 2025-02-03 21:28 5873
1193b4be Poul Sander 2025-02-03 21:28 5874
    float third = sz / 3.0f;
1193b4be Poul Sander 2025-02-03 21:28 5875
    float bx = pos.x + third;
1193b4be Poul Sander 2025-02-03 21:28 5876
    float by = pos.y + sz - third * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 5877
    draw_list->PathLineTo(ImVec2(bx - third, by - third));
1193b4be Poul Sander 2025-02-03 21:28 5878
    draw_list->PathLineTo(ImVec2(bx, by));
1193b4be Poul Sander 2025-02-03 21:28 5879
    draw_list->PathLineTo(ImVec2(bx + third * 2.0f, by - third * 2.0f));
1193b4be Poul Sander 2025-02-03 21:28 5880
    draw_list->PathStroke(col, 0, thickness);
1193b4be Poul Sander 2025-02-03 21:28 5881
}
1193b4be Poul Sander 2025-02-03 21:28 5882
1193b4be Poul Sander 2025-02-03 21:28 5883
// 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 5884
void ImGui::RenderArrowPointingAt(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col)
1193b4be Poul Sander 2025-02-03 21:28 5885
{
1193b4be Poul Sander 2025-02-03 21:28 5886
    switch (direction)
1193b4be Poul Sander 2025-02-03 21:28 5887
    {
1193b4be Poul Sander 2025-02-03 21:28 5888
    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 5889
    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 5890
    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 5891
    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 5892
    case ImGuiDir_None: case ImGuiDir_COUNT: break; // Fix warnings
1193b4be Poul Sander 2025-02-03 21:28 5893
    }
1193b4be Poul Sander 2025-02-03 21:28 5894
}
1193b4be Poul Sander 2025-02-03 21:28 5895
1193b4be Poul Sander 2025-02-03 21:28 5896
// 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 5897
// 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 5898
void ImGui::RenderArrowDockMenu(ImDrawList* draw_list, ImVec2 p_min, float sz, ImU32 col)
1193b4be Poul Sander 2025-02-03 21:28 5899
{
1193b4be Poul Sander 2025-02-03 21:28 5900
    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 5901
    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 5902
}
1193b4be Poul Sander 2025-02-03 21:28 5903
1193b4be Poul Sander 2025-02-03 21:28 5904
static inline float ImAcos01(float x)
1193b4be Poul Sander 2025-02-03 21:28 5905
{
1193b4be Poul Sander 2025-02-03 21:28 5906
    if (x <= 0.0f) return IM_PI * 0.5f;
1193b4be Poul Sander 2025-02-03 21:28 5907
    if (x >= 1.0f) return 0.0f;
1193b4be Poul Sander 2025-02-03 21:28 5908
    return ImAcos(x);
1193b4be Poul Sander 2025-02-03 21:28 5909
    //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 5910
}
1193b4be Poul Sander 2025-02-03 21:28 5911
1193b4be Poul Sander 2025-02-03 21:28 5912
// FIXME: Cleanup and move code to ImDrawList.
1193b4be Poul Sander 2025-02-03 21:28 5913
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 5914
{
1193b4be Poul Sander 2025-02-03 21:28 5915
    if (x_end_norm == x_start_norm)
1193b4be Poul Sander 2025-02-03 21:28 5916
        return;
1193b4be Poul Sander 2025-02-03 21:28 5917
    if (x_start_norm > x_end_norm)
1193b4be Poul Sander 2025-02-03 21:28 5918
        ImSwap(x_start_norm, x_end_norm);
1193b4be Poul Sander 2025-02-03 21:28 5919
1193b4be Poul Sander 2025-02-03 21:28 5920
    ImVec2 p0 = ImVec2(ImLerp(rect.Min.x, rect.Max.x, x_start_norm), rect.Min.y);
1193b4be Poul Sander 2025-02-03 21:28 5921
    ImVec2 p1 = ImVec2(ImLerp(rect.Min.x, rect.Max.x, x_end_norm), rect.Max.y);
1193b4be Poul Sander 2025-02-03 21:28 5922
    if (rounding == 0.0f)
1193b4be Poul Sander 2025-02-03 21:28 5923
    {
1193b4be Poul Sander 2025-02-03 21:28 5924
        draw_list->AddRectFilled(p0, p1, col, 0.0f);
1193b4be Poul Sander 2025-02-03 21:28 5925
        return;
1193b4be Poul Sander 2025-02-03 21:28 5926
    }
1193b4be Poul Sander 2025-02-03 21:28 5927
1193b4be Poul Sander 2025-02-03 21:28 5928
    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 5929
    const float inv_rounding = 1.0f / rounding;
1193b4be Poul Sander 2025-02-03 21:28 5930
    const float arc0_b = ImAcos01(1.0f - (p0.x - rect.Min.x) * inv_rounding);
1193b4be Poul Sander 2025-02-03 21:28 5931
    const float arc0_e = ImAcos01(1.0f - (p1.x - rect.Min.x) * inv_rounding);
1193b4be Poul Sander 2025-02-03 21:28 5932
    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 5933
    const float x0 = ImMax(p0.x, rect.Min.x + rounding);
1193b4be Poul Sander 2025-02-03 21:28 5934
    if (arc0_b == arc0_e)
1193b4be Poul Sander 2025-02-03 21:28 5935
    {
1193b4be Poul Sander 2025-02-03 21:28 5936
        draw_list->PathLineTo(ImVec2(x0, p1.y));
1193b4be Poul Sander 2025-02-03 21:28 5937
        draw_list->PathLineTo(ImVec2(x0, p0.y));
1193b4be Poul Sander 2025-02-03 21:28 5938
    }
1193b4be Poul Sander 2025-02-03 21:28 5939
    else if (arc0_b == 0.0f && arc0_e == half_pi)
1193b4be Poul Sander 2025-02-03 21:28 5940
    {
1193b4be Poul Sander 2025-02-03 21:28 5941
        draw_list->PathArcToFast(ImVec2(x0, p1.y - rounding), rounding, 3, 6); // BL
1193b4be Poul Sander 2025-02-03 21:28 5942
        draw_list->PathArcToFast(ImVec2(x0, p0.y + rounding), rounding, 6, 9); // TR
1193b4be Poul Sander 2025-02-03 21:28 5943
    }
1193b4be Poul Sander 2025-02-03 21:28 5944
    else
1193b4be Poul Sander 2025-02-03 21:28 5945
    {
1193b4be Poul Sander 2025-02-03 21:28 5946
        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 5947
        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 5948
    }
1193b4be Poul Sander 2025-02-03 21:28 5949
    if (p1.x > rect.Min.x + rounding)
1193b4be Poul Sander 2025-02-03 21:28 5950
    {
1193b4be Poul Sander 2025-02-03 21:28 5951
        const float arc1_b = ImAcos01(1.0f - (rect.Max.x - p1.x) * inv_rounding);
1193b4be Poul Sander 2025-02-03 21:28 5952
        const float arc1_e = ImAcos01(1.0f - (rect.Max.x - p0.x) * inv_rounding);
1193b4be Poul Sander 2025-02-03 21:28 5953
        const float x1 = ImMin(p1.x, rect.Max.x - rounding);
1193b4be Poul Sander 2025-02-03 21:28 5954
        if (arc1_b == arc1_e)
1193b4be Poul Sander 2025-02-03 21:28 5955
        {
1193b4be Poul Sander 2025-02-03 21:28 5956
            draw_list->PathLineTo(ImVec2(x1, p0.y));
1193b4be Poul Sander 2025-02-03 21:28 5957
            draw_list->PathLineTo(ImVec2(x1, p1.y));
1193b4be Poul Sander 2025-02-03 21:28 5958
        }
1193b4be Poul Sander 2025-02-03 21:28 5959
        else if (arc1_b == 0.0f && arc1_e == half_pi)
1193b4be Poul Sander 2025-02-03 21:28 5960
        {
1193b4be Poul Sander 2025-02-03 21:28 5961
            draw_list->PathArcToFast(ImVec2(x1, p0.y + rounding), rounding, 9, 12); // TR
1193b4be Poul Sander 2025-02-03 21:28 5962
            draw_list->PathArcToFast(ImVec2(x1, p1.y - rounding), rounding, 0, 3);  // BR
1193b4be Poul Sander 2025-02-03 21:28 5963
        }
1193b4be Poul Sander 2025-02-03 21:28 5964
        else
1193b4be Poul Sander 2025-02-03 21:28 5965
        {
1193b4be Poul Sander 2025-02-03 21:28 5966
            draw_list->PathArcTo(ImVec2(x1, p0.y + rounding), rounding, -arc1_e, -arc1_b); // TR
1193b4be Poul Sander 2025-02-03 21:28 5967
            draw_list->PathArcTo(ImVec2(x1, p1.y - rounding), rounding, +arc1_b, +arc1_e); // BR
1193b4be Poul Sander 2025-02-03 21:28 5968
        }
1193b4be Poul Sander 2025-02-03 21:28 5969
    }
1193b4be Poul Sander 2025-02-03 21:28 5970
    draw_list->PathFillConvex(col);
1193b4be Poul Sander 2025-02-03 21:28 5971
}
1193b4be Poul Sander 2025-02-03 21:28 5972
1193b4be Poul Sander 2025-02-03 21:28 5973
void ImGui::RenderRectFilledWithHole(ImDrawList* draw_list, const ImRect& outer, const ImRect& inner, ImU32 col, float rounding)
1193b4be Poul Sander 2025-02-03 21:28 5974
{
1193b4be Poul Sander 2025-02-03 21:28 5975
    const bool fill_L = (inner.Min.x > outer.Min.x);
1193b4be Poul Sander 2025-02-03 21:28 5976
    const bool fill_R = (inner.Max.x < outer.Max.x);
1193b4be Poul Sander 2025-02-03 21:28 5977
    const bool fill_U = (inner.Min.y > outer.Min.y);
1193b4be Poul Sander 2025-02-03 21:28 5978
    const bool fill_D = (inner.Max.y < outer.Max.y);
1193b4be Poul Sander 2025-02-03 21:28 5979
    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 5980
    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 5981
    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 5982
    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 5983
    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 5984
    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 5985
    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 5986
    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 5987
}
1193b4be Poul Sander 2025-02-03 21:28 5988
1193b4be Poul Sander 2025-02-03 21:28 5989
ImDrawFlags ImGui::CalcRoundingFlagsForRectInRect(const ImRect& r_in, const ImRect& r_outer, float threshold)
1193b4be Poul Sander 2025-02-03 21:28 5990
{
1193b4be Poul Sander 2025-02-03 21:28 5991
    bool round_l = r_in.Min.x <= r_outer.Min.x + threshold;
1193b4be Poul Sander 2025-02-03 21:28 5992
    bool round_r = r_in.Max.x >= r_outer.Max.x - threshold;
1193b4be Poul Sander 2025-02-03 21:28 5993
    bool round_t = r_in.Min.y <= r_outer.Min.y + threshold;
1193b4be Poul Sander 2025-02-03 21:28 5994
    bool round_b = r_in.Max.y >= r_outer.Max.y - threshold;
1193b4be Poul Sander 2025-02-03 21:28 5995
    return ImDrawFlags_RoundCornersNone
1193b4be Poul Sander 2025-02-03 21:28 5996
        | ((round_t && round_l) ? ImDrawFlags_RoundCornersTopLeft : 0) | ((round_t && round_r) ? ImDrawFlags_RoundCornersTopRight : 0)
1193b4be Poul Sander 2025-02-03 21:28 5997
        | ((round_b && round_l) ? ImDrawFlags_RoundCornersBottomLeft : 0) | ((round_b && round_r) ? ImDrawFlags_RoundCornersBottomRight : 0);
1193b4be Poul Sander 2025-02-03 21:28 5998
}
1193b4be Poul Sander 2025-02-03 21:28 5999
1193b4be Poul Sander 2025-02-03 21:28 6000
// Helper for ColorPicker4()
1193b4be Poul Sander 2025-02-03 21:28 6001
// 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 6002
// 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 6003
// FIXME: uses ImGui::GetColorU32
1193b4be Poul Sander 2025-02-03 21:28 6004
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 6005
{
1193b4be Poul Sander 2025-02-03 21:28 6006
    if ((flags & ImDrawFlags_RoundCornersMask_) == 0)
1193b4be Poul Sander 2025-02-03 21:28 6007
        flags = ImDrawFlags_RoundCornersDefault_;
1193b4be Poul Sander 2025-02-03 21:28 6008
    if (((col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT) < 0xFF)
1193b4be Poul Sander 2025-02-03 21:28 6009
    {
1193b4be Poul Sander 2025-02-03 21:28 6010
        ImU32 col_bg1 = GetColorU32(ImAlphaBlendColors(IM_COL32(204, 204, 204, 255), col));
1193b4be Poul Sander 2025-02-03 21:28 6011
        ImU32 col_bg2 = GetColorU32(ImAlphaBlendColors(IM_COL32(128, 128, 128, 255), col));
1193b4be Poul Sander 2025-02-03 21:28 6012
        draw_list->AddRectFilled(p_min, p_max, col_bg1, rounding, flags);
1193b4be Poul Sander 2025-02-03 21:28 6013
1193b4be Poul Sander 2025-02-03 21:28 6014
        int yi = 0;
1193b4be Poul Sander 2025-02-03 21:28 6015
        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 6016
        {
1193b4be Poul Sander 2025-02-03 21:28 6017
            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 6018
            if (y2 <= y1)
1193b4be Poul Sander 2025-02-03 21:28 6019
                continue;
1193b4be Poul Sander 2025-02-03 21:28 6020
            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 6021
            {
1193b4be Poul Sander 2025-02-03 21:28 6022
                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 6023
                if (x2 <= x1)
1193b4be Poul Sander 2025-02-03 21:28 6024
                    continue;
1193b4be Poul Sander 2025-02-03 21:28 6025
                ImDrawFlags cell_flags = ImDrawFlags_RoundCornersNone;
1193b4be Poul Sander 2025-02-03 21:28 6026
                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 6027
                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 6028
1193b4be Poul Sander 2025-02-03 21:28 6029
                // Combine flags
1193b4be Poul Sander 2025-02-03 21:28 6030
                cell_flags = (flags == ImDrawFlags_RoundCornersNone || cell_flags == ImDrawFlags_RoundCornersNone) ? ImDrawFlags_RoundCornersNone : (cell_flags & flags);
1193b4be Poul Sander 2025-02-03 21:28 6031
                draw_list->AddRectFilled(ImVec2(x1, y1), ImVec2(x2, y2), col_bg2, rounding, cell_flags);
1193b4be Poul Sander 2025-02-03 21:28 6032
            }
1193b4be Poul Sander 2025-02-03 21:28 6033
        }
1193b4be Poul Sander 2025-02-03 21:28 6034
    }
1193b4be Poul Sander 2025-02-03 21:28 6035
    else
1193b4be Poul Sander 2025-02-03 21:28 6036
    {
1193b4be Poul Sander 2025-02-03 21:28 6037
        draw_list->AddRectFilled(p_min, p_max, col, rounding, flags);
1193b4be Poul Sander 2025-02-03 21:28 6038
    }
1193b4be Poul Sander 2025-02-03 21:28 6039
}
1193b4be Poul Sander 2025-02-03 21:28 6040
1193b4be Poul Sander 2025-02-03 21:28 6041
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 6042
// [SECTION] Decompression code
1193b4be Poul Sander 2025-02-03 21:28 6043
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 6044
// Compressed with stb_compress() then converted to a C array and encoded as base85.
1193b4be Poul Sander 2025-02-03 21:28 6045
// 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 6046
// 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 6047
// 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 6048
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 6049
1193b4be Poul Sander 2025-02-03 21:28 6050
static unsigned int stb_decompress_length(const unsigned char *input)
1193b4be Poul Sander 2025-02-03 21:28 6051
{
1193b4be Poul Sander 2025-02-03 21:28 6052
    return (input[8] << 24) + (input[9] << 16) + (input[10] << 8) + input[11];
1193b4be Poul Sander 2025-02-03 21:28 6053
}
1193b4be Poul Sander 2025-02-03 21:28 6054
1193b4be Poul Sander 2025-02-03 21:28 6055
static unsigned char *stb__barrier_out_e, *stb__barrier_out_b;
1193b4be Poul Sander 2025-02-03 21:28 6056
static const unsigned char *stb__barrier_in_b;
1193b4be Poul Sander 2025-02-03 21:28 6057
static unsigned char *stb__dout;
1193b4be Poul Sander 2025-02-03 21:28 6058
static void stb__match(const unsigned char *data, unsigned int length)
1193b4be Poul Sander 2025-02-03 21:28 6059
{
1193b4be Poul Sander 2025-02-03 21:28 6060
    // INVERSE of memmove... write each byte before copying the next...
1193b4be Poul Sander 2025-02-03 21:28 6061
    IM_ASSERT(stb__dout + length <= stb__barrier_out_e);
1193b4be Poul Sander 2025-02-03 21:28 6062
    if (stb__dout + length > stb__barrier_out_e) { stb__dout += length; return; }
1193b4be Poul Sander 2025-02-03 21:28 6063
    if (data < stb__barrier_out_b) { stb__dout = stb__barrier_out_e+1; return; }
1193b4be Poul Sander 2025-02-03 21:28 6064
    while (length--) *stb__dout++ = *data++;
1193b4be Poul Sander 2025-02-03 21:28 6065
}
1193b4be Poul Sander 2025-02-03 21:28 6066
1193b4be Poul Sander 2025-02-03 21:28 6067
static void stb__lit(const unsigned char *data, unsigned int length)
1193b4be Poul Sander 2025-02-03 21:28 6068
{
1193b4be Poul Sander 2025-02-03 21:28 6069
    IM_ASSERT(stb__dout + length <= stb__barrier_out_e);
1193b4be Poul Sander 2025-02-03 21:28 6070
    if (stb__dout + length > stb__barrier_out_e) { stb__dout += length; return; }
1193b4be Poul Sander 2025-02-03 21:28 6071
    if (data < stb__barrier_in_b) { stb__dout = stb__barrier_out_e+1; return; }
1193b4be Poul Sander 2025-02-03 21:28 6072
    memcpy(stb__dout, data, length);
1193b4be Poul Sander 2025-02-03 21:28 6073
    stb__dout += length;
1193b4be Poul Sander 2025-02-03 21:28 6074
}
1193b4be Poul Sander 2025-02-03 21:28 6075
1193b4be Poul Sander 2025-02-03 21:28 6076
#define stb__in2(x)   ((i[x] << 8) + i[(x)+1])
1193b4be Poul Sander 2025-02-03 21:28 6077
#define stb__in3(x)   ((i[x] << 16) + stb__in2((x)+1))
1193b4be Poul Sander 2025-02-03 21:28 6078
#define stb__in4(x)   ((i[x] << 24) + stb__in3((x)+1))
1193b4be Poul Sander 2025-02-03 21:28 6079
1193b4be Poul Sander 2025-02-03 21:28 6080
static const unsigned char *stb_decompress_token(const unsigned char *i)
1193b4be Poul Sander 2025-02-03 21:28 6081
{
1193b4be Poul Sander 2025-02-03 21:28 6082
    if (*i >= 0x20) { // use fewer if's for cases that expand small
1193b4be Poul Sander 2025-02-03 21:28 6083
        if (*i >= 0x80)       stb__match(stb__dout-i[1]-1, i[0] - 0x80 + 1), i += 2;
1193b4be Poul Sander 2025-02-03 21:28 6084
        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 6085
        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 6086
    } else { // more ifs for cases that expand large, since overhead is amortized
1193b4be Poul Sander 2025-02-03 21:28 6087
        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 6088
        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 6089
        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 6090
        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 6091
        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 6092
        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 6093
    }
1193b4be Poul Sander 2025-02-03 21:28 6094
    return i;
1193b4be Poul Sander 2025-02-03 21:28 6095
}
1193b4be Poul Sander 2025-02-03 21:28 6096
1193b4be Poul Sander 2025-02-03 21:28 6097
static unsigned int stb_adler32(unsigned int adler32, unsigned char *buffer, unsigned int buflen)
1193b4be Poul Sander 2025-02-03 21:28 6098
{
1193b4be Poul Sander 2025-02-03 21:28 6099
    const unsigned long ADLER_MOD = 65521;
1193b4be Poul Sander 2025-02-03 21:28 6100
    unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16;
1193b4be Poul Sander 2025-02-03 21:28 6101
    unsigned long blocklen = buflen % 5552;
1193b4be Poul Sander 2025-02-03 21:28 6102
1193b4be Poul Sander 2025-02-03 21:28 6103
    unsigned long i;
1193b4be Poul Sander 2025-02-03 21:28 6104
    while (buflen) {
1193b4be Poul Sander 2025-02-03 21:28 6105
        for (i=0; i + 7 < blocklen; i += 8) {
1193b4be Poul Sander 2025-02-03 21:28 6106
            s1 += buffer[0], s2 += s1;
1193b4be Poul Sander 2025-02-03 21:28 6107
            s1 += buffer[1], s2 += s1;
1193b4be Poul Sander 2025-02-03 21:28 6108
            s1 += buffer[2], s2 += s1;
1193b4be Poul Sander 2025-02-03 21:28 6109
            s1 += buffer[3], s2 += s1;
1193b4be Poul Sander 2025-02-03 21:28 6110
            s1 += buffer[4], s2 += s1;
1193b4be Poul Sander 2025-02-03 21:28 6111
            s1 += buffer[5], s2 += s1;
1193b4be Poul Sander 2025-02-03 21:28 6112
            s1 += buffer[6], s2 += s1;
1193b4be Poul Sander 2025-02-03 21:28 6113
            s1 += buffer[7], s2 += s1;
1193b4be Poul Sander 2025-02-03 21:28 6114
1193b4be Poul Sander 2025-02-03 21:28 6115
            buffer += 8;
1193b4be Poul Sander 2025-02-03 21:28 6116
        }
1193b4be Poul Sander 2025-02-03 21:28 6117
1193b4be Poul Sander 2025-02-03 21:28 6118
        for (; i < blocklen; ++i)
1193b4be Poul Sander 2025-02-03 21:28 6119
            s1 += *buffer++, s2 += s1;
1193b4be Poul Sander 2025-02-03 21:28 6120
1193b4be Poul Sander 2025-02-03 21:28 6121
        s1 %= ADLER_MOD, s2 %= ADLER_MOD;
1193b4be Poul Sander 2025-02-03 21:28 6122
        buflen -= blocklen;
1193b4be Poul Sander 2025-02-03 21:28 6123
        blocklen = 5552;
1193b4be Poul Sander 2025-02-03 21:28 6124
    }
1193b4be Poul Sander 2025-02-03 21:28 6125
    return (unsigned int)(s2 << 16) + (unsigned int)s1;
1193b4be Poul Sander 2025-02-03 21:28 6126
}
1193b4be Poul Sander 2025-02-03 21:28 6127
1193b4be Poul Sander 2025-02-03 21:28 6128
static unsigned int stb_decompress(unsigned char *output, const unsigned char *i, unsigned int /*length*/)
1193b4be Poul Sander 2025-02-03 21:28 6129
{
1193b4be Poul Sander 2025-02-03 21:28 6130
    if (stb__in4(0) != 0x57bC0000) return 0;
1193b4be Poul Sander 2025-02-03 21:28 6131
    if (stb__in4(4) != 0)          return 0; // error! stream is > 4GB
1193b4be Poul Sander 2025-02-03 21:28 6132
    const unsigned int olen = stb_decompress_length(i);
1193b4be Poul Sander 2025-02-03 21:28 6133
    stb__barrier_in_b = i;
1193b4be Poul Sander 2025-02-03 21:28 6134
    stb__barrier_out_e = output + olen;
1193b4be Poul Sander 2025-02-03 21:28 6135
    stb__barrier_out_b = output;
1193b4be Poul Sander 2025-02-03 21:28 6136
    i += 16;
1193b4be Poul Sander 2025-02-03 21:28 6137
1193b4be Poul Sander 2025-02-03 21:28 6138
    stb__dout = output;
1193b4be Poul Sander 2025-02-03 21:28 6139
    for (;;) {
1193b4be Poul Sander 2025-02-03 21:28 6140
        const unsigned char *old_i = i;
1193b4be Poul Sander 2025-02-03 21:28 6141
        i = stb_decompress_token(i);
1193b4be Poul Sander 2025-02-03 21:28 6142
        if (i == old_i) {
1193b4be Poul Sander 2025-02-03 21:28 6143
            if (*i == 0x05 && i[1] == 0xfa) {
1193b4be Poul Sander 2025-02-03 21:28 6144
                IM_ASSERT(stb__dout == output + olen);
1193b4be Poul Sander 2025-02-03 21:28 6145
                if (stb__dout != output + olen) return 0;
1193b4be Poul Sander 2025-02-03 21:28 6146
                if (stb_adler32(1, output, olen) != (unsigned int) stb__in4(2))
1193b4be Poul Sander 2025-02-03 21:28 6147
                    return 0;
1193b4be Poul Sander 2025-02-03 21:28 6148
                return olen;
1193b4be Poul Sander 2025-02-03 21:28 6149
            } else {
1193b4be Poul Sander 2025-02-03 21:28 6150
                IM_ASSERT(0); /* NOTREACHED */
1193b4be Poul Sander 2025-02-03 21:28 6151
                return 0;
1193b4be Poul Sander 2025-02-03 21:28 6152
            }
1193b4be Poul Sander 2025-02-03 21:28 6153
        }
1193b4be Poul Sander 2025-02-03 21:28 6154
        IM_ASSERT(stb__dout <= output + olen);
1193b4be Poul Sander 2025-02-03 21:28 6155
        if (stb__dout > output + olen)
1193b4be Poul Sander 2025-02-03 21:28 6156
            return 0;
1193b4be Poul Sander 2025-02-03 21:28 6157
    }
1193b4be Poul Sander 2025-02-03 21:28 6158
}
1193b4be Poul Sander 2025-02-03 21:28 6159
1193b4be Poul Sander 2025-02-03 21:28 6160
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 6161
// [SECTION] Default font data (ProggyClean.ttf)
1193b4be Poul Sander 2025-02-03 21:28 6162
//-----------------------------------------------------------------------------
1193b4be Poul Sander 2025-02-03 21:28 6163
// ProggyClean.ttf
1193b4be Poul Sander 2025-02-03 21:28 6164
// Copyright (c) 2004, 2005 Tristan Grimmer
1193b4be Poul Sander 2025-02-03 21:28 6165
// MIT license (see License.txt in http://www.proggyfonts.net/index.php?menu=download)
1193b4be Poul Sander 2025-02-03 21:28 6166
// Download and more information at http://www.proggyfonts.net or http://upperboundsinteractive.com/fonts.php
4e9e2555 Poul Sander 2025-10-05 10:15 6167
// If you want a similar font which may be better scaled, consider using ProggyVector from the same author!
1193b4be Poul Sander 2025-02-03 21:28 6168
//-----------------------------------------------------------------------------
4e9e2555 Poul Sander 2025-10-05 10:15 6169
4e9e2555 Poul Sander 2025-10-05 10:15 6170
#ifndef IMGUI_DISABLE_DEFAULT_FONT
4e9e2555 Poul Sander 2025-10-05 10:15 6171
1193b4be Poul Sander 2025-02-03 21:28 6172
// File: 'ProggyClean.ttf' (41208 bytes)
4e9e2555 Poul Sander 2025-10-05 10:15 6173
// Exported using binary_to_compressed_c.exe -u8 "ProggyClean.ttf" proggy_clean_ttf
4e9e2555 Poul Sander 2025-10-05 10:15 6174
static const unsigned int proggy_clean_ttf_compressed_size = 9583;
4e9e2555 Poul Sander 2025-10-05 10:15 6175
static const unsigned char proggy_clean_ttf_compressed_data[9583] =
4e9e2555 Poul Sander 2025-10-05 10:15 6176
{
4e9e2555 Poul Sander 2025-10-05 10:15 6177
    87,188,0,0,0,0,0,0,0,0,160,248,0,4,0,0,55,0,1,0,0,0,12,0,128,0,3,0,64,79,83,47,50,136,235,116,144,0,0,1,72,130,21,44,78,99,109,97,112,2,18,35,117,0,0,3,160,130,19,36,82,99,118,116,
4e9e2555 Poul Sander 2025-10-05 10:15 6178
    32,130,23,130,2,33,4,252,130,4,56,2,103,108,121,102,18,175,137,86,0,0,7,4,0,0,146,128,104,101,97,100,215,145,102,211,130,27,32,204,130,3,33,54,104,130,16,39,8,66,1,195,0,0,1,4,130,
4e9e2555 Poul Sander 2025-10-05 10:15 6179
    15,59,36,104,109,116,120,138,0,126,128,0,0,1,152,0,0,2,6,108,111,99,97,140,115,176,216,0,0,5,130,30,41,2,4,109,97,120,112,1,174,0,218,130,31,32,40,130,16,44,32,110,97,109,101,37,89,
4e9e2555 Poul Sander 2025-10-05 10:15 6180
    187,150,0,0,153,132,130,19,44,158,112,111,115,116,166,172,131,239,0,0,155,36,130,51,44,210,112,114,101,112,105,2,1,18,0,0,4,244,130,47,32,8,132,203,46,1,0,0,60,85,233,213,95,15,60,
4e9e2555 Poul Sander 2025-10-05 10:15 6181
    245,0,3,8,0,131,0,34,183,103,119,130,63,43,0,0,189,146,166,215,0,0,254,128,3,128,131,111,130,241,33,2,0,133,0,32,1,130,65,38,192,254,64,0,0,3,128,131,16,130,5,32,1,131,7,138,3,33,2,
4e9e2555 Poul Sander 2025-10-05 10:15 6182
    0,130,17,36,1,1,0,144,0,130,121,130,23,38,2,0,8,0,64,0,10,130,9,32,118,130,9,130,6,32,0,130,59,33,1,144,131,200,35,2,188,2,138,130,16,32,143,133,7,37,1,197,0,50,2,0,131,0,33,4,9,131,
4e9e2555 Poul Sander 2025-10-05 10:15 6183
    5,145,3,43,65,108,116,115,0,64,0,0,32,172,8,0,131,0,35,5,0,1,128,131,77,131,3,33,3,128,191,1,33,1,128,130,184,35,0,0,128,0,130,3,131,11,32,1,130,7,33,0,128,131,1,32,1,136,9,32,0,132,
4e9e2555 Poul Sander 2025-10-05 10:15 6184
    15,135,5,32,1,131,13,135,27,144,35,32,1,149,25,131,21,32,0,130,0,32,128,132,103,130,35,132,39,32,0,136,45,136,97,133,17,130,5,33,0,0,136,19,34,0,128,1,133,13,133,5,32,128,130,15,132,
4e9e2555 Poul Sander 2025-10-05 10:15 6185
    131,32,3,130,5,32,3,132,27,144,71,32,0,133,27,130,29,130,31,136,29,131,63,131,3,65,63,5,132,5,132,205,130,9,33,0,0,131,9,137,119,32,3,132,19,138,243,130,55,32,1,132,35,135,19,131,201,
4e9e2555 Poul Sander 2025-10-05 10:15 6186
    136,11,132,143,137,13,130,41,32,0,131,3,144,35,33,128,0,135,1,131,223,131,3,141,17,134,13,136,63,134,15,136,53,143,15,130,96,33,0,3,131,4,130,3,34,28,0,1,130,5,34,0,0,76,130,17,131,
4e9e2555 Poul Sander 2025-10-05 10:15 6187
    9,36,28,0,4,0,48,130,17,46,8,0,8,0,2,0,0,0,127,0,255,32,172,255,255,130,9,34,0,0,129,132,9,130,102,33,223,213,134,53,132,22,33,1,6,132,6,64,4,215,32,129,165,216,39,177,0,1,141,184,
4e9e2555 Poul Sander 2025-10-05 10:15 6188
    1,255,133,134,45,33,198,0,193,1,8,190,244,1,28,1,158,2,20,2,136,2,252,3,20,3,88,3,156,3,222,4,20,4,50,4,80,4,98,4,162,5,22,5,102,5,188,6,18,6,116,6,214,7,56,7,126,7,236,8,78,8,108,
4e9e2555 Poul Sander 2025-10-05 10:15 6189
    8,150,8,208,9,16,9,74,9,136,10,22,10,128,11,4,11,86,11,200,12,46,12,130,12,234,13,94,13,164,13,234,14,80,14,150,15,40,15,176,16,18,16,116,16,224,17,82,17,182,18,4,18,110,18,196,19,
4e9e2555 Poul Sander 2025-10-05 10:15 6190
    76,19,172,19,246,20,88,20,174,20,234,21,64,21,128,21,166,21,184,22,18,22,126,22,198,23,52,23,142,23,224,24,86,24,186,24,238,25,54,25,150,25,212,26,72,26,156,26,240,27,92,27,200,28,
4e9e2555 Poul Sander 2025-10-05 10:15 6191
    4,28,76,28,150,28,234,29,42,29,146,29,210,30,64,30,142,30,224,31,36,31,118,31,166,31,166,32,16,130,1,52,46,32,138,32,178,32,200,33,20,33,116,33,152,33,238,34,98,34,134,35,12,130,1,
4e9e2555 Poul Sander 2025-10-05 10:15 6192
    33,128,35,131,1,60,152,35,176,35,216,36,0,36,74,36,104,36,144,36,174,37,6,37,96,37,130,37,248,37,248,38,88,38,170,130,1,8,190,216,39,64,39,154,40,10,40,104,40,168,41,14,41,32,41,184,
4e9e2555 Poul Sander 2025-10-05 10:15 6193
    41,248,42,54,42,96,42,96,43,2,43,42,43,94,43,172,43,230,44,32,44,52,44,154,45,40,45,92,45,120,45,170,45,232,46,38,46,166,47,38,47,182,47,244,48,94,48,200,49,62,49,180,50,30,50,158,
4e9e2555 Poul Sander 2025-10-05 10:15 6194
    51,30,51,130,51,238,52,92,52,206,53,58,53,134,53,212,54,38,54,114,54,230,55,118,55,216,56,58,56,166,57,18,57,116,57,174,58,46,58,154,59,6,59,124,59,232,60,58,60,150,61,34,61,134,61,
4e9e2555 Poul Sander 2025-10-05 10:15 6195
    236,62,86,62,198,63,42,63,154,64,18,64,106,64,208,65,54,65,162,66,8,66,64,66,122,66,184,66,240,67,98,67,204,68,42,68,138,68,238,69,88,69,182,69,226,70,84,70,180,71,20,71,122,71,218,
4e9e2555 Poul Sander 2025-10-05 10:15 6196
    72,84,72,198,73,64,0,36,70,21,8,8,77,3,0,7,0,11,0,15,0,19,0,23,0,27,0,31,0,35,0,39,0,43,0,47,0,51,0,55,0,59,0,63,0,67,0,71,0,75,0,79,0,83,0,87,0,91,0,95,0,99,0,103,0,107,0,111,0,115,
4e9e2555 Poul Sander 2025-10-05 10:15 6197
    0,119,0,123,0,127,0,131,0,135,0,139,0,143,0,0,17,53,51,21,49,150,3,32,5,130,23,32,33,130,3,211,7,151,115,32,128,133,0,37,252,128,128,2,128,128,190,5,133,74,32,4,133,6,206,5,42,0,7,
4e9e2555 Poul Sander 2025-10-05 10:15 6198
    1,128,0,0,2,0,4,0,0,65,139,13,37,0,1,53,51,21,7,146,3,32,3,130,19,32,1,141,133,32,3,141,14,131,13,38,255,0,128,128,0,6,1,130,84,35,2,128,4,128,140,91,132,89,32,51,65,143,6,139,7,33,
4e9e2555 Poul Sander 2025-10-05 10:15 6199
    1,0,130,57,32,254,130,3,32,128,132,4,32,4,131,14,138,89,35,0,0,24,0,130,0,33,3,128,144,171,66,55,33,148,115,65,187,19,32,5,130,151,143,155,163,39,32,1,136,182,32,253,134,178,132,7,
4e9e2555 Poul Sander 2025-10-05 10:15 6200
    132,200,145,17,32,3,65,48,17,165,17,39,0,0,21,0,128,255,128,3,65,175,17,65,3,27,132,253,131,217,139,201,155,233,155,27,131,67,131,31,130,241,33,255,0,131,181,137,232,132,15,132,4,138,
4e9e2555 Poul Sander 2025-10-05 10:15 6201
    247,34,255,0,128,179,238,32,0,130,0,32,20,65,239,48,33,0,19,67,235,10,32,51,65,203,14,65,215,11,32,7,154,27,135,39,32,33,130,35,33,128,128,130,231,32,253,132,231,32,128,132,232,34,
4e9e2555 Poul Sander 2025-10-05 10:15 6202
    128,128,254,133,13,136,8,32,253,65,186,5,130,36,130,42,176,234,133,231,34,128,0,0,66,215,44,33,0,1,68,235,6,68,211,19,32,49,68,239,14,139,207,139,47,66,13,7,32,51,130,47,33,1,0,130,
4e9e2555 Poul Sander 2025-10-05 10:15 6203
    207,35,128,128,1,0,131,222,131,5,130,212,130,6,131,212,32,0,130,10,133,220,130,233,130,226,32,254,133,255,178,233,39,3,1,128,3,0,2,0,4,68,15,7,68,99,12,130,89,130,104,33,128,4,133,
4e9e2555 Poul Sander 2025-10-05 10:15 6204
    93,130,10,38,0,0,11,1,0,255,0,68,63,16,70,39,9,66,215,8,32,7,68,77,6,68,175,14,32,29,68,195,6,132,7,35,2,0,128,255,131,91,132,4,65,178,5,141,111,67,129,23,165,135,140,107,142,135,33,
4e9e2555 Poul Sander 2025-10-05 10:15 6205
    21,5,69,71,6,131,7,33,1,0,140,104,132,142,130,4,137,247,140,30,68,255,12,39,11,0,128,0,128,3,0,3,69,171,15,67,251,7,65,15,8,66,249,11,65,229,7,67,211,7,66,13,7,35,1,128,128,254,133,
4e9e2555 Poul Sander 2025-10-05 10:15 6206
    93,32,254,131,145,132,4,132,18,32,2,151,128,130,23,34,0,0,9,154,131,65,207,8,68,107,15,68,51,7,32,7,70,59,7,135,121,130,82,32,128,151,111,41,0,0,4,0,128,255,0,1,128,1,137,239,33,0,
4e9e2555 Poul Sander 2025-10-05 10:15 6207
    37,70,145,10,65,77,10,65,212,14,37,0,0,0,5,0,128,66,109,5,70,123,10,33,0,19,72,33,18,133,237,70,209,11,33,0,2,130,113,137,119,136,115,33,1,0,133,43,130,5,34,0,0,10,69,135,6,70,219,
4e9e2555 Poul Sander 2025-10-05 10:15 6208
    13,66,155,7,65,9,12,66,157,11,66,9,11,32,7,130,141,132,252,66,151,9,137,9,66,15,30,36,0,20,0,128,0,130,218,71,11,42,68,51,8,65,141,7,73,19,15,69,47,23,143,39,66,81,7,32,1,66,55,6,34,
4e9e2555 Poul Sander 2025-10-05 10:15 6209
    1,128,128,68,25,5,69,32,6,137,6,136,25,32,254,131,42,32,3,66,88,26,148,26,32,0,130,0,32,14,164,231,70,225,12,66,233,7,67,133,19,71,203,15,130,161,32,255,130,155,32,254,139,127,134,
4e9e2555 Poul Sander 2025-10-05 10:15 6210
    12,164,174,33,0,15,164,159,33,59,0,65,125,20,66,25,7,32,5,68,191,6,66,29,7,144,165,65,105,9,35,128,128,255,0,137,2,133,182,164,169,33,128,128,197,171,130,155,68,235,7,32,21,70,77,19,
4e9e2555 Poul Sander 2025-10-05 10:15 6211
    66,21,10,68,97,8,66,30,5,66,4,43,34,0,17,0,71,19,41,65,253,20,71,25,23,65,91,15,65,115,7,34,2,128,128,66,9,8,130,169,33,1,0,66,212,13,132,28,72,201,43,35,0,0,0,18,66,27,38,76,231,5,
4e9e2555 Poul Sander 2025-10-05 10:15 6212
    68,157,20,135,157,32,7,68,185,13,65,129,28,66,20,5,32,253,66,210,11,65,128,49,133,61,32,0,65,135,6,74,111,37,72,149,12,66,203,19,65,147,19,68,93,7,68,85,8,76,4,5,33,255,0,133,129,34,
4e9e2555 Poul Sander 2025-10-05 10:15 6213
    254,0,128,68,69,8,181,197,34,0,0,12,65,135,32,65,123,20,69,183,27,133,156,66,50,5,72,87,10,67,137,32,33,0,19,160,139,78,251,13,68,55,20,67,119,19,65,91,36,69,177,15,32,254,143,16,65,
4e9e2555 Poul Sander 2025-10-05 10:15 6214
    98,53,32,128,130,0,32,0,66,43,54,70,141,23,66,23,15,131,39,69,47,11,131,15,70,129,19,74,161,9,36,128,255,0,128,254,130,153,65,148,32,67,41,9,34,0,0,4,79,15,5,73,99,10,71,203,8,32,3,
4e9e2555 Poul Sander 2025-10-05 10:15 6215
    72,123,6,72,43,8,32,2,133,56,131,99,130,9,34,0,0,6,72,175,5,73,159,14,144,63,135,197,132,189,133,66,33,255,0,73,6,7,70,137,12,35,0,0,0,10,130,3,73,243,25,67,113,12,65,73,7,69,161,7,
4e9e2555 Poul Sander 2025-10-05 10:15 6216
    138,7,37,21,2,0,128,128,254,134,3,73,116,27,33,128,128,130,111,39,12,0,128,1,0,3,128,2,72,219,21,35,43,0,47,0,67,47,20,130,111,33,21,1,68,167,13,81,147,8,133,230,32,128,77,73,6,32,
4e9e2555 Poul Sander 2025-10-05 10:15 6217
    128,131,142,134,18,130,6,32,255,75,18,12,131,243,37,128,0,128,3,128,3,74,231,21,135,123,32,29,134,107,135,7,32,21,74,117,7,135,7,134,96,135,246,74,103,23,132,242,33,0,10,67,151,28,
4e9e2555 Poul Sander 2025-10-05 10:15 6218
    67,133,20,66,141,11,131,11,32,3,77,71,6,32,128,130,113,32,1,81,4,6,134,218,66,130,24,131,31,34,0,26,0,130,0,77,255,44,83,15,11,148,155,68,13,7,32,49,78,231,18,79,7,11,73,243,11,32,
4e9e2555 Poul Sander 2025-10-05 10:15 6219
    33,65,187,10,130,63,65,87,8,73,239,19,35,0,128,1,0,131,226,32,252,65,100,6,32,128,139,8,33,1,0,130,21,32,253,72,155,44,73,255,20,32,128,71,67,8,81,243,39,67,15,20,74,191,23,68,121,
4e9e2555 Poul Sander 2025-10-05 10:15 6220
    27,32,1,66,150,6,32,254,79,19,11,131,214,32,128,130,215,37,2,0,128,253,0,128,136,5,65,220,24,147,212,130,210,33,0,24,72,219,42,84,255,13,67,119,16,69,245,19,72,225,19,65,3,15,69,93,
4e9e2555 Poul Sander 2025-10-05 10:15 6221
    19,131,55,132,178,71,115,14,81,228,6,142,245,33,253,0,132,43,172,252,65,16,11,75,219,8,65,219,31,66,223,24,75,223,10,33,29,1,80,243,10,66,175,8,131,110,134,203,133,172,130,16,70,30,
4e9e2555 Poul Sander 2025-10-05 10:15 6222
    7,164,183,130,163,32,20,65,171,48,65,163,36,65,143,23,65,151,19,65,147,13,65,134,17,133,17,130,216,67,114,5,164,217,65,137,12,72,147,48,79,71,19,74,169,22,80,251,8,65,173,7,66,157,
4e9e2555 Poul Sander 2025-10-05 10:15 6223
    15,74,173,15,32,254,65,170,8,71,186,45,72,131,6,77,143,40,187,195,152,179,65,123,38,68,215,57,68,179,15,65,85,7,69,187,14,32,21,66,95,15,67,19,25,32,1,83,223,6,32,2,76,240,7,77,166,
4e9e2555 Poul Sander 2025-10-05 10:15 6224
    43,65,8,5,130,206,32,0,67,39,54,143,167,66,255,19,82,193,11,151,47,85,171,5,67,27,17,132,160,69,172,11,69,184,56,66,95,6,33,12,1,130,237,32,2,68,179,27,68,175,16,80,135,15,72,55,7,
4e9e2555 Poul Sander 2025-10-05 10:15 6225
    71,87,12,73,3,12,132,12,66,75,32,76,215,5,169,139,147,135,148,139,81,12,12,81,185,36,75,251,7,65,23,27,76,215,9,87,165,12,65,209,15,72,157,7,65,245,31,32,128,71,128,6,32,1,82,125,5,
4e9e2555 Poul Sander 2025-10-05 10:15 6226
    34,0,128,254,131,169,32,254,131,187,71,180,9,132,27,32,2,88,129,44,32,0,78,47,40,65,79,23,79,171,14,32,21,71,87,8,72,15,14,65,224,33,130,139,74,27,62,93,23,7,68,31,7,75,27,7,139,15,
4e9e2555 Poul Sander 2025-10-05 10:15 6227
    74,3,7,74,23,27,65,165,11,65,177,15,67,123,5,32,1,130,221,32,252,71,96,5,74,12,12,133,244,130,25,34,1,0,128,130,2,139,8,93,26,8,65,9,32,65,57,14,140,14,32,0,73,79,67,68,119,11,135,
4e9e2555 Poul Sander 2025-10-05 10:15 6228
    11,32,51,90,75,14,139,247,65,43,7,131,19,139,11,69,159,11,65,247,6,36,1,128,128,253,0,90,71,9,33,1,0,132,14,32,128,89,93,14,69,133,6,130,44,131,30,131,6,65,20,56,33,0,16,72,179,40,
4e9e2555 Poul Sander 2025-10-05 10:15 6229
    75,47,12,65,215,19,74,95,19,65,43,11,131,168,67,110,5,75,23,17,69,106,6,75,65,5,71,204,43,32,0,80,75,47,71,203,15,159,181,68,91,11,67,197,7,73,101,13,68,85,6,33,128,128,130,214,130,
4e9e2555 Poul Sander 2025-10-05 10:15 6230
    25,32,254,74,236,48,130,194,37,0,18,0,128,255,128,77,215,40,65,139,64,32,51,80,159,10,65,147,39,130,219,84,212,43,130,46,75,19,97,74,33,11,65,201,23,65,173,31,33,1,0,79,133,6,66,150,
4e9e2555 Poul Sander 2025-10-05 10:15 6231
    5,67,75,48,85,187,6,70,207,37,32,71,87,221,13,73,163,14,80,167,15,132,15,83,193,19,82,209,8,78,99,9,72,190,11,77,110,49,89,63,5,80,91,35,99,63,32,70,235,23,81,99,10,69,148,10,65,110,
4e9e2555 Poul Sander 2025-10-05 10:15 6232
    36,32,0,65,99,47,95,219,11,68,171,51,66,87,7,72,57,7,74,45,17,143,17,65,114,50,33,14,0,65,111,40,159,195,98,135,15,35,7,53,51,21,100,78,9,95,146,16,32,254,82,114,6,32,128,67,208,37,
4e9e2555 Poul Sander 2025-10-05 10:15 6233
    130,166,99,79,58,32,17,96,99,14,72,31,19,72,87,31,82,155,7,67,47,14,32,21,131,75,134,231,72,51,17,72,78,8,133,8,80,133,6,33,253,128,88,37,9,66,124,36,72,65,12,134,12,71,55,43,66,139,
4e9e2555 Poul Sander 2025-10-05 10:15 6234
    27,85,135,10,91,33,12,65,35,11,66,131,11,71,32,8,90,127,6,130,244,71,76,11,168,207,33,0,12,66,123,32,32,0,65,183,15,68,135,11,66,111,7,67,235,11,66,111,15,32,254,97,66,12,160,154,67,
4e9e2555 Poul Sander 2025-10-05 10:15 6235
    227,52,80,33,15,87,249,15,93,45,31,75,111,12,93,45,11,77,99,9,160,184,81,31,12,32,15,98,135,30,104,175,7,77,249,36,69,73,15,78,5,12,32,254,66,151,19,34,128,128,4,87,32,12,149,35,133,
4e9e2555 Poul Sander 2025-10-05 10:15 6236
    21,96,151,31,32,19,72,35,5,98,173,15,143,15,32,21,143,99,158,129,33,0,0,65,35,52,65,11,15,147,15,98,75,11,33,1,0,143,151,132,15,32,254,99,200,37,132,43,130,4,39,0,10,0,128,1,128,3,
4e9e2555 Poul Sander 2025-10-05 10:15 6237
    0,104,151,14,97,187,20,69,131,15,67,195,11,87,227,7,33,128,128,132,128,33,254,0,68,131,9,65,46,26,42,0,0,0,7,0,0,255,128,3,128,0,88,223,15,33,0,21,89,61,22,66,209,12,65,2,12,37,0,2,
4e9e2555 Poul Sander 2025-10-05 10:15 6238
    1,0,3,128,101,83,8,36,0,1,53,51,29,130,3,34,21,1,0,66,53,8,32,0,68,215,6,100,55,25,107,111,9,66,193,11,72,167,8,73,143,31,139,31,33,1,0,131,158,32,254,132,5,33,253,128,65,16,9,133,
4e9e2555 Poul Sander 2025-10-05 10:15 6239
    17,89,130,25,141,212,33,0,0,93,39,8,90,131,25,93,39,14,66,217,6,106,179,8,159,181,71,125,15,139,47,138,141,87,11,14,76,23,14,65,231,26,140,209,66,122,8,81,179,5,101,195,26,32,47,74,
4e9e2555 Poul Sander 2025-10-05 10:15 6240
    75,13,69,159,11,83,235,11,67,21,16,136,167,131,106,130,165,130,15,32,128,101,90,24,134,142,32,0,65,103,51,108,23,11,101,231,15,75,173,23,74,237,23,66,15,6,66,46,17,66,58,17,65,105,
4e9e2555 Poul Sander 2025-10-05 10:15 6241
    49,66,247,55,71,179,12,70,139,15,86,229,7,84,167,15,32,1,95,72,12,89,49,6,33,128,128,65,136,38,66,30,9,32,0,100,239,7,66,247,29,70,105,20,65,141,19,69,81,15,130,144,32,128,83,41,5,
4e9e2555 Poul Sander 2025-10-05 10:15 6242
    32,255,131,177,68,185,5,133,126,65,97,37,32,0,130,0,33,21,0,130,55,66,195,28,67,155,13,34,79,0,83,66,213,13,73,241,19,66,59,19,65,125,11,135,201,66,249,16,32,128,66,44,11,66,56,17,
4e9e2555 Poul Sander 2025-10-05 10:15 6243
    68,143,8,68,124,38,67,183,12,96,211,9,65,143,29,112,171,5,32,0,68,131,63,34,33,53,51,71,121,11,32,254,98,251,16,32,253,74,231,10,65,175,37,133,206,37,0,0,8,1,0,0,107,123,11,113,115,
4e9e2555 Poul Sander 2025-10-05 10:15 6244
    9,33,0,1,130,117,131,3,73,103,7,66,51,18,66,44,5,133,75,70,88,5,32,254,65,39,12,68,80,9,34,12,0,128,107,179,28,68,223,6,155,111,86,147,15,32,2,131,82,141,110,33,254,0,130,15,32,4,103,
4e9e2555 Poul Sander 2025-10-05 10:15 6245
    184,15,141,35,87,176,5,83,11,5,71,235,23,114,107,11,65,189,16,70,33,15,86,153,31,135,126,86,145,30,65,183,41,32,0,130,0,32,10,65,183,24,34,35,0,39,67,85,9,65,179,15,143,15,33,1,0,65,
4e9e2555 Poul Sander 2025-10-05 10:15 6246
    28,17,157,136,130,123,32,20,130,3,32,0,97,135,24,115,167,19,80,71,12,32,51,110,163,14,78,35,19,131,19,155,23,77,229,8,78,9,17,151,17,67,231,46,94,135,8,73,31,31,93,215,56,82,171,25,
4e9e2555 Poul Sander 2025-10-05 10:15 6247
    72,77,8,162,179,169,167,99,131,11,69,85,19,66,215,15,76,129,13,68,115,22,72,79,35,67,113,5,34,0,0,19,70,31,46,65,89,52,73,223,15,85,199,33,95,33,8,132,203,73,29,32,67,48,16,177,215,
4e9e2555 Poul Sander 2025-10-05 10:15 6248
    101,13,15,65,141,43,69,141,15,75,89,5,70,0,11,70,235,21,178,215,36,10,0,128,0,0,71,207,24,33,0,19,100,67,6,80,215,11,66,67,7,80,43,12,71,106,7,80,192,5,65,63,5,66,217,26,33,0,13,156,
4e9e2555 Poul Sander 2025-10-05 10:15 6249
    119,68,95,5,72,233,12,134,129,85,81,11,76,165,20,65,43,8,73,136,8,75,10,31,38,128,128,0,0,0,13,1,130,4,32,3,106,235,29,114,179,12,66,131,23,32,7,77,133,6,67,89,12,131,139,116,60,9,
4e9e2555 Poul Sander 2025-10-05 10:15 6250
    89,15,37,32,0,74,15,7,103,11,22,65,35,5,33,55,0,93,81,28,67,239,23,78,85,5,107,93,14,66,84,17,65,193,26,74,183,10,66,67,34,143,135,79,91,15,32,7,117,111,8,75,56,9,84,212,9,154,134,
4e9e2555 Poul Sander 2025-10-05 10:15 6251
    32,0,130,0,32,18,130,3,70,171,41,83,7,16,70,131,19,84,191,15,84,175,19,84,167,30,84,158,12,154,193,68,107,15,33,0,0,65,79,42,65,71,7,73,55,7,118,191,16,83,180,9,32,255,76,166,9,154,
4e9e2555 Poul Sander 2025-10-05 10:15 6252
    141,32,0,130,0,69,195,52,65,225,15,151,15,75,215,31,80,56,10,68,240,17,100,32,9,70,147,39,65,93,12,71,71,41,92,85,15,84,135,23,78,35,15,110,27,10,84,125,8,107,115,29,136,160,38,0,0,
4e9e2555 Poul Sander 2025-10-05 10:15 6253
    14,0,128,255,0,82,155,24,67,239,8,119,255,11,69,131,11,77,29,6,112,31,8,134,27,105,203,8,32,2,75,51,11,75,195,12,74,13,29,136,161,37,128,0,0,0,11,1,130,163,82,115,8,125,191,17,69,35,
4e9e2555 Poul Sander 2025-10-05 10:15 6254
    12,74,137,15,143,15,32,1,65,157,12,136,12,161,142,65,43,40,65,199,6,65,19,24,102,185,11,76,123,11,99,6,12,135,12,32,254,130,8,161,155,101,23,9,39,8,0,0,1,128,3,128,2,78,63,17,72,245,
4e9e2555 Poul Sander 2025-10-05 10:15 6255
    12,67,41,11,90,167,9,32,128,97,49,9,32,128,109,51,14,132,97,81,191,8,130,97,125,99,12,121,35,9,127,75,15,71,79,12,81,151,23,87,97,7,70,223,15,80,245,16,105,97,15,32,254,113,17,6,32,
4e9e2555 Poul Sander 2025-10-05 10:15 6256
    128,130,8,105,105,8,76,122,18,65,243,21,74,63,7,38,4,1,0,255,0,2,0,119,247,28,133,65,32,255,141,91,35,0,0,0,16,67,63,36,34,59,0,63,77,59,9,119,147,11,143,241,66,173,15,66,31,11,67,
4e9e2555 Poul Sander 2025-10-05 10:15 6257
    75,8,81,74,16,32,128,131,255,87,181,42,127,43,5,34,255,128,2,120,235,11,37,19,0,23,0,0,37,109,191,14,118,219,7,127,43,14,65,79,14,35,0,0,0,3,73,91,5,130,5,38,3,0,7,0,11,0,0,70,205,
4e9e2555 Poul Sander 2025-10-05 10:15 6258
    11,88,221,12,32,0,73,135,7,87,15,22,73,135,10,79,153,15,97,71,19,65,49,11,32,1,131,104,121,235,11,80,65,11,142,179,144,14,81,123,46,32,1,88,217,5,112,5,8,65,201,15,83,29,15,122,147,
4e9e2555 Poul Sander 2025-10-05 10:15 6259
    11,135,179,142,175,143,185,67,247,39,66,199,7,35,5,0,128,3,69,203,15,123,163,12,67,127,7,130,119,71,153,10,141,102,70,175,8,32,128,121,235,30,136,89,100,191,11,116,195,11,111,235,15,
4e9e2555 Poul Sander 2025-10-05 10:15 6260
    72,39,7,32,2,97,43,5,132,5,94,67,8,131,8,125,253,10,32,3,65,158,16,146,16,130,170,40,0,21,0,128,0,0,3,128,5,88,219,15,24,64,159,32,135,141,65,167,15,68,163,10,97,73,49,32,255,82,58,
4e9e2555 Poul Sander 2025-10-05 10:15 6261
    7,93,80,8,97,81,16,24,67,87,52,34,0,0,5,130,231,33,128,2,80,51,13,65,129,8,113,61,6,132,175,65,219,5,130,136,77,152,17,32,0,95,131,61,70,215,6,33,21,51,90,53,10,78,97,23,105,77,31,
4e9e2555 Poul Sander 2025-10-05 10:15 6262
    65,117,7,139,75,24,68,195,9,24,64,22,9,33,0,128,130,11,33,128,128,66,25,5,121,38,5,134,5,134,45,66,40,36,66,59,18,34,128,0,0,66,59,81,135,245,123,103,19,120,159,19,77,175,12,33,255,
4e9e2555 Poul Sander 2025-10-05 10:15 6263
    0,87,29,10,94,70,21,66,59,54,39,3,1,128,3,0,2,128,4,24,65,7,15,66,47,7,72,98,12,37,0,0,0,3,1,0,24,65,55,21,131,195,32,1,67,178,6,33,4,0,77,141,8,32,6,131,47,74,67,16,24,69,3,20,24,
4e9e2555 Poul Sander 2025-10-05 10:15 6264
    65,251,7,133,234,130,229,94,108,17,35,0,0,6,0,141,175,86,59,5,162,79,85,166,8,70,112,13,32,13,24,64,67,26,24,71,255,7,123,211,12,80,121,11,69,215,15,66,217,11,69,71,10,131,113,132,
4e9e2555 Poul Sander 2025-10-05 10:15 6265
    126,119,90,9,66,117,19,132,19,32,0,130,0,24,64,47,59,33,7,0,73,227,5,68,243,15,85,13,12,76,37,22,74,254,15,130,138,33,0,4,65,111,6,137,79,65,107,16,32,1,77,200,6,34,128,128,3,75,154,
4e9e2555 Poul Sander 2025-10-05 10:15 6266
    12,37,0,16,0,0,2,0,104,115,36,140,157,68,67,19,68,51,15,106,243,15,134,120,70,37,10,68,27,10,140,152,65,121,24,32,128,94,155,7,67,11,8,24,74,11,25,65,3,12,83,89,18,82,21,37,67,200,
4e9e2555 Poul Sander 2025-10-05 10:15 6267
    5,130,144,24,64,172,12,33,4,0,134,162,74,80,14,145,184,32,0,130,0,69,251,20,32,19,81,243,5,82,143,8,33,5,53,89,203,5,133,112,79,109,15,33,0,21,130,71,80,175,41,36,75,0,79,0,83,121,
4e9e2555 Poul Sander 2025-10-05 10:15 6268
    117,9,87,89,27,66,103,11,70,13,15,75,191,11,135,67,87,97,20,109,203,5,69,246,8,108,171,5,78,195,38,65,51,13,107,203,11,77,3,17,24,75,239,17,65,229,28,79,129,39,130,175,32,128,123,253,
4e9e2555 Poul Sander 2025-10-05 10:15 6269
    7,132,142,24,65,51,15,65,239,41,36,128,128,0,0,13,65,171,5,66,163,28,136,183,118,137,11,80,255,15,67,65,7,74,111,8,32,0,130,157,32,253,24,76,35,10,103,212,5,81,175,9,69,141,7,66,150,
4e9e2555 Poul Sander 2025-10-05 10:15 6270
    29,131,158,24,75,199,28,124,185,7,76,205,15,68,124,14,32,3,123,139,16,130,16,33,128,128,108,199,6,33,0,3,65,191,35,107,11,6,73,197,11,24,70,121,15,83,247,15,24,70,173,23,69,205,14,
4e9e2555 Poul Sander 2025-10-05 10:15 6271
    32,253,131,140,32,254,136,4,94,198,9,32,3,78,4,13,66,127,13,143,13,32,0,130,0,33,16,0,24,69,59,39,109,147,12,76,253,19,24,69,207,15,69,229,15,130,195,71,90,10,139,10,130,152,73,43,
4e9e2555 Poul Sander 2025-10-05 10:15 6272
    40,91,139,10,65,131,37,35,75,0,79,0,84,227,12,143,151,68,25,15,80,9,23,95,169,11,34,128,2,128,112,186,5,130,6,83,161,19,76,50,6,130,37,65,145,44,110,83,5,32,16,67,99,6,71,67,15,76,
4e9e2555 Poul Sander 2025-10-05 10:15 6273
    55,17,140,215,67,97,23,76,69,15,77,237,11,104,211,23,77,238,11,65,154,43,33,0,10,83,15,28,83,13,20,67,145,19,67,141,14,97,149,21,68,9,15,86,251,5,66,207,5,66,27,37,82,1,23,127,71,12,
4e9e2555 Poul Sander 2025-10-05 10:15 6274
    94,235,10,110,175,24,98,243,15,132,154,132,4,24,66,69,10,32,4,67,156,43,130,198,35,2,1,0,4,75,27,9,69,85,9,95,240,7,32,128,130,35,32,28,66,43,40,24,82,63,23,83,123,12,72,231,15,127,
4e9e2555 Poul Sander 2025-10-05 10:15 6275
    59,23,116,23,19,117,71,7,24,77,99,15,67,111,15,71,101,8,36,2,128,128,252,128,127,60,11,32,1,132,16,130,18,141,24,67,107,9,32,3,68,194,15,175,15,38,0,11,0,128,1,128,2,80,63,25,32,0,
4e9e2555 Poul Sander 2025-10-05 10:15 6276
    24,65,73,11,69,185,15,83,243,16,32,0,24,81,165,8,130,86,77,35,6,155,163,88,203,5,24,66,195,30,70,19,19,24,80,133,15,32,1,75,211,8,32,254,108,133,8,79,87,20,65,32,9,41,0,0,7,0,128,0,
4e9e2555 Poul Sander 2025-10-05 10:15 6277
    0,2,128,2,68,87,15,66,1,16,92,201,16,24,76,24,17,133,17,34,128,0,30,66,127,64,34,115,0,119,73,205,9,66,43,11,109,143,15,24,79,203,11,90,143,15,131,15,155,31,65,185,15,86,87,11,35,128,
4e9e2555 Poul Sander 2025-10-05 10:15 6278
    128,253,0,69,7,6,130,213,33,1,0,119,178,15,142,17,66,141,74,83,28,6,36,7,0,0,4,128,82,39,18,76,149,12,67,69,21,32,128,79,118,15,32,0,130,0,32,8,131,206,32,2,79,83,9,100,223,14,102,
4e9e2555 Poul Sander 2025-10-05 10:15 6279
    113,23,115,115,7,24,65,231,12,130,162,32,4,68,182,19,130,102,93,143,8,69,107,29,24,77,255,12,143,197,72,51,7,76,195,15,132,139,85,49,15,130,152,131,18,71,81,23,70,14,11,36,0,10,0,128,
4e9e2555 Poul Sander 2025-10-05 10:15 6280
    2,69,59,9,89,151,15,66,241,11,76,165,12,71,43,15,75,49,13,65,12,23,132,37,32,0,179,115,130,231,95,181,16,132,77,32,254,67,224,8,65,126,20,79,171,8,32,2,89,81,5,75,143,6,80,41,8,34,
4e9e2555 Poul Sander 2025-10-05 10:15 6281
    2,0,128,24,81,72,9,32,0,130,0,35,17,0,0,255,77,99,39,95,65,36,67,109,15,24,69,93,11,77,239,5,95,77,23,35,128,1,0,128,24,86,7,8,132,167,32,2,69,198,41,130,202,33,0,26,120,75,44,24,89,
4e9e2555 Poul Sander 2025-10-05 10:15 6282
    51,15,71,243,12,70,239,11,24,84,3,11,66,7,11,71,255,10,32,21,69,155,35,88,151,12,32,128,74,38,10,65,210,8,74,251,5,65,226,5,75,201,13,32,3,65,9,41,146,41,40,0,0,0,9,1,0,1,0,2,91,99,
4e9e2555 Poul Sander 2025-10-05 10:15 6283
    19,32,35,106,119,13,70,219,15,83,239,12,137,154,32,2,67,252,19,36,128,0,0,4,1,130,196,32,2,130,8,91,107,8,32,0,135,81,24,73,211,8,132,161,73,164,13,36,0,8,0,128,2,105,123,26,139,67,
4e9e2555 Poul Sander 2025-10-05 10:15 6284
    76,99,15,34,1,0,128,135,76,83,156,20,92,104,8,67,251,30,24,86,47,27,123,207,12,24,86,7,15,71,227,8,32,4,65,20,20,131,127,32,0,130,123,32,0,71,223,26,32,19,90,195,22,71,223,15,84,200,
4e9e2555 Poul Sander 2025-10-05 10:15 6285
    6,32,128,133,241,24,84,149,9,67,41,25,36,0,0,0,22,0,88,111,49,32,87,66,21,5,77,3,27,123,75,7,71,143,19,135,183,71,183,19,130,171,74,252,5,131,5,89,87,17,32,1,132,18,130,232,68,11,10,
4e9e2555 Poul Sander 2025-10-05 10:15 6286
    33,1,128,70,208,16,66,230,18,147,18,130,254,223,255,75,27,23,65,59,15,135,39,155,255,34,128,128,254,104,92,8,33,0,128,65,32,11,65,1,58,33,26,0,130,0,72,71,18,78,55,17,76,11,19,86,101,
4e9e2555 Poul Sander 2025-10-05 10:15 6287
    12,75,223,11,89,15,11,24,76,87,15,75,235,15,131,15,72,95,7,85,71,11,72,115,11,73,64,6,34,1,128,128,66,215,9,34,128,254,128,134,14,33,128,255,67,102,5,32,0,130,16,70,38,11,66,26,57,
4e9e2555 Poul Sander 2025-10-05 10:15 6288
    88,11,8,24,76,215,34,78,139,7,95,245,7,32,7,24,73,75,23,32,128,131,167,130,170,101,158,9,82,49,22,118,139,6,32,18,67,155,44,116,187,9,108,55,14,80,155,23,66,131,15,93,77,10,131,168,
4e9e2555 Poul Sander 2025-10-05 10:15 6289
    32,128,73,211,12,24,75,187,22,32,4,96,71,20,67,108,19,132,19,120,207,8,32,5,76,79,15,66,111,21,66,95,8,32,3,190,211,111,3,8,211,212,32,20,65,167,44,34,75,0,79,97,59,13,32,33,112,63,
4e9e2555 Poul Sander 2025-10-05 10:15 6290
    10,65,147,19,69,39,19,143,39,24,66,71,9,130,224,65,185,43,94,176,12,65,183,24,71,38,8,24,72,167,7,65,191,38,136,235,24,96,167,12,65,203,62,115,131,13,65,208,42,175,235,67,127,6,32,
4e9e2555 Poul Sander 2025-10-05 10:15 6291
    4,76,171,29,114,187,5,32,71,65,211,5,65,203,68,72,51,8,164,219,32,0,172,214,71,239,58,78,3,27,66,143,15,77,19,15,147,31,35,33,53,51,21,66,183,10,173,245,66,170,30,150,30,34,0,0,23,
4e9e2555 Poul Sander 2025-10-05 10:15 6292
    80,123,54,76,1,16,73,125,15,82,245,11,167,253,24,76,85,12,70,184,5,32,254,131,185,37,254,0,128,1,0,128,133,16,117,158,18,92,27,38,65,3,17,130,251,35,17,0,128,254,24,69,83,39,140,243,
4e9e2555 Poul Sander 2025-10-05 10:15 6293
    121,73,19,109,167,7,81,41,15,24,95,175,12,102,227,15,121,96,11,24,95,189,7,32,3,145,171,154,17,24,77,47,9,33,0,5,70,71,37,68,135,7,32,29,117,171,11,69,87,15,24,79,97,19,24,79,149,23,
4e9e2555 Poul Sander 2025-10-05 10:15 6294
    131,59,32,1,75,235,5,72,115,11,72,143,7,132,188,71,27,46,131,51,32,0,69,95,6,175,215,32,21,131,167,81,15,19,151,191,151,23,131,215,71,43,5,32,254,24,79,164,24,74,109,8,77,166,13,65,
4e9e2555 Poul Sander 2025-10-05 10:15 6295
    176,26,88,162,5,98,159,6,171,219,120,247,6,79,29,8,99,169,10,103,59,19,65,209,35,131,35,91,25,19,112,94,15,83,36,8,173,229,33,20,0,88,75,43,71,31,12,65,191,71,33,1,0,130,203,32,254,
4e9e2555 Poul Sander 2025-10-05 10:15 6296
    131,4,68,66,7,67,130,6,104,61,13,173,215,38,13,1,0,0,0,2,128,67,111,28,74,129,16,104,35,19,79,161,16,87,14,7,138,143,132,10,67,62,36,114,115,5,162,151,67,33,16,108,181,15,143,151,67,
4e9e2555 Poul Sander 2025-10-05 10:15 6297
    5,5,24,100,242,15,170,153,34,0,0,14,65,51,34,32,55,79,75,9,32,51,74,7,10,65,57,38,132,142,32,254,72,0,14,139,163,32,128,80,254,8,67,158,21,65,63,7,32,4,72,227,27,95,155,12,67,119,19,
4e9e2555 Poul Sander 2025-10-05 10:15 6298
    124,91,24,149,154,72,177,34,97,223,8,155,151,24,108,227,15,88,147,16,72,117,19,68,35,11,92,253,15,70,199,15,24,87,209,17,32,2,87,233,7,32,1,24,88,195,10,119,24,8,32,3,81,227,24,65,
4e9e2555 Poul Sander 2025-10-05 10:15 6299
    125,21,35,128,128,0,25,76,59,48,24,90,187,9,97,235,12,66,61,11,91,105,19,24,79,141,11,24,79,117,15,24,79,129,27,90,53,13,130,13,32,253,131,228,24,79,133,40,69,70,8,66,137,31,65,33,
4e9e2555 Poul Sander 2025-10-05 10:15 6300
    19,96,107,8,68,119,29,66,7,5,68,125,16,65,253,19,65,241,27,24,90,179,13,24,79,143,18,33,128,128,130,246,32,254,130,168,68,154,36,77,51,9,97,47,5,167,195,32,21,131,183,78,239,27,155,
4e9e2555 Poul Sander 2025-10-05 10:15 6301
    195,78,231,14,201,196,77,11,6,32,5,73,111,37,97,247,12,77,19,31,155,207,78,215,19,162,212,69,17,14,66,91,19,80,143,57,78,203,39,159,215,32,128,93,134,8,24,80,109,24,66,113,15,169,215,
4e9e2555 Poul Sander 2025-10-05 10:15 6302
    66,115,6,32,4,69,63,33,32,0,101,113,7,86,227,35,143,211,36,49,53,51,21,1,77,185,14,65,159,28,69,251,34,67,56,8,33,9,0,24,107,175,25,90,111,12,110,251,11,119,189,24,119,187,34,87,15,
4e9e2555 Poul Sander 2025-10-05 10:15 6303
    9,32,4,66,231,37,90,39,7,66,239,8,84,219,15,69,105,23,24,85,27,27,87,31,11,33,1,128,76,94,6,32,1,85,241,7,33,128,128,106,48,10,33,128,128,69,136,11,133,13,24,79,116,49,84,236,8,24,
4e9e2555 Poul Sander 2025-10-05 10:15 6304
    91,87,9,32,5,165,255,69,115,12,66,27,15,159,15,24,72,247,12,74,178,5,24,80,64,15,33,0,128,143,17,77,89,51,130,214,24,81,43,7,170,215,74,49,8,159,199,143,31,139,215,69,143,5,32,254,
4e9e2555 Poul Sander 2025-10-05 10:15 6305
    24,81,50,35,181,217,84,123,70,143,195,159,15,65,187,16,66,123,7,65,175,15,65,193,29,68,207,39,79,27,5,70,131,6,32,4,68,211,33,33,67,0,83,143,14,159,207,143,31,140,223,33,0,128,24,80,
4e9e2555 Poul Sander 2025-10-05 10:15 6306
    82,14,24,93,16,23,32,253,65,195,5,68,227,40,133,214,107,31,7,32,5,67,115,27,87,9,8,107,31,43,66,125,6,32,0,103,177,23,131,127,72,203,36,32,0,110,103,8,155,163,73,135,6,32,19,24,112,
4e9e2555 Poul Sander 2025-10-05 10:15 6307
    99,10,65,71,11,73,143,19,143,31,126,195,5,24,85,21,9,24,76,47,14,32,254,24,93,77,36,68,207,11,39,25,0,0,255,128,3,128,4,66,51,37,95,247,13,82,255,24,76,39,19,147,221,66,85,27,24,118,
4e9e2555 Poul Sander 2025-10-05 10:15 6308
    7,8,24,74,249,12,76,74,8,91,234,8,67,80,17,131,222,33,253,0,121,30,44,73,0,16,69,15,6,32,0,65,23,38,69,231,12,65,179,6,98,131,16,86,31,27,24,108,157,14,80,160,8,24,65,46,17,33,4,0,
4e9e2555 Poul Sander 2025-10-05 10:15 6309
    96,2,18,144,191,65,226,8,68,19,5,171,199,80,9,15,180,199,67,89,5,32,255,24,79,173,28,174,201,24,79,179,50,32,1,24,122,5,10,82,61,10,180,209,83,19,8,32,128,24,80,129,27,111,248,43,131,
4e9e2555 Poul Sander 2025-10-05 10:15 6310
    71,24,115,103,8,67,127,41,78,213,24,100,247,19,66,115,39,75,107,5,32,254,165,219,78,170,40,24,112,163,49,32,1,97,203,6,65,173,64,32,0,83,54,7,133,217,88,37,12,32,254,131,28,33,128,
4e9e2555 Poul Sander 2025-10-05 10:15 6311
    3,67,71,44,84,183,6,32,5,69,223,33,96,7,7,123,137,16,192,211,24,112,14,9,32,255,67,88,29,68,14,10,84,197,38,33,0,22,116,47,50,32,87,106,99,9,116,49,15,89,225,15,97,231,23,70,41,19,
4e9e2555 Poul Sander 2025-10-05 10:15 6312
    82,85,8,93,167,6,32,253,132,236,108,190,7,89,251,5,116,49,58,33,128,128,131,234,32,15,24,74,67,38,70,227,24,24,83,45,23,89,219,12,70,187,12,89,216,19,32,2,69,185,24,141,24,70,143,66,
4e9e2555 Poul Sander 2025-10-05 10:15 6313
    24,82,119,56,78,24,10,32,253,133,149,132,6,24,106,233,7,69,198,48,178,203,81,243,12,68,211,15,106,255,23,66,91,15,69,193,7,100,39,10,24,83,72,16,176,204,33,19,0,88,207,45,68,21,12,
4e9e2555 Poul Sander 2025-10-05 10:15 6314
    68,17,10,65,157,53,68,17,6,32,254,92,67,10,65,161,25,69,182,43,24,118,91,47,69,183,18,181,209,111,253,12,89,159,8,66,112,12,69,184,45,35,0,0,0,9,24,80,227,26,73,185,16,118,195,15,131,
4e9e2555 Poul Sander 2025-10-05 10:15 6315
    15,33,1,0,65,59,15,66,39,27,160,111,66,205,12,148,111,143,110,33,128,128,156,112,24,81,199,8,75,199,23,66,117,20,155,121,32,254,68,126,12,72,213,29,134,239,149,123,89,27,16,148,117,
4e9e2555 Poul Sander 2025-10-05 10:15 6316
    65,245,8,24,71,159,14,141,134,134,28,73,51,55,109,77,15,105,131,11,68,67,11,76,169,27,107,209,12,102,174,8,32,128,72,100,18,116,163,56,79,203,11,75,183,44,85,119,19,71,119,23,151,227,
4e9e2555 Poul Sander 2025-10-05 10:15 6317
    32,1,93,27,8,65,122,5,77,102,8,110,120,20,66,23,8,66,175,17,66,63,12,133,12,79,35,8,74,235,33,67,149,16,69,243,15,78,57,15,69,235,16,67,177,7,151,192,130,23,67,84,29,141,192,174,187,
4e9e2555 Poul Sander 2025-10-05 10:15 6318
    77,67,15,69,11,12,159,187,77,59,10,199,189,24,70,235,50,96,83,19,66,53,23,105,65,19,77,47,12,163,199,66,67,37,78,207,50,67,23,23,174,205,67,228,6,71,107,13,67,22,14,66,85,11,83,187,
4e9e2555 Poul Sander 2025-10-05 10:15 6319
    38,124,47,49,95,7,19,66,83,23,67,23,19,24,96,78,17,80,101,16,71,98,40,33,0,7,88,131,22,24,89,245,12,84,45,12,102,213,5,123,12,9,32,2,126,21,14,43,255,0,128,128,0,0,20,0,128,255,128,
4e9e2555 Poul Sander 2025-10-05 10:15 6320
    3,126,19,39,32,75,106,51,7,113,129,15,24,110,135,19,126,47,15,115,117,11,69,47,11,32,2,109,76,9,102,109,9,32,128,75,2,10,130,21,32,254,69,47,6,32,3,94,217,47,32,0,65,247,10,69,15,46,
4e9e2555 Poul Sander 2025-10-05 10:15 6321
    65,235,31,65,243,15,101,139,10,66,174,14,65,247,16,72,102,28,69,17,14,84,243,9,165,191,88,47,48,66,53,12,32,128,71,108,6,203,193,32,17,75,187,42,73,65,16,65,133,52,114,123,9,167,199,
4e9e2555 Poul Sander 2025-10-05 10:15 6322
    69,21,37,86,127,44,75,171,11,180,197,78,213,12,148,200,81,97,46,24,95,243,9,32,4,66,75,33,113,103,9,87,243,36,143,225,24,84,27,31,90,145,8,148,216,67,49,5,24,84,34,14,75,155,27,67,
4e9e2555 Poul Sander 2025-10-05 10:15 6323
    52,13,140,13,36,0,20,0,128,255,24,135,99,46,88,59,43,155,249,80,165,7,136,144,71,161,23,32,253,132,33,32,254,88,87,44,136,84,35,128,0,0,21,81,103,5,94,47,44,76,51,12,143,197,151,15,
4e9e2555 Poul Sander 2025-10-05 10:15 6324
    65,215,31,24,64,77,13,65,220,20,65,214,14,71,4,40,65,213,13,32,0,130,0,35,21,1,2,0,135,0,34,36,0,72,134,10,36,1,0,26,0,130,134,11,36,2,0,14,0,108,134,11,32,3,138,23,32,4,138,11,34,
4e9e2555 Poul Sander 2025-10-05 10:15 6325
    5,0,20,134,33,34,0,0,6,132,23,32,1,134,15,32,18,130,25,133,11,37,1,0,13,0,49,0,133,11,36,2,0,7,0,38,134,11,36,3,0,17,0,45,134,11,32,4,138,35,36,5,0,10,0,62,134,23,32,6,132,23,36,3,
4e9e2555 Poul Sander 2025-10-05 10:15 6326
    0,1,4,9,130,87,131,167,133,11,133,167,133,11,133,167,133,11,37,3,0,34,0,122,0,133,11,133,167,133,11,133,167,133,11,133,167,34,50,0,48,130,1,34,52,0,47,134,5,8,49,49,0,53,98,121,32,
4e9e2555 Poul Sander 2025-10-05 10:15 6327
    84,114,105,115,116,97,110,32,71,114,105,109,109,101,114,82,101,103,117,108,97,114,84,84,88,32,80,114,111,103,103,121,67,108,101,97,110,84,84,50,48,48,52,47,130,2,53,49,53,0,98,0,121,
4e9e2555 Poul Sander 2025-10-05 10:15 6328
    0,32,0,84,0,114,0,105,0,115,0,116,0,97,0,110,130,15,32,71,132,15,36,109,0,109,0,101,130,9,32,82,130,5,36,103,0,117,0,108,130,29,32,114,130,43,34,84,0,88,130,35,32,80,130,25,34,111,
4e9e2555 Poul Sander 2025-10-05 10:15 6329
    0,103,130,1,34,121,0,67,130,27,32,101,132,59,32,84,130,31,33,0,0,65,155,9,34,20,0,0,65,11,6,130,8,135,2,33,1,1,130,9,8,120,1,1,2,1,3,1,4,1,5,1,6,1,7,1,8,1,9,1,10,1,11,1,12,1,13,1,14,
4e9e2555 Poul Sander 2025-10-05 10:15 6330
    1,15,1,16,1,17,1,18,1,19,1,20,1,21,1,22,1,23,1,24,1,25,1,26,1,27,1,28,1,29,1,30,1,31,1,32,0,3,0,4,0,5,0,6,0,7,0,8,0,9,0,10,0,11,0,12,0,13,0,14,0,15,0,16,0,17,0,18,0,19,0,20,0,21,0,
4e9e2555 Poul Sander 2025-10-05 10:15 6331
    22,0,23,0,24,0,25,0,26,0,27,0,28,0,29,0,30,0,31,130,187,8,66,33,0,34,0,35,0,36,0,37,0,38,0,39,0,40,0,41,0,42,0,43,0,44,0,45,0,46,0,47,0,48,0,49,0,50,0,51,0,52,0,53,0,54,0,55,0,56,0,
4e9e2555 Poul Sander 2025-10-05 10:15 6332
    57,0,58,0,59,0,60,0,61,0,62,0,63,0,64,0,65,0,66,130,243,9,75,68,0,69,0,70,0,71,0,72,0,73,0,74,0,75,0,76,0,77,0,78,0,79,0,80,0,81,0,82,0,83,0,84,0,85,0,86,0,87,0,88,0,89,0,90,0,91,0,
4e9e2555 Poul Sander 2025-10-05 10:15 6333
    92,0,93,0,94,0,95,0,96,0,97,1,33,1,34,1,35,1,36,1,37,1,38,1,39,1,40,1,41,1,42,1,43,1,44,1,45,1,46,1,47,1,48,1,49,1,50,1,51,1,52,1,53,1,54,1,55,1,56,1,57,1,58,1,59,1,60,1,61,1,62,1,
4e9e2555 Poul Sander 2025-10-05 10:15 6334
    63,1,64,1,65,0,172,0,163,0,132,0,133,0,189,0,150,0,232,0,134,0,142,0,139,0,157,0,169,0,164,0,239,0,138,0,218,0,131,0,147,0,242,0,243,0,141,0,151,0,136,0,195,0,222,0,241,0,158,0,170,
4e9e2555 Poul Sander 2025-10-05 10:15 6335
    0,245,0,244,0,246,0,162,0,173,0,201,0,199,0,174,0,98,0,99,0,144,0,100,0,203,0,101,0,200,0,202,0,207,0,204,0,205,0,206,0,233,0,102,0,211,0,208,0,209,0,175,0,103,0,240,0,145,0,214,0,
4e9e2555 Poul Sander 2025-10-05 10:15 6336
    212,0,213,0,104,0,235,0,237,0,137,0,106,0,105,0,107,0,109,0,108,0,110,0,160,0,111,0,113,0,112,0,114,0,115,0,117,0,116,0,118,0,119,0,234,0,120,0,122,0,121,0,123,0,125,0,124,0,184,0,
4e9e2555 Poul Sander 2025-10-05 10:15 6337
    161,0,127,0,126,0,128,0,129,0,236,0,238,0,186,14,117,110,105,99,111,100,101,35,48,120,48,48,48,49,141,14,32,50,141,14,32,51,141,14,32,52,141,14,32,53,141,14,32,54,141,14,32,55,141,
4e9e2555 Poul Sander 2025-10-05 10:15 6338
    14,32,56,141,14,32,57,141,14,32,97,141,14,32,98,141,14,32,99,141,14,32,100,141,14,32,101,141,14,32,102,140,14,33,49,48,141,14,141,239,32,49,141,239,32,49,141,239,32,49,141,239,32,49,
4e9e2555 Poul Sander 2025-10-05 10:15 6339
    141,239,32,49,141,239,32,49,141,239,32,49,141,239,32,49,141,239,32,49,141,239,32,49,141,239,32,49,141,239,32,49,141,239,32,49,141,239,45,49,102,6,100,101,108,101,116,101,4,69,117,114,
4e9e2555 Poul Sander 2025-10-05 10:15 6340
    111,140,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,
4e9e2555 Poul Sander 2025-10-05 10:15 6341
    32,56,141,236,32,56,141,236,32,56,65,220,13,32,57,65,220,13,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141,
4e9e2555 Poul Sander 2025-10-05 10:15 6342
    239,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141,239,35,57,102,0,0,5,250,72,249,98,247,
4e9e2555 Poul Sander 2025-10-05 10:15 6343
};
4e9e2555 Poul Sander 2025-10-05 10:15 6344
4e9e2555 Poul Sander 2025-10-05 10:15 6345
static const char* GetDefaultCompressedFontDataTTF(int* out_size)
4e9e2555 Poul Sander 2025-10-05 10:15 6346
{
4e9e2555 Poul Sander 2025-10-05 10:15 6347
    *out_size = proggy_clean_ttf_compressed_size;
4e9e2555 Poul Sander 2025-10-05 10:15 6348
    return (const char*)proggy_clean_ttf_compressed_data;
1193b4be Poul Sander 2025-02-03 21:28 6349
}
4e9e2555 Poul Sander 2025-10-05 10:15 6350
#endif // #ifndef IMGUI_DISABLE_DEFAULT_FONT
1193b4be Poul Sander 2025-02-03 21:28 6351
1193b4be Poul Sander 2025-02-03 21:28 6352
#endif // #ifndef IMGUI_DISABLE
1970-01-01 00:00 6353