Update imgui.

This commit is contained in:
Mr_Goldberg
2021-06-13 00:07:16 -04:00
parent 02195f5636
commit 7350397f9d
19 changed files with 496 additions and 233 deletions

View File

@ -1,4 +1,4 @@
// dear imgui, v1.83 WIP
// dear imgui, v1.84 WIP
// (main code and documentation)
// Help:
@ -304,9 +304,9 @@ CODE
}
else
{
// The texture for the draw call is specified by pcmd->TextureId.
// The texture for the draw call is specified by pcmd->GetTexID().
// The vast majority of draw calls will use the Dear ImGui texture atlas, which value you have set yourself during initialization.
MyEngineBindTexture((MyTexture*)pcmd->TextureId);
MyEngineBindTexture((MyTexture*)pcmd->GetTexID());
// We are using scissoring to clip some objects. All low-level graphics API should support it.
// - If your engine doesn't support scissoring yet, you may ignore this at first. You will get some small glitches
@ -376,6 +376,9 @@ CODE
When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files.
You can read releases logs https://github.com/ocornut/imgui/releases for more details.
- 2021/05/19 (1.83) - backends: obsoleted direct access to ImDrawCmd::TextureId in favor of calling ImDrawCmd::GetTexID().
- if you are using official backends from the source tree: you have nothing to do.
- if you have copied old backend code or using your own: change access to draw_cmd->TextureId to draw_cmd->GetTexID().
- 2021/03/12 (1.82) - upgraded ImDrawList::AddRect(), AddRectFilled(), PathRect() to use ImDrawFlags instead of ImDrawCornersFlags.
- ImDrawCornerFlags_TopLeft -> use ImDrawFlags_RoundCornersTopLeft
- ImDrawCornerFlags_BotRight -> use ImDrawFlags_RoundCornersBottomRight
@ -1698,7 +1701,7 @@ int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end)
}
// Based on stb_to_utf8() from github.com/nothings/stb/
static inline int ImTextCharToUtf8(char* buf, int buf_size, unsigned int c)
static inline int ImTextCharToUtf8_inline(char* buf, int buf_size, unsigned int c)
{
if (c < 0x80)
{
@ -1733,6 +1736,13 @@ static inline int ImTextCharToUtf8(char* buf, int buf_size, unsigned int c)
return 0;
}
const char* ImTextCharToUtf8(char out_buf[5], unsigned int c)
{
int count = ImTextCharToUtf8_inline(out_buf, 5, c);
out_buf[count] = 0;
return out_buf;
}
// Not optimal but we very rarely use this function.
int ImTextCountUtf8BytesFromChar(const char* in_text, const char* in_text_end)
{
@ -1749,20 +1759,20 @@ static inline int ImTextCountUtf8BytesFromChar(unsigned int c)
return 3;
}
int ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end)
int ImTextStrToUtf8(char* out_buf, int out_buf_size, const ImWchar* in_text, const ImWchar* in_text_end)
{
char* buf_out = buf;
const char* buf_end = buf + buf_size;
while (buf_out < buf_end - 1 && (!in_text_end || in_text < in_text_end) && *in_text)
char* buf_p = out_buf;
const char* buf_end = out_buf + out_buf_size;
while (buf_p < buf_end - 1 && (!in_text_end || in_text < in_text_end) && *in_text)
{
unsigned int c = (unsigned int)(*in_text++);
if (c < 0x80)
*buf_out++ = (char)c;
*buf_p++ = (char)c;
else
buf_out += ImTextCharToUtf8(buf_out, (int)(buf_end - buf_out - 1), c);
buf_p += ImTextCharToUtf8_inline(buf_p, (int)(buf_end - buf_p - 1), c);
}
*buf_out = 0;
return (int)(buf_out - buf);
*buf_p = 0;
return (int)(buf_p - out_buf);
}
int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end)
@ -3923,7 +3933,8 @@ void ImGui::NewFrame()
g.FramerateSecPerFrameAccum += g.IO.DeltaTime - g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx];
g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx] = g.IO.DeltaTime;
g.FramerateSecPerFrameIdx = (g.FramerateSecPerFrameIdx + 1) % IM_ARRAYSIZE(g.FramerateSecPerFrame);
g.IO.Framerate = (g.FramerateSecPerFrameAccum > 0.0f) ? (1.0f / (g.FramerateSecPerFrameAccum / (float)IM_ARRAYSIZE(g.FramerateSecPerFrame))) : FLT_MAX;
g.FramerateSecPerFrameCount = ImMin(g.FramerateSecPerFrameCount + 1, IM_ARRAYSIZE(g.FramerateSecPerFrame));
g.IO.Framerate = (g.FramerateSecPerFrameAccum > 0.0f) ? (1.0f / (g.FramerateSecPerFrameAccum / (float)g.FramerateSecPerFrameCount)) : FLT_MAX;
UpdateViewportsNewFrame();
@ -4060,6 +4071,9 @@ void ImGui::NewFrame()
for (int i = 0; i < g.TablesLastTimeActive.Size; i++)
if (g.TablesLastTimeActive[i] >= 0.0f && g.TablesLastTimeActive[i] < memory_compact_start_time)
TableGcCompactTransientBuffers(g.Tables.GetByIndex(i));
for (int i = 0; i < g.TablesTempDataStack.Size; i++)
if (g.TablesTempDataStack[i].LastTimeActive >= 0.0f && g.TablesTempDataStack[i].LastTimeActive < memory_compact_start_time)
TableGcCompactTransientBuffers(&g.TablesTempDataStack[i]);
if (g.GcCompactAll)
GcCompactTransientMiscBuffers();
g.GcCompactAll = false;
@ -4099,20 +4113,20 @@ void ImGui::UpdateDebugToolItemPicker()
if (g.DebugItemPickerActive)
{
const ImGuiID hovered_id = g.HoveredIdPreviousFrame;
ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
if (ImGui::IsKeyPressedMap(ImGuiKey_Escape))
SetMouseCursor(ImGuiMouseCursor_Hand);
if (IsKeyPressedMap(ImGuiKey_Escape))
g.DebugItemPickerActive = false;
if (ImGui::IsMouseClicked(0) && hovered_id)
if (IsMouseClicked(0) && hovered_id)
{
g.DebugItemPickerBreakId = hovered_id;
g.DebugItemPickerActive = false;
}
ImGui::SetNextWindowBgAlpha(0.60f);
ImGui::BeginTooltip();
ImGui::Text("HoveredId: 0x%08X", hovered_id);
ImGui::Text("Press ESC to abort picking.");
ImGui::TextColored(GetStyleColorVec4(hovered_id ? ImGuiCol_Text : ImGuiCol_TextDisabled), "Click to break in debugger!");
ImGui::EndTooltip();
SetNextWindowBgAlpha(0.60f);
BeginTooltip();
Text("HoveredId: 0x%08X", hovered_id);
Text("Press ESC to abort picking.");
TextColored(GetStyleColorVec4(hovered_id ? ImGuiCol_Text : ImGuiCol_TextDisabled), "Click to break in debugger!");
EndTooltip();
}
}
@ -4134,10 +4148,8 @@ void ImGui::Initialize(ImGuiContext* context)
g.SettingsHandlers.push_back(ini_handler);
}
#ifdef IMGUI_HAS_TABLE
// Add .ini handle for ImGuiTable type
TableSettingsInstallHandler(context);
#endif // #ifdef IMGUI_HAS_TABLE
// Create default viewport
ImGuiViewportP* viewport = IM_NEW(ImGuiViewportP)();
@ -4204,7 +4216,9 @@ void ImGui::Shutdown(ImGuiContext* context)
g.ShrinkWidthBuffer.clear();
g.Tables.Clear();
g.CurrentTableStack.clear();
for (int i = 0; i < g.TablesTempDataStack.Size; i++)
g.TablesTempDataStack[i].~ImGuiTableTempData();
g.TablesTempDataStack.clear();
g.DrawChannelsTempMergeBuffer.clear();
g.ClipboardHandlerData.clear();
@ -7206,13 +7220,11 @@ void ImGui::ErrorCheckEndFrameRecover(ImGuiErrorLogCallback log_callback, voi
ImGuiContext& g = *GImGui;
while (g.CurrentWindowStack.Size > 0)
{
#ifdef IMGUI_HAS_TABLE
while (g.CurrentTable && (g.CurrentTable->OuterWindow == g.CurrentWindow || g.CurrentTable->InnerWindow == g.CurrentWindow))
{
if (log_callback) log_callback(user_data, "Recovered from missing EndTable() in '%s'", g.CurrentTable->OuterWindow->Name);
EndTable();
}
#endif
ImGuiWindow* window = g.CurrentWindow;
IM_ASSERT(window != NULL);
while (g.CurrentTabBar != NULL) //-V1044
@ -8517,7 +8529,7 @@ ImVec2 ImGui::FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& s
}
// Note that this is used for popups, which can overlap the non work-area of individual viewports.
ImRect ImGui::GetWindowAllowedExtentRect(ImGuiWindow* window)
ImRect ImGui::GetPopupAllowedExtentRect(ImGuiWindow* window)
{
ImGuiContext& g = *GImGui;
IM_UNUSED(window);
@ -8531,7 +8543,7 @@ ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window)
{
ImGuiContext& g = *GImGui;
ImRect r_outer = GetWindowAllowedExtentRect(window);
ImRect r_outer = GetPopupAllowedExtentRect(window);
if (window->Flags & ImGuiWindowFlags_ChildMenu)
{
// Child menus typically request _any_ position within the parent menu item, and then we move the new menu outside the parent bounds.
@ -9659,8 +9671,13 @@ static void ImGui::NavUpdateWindowing()
NavInitWindow(apply_focus_window, false);
// If the window has ONLY a menu layer (no main layer), select it directly
// FIXME-NAV: This should be done in NavInit.. or in FocusWindow..
if (apply_focus_window->DC.NavLayersActiveMask == (1 << ImGuiNavLayer_Menu))
// Use NavLayersActiveMaskNext since windows didn't have a chance to be Begin()-ed on this frame,
// so CTRL+Tab where the keys are only held for 1 frame will be able to use correct layers mask since
// the target window as already been previewed once.
// FIXME-NAV: This should be done in NavInit.. or in FocusWindow... However in both of those cases,
// we won't have a guarantee that windows has been visible before and therefore NavLayersActiveMask*
// won't be valid.
if (apply_focus_window->DC.NavLayersActiveMaskNext == (1 << ImGuiNavLayer_Menu))
g.NavLayer = ImGuiNavLayer_Menu;
}
if (apply_focus_window)
@ -10900,6 +10917,10 @@ static void MetricsHelpMarker(const char* desc)
}
}
#ifndef IMGUI_DISABLE_DEMO_WINDOWS
namespace ImGui { void ShowFontAtlas(ImFontAtlas* atlas); }
#endif
void ImGui::ShowMetricsWindow(bool* p_open)
{
if (!Begin("Dear ImGui Metrics/Debugger", p_open))
@ -11002,10 +11023,10 @@ void ImGui::ShowMetricsWindow(bool* p_open)
cfg->ShowTablesRects |= Combo("##show_table_rects_type", &cfg->ShowTablesRectsType, trt_rects_names, TRT_Count, TRT_Count);
if (cfg->ShowTablesRects && g.NavWindow != NULL)
{
for (int table_n = 0; table_n < g.Tables.GetSize(); table_n++)
for (int table_n = 0; table_n < g.Tables.GetMapSize(); table_n++)
{
ImGuiTable* table = g.Tables.GetByIndex(table_n);
if (table->LastFrameActive < g.FrameCount - 1 || (table->OuterWindow != g.NavWindow && table->InnerWindow != g.NavWindow))
ImGuiTable* table = g.Tables.TryGetMapData(table_n);
if (table == NULL || table->LastFrameActive < g.FrameCount - 1 || (table->OuterWindow != g.NavWindow && table->InnerWindow != g.NavWindow))
continue;
BulletText("Table 0x%08X (%d columns, in '%s')", table->ID, table->ColumnsCount, table->OuterWindow->Name);
@ -11087,22 +11108,36 @@ void ImGui::ShowMetricsWindow(bool* p_open)
}
// Details for TabBars
if (TreeNode("TabBars", "Tab Bars (%d)", g.TabBars.GetSize()))
if (TreeNode("TabBars", "Tab Bars (%d)", g.TabBars.GetAliveCount()))
{
for (int n = 0; n < g.TabBars.GetSize(); n++)
DebugNodeTabBar(g.TabBars.GetByIndex(n), "TabBar");
for (int n = 0; n < g.TabBars.GetMapSize(); n++)
if (ImGuiTabBar* tab_bar = g.TabBars.TryGetMapData(n))
{
PushID(tab_bar);
DebugNodeTabBar(tab_bar, "TabBar");
PopID();
}
TreePop();
}
// Details for Tables
#ifdef IMGUI_HAS_TABLE
if (TreeNode("Tables", "Tables (%d)", g.Tables.GetSize()))
if (TreeNode("Tables", "Tables (%d)", g.Tables.GetAliveCount()))
{
for (int n = 0; n < g.Tables.GetSize(); n++)
DebugNodeTable(g.Tables.GetByIndex(n));
for (int n = 0; n < g.Tables.GetMapSize(); n++)
if (ImGuiTable* table = g.Tables.TryGetMapData(n))
DebugNodeTable(table);
TreePop();
}
#endif // #ifdef IMGUI_HAS_TABLE
// Details for Fonts
#ifndef IMGUI_DISABLE_DEMO_WINDOWS
ImFontAtlas* atlas = g.IO.Fonts;
if (TreeNode("Fonts", "Fonts (%d)", atlas->Fonts.Size))
{
ShowFontAtlas(atlas);
TreePop();
}
#endif
// Details for Docking
#ifdef IMGUI_HAS_DOCK
@ -11142,14 +11177,12 @@ void ImGui::ShowMetricsWindow(bool* p_open)
TreePop();
}
#ifdef IMGUI_HAS_TABLE
if (TreeNode("SettingsTables", "Settings packed data: Tables: %d bytes", g.SettingsTables.size()))
{
for (ImGuiTableSettings* settings = g.SettingsTables.begin(); settings != NULL; settings = g.SettingsTables.next_chunk(settings))
DebugNodeTableSettings(settings);
TreePop();
}
#endif // #ifdef IMGUI_HAS_TABLE
#ifdef IMGUI_HAS_DOCK
#endif // #ifdef IMGUI_HAS_DOCK
@ -11223,14 +11256,13 @@ void ImGui::ShowMetricsWindow(bool* p_open)
}
}
#ifdef IMGUI_HAS_TABLE
// Overlay: Display Tables Rectangles
if (cfg->ShowTablesRects)
{
for (int table_n = 0; table_n < g.Tables.GetSize(); table_n++)
for (int table_n = 0; table_n < g.Tables.GetMapSize(); table_n++)
{
ImGuiTable* table = g.Tables.GetByIndex(table_n);
if (table->LastFrameActive < g.FrameCount - 1)
ImGuiTable* table = g.Tables.TryGetMapData(table_n);
if (table == NULL || table->LastFrameActive < g.FrameCount - 1)
continue;
ImDrawList* draw_list = GetForegroundDrawList(table->OuterWindow);
if (cfg->ShowTablesRectsType >= TRT_ColumnsRect)
@ -11250,7 +11282,6 @@ void ImGui::ShowMetricsWindow(bool* p_open)
}
}
}
#endif // #ifdef IMGUI_HAS_TABLE
#ifdef IMGUI_HAS_DOCK
// Overlay: Display Docking info
@ -11262,6 +11293,25 @@ void ImGui::ShowMetricsWindow(bool* p_open)
End();
}
// [DEBUG] List fonts in a font atlas and display its texture
void ImGui::ShowFontAtlas(ImFontAtlas* atlas)
{
for (int i = 0; i < atlas->Fonts.Size; i++)
{
ImFont* font = atlas->Fonts[i];
PushID(font);
DebugNodeFont(font);
PopID();
}
if (TreeNode("Atlas texture", "Atlas texture (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight))
{
ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
ImVec4 border_col = ImVec4(1.0f, 1.0f, 1.0f, 0.5f);
Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), tint_col, border_col);
TreePop();
}
}
// [DEBUG] Display contents of Columns
void ImGui::DebugNodeColumns(ImGuiOldColumns* columns)
{
@ -11396,6 +11446,102 @@ void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, co
out_draw_list->Flags = backup_flags;
}
// [DEBUG] Display details for a single font, called by ShowStyleEditor().
void ImGui::DebugNodeFont(ImFont* font)
{
bool opened = TreeNode(font, "Font: \"%s\"\n%.2f px, %d glyphs, %d file(s)",
font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size, font->ConfigDataCount);
SameLine();
if (SmallButton("Set as default"))
GetIO().FontDefault = font;
if (!opened)
return;
// Display preview text
PushFont(font);
Text("The quick brown fox jumps over the lazy dog");
PopFont();
// Display details
SetNextItemWidth(GetFontSize() * 8);
DragFloat("Font scale", &font->Scale, 0.005f, 0.3f, 2.0f, "%.1f");
SameLine(); MetricsHelpMarker(
"Note than the default embedded font is NOT meant to be scaled.\n\n"
"Font are currently rendered into bitmaps at a given size at the time of building the atlas. "
"You may oversample them to get some flexibility with scaling. "
"You can also render at multiple sizes and select which one to use at runtime.\n\n"
"(Glimmer of hope: the atlas system will be rewritten in the future to make scaling more flexible.)");
Text("Ascent: %f, Descent: %f, Height: %f", font->Ascent, font->Descent, font->Ascent - font->Descent);
char c_str[5];
Text("Fallback character: '%s' (U+%04X)", ImTextCharToUtf8(c_str, font->FallbackChar), font->FallbackChar);
Text("Ellipsis character: '%s' (U+%04X)", ImTextCharToUtf8(c_str, font->EllipsisChar), font->EllipsisChar);
const int surface_sqrt = (int)ImSqrt((float)font->MetricsTotalSurface);
Text("Texture Area: about %d px ~%dx%d px", font->MetricsTotalSurface, surface_sqrt, surface_sqrt);
for (int config_i = 0; config_i < font->ConfigDataCount; config_i++)
if (font->ConfigData)
if (const ImFontConfig* cfg = &font->ConfigData[config_i])
BulletText("Input %d: \'%s\', Oversample: (%d,%d), PixelSnapH: %d, Offset: (%.1f,%.1f)",
config_i, cfg->Name, cfg->OversampleH, cfg->OversampleV, cfg->PixelSnapH, cfg->GlyphOffset.x, cfg->GlyphOffset.y);
// Display all glyphs of the fonts in separate pages of 256 characters
if (TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size))
{
ImDrawList* draw_list = GetWindowDrawList();
const ImU32 glyph_col = GetColorU32(ImGuiCol_Text);
const float cell_size = font->FontSize * 1;
const float cell_spacing = GetStyle().ItemSpacing.y;
for (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; base += 256)
{
// Skip ahead if a large bunch of glyphs are not present in the font (test in chunks of 4k)
// This is only a small optimization to reduce the number of iterations when IM_UNICODE_MAX_CODEPOINT
// is large // (if ImWchar==ImWchar32 we will do at least about 272 queries here)
if (!(base & 4095) && font->IsGlyphRangeUnused(base, base + 4095))
{
base += 4096 - 256;
continue;
}
int count = 0;
for (unsigned int n = 0; n < 256; n++)
if (font->FindGlyphNoFallback((ImWchar)(base + n)))
count++;
if (count <= 0)
continue;
if (!TreeNode((void*)(intptr_t)base, "U+%04X..U+%04X (%d %s)", base, base + 255, count, count > 1 ? "glyphs" : "glyph"))
continue;
// Draw a 16x16 grid of glyphs
ImVec2 base_pos = GetCursorScreenPos();
for (unsigned int n = 0; n < 256; n++)
{
// We use ImFont::RenderChar as a shortcut because we don't have UTF-8 conversion functions
// available here and thus cannot easily generate a zero-terminated UTF-8 encoded string.
ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + (n / 16) * (cell_size + cell_spacing));
ImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size);
const ImFontGlyph* glyph = font->FindGlyphNoFallback((ImWchar)(base + n));
draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255, 255, 255, 100) : IM_COL32(255, 255, 255, 50));
if (glyph)
font->RenderChar(draw_list, cell_size, cell_p1, glyph_col, (ImWchar)(base + n));
if (glyph && IsMouseHoveringRect(cell_p1, cell_p2))
{
BeginTooltip();
Text("Codepoint: U+%04X", base + n);
Separator();
Text("Visible: %d", glyph->Visible);
Text("AdvanceX: %.1f", glyph->AdvanceX);
Text("Pos: (%.2f,%.2f)->(%.2f,%.2f)", glyph->X0, glyph->Y0, glyph->X1, glyph->Y1);
Text("UV: (%.3f,%.3f)->(%.3f,%.3f)", glyph->U0, glyph->V0, glyph->U1, glyph->V1);
EndTooltip();
}
}
Dummy(ImVec2((cell_size + cell_spacing) * 16, (cell_size + cell_spacing) * 16));
TreePop();
}
TreePop();
}
TreePop();
}
// [DEBUG] Display contents of ImGuiStorage
void ImGui::DebugNodeStorage(ImGuiStorage* storage, const char* label)
{
@ -11420,7 +11566,7 @@ void ImGui::DebugNodeTabBar(ImGuiTabBar* tab_bar, const char* label)
p += ImFormatString(p, buf_end - p, "%s 0x%08X (%d tabs)%s", label, tab_bar->ID, tab_bar->Tabs.Size, is_active ? "" : " *Inactive*");
IM_UNUSED(p);
if (!is_active) { PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); }
bool open = TreeNode(tab_bar, "%s", buf);
bool open = TreeNode(label, "%s", buf);
if (!is_active) { PopStyleColor(); }
if (is_active && IsItemHovered())
{
@ -11546,9 +11692,11 @@ void ImGui::DebugNodeWindowsList(ImVector<ImGuiWindow*>* windows, const char* la
#else
void ImGui::ShowMetricsWindow(bool*) {}
void ImGui::ShowFontAtlas(ImFontAtlas*) {}
void ImGui::DebugNodeColumns(ImGuiOldColumns*) {}
void ImGui::DebugNodeDrawList(ImGuiWindow*, const ImDrawList*, const char*) {}
void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList*, const ImDrawList*, const ImDrawCmd*, bool, bool) {}
void ImGui::DebugNodeFont(ImFont*) {}
void ImGui::DebugNodeStorage(ImGuiStorage*, const char*) {}
void ImGui::DebugNodeTabBar(ImGuiTabBar*, const char*) {}
void ImGui::DebugNodeWindow(ImGuiWindow*, const char*) {}