diff --git a/openVulkanoCpp/Scene/UI/ImGuiExtensions/ImGuiPlotTwoLines.cpp b/openVulkanoCpp/Scene/UI/ImGuiExtensions/ImGuiPlotTwoLines.cpp index bec93d1..5052545 100644 --- a/openVulkanoCpp/Scene/UI/ImGuiExtensions/ImGuiPlotTwoLines.cpp +++ b/openVulkanoCpp/Scene/UI/ImGuiExtensions/ImGuiPlotTwoLines.cpp @@ -11,132 +11,104 @@ namespace ImGui { - void PlotTwoLines(const char* label, - float (*getter1)(void* data, int idx), void* data1, const char *tooltipPrefix1, - float (*getter2)(void* data, int idx), void* data2, const char *tooltipPrefix2, - int values_count, float scale_min, float scale_max, ImVec2 graph_size) - { - ImGuiContext& g = *ImGui::GetCurrentContext(); - ImGuiWindow* window = ImGui::GetCurrentWindow(); - if (window->SkipItems) - return; + namespace + { + void RenderLine(ImDrawList* drawList, float (*getter)(void* data, int idx), void* data, int valuesCount, float scaleMin, float scaleMax, ImRect innerBb, ImColor color, int resW) + { + const float tStep = 1.0f / (float)resW; + const float invScale = (scaleMin == scaleMax) ? 0.0f : (1.0f / (scaleMax - scaleMin)); - const ImGuiStyle& style = g.Style; + float v0 = getter(data, 0); + float t0 = 0.0f; + ImVec2 tp0 = ImVec2(t0, 1.0f - ImSaturate((v0 - scaleMin) * invScale)); - ImVec2 label_size = ImGui::CalcTextSize(label, NULL, true); - if (graph_size.x == 0.0f) - graph_size.x = ImGui::CalcItemWidth(); - if (graph_size.y == 0.0f) - graph_size.y = label_size.y + (style.FramePadding.y * 2); + for (int n = 0; n < resW; n++) + { + const float t1 = t0 + tStep; + const int v1Idx = (int)(t0 * (valuesCount - 1) + 0.5f); + IM_ASSERT(v1Idx >= 0 && v1Idx < valuesCount); + const float v1 = getter(data, ImMin(v1Idx + 1, valuesCount - 1)); + const ImVec2 tp1 = ImVec2( t1, 1.0f - ImSaturate((v1 - scaleMin) * invScale) ); - ImRect frame_bb(window->DC.CursorPos, ImVec2(window->DC.CursorPos.x + graph_size.x, window->DC.CursorPos.y + graph_size.y)); - ImRect inner_bb(ImVec2(frame_bb.Min.x + style.FramePadding.x, frame_bb.Min.y + style.FramePadding.y), ImVec2(frame_bb.Max.x - style.FramePadding.x, frame_bb.Max.y - style.FramePadding.y)); - ImRect total_bb(frame_bb.Min, ImVec2(frame_bb.Max.x + (label_size.x > 0.0f ? (style.ItemInnerSpacing.x + label_size.x) : 0.0f), frame_bb.Max.y)); + ImVec2 pos0 = ImLerp(innerBb.Min, innerBb.Max, tp0); + ImVec2 pos1 = ImLerp(innerBb.Min, innerBb.Max, tp1); - ImGui::ItemSize(total_bb, style.FramePadding.y); - if (!ImGui::ItemAdd(total_bb, 0)) - return; + drawList->AddLine(pos0, pos1, color); - // Determine scale from inputs if not specified - if (scale_min == FLT_MAX || scale_max == FLT_MAX) - { - float v1_min = FLT_MAX, v1_max = -FLT_MAX; - for (int i = 0; i < values_count; i++) - { - float v = getter1(data1, i); - if (v != v) // Ignore NaN values - continue; - v1_min = ImMin(v1_min, v); - v1_max = ImMax(v1_max, v); - } - float v2_min = FLT_MAX, v2_max = -FLT_MAX; - for (int i = 0; i < values_count; i++) - { - float v = getter2(data2, i); - if (v != v) // Ignore NaN values - continue; - v2_min = ImMin(v2_min, v); - v2_max = ImMax(v2_max, v); - } - if (scale_min == FLT_MAX) scale_min = ImMin(v1_min, v2_min); - if (scale_max == FLT_MAX) scale_max = ImMax(v1_max, v2_max); - } + t0 = t1; + tp0 = tp1; + } + } + } - ImGui::RenderFrame(frame_bb.Min, frame_bb.Max, ImGui::GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding); - int res_w = ImMin((int)graph_size.x, values_count); // Number of samples + void PlotTwoLines(const char* label, + float (*getter1)(void* data, int idx), void* data1, const char *tooltip1, + float (*getter2)(void* data, int idx), void* data2, const char *tooltip2, + int valuesCount, float scaleMin, float scaleMax, ImVec2 graphSize, ImColor color1, ImColor color2) + { + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; - if (res_w <= 0) - return; + const ImGuiStyle& style = ImGui::GetCurrentContext()->Style; + const ImGuiID id = window->GetID(label); - // Tooltip on hover - int v_hovered = -1; - if (ImGui::IsItemHovered()) - { - const float t = ImClamp((g.IO.MousePos.x - inner_bb.Min.x) / (inner_bb.Max.x - inner_bb.Min.x), 0.0f, 0.9999f); - const int v_idx = (int)(t * values_count); - IM_ASSERT(v_idx >= 0 && v_idx < values_count); + const ImVec2 labelSize = CalcTextSize(label, NULL, true); + const ImVec2 frameSize = CalcItemSize(graphSize, CalcItemWidth(), labelSize.y + style.FramePadding.y * 2.0f); - const float v0 = getter1(data1, v_idx); - const float v1 = getter2(data2, v_idx); - ImGui::SetTooltip("%d: (%s: %8.4g, %s: %8.4g)", v_idx, tooltipPrefix1, v0, tooltipPrefix2, v1); - v_hovered = v_idx; - } + const ImRect frameBb(window->DC.CursorPos, ImVec2(window->DC.CursorPos.x + frameSize.x, window->DC.CursorPos.y + frameSize.y)); + const ImRect innerBb(ImVec2(frameBb.Min.x + style.FramePadding.x, frameBb.Min.y + style.FramePadding.y), ImVec2(frameBb.Max.x - style.FramePadding.x, frameBb.Max.y - style.FramePadding.y)); + const ImRect totalBb(frameBb.Min, ImVec2(frameBb.Max.x + (labelSize.x > 0.0f ? (style.ItemInnerSpacing.x + labelSize.x) : 0.0f), frameBb.Max.y)); - const float t_step = 1.0f / res_w; + ItemSize(totalBb, style.FramePadding.y); + if (!ItemAdd(totalBb, 0, &frameBb)) + return; + const bool hovered = ItemHoverable(frameBb, id, ImGui::GetCurrentContext()->LastItemData.InFlags); - ImDrawList* draw_list = ImGui::GetWindowDrawList(); - draw_list->PushClipRect(inner_bb.Min, inner_bb.Max, true); + // Determine scale from values if not specified + if(scaleMin == FLT_MAX || scaleMax == FLT_MAX) + { + float vMin = FLT_MAX; + float vMax = -FLT_MAX; + for(int i = 0; i < valuesCount; i++) + { + const float v1 = getter1(data1, i); + const float v2 = getter2(data2, i); + if(v1 != v1 || v2 != v2) // Ignore NaN values + continue; + vMin = ImMin(ImMin(vMin, v1), v2); + vMax = ImMax(ImMax(vMax, v1), v2); + } + if(scaleMin == FLT_MAX) + scaleMin = vMin; + if(scaleMax == FLT_MAX) + scaleMax = vMax; + } - ImColor col1 = ImColor(255, 100, 100); - ImColor col2 = ImColor(100, 255, 100); + RenderFrame(frameBb.Min, frameBb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding); - // Plot first line - for (int n = 0; n < res_w; n++) - { - const float t0 = t_step * (n + 0); - const float t1 = t_step * (n + 1); - const int v_idx0 = (int)(t0 * values_count); - int v_idx1 = (int)(t1 * values_count); - if(v_idx1 >= values_count) - v_idx1 = values_count - 1; + if(valuesCount >= 2) + { + int resW = ImMin((int)frameSize.x, valuesCount) - 1; + int itemCount = valuesCount - 1; - IM_ASSERT(v_idx0 >= 0 && v_idx0 < values_count); - IM_ASSERT(v_idx1 >= 0 && v_idx1 < values_count); + // Tooltip on hover + if(hovered && innerBb.Contains(ImGui::GetCurrentContext()->IO.MousePos)) + { + const float t = ImClamp((ImGui::GetCurrentContext()->IO.MousePos.x - innerBb.Min.x) / (innerBb.Max.x - innerBb.Min.x), 0.0f, 0.9999f); + const int vIdx = (int)(t * itemCount); + IM_ASSERT(vIdx >= 0 && vIdx < valuesCount); - const float v0 = getter1(data1, v_idx0); - const float v1 = getter1(data1, v_idx1); - const float x0 = ImLerp(inner_bb.Min.x, inner_bb.Max.x, t0); - const float x1 = ImLerp(inner_bb.Min.x, inner_bb.Max.x, t1); - const float y0 = ImLerp(inner_bb.Max.y, inner_bb.Min.y, (v0 - scale_min) / (scale_max - scale_min)); - const float y1 = ImLerp(inner_bb.Max.y, inner_bb.Min.y, (v1 - scale_min) / (scale_max - scale_min)); - draw_list->AddLine(ImVec2(x0, y0), ImVec2(x1, y1), col1); - } + const float v0 = getter1(data1, vIdx % valuesCount); + const float v1 = getter2(data2, (vIdx + 1) % valuesCount); + SetTooltip("%s: %8.4g\n%s: %8.4g", tooltip1, v0, tooltip2, v1); + } - // Plot second line - for (int n = 0; n < res_w; n++) - { - const float t0 = t_step * (n + 0); - const float t1 = t_step * (n + 1); - const int v_idx0 = (int)(t0 * values_count); - int v_idx1 = (int)(t1 * values_count); - if(v_idx1 >= values_count) - v_idx1 = values_count - 1; + RenderLine(window->DrawList, getter1, data1, valuesCount, scaleMin, scaleMax, innerBb, color1, resW); + RenderLine(window->DrawList, getter2, data2, valuesCount, scaleMin, scaleMax, innerBb, color2, resW); + } - IM_ASSERT(v_idx0 >= 0 && v_idx0 < values_count); - IM_ASSERT(v_idx1 >= 0 && v_idx1 < values_count); - - const float v0 = getter2(data2, v_idx0); - const float v1 = getter2(data2, v_idx1); - const float x0 = ImLerp(inner_bb.Min.x, inner_bb.Max.x, t0); - const float x1 = ImLerp(inner_bb.Min.x, inner_bb.Max.x, t1); - const float y0 = ImLerp(inner_bb.Max.y, inner_bb.Min.y, (v0 - scale_min) / (scale_max - scale_min)); - const float y1 = ImLerp(inner_bb.Max.y, inner_bb.Min.y, (v1 - scale_min) / (scale_max - scale_min)); - draw_list->AddLine(ImVec2(x0, y0), ImVec2(x1, y1), col2); - } - - draw_list->PopClipRect(); - - if (label_size.x > 0.0f) - ImGui::RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label); - } + if(labelSize.x > 0.0f) + RenderText(ImVec2(frameBb.Max.x + style.ItemInnerSpacing.x, innerBb.Min.y), label); + } } \ No newline at end of file diff --git a/openVulkanoCpp/Scene/UI/ImGuiExtensions/ImGuiPlotTwoLines.hpp b/openVulkanoCpp/Scene/UI/ImGuiExtensions/ImGuiPlotTwoLines.hpp index a4bd497..1ad54fe 100644 --- a/openVulkanoCpp/Scene/UI/ImGuiExtensions/ImGuiPlotTwoLines.hpp +++ b/openVulkanoCpp/Scene/UI/ImGuiExtensions/ImGuiPlotTwoLines.hpp @@ -13,5 +13,6 @@ namespace ImGui void PlotTwoLines(const char* label, float (*getter1)(void* data, int idx), void* data1, const char *tooltipPrefix1, float (*getter2)(void* data, int idx), void* data2, const char *tooltipPrefix2, - int values_count, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0)); + int values_count, float scale_min = FLT_MAX, float scale_max = FLT_MAX, + ImVec2 graph_size = ImVec2(0, 0), ImColor color1 = ImColor(255, 100, 100), ImColor color2 = ImColor(100, 255, 100)); } \ No newline at end of file