1
0
Fork 0
mirror of https://github.com/gwm17/implot.git synced 2024-11-23 02:38:53 -05:00

Merge pull request #41 from sergeyn/pr_branch

Fixes issues when using 16-bit indices. Slight performance gains. Refactors how offsetting data works in the implementation. Improves Offset and Stride demo.
This commit is contained in:
Evan Pezent 2020-06-07 13:18:52 -05:00 committed by GitHub
commit c0bea59c58
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 376 additions and 301 deletions

View File

@ -61,7 +61,6 @@ You can read releases logs https://github.com/epezent/implot/releases for more d
#include "implot.h" #include "implot.h"
#include "imgui_internal.h" #include "imgui_internal.h"
#ifdef _MSC_VER #ifdef _MSC_VER
#define sprintf sprintf_s #define sprintf sprintf_s
#endif #endif
@ -515,7 +514,6 @@ inline void FitPoint(const ImPlotPoint& p) {
inline void UpdateTransformCache() { inline void UpdateTransformCache() {
// get pixels for transforms // get pixels for transforms
for (int i = 0; i < MAX_Y_AXES; i++) { 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, 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, 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 // Transformer functors
struct TransformerLinLin { 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()(const ImPlotPoint& plt) { return (*this)(plt.x, plt.y); }
inline ImVec2 operator()(double x, double 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)), return ImVec2( (float)(gp.PixelRange[YAxis].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)) ); (float)(gp.PixelRange[YAxis].Min.y + gp.My[YAxis] * (y - gp.CurrentPlot->YAxis[YAxis].Range.Min)) );
} }
int y_axis; int YAxis;
}; };
struct TransformerLogLin { 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()(const ImPlotPoint& plt) { return (*this)(plt.x, plt.y); }
inline ImVec2 operator()(double x, double y) { inline ImVec2 operator()(double x, double y) {
double t = ImLog10(x / gp.CurrentPlot->XAxis.Range.Min) / gp.LogDenX; 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); 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)), return ImVec2( (float)(gp.PixelRange[YAxis].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)) ); (float)(gp.PixelRange[YAxis].Min.y + gp.My[YAxis] * (y - gp.CurrentPlot->YAxis[YAxis].Range.Min)) );
} }
int y_axis; int YAxis;
}; };
struct TransformerLinLog { 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()(const ImPlotPoint& plt) { return (*this)(plt.x, plt.y); }
inline ImVec2 operator()(double x, double y) { inline ImVec2 operator()(double x, double y) {
double t = ImLog10(y / gp.CurrentPlot->YAxis[y_axis].Range.Min) / gp.LogDenY[y_axis]; double t = ImLog10(y / gp.CurrentPlot->YAxis[YAxis].Range.Min) / gp.LogDenY[YAxis];
y = ImLerp(gp.CurrentPlot->YAxis[y_axis].Range.Min, gp.CurrentPlot->YAxis[y_axis].Range.Max, (float)t); y = ImLerp(gp.CurrentPlot->YAxis[YAxis].Range.Min, gp.CurrentPlot->YAxis[YAxis].Range.Max, (float)t);
return ImVec2( (float)(gp.PixelRange[y_axis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min)), return ImVec2( (float)(gp.PixelRange[YAxis].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)) ); (float)(gp.PixelRange[YAxis].Min.y + gp.My[YAxis] * (y - gp.CurrentPlot->YAxis[YAxis].Range.Min)) );
} }
int y_axis; int YAxis;
}; };
struct TransformerLogLog { 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()(const ImPlotPoint& plt) { return (*this)(plt.x, plt.y); }
inline ImVec2 operator()(double x, double y) { inline ImVec2 operator()(double x, double y) {
double t = ImLog10(x / gp.CurrentPlot->XAxis.Range.Min) / gp.LogDenX; 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); 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]; t = ImLog10(y / gp.CurrentPlot->YAxis[YAxis].Range.Min) / gp.LogDenY[YAxis];
y = ImLerp(gp.CurrentPlot->YAxis[y_axis].Range.Min, gp.CurrentPlot->YAxis[y_axis].Range.Max, (float)t); y = ImLerp(gp.CurrentPlot->YAxis[YAxis].Range.Min, gp.CurrentPlot->YAxis[YAxis].Range.Max, (float)t);
return ImVec2( (float)(gp.PixelRange[y_axis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min)), return ImVec2( (float)(gp.PixelRange[YAxis].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)) ); (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<ImPlotTick>& 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<ImPlotTick> &ticks, bool scientific, ImGuiTextBuffer& buffer) { inline void LabelTicks(ImVector<ImPlotTick> &ticks, bool scientific, ImGuiTextBuffer& buffer) {
char temp[32]; char temp[32];
for (int t = 0; t < ticks.Size; t++) { for (int t = 0; t < ticks.Size; t++) {
@ -749,19 +758,6 @@ inline void LabelTicks(ImVector<ImPlotTick> &ticks, bool scientific, ImGuiTextBu
} }
} }
inline void AddCustomTicks(const double* values, const char** labels, int n, ImVector<ImPlotTick>& 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<ImPlotTick>& ticks) { inline float MaxTickLabelWidth(ImVector<ImPlotTick>& ticks) {
float w = 0; float w = 0;
for (int i = 0; i < ticks.Size; ++i) 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 <typename Transformer, typename Getter> template <typename Transformer, typename Getter>
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) { 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) {
int idx = offset; for (int i = 0; i < getter.Count; ++i) {
for (int i = 0; i < count; ++i) { ImVec2 c = transformer(getter(i));
ImVec2 c;
c = transformer(getter(idx));
idx = (idx + 1) % count;
if (!cull || gp.BB_Plot.Contains(c)) { if (!cull || gp.BB_Plot.Contains(c)) {
// TODO: Optimize the loop and if statements, this is atrocious // TODO: Optimize the loop and if statements, this is atrocious
if (HasFlag(gp.Style.Marker, ImPlotMarker_Circle)) if (HasFlag(gp.Style.Marker, ImPlotMarker_Circle))
@ -2171,29 +2164,30 @@ int idx = offset;
} }
} }
inline void RenderLine(ImDrawList& DrawList, const ImVec2& p1, const ImVec2& p2, float line_weight, ImU32 col_line, ImVec2 uv) { struct LineRenderer {
// http://assemblyrequired.crashworks.org/timing-square-root/ 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 dx = p2.x - p1.x;
float dy = p2.y - p1.y; float dy = p2.y - p1.y;
IM_NORMALIZE2F_OVER_ZERO(dx, dy); IM_NORMALIZE2F_OVER_ZERO(dx, dy);
dx *= (line_weight * 0.5f); dx *= (Weight * 0.5f);
dy *= (line_weight * 0.5f); dy *= (Weight * 0.5f);
DrawList._VtxWritePtr[0].pos.x = p1.x + dy; DrawList._VtxWritePtr[0].pos.x = p1.x + dy;
DrawList._VtxWritePtr[0].pos.y = p1.y - dx; DrawList._VtxWritePtr[0].pos.y = p1.y - dx;
DrawList._VtxWritePtr[0].uv = uv; DrawList._VtxWritePtr[0].uv = uv;
DrawList._VtxWritePtr[0].col = col_line; DrawList._VtxWritePtr[0].col = Col;
DrawList._VtxWritePtr[1].pos.x = p2.x + dy; DrawList._VtxWritePtr[1].pos.x = p2.x + dy;
DrawList._VtxWritePtr[1].pos.y = p2.y - dx; DrawList._VtxWritePtr[1].pos.y = p2.y - dx;
DrawList._VtxWritePtr[1].uv = uv; DrawList._VtxWritePtr[1].uv = uv;
DrawList._VtxWritePtr[1].col = col_line; DrawList._VtxWritePtr[1].col = Col;
DrawList._VtxWritePtr[2].pos.x = p2.x - dy; DrawList._VtxWritePtr[2].pos.x = p2.x - dy;
DrawList._VtxWritePtr[2].pos.y = p2.y + dx; DrawList._VtxWritePtr[2].pos.y = p2.y + dx;
DrawList._VtxWritePtr[2].uv = uv; DrawList._VtxWritePtr[2].uv = uv;
DrawList._VtxWritePtr[2].col = col_line; DrawList._VtxWritePtr[2].col = Col;
DrawList._VtxWritePtr[3].pos.x = p1.x - dy; DrawList._VtxWritePtr[3].pos.x = p1.x - dy;
DrawList._VtxWritePtr[3].pos.y = p1.y + dx; DrawList._VtxWritePtr[3].pos.y = p1.y + dx;
DrawList._VtxWritePtr[3].uv = uv; DrawList._VtxWritePtr[3].uv = uv;
DrawList._VtxWritePtr[3].col = col_line; DrawList._VtxWritePtr[3].col = Col;
DrawList._VtxWritePtr += 4; DrawList._VtxWritePtr += 4;
DrawList._IdxWritePtr[0] = (ImDrawIdx)(DrawList._VtxCurrentIdx); DrawList._IdxWritePtr[0] = (ImDrawIdx)(DrawList._VtxCurrentIdx);
DrawList._IdxWritePtr[1] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 1); DrawList._IdxWritePtr[1] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 1);
@ -2203,54 +2197,33 @@ inline void RenderLine(ImDrawList& DrawList, const ImVec2& p1, const ImVec2& p2,
DrawList._IdxWritePtr[5] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 3); DrawList._IdxWritePtr[5] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 3);
DrawList._IdxWritePtr += 6; DrawList._IdxWritePtr += 6;
DrawList._VtxCurrentIdx += 4; 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) { struct FillRenderer {
DrawList._VtxWritePtr[0].pos.x = p1.x; FillRenderer(ImU32 col, float zero) { Col = col; Zero = zero; }
DrawList._VtxWritePtr[0].pos.y = p1.y; inline void render(ImDrawList& DrawList, const ImVec2& p1, const ImVec2& p2, ImVec2 uv) {
DrawList._VtxWritePtr[0].uv = uv; const int crosses_zero = (p1.y > Zero && p2.y < Zero) || (p1.y < Zero && p2.y > Zero); // could do y*y < 0 earlier on
DrawList._VtxWritePtr[0].col = col_ul; const float xmid = p1.x + (p2.x - p1.x) / (p2.y-p1.y) * (Zero - p1.y);
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;
}
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].pos = p1;
DrawList._VtxWritePtr[0].uv = uv; DrawList._VtxWritePtr[0].uv = uv;
DrawList._VtxWritePtr[0].col = col_fill; DrawList._VtxWritePtr[0].col = Col;
DrawList._VtxWritePtr[1].pos = p2; DrawList._VtxWritePtr[1].pos = p2;
DrawList._VtxWritePtr[1].uv = uv; DrawList._VtxWritePtr[1].uv = uv;
DrawList._VtxWritePtr[1].col = col_fill; DrawList._VtxWritePtr[1].col = Col;
DrawList._VtxWritePtr[2].pos = ImVec2(xmid, zero); DrawList._VtxWritePtr[2].pos = ImVec2(xmid, Zero);
DrawList._VtxWritePtr[2].uv = uv; DrawList._VtxWritePtr[2].uv = uv;
DrawList._VtxWritePtr[2].col = col_fill; DrawList._VtxWritePtr[2].col = Col;
DrawList._VtxWritePtr[3].pos = ImVec2(p1.x, zero); DrawList._VtxWritePtr[3].pos = ImVec2(p1.x, Zero);
DrawList._VtxWritePtr[3].uv = uv; DrawList._VtxWritePtr[3].uv = uv;
DrawList._VtxWritePtr[3].col = col_fill; DrawList._VtxWritePtr[3].col = Col;
DrawList._VtxWritePtr[4].pos = ImVec2(p2.x, zero);; DrawList._VtxWritePtr[4].pos = ImVec2(p2.x, Zero);;
DrawList._VtxWritePtr[4].uv = uv; DrawList._VtxWritePtr[4].uv = uv;
DrawList._VtxWritePtr[4].col = col_fill; DrawList._VtxWritePtr[4].col = Col;
DrawList._VtxWritePtr += 5; DrawList._VtxWritePtr += 5;
DrawList._IdxWritePtr[0] = (ImDrawIdx)(DrawList._VtxCurrentIdx); DrawList._IdxWritePtr[0] = (ImDrawIdx)(DrawList._VtxCurrentIdx);
DrawList._IdxWritePtr[1] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 1 + crosses_zero); DrawList._IdxWritePtr[1] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 1 + crosses_zero);
@ -2260,126 +2233,208 @@ inline void RenderFill(ImDrawList& DrawList, const ImVec2& p1, const ImVec2& p2,
DrawList._IdxWritePtr[5] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 4); DrawList._IdxWritePtr[5] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 4);
DrawList._IdxWritePtr += 6; DrawList._IdxWritePtr += 6;
DrawList._VtxCurrentIdx += 5; DrawList._VtxCurrentIdx += 5;
} }
ImU32 Col;
float Zero;
static const int IdxConsumed = 6;
static const int VtxConsumed = 5;
};
inline void RenderLineAA(ImDrawList& DrawList, const ImVec2& p1, const ImVec2& p2, float line_weight, ImU32 col_line) { struct RectRenderer {
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 <typename Getter, typename Transformer, typename Renderer>
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 <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, float line_weight, ImU32 col, 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));
if (HasFlag(gp.CurrentPlot->Flags, ImPlotFlags_AntiAliased)) { 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 p1 = transformer(getter(0));
ImVec2 p2 = transformer(getter(i1)); 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)))) 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; p1 = p2;
} }
} }
else { else {
const ImVec2 uv = DrawList._Data->TexUvWhitePixel; RenderPrimitives(getter, transformer, LineRenderer(col, line_weight), DrawList, cull);
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);
} }
} }
template <typename Getter, typename Transformer> template <typename Getter, typename Transformer>
inline void RenderLineFill(Getter getter, Transformer transformer, ImDrawList& DrawList, int count, int offset, ImU32 col_fill, bool cull) { inline void RenderLineFill(Getter getter, Transformer transformer, ImDrawList& DrawList, ImU32 col_fill) {
(void)cull; // TODO: Culling
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; float zero = transformer(0,0).y;
const ImVec2 uv = DrawList._Data->TexUvWhitePixel; RenderPrimitives(getter, transformer, FillRenderer(col_fill, zero), DrawList, false);
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
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
inline int PosMod(int l, int r) {
return (l % r + r) % r;
}
// template <typename T>
// inline T StrideIndex(const T* data, int idx, int stride) {
// return *(const T*)(const void*)((const unsigned char*)data + (size_t)idx * stride);
// }
template <typename T> template <typename T>
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); return *(const T*)(const void*)((const unsigned char*)data + (size_t)idx * stride);
} }
template <typename T> template <typename T>
struct GetterYs { 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; const T* Ys;
int Count;
int Offset;
int Stride; int Stride;
inline ImPlotPoint operator()(int idx) { inline ImPlotPoint operator()(int idx) {
return ImPlotPoint((T)idx, StrideIndex(Ys, idx, Stride)); return ImPlotPoint((T)idx, OffsetAndStride(Ys, idx, Count, Offset, Stride));
} }
}; };
template <typename T> template <typename T>
struct GetterXsYs { 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* Xs;
const T* Ys; const T* Ys;
int Count;
int Offset;
int Stride; int Stride;
inline ImPlotPoint operator()(int idx) { 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 { 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); } inline ImPlotPoint operator()(int idx) { return ImPlotPoint(Data[idx].x, Data[idx].y); }
const ImVec2* Data; const ImVec2* Data;
int Count;
int Offset;
}; };
struct GetterImPlotPoint { 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]; } inline ImPlotPoint operator()(int idx) { return Data[idx]; }
const ImPlotPoint* Data; const ImPlotPoint* Data;
int Count;
int Offset;
}; };
struct GetterFuncPtrImPlotPoint { struct GetterFuncPtrImPlotPoint {
GetterFuncPtrImPlotPoint(ImPlotPoint (*g)(void* data, int idx), void* d) { getter = g; data = d;} GetterFuncPtrImPlotPoint(ImPlotPoint (*g)(void* data, int idx), void* d, int count, int offset) {
inline ImPlotPoint operator()(int idx) { return getter(data, idx); } 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); ImPlotPoint (*getter)(void* data, int idx);
void* data; void* Data;
int Count;
int Offset;
}; };
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -2387,7 +2442,7 @@ struct GetterFuncPtrImPlotPoint {
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template <typename Getter> template <typename Getter>
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()!"); 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 // find data extents
if (gp.FitThisFrame) { if (gp.FitThisFrame) {
for (int i = 0; i < count; ++i) { for (int i = 0; i < getter.Count; ++i) {
ImPlotPoint p = getter(i); ImPlotPoint p = getter(i);
FitPoint(p); FitPoint(p);
} }
if (rend_fill) { if (rend_fill) {
ImPlotPoint p1 = getter(0); ImPlotPoint p1 = getter(0);
ImPlotPoint p2 = getter(count - 1); ImPlotPoint p2 = getter(getter.Count - 1);
p1.y = 0; p2.y = 0; p1.y = 0; p2.y = 0;
FitPoint(p1); FitPoint(p2); FitPoint(p1); FitPoint(p2);
} }
} }
PushPlotClipRect(); PushPlotClipRect();
// render fill // render fill
if (count > 1 && rend_fill) { if (getter.Count > 1 && rend_fill) {
const ImU32 col_fill = ImGui::GetColorU32(gp.Style.Colors[ImPlotCol_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)) 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)) 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)) 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 else
RenderLineFill(getter, TransformerLinLin(y_axis), DrawList, count, offset, col_fill, cull); RenderLineFill(getter, TransformerLinLin(y_axis), DrawList, col_fill);
} }
// render line // 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; 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, line_weight, col_line, cull);
else if (HasFlag(plot->XAxis.Flags, ImPlotAxisFlags_LogScale)) 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)) 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 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 // render markers
if (gp.Style.Marker != ImPlotMarker_None) { 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_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]); 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, 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))
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)) 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 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(); PopPlotClipRect();
} }
@ -2469,18 +2524,18 @@ inline void PlotEx(const char* label_id, Getter getter, int count, int offset)
// float // float
void PlotLine(const char* label_id, const float* values, int count, int offset, int stride) { void PlotLine(const char* label_id, const float* values, int count, int offset, int stride) {
GetterYs<float> getter(values,stride); GetterYs<float> getter(values,count,offset,stride);
PlotEx(label_id, getter, count, offset); PlotEx(label_id, getter);
} }
void PlotLine(const char* label_id, const float* xs, const float* ys, int count, int offset, int stride) { void PlotLine(const char* label_id, const float* xs, const float* ys, int count, int offset, int stride) {
GetterXsYs<float> getter(xs,ys,stride); GetterXsYs<float> getter(xs,ys,count,offset,stride);
return PlotEx(label_id, getter, count, offset); return PlotEx(label_id, getter);
} }
void PlotLine(const char* label_id, const ImVec2* data, int count, int offset) { void PlotLine(const char* label_id, const ImVec2* data, int count, int offset) {
GetterImVec2 getter(data); GetterImVec2 getter(data, count, offset);
return PlotEx(label_id, getter, 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 // double
void PlotLine(const char* label_id, const double* values, int count, int offset, int stride) { void PlotLine(const char* label_id, const double* values, int count, int offset, int stride) {
GetterYs<double> getter(values,stride); GetterYs<double> getter(values,count,offset,stride);
PlotEx(label_id, getter, count, offset); PlotEx(label_id, getter);
} }
void PlotLine(const char* label_id, const double* xs, const double* ys, int count, int offset, int stride) { void PlotLine(const char* label_id, const double* xs, const double* ys, int count, int offset, int stride) {
GetterXsYs<double> getter(xs,ys,stride); GetterXsYs<double> getter(xs,ys,count,offset,stride);
return PlotEx(label_id, getter, count, offset); return PlotEx(label_id, getter);
} }
void PlotLine(const char* label_id, const ImPlotPoint* data, int count, int offset) { void PlotLine(const char* label_id, const ImPlotPoint* data, int count, int offset) {
GetterImPlotPoint getter(data); GetterImPlotPoint getter(data, count, offset);
return PlotEx(label_id, getter, count, offset); return PlotEx(label_id, getter);
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// custom // custom
void PlotLine(const char* label_id, ImPlotPoint (*getter_func)(void* data, int idx), void* data, int count, int offset) { void PlotLine(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 PlotEx(label_id, getter, 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 // PLOT BAR V
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// TODO: Migrate to RenderPrimitives
template <typename T> template <typename T>
struct GetterBarV { struct GetterBarV {
const T* Ys; T XShift; int Stride; const T* Ys; T XShift; int Count; int Offset; int Stride;
GetterBarV(const T* ys, T xshift, int stride) { Ys = ys; XShift = xshift; Stride = 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, StrideIndex(Ys, idx, Stride)); } inline ImPlotPoint operator()(int idx) { return ImPlotPoint((T)idx + XShift, OffsetAndStride(Ys, idx, Count, Offset, Stride)); }
}; };
template <typename T> template <typename T>
struct GetterBarH { struct GetterBarH {
const T* Xs; T YShift; int Stride; const T* Xs; T YShift; int Count; int Offset; int Stride;
GetterBarH(const T* xs, T yshift, int stride) { Xs = xs; YShift = yshift; Stride = 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(StrideIndex(Xs, idx, Stride), (T)idx + YShift); } inline ImPlotPoint operator()(int idx) { return ImPlotPoint(OffsetAndStride(Xs, idx, Count, Offset, Stride), (T)idx + YShift); }
}; };
template <typename Getter, typename TWidth> template <typename Getter, typename TWidth>
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()!"); 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 // find data extents
if (gp.FitThisFrame) { if (gp.FitThisFrame) {
for (int i = 0; i < count; ++i) { for (int i = 0; i < getter.Count; ++i) {
ImPlotPoint p = getter(i); ImPlotPoint p = getter(i);
FitPoint(ImPlotPoint(p.x - half_width, p.y)); FitPoint(ImPlotPoint(p.x - half_width, p.y));
FitPoint(ImPlotPoint(p.x + half_width, 0)); FitPoint(ImPlotPoint(p.x + half_width, 0));
} }
} }
int idx = offset; for (int i = 0; i < getter.Count; ++i) {
for (int i = 0; i < count; ++i) { ImPlotPoint p = getter(i);
ImPlotPoint p = getter(idx);
idx = (idx + 1) % count;
if (p.y == 0) if (p.y == 0)
continue; continue;
ImVec2 a = PlotToPixels(p.x - half_width, p.y); 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 // float
void PlotBars(const char* label_id, const float* values, int count, float width, float shift, int offset, int stride) { void PlotBars(const char* label_id, const float* values, int count, float width, float shift, int offset, int stride) {
GetterBarV<float> getter(values,shift,stride); GetterBarV<float> getter(values,shift,count,offset,stride);
PlotBarsEx(label_id, getter, count, width, offset); 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) { void PlotBars(const char* label_id, const float* xs, const float* ys, int count, float width, int offset, int stride) {
GetterXsYs<float> getter(xs,ys,stride); GetterXsYs<float> getter(xs,ys,count,offset,stride);
PlotBarsEx(label_id, getter, count, width, offset); PlotBarsEx(label_id, getter, width);
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// double // double
void PlotBars(const char* label_id, const double* values, int count, double width, double shift, int offset, int stride) { void PlotBars(const char* label_id, const double* values, int count, double width, double shift, int offset, int stride) {
GetterBarV<double> getter(values,shift,stride); GetterBarV<double> getter(values,shift,count,offset,stride);
PlotBarsEx(label_id, getter, count, width, offset); 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) { void PlotBars(const char* label_id, const double* xs, const double* ys, int count, double width, int offset, int stride) {
GetterXsYs<double> getter(xs,ys,stride); GetterXsYs<double> getter(xs,ys,count,offset,stride);
PlotBarsEx(label_id, getter, count, width, offset); PlotBarsEx(label_id, getter, width);
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// custom // custom
void PlotBars(const char* label_id, ImPlotPoint (*getter_func)(void* data, int idx), void* data, int count, double width, int offset) { 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); GetterFuncPtrImPlotPoint getter(getter_func, data, count, offset);
PlotBarsEx(label_id, getter, count, width, offset); PlotBarsEx(label_id, getter, width);
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// PLOT BAR H // PLOT BAR H
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// TODO: Migrate to RenderPrimitives
template <typename Getter, typename THeight> template <typename Getter, typename THeight>
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()!"); 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 // find data extents
if (gp.FitThisFrame) { if (gp.FitThisFrame) {
for (int i = 0; i < count; ++i) { for (int i = 0; i < getter.Count; ++i) {
ImPlotPoint p = getter(i); ImPlotPoint p = getter(i);
FitPoint(ImPlotPoint(0, p.y - half_height)); FitPoint(ImPlotPoint(0, p.y - half_height));
FitPoint(ImPlotPoint(p.x, p.y + half_height)); FitPoint(ImPlotPoint(p.x, p.y + half_height));
} }
} }
int idx = offset; for (int i = 0; i < getter.Count; ++i) {
for (int i = 0; i < count; ++i) { ImPlotPoint p = getter(i);
ImPlotPoint p = getter(idx);
idx = (idx + 1) % count;
if (p.x == 0) if (p.x == 0)
continue; continue;
ImVec2 a = PlotToPixels(0, p.y - half_height); 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 // float
void PlotBarsH(const char* label_id, const float* values, int count, float height, float shift, int offset, int stride) { void PlotBarsH(const char* label_id, const float* values, int count, float height, float shift, int offset, int stride) {
GetterBarH<float> getter(values,shift,stride); GetterBarH<float> getter(values,shift,count,offset,stride);
PlotBarsHEx(label_id, getter, count, height, offset); 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) { void PlotBarsH(const char* label_id, const float* xs, const float* ys, int count, float height, int offset, int stride) {
GetterXsYs<float> getter(xs,ys,stride); GetterXsYs<float> getter(xs,ys,count,offset,stride);
PlotBarsHEx(label_id, getter, count, height, offset); PlotBarsHEx(label_id, getter, height);
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// double // double
void PlotBarsH(const char* label_id, const double* values, int count, double height, double shift, int offset, int stride) { void PlotBarsH(const char* label_id, const double* values, int count, double height, double shift, int offset, int stride) {
GetterBarH<double> getter(values,shift,stride); GetterBarH<double> getter(values,shift,count,offset,stride);
PlotBarsHEx(label_id, getter, count, height, offset); 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) { void PlotBarsH(const char* label_id, const double* xs, const double* ys, int count, double height, int offset, int stride) {
GetterXsYs<double> getter(xs,ys,stride); GetterXsYs<double> getter(xs,ys,count,offset,stride);
PlotBarsHEx(label_id, getter, count, height, offset); PlotBarsHEx(label_id, getter, height);
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// custom // custom
void PlotBarsH(const char* label_id, ImPlotPoint (*getter_func)(void* data, int idx), void* data, int count, double height, int offset) { 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); GetterFuncPtrImPlotPoint getter(getter_func, data, count, offset);
PlotBarsHEx(label_id, getter, count, height, offset); PlotBarsHEx(label_id, getter, height);
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -2783,20 +2838,20 @@ struct ImPlotPointError {
template <typename T> template <typename T>
struct GetterError { struct GetterError {
const T* Xs; const T* Ys; const T* Neg; const T* Pos; int 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 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; Stride = stride; Xs = xs; Ys = ys; Neg = neg; Pos = pos; Count = count; Offset = offset; Stride = stride;
} }
ImPlotPointError operator()(int idx) { ImPlotPointError operator()(int idx) {
return ImPlotPointError(StrideIndex(Xs, idx, Stride), return ImPlotPointError(OffsetAndStride(Xs, idx, Count, Offset, Stride),
StrideIndex(Ys, idx, Stride), OffsetAndStride(Ys, idx, Count, Offset, Stride),
StrideIndex(Neg, idx, Stride), OffsetAndStride(Neg, idx, Count, Offset, Stride),
StrideIndex(Pos, idx, Stride)); OffsetAndStride(Pos, idx, Count, Offset, Stride));
} }
}; };
template <typename Getter> template <typename Getter>
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()!"); IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PlotErrorBars() needs to be called between BeginPlot() and EndPlot()!");
ImGuiID id = ImGui::GetID(label_id); 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 // find data extents
if (gp.FitThisFrame) { if (gp.FitThisFrame) {
for (int i = 0; i < count; ++i) { for (int i = 0; i < getter.Count; ++i) {
ImPlotPointError e = getter(i); ImPlotPointError e = getter(i);
FitPoint(ImPlotPoint(e.x , e.y - e.neg)); FitPoint(ImPlotPoint(e.x , e.y - e.neg));
FitPoint(ImPlotPoint(e.x , e.y + e.pos )); FitPoint(ImPlotPoint(e.x , e.y + e.pos ));
} }
} }
int idx = offset; for (int i = 0; i < getter.Count; ++i) {
for (int i = 0; i < count; ++i) { ImPlotPointError e = getter(i);
ImPlotPointError e = getter(idx);
idx = (idx + 1) % count;
ImVec2 p1 = PlotToPixels(e.x, e.y - e.neg); ImVec2 p1 = PlotToPixels(e.x, e.y - e.neg);
ImVec2 p2 = PlotToPixels(e.x, e.y + e.pos); ImVec2 p2 = PlotToPixels(e.x, e.y + e.pos);
DrawList.AddLine(p1,p2,col, gp.Style.ErrorBarWeight); 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 // float
void PlotErrorBars(const char* label_id, const float* xs, const float* ys, const float* err, int count, int offset, int stride) { void PlotErrorBars(const char* label_id, const float* xs, const float* ys, const float* err, int count, int offset, int stride) {
GetterError<float> getter(xs, ys, err, err, stride); GetterError<float> getter(xs, ys, err, err, count, offset, stride);
PlotErrorBarsEx(label_id, getter, count, offset); 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) { 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<float> getter(xs, ys, neg, pos, stride); GetterError<float> getter(xs, ys, neg, pos, count, offset, stride);
PlotErrorBarsEx(label_id, getter, count, offset); PlotErrorBarsEx(label_id, getter);
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// double // double
void PlotErrorBars(const char* label_id, const double* xs, const double* ys, const double* err, int count, int offset, int stride) { void PlotErrorBars(const char* label_id, const double* xs, const double* ys, const double* err, int count, int offset, int stride) {
GetterError<double> getter(xs, ys, err, err, stride); GetterError<double> getter(xs, ys, err, err, count, offset, stride);
PlotErrorBarsEx(label_id, getter, count, offset); 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) { 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<double> getter(xs, ys, neg, pos, stride); GetterError<double> getter(xs, ys, neg, pos, count, offset, stride);
PlotErrorBarsEx(label_id, getter, count, offset); 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 w = (bounds_max.x - bounds_min.x) / cols;
const double h = (bounds_max.y - bounds_min.y) / rows; const double h = (bounds_max.y - bounds_min.y) / rows;
const ImPlotPoint half_size(w*0.5,h*0.5); const ImPlotPoint half_size(w*0.5,h*0.5);
const int n = rows * cols;
int i = 0; int i = 0;
DrawList.PrimReserve(6*n, 4*n);
const ImVec2 uv = DrawList._Data->TexUvWhitePixel;
for (int r = 0; r < rows; ++r) { for (int r = 0; r < rows; ++r) {
for (int c = 0; c < cols; ++c) { for (int c = 0; c < cols; ++c) {
ImPlotPoint p; 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)); float t = (float)Remap(values[i], scale_min, scale_max, T(0), T(1));
ImVec4 color = LerpColormap(t); ImVec4 color = LerpColormap(t);
ImU32 col = ImGui::GetColorU32(color); ImU32 col = ImGui::GetColorU32(color);
RenderRect(DrawList, a, b, col, col, col, col, uv); DrawList.AddRectFilled(a, b, col);
i++; i++;
} }
} }
@ -3112,7 +3162,7 @@ inline void PlotDigitalEx(const char* label_id, Getter getter, int count, int of
// float // float
void PlotDigital(const char* label_id, const float* xs, const float* ys, int count, int offset, int stride) { void PlotDigital(const char* label_id, const float* xs, const float* ys, int count, int offset, int stride) {
GetterXsYs<float> getter(xs,ys,stride); GetterXsYs<float> getter(xs,ys,count,offset,stride);
return PlotDigitalEx(label_id, getter, count, offset); 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 // double
void PlotDigital(const char* label_id, const double* xs, const double* ys, int count, int offset, int stride) { void PlotDigital(const char* label_id, const double* xs, const double* ys, int count, int offset, int stride) {
GetterXsYs<double> getter(xs,ys,stride); GetterXsYs<double> getter(xs,ys,count,offset,stride);
return PlotDigitalEx(label_id, getter, count, offset); 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 // custom
void PlotDigital(const char* label_id, ImPlotPoint (*getter_func)(void* data, int idx), void* data, int count, int offset) { 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); return PlotDigitalEx(label_id, getter, count, offset);
} }

View File

@ -160,6 +160,12 @@ void ShowDemoWindow(bool* p_open) {
ImGui::Unindent(); ImGui::Unindent();
ImGui::BulletText("Double right click to open the plot context menu."); ImGui::BulletText("Double right click to open the plot context menu.");
ImGui::BulletText("Click legend label icons to show/hide plot items."); 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 #ifdef IMPLOT_DEMO_USE_DOUBLE
ImGui::BulletText("The demo data precision is: double"); ImGui::BulletText("The demo data precision is: double");
#else #else
@ -831,18 +837,37 @@ void ShowDemoWindow(bool* p_open) {
} }
} }
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
if (ImGui::CollapsingHeader("Offset Data")) { if (ImGui::CollapsingHeader("Offset and Stride")) {
t_float xs[50], ys[50]; static const int k_circles = 11;
for (int i = 0; i < 50; ++i) { static const int k_points_per = 50;
xs[i] = 0.5f + 0.4f * Cos(i/50.f * 6.28f); static const int k_size = 2 * k_points_per * k_circles;
ys[i] = 0.5f + 0.4f * Sin(i/50.f * 6.28f); 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; static int offset = 0;
ImGui::SliderInt("Offset", &offset, -100, 100); ImGui::BulletText("Offsetting is useful for realtime plots (see above) and circular buffers.");
if (ImPlot::BeginPlot("##offset")) { ImGui::BulletText("Striding is useful for interleaved data (e.g. audio) or plotting structs.");
ImPlot::PlotLine("circle", xs, ys, 50, offset); ImGui::BulletText("Here, all circle data is stored in a single interleaved buffer:");
ImPlot::EndPlot(); 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")) { if (ImGui::CollapsingHeader("Custom Ticks")) {