1
0
Fork 0
mirror of https://github.com/gwm17/implot.git synced 2024-11-30 05:58:52 -05:00

add ability to render filled lines

This commit is contained in:
Evan Pezent 2020-05-31 16:32:32 -05:00
parent c7b10464a3
commit 3faaa5d25d
2 changed files with 138 additions and 41 deletions

View File

@ -2121,20 +2121,50 @@ inline void RenderLine(ImDrawList& DrawList, const ImVec2& p1, const ImVec2& p2,
DrawList._VtxCurrentIdx += 4; DrawList._VtxCurrentIdx += 4;
} }
inline void RenderFill(ImDrawList& DrawList, const ImVec2& p1, const ImVec2& p2, float zero, ImU32 col_fill, ImVec2 uv) {
const int crosses_zero = (p1.y > zero && p2.y < zero) || (p1.y < zero && p2.y > zero); // could do y*y < 0 earlier on
const float xmid = p1.x + (p2.x - p1.x) / (p2.y-p1.y) * (zero - p1.y);
DrawList._VtxWritePtr[0].pos = p1;
DrawList._VtxWritePtr[0].uv = uv;
DrawList._VtxWritePtr[0].col = col_fill;
DrawList._VtxWritePtr[1].pos = p2;
DrawList._VtxWritePtr[1].uv = uv;
DrawList._VtxWritePtr[1].col = col_fill;
DrawList._VtxWritePtr[2].pos = ImVec2(xmid, zero);
DrawList._VtxWritePtr[2].uv = uv;
DrawList._VtxWritePtr[2].col = col_fill;
DrawList._VtxWritePtr[3].pos = ImVec2(p1.x, zero);
DrawList._VtxWritePtr[3].uv = uv;
DrawList._VtxWritePtr[3].col = col_fill;
DrawList._VtxWritePtr[4].pos = ImVec2(p2.x, zero);;
DrawList._VtxWritePtr[4].uv = uv;
DrawList._VtxWritePtr[4].col = col_fill;
DrawList._VtxWritePtr += 5;
DrawList._IdxWritePtr[0] = (ImDrawIdx)(DrawList._VtxCurrentIdx);
DrawList._IdxWritePtr[1] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 1 + crosses_zero);
DrawList._IdxWritePtr[2] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 3);
DrawList._IdxWritePtr[3] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 1);
DrawList._IdxWritePtr[4] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 3 - crosses_zero);
DrawList._IdxWritePtr[5] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 4);
DrawList._IdxWritePtr += 6;
DrawList._VtxCurrentIdx += 5;
}
inline void RenderLineAA(ImDrawList& DrawList, const ImVec2& p1, const ImVec2& p2, float line_weight, ImU32 col_line) { inline void RenderLineAA(ImDrawList& DrawList, const ImVec2& p1, const ImVec2& p2, float line_weight, ImU32 col_line) {
DrawList.AddLine(p1, p2, col_line, line_weight); DrawList.AddLine(p1, p2, col_line, line_weight);
} }
template <typename Getter, typename Transformer> template <typename Getter, typename Transformer>
inline void RenderLineStrip(Getter getter, Transformer transformer, ImDrawList& DrawList, int count, int offset, float line_weight, ImU32 col_line, bool cull) { inline void RenderLineStrip(Getter getter, Transformer transformer, ImDrawList& DrawList, int count, int offset, float line_weight, ImU32 col_line, bool cull) {
// render line segments
offset %= count; offset %= count;
if (offset < 0) offset += count; // shift negative offset to positive range if (offset < 0)
offset += count; // shift negative offset to positive range
int i_start = offset + 1; int i_start = offset + 1;
if (i_start >= count ) i_start -= count; if (i_start >= count)
i_start -= count;
int i_end = offset + count; int i_end = offset + count;
if (i_end >= count) i_end -= count; if (i_end >= count)
i_end -= count;
const int segments = count - 1; const int segments = count - 1;
ImVec2 p1 = transformer(getter(offset)); ImVec2 p1 = transformer(getter(offset));
if (HasFlag(gp.CurrentPlot->Flags, ImPlotFlags_AntiAliased)) { if (HasFlag(gp.CurrentPlot->Flags, ImPlotFlags_AntiAliased)) {
@ -2152,7 +2182,6 @@ inline void RenderLineStrip(Getter getter, Transformer transformer, ImDrawList&
int segments_culled = 0; int segments_culled = 0;
for (int i1 = i_start; i1 != i_end; i1 = i1 + 1 < count ? i1 + 1 : i1 + 1 - count) { for (int i1 = i_start; i1 != i_end; i1 = i1 + 1 < count ? i1 + 1 : i1 + 1 - count) {
ImVec2 p2 = transformer(getter(i1)); ImVec2 p2 = transformer(getter(i1));
if (!cull || gp.BB_Grid.Overlaps(ImRect(ImMin(p1, p2), ImMax(p1, p2)))) if (!cull || gp.BB_Grid.Overlaps(ImRect(ImMin(p1, p2), ImMax(p1, p2))))
RenderLine(DrawList, p1, p2, line_weight, col_line, uv); RenderLine(DrawList, p1, p2, line_weight, col_line, uv);
else else
@ -2164,6 +2193,34 @@ inline void RenderLineStrip(Getter getter, Transformer transformer, ImDrawList&
} }
} }
template <typename Getter, typename Transformer>
inline void RenderLineFill(Getter getter, Transformer transformer, ImDrawList& DrawList, int count, int offset, ImU32 col_fill, bool cull) {
(void)cull;
offset %= count;
if (offset < 0)
offset += count; // shift negative offset to positive range
int i_start = offset + 1;
if (i_start >= count)
i_start -= count;
int i_end = offset + count;
if (i_end >= count)
i_end -= count;
const int segments = count - 1;
ImVec2 p1 = transformer(getter(offset));
float zero = transformer(0,0).y;
const ImVec2 uv = DrawList._Data->TexUvWhitePixel;
DrawList.PrimReserve(segments * 6, segments * 5);
int segments_culled = 0;
for (int i1 = i_start; i1 != i_end; i1 = i1 + 1 < count ? i1 + 1 : i1 + 1 - count) {
ImVec2 p2 = transformer(getter(i1));
// TODO: Culling (not as simple as RenderLineStrip)
RenderFill(DrawList, p1, p2, zero, col_fill, uv);
p1 = p2;
}
if (segments_culled > 0)
DrawList.PrimUnreserve(segments_culled * 6, segments_culled * 5);
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// DATA GETTERS // DATA GETTERS
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -2231,14 +2288,9 @@ inline void PlotEx(const char* label_id, Getter getter, int count, int offset)
ImDrawList & DrawList = *ImGui::GetWindowDrawList(); ImDrawList & DrawList = *ImGui::GetWindowDrawList();
const bool rend_line = gp.Style.Colors[ImPlotCol_Line].w != 0 && gp.Style.LineWeight > 0; const bool rend_line = gp.Style.Colors[ImPlotCol_Line].w != 0 && gp.Style.LineWeight > 0;
const bool rend_mk_line = gp.Style.Colors[ImPlotCol_MarkerOutline].w != 0 && gp.Style.MarkerWeight > 0; const bool rend_fill = gp.Style.Colors[ImPlotCol_Fill].w > 0;
const bool rend_mk_fill = gp.Style.Colors[ImPlotCol_MarkerFill].w != 0;
ImU32 col_line = gp.Style.Colors[ImPlotCol_Line].w == -1 ? ImGui::GetColorU32(item->Color) : ImGui::GetColorU32(gp.Style.Colors[ImPlotCol_Line]); ImU32 col_line = gp.Style.Colors[ImPlotCol_Line].w == -1 ? ImGui::GetColorU32(item->Color) : ImGui::GetColorU32(gp.Style.Colors[ImPlotCol_Line]);
ImU32 col_mk_line = gp.Style.Colors[ImPlotCol_MarkerOutline].w == -1 ? col_line : ImGui::GetColorU32(gp.Style.Colors[ImPlotCol_MarkerOutline]);
ImU32 col_mk_fill = gp.Style.Colors[ImPlotCol_MarkerFill].w == -1 ? col_line : ImGui::GetColorU32(gp.Style.Colors[ImPlotCol_MarkerFill]);
const float line_weight = item->Highlight ? gp.Style.LineWeight * 2 : gp.Style.LineWeight;
if (gp.Style.Colors[ImPlotCol_Line].w != -1) if (gp.Style.Colors[ImPlotCol_Line].w != -1)
item->Color = gp.Style.Colors[ImPlotCol_Line]; item->Color = gp.Style.Colors[ImPlotCol_Line];
@ -2253,7 +2305,21 @@ inline void PlotEx(const char* label_id, Getter getter, int count, int offset)
} }
} }
PushPlotClipRect(); PushPlotClipRect();
// render fill
if (count > 1 && rend_fill) {
const ImU32 col_fill = ImGui::GetColorU32(gp.Style.Colors[ImPlotCol_Fill]);
if (HasFlag(plot->XAxis.Flags, ImPlotAxisFlags_LogScale) && HasFlag(plot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale))
RenderLineFill(getter, TransformerLogLog(y_axis), DrawList, count, offset, col_fill, cull);
else if (HasFlag(plot->XAxis.Flags, ImPlotAxisFlags_LogScale))
RenderLineFill(getter, TransformerLogLin(y_axis), DrawList, count, offset, col_fill, cull);
else if (HasFlag(plot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale))
RenderLineFill(getter, TransformerLinLog(y_axis), DrawList, count, offset, col_fill, cull);
else
RenderLineFill(getter, TransformerLinLin(y_axis), DrawList, count, offset, col_fill, cull);
}
// render line
if (count > 1 && rend_line) { if (count > 1 && rend_line) {
const float line_weight = item->Highlight ? gp.Style.LineWeight * 2 : gp.Style.LineWeight;
if (HasFlag(plot->XAxis.Flags, ImPlotAxisFlags_LogScale) && HasFlag(plot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale)) if (HasFlag(plot->XAxis.Flags, ImPlotAxisFlags_LogScale) && HasFlag(plot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale))
RenderLineStrip(getter, TransformerLogLog(y_axis), DrawList, count, offset, line_weight, col_line, cull); RenderLineStrip(getter, TransformerLogLog(y_axis), DrawList, count, offset, line_weight, col_line, cull);
else if (HasFlag(plot->XAxis.Flags, ImPlotAxisFlags_LogScale)) else if (HasFlag(plot->XAxis.Flags, ImPlotAxisFlags_LogScale))
@ -2265,6 +2331,10 @@ inline void PlotEx(const char* label_id, Getter getter, int count, int offset)
} }
// render markers // render markers
if (gp.Style.Marker != ImPlotMarker_None) { if (gp.Style.Marker != ImPlotMarker_None) {
const bool rend_mk_line = gp.Style.Colors[ImPlotCol_MarkerOutline].w != 0 && gp.Style.MarkerWeight > 0;
const bool rend_mk_fill = gp.Style.Colors[ImPlotCol_MarkerFill].w != 0;
const ImU32 col_mk_line = gp.Style.Colors[ImPlotCol_MarkerOutline].w == -1 ? col_line : ImGui::GetColorU32(gp.Style.Colors[ImPlotCol_MarkerOutline]);
const ImU32 col_mk_fill = gp.Style.Colors[ImPlotCol_MarkerFill].w == -1 ? col_line : ImGui::GetColorU32(gp.Style.Colors[ImPlotCol_MarkerFill]);
if (HasFlag(plot->XAxis.Flags, ImPlotAxisFlags_LogScale) && HasFlag(plot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale)) if (HasFlag(plot->XAxis.Flags, ImPlotAxisFlags_LogScale) && HasFlag(plot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale))
RenderMarkers(getter, TransformerLogLog(y_axis), DrawList, count, offset, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, cull); RenderMarkers(getter, TransformerLogLog(y_axis), DrawList, count, offset, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, cull);
else if (HasFlag(plot->XAxis.Flags, ImPlotAxisFlags_LogScale)) else if (HasFlag(plot->XAxis.Flags, ImPlotAxisFlags_LogScale))

View File

@ -183,7 +183,7 @@ void ShowDemoWindow(bool* p_open) {
ys2[i] = xs2[i] * xs2[i]; ys2[i] = xs2[i] * xs2[i];
} }
if (ImPlot::BeginPlot("Line Plot", "x", "f(x)")) { if (ImPlot::BeginPlot("Line Plot", "x", "f(x)")) {
ImPlot::PlotLine("sin(50*x)", xs1, ys1, 1001); ImPlot::PlotLine("0.5 + 0.5*sin(50*x)", xs1, ys1, 1001);
ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Circle); ImPlot::PushStyleVar(ImPlotStyleVar_Marker, ImPlotMarker_Circle);
ImPlot::PlotLine("x^2", xs2, ys2, 11); ImPlot::PlotLine("x^2", xs2, ys2, 11);
ImPlot::PopStyleVar(); ImPlot::PopStyleVar();
@ -191,6 +191,33 @@ void ShowDemoWindow(bool* p_open) {
} }
} }
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
if (ImGui::CollapsingHeader("Filled Plots")) {
static t_float xs1[101], ys1[101], ys2[101], ys3[101];
srand(0);
for (int i = 0; i < 101; ++i) {
xs1[i] = (float)i;
ys1[i] = RandomRange(400,450);
ys2[i] = RandomRange(275,350);
ys3[i] = RandomRange(150,225);
}
ImPlot::SetNextPlotLimits(0,100,0,500);
if (ImPlot::BeginPlot("Stock Prices", "Days", "Price")) {
ImPlot::PushStyleColor(ImPlotCol_Line, ImVec4(1,1,0,1));
ImPlot::PushStyleColor(ImPlotCol_Fill, ImVec4(1,1,0,0.25f));
ImPlot::PlotLine("Stock 1", xs1, ys1, 101);
ImPlot::PopStyleColor(2);
ImPlot::PushStyleColor(ImPlotCol_Line, ImVec4(1,0,1,1));
ImPlot::PushStyleColor(ImPlotCol_Fill, ImVec4(1,0,1,0.25f));
ImPlot::PlotLine("Stock 2", xs1, ys2, 101);
ImPlot::PopStyleColor(2);
ImPlot::PushStyleColor(ImPlotCol_Line, ImVec4(1,0,0,1));
ImPlot::PushStyleColor(ImPlotCol_Fill, ImVec4(1,0,0,0.25f));
ImPlot::PlotLine("Stock 3", xs1, ys3, 101);
ImPlot::PopStyleColor(2);
ImPlot::EndPlot();
}
}
//-------------------------------------------------------------------------
if (ImGui::CollapsingHeader("Scatter Plots")) { if (ImGui::CollapsingHeader("Scatter Plots")) {
srand(0); srand(0);
static t_float xs1[100], ys1[100]; static t_float xs1[100], ys1[100];