diff --git a/implot.h b/implot.h index ae1f6000..3dc344f0 100644 --- a/implot.h +++ b/implot.h @@ -589,6 +589,9 @@ typedef int (*ImPlotFormatter)(double value, char* buff, int size, void* user_da // Callback signature for data getter. typedef ImPlotPoint (*ImPlotGetter)(int idx, void* user_data); +// Callback signature for color getter. +typedef ImU32 (*ImPlotColorGetter)(ImPlotCol col, int idx, void* user_data); + // Callback signature for axis transform. typedef double (*ImPlotTransform)(double value, void* user_data); @@ -858,11 +861,13 @@ IMPLOT_API void SetNextAxesToFit(); IMPLOT_TMP void PlotLine(const char* label_id, const T* values, int count, double xscale=1, double xstart=0, ImPlotLineFlags flags=0, int offset=0, int stride=sizeof(T)); IMPLOT_TMP void PlotLine(const char* label_id, const T* xs, const T* ys, int count, ImPlotLineFlags flags=0, int offset=0, int stride=sizeof(T)); IMPLOT_API void PlotLineG(const char* label_id, ImPlotGetter getter, void* data, int count, ImPlotLineFlags flags=0); +IMPLOT_API void PlotLineCG(const char* label_id, ImPlotGetter getter_func, void* data, int count, ImPlotColorGetter color_func, void* color_data, ImPlotLineFlags flags=0); // Plots a standard 2D scatter plot. Default marker is ImPlotMarker_Circle. IMPLOT_TMP void PlotScatter(const char* label_id, const T* values, int count, double xscale=1, double xstart=0, ImPlotScatterFlags flags=0, int offset=0, int stride=sizeof(T)); IMPLOT_TMP void PlotScatter(const char* label_id, const T* xs, const T* ys, int count, ImPlotScatterFlags flags=0, int offset=0, int stride=sizeof(T)); IMPLOT_API void PlotScatterG(const char* label_id, ImPlotGetter getter, void* data, int count, ImPlotScatterFlags flags=0); +IMPLOT_API void PlotScatterCG(const char* label_id, ImPlotGetter getter, void* data, int count, ImPlotColorGetter color_func, void* color_data, ImPlotScatterFlags flags=0); // Plots a a stairstep graph. The y value is continued constantly to the right from every x position, i.e. the interval [x[i], x[i+1]) has the value y[i] IMPLOT_TMP void PlotStairs(const char* label_id, const T* values, int count, double xscale=1, double xstart=0, ImPlotStairsFlags flags=0, int offset=0, int stride=sizeof(T)); @@ -937,13 +942,13 @@ IMPLOT_API void PlotDummy(const char* label_id, ImPlotDummyFlags flags=0); // user interactions can be retrieved through the optional output parameters. // Shows a draggable point at x,y. #col defaults to ImGuiCol_Text. -IMPLOT_API bool DragPoint(int id, double* x, double* y, const ImVec4& col, float size = 4, ImPlotDragToolFlags flags = 0, bool* out_clicked = nullptr, bool* out_hovered = nullptr, bool* held = nullptr); +IMPLOT_API bool DragPoint(int id, double* x, double* y, const ImVec4& col, float size = 4, ImPlotDragToolFlags flags = 0, bool* out_clicked = nullptr, bool* out_hovered = nullptr, bool* out_held = nullptr); // Shows a draggable vertical guide line at an x-value. #col defaults to ImGuiCol_Text. -IMPLOT_API bool DragLineX(int id, double* x, const ImVec4& col, float thickness = 1, ImPlotDragToolFlags flags = 0, bool* out_clicked = nullptr, bool* out_hovered = nullptr, bool* held = nullptr); +IMPLOT_API bool DragLineX(int id, double* x, const ImVec4& col, float thickness = 1, ImPlotDragToolFlags flags = 0, bool* out_clicked = nullptr, bool* out_hovered = nullptr, bool* out_held = nullptr); // Shows a draggable horizontal guide line at a y-value. #col defaults to ImGuiCol_Text. -IMPLOT_API bool DragLineY(int id, double* y, const ImVec4& col, float thickness = 1, ImPlotDragToolFlags flags = 0, bool* out_clicked = nullptr, bool* out_hovered = nullptr, bool* held = nullptr); +IMPLOT_API bool DragLineY(int id, double* y, const ImVec4& col, float thickness = 1, ImPlotDragToolFlags flags = 0, bool* out_clicked = nullptr, bool* out_hovered = nullptr, bool* out_held = nullptr); // Shows a draggable and resizeable rectangle. -IMPLOT_API bool DragRect(int id, double* x1, double* y1, double* x2, double* y2, const ImVec4& col, ImPlotDragToolFlags flags = 0, bool* out_clicked = nullptr, bool* out_hovered = nullptr, bool* held = nullptr); +IMPLOT_API bool DragRect(int id, double* x1, double* y1, double* x2, double* y2, const ImVec4& col, ImPlotDragToolFlags flags = 0, bool* out_clicked = nullptr, bool* out_hovered = nullptr, bool* out_held = nullptr); // Shows an annotation callout at a chosen point. Clamping keeps annotations in the plot area. Annotations are always rendered on top. IMPLOT_API void Annotation(double x, double y, const ImVec4& col, const ImVec2& pix_offset, bool clamp, bool round = false); diff --git a/implot_demo.cpp b/implot_demo.cpp index 47298d64..5c9f4beb 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -2165,7 +2165,39 @@ void Demo_CustomPlottersAndTooltips() { MyImPlot::PlotCandlestick("GOOGL",dates, opens, closes, lows, highs, 218, tooltip, 0.25f, bullCol, bearCol); ImPlot::EndPlot(); } +} + +void Demo_CustomColors() { + + if (ImPlot::BeginPlot("Custom Colors")){ + ImPlot::PlotLineCG("Line Plot", + [](int idx, void* user_data){ + return ImPlotPoint(0.1*idx, sin(0.1*idx)); + }, nullptr, 100, + [](ImPlotCol col, int idx, void* user_data){ + switch (idx % 3){ + case 0 : return 0xFF0000FFu; + case 1 : return 0xFF00FF00u; + case 2 : return 0xFFFF0000u; + default: return 0u; + } + }, nullptr); + ImPlot::PlotScatterCG("Scatter Plot", + [](int idx, void* user_data){ + srand(idx); + return ImPlotPoint(10.0*float(rand())/float(RAND_MAX), -1.0+2.0*float(rand())/float(RAND_MAX)); + }, nullptr, 20, + [](ImPlotCol col, int idx, void* user_data){ + switch (idx % 3){ + case 0 : return 0xFF0000FFu; + case 1 : return 0xFF00FF00u; + case 2 : return 0xFFFF0000u; + default: return 0u; + } + }, nullptr); + ImPlot::EndPlot(); } +} //----------------------------------------------------------------------------- // DEMO WINDOW @@ -2254,6 +2286,7 @@ void ShowDemoWindow(bool* p_open) { DemoHeader("Images", Demo_Images); DemoHeader("Markers and Text", Demo_MarkersAndText); DemoHeader("NaN Values", Demo_NaNValues); + DemoHeader("Custom Colors", Demo_CustomColors); ImGui::EndTabItem(); } if (ImGui::BeginTabItem("Subplots")) { diff --git a/implot_items.cpp b/implot_items.cpp index f7de3465..700ef7ba 100644 --- a/implot_items.cpp +++ b/implot_items.cpp @@ -647,6 +647,38 @@ struct GetterError { const int Stride; }; +struct ColorGetter { + ColorGetter() { } + IMPLOT_INLINE void FillColors() { + for (int i = 0; i < 5; i++) Colors[i] = ImGui::GetColorU32(GetItemData().Colors[i]); + } + template IMPLOT_INLINE ImU32 operator()(ImPlotCol col, I idx) const { + (void)idx; + IM_ASSERT(col < 5); + return Colors[col]; + } + IMPLOT_INLINE bool IsFillEqLine() const { + return Colors[ImPlotCol_Fill] == Colors[ImPlotCol_Line]; + } + ImU32 Colors[5] = {}; +}; + +/// Interprets a user's function pointer as ImU32 color +struct ColorGetterFuncPtr { + ColorGetterFuncPtr(ImPlotColorGetter color, void* data) : + Color(color), + Data(data) + { } + IMPLOT_INLINE void FillColors() { } + template IMPLOT_INLINE ImU32 operator()(ImPlotCol col, I idx) const { + IM_ASSERT(col < 5); + return Color(col, idx, Data); + } + IMPLOT_INLINE bool IsFillEqLine() const { return false; } + ImPlotColorGetter Color; + void* const Data; +}; + //----------------------------------------------------------------------------- // [SECTION] Fitters //----------------------------------------------------------------------------- @@ -863,73 +895,84 @@ struct RendererBase { const int VtxConsumed; }; -template +template struct RendererLineStrip : RendererBase { - RendererLineStrip(const _Getter& getter, ImU32 col, float weight) : + RendererLineStrip(const _Getter& getter, const _ColorGetter& col, float weight) : RendererBase(getter.Count - 1, 6, 4), Getter(getter), Col(col), HalfWeight(ImMax(1.0f,weight)*0.5f) { P1 = this->Transformer(Getter(0)); + C1 = Col(ImPlotCol_Line, 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 C2 = Col(ImPlotCol_Line, prim + 1); if (!cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2)))) { P1 = P2; return false; } - PrimLine(draw_list,P1,P2,HalfWeight,Col,UV0,UV1); + PrimLine(draw_list,P1,P2,HalfWeight,C1,UV0,UV1); P1 = P2; + C1 = C2; return true; } const _Getter& Getter; - const ImU32 Col; + const _ColorGetter& Col; mutable float HalfWeight; mutable ImVec2 P1; + mutable ImU32 C1; mutable ImVec2 UV0; mutable ImVec2 UV1; }; -template +template struct RendererLineStripSkip : RendererBase { - RendererLineStripSkip(const _Getter& getter, ImU32 col, float weight) : + RendererLineStripSkip(const _Getter& getter, const _ColorGetter& col, float weight) : RendererBase(getter.Count - 1, 6, 4), Getter(getter), Col(col), HalfWeight(ImMax(1.0f,weight)*0.5f) { P1 = this->Transformer(Getter(0)); + C1 = Col(ImPlotCol_Line, 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 C2 = Col(ImPlotCol_Line, prim + 1); if (!cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2)))) { - if (!ImNan(P2.x) && !ImNan(P2.y)) + if (!ImNan(P2.x) && !ImNan(P2.y)){ P1 = P2; + C1 = C2; + } return false; } - PrimLine(draw_list,P1,P2,HalfWeight,Col,UV0,UV1); - if (!ImNan(P2.x) && !ImNan(P2.y)) + PrimLine(draw_list,P1,P2,HalfWeight,C1,UV0,UV1); + if (!ImNan(P2.x) && !ImNan(P2.y)){ P1 = P2; + C1 = C2; + } return true; } const _Getter& Getter; - const ImU32 Col; + const _ColorGetter& Col; mutable float HalfWeight; mutable ImVec2 P1; + mutable ImU32 C1; mutable ImVec2 UV0; mutable ImVec2 UV1; }; -template +template struct RendererLineSegments1 : RendererBase { - RendererLineSegments1(const _Getter& getter, ImU32 col, float weight) : + RendererLineSegments1(const _Getter& getter, const _ColorGetter& col, float weight) : RendererBase(getter.Count / 2, 6, 4), Getter(getter), Col(col), @@ -941,21 +984,22 @@ 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 C1 = Col(ImPlotCol_Line, prim*2+0); 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,C1,UV0,UV1); return true; } const _Getter& Getter; - const ImU32 Col; + const _ColorGetter& Col; 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 _ColorGetter& col, float weight) : RendererBase(ImMin(getter1.Count, getter1.Count), 6, 4), Getter1(getter1), Getter2(getter2), @@ -968,22 +1012,23 @@ 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 C1 = Col(ImPlotCol_Line, 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,C1,UV0,UV1); return true; } const _Getter1& Getter1; const _Getter2& Getter2; - const ImU32 Col; + const _ColorGetter& Col; 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 _ColorGetter& col, double width) : RendererBase(ImMin(getter1.Count, getter1.Count), 6, 4), Getter1(getter1), Getter2(getter2), @@ -1000,6 +1045,7 @@ struct RendererBarsFillV : RendererBase { p2.x -= HalfWidth; ImVec2 P1 = this->Transformer(p1); ImVec2 P2 = this->Transformer(p2); + ImU32 C1 = Col(ImPlotCol_Fill, prim); float width_px = ImAbs(P1.x-P2.x); if (width_px < 1.0f) { P1.x += P1.x > P2.x ? (1-width_px) / 2 : (width_px-1) / 2; @@ -1009,19 +1055,19 @@ 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,C1,UV); return true; } const _Getter1& Getter1; const _Getter2& Getter2; - const ImU32 Col; + const _ColorGetter& Col; 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 _ColorGetter& col, double height) : RendererBase(ImMin(getter1.Count, getter1.Count), 6, 4), Getter1(getter1), Getter2(getter2), @@ -1038,6 +1084,7 @@ struct RendererBarsFillH : RendererBase { p2.y -= HalfHeight; ImVec2 P1 = this->Transformer(p1); ImVec2 P2 = this->Transformer(p2); + ImU32 C1 = Col(ImPlotCol_Fill, prim); float height_px = ImAbs(P1.y-P2.y); if (height_px < 1.0f) { P1.y += P1.y > P2.y ? (1-height_px) / 2 : (height_px-1) / 2; @@ -1047,19 +1094,19 @@ 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,C1,UV); return true; } const _Getter1& Getter1; const _Getter2& Getter2; - const ImU32 Col; + const _ColorGetter& Col; 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 _ColorGetter& col, double width, float weight) : RendererBase(ImMin(getter1.Count, getter1.Count), 24, 8), Getter1(getter1), Getter2(getter2), @@ -1077,6 +1124,7 @@ struct RendererBarsLineV : RendererBase { p2.x -= HalfWidth; ImVec2 P1 = this->Transformer(p1); ImVec2 P2 = this->Transformer(p2); + ImU32 C1 = Col(ImPlotCol_Line, prim); float width_px = ImAbs(P1.x-P2.x); if (width_px < 1.0f) { P1.x += P1.x > P2.x ? (1-width_px) / 2 : (width_px-1) / 2; @@ -1086,20 +1134,20 @@ struct RendererBarsLineV : RendererBase { ImVec2 PMax = ImMax(P1, P2); if (!cull_rect.Overlaps(ImRect(PMin, PMax))) return false; - PrimRectLine(draw_list,PMin,PMax,Weight,Col,UV); + PrimRectLine(draw_list,PMin,PMax,Weight,C1,UV); return true; } const _Getter1& Getter1; const _Getter2& Getter2; - const ImU32 Col; + const _ColorGetter& Col; 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 _ColorGetter& col, double height, float weight) : RendererBase(ImMin(getter1.Count, getter1.Count), 24, 8), Getter1(getter1), Getter2(getter2), @@ -1117,6 +1165,7 @@ struct RendererBarsLineH : RendererBase { p2.y -= HalfHeight; ImVec2 P1 = this->Transformer(p1); ImVec2 P2 = this->Transformer(p2); + ImU32 C1 = Col(ImPlotCol_Line, prim); float height_px = ImAbs(P1.y-P2.y); if (height_px < 1.0f) { P1.y += P1.y > P2.y ? (1-height_px) / 2 : (height_px-1) / 2; @@ -1126,88 +1175,99 @@ struct RendererBarsLineH : RendererBase { ImVec2 PMax = ImMax(P1, P2); if (!cull_rect.Overlaps(ImRect(PMin, PMax))) return false; - PrimRectLine(draw_list,PMin,PMax,Weight,Col,UV); + PrimRectLine(draw_list,PMin,PMax,Weight,C1,UV); return true; } const _Getter1& Getter1; const _Getter2& Getter2; - const ImU32 Col; + const _ColorGetter& Col; 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 _ColorGetter& col, float weight) : RendererBase(getter.Count - 1, 12, 8), Getter(getter), Col(col), HalfWeight(ImMax(1.0f,weight)*0.5f) { P1 = this->Transformer(Getter(0)); + C1 = Col(ImPlotCol_Line, 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 C2 = Col(ImPlotCol_Line, prim + 1); if (!cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2)))) { P1 = P2; + C1 = C2; 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); + PrimRectFill(draw_list, ImVec2(P1.x - HalfWeight, P1.y), ImVec2(P1.x + HalfWeight, P2.y), C1, UV); + PrimRectFill(draw_list, ImVec2(P1.x, P2.y + HalfWeight), ImVec2(P2.x, P2.y - HalfWeight), C1, UV); P1 = P2; + C1 = C2; return true; } const _Getter& Getter; - const ImU32 Col; + const _ColorGetter& Col; mutable float HalfWeight; mutable ImVec2 P1; + mutable ImU32 C1; mutable ImVec2 UV; }; -template +template struct RendererStairsPost : RendererBase { - RendererStairsPost(const _Getter& getter, ImU32 col, float weight) : + RendererStairsPost(const _Getter& getter, const _ColorGetter& col, float weight) : RendererBase(getter.Count - 1, 12, 8), Getter(getter), Col(col), HalfWeight(ImMax(1.0f,weight) * 0.5f) { P1 = this->Transformer(Getter(0)); + C1 = Col(ImPlotCol_Fill, 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 C2 = Col(ImPlotCol_Fill, prim + 1); if (!cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2)))) { P1 = P2; + C1 = C2; 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); + PrimRectFill(draw_list, ImVec2(P1.x, P1.y + HalfWeight), ImVec2(P2.x, P1.y - HalfWeight), C1, UV); + PrimRectFill(draw_list, ImVec2(P2.x - HalfWeight, P2.y), ImVec2(P2.x + HalfWeight, P1.y), C1, UV); P1 = P2; + C1 = C2; return true; } const _Getter& Getter; - const ImU32 Col; + const _ColorGetter& Col; mutable float HalfWeight; mutable ImVec2 P1; + mutable ImU32 C1; mutable ImVec2 UV; }; -template +template struct RendererStairsPreShaded : RendererBase { - RendererStairsPreShaded(const _Getter& getter, ImU32 col) : + RendererStairsPreShaded(const _Getter& getter, const _ColorGetter& col) : RendererBase(getter.Count - 1, 6, 4), Getter(getter), Col(col) { P1 = this->Transformer(Getter(0)); + C1 = Col(ImPlotCol_Fill, 0); Y0 = this->Transformer(ImPlotPoint(0,0)).y; } void Init(ImDrawList& draw_list) const { @@ -1215,31 +1275,36 @@ 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 C2 = Col(ImPlotCol_Fill, 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; + C1 = C2; return false; } - PrimRectFill(draw_list, PMin, PMax, Col, UV); + PrimRectFill(draw_list, PMin, PMax, C1, UV); P1 = P2; + C1 = C2; return true; } const _Getter& Getter; - const ImU32 Col; + const _ColorGetter& Col; float Y0; mutable ImVec2 P1; + mutable ImU32 C1; mutable ImVec2 UV; }; -template +template struct RendererStairsPostShaded : RendererBase { - RendererStairsPostShaded(const _Getter& getter, ImU32 col) : + RendererStairsPostShaded(const _Getter& getter, const _ColorGetter& col) : RendererBase(getter.Count - 1, 6, 4), Getter(getter), Col(col) { P1 = this->Transformer(Getter(0)); + C1 = Col(ImPlotCol_Fill, 0); Y0 = this->Transformer(ImPlotPoint(0,0)).y; } void Init(ImDrawList& draw_list) const { @@ -1247,28 +1312,32 @@ 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 C2 = Col(ImPlotCol_Fill, 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; + C1 = C2; return false; } - PrimRectFill(draw_list, PMin, PMax, Col, UV); + PrimRectFill(draw_list, PMin, PMax, C1, UV); P1 = P2; + C1 = C2; return true; } const _Getter& Getter; - const ImU32 Col; + const _ColorGetter& Col; float Y0; mutable ImVec2 P1; + mutable ImU32 C1; 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 _ColorGetter& col) : RendererBase(ImMin(getter1.Count, getter2.Count) - 1, 6, 5), Getter1(getter1), Getter2(getter2), @@ -1276,6 +1345,7 @@ struct RendererShaded : RendererBase { { P11 = this->Transformer(Getter1(0)); P12 = this->Transformer(Getter2(0)); + C11 = Col(ImPlotCol_Fill, 0); } void Init(ImDrawList& draw_list) const { UV = draw_list._Data->TexUvWhitePixel; @@ -1283,29 +1353,31 @@ 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 C21 = Col(ImPlotCol_Fill, 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; P12 = P22; + C11 = C21; return false; } const int intersect = (P11.y > P12.y && P22.y > P21.y) || (P12.y > P11.y && P21.y > P22.y); const ImVec2 intersection = intersect == 0 ? ImVec2(0,0) : 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 = C11; draw_list._VtxWritePtr[1].pos = P21; draw_list._VtxWritePtr[1].uv = UV; - draw_list._VtxWritePtr[1].col = Col; + draw_list._VtxWritePtr[1].col = C11; draw_list._VtxWritePtr[2].pos = intersection; draw_list._VtxWritePtr[2].uv = UV; - draw_list._VtxWritePtr[2].col = Col; + draw_list._VtxWritePtr[2].col = C11; draw_list._VtxWritePtr[3].pos = P12; draw_list._VtxWritePtr[3].uv = UV; - draw_list._VtxWritePtr[3].col = Col; + draw_list._VtxWritePtr[3].col = C11; draw_list._VtxWritePtr[4].pos = P22; draw_list._VtxWritePtr[4].uv = UV; - draw_list._VtxWritePtr[4].col = Col; + draw_list._VtxWritePtr[4].col = C11; draw_list._VtxWritePtr += 5; draw_list._IdxWritePtr[0] = (ImDrawIdx)(draw_list._VtxCurrentIdx); draw_list._IdxWritePtr[1] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 1 + intersect); @@ -1317,13 +1389,15 @@ struct RendererShaded : RendererBase { draw_list._VtxCurrentIdx += 5; P11 = P21; P12 = P22; + C11 = C21; return true; } const _Getter1& Getter1; const _Getter2& Getter2; - const ImU32 Col; + const _ColorGetter& Col; mutable ImVec2 P11; mutable ImVec2 P12; + mutable ImU32 C11; mutable ImVec2 UV; }; @@ -1406,20 +1480,27 @@ void RenderPrimitives1(const _Getter& getter, Args... args) { RenderPrimitivesEx(_Renderer<_Getter>(getter,args...), draw_list, cull_rect); } -template