diff --git a/implot.cpp b/implot.cpp index 85a5c2d..5567c1a 100644 --- a/implot.cpp +++ b/implot.cpp @@ -61,7 +61,6 @@ You can read releases logs https://github.com/epezent/implot/releases for more d #include "implot.h" #include "imgui_internal.h" - #ifdef _MSC_VER #define sprintf sprintf_s #endif @@ -515,7 +514,6 @@ inline void FitPoint(const ImPlotPoint& p) { inline void UpdateTransformCache() { // get pixels for transforms - for (int i = 0; i < MAX_Y_AXES; i++) { gp.PixelRange[i] = ImRect(HasFlag(gp.CurrentPlot->XAxis.Flags, ImPlotAxisFlags_Invert) ? gp.BB_Plot.Max.x : gp.BB_Plot.Min.x, HasFlag(gp.CurrentPlot->YAxis[i].Flags, ImPlotAxisFlags_Invert) ? gp.BB_Plot.Min.y : gp.BB_Plot.Max.y, @@ -578,60 +576,58 @@ ImVec2 PlotToPixels(const ImPlotPoint& plt, int y_axis) { // Transformer functors struct TransformerLinLin { - TransformerLinLin(int y_axis_in) : y_axis(y_axis_in) {} + TransformerLinLin(int y_axis) : YAxis(y_axis) {} inline ImVec2 operator()(const ImPlotPoint& plt) { return (*this)(plt.x, plt.y); } inline ImVec2 operator()(double x, double y) { - return ImVec2( (float)(gp.PixelRange[y_axis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min)), - (float)(gp.PixelRange[y_axis].Min.y + gp.My[y_axis] * (y - gp.CurrentPlot->YAxis[y_axis].Range.Min)) ); + return ImVec2( (float)(gp.PixelRange[YAxis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min)), + (float)(gp.PixelRange[YAxis].Min.y + gp.My[YAxis] * (y - gp.CurrentPlot->YAxis[YAxis].Range.Min)) ); } - int y_axis; + int YAxis; }; struct TransformerLogLin { - TransformerLogLin(int y_axis_in) : y_axis(y_axis_in) {} + TransformerLogLin(int y_axis) : YAxis(y_axis) {} inline ImVec2 operator()(const ImPlotPoint& plt) { return (*this)(plt.x, plt.y); } inline ImVec2 operator()(double x, double y) { double t = ImLog10(x / gp.CurrentPlot->XAxis.Range.Min) / gp.LogDenX; x = ImLerp(gp.CurrentPlot->XAxis.Range.Min, gp.CurrentPlot->XAxis.Range.Max, (float)t); - return ImVec2( (float)(gp.PixelRange[y_axis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min)), - (float)(gp.PixelRange[y_axis].Min.y + gp.My[y_axis] * (y - gp.CurrentPlot->YAxis[y_axis].Range.Min)) ); + return ImVec2( (float)(gp.PixelRange[YAxis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min)), + (float)(gp.PixelRange[YAxis].Min.y + gp.My[YAxis] * (y - gp.CurrentPlot->YAxis[YAxis].Range.Min)) ); } - int y_axis; + int YAxis; }; struct TransformerLinLog { - TransformerLinLog(int y_axis_in) : y_axis(y_axis_in) {} + TransformerLinLog(int y_axis) : YAxis(y_axis) {} inline ImVec2 operator()(const ImPlotPoint& plt) { return (*this)(plt.x, plt.y); } inline ImVec2 operator()(double x, double y) { - double t = ImLog10(y / gp.CurrentPlot->YAxis[y_axis].Range.Min) / gp.LogDenY[y_axis]; - y = ImLerp(gp.CurrentPlot->YAxis[y_axis].Range.Min, gp.CurrentPlot->YAxis[y_axis].Range.Max, (float)t); - return ImVec2( (float)(gp.PixelRange[y_axis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min)), - (float)(gp.PixelRange[y_axis].Min.y + gp.My[y_axis] * (y - gp.CurrentPlot->YAxis[y_axis].Range.Min)) ); + double t = ImLog10(y / gp.CurrentPlot->YAxis[YAxis].Range.Min) / gp.LogDenY[YAxis]; + y = ImLerp(gp.CurrentPlot->YAxis[YAxis].Range.Min, gp.CurrentPlot->YAxis[YAxis].Range.Max, (float)t); + return ImVec2( (float)(gp.PixelRange[YAxis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min)), + (float)(gp.PixelRange[YAxis].Min.y + gp.My[YAxis] * (y - gp.CurrentPlot->YAxis[YAxis].Range.Min)) ); } - int y_axis; + int YAxis; }; struct TransformerLogLog { - TransformerLogLog(int y_axis_in) : y_axis(y_axis_in) { - - } + TransformerLogLog(int y_axis) : YAxis(y_axis) {} inline ImVec2 operator()(const ImPlotPoint& plt) { return (*this)(plt.x, plt.y); } inline ImVec2 operator()(double x, double y) { double t = ImLog10(x / gp.CurrentPlot->XAxis.Range.Min) / gp.LogDenX; x = ImLerp(gp.CurrentPlot->XAxis.Range.Min, gp.CurrentPlot->XAxis.Range.Max, (float)t); - t = ImLog10(y / gp.CurrentPlot->YAxis[y_axis].Range.Min) / gp.LogDenY[y_axis]; - y = ImLerp(gp.CurrentPlot->YAxis[y_axis].Range.Min, gp.CurrentPlot->YAxis[y_axis].Range.Max, (float)t); - return ImVec2( (float)(gp.PixelRange[y_axis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min)), - (float)(gp.PixelRange[y_axis].Min.y + gp.My[y_axis] * (y - gp.CurrentPlot->YAxis[y_axis].Range.Min)) ); + t = ImLog10(y / gp.CurrentPlot->YAxis[YAxis].Range.Min) / gp.LogDenY[YAxis]; + y = ImLerp(gp.CurrentPlot->YAxis[YAxis].Range.Min, gp.CurrentPlot->YAxis[YAxis].Range.Max, (float)t); + return ImVec2( (float)(gp.PixelRange[YAxis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min)), + (float)(gp.PixelRange[YAxis].Min.y + gp.My[YAxis] * (y - gp.CurrentPlot->YAxis[YAxis].Range.Min)) ); } - int y_axis; + int YAxis; }; //----------------------------------------------------------------------------- @@ -732,6 +728,19 @@ inline void AddDefaultTicks(const ImPlotRange& range, int nMajor, int nMinor, bo } } +inline void AddCustomTicks(const double* values, const char** labels, int n, ImVector& ticks, ImGuiTextBuffer& buffer) { + for (int i = 0; i < n; ++i) { + ImPlotTick tick(values[i],false); + tick.TextOffset = buffer.size(); + if (labels != NULL) { + buffer.append(labels[i], labels[i] + strlen(labels[i]) + 1); + tick.Size = ImGui::CalcTextSize(labels[i]); + tick.Labeled = true; + } + ticks.push_back(tick); + } +} + inline void LabelTicks(ImVector &ticks, bool scientific, ImGuiTextBuffer& buffer) { char temp[32]; for (int t = 0; t < ticks.Size; t++) { @@ -749,19 +758,6 @@ inline void LabelTicks(ImVector &ticks, bool scientific, ImGuiTextBu } } -inline void AddCustomTicks(const double* values, const char** labels, int n, ImVector& ticks, ImGuiTextBuffer& buffer) { - for (int i = 0; i < n; ++i) { - ImPlotTick tick(values[i],false); - tick.TextOffset = buffer.size(); - if (labels != NULL) { - buffer.append(labels[i], labels[i] + strlen(labels[i]) + 1); - tick.Size = ImGui::CalcTextSize(labels[i]); - tick.Labeled = true; - } - ticks.push_back(tick); - } -} - inline float MaxTickLabelWidth(ImVector& ticks) { float w = 0; for (int i = 0; i < ticks.Size; ++i) @@ -2139,12 +2135,9 @@ inline void MarkerCross(ImDrawList& DrawList, const ImVec2& c, float s, bool /*o } template -inline void RenderMarkers(Getter getter, Transformer transformer, ImDrawList& DrawList, int count, int offset, bool rend_mk_line, ImU32 col_mk_line, bool rend_mk_fill, ImU32 col_mk_fill, bool cull) { -int idx = offset; - for (int i = 0; i < count; ++i) { - ImVec2 c; - c = transformer(getter(idx)); - idx = (idx + 1) % count; +inline void RenderMarkers(Getter getter, Transformer transformer, ImDrawList& DrawList, bool rend_mk_line, ImU32 col_mk_line, bool rend_mk_fill, ImU32 col_mk_fill, bool cull) { + for (int i = 0; i < getter.Count; ++i) { + ImVec2 c = transformer(getter(i)); if (!cull || gp.BB_Plot.Contains(c)) { // TODO: Optimize the loop and if statements, this is atrocious if (HasFlag(gp.Style.Marker, ImPlotMarker_Circle)) @@ -2171,215 +2164,277 @@ int idx = offset; } } -inline void RenderLine(ImDrawList& DrawList, const ImVec2& p1, const ImVec2& p2, float line_weight, ImU32 col_line, ImVec2 uv) { - // http://assemblyrequired.crashworks.org/timing-square-root/ - float dx = p2.x - p1.x; - float dy = p2.y - p1.y; - IM_NORMALIZE2F_OVER_ZERO(dx, dy); - dx *= (line_weight * 0.5f); - dy *= (line_weight * 0.5f); - DrawList._VtxWritePtr[0].pos.x = p1.x + dy; - DrawList._VtxWritePtr[0].pos.y = p1.y - dx; - DrawList._VtxWritePtr[0].uv = uv; - DrawList._VtxWritePtr[0].col = col_line; - DrawList._VtxWritePtr[1].pos.x = p2.x + dy; - DrawList._VtxWritePtr[1].pos.y = p2.y - dx; - DrawList._VtxWritePtr[1].uv = uv; - DrawList._VtxWritePtr[1].col = col_line; - DrawList._VtxWritePtr[2].pos.x = p2.x - dy; - DrawList._VtxWritePtr[2].pos.y = p2.y + dx; - DrawList._VtxWritePtr[2].uv = uv; - DrawList._VtxWritePtr[2].col = col_line; - DrawList._VtxWritePtr[3].pos.x = p1.x - dy; - DrawList._VtxWritePtr[3].pos.y = p1.y + dx; - DrawList._VtxWritePtr[3].uv = uv; - DrawList._VtxWritePtr[3].col = col_line; - DrawList._VtxWritePtr += 4; - DrawList._IdxWritePtr[0] = (ImDrawIdx)(DrawList._VtxCurrentIdx); - DrawList._IdxWritePtr[1] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 1); - DrawList._IdxWritePtr[2] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 2); - DrawList._IdxWritePtr[3] = (ImDrawIdx)(DrawList._VtxCurrentIdx); - DrawList._IdxWritePtr[4] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 2); - DrawList._IdxWritePtr[5] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 3); - DrawList._IdxWritePtr += 6; - DrawList._VtxCurrentIdx += 4; -} +struct LineRenderer { + LineRenderer(ImU32 col, float weight) { Col = col; Weight = weight; } + inline void render(ImDrawList& DrawList, const ImVec2& p1, const ImVec2& p2, ImVec2 uv) { + float dx = p2.x - p1.x; + float dy = p2.y - p1.y; + IM_NORMALIZE2F_OVER_ZERO(dx, dy); + dx *= (Weight * 0.5f); + dy *= (Weight * 0.5f); + DrawList._VtxWritePtr[0].pos.x = p1.x + dy; + DrawList._VtxWritePtr[0].pos.y = p1.y - dx; + DrawList._VtxWritePtr[0].uv = uv; + DrawList._VtxWritePtr[0].col = Col; + DrawList._VtxWritePtr[1].pos.x = p2.x + dy; + DrawList._VtxWritePtr[1].pos.y = p2.y - dx; + DrawList._VtxWritePtr[1].uv = uv; + DrawList._VtxWritePtr[1].col = Col; + DrawList._VtxWritePtr[2].pos.x = p2.x - dy; + DrawList._VtxWritePtr[2].pos.y = p2.y + dx; + DrawList._VtxWritePtr[2].uv = uv; + DrawList._VtxWritePtr[2].col = Col; + DrawList._VtxWritePtr[3].pos.x = p1.x - dy; + DrawList._VtxWritePtr[3].pos.y = p1.y + dx; + DrawList._VtxWritePtr[3].uv = uv; + DrawList._VtxWritePtr[3].col = Col; + DrawList._VtxWritePtr += 4; + DrawList._IdxWritePtr[0] = (ImDrawIdx)(DrawList._VtxCurrentIdx); + DrawList._IdxWritePtr[1] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 1); + DrawList._IdxWritePtr[2] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 2); + DrawList._IdxWritePtr[3] = (ImDrawIdx)(DrawList._VtxCurrentIdx); + DrawList._IdxWritePtr[4] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 2); + DrawList._IdxWritePtr[5] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 3); + DrawList._IdxWritePtr += 6; + DrawList._VtxCurrentIdx += 4; + } + ImU32 Col; + float Weight; + static const int IdxConsumed = 6; + static const int VtxConsumed = 4; +}; -inline void RenderRect(ImDrawList& DrawList, const ImVec2& p1, const ImVec2& p2, ImU32 col_ul, ImU32 col_ur, ImU32 col_bl, ImU32 col_br, ImVec2 uv) { - DrawList._VtxWritePtr[0].pos.x = p1.x; - DrawList._VtxWritePtr[0].pos.y = p1.y; - DrawList._VtxWritePtr[0].uv = uv; - DrawList._VtxWritePtr[0].col = col_ul; - DrawList._VtxWritePtr[1].pos.x = p2.x; - DrawList._VtxWritePtr[1].pos.y = p1.y; - DrawList._VtxWritePtr[1].uv = uv; - DrawList._VtxWritePtr[1].col = col_ur; - DrawList._VtxWritePtr[2].pos.x = p2.x; - DrawList._VtxWritePtr[2].pos.y = p2.y; - DrawList._VtxWritePtr[2].uv = uv; - DrawList._VtxWritePtr[2].col = col_br; - DrawList._VtxWritePtr[3].pos.x = p1.x; - DrawList._VtxWritePtr[3].pos.y = p2.y; - DrawList._VtxWritePtr[3].uv = uv; - DrawList._VtxWritePtr[3].col = col_bl; - DrawList._VtxWritePtr += 4; - DrawList._IdxWritePtr[0] = (ImDrawIdx)(DrawList._VtxCurrentIdx); - DrawList._IdxWritePtr[1] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 1); - DrawList._IdxWritePtr[2] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 3); - DrawList._IdxWritePtr[3] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 1); - DrawList._IdxWritePtr[4] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 2); - DrawList._IdxWritePtr[5] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 3); - DrawList._IdxWritePtr += 6; - DrawList._VtxCurrentIdx += 4; -} +struct FillRenderer { + FillRenderer(ImU32 col, float zero) { Col = col; Zero = zero; } + inline void render(ImDrawList& DrawList, const ImVec2& p1, const ImVec2& p2, 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; + DrawList._VtxWritePtr[1].pos = p2; + DrawList._VtxWritePtr[1].uv = uv; + DrawList._VtxWritePtr[1].col = Col; + DrawList._VtxWritePtr[2].pos = ImVec2(xmid, Zero); + DrawList._VtxWritePtr[2].uv = uv; + DrawList._VtxWritePtr[2].col = Col; + DrawList._VtxWritePtr[3].pos = ImVec2(p1.x, Zero); + DrawList._VtxWritePtr[3].uv = uv; + DrawList._VtxWritePtr[3].col = Col; + DrawList._VtxWritePtr[4].pos = ImVec2(p2.x, Zero);; + DrawList._VtxWritePtr[4].uv = uv; + DrawList._VtxWritePtr[4].col = Col; + 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; + } + ImU32 Col; + float Zero; + static const int IdxConsumed = 6; + static const int VtxConsumed = 5; +}; -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; -} +struct RectRenderer { -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); + RectRenderer(ImU32 col) { Col = col; } + + inline void render(ImDrawList& DrawList, const ImVec2& p1, const ImVec2& p2, ImVec2 uv) { + DrawList._VtxWritePtr[0].pos.x = p1.x; + DrawList._VtxWritePtr[0].pos.y = p1.y; + DrawList._VtxWritePtr[0].uv = uv; + DrawList._VtxWritePtr[0].col = Col; + DrawList._VtxWritePtr[1].pos.x = p2.x; + DrawList._VtxWritePtr[1].pos.y = p1.y; + DrawList._VtxWritePtr[1].uv = uv; + DrawList._VtxWritePtr[1].col = Col; + DrawList._VtxWritePtr[2].pos.x = p2.x; + DrawList._VtxWritePtr[2].pos.y = p2.y; + DrawList._VtxWritePtr[2].uv = uv; + DrawList._VtxWritePtr[2].col = Col; + DrawList._VtxWritePtr[3].pos.x = p1.x; + DrawList._VtxWritePtr[3].pos.y = p2.y; + DrawList._VtxWritePtr[3].uv = uv; + DrawList._VtxWritePtr[3].col = Col; + DrawList._VtxWritePtr += 4; + DrawList._IdxWritePtr[0] = (ImDrawIdx)(DrawList._VtxCurrentIdx); + DrawList._IdxWritePtr[1] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 1); + DrawList._IdxWritePtr[2] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 3); + DrawList._IdxWritePtr[3] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 1); + DrawList._IdxWritePtr[4] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 2); + DrawList._IdxWritePtr[5] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 3); + DrawList._IdxWritePtr += 6; + DrawList._VtxCurrentIdx += 4; + } + ImU32 Col; + static const int IdxConsumed = 6; + static const int VtxConsumed = 4; +}; + +template +inline void RenderPrimitives(Getter getter, Transformer transformer, Renderer renderer, ImDrawList& DrawList, bool cull) { + ImVec2 p1 = transformer(getter(0)); + int prims = getter.Count - 1; + int i1 = 1; + int prims_culled = 0; + + const ImVec2 uv = DrawList._Data->TexUvWhitePixel; + while (prims) { + // find how many can be reserved up to end of current draw command's limit + int cnt = (int)ImMin(size_t(prims), (((size_t(1) << sizeof(ImDrawIdx) * 8) - 1 - DrawList._VtxCurrentIdx) / Renderer::VtxConsumed)); + // make sure at least this many elements can be rendered to avoid situations where at the end of buffer this slow path is not taken all the time + if (cnt >= ImMin(64, prims)) { + if (prims_culled >= cnt) + prims_culled -= cnt; // reuse previous reservation + else { + DrawList.PrimReserve((cnt - prims_culled) * Renderer::IdxConsumed, (cnt - prims_culled) * Renderer::VtxConsumed); // add more elements to previous reservation + prims_culled = 0; + } + } + else + { + if (prims_culled > 0) { + DrawList.PrimUnreserve(prims_culled * Renderer::IdxConsumed, prims_culled * Renderer::VtxConsumed); + prims_culled = 0; + } + + cnt = (int)ImMin(size_t(prims), (((size_t(1) << sizeof(ImDrawIdx) * 8) - 1 - 0/*DrawList._VtxCurrentIdx*/) / Renderer::VtxConsumed)); + DrawList.PrimReserve(cnt * Renderer::IdxConsumed, cnt * Renderer::VtxConsumed); // reserve new draw command + } + prims -= cnt; + for (int ie = i1 + cnt; i1 != ie; ++i1) { + + ImVec2 p2 = transformer(getter(i1)); + // TODO: Put the cull check inside of each Renderer + if (!cull || gp.BB_Plot.Overlaps(ImRect(ImMin(p1, p2), ImMax(p1, p2)))) + renderer.render(DrawList, p1, p2, uv); + else + prims_culled++; + p1 = p2; + } + } + if (prims_culled > 0) + DrawList.PrimUnreserve(prims_culled * Renderer::IdxConsumed, prims_culled * Renderer::VtxConsumed); } template -inline void RenderLineStrip(Getter getter, Transformer transformer, ImDrawList& DrawList, int count, int offset, float line_weight, ImU32 col_line, bool 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)); +inline void RenderLineStrip(Getter getter, Transformer transformer, ImDrawList& DrawList, float line_weight, ImU32 col, bool cull) { if (HasFlag(gp.CurrentPlot->Flags, ImPlotFlags_AntiAliased)) { - for (int i1 = i_start; i1 != i_end; i1 = i1 + 1 < count ? i1 + 1 : i1 + 1 - count) { - ImVec2 p2 = transformer(getter(i1)); - + ImVec2 p1 = transformer(getter(0)); + for (int i = 0; i < getter.Count; ++i) { + ImVec2 p2 = transformer(getter(i)); if (!cull || gp.BB_Plot.Overlaps(ImRect(ImMin(p1, p2), ImMax(p1, p2)))) - RenderLineAA(DrawList, p1, p2, line_weight, col_line); + DrawList.AddLine(p1, p2, col, line_weight); p1 = p2; } } else { - const ImVec2 uv = DrawList._Data->TexUvWhitePixel; - DrawList.PrimReserve(segments * 6, segments * 4); - 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)); - if (!cull || gp.BB_Plot.Overlaps(ImRect(ImMin(p1, p2), ImMax(p1, p2)))) - RenderLine(DrawList, p1, p2, line_weight, col_line, uv); - else - segments_culled++; - p1 = p2; - } - if (segments_culled > 0) - DrawList.PrimUnreserve(segments_culled * 6, segments_culled * 4); + RenderPrimitives(getter, transformer, LineRenderer(col, line_weight), DrawList, cull); } } template -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)); +inline void RenderLineFill(Getter getter, Transformer transformer, ImDrawList& DrawList, ImU32 col_fill) { + // TODO: Culling 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); + RenderPrimitives(getter, transformer, FillRenderer(col_fill, zero), DrawList, false); } //----------------------------------------------------------------------------- // DATA GETTERS //----------------------------------------------------------------------------- +inline int PosMod(int l, int r) { + return (l % r + r) % r; +} + +// template +// inline T StrideIndex(const T* data, int idx, int stride) { +// return *(const T*)(const void*)((const unsigned char*)data + (size_t)idx * stride); +// } + template -inline T StrideIndex(const T* data, int idx, int stride) { +inline T OffsetAndStride(const T* data, int idx, int count, int offset, int stride) { + idx = PosMod(offset + idx, count); return *(const T*)(const void*)((const unsigned char*)data + (size_t)idx * stride); } template struct GetterYs { - GetterYs(const T* ys, int stride) { Ys = ys; Stride = stride; } + GetterYs(const T* ys, int count, int offset, int stride) { + Ys = ys; + Count = count; + Offset = PosMod(offset, count);; + Stride = stride; + } const T* Ys; + int Count; + int Offset; int Stride; inline ImPlotPoint operator()(int idx) { - return ImPlotPoint((T)idx, StrideIndex(Ys, idx, Stride)); + return ImPlotPoint((T)idx, OffsetAndStride(Ys, idx, Count, Offset, Stride)); } }; template struct GetterXsYs { - GetterXsYs(const T* xs, const T* ys, int stride) { Xs = xs; Ys = ys; Stride = stride; } + GetterXsYs(const T* xs, const T* ys, int count, int offset, int stride) { + Xs = xs; Ys = ys; + Count = count; + Offset = PosMod(offset, count);; + Stride = stride; + } const T* Xs; const T* Ys; + int Count; + int Offset; int Stride; inline ImPlotPoint operator()(int idx) { - return ImPlotPoint(StrideIndex(Xs, idx, Stride), StrideIndex(Ys, idx, Stride)); + return ImPlotPoint(OffsetAndStride(Xs, idx, Count, Offset, Stride), OffsetAndStride(Ys, idx, Count, Offset, Stride)); } }; struct GetterImVec2 { - GetterImVec2(const ImVec2* data) { Data = data; } + GetterImVec2(const ImVec2* data, int count, int offset) { + Data = data; + Count = count; + Offset = PosMod(offset, count); + } inline ImPlotPoint operator()(int idx) { return ImPlotPoint(Data[idx].x, Data[idx].y); } const ImVec2* Data; + int Count; + int Offset; }; struct GetterImPlotPoint { - GetterImPlotPoint(const ImPlotPoint* data) { Data = data; } + GetterImPlotPoint(const ImPlotPoint* data, int count, int offset) { + Data = data; + Count = count; + Offset = PosMod(offset, count); + } inline ImPlotPoint operator()(int idx) { return Data[idx]; } const ImPlotPoint* Data; + int Count; + int Offset; }; struct GetterFuncPtrImPlotPoint { - GetterFuncPtrImPlotPoint(ImPlotPoint (*g)(void* data, int idx), void* d) { getter = g; data = d;} - inline ImPlotPoint operator()(int idx) { return getter(data, idx); } + GetterFuncPtrImPlotPoint(ImPlotPoint (*g)(void* data, int idx), void* d, int count, int offset) { + getter = g; + Data = d; + Count = count; + Offset = PosMod(offset, count); + } + inline ImPlotPoint operator()(int idx) { return getter(Data, idx); } ImPlotPoint (*getter)(void* data, int idx); - void* data; + void* Data; + int Count; + int Offset; }; //----------------------------------------------------------------------------- @@ -2387,7 +2442,7 @@ struct GetterFuncPtrImPlotPoint { //----------------------------------------------------------------------------- template -inline void PlotEx(const char* label_id, Getter getter, int count, int offset) +inline void PlotEx(const char* label_id, Getter getter) { IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "Plot() needs to be called between BeginPlot() and EndPlot()!"); @@ -2411,41 +2466,41 @@ inline void PlotEx(const char* label_id, Getter getter, int count, int offset) // find data extents if (gp.FitThisFrame) { - for (int i = 0; i < count; ++i) { + for (int i = 0; i < getter.Count; ++i) { ImPlotPoint p = getter(i); FitPoint(p); } if (rend_fill) { ImPlotPoint p1 = getter(0); - ImPlotPoint p2 = getter(count - 1); + ImPlotPoint p2 = getter(getter.Count - 1); p1.y = 0; p2.y = 0; FitPoint(p1); FitPoint(p2); } } PushPlotClipRect(); // render fill - if (count > 1 && rend_fill) { + if (getter.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); + RenderLineFill(getter, TransformerLogLog(y_axis), DrawList, col_fill); else if (HasFlag(plot->XAxis.Flags, ImPlotAxisFlags_LogScale)) - RenderLineFill(getter, TransformerLogLin(y_axis), DrawList, count, offset, col_fill, cull); + RenderLineFill(getter, TransformerLogLin(y_axis), DrawList, col_fill); else if (HasFlag(plot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale)) - RenderLineFill(getter, TransformerLinLog(y_axis), DrawList, count, offset, col_fill, cull); + RenderLineFill(getter, TransformerLinLog(y_axis), DrawList, col_fill); else - RenderLineFill(getter, TransformerLinLin(y_axis), DrawList, count, offset, col_fill, cull); + RenderLineFill(getter, TransformerLinLin(y_axis), DrawList, col_fill); } // render line - if (count > 1 && rend_line) { + if (getter.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)) - RenderLineStrip(getter, TransformerLogLog(y_axis), DrawList, count, offset, line_weight, col_line, cull); + RenderLineStrip(getter, TransformerLogLog(y_axis), DrawList, line_weight, col_line, cull); else if (HasFlag(plot->XAxis.Flags, ImPlotAxisFlags_LogScale)) - RenderLineStrip(getter, TransformerLogLin(y_axis), DrawList, count, offset, line_weight, col_line, cull); + RenderLineStrip(getter, TransformerLogLin(y_axis), DrawList, line_weight, col_line, cull); else if (HasFlag(plot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale)) - RenderLineStrip(getter, TransformerLinLog(y_axis), DrawList, count, offset, line_weight, col_line, cull); + RenderLineStrip(getter, TransformerLinLog(y_axis), DrawList, line_weight, col_line, cull); else - RenderLineStrip(getter, TransformerLinLin(y_axis), DrawList, count, offset, line_weight, col_line, cull); + RenderLineStrip(getter, TransformerLinLin(y_axis), DrawList, line_weight, col_line, cull); } // render markers if (gp.Style.Marker != ImPlotMarker_None) { @@ -2454,13 +2509,13 @@ inline void PlotEx(const char* label_id, Getter getter, int count, int offset) 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)) - 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, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, cull); else if (HasFlag(plot->XAxis.Flags, ImPlotAxisFlags_LogScale)) - RenderMarkers(getter, TransformerLogLin(y_axis), DrawList, count, offset, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, cull); + RenderMarkers(getter, TransformerLogLin(y_axis), DrawList, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, cull); else if (HasFlag(plot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale)) - RenderMarkers(getter, TransformerLinLog(y_axis), DrawList, count, offset, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, cull); + RenderMarkers(getter, TransformerLinLog(y_axis), DrawList, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, cull); else - RenderMarkers(getter, TransformerLinLin(y_axis), DrawList, count, offset, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, cull); + RenderMarkers(getter, TransformerLinLin(y_axis), DrawList, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, cull); } PopPlotClipRect(); } @@ -2469,18 +2524,18 @@ inline void PlotEx(const char* label_id, Getter getter, int count, int offset) // float void PlotLine(const char* label_id, const float* values, int count, int offset, int stride) { - GetterYs getter(values,stride); - PlotEx(label_id, getter, count, offset); + GetterYs getter(values,count,offset,stride); + PlotEx(label_id, getter); } void PlotLine(const char* label_id, const float* xs, const float* ys, int count, int offset, int stride) { - GetterXsYs getter(xs,ys,stride); - return PlotEx(label_id, getter, count, offset); + GetterXsYs getter(xs,ys,count,offset,stride); + return PlotEx(label_id, getter); } void PlotLine(const char* label_id, const ImVec2* data, int count, int offset) { - GetterImVec2 getter(data); - return PlotEx(label_id, getter, count, offset); + GetterImVec2 getter(data, count, offset); + return PlotEx(label_id, getter); } @@ -2488,26 +2543,26 @@ void PlotLine(const char* label_id, const ImVec2* data, int count, int offset) { // double void PlotLine(const char* label_id, const double* values, int count, int offset, int stride) { - GetterYs getter(values,stride); - PlotEx(label_id, getter, count, offset); + GetterYs getter(values,count,offset,stride); + PlotEx(label_id, getter); } void PlotLine(const char* label_id, const double* xs, const double* ys, int count, int offset, int stride) { - GetterXsYs getter(xs,ys,stride); - return PlotEx(label_id, getter, count, offset); + GetterXsYs getter(xs,ys,count,offset,stride); + return PlotEx(label_id, getter); } void PlotLine(const char* label_id, const ImPlotPoint* data, int count, int offset) { - GetterImPlotPoint getter(data); - return PlotEx(label_id, getter, count, offset); + GetterImPlotPoint getter(data, count, offset); + return PlotEx(label_id, getter); } //----------------------------------------------------------------------------- // custom void PlotLine(const char* label_id, ImPlotPoint (*getter_func)(void* data, int idx), void* data, int count, int offset) { - GetterFuncPtrImPlotPoint getter(getter_func,data); - return PlotEx(label_id, getter, count, offset); + GetterFuncPtrImPlotPoint getter(getter_func,data, count, offset); + return PlotEx(label_id, getter); } //----------------------------------------------------------------------------- @@ -2579,23 +2634,25 @@ void PlotScatter(const char* label_id, ImPlotPoint (*getter)(void* data, int idx // PLOT BAR V //----------------------------------------------------------------------------- +// TODO: Migrate to RenderPrimitives + template struct GetterBarV { - const T* Ys; T XShift; int Stride; - GetterBarV(const T* ys, T xshift, int stride) { Ys = ys; XShift = xshift; Stride = stride; } - inline ImPlotPoint operator()(int idx) { return ImPlotPoint((T)idx + XShift, StrideIndex(Ys, idx, Stride)); } + const T* Ys; T XShift; int Count; int Offset; int Stride; + GetterBarV(const T* ys, T xshift, int count, int offset, int stride) { Ys = ys; XShift = xshift; Count = count; Offset = offset; Stride = stride; } + inline ImPlotPoint operator()(int idx) { return ImPlotPoint((T)idx + XShift, OffsetAndStride(Ys, idx, Count, Offset, Stride)); } }; template struct GetterBarH { - const T* Xs; T YShift; int Stride; - GetterBarH(const T* xs, T yshift, int stride) { Xs = xs; YShift = yshift; Stride = stride; } - inline ImPlotPoint operator()(int idx) { return ImPlotPoint(StrideIndex(Xs, idx, Stride), (T)idx + YShift); } + const T* Xs; T YShift; int Count; int Offset; int Stride; + GetterBarH(const T* xs, T yshift, int count, int offset, int stride) { Xs = xs; YShift = yshift; Count = count; Offset = offset; Stride = stride; } + inline ImPlotPoint operator()(int idx) { return ImPlotPoint(OffsetAndStride(Xs, idx, Count, Offset, Stride), (T)idx + YShift); } }; template -void PlotBarsEx(const char* label_id, Getter getter, int count, TWidth width, int offset) { +void PlotBarsEx(const char* label_id, Getter getter, TWidth width) { IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PlotBars() needs to be called between BeginPlot() and EndPlot()!"); @@ -2623,17 +2680,15 @@ void PlotBarsEx(const char* label_id, Getter getter, int count, TWidth width, in // find data extents if (gp.FitThisFrame) { - for (int i = 0; i < count; ++i) { + for (int i = 0; i < getter.Count; ++i) { ImPlotPoint p = getter(i); FitPoint(ImPlotPoint(p.x - half_width, p.y)); FitPoint(ImPlotPoint(p.x + half_width, 0)); } } - int idx = offset; - for (int i = 0; i < count; ++i) { - ImPlotPoint p = getter(idx); - idx = (idx + 1) % count; + for (int i = 0; i < getter.Count; ++i) { + ImPlotPoint p = getter(i); if (p.y == 0) continue; ImVec2 a = PlotToPixels(p.x - half_width, p.y); @@ -2650,42 +2705,44 @@ void PlotBarsEx(const char* label_id, Getter getter, int count, TWidth width, in // float void PlotBars(const char* label_id, const float* values, int count, float width, float shift, int offset, int stride) { - GetterBarV getter(values,shift,stride); - PlotBarsEx(label_id, getter, count, width, offset); + GetterBarV getter(values,shift,count,offset,stride); + PlotBarsEx(label_id, getter, width); } void PlotBars(const char* label_id, const float* xs, const float* ys, int count, float width, int offset, int stride) { - GetterXsYs getter(xs,ys,stride); - PlotBarsEx(label_id, getter, count, width, offset); + GetterXsYs getter(xs,ys,count,offset,stride); + PlotBarsEx(label_id, getter, width); } //----------------------------------------------------------------------------- // double void PlotBars(const char* label_id, const double* values, int count, double width, double shift, int offset, int stride) { - GetterBarV getter(values,shift,stride); - PlotBarsEx(label_id, getter, count, width, offset); + GetterBarV getter(values,shift,count,offset,stride); + PlotBarsEx(label_id, getter, width); } void PlotBars(const char* label_id, const double* xs, const double* ys, int count, double width, int offset, int stride) { - GetterXsYs getter(xs,ys,stride); - PlotBarsEx(label_id, getter, count, width, offset); + GetterXsYs getter(xs,ys,count,offset,stride); + PlotBarsEx(label_id, getter, width); } //----------------------------------------------------------------------------- // custom void PlotBars(const char* label_id, ImPlotPoint (*getter_func)(void* data, int idx), void* data, int count, double width, int offset) { - GetterFuncPtrImPlotPoint getter(getter_func, data); - PlotBarsEx(label_id, getter, count, width, offset); + GetterFuncPtrImPlotPoint getter(getter_func, data, count, offset); + PlotBarsEx(label_id, getter, width); } //----------------------------------------------------------------------------- // PLOT BAR H //----------------------------------------------------------------------------- +// TODO: Migrate to RenderPrimitives + template -void PlotBarsHEx(const char* label_id, Getter getter, int count, THeight height, int offset) { +void PlotBarsHEx(const char* label_id, Getter getter, THeight height) { IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PlotBarsH() needs to be called between BeginPlot() and EndPlot()!"); @@ -2713,17 +2770,15 @@ void PlotBarsHEx(const char* label_id, Getter getter, int count, THeight height, // find data extents if (gp.FitThisFrame) { - for (int i = 0; i < count; ++i) { + for (int i = 0; i < getter.Count; ++i) { ImPlotPoint p = getter(i); FitPoint(ImPlotPoint(0, p.y - half_height)); FitPoint(ImPlotPoint(p.x, p.y + half_height)); } } - int idx = offset; - for (int i = 0; i < count; ++i) { - ImPlotPoint p = getter(idx); - idx = (idx + 1) % count; + for (int i = 0; i < getter.Count; ++i) { + ImPlotPoint p = getter(i); if (p.x == 0) continue; ImVec2 a = PlotToPixels(0, p.y - half_height); @@ -2740,34 +2795,34 @@ void PlotBarsHEx(const char* label_id, Getter getter, int count, THeight height, // float void PlotBarsH(const char* label_id, const float* values, int count, float height, float shift, int offset, int stride) { - GetterBarH getter(values,shift,stride); - PlotBarsHEx(label_id, getter, count, height, offset); + GetterBarH getter(values,shift,count,offset,stride); + PlotBarsHEx(label_id, getter, height); } void PlotBarsH(const char* label_id, const float* xs, const float* ys, int count, float height, int offset, int stride) { - GetterXsYs getter(xs,ys,stride); - PlotBarsHEx(label_id, getter, count, height, offset); + GetterXsYs getter(xs,ys,count,offset,stride); + PlotBarsHEx(label_id, getter, height); } //----------------------------------------------------------------------------- // double void PlotBarsH(const char* label_id, const double* values, int count, double height, double shift, int offset, int stride) { - GetterBarH getter(values,shift,stride); - PlotBarsHEx(label_id, getter, count, height, offset); + GetterBarH getter(values,shift,count,offset,stride); + PlotBarsHEx(label_id, getter, height); } void PlotBarsH(const char* label_id, const double* xs, const double* ys, int count, double height, int offset, int stride) { - GetterXsYs getter(xs,ys,stride); - PlotBarsHEx(label_id, getter, count, height, offset); + GetterXsYs getter(xs,ys,count,offset,stride); + PlotBarsHEx(label_id, getter, height); } //----------------------------------------------------------------------------- // custom void PlotBarsH(const char* label_id, ImPlotPoint (*getter_func)(void* data, int idx), void* data, int count, double height, int offset) { - GetterFuncPtrImPlotPoint getter(getter_func, data); - PlotBarsHEx(label_id, getter, count, height, offset); + GetterFuncPtrImPlotPoint getter(getter_func, data, count, offset); + PlotBarsHEx(label_id, getter, height); } //----------------------------------------------------------------------------- @@ -2783,20 +2838,20 @@ struct ImPlotPointError { template struct GetterError { - const T* Xs; const T* Ys; const T* Neg; const T* Pos; int Stride; - GetterError(const T* xs, const T* ys, const T* neg, const T* pos, int stride) { - Xs = xs; Ys = ys; Neg = neg; Pos = pos; Stride = stride; + const T* Xs; const T* Ys; const T* Neg; const T* Pos; int Count; int Offset; int Stride; + GetterError(const T* xs, const T* ys, const T* neg, const T* pos, int count, int offset, int stride) { + Xs = xs; Ys = ys; Neg = neg; Pos = pos; Count = count; Offset = offset; Stride = stride; } ImPlotPointError operator()(int idx) { - return ImPlotPointError(StrideIndex(Xs, idx, Stride), - StrideIndex(Ys, idx, Stride), - StrideIndex(Neg, idx, Stride), - StrideIndex(Pos, idx, Stride)); + return ImPlotPointError(OffsetAndStride(Xs, idx, Count, Offset, Stride), + OffsetAndStride(Ys, idx, Count, Offset, Stride), + OffsetAndStride(Neg, idx, Count, Offset, Stride), + OffsetAndStride(Pos, idx, Count, Offset, Stride)); } }; template -void PlotErrorBarsEx(const char* label_id, Getter getter, int count, int offset) { +void PlotErrorBarsEx(const char* label_id, Getter getter) { IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PlotErrorBars() needs to be called between BeginPlot() and EndPlot()!"); ImGuiID id = ImGui::GetID(label_id); @@ -2815,17 +2870,15 @@ void PlotErrorBarsEx(const char* label_id, Getter getter, int count, int offset) // find data extents if (gp.FitThisFrame) { - for (int i = 0; i < count; ++i) { + for (int i = 0; i < getter.Count; ++i) { ImPlotPointError e = getter(i); FitPoint(ImPlotPoint(e.x , e.y - e.neg)); FitPoint(ImPlotPoint(e.x , e.y + e.pos )); } } - int idx = offset; - for (int i = 0; i < count; ++i) { - ImPlotPointError e = getter(idx); - idx = (idx + 1) % count; + for (int i = 0; i < getter.Count; ++i) { + ImPlotPointError e = getter(i); ImVec2 p1 = PlotToPixels(e.x, e.y - e.neg); ImVec2 p2 = PlotToPixels(e.x, e.y + e.pos); DrawList.AddLine(p1,p2,col, gp.Style.ErrorBarWeight); @@ -2841,26 +2894,26 @@ void PlotErrorBarsEx(const char* label_id, Getter getter, int count, int offset) // float void PlotErrorBars(const char* label_id, const float* xs, const float* ys, const float* err, int count, int offset, int stride) { - GetterError getter(xs, ys, err, err, stride); - PlotErrorBarsEx(label_id, getter, count, offset); + GetterError getter(xs, ys, err, err, count, offset, stride); + PlotErrorBarsEx(label_id, getter); } void PlotErrorBars(const char* label_id, const float* xs, const float* ys, const float* neg, const float* pos, int count, int offset, int stride) { - GetterError getter(xs, ys, neg, pos, stride); - PlotErrorBarsEx(label_id, getter, count, offset); + GetterError getter(xs, ys, neg, pos, count, offset, stride); + PlotErrorBarsEx(label_id, getter); } //----------------------------------------------------------------------------- // double void PlotErrorBars(const char* label_id, const double* xs, const double* ys, const double* err, int count, int offset, int stride) { - GetterError getter(xs, ys, err, err, stride); - PlotErrorBarsEx(label_id, getter, count, offset); + GetterError getter(xs, ys, err, err, count, offset, stride); + PlotErrorBarsEx(label_id, getter); } void PlotErrorBars(const char* label_id, const double* xs, const double* ys, const double* neg, const double* pos, int count, int offset, int stride) { - GetterError getter(xs, ys, neg, pos, stride); - PlotErrorBarsEx(label_id, getter, count, offset); + GetterError getter(xs, ys, neg, pos, count, offset, stride); + PlotErrorBarsEx(label_id, getter); } //----------------------------------------------------------------------------- @@ -2954,10 +3007,7 @@ void RenderHeatmap(Transformer transformer, ImDrawList& DrawList, const T* value const double w = (bounds_max.x - bounds_min.x) / cols; const double h = (bounds_max.y - bounds_min.y) / rows; const ImPlotPoint half_size(w*0.5,h*0.5); - const int n = rows * cols; int i = 0; - DrawList.PrimReserve(6*n, 4*n); - const ImVec2 uv = DrawList._Data->TexUvWhitePixel; for (int r = 0; r < rows; ++r) { for (int c = 0; c < cols; ++c) { ImPlotPoint p; @@ -2968,7 +3018,7 @@ void RenderHeatmap(Transformer transformer, ImDrawList& DrawList, const T* value float t = (float)Remap(values[i], scale_min, scale_max, T(0), T(1)); ImVec4 color = LerpColormap(t); ImU32 col = ImGui::GetColorU32(color); - RenderRect(DrawList, a, b, col, col, col, col, uv); + DrawList.AddRectFilled(a, b, col); i++; } } @@ -3112,7 +3162,7 @@ inline void PlotDigitalEx(const char* label_id, Getter getter, int count, int of // float void PlotDigital(const char* label_id, const float* xs, const float* ys, int count, int offset, int stride) { - GetterXsYs getter(xs,ys,stride); + GetterXsYs getter(xs,ys,count,offset,stride); return PlotDigitalEx(label_id, getter, count, offset); } @@ -3120,7 +3170,7 @@ void PlotDigital(const char* label_id, const float* xs, const float* ys, int cou // double void PlotDigital(const char* label_id, const double* xs, const double* ys, int count, int offset, int stride) { - GetterXsYs getter(xs,ys,stride); + GetterXsYs getter(xs,ys,count,offset,stride); return PlotDigitalEx(label_id, getter, count, offset); } @@ -3128,7 +3178,7 @@ void PlotDigital(const char* label_id, const double* xs, const double* ys, int c // custom void PlotDigital(const char* label_id, ImPlotPoint (*getter_func)(void* data, int idx), void* data, int count, int offset) { - GetterFuncPtrImPlotPoint getter(getter_func,data); + GetterFuncPtrImPlotPoint getter(getter_func,data,count,offset); return PlotDigitalEx(label_id, getter, count, offset); } diff --git a/implot_demo.cpp b/implot_demo.cpp index 3231854..4256b5e 100644 --- a/implot_demo.cpp +++ b/implot_demo.cpp @@ -160,6 +160,12 @@ void ShowDemoWindow(bool* p_open) { ImGui::Unindent(); ImGui::BulletText("Double right click to open the plot context menu."); ImGui::BulletText("Click legend label icons to show/hide plot items."); + ImGui::BulletText("IMPORTANT: By default, anti-aliased lines are turned OFF."); + ImGui::Indent(); + ImGui::BulletText("Software AA can be enabled per plot with ImPlotFlags_AntiAliased."); + ImGui::BulletText("AA for demo plots can be enabled from the plot's context menu."); + ImGui::BulletText("If allowable, you are better off using hardware AA (e.g. MSAA)."); + ImGui::Unindent(); #ifdef IMPLOT_DEMO_USE_DOUBLE ImGui::BulletText("The demo data precision is: double"); #else @@ -831,18 +837,37 @@ void ShowDemoWindow(bool* p_open) { } } //------------------------------------------------------------------------- - if (ImGui::CollapsingHeader("Offset Data")) { - t_float xs[50], ys[50]; - for (int i = 0; i < 50; ++i) { - xs[i] = 0.5f + 0.4f * Cos(i/50.f * 6.28f); - ys[i] = 0.5f + 0.4f * Sin(i/50.f * 6.28f); + if (ImGui::CollapsingHeader("Offset and Stride")) { + static const int k_circles = 11; + static const int k_points_per = 50; + static const int k_size = 2 * k_points_per * k_circles; + static t_float interleaved_data[k_size]; + for (int p = 0; p < k_points_per; ++p) { + for (int c = 0; c < k_circles; ++c) { + t_float r = (t_float)c / (k_circles - 1) * 0.2f + 0.2f; + interleaved_data[p*2*k_circles + 2*c + 0] = 0.5f + r * Cos((t_float)p/k_points_per * 6.28f); + interleaved_data[p*2*k_circles + 2*c + 1] = 0.5f + r * Sin((t_float)p/k_points_per * 6.28f); + } } static int offset = 0; - ImGui::SliderInt("Offset", &offset, -100, 100); - if (ImPlot::BeginPlot("##offset")) { - ImPlot::PlotLine("circle", xs, ys, 50, offset); + ImGui::BulletText("Offsetting is useful for realtime plots (see above) and circular buffers."); + ImGui::BulletText("Striding is useful for interleaved data (e.g. audio) or plotting structs."); + ImGui::BulletText("Here, all circle data is stored in a single interleaved buffer:"); + ImGui::BulletText("[c0.x0 c0.y0 ... cn.x0 cn.y0 c0.x1 c0.y1 ... cn.x1 cn.y1 ... cn.xm cn.ym]"); + ImGui::BulletText("The offset value indicates which circle point index is considered the first."); + ImGui::BulletText("Offsets can be negative and/or larger than the actual data count."); + ImGui::SliderInt("Offset", &offset, -2*k_points_per, 2*k_points_per); + if (ImPlot::BeginPlot("##strideoffset")) { + ImPlot::SetColormap(ImPlotColormap_Jet); + char buff[16]; + for (int c = 0; c < k_circles; ++c) { + sprintf(buff, "Circle %d", c); + ImPlot::PlotLine(buff, &interleaved_data[c*2 + 0], &interleaved_data[c*2 + 1], k_points_per, offset, 2*k_circles*sizeof(t_float)); + } ImPlot::EndPlot(); + ImPlot::SetColormap(ImPlotColormap_Default); } + // offset++; uncomment for animation! } //------------------------------------------------------------------------- if (ImGui::CollapsingHeader("Custom Ticks")) {