From fc0fd112467c2be84bc56daa57612b0c579ff1af Mon Sep 17 00:00:00 2001 From: Evan Pezent Date: Wed, 22 Jun 2022 11:00:42 -0500 Subject: [PATCH] ImPlotLineFlags_Shaded and ImPlotStairsFlags_Shaded --- TODO.md | 2 + implot.h | 9 ++- implot_demo.cpp | 21 +++---- implot_items.cpp | 140 +++++++++++++++++++++++++++++++++++++---------- 4 files changed, 130 insertions(+), 42 deletions(-) diff --git a/TODO.md b/TODO.md index 895443c..35b303e 100644 --- a/TODO.md +++ b/TODO.md @@ -45,6 +45,8 @@ The list below represents a combination of high-priority work, nice-to-have feat - first frame render delay might fix "fit pop" effect - move some code to new `implot_tools.cpp` - ColormapSlider (see metrics) +- FillAlpha should not affect markers? +- fix mouse text for time axes ## Optimizations diff --git a/implot.h b/implot.h index 2c07664..4a08f3b 100644 --- a/implot.h +++ b/implot.h @@ -84,6 +84,7 @@ typedef int ImPlotLegendFlags; // -> enum ImPlotLegendFlags_ typedef int ImPlotMouseTextFlags; // -> enum ImPlotMouseTextFlags_ typedef int ImPlotDragToolFlags; // -> ImPlotDragToolFlags_ typedef int ImPlotColormapScaleFlags; // -> ImPlotColormapScaleFlags_ + typedef int ImPlotItemFlags; // -> ImPlotItemFlags_ typedef int ImPlotLineFlags; // -> ImPlotLineFlags_ typedef int ImPlotScatterFlags; // -> ImPlotScatterFlags @@ -163,7 +164,7 @@ enum ImPlotAxisFlags_ { ImPlotAxisFlags_AuxDefault = ImPlotAxisFlags_NoGridLines | ImPlotAxisFlags_Opposite }; -// Options for subplots (see BeginSubplot). +// Options for subplots (see BeginSubplot) enum ImPlotSubplotFlags_ { ImPlotSubplotFlags_None = 0, // default ImPlotSubplotFlags_NoTitle = 1 << 0, // the subplot title will not be displayed (titles are also hidden if preceeded by double hashes, e.g. "##MySubplot") @@ -229,6 +230,7 @@ enum ImPlotLineFlags_ { ImPlotLineFlags_Loop = 1 << 11, // the last and first point will be connected to form a closed loop ImPlotLineFlags_SkipNaN = 1 << 12, // NaNs values will be skipped instead of rendered as missing data ImPlotLineFlags_NoClip = 1 << 13, // markers (if displayed) on the edge of a plot will not be clipped + ImPlotLineFlags_Shaded = 1 << 14, // a filled region between the line and horizontal origin will be rendered; use PlotShaded for more advanced cases }; // Flags for PlotScatter @@ -239,8 +241,9 @@ enum ImPlotScatterFlags_ { // Flags for PlotStairs enum ImPlotStairsFlags_ { - ImPlotStairsFlags_None = 0, // default - ImPlotStairsFlags_PreStep = 1 << 10 // the y value is continued constantly to the left from every x position, i.e. the interval (x[i-1], x[i]] has the value y[i] + ImPlotStairsFlags_None = 0, // default + ImPlotStairsFlags_PreStep = 1 << 10, // the y value is continued constantly to the left from every x position, i.e. the interval (x[i-1], x[i]] has the value y[i] + ImPlotStairsFlags_Shaded = 1 << 11 // a filled region between the stairs and horizontal origin will be rendered; use PlotShaded for more advanced cases }; // Flags for PlotShaded (placeholder) diff --git a/implot_demo.cpp b/implot_demo.cpp index f3c52d3..d0b9227 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -295,7 +295,7 @@ void Demo_LinePlots() { xs2[i] = i * 1/19.0f; ys2[i] = xs2[i] * xs2[i]; } - if (ImPlot::BeginPlot("Line Plot")) { + if (ImPlot::BeginPlot("Line Plots")) { ImPlot::SetupAxes("x","y"); ImPlot::PlotLine("f(x)", xs1, ys1, 1001); ImPlot::SetNextMarkerStyle(ImPlotMarker_Circle); @@ -419,6 +419,8 @@ void Demo_StairstepPlots() { ys1[i] = 0.75f + 0.2f * sinf(10 * i * 0.05f); ys2[i] = 0.25f + 0.2f * sinf(10 * i * 0.05f); } + static ImPlotStairsFlags flags = 0; + CHECKBOX_FLAG(flags, ImPlotStairsFlags_Shaded); if (ImPlot::BeginPlot("Stairstep Plot")) { ImPlot::SetupAxes("x","f(x)"); ImPlot::SetupAxesLimits(0,1,0,1); @@ -429,9 +431,11 @@ void Demo_StairstepPlots() { ImPlot::PopStyleColor(); ImPlot::SetNextMarkerStyle(ImPlotMarker_Circle); - ImPlot::PlotStairs("Post Step (default)", ys1, 21, 0.05f); + ImPlot::SetNextFillStyle(IMPLOT_AUTO_COL, 0.25f); + ImPlot::PlotStairs("Post Step (default)", ys1, 21, 0.05f, 0, flags); ImPlot::SetNextMarkerStyle(ImPlotMarker_Circle); - ImPlot::PlotStairs("Pre Step", ys2, 21, 0.05f, 0, ImPlotStairsFlags_PreStep); + ImPlot::SetNextFillStyle(IMPLOT_AUTO_COL, 0.25f); + ImPlot::PlotStairs("Pre Step", ys2, 21, 0.05f, 0, flags|ImPlotStairsFlags_PreStep); ImPlot::EndPlot(); } @@ -1202,7 +1206,7 @@ void Demo_AxisConstraints() { //----------------------------------------------------------------------------- void Demo_EqualAxes() { - ImGui::BulletText("Equal constraint applies to axis pairs (e.g ImAxis_X1/Y1, ImAxis_X2/Y2"); + ImGui::BulletText("Equal constraint applies to axis pairs (e.g ImAxis_X1/Y1, ImAxis_X2/Y2)"); static double xs1[360], ys1[360]; for (int i = 0; i < 360; ++i) { double angle = i * 2 * PI / 359.0; @@ -2289,12 +2293,9 @@ void Sparkline(const char* id, const float* values, int count, float min_v, floa if (ImPlot::BeginPlot(id,size,ImPlotFlags_CanvasOnly|ImPlotFlags_NoChild)) { ImPlot::SetupAxes(0,0,ImPlotAxisFlags_NoDecorations,ImPlotAxisFlags_NoDecorations); ImPlot::SetupAxesLimits(0, count - 1, min_v, max_v, ImGuiCond_Always); - ImPlot::PushStyleColor(ImPlotCol_Line, col); - ImPlot::PlotLine(id, values, count, 1, 0, 0, offset); - ImPlot::PushStyleVar(ImPlotStyleVar_FillAlpha, 0.25f); - ImPlot::PlotShaded(id, values, count, 0, 1, 0, 0, offset); - ImPlot::PopStyleVar(); - ImPlot::PopStyleColor(); + ImPlot::SetNextLineStyle(col); + ImPlot::SetNextFillStyle(col, 0.25); + ImPlot::PlotLine(id, values, count, 1, 0, ImPlotLineFlags_Shaded, offset); ImPlot::EndPlot(); } ImPlot::PopStyleVar(); diff --git a/implot_items.cpp b/implot_items.cpp index b6247fc..2b8dfad 100644 --- a/implot_items.cpp +++ b/implot_items.cpp @@ -1159,6 +1159,72 @@ struct RendererStairsPost : RendererBase { mutable ImVec2 UV; }; +template +struct RendererStairsPreShaded : RendererBase { + RendererStairsPreShaded(const _Getter& getter, ImU32 col) : + RendererBase(getter.Count - 1, 6, 4), + Getter(getter), + Col(col) + { + P1 = this->Transformer(Getter(0)); + Y0 = this->Transformer(ImPlotPoint(0,0)).y; + } + void Init(ImDrawList& draw_list) const { + UV = draw_list._Data->TexUvWhitePixel; + } + IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { + ImVec2 P2 = this->Transformer(Getter(prim + 1)); + ImVec2 PMin(ImMin(P1.x, P2.x), ImMin(Y0, P2.y)); + ImVec2 PMax(ImMax(P1.x, P2.x), ImMax(Y0, P2.y)); + if (!cull_rect.Overlaps(ImRect(PMin, PMax))) { + P1 = P2; + return false; + } + PrimRectFill(draw_list, PMin, PMax, Col, UV); + P1 = P2; + return true; + } + const _Getter& Getter; + const ImU32 Col; + float Y0; + mutable ImVec2 P1; + mutable ImVec2 UV; +}; + +template +struct RendererStairsPostShaded : RendererBase { + RendererStairsPostShaded(const _Getter& getter, ImU32 col) : + RendererBase(getter.Count - 1, 6, 4), + Getter(getter), + Col(col) + { + P1 = this->Transformer(Getter(0)); + Y0 = this->Transformer(ImPlotPoint(0,0)).y; + } + void Init(ImDrawList& draw_list) const { + UV = draw_list._Data->TexUvWhitePixel; + } + IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { + ImVec2 P2 = this->Transformer(Getter(prim + 1)); + ImVec2 PMin(ImMin(P1.x, P2.x), ImMin(P1.y, Y0)); + ImVec2 PMax(ImMax(P1.x, P2.x), ImMax(P1.y, Y0)); + if (!cull_rect.Overlaps(ImRect(PMin, PMax))) { + P1 = P2; + return false; + } + PrimRectFill(draw_list, PMin, PMax, Col, UV); + P1 = P2; + return true; + } + const _Getter& Getter; + const ImU32 Col; + float Y0; + mutable ImVec2 P1; + mutable ImVec2 UV; +}; + + + template struct RendererShaded : RendererBase { RendererShaded(const _Getter1& getter1, const _Getter2& getter2, ImU32 col) : @@ -1462,26 +1528,33 @@ void RenderMarkers(const _Getter& getter, ImPlotMarker marker, float size, bool // [SECTION] PlotLine //----------------------------------------------------------------------------- -template -void PlotLineEx(const char* label_id, const Getter& getter, ImPlotLineFlags flags) { - if (BeginItemEx(label_id, Fitter1(getter), flags, ImPlotCol_Line)) { +template +void PlotLineEx(const char* label_id, const _Getter& getter, ImPlotLineFlags flags) { + if (BeginItemEx(label_id, Fitter1<_Getter>(getter), flags, ImPlotCol_Line)) { const ImPlotNextItemData& s = GetItemData(); - if (getter.Count > 1 && s.RenderLine) { - const ImU32 col_line = ImGui::GetColorU32(s.Colors[ImPlotCol_Line]); - if (ImHasFlag(flags,ImPlotLineFlags_Segments)) { - RenderPrimitives1(getter,col_line,s.LineWeight); + if (getter.Count > 1) { + if (ImHasFlag(flags, ImPlotLineFlags_Shaded) && s.RenderFill) { + const ImU32 col_fill = ImGui::GetColorU32(s.Colors[ImPlotCol_Fill]); + GetterOverrideY<_Getter> getter2(getter, 0); + RenderPrimitives2(getter,getter2,col_fill); } - else if (ImHasFlag(flags, ImPlotLineFlags_Loop)) { - if (ImHasFlag(flags, ImPlotLineFlags_SkipNaN)) - RenderPrimitives1(GetterLoop(getter),col_line,s.LineWeight); - else - RenderPrimitives1(GetterLoop(getter),col_line,s.LineWeight); - } - else { - if (ImHasFlag(flags, ImPlotLineFlags_SkipNaN)) - RenderPrimitives1(getter,col_line,s.LineWeight); - else - RenderPrimitives1(getter,col_line,s.LineWeight); + if (s.RenderLine) { + const ImU32 col_line = ImGui::GetColorU32(s.Colors[ImPlotCol_Line]); + if (ImHasFlag(flags,ImPlotLineFlags_Segments)) { + RenderPrimitives1(getter,col_line,s.LineWeight); + } + else if (ImHasFlag(flags, ImPlotLineFlags_Loop)) { + if (ImHasFlag(flags, ImPlotLineFlags_SkipNaN)) + RenderPrimitives1(GetterLoop<_Getter>(getter),col_line,s.LineWeight); + else + RenderPrimitives1(GetterLoop<_Getter>(getter),col_line,s.LineWeight); + } + else { + if (ImHasFlag(flags, ImPlotLineFlags_SkipNaN)) + RenderPrimitives1(getter,col_line,s.LineWeight); + else + RenderPrimitives1(getter,col_line,s.LineWeight); + } } } // render markers @@ -1492,7 +1565,7 @@ void PlotLineEx(const char* label_id, const Getter& getter, ImPlotLineFlags flag } const ImU32 col_line = ImGui::GetColorU32(s.Colors[ImPlotCol_MarkerOutline]); const ImU32 col_fill = ImGui::GetColorU32(s.Colors[ImPlotCol_MarkerFill]); - RenderMarkers(getter, s.Marker, s.MarkerSize, s.RenderMarkerFill, col_fill, s.RenderMarkerLine, col_line, s.MarkerWeight); + RenderMarkers<_Getter>(getter, s.Marker, s.MarkerSize, s.RenderMarkerFill, col_fill, s.RenderMarkerLine, col_line, s.MarkerWeight); } EndItem(); } @@ -1518,7 +1591,7 @@ template IMPLOT_API void PlotLine(const char* label_id, const double* va template void PlotLine(const char* label_id, const T* xs, const T* ys, int count, ImPlotLineFlags flags, int offset, int stride) { GetterXY,IndexerIdx> getter(IndexerIdx(xs,count,offset,stride),IndexerIdx(ys,count,offset,stride),count); - return PlotLineEx(label_id, getter, flags); + PlotLineEx(label_id, getter, flags); } template IMPLOT_API void PlotLine(const char* label_id, const ImS8* xs, const ImS8* ys, int count, ImPlotLineFlags flags, int offset, int stride); @@ -1535,7 +1608,7 @@ template IMPLOT_API void PlotLine(const char* label_id, const double* xs // custom void PlotLineG(const char* label_id, ImPlotGetter getter_func, void* data, int count, ImPlotLineFlags flags) { GetterFuncPtr getter(getter_func,data, count); - return PlotLineEx(label_id, getter, flags); + PlotLineEx(label_id, getter, flags); } //----------------------------------------------------------------------------- @@ -1608,12 +1681,21 @@ template void PlotStairsEx(const char* label_id, const Getter& getter, ImPlotStairsFlags flags) { if (BeginItemEx(label_id, Fitter1(getter), flags, ImPlotCol_Line)) { const ImPlotNextItemData& s = GetItemData(); - if (getter.Count > 1 && s.RenderLine) { - const ImU32 col_line = ImGui::GetColorU32(s.Colors[ImPlotCol_Line]); - if (ImHasFlag(flags, ImPlotStairsFlags_PreStep)) - RenderPrimitives1(getter,col_line,s.LineWeight); - else - RenderPrimitives1(getter,col_line,s.LineWeight); + if (getter.Count > 1 ) { + if (s.RenderFill && ImHasFlag(flags,ImPlotStairsFlags_Shaded)) { + const ImU32 col_fill = ImGui::GetColorU32(s.Colors[ImPlotCol_Fill]); + if (ImHasFlag(flags, ImPlotStairsFlags_PreStep)) + RenderPrimitives1(getter,col_fill); + else + RenderPrimitives1(getter,col_fill); + } + if (s.RenderLine) { + const ImU32 col_line = ImGui::GetColorU32(s.Colors[ImPlotCol_Line]); + if (ImHasFlag(flags, ImPlotStairsFlags_PreStep)) + RenderPrimitives1(getter,col_line,s.LineWeight); + else + RenderPrimitives1(getter,col_line,s.LineWeight); + } } // render markers if (s.Marker != ImPlotMarker_None) { @@ -1690,7 +1772,7 @@ void PlotShaded(const char* label_id, const T* values, int count, double y_ref, if (!(y_ref < DBL_MAX)) y_ref = GetPlotLimits(IMPLOT_AUTO,IMPLOT_AUTO).Y.Max; GetterXY> getter1(IndexerLin(xscale,x0),IndexerIdx(values,count,offset,stride),count); - GetterXY getter2(IndexerLin(xscale,x0),IndexerConst(y_ref),count); + GetterXY getter2(IndexerLin(xscale,x0),IndexerConst(y_ref),count); PlotShadedEx(label_id, getter1, getter2, flags); } @@ -1712,7 +1794,7 @@ void PlotShaded(const char* label_id, const T* xs, const T* ys, int count, doubl if (y_ref == HUGE_VAL) y_ref = GetPlotLimits(IMPLOT_AUTO,IMPLOT_AUTO).Y.Max; GetterXY,IndexerIdx> getter1(IndexerIdx(xs,count,offset,stride),IndexerIdx(ys,count,offset,stride),count); - GetterXY,IndexerConst> getter2(IndexerIdx(xs,count,offset,stride),IndexerConst(y_ref),count); + GetterXY,IndexerConst> getter2(IndexerIdx(xs,count,offset,stride),IndexerConst(y_ref),count); PlotShadedEx(label_id, getter1, getter2, flags); }