|
|
@@ -1,4 +1,4 @@
|
|
|
-// dear imgui, v1.66 WIP
|
|
|
+// dear imgui, v1.68 WIP
|
|
|
// (drawing and font code)
|
|
|
|
|
|
/*
|
|
|
@@ -12,7 +12,8 @@ Index of this file:
|
|
|
// [SECTION] Helpers ShadeVertsXXX functions
|
|
|
// [SECTION] ImFontConfig
|
|
|
// [SECTION] ImFontAtlas
|
|
|
-// [SECTION] ImFontAtlas glyph ranges helpers + GlyphRangesBuilder
|
|
|
+// [SECTION] ImFontAtlas glyph ranges helpers
|
|
|
+// [SECTION] ImFontGlyphRangesBuilder
|
|
|
// [SECTION] ImFont
|
|
|
// [SECTION] Internal Render Helpers
|
|
|
// [SECTION] Decompression code
|
|
|
@@ -32,7 +33,7 @@ Index of this file:
|
|
|
|
|
|
#include <stdio.h> // vsnprintf, sscanf, printf
|
|
|
#if !defined(alloca)
|
|
|
-#if defined(__GLIBC__) || defined(__sun) || defined(__CYGWIN__)
|
|
|
+#if defined(__GLIBC__) || defined(__sun) || defined(__CYGWIN__) || defined(__APPLE__)
|
|
|
#include <alloca.h> // alloca (glibc uses <alloca.h>. Note that Cygwin may have _WIN32 defined, so the order matters here)
|
|
|
#elif defined(_WIN32)
|
|
|
#include <malloc.h> // alloca
|
|
|
@@ -56,6 +57,9 @@ Index of this file:
|
|
|
#pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants ok.
|
|
|
#pragma clang diagnostic ignored "-Wglobal-constructors" // warning : declaration requires a global destructor // similar to above, not sure what the exact difference it.
|
|
|
#pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness //
|
|
|
+#if __has_warning("-Wzero-as-null-pointer-constant")
|
|
|
+#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning : zero as null pointer constant // some standard header variations use #define NULL 0
|
|
|
+#endif
|
|
|
#if __has_warning("-Wcomma")
|
|
|
#pragma clang diagnostic ignored "-Wcomma" // warning : possible misuse of comma operator here //
|
|
|
#endif
|
|
|
@@ -63,7 +67,7 @@ Index of this file:
|
|
|
#pragma clang diagnostic ignored "-Wreserved-id-macro" // warning : macro name is a reserved identifier //
|
|
|
#endif
|
|
|
#if __has_warning("-Wdouble-promotion")
|
|
|
-#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function
|
|
|
+#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.
|
|
|
#endif
|
|
|
#elif defined(__GNUC__)
|
|
|
#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used
|
|
|
@@ -175,7 +179,7 @@ void ImGui::StyleColorsDark(ImGuiStyle* dst)
|
|
|
colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
|
|
|
colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
|
|
|
colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.06f, 0.06f, 0.94f);
|
|
|
- colors[ImGuiCol_ChildBg] = ImVec4(1.00f, 1.00f, 1.00f, 0.00f);
|
|
|
+ colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
|
|
|
colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.08f, 0.94f);
|
|
|
colors[ImGuiCol_Border] = ImVec4(0.43f, 0.43f, 0.50f, 0.50f);
|
|
|
colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
|
|
|
@@ -206,12 +210,12 @@ void ImGui::StyleColorsDark(ImGuiStyle* dst)
|
|
|
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
|
|
|
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
|
|
|
colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f);
|
|
|
+ colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered];
|
|
|
colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
|
|
|
colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
|
|
|
colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f);
|
|
|
- colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered];
|
|
|
colors[ImGuiCol_DockingPreview] = colors[ImGuiCol_HeaderActive] * ImVec4(1.0f, 1.0f, 1.0f, 0.7f);
|
|
|
- colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);;
|
|
|
+ colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);
|
|
|
colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);
|
|
|
colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
|
|
|
colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
|
|
|
@@ -263,12 +267,12 @@ void ImGui::StyleColorsClassic(ImGuiStyle* dst)
|
|
|
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.78f, 0.82f, 1.00f, 0.60f);
|
|
|
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.78f, 0.82f, 1.00f, 0.90f);
|
|
|
colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f);
|
|
|
+ colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered];
|
|
|
colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
|
|
|
colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
|
|
|
colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f);
|
|
|
- colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered];
|
|
|
colors[ImGuiCol_DockingPreview] = colors[ImGuiCol_Header] * ImVec4(1.0f, 1.0f, 1.0f, 0.7f);
|
|
|
- colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);;
|
|
|
+ colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);
|
|
|
colors[ImGuiCol_PlotLines] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
|
|
|
colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
|
|
|
colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
|
|
|
@@ -321,12 +325,12 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst)
|
|
|
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
|
|
|
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
|
|
|
colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.90f);
|
|
|
+ colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered];
|
|
|
colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
|
|
|
colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
|
|
|
colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f);
|
|
|
- colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered];
|
|
|
colors[ImGuiCol_DockingPreview] = colors[ImGuiCol_Header] * ImVec4(1.0f, 1.0f, 1.0f, 0.7f);
|
|
|
- colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);;
|
|
|
+ colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);
|
|
|
colors[ImGuiCol_PlotLines] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f);
|
|
|
colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
|
|
|
colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
|
|
|
@@ -661,7 +665,13 @@ void ImDrawList::PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, c
|
|
|
_IdxWritePtr += 6;
|
|
|
}
|
|
|
|
|
|
+// On AddPolyline() and AddConvexPolyFilled() we intentionally avoid using ImVec2 and superflous function calls to optimize debug/non-inlined builds.
|
|
|
+// Those macros expects l-values.
|
|
|
+#define IM_NORMALIZE2F_OVER_ZERO(VX,VY) { float d2 = VX*VX + VY*VY; if (d2 > 0.0f) { float inv_len = 1.0f / ImSqrt(d2); VX *= inv_len; VY *= inv_len; } }
|
|
|
+#define IM_NORMALIZE2F_OVER_EPSILON_CLAMP(VX,VY,EPS,INVLENMAX) { float d2 = VX*VX + VY*VY; if (d2 > EPS) { float inv_len = 1.0f / ImSqrt(d2); if (inv_len > INVLENMAX) inv_len = INVLENMAX; VX *= inv_len; VY *= inv_len; } }
|
|
|
+
|
|
|
// TODO: Thickness anti-aliased lines cap are missing their AA fringe.
|
|
|
+// We avoid using the ImVec2 math operators here to reduce cost to a minimum for debug/non-inlined builds.
|
|
|
void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 col, bool closed, float thickness)
|
|
|
{
|
|
|
if (points_count < 2)
|
|
|
@@ -685,16 +695,17 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
|
|
|
PrimReserve(idx_count, vtx_count);
|
|
|
|
|
|
// Temporary buffer
|
|
|
- ImVec2* temp_normals = (ImVec2*)alloca(points_count * (thick_line ? 5 : 3) * sizeof(ImVec2));
|
|
|
+ ImVec2* temp_normals = (ImVec2*)alloca(points_count * (thick_line ? 5 : 3) * sizeof(ImVec2)); //-V630
|
|
|
ImVec2* temp_points = temp_normals + points_count;
|
|
|
|
|
|
for (int i1 = 0; i1 < count; i1++)
|
|
|
{
|
|
|
const int i2 = (i1+1) == points_count ? 0 : i1+1;
|
|
|
- ImVec2 diff = points[i2] - points[i1];
|
|
|
- diff *= ImInvLength(diff, 1.0f);
|
|
|
- temp_normals[i1].x = diff.y;
|
|
|
- temp_normals[i1].y = -diff.x;
|
|
|
+ float dx = points[i2].x - points[i1].x;
|
|
|
+ float dy = points[i2].y - points[i1].y;
|
|
|
+ IM_NORMALIZE2F_OVER_ZERO(dx, dy);
|
|
|
+ temp_normals[i1].x = dy;
|
|
|
+ temp_normals[i1].y = -dx;
|
|
|
}
|
|
|
if (!closed)
|
|
|
temp_normals[points_count-1] = temp_normals[points_count-2];
|
|
|
@@ -717,17 +728,18 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
|
|
|
unsigned int idx2 = (i1+1) == points_count ? _VtxCurrentIdx : idx1+3;
|
|
|
|
|
|
// Average normals
|
|
|
- ImVec2 dm = (temp_normals[i1] + temp_normals[i2]) * 0.5f;
|
|
|
- float dmr2 = dm.x*dm.x + dm.y*dm.y;
|
|
|
- if (dmr2 > 0.000001f)
|
|
|
- {
|
|
|
- float scale = 1.0f / dmr2;
|
|
|
- if (scale > 100.0f) scale = 100.0f;
|
|
|
- dm *= scale;
|
|
|
- }
|
|
|
- dm *= AA_SIZE;
|
|
|
- temp_points[i2*2+0] = points[i2] + dm;
|
|
|
- temp_points[i2*2+1] = points[i2] - dm;
|
|
|
+ float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f;
|
|
|
+ float dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5f;
|
|
|
+ IM_NORMALIZE2F_OVER_EPSILON_CLAMP(dm_x, dm_y, 0.000001f, 100.0f)
|
|
|
+ dm_x *= AA_SIZE;
|
|
|
+ dm_y *= AA_SIZE;
|
|
|
+
|
|
|
+ // Add temporary vertexes
|
|
|
+ ImVec2* out_vtx = &temp_points[i2*2];
|
|
|
+ out_vtx[0].x = points[i2].x + dm_x;
|
|
|
+ out_vtx[0].y = points[i2].y + dm_y;
|
|
|
+ out_vtx[1].x = points[i2].x - dm_x;
|
|
|
+ out_vtx[1].y = points[i2].y - dm_y;
|
|
|
|
|
|
// Add indexes
|
|
|
_IdxWritePtr[0] = (ImDrawIdx)(idx2+0); _IdxWritePtr[1] = (ImDrawIdx)(idx1+0); _IdxWritePtr[2] = (ImDrawIdx)(idx1+2);
|
|
|
@@ -771,20 +783,24 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
|
|
|
unsigned int idx2 = (i1+1) == points_count ? _VtxCurrentIdx : idx1+4;
|
|
|
|
|
|
// Average normals
|
|
|
- ImVec2 dm = (temp_normals[i1] + temp_normals[i2]) * 0.5f;
|
|
|
- float dmr2 = dm.x*dm.x + dm.y*dm.y;
|
|
|
- if (dmr2 > 0.000001f)
|
|
|
- {
|
|
|
- float scale = 1.0f / dmr2;
|
|
|
- if (scale > 100.0f) scale = 100.0f;
|
|
|
- dm *= scale;
|
|
|
- }
|
|
|
- ImVec2 dm_out = dm * (half_inner_thickness + AA_SIZE);
|
|
|
- ImVec2 dm_in = dm * half_inner_thickness;
|
|
|
- temp_points[i2*4+0] = points[i2] + dm_out;
|
|
|
- temp_points[i2*4+1] = points[i2] + dm_in;
|
|
|
- temp_points[i2*4+2] = points[i2] - dm_in;
|
|
|
- temp_points[i2*4+3] = points[i2] - dm_out;
|
|
|
+ float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f;
|
|
|
+ float dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5f;
|
|
|
+ IM_NORMALIZE2F_OVER_EPSILON_CLAMP(dm_x, dm_y, 0.000001f, 100.0f);
|
|
|
+ float dm_out_x = dm_x * (half_inner_thickness + AA_SIZE);
|
|
|
+ float dm_out_y = dm_y * (half_inner_thickness + AA_SIZE);
|
|
|
+ float dm_in_x = dm_x * half_inner_thickness;
|
|
|
+ float dm_in_y = dm_y * half_inner_thickness;
|
|
|
+
|
|
|
+ // Add temporary vertexes
|
|
|
+ ImVec2* out_vtx = &temp_points[i2*4];
|
|
|
+ out_vtx[0].x = points[i2].x + dm_out_x;
|
|
|
+ out_vtx[0].y = points[i2].y + dm_out_y;
|
|
|
+ out_vtx[1].x = points[i2].x + dm_in_x;
|
|
|
+ out_vtx[1].y = points[i2].y + dm_in_y;
|
|
|
+ out_vtx[2].x = points[i2].x - dm_in_x;
|
|
|
+ out_vtx[2].y = points[i2].y - dm_in_y;
|
|
|
+ out_vtx[3].x = points[i2].x - dm_out_x;
|
|
|
+ out_vtx[3].y = points[i2].y - dm_out_y;
|
|
|
|
|
|
// Add indexes
|
|
|
_IdxWritePtr[0] = (ImDrawIdx)(idx2+1); _IdxWritePtr[1] = (ImDrawIdx)(idx1+1); _IdxWritePtr[2] = (ImDrawIdx)(idx1+2);
|
|
|
@@ -822,11 +838,13 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
|
|
|
const int i2 = (i1+1) == points_count ? 0 : i1+1;
|
|
|
const ImVec2& p1 = points[i1];
|
|
|
const ImVec2& p2 = points[i2];
|
|
|
- ImVec2 diff = p2 - p1;
|
|
|
- diff *= ImInvLength(diff, 1.0f);
|
|
|
|
|
|
- const float dx = diff.x * (thickness * 0.5f);
|
|
|
- const float dy = diff.y * (thickness * 0.5f);
|
|
|
+ float dx = p2.x - p1.x;
|
|
|
+ float dy = p2.y - p1.y;
|
|
|
+ IM_NORMALIZE2F_OVER_ZERO(dx, dy);
|
|
|
+ dx *= (thickness * 0.5f);
|
|
|
+ dy *= (thickness * 0.5f);
|
|
|
+
|
|
|
_VtxWritePtr[0].pos.x = p1.x + dy; _VtxWritePtr[0].pos.y = p1.y - dx; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;
|
|
|
_VtxWritePtr[1].pos.x = p2.x + dy; _VtxWritePtr[1].pos.y = p2.y - dx; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col;
|
|
|
_VtxWritePtr[2].pos.x = p2.x - dy; _VtxWritePtr[2].pos.y = p2.y + dx; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col;
|
|
|
@@ -841,6 +859,7 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// We intentionally avoid using ImVec2 and its math operators here to reduce cost to a minimum for debug/non-inlined builds.
|
|
|
void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_count, ImU32 col)
|
|
|
{
|
|
|
if (points_count < 3)
|
|
|
@@ -867,15 +886,16 @@ void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_coun
|
|
|
}
|
|
|
|
|
|
// Compute normals
|
|
|
- ImVec2* temp_normals = (ImVec2*)alloca(points_count * sizeof(ImVec2));
|
|
|
+ ImVec2* temp_normals = (ImVec2*)alloca(points_count * sizeof(ImVec2)); //-V630
|
|
|
for (int i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++)
|
|
|
{
|
|
|
const ImVec2& p0 = points[i0];
|
|
|
const ImVec2& p1 = points[i1];
|
|
|
- ImVec2 diff = p1 - p0;
|
|
|
- diff *= ImInvLength(diff, 1.0f);
|
|
|
- temp_normals[i0].x = diff.y;
|
|
|
- temp_normals[i0].y = -diff.x;
|
|
|
+ float dx = p1.x - p0.x;
|
|
|
+ float dy = p1.y - p0.y;
|
|
|
+ IM_NORMALIZE2F_OVER_ZERO(dx, dy);
|
|
|
+ temp_normals[i0].x = dy;
|
|
|
+ temp_normals[i0].y = -dx;
|
|
|
}
|
|
|
|
|
|
for (int i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++)
|
|
|
@@ -883,19 +903,15 @@ void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_coun
|
|
|
// Average normals
|
|
|
const ImVec2& n0 = temp_normals[i0];
|
|
|
const ImVec2& n1 = temp_normals[i1];
|
|
|
- ImVec2 dm = (n0 + n1) * 0.5f;
|
|
|
- float dmr2 = dm.x*dm.x + dm.y*dm.y;
|
|
|
- if (dmr2 > 0.000001f)
|
|
|
- {
|
|
|
- float scale = 1.0f / dmr2;
|
|
|
- if (scale > 100.0f) scale = 100.0f;
|
|
|
- dm *= scale;
|
|
|
- }
|
|
|
- dm *= AA_SIZE * 0.5f;
|
|
|
+ float dm_x = (n0.x + n1.x) * 0.5f;
|
|
|
+ float dm_y = (n0.y + n1.y) * 0.5f;
|
|
|
+ IM_NORMALIZE2F_OVER_EPSILON_CLAMP(dm_x, dm_y, 0.000001f, 100.0f);
|
|
|
+ dm_x *= AA_SIZE * 0.5f;
|
|
|
+ dm_y *= AA_SIZE * 0.5f;
|
|
|
|
|
|
// Add vertices
|
|
|
- _VtxWritePtr[0].pos = (points[i1] - dm); _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; // Inner
|
|
|
- _VtxWritePtr[1].pos = (points[i1] + dm); _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col_trans; // Outer
|
|
|
+ _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
|
|
|
+ _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
|
|
|
_VtxWritePtr += 2;
|
|
|
|
|
|
// Add indexes for fringes
|
|
|
@@ -947,6 +963,9 @@ void ImDrawList::PathArcTo(const ImVec2& centre, float radius, float a_min, floa
|
|
|
_Path.push_back(centre);
|
|
|
return;
|
|
|
}
|
|
|
+
|
|
|
+ // Note that we are adding a point at both a_min and a_max.
|
|
|
+ // If you are trying to draw a full closed circle you don't want the overlapping points!
|
|
|
_Path.reserve(_Path.Size + (num_segments + 1));
|
|
|
for (int i = 0; i <= num_segments; i++)
|
|
|
{
|
|
|
@@ -1130,21 +1149,23 @@ void ImDrawList::AddTriangleFilled(const ImVec2& a, const ImVec2& b, const ImVec
|
|
|
|
|
|
void ImDrawList::AddCircle(const ImVec2& centre, float radius, ImU32 col, int num_segments, float thickness)
|
|
|
{
|
|
|
- if ((col & IM_COL32_A_MASK) == 0)
|
|
|
+ if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2)
|
|
|
return;
|
|
|
|
|
|
+ // Because we are filling a closed shape we remove 1 from the count of segments/points
|
|
|
const float a_max = IM_PI*2.0f * ((float)num_segments - 1.0f) / (float)num_segments;
|
|
|
- PathArcTo(centre, radius-0.5f, 0.0f, a_max, num_segments);
|
|
|
+ PathArcTo(centre, radius-0.5f, 0.0f, a_max, num_segments - 1);
|
|
|
PathStroke(col, true, thickness);
|
|
|
}
|
|
|
|
|
|
void ImDrawList::AddCircleFilled(const ImVec2& centre, float radius, ImU32 col, int num_segments)
|
|
|
{
|
|
|
- if ((col & IM_COL32_A_MASK) == 0)
|
|
|
+ if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2)
|
|
|
return;
|
|
|
|
|
|
+ // Because we are filling a closed shape we remove 1 from the count of segments/points
|
|
|
const float a_max = IM_PI*2.0f * ((float)num_segments - 1.0f) / (float)num_segments;
|
|
|
- PathArcTo(centre, radius, 0.0f, a_max, num_segments);
|
|
|
+ PathArcTo(centre, radius, 0.0f, a_max, num_segments - 1);
|
|
|
PathFillConvex(col);
|
|
|
}
|
|
|
|
|
|
@@ -1510,7 +1531,7 @@ void ImFontAtlas::GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_wid
|
|
|
GetTexDataAsAlpha8(&pixels, NULL, NULL);
|
|
|
if (pixels)
|
|
|
{
|
|
|
- TexPixelsRGBA32 = (unsigned int*)ImGui::MemAlloc((size_t)(TexWidth * TexHeight * 4));
|
|
|
+ TexPixelsRGBA32 = (unsigned int*)ImGui::MemAlloc((size_t)TexWidth * (size_t)TexHeight * 4);
|
|
|
const unsigned char* src = pixels;
|
|
|
unsigned int* dst = TexPixelsRGBA32;
|
|
|
for (int n = TexWidth * TexHeight; n > 0; n--)
|
|
|
@@ -1534,11 +1555,11 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg)
|
|
|
if (!font_cfg->MergeMode)
|
|
|
Fonts.push_back(IM_NEW(ImFont));
|
|
|
else
|
|
|
- IM_ASSERT(!Fonts.empty()); // When using MergeMode make sure that a font has already been added before. You can use ImGui::GetIO().Fonts->AddFontDefault() to add the default imgui font.
|
|
|
+ IM_ASSERT(!Fonts.empty() && "Cannot use MergeMode for the first font"); // When using MergeMode make sure that a font has already been added before. You can use ImGui::GetIO().Fonts->AddFontDefault() to add the default imgui font.
|
|
|
|
|
|
ConfigData.push_back(*font_cfg);
|
|
|
ImFontConfig& new_font_cfg = ConfigData.back();
|
|
|
- if (!new_font_cfg.DstFont)
|
|
|
+ if (new_font_cfg.DstFont == NULL)
|
|
|
new_font_cfg.DstFont = Fonts.back();
|
|
|
if (!new_font_cfg.FontDataOwnedByAtlas)
|
|
|
{
|
|
|
@@ -1577,8 +1598,10 @@ ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template)
|
|
|
font_cfg.OversampleH = font_cfg.OversampleV = 1;
|
|
|
font_cfg.PixelSnapH = true;
|
|
|
}
|
|
|
- if (font_cfg.Name[0] == '\0') strcpy(font_cfg.Name, "ProggyClean.ttf, 13px");
|
|
|
- if (font_cfg.SizePixels <= 0.0f) font_cfg.SizePixels = 13.0f;
|
|
|
+ if (font_cfg.SizePixels <= 0.0f)
|
|
|
+ font_cfg.SizePixels = 13.0f * 1.0f;
|
|
|
+ if (font_cfg.Name[0] == '\0')
|
|
|
+ ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "ProggyClean.ttf, %dpx", (int)font_cfg.SizePixels);
|
|
|
|
|
|
const char* ttf_compressed_base85 = GetDefaultCompressedFontDataTTFBase85();
|
|
|
const ImWchar* glyph_ranges = font_cfg.GlyphRanges != NULL ? font_cfg.GlyphRanges : GetGlyphRangesDefault();
|
|
|
@@ -1726,139 +1749,220 @@ void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsig
|
|
|
data[i] = table[data[i]];
|
|
|
}
|
|
|
|
|
|
+// Temporary data for one source font (multiple source fonts can be merged into one destination ImFont)
|
|
|
+// (C++03 doesn't allow instancing ImVector<> with function-local types so we declare the type here.)
|
|
|
+struct ImFontBuildSrcData
|
|
|
+{
|
|
|
+ stbtt_fontinfo FontInfo;
|
|
|
+ stbtt_pack_range PackRange; // Hold the list of codepoints to pack (essentially points to Codepoints.Data)
|
|
|
+ stbrp_rect* Rects; // Rectangle to pack. We first fill in their size and the packer will give us their position.
|
|
|
+ stbtt_packedchar* PackedChars; // Output glyphs
|
|
|
+ const ImWchar* SrcRanges; // Ranges as requested by user (user is allowed to request too much, e.g. 0x0020..0xFFFF)
|
|
|
+ int DstIndex; // Index into atlas->Fonts[] and dst_tmp_array[]
|
|
|
+ int GlyphsHighest; // Highest requested codepoint
|
|
|
+ int GlyphsCount; // Glyph count (excluding missing glyphs and glyphs already set by an earlier source font)
|
|
|
+ ImBoolVector GlyphsSet; // Glyph bit map (random access, 1-bit per codepoint. This will be a maximum of 8KB)
|
|
|
+ ImVector<int> GlyphsList; // Glyph codepoints list (flattened version of GlyphsMap)
|
|
|
+};
|
|
|
+
|
|
|
+// Temporary data for one destination ImFont* (multiple source fonts can be merged into one destination ImFont)
|
|
|
+struct ImFontBuildDstData
|
|
|
+{
|
|
|
+ int SrcCount; // Number of source fonts targeting this destination font.
|
|
|
+ int GlyphsHighest;
|
|
|
+ int GlyphsCount;
|
|
|
+ ImBoolVector GlyphsSet; // This is used to resolve collision when multiple sources are merged into a same destination font.
|
|
|
+};
|
|
|
+
|
|
|
+static void UnpackBoolVectorToFlatIndexList(const ImBoolVector* in, ImVector<int>* out)
|
|
|
+{
|
|
|
+ IM_ASSERT(sizeof(in->Storage.Data[0]) == sizeof(int));
|
|
|
+ const int* it_begin = in->Storage.begin();
|
|
|
+ const int* it_end = in->Storage.end();
|
|
|
+ for (const int* it = it_begin; it < it_end; it++)
|
|
|
+ if (int entries_32 = *it)
|
|
|
+ for (int bit_n = 0; bit_n < 32; bit_n++)
|
|
|
+ if (entries_32 & (1 << bit_n))
|
|
|
+ out->push_back((int)((it - it_begin) << 5) + bit_n);
|
|
|
+}
|
|
|
+
|
|
|
bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
|
|
|
{
|
|
|
IM_ASSERT(atlas->ConfigData.Size > 0);
|
|
|
|
|
|
ImFontAtlasBuildRegisterDefaultCustomRects(atlas);
|
|
|
|
|
|
+ // Clear atlas
|
|
|
atlas->TexID = (ImTextureID)NULL;
|
|
|
atlas->TexWidth = atlas->TexHeight = 0;
|
|
|
atlas->TexUvScale = ImVec2(0.0f, 0.0f);
|
|
|
atlas->TexUvWhitePixel = ImVec2(0.0f, 0.0f);
|
|
|
atlas->ClearTexData();
|
|
|
|
|
|
- // Count glyphs/ranges
|
|
|
- int total_glyphs_count = 0;
|
|
|
- int total_ranges_count = 0;
|
|
|
- for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
|
|
|
- {
|
|
|
- ImFontConfig& cfg = atlas->ConfigData[input_i];
|
|
|
- if (!cfg.GlyphRanges)
|
|
|
- cfg.GlyphRanges = atlas->GetGlyphRangesDefault();
|
|
|
- for (const ImWchar* in_range = cfg.GlyphRanges; in_range[0] && in_range[1]; in_range += 2, total_ranges_count++)
|
|
|
- total_glyphs_count += (in_range[1] - in_range[0]) + 1;
|
|
|
- }
|
|
|
-
|
|
|
- // We need a width for the skyline algorithm. Using a dumb heuristic here to decide of width. User can override TexDesiredWidth and TexGlyphPadding if they wish.
|
|
|
- // Width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height.
|
|
|
- atlas->TexWidth = (atlas->TexDesiredWidth > 0) ? atlas->TexDesiredWidth : (total_glyphs_count > 4000) ? 4096 : (total_glyphs_count > 2000) ? 2048 : (total_glyphs_count > 1000) ? 1024 : 512;
|
|
|
- atlas->TexHeight = 0;
|
|
|
-
|
|
|
- // Start packing
|
|
|
- const int max_tex_height = 1024*32;
|
|
|
- stbtt_pack_context spc = {};
|
|
|
- if (!stbtt_PackBegin(&spc, NULL, atlas->TexWidth, max_tex_height, 0, atlas->TexGlyphPadding, NULL))
|
|
|
- return false;
|
|
|
- stbtt_PackSetOversampling(&spc, 1, 1);
|
|
|
+ // Temporary storage for building
|
|
|
+ ImVector<ImFontBuildSrcData> src_tmp_array;
|
|
|
+ ImVector<ImFontBuildDstData> dst_tmp_array;
|
|
|
+ src_tmp_array.resize(atlas->ConfigData.Size);
|
|
|
+ dst_tmp_array.resize(atlas->Fonts.Size);
|
|
|
+ memset(src_tmp_array.Data, 0, (size_t)src_tmp_array.size_in_bytes());
|
|
|
+ memset(dst_tmp_array.Data, 0, (size_t)dst_tmp_array.size_in_bytes());
|
|
|
|
|
|
- // Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values).
|
|
|
- ImFontAtlasBuildPackCustomRects(atlas, spc.pack_info);
|
|
|
-
|
|
|
- // Initialize font information (so we can error without any cleanup)
|
|
|
- struct ImFontTempBuildData
|
|
|
- {
|
|
|
- stbtt_fontinfo FontInfo;
|
|
|
- stbrp_rect* Rects;
|
|
|
- int RectsCount;
|
|
|
- stbtt_pack_range* Ranges;
|
|
|
- int RangesCount;
|
|
|
- };
|
|
|
- ImFontTempBuildData* tmp_array = (ImFontTempBuildData*)ImGui::MemAlloc((size_t)atlas->ConfigData.Size * sizeof(ImFontTempBuildData));
|
|
|
- for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
|
|
|
+ // 1. Initialize font loading structure, check font data validity
|
|
|
+ for (int src_i = 0; src_i < atlas->ConfigData.Size; src_i++)
|
|
|
{
|
|
|
- ImFontConfig& cfg = atlas->ConfigData[input_i];
|
|
|
- ImFontTempBuildData& tmp = tmp_array[input_i];
|
|
|
+ ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
|
|
|
+ ImFontConfig& cfg = atlas->ConfigData[src_i];
|
|
|
IM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas));
|
|
|
|
|
|
+ // Find index from cfg.DstFont (we allow the user to set cfg.DstFont. Also it makes casual debugging nicer than when storing indices)
|
|
|
+ src_tmp.DstIndex = -1;
|
|
|
+ for (int output_i = 0; output_i < atlas->Fonts.Size && src_tmp.DstIndex == -1; output_i++)
|
|
|
+ if (cfg.DstFont == atlas->Fonts[output_i])
|
|
|
+ src_tmp.DstIndex = output_i;
|
|
|
+ IM_ASSERT(src_tmp.DstIndex != -1); // cfg.DstFont not pointing within atlas->Fonts[] array?
|
|
|
+ if (src_tmp.DstIndex == -1)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ // Initialize helper structure for font loading and verify that the TTF/OTF data is correct
|
|
|
const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)cfg.FontData, cfg.FontNo);
|
|
|
IM_ASSERT(font_offset >= 0 && "FontData is incorrect, or FontNo cannot be found.");
|
|
|
- if (!stbtt_InitFont(&tmp.FontInfo, (unsigned char*)cfg.FontData, font_offset))
|
|
|
- {
|
|
|
- atlas->TexWidth = atlas->TexHeight = 0; // Reset output on failure
|
|
|
- ImGui::MemFree(tmp_array);
|
|
|
+ if (!stbtt_InitFont(&src_tmp.FontInfo, (unsigned char*)cfg.FontData, font_offset))
|
|
|
return false;
|
|
|
- }
|
|
|
+
|
|
|
+ // Measure highest codepoints
|
|
|
+ ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex];
|
|
|
+ src_tmp.SrcRanges = cfg.GlyphRanges ? cfg.GlyphRanges : atlas->GetGlyphRangesDefault();
|
|
|
+ for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
|
|
|
+ src_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]);
|
|
|
+ dst_tmp.SrcCount++;
|
|
|
+ dst_tmp.GlyphsHighest = ImMax(dst_tmp.GlyphsHighest, src_tmp.GlyphsHighest);
|
|
|
}
|
|
|
|
|
|
+ // 2. For every requested codepoint, check for their presence in the font data, and handle redundancy or overlaps between source fonts to avoid unused glyphs.
|
|
|
+ int total_glyphs_count = 0;
|
|
|
+ for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
|
|
+ {
|
|
|
+ ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
|
|
|
+ ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex];
|
|
|
+ ImFontConfig& cfg = atlas->ConfigData[src_i];
|
|
|
+ src_tmp.GlyphsSet.Resize(src_tmp.GlyphsHighest + 1);
|
|
|
+ if (dst_tmp.SrcCount > 1 && dst_tmp.GlyphsSet.Storage.empty())
|
|
|
+ dst_tmp.GlyphsSet.Resize(dst_tmp.GlyphsHighest + 1);
|
|
|
+
|
|
|
+ for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
|
|
|
+ for (int codepoint = src_range[0]; codepoint <= src_range[1]; codepoint++)
|
|
|
+ {
|
|
|
+ if (cfg.MergeMode && dst_tmp.GlyphsSet.GetBit(codepoint)) // Don't overwrite existing glyphs. We could make this an option (e.g. MergeOverwrite)
|
|
|
+ continue;
|
|
|
+ if (!stbtt_FindGlyphIndex(&src_tmp.FontInfo, codepoint)) // It is actually in the font?
|
|
|
+ continue;
|
|
|
+
|
|
|
+ // Add to avail set/counters
|
|
|
+ src_tmp.GlyphsCount++;
|
|
|
+ dst_tmp.GlyphsCount++;
|
|
|
+ src_tmp.GlyphsSet.SetBit(codepoint, true);
|
|
|
+ if (dst_tmp.SrcCount > 1)
|
|
|
+ dst_tmp.GlyphsSet.SetBit(codepoint, true);
|
|
|
+ total_glyphs_count++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. Unpack our bit map into a flat list (we now have all the Unicode points that we know are requested _and_ available _and_ not overlapping another)
|
|
|
+ for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
|
|
+ {
|
|
|
+ ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
|
|
|
+ src_tmp.GlyphsList.reserve(src_tmp.GlyphsCount);
|
|
|
+ UnpackBoolVectorToFlatIndexList(&src_tmp.GlyphsSet, &src_tmp.GlyphsList);
|
|
|
+ src_tmp.GlyphsSet.Clear();
|
|
|
+ IM_ASSERT(src_tmp.GlyphsList.Size == src_tmp.GlyphsCount);
|
|
|
+ }
|
|
|
+ for (int dst_i = 0; dst_i < dst_tmp_array.Size; dst_i++)
|
|
|
+ dst_tmp_array[dst_i].GlyphsSet.Clear();
|
|
|
+ dst_tmp_array.clear();
|
|
|
+
|
|
|
// Allocate packing character data and flag packed characters buffer as non-packed (x0=y0=x1=y1=0)
|
|
|
- int buf_packedchars_n = 0, buf_rects_n = 0, buf_ranges_n = 0;
|
|
|
- stbtt_packedchar* buf_packedchars = (stbtt_packedchar*)ImGui::MemAlloc(total_glyphs_count * sizeof(stbtt_packedchar));
|
|
|
- stbrp_rect* buf_rects = (stbrp_rect*)ImGui::MemAlloc(total_glyphs_count * sizeof(stbrp_rect));
|
|
|
- stbtt_pack_range* buf_ranges = (stbtt_pack_range*)ImGui::MemAlloc(total_ranges_count * sizeof(stbtt_pack_range));
|
|
|
- memset(buf_packedchars, 0, total_glyphs_count * sizeof(stbtt_packedchar));
|
|
|
- memset(buf_rects, 0, total_glyphs_count * sizeof(stbrp_rect)); // Unnecessary but let's clear this for the sake of sanity.
|
|
|
- memset(buf_ranges, 0, total_ranges_count * sizeof(stbtt_pack_range));
|
|
|
-
|
|
|
- // First font pass: pack all glyphs (no rendering at this point, we are working with rectangles in an infinitely tall texture at this point)
|
|
|
- for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
|
|
|
- {
|
|
|
- ImFontConfig& cfg = atlas->ConfigData[input_i];
|
|
|
- ImFontTempBuildData& tmp = tmp_array[input_i];
|
|
|
-
|
|
|
- // Setup ranges
|
|
|
- int font_glyphs_count = 0;
|
|
|
- int font_ranges_count = 0;
|
|
|
- for (const ImWchar* in_range = cfg.GlyphRanges; in_range[0] && in_range[1]; in_range += 2, font_ranges_count++)
|
|
|
- font_glyphs_count += (in_range[1] - in_range[0]) + 1;
|
|
|
- tmp.Ranges = buf_ranges + buf_ranges_n;
|
|
|
- tmp.RangesCount = font_ranges_count;
|
|
|
- buf_ranges_n += font_ranges_count;
|
|
|
- for (int i = 0; i < font_ranges_count; i++)
|
|
|
- {
|
|
|
- const ImWchar* in_range = &cfg.GlyphRanges[i * 2];
|
|
|
- stbtt_pack_range& range = tmp.Ranges[i];
|
|
|
- range.font_size = cfg.SizePixels;
|
|
|
- range.first_unicode_codepoint_in_range = in_range[0];
|
|
|
- range.num_chars = (in_range[1] - in_range[0]) + 1;
|
|
|
- range.chardata_for_range = buf_packedchars + buf_packedchars_n;
|
|
|
- buf_packedchars_n += range.num_chars;
|
|
|
- }
|
|
|
+ // (We technically don't need to zero-clear buf_rects, but let's do it for the sake of sanity)
|
|
|
+ ImVector<stbrp_rect> buf_rects;
|
|
|
+ ImVector<stbtt_packedchar> buf_packedchars;
|
|
|
+ buf_rects.resize(total_glyphs_count);
|
|
|
+ buf_packedchars.resize(total_glyphs_count);
|
|
|
+ memset(buf_rects.Data, 0, (size_t)buf_rects.size_in_bytes());
|
|
|
+ memset(buf_packedchars.Data, 0, (size_t)buf_packedchars.size_in_bytes());
|
|
|
+
|
|
|
+ // 4. Gather glyphs sizes so we can pack them in our virtual canvas.
|
|
|
+ int total_surface = 0;
|
|
|
+ int buf_rects_out_n = 0;
|
|
|
+ int buf_packedchars_out_n = 0;
|
|
|
+ for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
|
|
+ {
|
|
|
+ ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
|
|
|
+ if (src_tmp.GlyphsCount == 0)
|
|
|
+ continue;
|
|
|
|
|
|
- // Gather the sizes of all rectangle we need
|
|
|
- tmp.Rects = buf_rects + buf_rects_n;
|
|
|
- tmp.RectsCount = font_glyphs_count;
|
|
|
- buf_rects_n += font_glyphs_count;
|
|
|
- stbtt_PackSetOversampling(&spc, cfg.OversampleH, cfg.OversampleV);
|
|
|
- int n = stbtt_PackFontRangesGatherRects(&spc, &tmp.FontInfo, tmp.Ranges, tmp.RangesCount, tmp.Rects);
|
|
|
- IM_ASSERT(n == font_glyphs_count);
|
|
|
-
|
|
|
- // Detect missing glyphs and replace them with a zero-sized box instead of relying on the default glyphs
|
|
|
- // This allows us merging overlapping icon fonts more easily.
|
|
|
- int rect_i = 0;
|
|
|
- for (int range_i = 0; range_i < tmp.RangesCount; range_i++)
|
|
|
- for (int char_i = 0; char_i < tmp.Ranges[range_i].num_chars; char_i++, rect_i++)
|
|
|
- if (stbtt_FindGlyphIndex(&tmp.FontInfo, tmp.Ranges[range_i].first_unicode_codepoint_in_range + char_i) == 0)
|
|
|
- tmp.Rects[rect_i].w = tmp.Rects[rect_i].h = 0;
|
|
|
-
|
|
|
- // Pack
|
|
|
- stbrp_pack_rects((stbrp_context*)spc.pack_info, tmp.Rects, n);
|
|
|
-
|
|
|
- // Extend texture height
|
|
|
- // Also mark missing glyphs as non-packed so we don't attempt to render into them
|
|
|
- for (int i = 0; i < n; i++)
|
|
|
+ src_tmp.Rects = &buf_rects[buf_rects_out_n];
|
|
|
+ src_tmp.PackedChars = &buf_packedchars[buf_packedchars_out_n];
|
|
|
+ buf_rects_out_n += src_tmp.GlyphsCount;
|
|
|
+ buf_packedchars_out_n += src_tmp.GlyphsCount;
|
|
|
+
|
|
|
+ // Convert our ranges in the format stb_truetype wants
|
|
|
+ ImFontConfig& cfg = atlas->ConfigData[src_i];
|
|
|
+ src_tmp.PackRange.font_size = cfg.SizePixels;
|
|
|
+ src_tmp.PackRange.first_unicode_codepoint_in_range = 0;
|
|
|
+ src_tmp.PackRange.array_of_unicode_codepoints = src_tmp.GlyphsList.Data;
|
|
|
+ src_tmp.PackRange.num_chars = src_tmp.GlyphsList.Size;
|
|
|
+ src_tmp.PackRange.chardata_for_range = src_tmp.PackedChars;
|
|
|
+ src_tmp.PackRange.h_oversample = (unsigned char)cfg.OversampleH;
|
|
|
+ src_tmp.PackRange.v_oversample = (unsigned char)cfg.OversampleV;
|
|
|
+
|
|
|
+ // Gather the sizes of all rectangles we will need to pack (this loop is based on stbtt_PackFontRangesGatherRects)
|
|
|
+ const float scale = (cfg.SizePixels > 0) ? stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels) : stbtt_ScaleForMappingEmToPixels(&src_tmp.FontInfo, -cfg.SizePixels);
|
|
|
+ const int padding = atlas->TexGlyphPadding;
|
|
|
+ for (int glyph_i = 0; glyph_i < src_tmp.GlyphsList.Size; glyph_i++)
|
|
|
{
|
|
|
- if (tmp.Rects[i].w == 0 && tmp.Rects[i].h == 0)
|
|
|
- tmp.Rects[i].was_packed = 0;
|
|
|
- if (tmp.Rects[i].was_packed)
|
|
|
- atlas->TexHeight = ImMax(atlas->TexHeight, tmp.Rects[i].y + tmp.Rects[i].h);
|
|
|
+ int x0, y0, x1, y1;
|
|
|
+ const int glyph_index_in_font = stbtt_FindGlyphIndex(&src_tmp.FontInfo, src_tmp.GlyphsList[glyph_i]);
|
|
|
+ IM_ASSERT(glyph_index_in_font != 0);
|
|
|
+ stbtt_GetGlyphBitmapBoxSubpixel(&src_tmp.FontInfo, glyph_index_in_font, scale * cfg.OversampleH, scale * cfg.OversampleV, 0, 0, &x0, &y0, &x1, &y1);
|
|
|
+ src_tmp.Rects[glyph_i].w = (stbrp_coord)(x1 - x0 + padding + cfg.OversampleH - 1);
|
|
|
+ src_tmp.Rects[glyph_i].h = (stbrp_coord)(y1 - y0 + padding + cfg.OversampleV - 1);
|
|
|
+ total_surface += src_tmp.Rects[glyph_i].w * src_tmp.Rects[glyph_i].h;
|
|
|
}
|
|
|
}
|
|
|
- IM_ASSERT(buf_rects_n == total_glyphs_count);
|
|
|
- IM_ASSERT(buf_packedchars_n == total_glyphs_count);
|
|
|
- IM_ASSERT(buf_ranges_n == total_ranges_count);
|
|
|
|
|
|
- // Create texture
|
|
|
+ // We need a width for the skyline algorithm, any width!
|
|
|
+ // The exact width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height.
|
|
|
+ // User can override TexDesiredWidth and TexGlyphPadding if they wish, otherwise we use a simple heuristic to select the width based on expected surface.
|
|
|
+ const int surface_sqrt = (int)ImSqrt((float)total_surface) + 1;
|
|
|
+ atlas->TexHeight = 0;
|
|
|
+ if (atlas->TexDesiredWidth > 0)
|
|
|
+ atlas->TexWidth = atlas->TexDesiredWidth;
|
|
|
+ else
|
|
|
+ atlas->TexWidth = (surface_sqrt >= 4096*0.7f) ? 4096 : (surface_sqrt >= 2048*0.7f) ? 2048 : (surface_sqrt >= 1024*0.7f) ? 1024 : 512;
|
|
|
+
|
|
|
+ // 5. Start packing
|
|
|
+ // Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values).
|
|
|
+ const int TEX_HEIGHT_MAX = 1024 * 32;
|
|
|
+ stbtt_pack_context spc = {};
|
|
|
+ stbtt_PackBegin(&spc, NULL, atlas->TexWidth, TEX_HEIGHT_MAX, 0, atlas->TexGlyphPadding, NULL);
|
|
|
+ ImFontAtlasBuildPackCustomRects(atlas, spc.pack_info);
|
|
|
+
|
|
|
+ // 6. Pack each source font. No rendering yet, we are working with rectangles in an infinitely tall texture at this point.
|
|
|
+ for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
|
|
+ {
|
|
|
+ ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
|
|
|
+ if (src_tmp.GlyphsCount == 0)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ stbrp_pack_rects((stbrp_context*)spc.pack_info, src_tmp.Rects, src_tmp.GlyphsCount);
|
|
|
+
|
|
|
+ // Extend texture height and mark missing glyphs as non-packed so we won't render them.
|
|
|
+ // FIXME: We are not handling packing failure here (would happen if we got off TEX_HEIGHT_MAX or if a single if larger than TexWidth?)
|
|
|
+ for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++)
|
|
|
+ if (src_tmp.Rects[glyph_i].was_packed)
|
|
|
+ atlas->TexHeight = ImMax(atlas->TexHeight, src_tmp.Rects[glyph_i].y + src_tmp.Rects[glyph_i].h);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 7. Allocate texture
|
|
|
atlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight);
|
|
|
atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight);
|
|
|
atlas->TexPixelsAlpha8 = (unsigned char*)ImGui::MemAlloc(atlas->TexWidth * atlas->TexHeight);
|
|
|
@@ -1866,41 +1970,46 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
|
|
|
spc.pixels = atlas->TexPixelsAlpha8;
|
|
|
spc.height = atlas->TexHeight;
|
|
|
|
|
|
- // Second pass: render font characters
|
|
|
- for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
|
|
|
+ // 8. Render/rasterize font characters into the texture
|
|
|
+ for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
|
|
{
|
|
|
- ImFontConfig& cfg = atlas->ConfigData[input_i];
|
|
|
- ImFontTempBuildData& tmp = tmp_array[input_i];
|
|
|
- stbtt_PackSetOversampling(&spc, cfg.OversampleH, cfg.OversampleV);
|
|
|
- stbtt_PackFontRangesRenderIntoRects(&spc, &tmp.FontInfo, tmp.Ranges, tmp.RangesCount, tmp.Rects);
|
|
|
+ ImFontConfig& cfg = atlas->ConfigData[src_i];
|
|
|
+ ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
|
|
|
+ if (src_tmp.GlyphsCount == 0)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ stbtt_PackFontRangesRenderIntoRects(&spc, &src_tmp.FontInfo, &src_tmp.PackRange, 1, src_tmp.Rects);
|
|
|
+
|
|
|
+ // Apply multiply operator
|
|
|
if (cfg.RasterizerMultiply != 1.0f)
|
|
|
{
|
|
|
unsigned char multiply_table[256];
|
|
|
ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply);
|
|
|
- for (const stbrp_rect* r = tmp.Rects; r != tmp.Rects + tmp.RectsCount; r++)
|
|
|
+ stbrp_rect* r = &src_tmp.Rects[0];
|
|
|
+ for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++, r++)
|
|
|
if (r->was_packed)
|
|
|
- ImFontAtlasBuildMultiplyRectAlpha8(multiply_table, spc.pixels, r->x, r->y, r->w, r->h, spc.stride_in_bytes);
|
|
|
+ ImFontAtlasBuildMultiplyRectAlpha8(multiply_table, atlas->TexPixelsAlpha8, r->x, r->y, r->w, r->h, atlas->TexWidth * 1);
|
|
|
}
|
|
|
- tmp.Rects = NULL;
|
|
|
+ src_tmp.Rects = NULL;
|
|
|
}
|
|
|
|
|
|
// End packing
|
|
|
stbtt_PackEnd(&spc);
|
|
|
- ImGui::MemFree(buf_rects);
|
|
|
- buf_rects = NULL;
|
|
|
+ buf_rects.clear();
|
|
|
|
|
|
- // Third pass: setup ImFont and glyphs for runtime
|
|
|
- for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
|
|
|
+ // 9. Setup ImFont and glyphs for runtime
|
|
|
+ for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
|
|
{
|
|
|
- ImFontConfig& cfg = atlas->ConfigData[input_i];
|
|
|
- ImFontTempBuildData& tmp = tmp_array[input_i];
|
|
|
+ ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
|
|
|
+ if (src_tmp.GlyphsCount == 0)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ ImFontConfig& cfg = atlas->ConfigData[src_i];
|
|
|
ImFont* dst_font = cfg.DstFont; // We can have multiple input fonts writing into a same destination font (when using MergeMode=true)
|
|
|
- if (cfg.MergeMode)
|
|
|
- dst_font->BuildLookupTable();
|
|
|
|
|
|
- const float font_scale = stbtt_ScaleForPixelHeight(&tmp.FontInfo, cfg.SizePixels);
|
|
|
+ const float font_scale = stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels);
|
|
|
int unscaled_ascent, unscaled_descent, unscaled_line_gap;
|
|
|
- stbtt_GetFontVMetrics(&tmp.FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap);
|
|
|
+ stbtt_GetFontVMetrics(&src_tmp.FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap);
|
|
|
|
|
|
const float ascent = ImFloor(unscaled_ascent * font_scale + ((unscaled_ascent > 0.0f) ? +1 : -1));
|
|
|
const float descent = ImFloor(unscaled_descent * font_scale + ((unscaled_descent > 0.0f) ? +1 : -1));
|
|
|
@@ -1908,40 +2017,30 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
|
|
|
const float font_off_x = cfg.GlyphOffset.x;
|
|
|
const float font_off_y = cfg.GlyphOffset.y + (float)(int)(dst_font->Ascent + 0.5f);
|
|
|
|
|
|
- for (int i = 0; i < tmp.RangesCount; i++)
|
|
|
+ for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++)
|
|
|
{
|
|
|
- stbtt_pack_range& range = tmp.Ranges[i];
|
|
|
- for (int char_idx = 0; char_idx < range.num_chars; char_idx += 1)
|
|
|
- {
|
|
|
- const stbtt_packedchar& pc = range.chardata_for_range[char_idx];
|
|
|
- if (!pc.x0 && !pc.x1 && !pc.y0 && !pc.y1)
|
|
|
- continue;
|
|
|
-
|
|
|
- const int codepoint = range.first_unicode_codepoint_in_range + char_idx;
|
|
|
- if (cfg.MergeMode && dst_font->FindGlyphNoFallback((ImWchar)codepoint))
|
|
|
- continue;
|
|
|
-
|
|
|
- float char_advance_x_org = pc.xadvance;
|
|
|
- float char_advance_x_mod = ImClamp(char_advance_x_org, cfg.GlyphMinAdvanceX, cfg.GlyphMaxAdvanceX);
|
|
|
- float char_off_x = font_off_x;
|
|
|
- if (char_advance_x_org != char_advance_x_mod)
|
|
|
- char_off_x += cfg.PixelSnapH ? (float)(int)((char_advance_x_mod - char_advance_x_org) * 0.5f) : (char_advance_x_mod - char_advance_x_org) * 0.5f;
|
|
|
-
|
|
|
- stbtt_aligned_quad q;
|
|
|
- float dummy_x = 0.0f, dummy_y = 0.0f;
|
|
|
- stbtt_GetPackedQuad(range.chardata_for_range, atlas->TexWidth, atlas->TexHeight, char_idx, &dummy_x, &dummy_y, &q, 0);
|
|
|
- dst_font->AddGlyph((ImWchar)codepoint, q.x0 + char_off_x, q.y0 + font_off_y, q.x1 + char_off_x, q.y1 + font_off_y, q.s0, q.t0, q.s1, q.t1, char_advance_x_mod);
|
|
|
- }
|
|
|
+ const int codepoint = src_tmp.GlyphsList[glyph_i];
|
|
|
+ const stbtt_packedchar& pc = src_tmp.PackedChars[glyph_i];
|
|
|
+
|
|
|
+ const float char_advance_x_org = pc.xadvance;
|
|
|
+ const float char_advance_x_mod = ImClamp(char_advance_x_org, cfg.GlyphMinAdvanceX, cfg.GlyphMaxAdvanceX);
|
|
|
+ float char_off_x = font_off_x;
|
|
|
+ if (char_advance_x_org != char_advance_x_mod)
|
|
|
+ char_off_x += cfg.PixelSnapH ? (float)(int)((char_advance_x_mod - char_advance_x_org) * 0.5f) : (char_advance_x_mod - char_advance_x_org) * 0.5f;
|
|
|
+
|
|
|
+ // Register glyph
|
|
|
+ stbtt_aligned_quad q;
|
|
|
+ float dummy_x = 0.0f, dummy_y = 0.0f;
|
|
|
+ stbtt_GetPackedQuad(src_tmp.PackedChars, atlas->TexWidth, atlas->TexHeight, glyph_i, &dummy_x, &dummy_y, &q, 0);
|
|
|
+ dst_font->AddGlyph((ImWchar)codepoint, q.x0 + char_off_x, q.y0 + font_off_y, q.x1 + char_off_x, q.y1 + font_off_y, q.s0, q.t0, q.s1, q.t1, char_advance_x_mod);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // Cleanup temporaries
|
|
|
- ImGui::MemFree(buf_packedchars);
|
|
|
- ImGui::MemFree(buf_ranges);
|
|
|
- ImGui::MemFree(tmp_array);
|
|
|
+ // Cleanup temporary (ImVector doesn't honor destructor)
|
|
|
+ for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
|
|
+ src_tmp_array[src_i].~ImFontBuildSrcData();
|
|
|
|
|
|
ImFontAtlasBuildFinish(atlas);
|
|
|
-
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
@@ -1969,16 +2068,17 @@ void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* f
|
|
|
font->ConfigDataCount++;
|
|
|
}
|
|
|
|
|
|
-void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* pack_context_opaque)
|
|
|
+void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque)
|
|
|
{
|
|
|
- stbrp_context* pack_context = (stbrp_context*)pack_context_opaque;
|
|
|
+ stbrp_context* pack_context = (stbrp_context*)stbrp_context_opaque;
|
|
|
+ IM_ASSERT(pack_context != NULL);
|
|
|
|
|
|
ImVector<ImFontAtlas::CustomRect>& user_rects = atlas->CustomRects;
|
|
|
IM_ASSERT(user_rects.Size >= 1); // We expect at least the default custom rects to be registered, else something went wrong.
|
|
|
|
|
|
ImVector<stbrp_rect> pack_rects;
|
|
|
pack_rects.resize(user_rects.Size);
|
|
|
- memset(pack_rects.Data, 0, sizeof(stbrp_rect) * user_rects.Size);
|
|
|
+ memset(pack_rects.Data, 0, (size_t)pack_rects.size_in_bytes());
|
|
|
for (int i = 0; i < user_rects.Size; i++)
|
|
|
{
|
|
|
pack_rects[i].w = user_rects[i].Width;
|
|
|
@@ -2078,7 +2178,8 @@ const ImWchar* ImFontAtlas::GetGlyphRangesChineseFull()
|
|
|
static const ImWchar ranges[] =
|
|
|
{
|
|
|
0x0020, 0x00FF, // Basic Latin + Latin Supplement
|
|
|
- 0x3000, 0x30FF, // Punctuations, Hiragana, Katakana
|
|
|
+ 0x2000, 0x206F, // General Punctuation
|
|
|
+ 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
|
|
|
0x31F0, 0x31FF, // Katakana Phonetic Extensions
|
|
|
0xFF00, 0xFFEF, // Half-width characters
|
|
|
0x4e00, 0x9FAF, // CJK Ideograms
|
|
|
@@ -2098,7 +2199,7 @@ static void UnpackAccumulativeOffsetsIntoRanges(int base_codepoint, const short*
|
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
-// [SECTION] ImFontAtlas glyph ranges helpers + GlyphRangesBuilder
|
|
|
+// [SECTION] ImFontAtlas glyph ranges helpers
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
|
|
const ImWchar* ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon()
|
|
|
@@ -2106,7 +2207,7 @@ const ImWchar* ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon()
|
|
|
// Store 2500 regularly used characters for Simplified Chinese.
|
|
|
// 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
|
|
|
// This table covers 97.97% of all characters used during the month in July, 1987.
|
|
|
- // You can use ImFontAtlas::GlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters.
|
|
|
+ // You can use ImFontGlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters.
|
|
|
// (Stored as accumulative offsets from the initial unicode codepoint 0x4E00. This encoding is designed to helps us compact the source code size.)
|
|
|
static const short accumulative_offsets_from_0x4E00[] =
|
|
|
{
|
|
|
@@ -2154,9 +2255,10 @@ const ImWchar* ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon()
|
|
|
static ImWchar base_ranges[] = // not zero-terminated
|
|
|
{
|
|
|
0x0020, 0x00FF, // Basic Latin + Latin Supplement
|
|
|
- 0x3000, 0x30FF, // Punctuations, Hiragana, Katakana
|
|
|
+ 0x2000, 0x206F, // General Punctuation
|
|
|
+ 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
|
|
|
0x31F0, 0x31FF, // Katakana Phonetic Extensions
|
|
|
- 0xFF00, 0xFFEF, // Half-width characters
|
|
|
+ 0xFF00, 0xFFEF // Half-width characters
|
|
|
};
|
|
|
static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00) * 2 + 1] = { 0 };
|
|
|
if (!full_ranges[0])
|
|
|
@@ -2172,7 +2274,7 @@ const ImWchar* ImFontAtlas::GetGlyphRangesJapanese()
|
|
|
// 1946 common ideograms code points for Japanese
|
|
|
// Sourced from http://theinstructionlimit.com/common-kanji-character-ranges-for-xna-spritefont-rendering
|
|
|
// FIXME: Source a list of the revised 2136 Joyo Kanji list from 2010 and rebuild this.
|
|
|
- // You can use ImFontAtlas::GlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters.
|
|
|
+ // You can use ImFontGlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters.
|
|
|
// (Stored as accumulative offsets from the initial unicode codepoint 0x4E00. This encoding is designed to helps us compact the source code size.)
|
|
|
static const short accumulative_offsets_from_0x4E00[] =
|
|
|
{
|
|
|
@@ -2207,14 +2309,14 @@ const ImWchar* ImFontAtlas::GetGlyphRangesJapanese()
|
|
|
3,7,6,3,1,2,3,9,1,3,1,6,3,2,1,3,11,3,1,6,10,3,2,3,1,2,1,5,1,1,11,3,6,4,1,7,2,1,2,5,5,34,4,14,18,4,19,7,5,8,2,6,79,1,5,2,14,8,2,9,2,1,36,28,16,
|
|
|
4,1,1,1,2,12,6,42,39,16,23,7,15,15,3,2,12,7,21,64,6,9,28,8,12,3,3,41,59,24,51,55,57,294,9,9,2,6,2,15,1,2,13,38,90,9,9,9,3,11,7,1,1,1,5,6,3,2,
|
|
|
1,2,2,3,8,1,4,4,1,5,7,1,4,3,20,4,9,1,1,1,5,5,17,1,5,2,6,2,4,1,4,5,7,3,18,11,11,32,7,5,4,7,11,127,8,4,3,3,1,10,1,1,6,21,14,1,16,1,7,1,3,6,9,65,
|
|
|
- 51,4,3,13,3,10,1,1,12,9,21,110,3,19,24,1,1,10,62,4,1,29,42,78,28,20,18,82,6,3,15,6,84,58,253,15,155,264,15,21,9,14,7,58,40,39,
|
|
|
+ 51,4,3,13,3,10,1,1,12,9,21,110,3,19,24,1,1,10,62,4,1,29,42,78,28,20,18,82,6,3,15,6,84,58,253,15,155,264,15,21,9,14,7,58,40,39,
|
|
|
};
|
|
|
static ImWchar base_ranges[] = // not zero-terminated
|
|
|
{
|
|
|
0x0020, 0x00FF, // Basic Latin + Latin Supplement
|
|
|
- 0x3000, 0x30FF, // Punctuations, Hiragana, Katakana
|
|
|
+ 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
|
|
|
0x31F0, 0x31FF, // Katakana Phonetic Extensions
|
|
|
- 0xFF00, 0xFFEF, // Half-width characters
|
|
|
+ 0xFF00, 0xFFEF // Half-width characters
|
|
|
};
|
|
|
static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00)*2 + 1] = { 0 };
|
|
|
if (!full_ranges[0])
|
|
|
@@ -2250,7 +2352,11 @@ const ImWchar* ImFontAtlas::GetGlyphRangesThai()
|
|
|
return &ranges[0];
|
|
|
}
|
|
|
|
|
|
-void ImFontAtlas::GlyphRangesBuilder::AddText(const char* text, const char* text_end)
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+// [SECTION] ImFontGlyphRangesBuilder
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+
|
|
|
+void ImFontGlyphRangesBuilder::AddText(const char* text, const char* text_end)
|
|
|
{
|
|
|
while (text_end ? (text < text_end) : *text)
|
|
|
{
|
|
|
@@ -2264,14 +2370,14 @@ void ImFontAtlas::GlyphRangesBuilder::AddText(const char* text, const char* text
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void ImFontAtlas::GlyphRangesBuilder::AddRanges(const ImWchar* ranges)
|
|
|
+void ImFontGlyphRangesBuilder::AddRanges(const ImWchar* ranges)
|
|
|
{
|
|
|
for (; ranges[0]; ranges += 2)
|
|
|
for (ImWchar c = ranges[0]; c <= ranges[1]; c++)
|
|
|
AddChar(c);
|
|
|
}
|
|
|
|
|
|
-void ImFontAtlas::GlyphRangesBuilder::BuildRanges(ImVector<ImWchar>* out_ranges)
|
|
|
+void ImFontGlyphRangesBuilder::BuildRanges(ImVector<ImWchar>* out_ranges)
|
|
|
{
|
|
|
for (int n = 0; n < 0x10000; n++)
|
|
|
if (GetBit(n))
|
|
|
@@ -2423,7 +2529,7 @@ const ImFontGlyph* ImFont::FindGlyph(ImWchar c) const
|
|
|
{
|
|
|
if (c >= IndexLookup.Size)
|
|
|
return FallbackGlyph;
|
|
|
- const ImWchar i = IndexLookup[c];
|
|
|
+ const ImWchar i = IndexLookup.Data[c];
|
|
|
if (i == (ImWchar)-1)
|
|
|
return FallbackGlyph;
|
|
|
return &Glyphs.Data[i];
|
|
|
@@ -2433,7 +2539,7 @@ const ImFontGlyph* ImFont::FindGlyphNoFallback(ImWchar c) const
|
|
|
{
|
|
|
if (c >= IndexLookup.Size)
|
|
|
return NULL;
|
|
|
- const ImWchar i = IndexLookup[c];
|
|
|
+ const ImWchar i = IndexLookup.Data[c];
|
|
|
if (i == (ImWchar)-1)
|
|
|
return NULL;
|
|
|
return &Glyphs.Data[i];
|
|
|
@@ -2493,7 +2599,7 @@ const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const c
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX[(int)c] : FallbackAdvanceX);
|
|
|
+ const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX.Data[c] : FallbackAdvanceX);
|
|
|
if (ImCharIsBlankW(c))
|
|
|
{
|
|
|
if (inside_word)
|
|
|
@@ -2610,7 +2716,7 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX[(int)c] : FallbackAdvanceX) * scale;
|
|
|
+ const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX.Data[c] : FallbackAdvanceX) * scale;
|
|
|
if (line_width + char_width >= max_width)
|
|
|
{
|
|
|
s = prev_s;
|
|
|
@@ -2683,7 +2789,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col
|
|
|
while (y_end < clip_rect.w && s_end < text_end)
|
|
|
{
|
|
|
s_end = (const char*)memchr(s_end, '\n', text_end - s_end);
|
|
|
- s = s ? s + 1 : text_end;
|
|
|
+ s_end = s_end ? s_end + 1 : text_end;
|
|
|
y_end += line_height;
|
|
|
}
|
|
|
text_end = s_end;
|
|
|
@@ -2932,13 +3038,14 @@ void ImGui::RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, Im
|
|
|
const float inv_rounding = 1.0f / rounding;
|
|
|
const float arc0_b = ImAcos01(1.0f - (p0.x - rect.Min.x) * inv_rounding);
|
|
|
const float arc0_e = ImAcos01(1.0f - (p1.x - rect.Min.x) * inv_rounding);
|
|
|
+ const float half_pi = IM_PI * 0.5f; // We will == compare to this because we know this is the exact value ImAcos01 can return.
|
|
|
const float x0 = ImMax(p0.x, rect.Min.x + rounding);
|
|
|
if (arc0_b == arc0_e)
|
|
|
{
|
|
|
draw_list->PathLineTo(ImVec2(x0, p1.y));
|
|
|
draw_list->PathLineTo(ImVec2(x0, p0.y));
|
|
|
}
|
|
|
- else if (arc0_b == 0.0f && arc0_e == IM_PI*0.5f)
|
|
|
+ else if (arc0_b == 0.0f && arc0_e == half_pi)
|
|
|
{
|
|
|
draw_list->PathArcToFast(ImVec2(x0, p1.y - rounding), rounding, 3, 6); // BL
|
|
|
draw_list->PathArcToFast(ImVec2(x0, p0.y + rounding), rounding, 6, 9); // TR
|
|
|
@@ -2958,7 +3065,7 @@ void ImGui::RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, Im
|
|
|
draw_list->PathLineTo(ImVec2(x1, p0.y));
|
|
|
draw_list->PathLineTo(ImVec2(x1, p1.y));
|
|
|
}
|
|
|
- else if (arc1_b == 0.0f && arc1_e == IM_PI*0.5f)
|
|
|
+ else if (arc1_b == 0.0f && arc1_e == half_pi)
|
|
|
{
|
|
|
draw_list->PathArcToFast(ImVec2(x1, p0.y + rounding), rounding, 9, 12); // TR
|
|
|
draw_list->PathArcToFast(ImVec2(x1, p1.y - rounding), rounding, 0, 3); // BR
|
|
|
@@ -2990,11 +3097,14 @@ void ImGui::RenderRectFilledWithHole(ImDrawList* draw_list, ImRect outer, ImRect
|
|
|
if (fill_R && fill_D) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Max.y), ImVec2(outer.Max.x, outer.Max.y), col, rounding, ImDrawCornerFlags_BotRight);
|
|
|
}
|
|
|
|
|
|
-// FIXME: Rendering an ellipsis "..." is a surprisingly tricky problem... can't rely on font glyph having it, and regular dot are typically too wide.
|
|
|
-// If we render a dot/shape ourselves it comes with the risk that it wouldn't match the boldness or positioning of what the font uses...
|
|
|
-void ImGui::RenderPixelEllipsis(ImDrawList* draw_list, ImFont* font, ImVec2 pos, int count, ImU32 col)
|
|
|
+// FIXME: Rendering an ellipsis "..." is a surprisingly tricky problem for us... we cannot rely on font glyph having it,
|
|
|
+// and regular dot are typically too wide. If we render a dot/shape ourselves it comes with the risk that it wouldn't match
|
|
|
+// the boldness or positioning of what the font uses...
|
|
|
+void ImGui::RenderPixelEllipsis(ImDrawList* draw_list, ImVec2 pos, int count, ImU32 col)
|
|
|
{
|
|
|
- pos.y += (float)(int)(font->DisplayOffset.y + font->Ascent + 0.5f - 1.0f);
|
|
|
+ ImFont* font = draw_list->_Data->Font;
|
|
|
+ const float font_scale = draw_list->_Data->FontSize / font->FontSize;
|
|
|
+ pos.y += (float)(int)(font->DisplayOffset.y + font->Ascent * font_scale + 0.5f - 1.0f);
|
|
|
for (int dot_n = 0; dot_n < count; dot_n++)
|
|
|
draw_list->AddRectFilled(ImVec2(pos.x + dot_n * 2.0f, pos.y), ImVec2(pos.x + dot_n * 2.0f + 1.0f, pos.y + 1.0f), col);
|
|
|
}
|