From 603137389a01dbb5fc9e02f273f6f362ae5e0afc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Bertolus?= Date: Mon, 14 Nov 2022 11:37:25 +0100 Subject: [PATCH] add SetNextColorsData to give per point colors Implementation and demo for lines, scatter, infinite lines, shaded plots and stairstep --- implot.h | 2 + implot_demo.cpp | 181 ++++++++++++++++++++ implot_internal.h | 5 + implot_items.cpp | 425 ++++++++++++++++++++++++++++++---------------- 4 files changed, 464 insertions(+), 149 deletions(-) diff --git a/implot.h b/implot.h index a31c8b6b..1f1bd7c2 100644 --- a/implot.h +++ b/implot.h @@ -1117,6 +1117,8 @@ IMPLOT_API void SetNextFillStyle(const ImVec4& col = IMPLOT_AUTO_COL, float alph IMPLOT_API void SetNextMarkerStyle(ImPlotMarker marker = IMPLOT_AUTO, float size = IMPLOT_AUTO, const ImVec4& fill = IMPLOT_AUTO_COL, float weight = IMPLOT_AUTO, const ImVec4& outline = IMPLOT_AUTO_COL); // Set the error bar style for the next item only. IMPLOT_API void SetNextErrorBarStyle(const ImVec4& col = IMPLOT_AUTO_COL, float size = IMPLOT_AUTO, float weight = IMPLOT_AUTO); +// Set color buffer for the next item only. The colors array must be keep alive until the next item plot. +IMPLOT_API void SetNextColorsData(ImPlotCol_ target, ImU32* const& colors, int stride = sizeof(ImU32)); // Gets the last item primary color (i.e. its legend icon color) IMPLOT_API ImVec4 GetLastItemColor(); diff --git a/implot_demo.cpp b/implot_demo.cpp index f9f17d56..d2fe9c0c 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -960,6 +960,186 @@ void Demo_MarkersAndText() { } } +void Demo_PlotColors() { + // Lines + { + static float xs1[1001], ys1[1001]; + ImU32 cs1[1001]; + for (int i = 0; i < 1001; ++i) { + xs1[i] = i * 0.001f; + ys1[i] = 0.5f + 0.5f * sinf(50 * (xs1[i] + (float)ImGui::GetTime() / 10)); + ImVec4 lineColor = ImPlot::SampleColormap(ys1[i], ImPlotColormap_Spectral); + lineColor.w = 1 - powf(1 - (i * 0.001f), 4); + cs1[i] = ImGui::GetColorU32(lineColor); + } + static double xs2[11], ys2[11]; + ImU32 cms2[11]; + for (int i = 0; i < 11; ++i) { + xs2[i] = i * 0.1f; + ys2[i] = xs2[i] * xs2[i]; + cms2[i] = ImGui::GetColorU32(ImPlot::RandomColor()); + } + if (ImPlot::BeginPlot("Line Plot with colors")) { + ImPlot::SetupAxes("x", "f(x)"); + ImVec4 s1Color = ImPlot::SampleColormap(0.5f, ImPlotColormap_Spectral); + ImPlot::SetNextLineStyle(s1Color); + ImPlot::SetNextColorsData(ImPlotCol_Line, cs1); + ImPlot::PlotLine("sin(x)", xs1, ys1, 1001); + ImVec4 s2Color = ImPlot::SampleColormap(0.5f, ImPlotColormap_Twilight); + ImPlot::SetNextLineStyle(s2Color); + ImPlot::SetNextMarkerStyle(ImPlotMarker_Circle); + ImPlot::SetNextColorsData(ImPlotCol_Line, cms2); + ImPlot::SetNextColorsData(ImPlotCol_MarkerFill, cms2); + ImPlot::SetNextColorsData(ImPlotCol_MarkerOutline, cms2); + ImPlot::PlotLine("x^2", xs2, ys2, 11); + ImPlot::EndPlot(); + } + } + // Scatter + { + srand(0); + static float xs1[100], ys1[100]; + static ImU32 cs1[1001]; + for (int i = 0; i < 100; ++i) { + xs1[i] = i * 0.01f; + ys1[i] = xs1[i] + 0.1f * ((float)rand() / (float)RAND_MAX); + cs1[i] = ImGui::GetColorU32(ImPlot::SampleColormap(10 * (ys1[i] - xs1[i]), ImPlotColormap_Viridis)); + } + static float xs2[50], ys2[50]; + ImU32 cmos2[50], cmfs2[50]; + + for (int i = 0; i < 50; i++) { + xs2[i] = 0.25f + 0.2f * ((float)rand() / (float)RAND_MAX); + ys2[i] = 0.75f + 0.2f * ((float)rand() / (float)RAND_MAX); + + ImVec4 markerOutlineColor = ImPlot::SampleColormap(((float)rand() / (float)RAND_MAX), ImPlotColormap_Plasma); + ImVec4 markerFillColor = ImVec4(markerOutlineColor.x, markerOutlineColor.x, markerOutlineColor.z, 0.5); + cmfs2[i] = ImGui::GetColorU32(markerFillColor); + cmos2[i] = ImGui::GetColorU32(markerOutlineColor); + } + + if (ImPlot::BeginPlot("Scatter Plot with colors")) { + ImVec4 s1Color = ImPlot::SampleColormap(0.5f, ImPlotColormap_Viridis); + ImPlot::SetNextMarkerStyle(ImPlotMarker_Circle, 4, s1Color, IMPLOT_AUTO, s1Color); + ImPlot::SetNextColorsData(ImPlotCol_MarkerOutline, cs1); + ImPlot::SetNextColorsData(ImPlotCol_MarkerFill, cs1); + ImPlot::PlotScatter("Data 1", xs1, ys1, 100); + + ImVec4 s2Color = ImPlot::SampleColormap(0.5f, ImPlotColormap_Plasma); + ImPlot::SetNextMarkerStyle(ImPlotMarker_Square, 6, s2Color, IMPLOT_AUTO, s2Color); + ImPlot::SetNextColorsData(ImPlotCol_MarkerOutline, cmos2); + ImPlot::SetNextColorsData(ImPlotCol_MarkerFill, cmfs2); + ImPlot::PlotScatter("Data 2", xs2, ys2, 50); + + ImPlot::EndPlot(); + } + } + + // Infinite lines + { + static double vals[] = { 0.25, 0.5, 0.75 }; + static ImU32 colors[] = { ImGui::GetColorU32(ImPlot::RandomColor()), ImGui::GetColorU32(ImPlot::RandomColor()), ImGui::GetColorU32(ImPlot::RandomColor()) }; + if (ImPlot::BeginPlot("##Infinite with colors")) { + ImPlot::SetupAxes(NULL, NULL, ImPlotAxisFlags_NoInitialFit, ImPlotAxisFlags_NoInitialFit); + ImPlot::SetNextLineStyle(ImVec4(1, 1, 1, 0.5)); + ImPlot::SetNextColorsData(ImPlotCol_Line, colors); + ImPlot::PlotInfLines("VLines", vals, 3); + ImPlot::SetNextLineStyle(ImVec4(1, 1, 1, 0.5)); + ImPlot::SetNextColorsData(ImPlotCol_Line, colors); + ImPlot::PlotInfLines("HLines", vals, 3, ImPlotInfLinesFlags_Horizontal); + ImPlot::EndPlot(); + } + } + + // Shaded plots + { + static float xs[1001], ys[1001], ys1[1001], ys2[1001], ys3[1001], ys4[1001]; + static ImU32 cl1[1001]; + static ImU32 cf1[1001]; + static ImU32 cf2[1001]; + srand(0); + + for (int i = 0; i < 1001; ++i) { + xs[i] = i * 0.001f; + ys[i] = 0.25f + 0.25f * sinf(25 * xs[i]) * sinf(5 * xs[i]) + RandomRange(-0.01f, 0.01f); + ys1[i] = ys[i] + RandomRange(0.1f, 0.12f); + ys2[i] = ys[i] - RandomRange(0.1f, 0.12f); + ys3[i] = 0.75f + 0.2f * sinf(37 * xs[i]); + ys4[i] = 0.75f + 0.1f * cosf(29 * xs[i]); + + ImVec4 lineColor = ImPlot::SampleColormap(i/1001.f, ImPlotColormap_Hot); + ImVec4 fillColor = lineColor; + fillColor.w = 0.25f; + cl1[i] = ImGui::GetColorU32(lineColor); + cf1[i] = ImGui::GetColorU32(fillColor); + + float diffNormalized = (float) fabs(ys3[i] - ys4[i]) / (0.3f); + ImVec4 fillColor2 = ImPlot::SampleColormap(diffNormalized, ImPlotColormap_Plasma); + fillColor2.w = 0.8f; + cf2[i] = ImGui::GetColorU32(fillColor2); + } + + if (ImPlot::BeginPlot("Shaded Plots with colors")) { + ImPlot::SetNextColorsData(ImPlotCol_Fill, cf1); + ImPlot::PlotShaded("Uncertain Data", xs, ys1, ys2, 1001); + ImPlot::SetNextColorsData(ImPlotCol_Line, cl1); + ImPlot::PlotLine("Uncertain Data", xs, ys, 1001); + ImPlot::SetNextColorsData(ImPlotCol_Fill, cf2); + ImPlot::PlotShaded("Overlapping", xs, ys3, ys4, 1001); + ImPlot::PlotLine("Overlapping", xs, ys3, 1001); + ImPlot::PlotLine("Overlapping", xs, ys4, 1001); + ImPlot::EndPlot(); + } + } + + // Stairstep + { + static float ys1[21], ys2[21]; + static ImU32 clys1[21], cfys1[21], clys2[21], cfys2[21]; + for (int i = 0; i < 21; ++i) { + ys1[i] = 0.75f + 0.2f * sinf(10 * i * 0.05f); + ys2[i] = 0.25f + 0.2f * sinf(10 * i * 0.05f); + ImVec4 cl1 = ImPlot::RandomColor(); + ImVec4 cl2 = ImPlot::RandomColor(); + ImVec4 cf1 = cl1; + ImVec4 cf2 = cl2; + cf1.w = 0.5; + cf2.w = 0.5; + + clys1[i] = ImGui::GetColorU32(cl1); + clys2[i] = ImGui::GetColorU32(cl2); + cfys1[i] = ImGui::GetColorU32(cf1); + cfys2[i] = ImGui::GetColorU32(cf2); + } + static ImPlotStairsFlags flags = 0; + CHECKBOX_FLAG(flags, ImPlotStairsFlags_Shaded); + if (ImPlot::BeginPlot("Stairstep Plot with colors")) { + ImPlot::SetupAxes("x", "f(x)"); + ImPlot::SetupAxesLimits(0, 1, 0, 1); + + ImPlot::PushStyleColor(ImPlotCol_Line, ImVec4(0.5f, 0.5f, 0.5f, 1.0f)); + ImPlot::PlotLine("##1", ys1, 21, 0.05f); + ImPlot::PlotLine("##2", ys2, 21, 0.05f); + ImPlot::PopStyleColor(); + + ImPlot::SetNextMarkerStyle(ImPlotMarker_Circle); + ImPlot::SetNextFillStyle(IMPLOT_AUTO_COL, 0.25f); + ImPlot::SetNextColorsData(ImPlotCol_Line, clys1); + ImPlot::SetNextColorsData(ImPlotCol_Fill, cfys1); + ImPlot::SetNextColorsData(ImPlotCol_MarkerOutline, clys1); + ImPlot::PlotStairs("Post Step (default)", ys1, 21, 0.05f, 0, flags); + ImPlot::SetNextMarkerStyle(ImPlotMarker_Circle); + ImPlot::SetNextFillStyle(IMPLOT_AUTO_COL, 0.25f); + ImPlot::SetNextColorsData(ImPlotCol_Line, clys2); + ImPlot::SetNextColorsData(ImPlotCol_Fill, cfys2); + ImPlot::SetNextColorsData(ImPlotCol_MarkerOutline, clys2); + ImPlot::PlotStairs("Pre Step", ys2, 21, 0.05f, 0, flags | ImPlotStairsFlags_PreStep); + + ImPlot::EndPlot(); + } + } +} + //----------------------------------------------------------------------------- void Demo_NaNValues() { @@ -2214,6 +2394,7 @@ void ShowDemoWindow(bool* p_open) { DemoHeader("Images", Demo_Images); DemoHeader("Markers and Text", Demo_MarkersAndText); DemoHeader("NaN Values", Demo_NaNValues); + DemoHeader("Plot Colors", Demo_PlotColors); ImGui::EndTabItem(); } if (ImGui::BeginTabItem("Subplots")) { diff --git a/implot_internal.h b/implot_internal.h index b2685ff4..d103123c 100644 --- a/implot_internal.h +++ b/implot_internal.h @@ -1175,6 +1175,8 @@ struct ImPlotNextPlotData // Temporary data storage for upcoming item struct ImPlotNextItemData { ImVec4 Colors[5]; // ImPlotCol_Line, ImPlotCol_Fill, ImPlotCol_MarkerOutline, ImPlotCol_MarkerFill, ImPlotCol_ErrorBar + ImU32 const* ColorsData[5]; + int ColorsDataStride[5]; float LineWeight; ImPlotMarker Marker; float MarkerSize; @@ -1194,7 +1196,10 @@ struct ImPlotNextItemData { ImPlotNextItemData() { Reset(); } void Reset() { for (int i = 0; i < 5; ++i) + { Colors[i] = IMPLOT_AUTO_COL; + ColorsData[i] = nullptr; + } LineWeight = MarkerSize = MarkerWeight = FillAlpha = ErrorBarSize = ErrorBarWeight = DigitalBitHeight = DigitalBitGap = IMPLOT_AUTO; Marker = IMPLOT_AUTO; HasHidden = Hidden = false; diff --git a/implot_items.cpp b/implot_items.cpp index 1fbdf5b1..3b4f6597 100644 --- a/implot_items.cpp +++ b/implot_items.cpp @@ -129,7 +129,7 @@ IMPLOT_INLINE void GetLineRenderProps(const ImDrawList& draw_list, float& half_w } } -IMPLOT_INLINE void PrimLine(ImDrawList& draw_list, const ImVec2& P1, const ImVec2& P2, float half_weight, ImU32 col, const ImVec2& tex_uv0, const ImVec2 tex_uv1) { +IMPLOT_INLINE void PrimLine(ImDrawList& draw_list, const ImVec2& P1, const ImVec2& P2, float half_weight, ImU32 col1, ImU32 col2, const ImVec2& tex_uv0, const ImVec2 tex_uv1) { float dx = P2.x - P1.x; float dy = P2.y - P1.y; IMPLOT_NORMALIZE2F_OVER_ZERO(dx, dy); @@ -138,19 +138,19 @@ IMPLOT_INLINE void PrimLine(ImDrawList& draw_list, const ImVec2& P1, const ImVec draw_list._VtxWritePtr[0].pos.x = P1.x + dy; draw_list._VtxWritePtr[0].pos.y = P1.y - dx; draw_list._VtxWritePtr[0].uv = tex_uv0; - draw_list._VtxWritePtr[0].col = col; + draw_list._VtxWritePtr[0].col = col1; draw_list._VtxWritePtr[1].pos.x = P2.x + dy; draw_list._VtxWritePtr[1].pos.y = P2.y - dx; draw_list._VtxWritePtr[1].uv = tex_uv0; - draw_list._VtxWritePtr[1].col = col; + draw_list._VtxWritePtr[1].col = col2; draw_list._VtxWritePtr[2].pos.x = P2.x - dy; draw_list._VtxWritePtr[2].pos.y = P2.y + dx; draw_list._VtxWritePtr[2].uv = tex_uv1; - draw_list._VtxWritePtr[2].col = col; + draw_list._VtxWritePtr[2].col = col2; draw_list._VtxWritePtr[3].pos.x = P1.x - dy; draw_list._VtxWritePtr[3].pos.y = P1.y + dx; draw_list._VtxWritePtr[3].uv = tex_uv1; - draw_list._VtxWritePtr[3].col = col; + draw_list._VtxWritePtr[3].col = col1; draw_list._VtxWritePtr += 4; draw_list._IdxWritePtr[0] = (ImDrawIdx)(draw_list._VtxCurrentIdx); draw_list._IdxWritePtr[1] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 1); @@ -162,21 +162,21 @@ IMPLOT_INLINE void PrimLine(ImDrawList& draw_list, const ImVec2& P1, const ImVec draw_list._VtxCurrentIdx += 4; } -IMPLOT_INLINE void PrimRectFill(ImDrawList& draw_list, const ImVec2& Pmin, const ImVec2& Pmax, ImU32 col, const ImVec2& uv) { +IMPLOT_INLINE void PrimRectFill(ImDrawList& draw_list, const ImVec2& Pmin, const ImVec2& Pmax, ImU32 cols[4], const ImVec2& uv) { draw_list._VtxWritePtr[0].pos = Pmin; draw_list._VtxWritePtr[0].uv = uv; - draw_list._VtxWritePtr[0].col = col; + draw_list._VtxWritePtr[0].col = cols[0]; draw_list._VtxWritePtr[1].pos = Pmax; draw_list._VtxWritePtr[1].uv = uv; - draw_list._VtxWritePtr[1].col = col; + draw_list._VtxWritePtr[1].col = cols[2]; draw_list._VtxWritePtr[2].pos.x = Pmin.x; draw_list._VtxWritePtr[2].pos.y = Pmax.y; draw_list._VtxWritePtr[2].uv = uv; - draw_list._VtxWritePtr[2].col = col; + draw_list._VtxWritePtr[2].col = cols[1]; draw_list._VtxWritePtr[3].pos.x = Pmax.x; draw_list._VtxWritePtr[3].pos.y = Pmin.y; draw_list._VtxWritePtr[3].uv = uv; - draw_list._VtxWritePtr[3].col = col; + draw_list._VtxWritePtr[3].col = cols[3]; draw_list._VtxWritePtr += 4; draw_list._IdxWritePtr[0] = (ImDrawIdx)(draw_list._VtxCurrentIdx); draw_list._IdxWritePtr[1] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 1); @@ -324,6 +324,13 @@ void SetNextLineStyle(const ImVec4& col, float weight) { gp.NextItemData.LineWeight = weight; } +void SetNextColorsData(ImPlotCol_ target, ImU32* const& colors, int stride) +{ + ImPlotContext& gp = *GImPlot; + gp.NextItemData.ColorsData[target] = colors; + gp.NextItemData.ColorsDataStride[target] = stride; +} + void SetNextFillStyle(const ImVec4& col, float alpha) { ImPlotContext& gp = *GImPlot; gp.NextItemData.Colors[ImPlotCol_Fill] = col; @@ -565,6 +572,17 @@ struct GetterXY { const int Count; }; +template +struct GetterColor { + GetterColor(_Indexer col, int count) : IndxerCol(col), Count(count) { } + template IMPLOT_INLINE ImColor operator()(I idx) const { + return ImU32(IndxerCol(idx)); + } + + const _Indexer IndxerCol; + const int Count; +}; + /// Interprets a user's function pointer as ImPlotPoints struct GetterFuncPtr { GetterFuncPtr(ImPlotGetter getter, void* data, int count) : @@ -859,76 +877,91 @@ struct RendererBase { const int VtxConsumed; }; -template +template struct RendererLineStrip : RendererBase { - RendererLineStrip(const _Getter& getter, ImU32 col, float weight) : + RendererLineStrip(const _Getter& getter, const _GetterCol& getterCol, float weight) : RendererBase(getter.Count - 1, 6, 4), Getter(getter), - Col(col), + GetterCol(getterCol), HalfWeight(ImMax(1.0f,weight)*0.5f) { P1 = this->Transformer(Getter(0)); + Col1 = GetterCol(0); } void Init(ImDrawList& draw_list) const { GetLineRenderProps(draw_list, HalfWeight, UV0, UV1); } IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { ImVec2 P2 = this->Transformer(Getter(prim + 1)); + ImU32 Col2 = GetterCol(prim+1); if (!cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2)))) { P1 = P2; + Col1 = Col2; return false; } - PrimLine(draw_list,P1,P2,HalfWeight,Col,UV0,UV1); + PrimLine(draw_list,P1,P2,HalfWeight,Col1,Col2,UV0,UV1); P1 = P2; + Col1 = Col2; return true; } const _Getter& Getter; - const ImU32 Col; + const _GetterCol& GetterCol; mutable float HalfWeight; mutable ImVec2 P1; + mutable ImU32 Col1; mutable ImVec2 UV0; mutable ImVec2 UV1; }; -template +template struct RendererLineStripSkip : RendererBase { - RendererLineStripSkip(const _Getter& getter, ImU32 col, float weight) : + RendererLineStripSkip(const _Getter& getter, const _GetterCol& getterCol, float weight) : RendererBase(getter.Count - 1, 6, 4), Getter(getter), - Col(col), + GetterCol(getterCol), HalfWeight(ImMax(1.0f,weight)*0.5f) { P1 = this->Transformer(Getter(0)); + Col1 = GetterCol(0); } void Init(ImDrawList& draw_list) const { GetLineRenderProps(draw_list, HalfWeight, UV0, UV1); } IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { ImVec2 P2 = this->Transformer(Getter(prim + 1)); + ImU32 Col2 = GetterCol(prim+1); if (!cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2)))) { if (!ImNan(P2.x) && !ImNan(P2.y)) + { P1 = P2; + Col1 = Col2; + } return false; } - PrimLine(draw_list,P1,P2,HalfWeight,Col,UV0,UV1); + PrimLine(draw_list,P1,P2,HalfWeight,Col1,Col2,UV0,UV1); if (!ImNan(P2.x) && !ImNan(P2.y)) + { P1 = P2; + Col1 = Col2; + } + return true; } const _Getter& Getter; - const ImU32 Col; + const _GetterCol& GetterCol; mutable float HalfWeight; mutable ImVec2 P1; + mutable ImU32 Col1; mutable ImVec2 UV0; mutable ImVec2 UV1; }; -template +template struct RendererLineSegments1 : RendererBase { - RendererLineSegments1(const _Getter& getter, ImU32 col, float weight) : + RendererLineSegments1(const _Getter& getter, const _GetterCol& getterCol, float weight) : RendererBase(getter.Count / 2, 6, 4), Getter(getter), - Col(col), + GetterCol(getterCol), HalfWeight(ImMax(1.0f,weight)*0.5f) { } void Init(ImDrawList& draw_list) const { @@ -937,25 +970,27 @@ struct RendererLineSegments1 : RendererBase { IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { ImVec2 P1 = this->Transformer(Getter(prim*2+0)); ImVec2 P2 = this->Transformer(Getter(prim*2+1)); + ImU32 Col1 = GetterCol(prim*2+0); + ImU32 Col2 = GetterCol(prim * 2+1); if (!cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2)))) return false; - PrimLine(draw_list,P1,P2,HalfWeight,Col,UV0,UV1); + PrimLine(draw_list,P1,P2,HalfWeight,Col1,Col2,UV0,UV1); return true; } const _Getter& Getter; - const ImU32 Col; + const _GetterCol& GetterCol; mutable float HalfWeight; mutable ImVec2 UV0; mutable ImVec2 UV1; }; -template +template struct RendererLineSegments2 : RendererBase { - RendererLineSegments2(const _Getter1& getter1, const _Getter2& getter2, ImU32 col, float weight) : + RendererLineSegments2(const _Getter1& getter1, const _Getter2& getter2, const _GetterCol& getterCol, float weight) : RendererBase(ImMin(getter1.Count, getter1.Count), 6, 4), Getter1(getter1), Getter2(getter2), - Col(col), + GetterCol(getterCol), HalfWeight(ImMax(1.0f,weight)*0.5f) {} void Init(ImDrawList& draw_list) const { @@ -964,26 +999,27 @@ struct RendererLineSegments2 : RendererBase { IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { ImVec2 P1 = this->Transformer(Getter1(prim)); ImVec2 P2 = this->Transformer(Getter2(prim)); + ImU32 Col = GetterCol(prim); if (!cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2)))) return false; - PrimLine(draw_list,P1,P2,HalfWeight,Col,UV0,UV1); + PrimLine(draw_list,P1,P2,HalfWeight,Col, Col,UV0,UV1); return true; } const _Getter1& Getter1; const _Getter2& Getter2; - const ImU32 Col; + const _GetterCol& GetterCol; mutable float HalfWeight; mutable ImVec2 UV0; mutable ImVec2 UV1; }; -template +template struct RendererBarsFillV : RendererBase { - RendererBarsFillV(const _Getter1& getter1, const _Getter2& getter2, ImU32 col, double width) : + RendererBarsFillV(const _Getter1& getter1, const _Getter2& getter2, const _GetterCol& getterCol, double width) : RendererBase(ImMin(getter1.Count, getter1.Count), 6, 4), Getter1(getter1), Getter2(getter2), - Col(col), + GetterCol(getterCol), HalfWidth(width/2) {} void Init(ImDrawList& draw_list) const { @@ -992,6 +1028,8 @@ struct RendererBarsFillV : RendererBase { IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { ImPlotPoint p1 = Getter1(prim); ImPlotPoint p2 = Getter2(prim); + ImU32 Col = GetterCol(prim); + ImU32 Cols[4] = { Col, Col, Col, Col }; p1.x += HalfWidth; p2.x -= HalfWidth; ImVec2 P1 = this->Transformer(p1); @@ -1005,23 +1043,23 @@ struct RendererBarsFillV : RendererBase { ImVec2 PMax = ImMax(P1, P2); if (!cull_rect.Overlaps(ImRect(PMin, PMax))) return false; - PrimRectFill(draw_list,PMin,PMax,Col,UV); + PrimRectFill(draw_list,PMin,PMax,Cols,UV); return true; } const _Getter1& Getter1; const _Getter2& Getter2; - const ImU32 Col; + const _GetterCol& GetterCol; const double HalfWidth; mutable ImVec2 UV; }; -template +template struct RendererBarsFillH : RendererBase { - RendererBarsFillH(const _Getter1& getter1, const _Getter2& getter2, ImU32 col, double height) : + RendererBarsFillH(const _Getter1& getter1, const _Getter2& getter2, const _GetterCol& getterCol, double height) : RendererBase(ImMin(getter1.Count, getter1.Count), 6, 4), Getter1(getter1), Getter2(getter2), - Col(col), + GetterCol(getterCol), HalfHeight(height/2) {} void Init(ImDrawList& draw_list) const { @@ -1030,6 +1068,8 @@ struct RendererBarsFillH : RendererBase { IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { ImPlotPoint p1 = Getter1(prim); ImPlotPoint p2 = Getter2(prim); + ImU32 Col = GetterCol(prim); + ImU32 Cols[4] = { Col, Col, Col, Col}; p1.y += HalfHeight; p2.y -= HalfHeight; ImVec2 P1 = this->Transformer(p1); @@ -1043,23 +1083,23 @@ struct RendererBarsFillH : RendererBase { ImVec2 PMax = ImMax(P1, P2); if (!cull_rect.Overlaps(ImRect(PMin, PMax))) return false; - PrimRectFill(draw_list,PMin,PMax,Col,UV); + PrimRectFill(draw_list,PMin,PMax,Cols,UV); return true; } const _Getter1& Getter1; const _Getter2& Getter2; - const ImU32 Col; + const _GetterCol& GetterCol; const double HalfHeight; mutable ImVec2 UV; }; -template +template struct RendererBarsLineV : RendererBase { - RendererBarsLineV(const _Getter1& getter1, const _Getter2& getter2, ImU32 col, double width, float weight) : + RendererBarsLineV(const _Getter1& getter1, const _Getter2& getter2, const _GetterCol& getterCol, double width, float weight) : RendererBase(ImMin(getter1.Count, getter1.Count), 24, 8), Getter1(getter1), Getter2(getter2), - Col(col), + GetterCol(getterCol), HalfWidth(width/2), Weight(weight) {} @@ -1069,6 +1109,7 @@ struct RendererBarsLineV : RendererBase { IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { ImPlotPoint p1 = Getter1(prim); ImPlotPoint p2 = Getter2(prim); + ImU32 Col = GetterCol(prim); p1.x += HalfWidth; p2.x -= HalfWidth; ImVec2 P1 = this->Transformer(p1); @@ -1087,19 +1128,19 @@ struct RendererBarsLineV : RendererBase { } const _Getter1& Getter1; const _Getter2& Getter2; - const ImU32 Col; + const _GetterCol& GetterCol; const double HalfWidth; const float Weight; mutable ImVec2 UV; }; -template +template struct RendererBarsLineH : RendererBase { - RendererBarsLineH(const _Getter1& getter1, const _Getter2& getter2, ImU32 col, double height, float weight) : + RendererBarsLineH(const _Getter1& getter1, const _Getter2& getter2, const _GetterCol& getterCol, double height, float weight) : RendererBase(ImMin(getter1.Count, getter1.Count), 24, 8), Getter1(getter1), Getter2(getter2), - Col(col), + GetterCol(getterCol), HalfHeight(height/2), Weight(weight) {} @@ -1109,6 +1150,7 @@ struct RendererBarsLineH : RendererBase { IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { ImPlotPoint p1 = Getter1(prim); ImPlotPoint p2 = Getter2(prim); + ImU32 Col = GetterCol(prim); p1.y += HalfHeight; p2.y -= HalfHeight; ImVec2 P1 = this->Transformer(p1); @@ -1127,83 +1169,100 @@ struct RendererBarsLineH : RendererBase { } const _Getter1& Getter1; const _Getter2& Getter2; - const ImU32 Col; + const _GetterCol& GetterCol; const double HalfHeight; const float Weight; mutable ImVec2 UV; }; -template +template struct RendererStairsPre : RendererBase { - RendererStairsPre(const _Getter& getter, ImU32 col, float weight) : + RendererStairsPre(const _Getter& getter, const _GetterCol& getterCol, float weight) : RendererBase(getter.Count - 1, 12, 8), Getter(getter), - Col(col), + GetterCol(getterCol), HalfWeight(ImMax(1.0f,weight)*0.5f) { P1 = this->Transformer(Getter(0)); + Col1 = GetterCol(0); } 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)); + ImU32 Col2 = GetterCol(prim+1); if (!cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2)))) { P1 = P2; + Col1 = Col2; return false; } - PrimRectFill(draw_list, ImVec2(P1.x - HalfWeight, P1.y), ImVec2(P1.x + HalfWeight, P2.y), Col, UV); - PrimRectFill(draw_list, ImVec2(P1.x, P2.y + HalfWeight), ImVec2(P2.x, P2.y - HalfWeight), Col, UV); + + ImU32 ColsV[4] = { Col1, Col1, Col1, Col1 }; + ImU32 ColsH[4] = { Col1, Col1, Col2, Col2 }; + PrimRectFill(draw_list, ImVec2(P1.x - HalfWeight, P1.y), ImVec2(P1.x + HalfWeight, P2.y), ColsV, UV); + PrimRectFill(draw_list, ImVec2(P1.x, P2.y + HalfWeight), ImVec2(P2.x, P2.y - HalfWeight), ColsH, UV); P1 = P2; + Col1 = Col2; return true; } const _Getter& Getter; - const ImU32 Col; + const _GetterCol& GetterCol; mutable float HalfWeight; mutable ImVec2 P1; + mutable ImU32 Col1; mutable ImVec2 UV; }; -template +template struct RendererStairsPost : RendererBase { - RendererStairsPost(const _Getter& getter, ImU32 col, float weight) : + RendererStairsPost(const _Getter& getter, const _GetterCol& getterCol, float weight) : RendererBase(getter.Count - 1, 12, 8), Getter(getter), - Col(col), + GetterCol(getterCol), HalfWeight(ImMax(1.0f,weight) * 0.5f) { P1 = this->Transformer(Getter(0)); + Col1 = GetterCol(0); } 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)); + ImU32 Col2 = GetterCol(prim+1); if (!cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2)))) { P1 = P2; + Col1 = Col2; return false; } - PrimRectFill(draw_list, ImVec2(P1.x, P1.y + HalfWeight), ImVec2(P2.x, P1.y - HalfWeight), Col, UV); - PrimRectFill(draw_list, ImVec2(P2.x - HalfWeight, P2.y), ImVec2(P2.x + HalfWeight, P1.y), Col, UV); + + ImU32 ColsH[4] = { Col1, Col1, Col2, Col2 }; + ImU32 ColsV[4] = { Col2, Col2, Col2, Col2 }; + PrimRectFill(draw_list, ImVec2(P1.x, P1.y + HalfWeight), ImVec2(P2.x, P1.y - HalfWeight), ColsH, UV); + PrimRectFill(draw_list, ImVec2(P2.x - HalfWeight, P2.y), ImVec2(P2.x + HalfWeight, P1.y), ColsV, UV); P1 = P2; + Col1 = Col2; return true; } const _Getter& Getter; - const ImU32 Col; + const _GetterCol& GetterCol; mutable float HalfWeight; mutable ImVec2 P1; + mutable ImU32 Col1; mutable ImVec2 UV; }; -template +template struct RendererStairsPreShaded : RendererBase { - RendererStairsPreShaded(const _Getter& getter, ImU32 col) : + RendererStairsPreShaded(const _Getter& getter, const _GetterCol& getterCol) : RendererBase(getter.Count - 1, 6, 4), Getter(getter), - Col(col) + GetterCol(getterCol) { P1 = this->Transformer(Getter(0)); + Col1 = GetterCol(0); Y0 = this->Transformer(ImPlotPoint(0,0)).y; } void Init(ImDrawList& draw_list) const { @@ -1211,31 +1270,38 @@ struct RendererStairsPreShaded : RendererBase { } IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { ImVec2 P2 = this->Transformer(Getter(prim + 1)); + ImU32 Col2 = GetterCol(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; + Col1 = Col2; return false; } - PrimRectFill(draw_list, PMin, PMax, Col, UV); + + ImU32 Cols[4] = { Col1, Col1, Col2, Col2 }; + PrimRectFill(draw_list, PMin, PMax, Cols, UV); P1 = P2; + Col1 = Col2; return true; } const _Getter& Getter; - const ImU32 Col; + const _GetterCol& GetterCol; float Y0; mutable ImVec2 P1; + mutable ImU32 Col1; mutable ImVec2 UV; }; -template +template struct RendererStairsPostShaded : RendererBase { - RendererStairsPostShaded(const _Getter& getter, ImU32 col) : + RendererStairsPostShaded(const _Getter& getter, const _GetterCol& getterCol) : RendererBase(getter.Count - 1, 6, 4), Getter(getter), - Col(col) + GetterCol(getterCol) { P1 = this->Transformer(Getter(0)); + Col1 = GetterCol(0); Y0 = this->Transformer(ImPlotPoint(0,0)).y; } void Init(ImDrawList& draw_list) const { @@ -1243,35 +1309,42 @@ struct RendererStairsPostShaded : RendererBase { } IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { ImVec2 P2 = this->Transformer(Getter(prim + 1)); + ImU32 Col2 = GetterCol(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; + Col1 = Col2; return false; } - PrimRectFill(draw_list, PMin, PMax, Col, UV); + + ImU32 Cols[4] = { Col1, Col1, Col2, Col2 }; + PrimRectFill(draw_list, PMin, PMax, Cols, UV); P1 = P2; + Col1 = Col2; return true; } const _Getter& Getter; - const ImU32 Col; + const _GetterCol& GetterCol; float Y0; mutable ImVec2 P1; + mutable ImU32 Col1; mutable ImVec2 UV; }; -template +template struct RendererShaded : RendererBase { - RendererShaded(const _Getter1& getter1, const _Getter2& getter2, ImU32 col) : + RendererShaded(const _Getter1& getter1, const _Getter2& getter2, const _GetterCol& getterCol) : RendererBase(ImMin(getter1.Count, getter2.Count) - 1, 6, 5), Getter1(getter1), Getter2(getter2), - Col(col) + GetterCol(getterCol) { P11 = this->Transformer(Getter1(0)); P12 = this->Transformer(Getter2(0)); + Col1 = GetterCol(0); } void Init(ImDrawList& draw_list) const { UV = draw_list._Data->TexUvWhitePixel; @@ -1279,6 +1352,7 @@ struct RendererShaded : RendererBase { IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { ImVec2 P21 = this->Transformer(Getter1(prim+1)); ImVec2 P22 = this->Transformer(Getter2(prim+1)); + ImU32 Col2 = GetterCol(prim + 1); ImRect rect(ImMin(ImMin(ImMin(P11,P12),P21),P22), ImMax(ImMax(ImMax(P11,P12),P21),P22)); if (!cull_rect.Overlaps(rect)) { P11 = P21; @@ -1289,19 +1363,19 @@ struct RendererShaded : RendererBase { ImVec2 intersection = Intersection(P11,P21,P12,P22); draw_list._VtxWritePtr[0].pos = P11; draw_list._VtxWritePtr[0].uv = UV; - draw_list._VtxWritePtr[0].col = Col; + draw_list._VtxWritePtr[0].col = Col1; draw_list._VtxWritePtr[1].pos = P21; draw_list._VtxWritePtr[1].uv = UV; - draw_list._VtxWritePtr[1].col = Col; + draw_list._VtxWritePtr[1].col = Col2; draw_list._VtxWritePtr[2].pos = intersection; draw_list._VtxWritePtr[2].uv = UV; - draw_list._VtxWritePtr[2].col = Col; + draw_list._VtxWritePtr[2].col = Col1; // TODO interpolate draw_list._VtxWritePtr[3].pos = P12; draw_list._VtxWritePtr[3].uv = UV; - draw_list._VtxWritePtr[3].col = Col; + draw_list._VtxWritePtr[3].col = Col1; draw_list._VtxWritePtr[4].pos = P22; draw_list._VtxWritePtr[4].uv = UV; - draw_list._VtxWritePtr[4].col = Col; + draw_list._VtxWritePtr[4].col = Col2; draw_list._VtxWritePtr += 5; draw_list._IdxWritePtr[0] = (ImDrawIdx)(draw_list._VtxCurrentIdx); draw_list._IdxWritePtr[1] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 1 + intersect); @@ -1313,41 +1387,46 @@ struct RendererShaded : RendererBase { draw_list._VtxCurrentIdx += 5; P11 = P21; P12 = P22; + Col1 = Col2; return true; } const _Getter1& Getter1; const _Getter2& Getter2; - const ImU32 Col; + const _GetterCol& GetterCol; mutable ImVec2 P11; mutable ImVec2 P12; + mutable ImU32 Col1; mutable ImVec2 UV; }; struct RectC { ImPlotPoint Pos; ImPlotPoint HalfSize; - ImU32 Color; }; -template +template struct RendererRectC : RendererBase { - RendererRectC(const _Getter& getter) : + RendererRectC(const _Getter& getter, const _GetterCol& getterCol) : RendererBase(getter.Count, 6, 4), - Getter(getter) + Getter(getter), + GetterCol(getterCol) {} 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 { - RectC rect = Getter(prim); + RectC rect = Getter.template operator()(prim); + ImU32 Col = GetterCol(prim); ImVec2 P1 = this->Transformer(rect.Pos.x - rect.HalfSize.x , rect.Pos.y - rect.HalfSize.y); ImVec2 P2 = this->Transformer(rect.Pos.x + rect.HalfSize.x , rect.Pos.y + rect.HalfSize.y); - if ((rect.Color & IM_COL32_A_MASK) == 0 || !cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2)))) + if ((Col & IM_COL32_A_MASK) == 0 || !cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2)))) return false; - PrimRectFill(draw_list,P1,P2,rect.Color,UV); + ImU32 Cols[4] = { Col, Col, Col, Col }; + PrimRectFill(draw_list,P1,P2, Cols,UV); return true; } const _Getter& Getter; + const _GetterCol& GetterCol; mutable ImVec2 UV; }; @@ -1395,39 +1474,40 @@ void RenderPrimitivesEx(const _Renderer& renderer, ImDrawList& draw_list, const draw_list.PrimUnreserve(prims_culled * renderer.IdxConsumed, prims_culled * renderer.VtxConsumed); } -template