diff options
Diffstat (limited to '3rdparty/implot/implot_items.cpp')
-rw-r--r-- | 3rdparty/implot/implot_items.cpp | 952 |
1 files changed, 564 insertions, 388 deletions
diff --git a/3rdparty/implot/implot_items.cpp b/3rdparty/implot/implot_items.cpp index 9f94492..ae750c9 100644 --- a/3rdparty/implot/implot_items.cpp +++ b/3rdparty/implot/implot_items.cpp @@ -20,29 +20,44 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -// ImPlot v0.10 WIP +// ImPlot v0.13 WIP #include "implot.h" #include "implot_internal.h" -#ifdef _MSC_VER -#define sprintf sprintf_s -#endif - #define SQRT_1_2 0.70710678118f #define SQRT_3_2 0.86602540378f -#define IMPLOT_NORMALIZE2F_OVER_ZERO(VX, VY) \ - { \ - float d2 = VX * VX + VY * VY; \ - if (d2 > 0.0f) { \ - float inv_len = 1.0f / ImSqrt(d2); \ - VX *= inv_len; \ - VY *= inv_len; \ - } \ - } +#ifndef IMPLOT_NO_FORCE_INLINE + #ifdef _MSC_VER + #define IMPLOT_INLINE __forceinline + #elif defined(__GNUC__) + #define IMPLOT_INLINE inline __attribute__((__always_inline__)) + #elif defined(__CLANG__) + #if __has_attribute(__always_inline__) + #define IMPLOT_INLINE inline __attribute__((__always_inline__)) + #else + #define IMPLOT_INLINE inline + #endif + #else + #define IMPLOT_INLINE inline + #endif +#else + #define IMPLOT_INLINE inline +#endif + +#if defined __SSE__ || defined __x86_64__ || defined _M_X64 +#ifndef IMGUI_ENABLE_SSE +#include <immintrin.h> +#endif +static IMPLOT_INLINE float ImInvSqrt(float x) { return _mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ss(x))); } +#else +static IMPLOT_INLINE float ImInvSqrt(float x) { return 1.0f / sqrtf(x); } +#endif -// Support for pre-1.82 version. Users on 1.82+ can use 0 (default) flags to mean "all corners" but in order to support older versions we are more explicit. +#define IMPLOT_NORMALIZE2F_OVER_ZERO(VX,VY) do { float d2 = VX*VX + VY*VY; if (d2 > 0.0f) { float inv_len = ImInvSqrt(d2); VX *= inv_len; VY *= inv_len; } } while (0) + +// Support for pre-1.82 versions. Users on 1.82+ can use 0 (default) flags to mean "all corners" but in order to support older versions we are more explicit. #if (IMGUI_VERSION_NUM < 18102) && !defined(ImDrawFlags_RoundCornersAll) #define ImDrawFlags_RoundCornersAll ImDrawCornerFlags_All #endif @@ -50,37 +65,50 @@ namespace ImPlot { //----------------------------------------------------------------------------- +// Utils +//----------------------------------------------------------------------------- + +// Calc maximum index size of ImDrawIdx +template <typename T> +struct MaxIdx { static const unsigned int Value; }; +template <> const unsigned int MaxIdx<unsigned short>::Value = 65535; +template <> const unsigned int MaxIdx<unsigned int>::Value = 4294967295; + +//----------------------------------------------------------------------------- // Item Utils //----------------------------------------------------------------------------- ImPlotItem* RegisterOrGetItem(const char* label_id, bool* just_created) { ImPlotContext& gp = *GImPlot; - ImGuiID id = ImGui::GetID(label_id); + ImPlotItemGroup& Items = *gp.CurrentItems; + ImGuiID id = Items.GetItemID(label_id); if (just_created != NULL) - *just_created = gp.CurrentPlot->Items.GetByKey(id) == NULL; - ImPlotItem* item = gp.CurrentPlot->Items.GetOrAddByKey(id); + *just_created = Items.GetItem(id) == NULL; + ImPlotItem* item = Items.GetOrAddItem(id); if (item->SeenThisFrame) return item; item->SeenThisFrame = true; - int idx = gp.CurrentPlot->Items.GetIndex(item); + int idx = Items.GetItemIndex(item); item->ID = id; if (ImGui::FindRenderedTextEnd(label_id, NULL) != label_id) { - gp.CurrentPlot->LegendData.Indices.push_back(idx); - item->NameOffset = gp.CurrentPlot->LegendData.Labels.size(); - gp.CurrentPlot->LegendData.Labels.append(label_id, label_id + strlen(label_id) + 1); + Items.Legend.Indices.push_back(idx); + item->NameOffset = Items.Legend.Labels.size(); + Items.Legend.Labels.append(label_id, label_id + strlen(label_id) + 1); } else { item->Show = true; } - if (item->Show) - gp.VisibleItemCount++; return item; } ImPlotItem* GetItem(const char* label_id) { ImPlotContext& gp = *GImPlot; - ImGuiID id = ImGui::GetID(label_id); - return gp.CurrentPlot->Items.GetByKey(id); + return gp.CurrentItems->GetItem(label_id); +} + +bool IsItemHidden(const char* label_id) { + ImPlotItem* item = GetItem(label_id); + return item != NULL && !item->Show; } ImPlotItem* GetCurrentItem() { @@ -123,20 +151,15 @@ ImVec4 GetLastItemColor() { return ImVec4(); } -void HideNextItem(bool hidden, ImGuiCond cond) { - ImPlotContext& gp = *GImPlot; - gp.NextItemData.HasHidden = true; - gp.NextItemData.Hidden = hidden; - gp.NextItemData.HiddenCond = cond; -} - void BustItemCache() { ImPlotContext& gp = *GImPlot; - for (int p = 0; p < gp.Plots.GetSize(); ++p) { + for (int p = 0; p < gp.Plots.GetBufSize(); ++p) { ImPlotPlot& plot = *gp.Plots.GetByIndex(p); - plot.ColormapIdx = 0; - plot.Items.Clear(); - plot.LegendData.Reset(); + plot.Items.Reset(); + } + for (int p = 0; p < gp.Subplots.GetBufSize(); ++p) { + ImPlotSubplot& subplot = *gp.Subplots.GetByIndex(p); + subplot.Items.Reset(); } } @@ -146,12 +169,15 @@ void BustColorCache(const char* plot_title_id) { BustItemCache(); } else { - ImPlotPlot* plot = gp.Plots.GetByKey(ImGui::GetCurrentWindow()->GetID(plot_title_id)); - if (plot == NULL) - return; - plot->ColormapIdx = 0; - plot->Items.Clear(); - plot->LegendData.Reset(); + ImGuiID id = ImGui::GetCurrentWindow()->GetID(plot_title_id); + ImPlotPlot* plot = gp.Plots.GetByKey(id); + if (plot != NULL) + plot->Items.Reset(); + else { + ImPlotSubplot* subplot = gp.Subplots.GetByKey(id); + if (subplot != NULL) + subplot->Items.Reset(); + } } } @@ -159,10 +185,15 @@ void BustColorCache(const char* plot_title_id) { // Begin/EndItem //----------------------------------------------------------------------------- +static const float ITEM_HIGHLIGHT_LINE_SCALE = 2.0f; +static const float ITEM_HIGHLIGHT_MARK_SCALE = 1.25f; + + // Begins a new item. Returns false if the item should not be plotted. bool BeginItem(const char* label_id, ImPlotCol recolor_from) { ImPlotContext& gp = *GImPlot; IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PlotX() needs to be called between BeginPlot() and EndPlot()!"); + SetupLock(); bool just_created; ImPlotItem* item = RegisterOrGetItem(label_id, &just_created); // set current item @@ -212,12 +243,21 @@ bool BeginItem(const char* label_id, ImPlotCol recolor_from) { s.DigitalBitGap = s.DigitalBitGap < 0 ? gp.Style.DigitalBitGap : s.DigitalBitGap; // apply alpha modifier(s) s.Colors[ImPlotCol_Fill].w *= s.FillAlpha; - // s.Colors[ImPlotCol_MarkerFill].w *= s.FillAlpha; // TODO: this should be separate, if it at all + s.Colors[ImPlotCol_MarkerFill].w *= s.FillAlpha; // TODO: this should be separate, if it at all // apply highlight mods - if (item->LegendHovered && !ImHasFlag(gp.CurrentPlot->Flags, ImPlotFlags_NoHighlight)) { - s.LineWeight *= 2; - s.MarkerWeight *= 2; - // TODO: highlight fills? + if (item->LegendHovered) { + if (!ImHasFlag(gp.CurrentItems->Legend.Flags, ImPlotLegendFlags_NoHighlightItem)) { + s.LineWeight *= ITEM_HIGHLIGHT_LINE_SCALE; + s.MarkerSize *= ITEM_HIGHLIGHT_MARK_SCALE; + s.MarkerWeight *= ITEM_HIGHLIGHT_LINE_SCALE; + // TODO: how to highlight fills? + } + if (!ImHasFlag(gp.CurrentItems->Legend.Flags, ImPlotLegendFlags_NoHighlightAxis)) { + if (gp.CurrentPlot->EnabledAxesX() > 1) + gp.CurrentPlot->Axes[gp.CurrentPlot->CurrentX].ColorHiLi = item->Color; + if (gp.CurrentPlot->EnabledAxesY() > 1) + gp.CurrentPlot->Axes[gp.CurrentPlot->CurrentY].ColorHiLi = item->Color; + } } // set render flags s.RenderLine = s.Colors[ImPlotCol_Line].w > 0 && s.LineWeight > 0; @@ -243,141 +283,133 @@ void EndItem() { } //----------------------------------------------------------------------------- +// INDEXERS +//----------------------------------------------------------------------------- + +// Offsets and strides a data buffer +template <typename T> +IMPLOT_INLINE T IndexData(const T* data, int idx, int count, int offset, int stride) { + const int s = ((offset == 0) << 0) | ((stride == sizeof(T)) << 1); + switch (s) { + case 3 : return data[idx]; + case 2 : return data[(offset + idx) % count]; + case 1 : return *(const T*)(const void*)((const unsigned char*)data + (size_t)((idx) ) * stride); + case 0 : return *(const T*)(const void*)((const unsigned char*)data + (size_t)((offset + idx) % count) * stride); + default: return T(0); + } +} + +//----------------------------------------------------------------------------- // GETTERS //----------------------------------------------------------------------------- // Getters can be thought of as iterators that convert user data (e.g. raw arrays) // to ImPlotPoints -// Interprets an array of Y points as ImPlotPoints where the X value is the index template <typename T> -struct GetterYs { - GetterYs(const T* ys, int count, double xscale, double x0, int offset, int stride) : - Ys(ys), +struct GetterIdx { + GetterIdx(const T* data, int count, int offset = 0, int stride = sizeof(T)) : + Data(data), Count(count), - XScale(xscale), - X0(x0), Offset(count ? ImPosMod(offset, count) : 0), Stride(stride) { } - inline ImPlotPoint operator()(int idx) const { - return ImPlotPoint(X0 + XScale * idx, (double)OffsetAndStride(Ys, idx, Count, Offset, Stride)); + template <typename I> IMPLOT_INLINE double operator()(I idx) const { + return (double)IndexData(Data, idx, Count, Offset, Stride); } - const T* const Ys; - const int Count; - const double XScale; - const double X0; - const int Offset; - const int Stride; + const T* Data; + int Count; + int Offset; + int Stride; }; -// Interprets separate arrays for X and Y points as ImPlotPoints -template <typename T> -struct GetterXsYs { - GetterXsYs(const T* xs, const T* ys, int count, int offset, int stride) : - Xs(xs), - Ys(ys), - Count(count), - Offset(count ? ImPosMod(offset, count) : 0), - Stride(stride) - { } - inline ImPlotPoint operator()(int idx) const { - return ImPlotPoint((double)OffsetAndStride(Xs, idx, Count, Offset, Stride), (double)OffsetAndStride(Ys, idx, Count, Offset, Stride)); +struct GetterLin { + GetterLin(double m, double b) : M(m), B(b) { } + template <typename I> IMPLOT_INLINE double operator()(I idx) const { + return M * idx + B; } - const T* const Xs; - const T* const Ys; - const int Count; - const int Offset; - const int Stride; + const double M; + const double B; }; -// Always returns a constant Y reference value where the X value is the index -struct GetterYRef { - GetterYRef(double y_ref, int count, double xscale, double x0) : - YRef(y_ref), - Count(count), - XScale(xscale), - X0(x0) - { } - inline ImPlotPoint operator()(int idx) const { - return ImPlotPoint(X0 + XScale*idx, YRef); - } - const double YRef; - const int Count; - const double XScale; - const double X0; +struct GetterRef { + GetterRef(double ref) : Ref(ref) { } + template <typename I> IMPLOT_INLINE double operator()(I) const { return Ref; } + const double Ref; }; -// Interprets an array of X points as ImPlotPoints where the Y value is a constant reference value -template <typename T> -struct GetterXsYRef { - GetterXsYRef(const T* xs, double y_ref, int count, int offset, int stride) : - Xs(xs), - YRef(y_ref), - Count(count), - Offset(count ? ImPosMod(offset, count) : 0), - Stride(stride) - { } - inline ImPlotPoint operator()(int idx) const { - return ImPlotPoint((double)OffsetAndStride(Xs, idx, Count, Offset, Stride), YRef); +template <typename TGetterX, typename TGetterY> +struct GetterXY { + GetterXY(TGetterX x, TGetterY y, int count) : GetterX(x), GetterY(y), Count(count) { } + template <typename I> IMPLOT_INLINE ImPlotPoint operator()(I idx) const { + return ImPlotPoint(GetterX(idx),GetterY(idx)); } - const T* const Xs; - const double YRef; + const TGetterX GetterX; + const TGetterY GetterY; const int Count; - const int Offset; - const int Stride; }; -// Interprets an array of Y points as ImPlotPoints where the X value is a constant reference value +// Interprets an array of Y points as ImPlotPoints where the X value is the index template <typename T> -struct GetterXRefYs { - GetterXRefYs(double x_ref, const T* ys, int count, int offset, int stride) : - XRef(x_ref), - Ys(ys), +struct GetterXs { + GetterXs(const T* xs, int count, double yscale, double y0, int offset, int stride) : + Xs(xs), Count(count), + YScale(yscale), + Y0(y0), Offset(count ? ImPosMod(offset, count) : 0), Stride(stride) { } - inline ImPlotPoint operator()(int idx) const { - return ImPlotPoint(XRef, (double)OffsetAndStride(Ys, idx, Count, Offset, Stride)); + template <typename I> IMPLOT_INLINE ImPlotPoint operator()(I idx) const { + return ImPlotPoint((double)IndexData(Xs, idx, Count, Offset, Stride), Y0 + YScale * idx); } - const double XRef; - const T* const Ys; + const T* const Xs; const int Count; + const double YScale; + const double Y0; const int Offset; const int Stride; }; /// Interprets a user's function pointer as ImPlotPoints struct GetterFuncPtr { - GetterFuncPtr(ImPlotPoint (*getter)(void* data, int idx), void* data, int count, int offset) : + GetterFuncPtr(ImPlotPoint (*getter)(void* data, int idx), void* data, int count) : Getter(getter), Data(data), - Count(count), - Offset(count ? ImPosMod(offset, count) : 0) + Count(count) { } - inline ImPlotPoint operator()(int idx) const { - idx = ImPosMod(Offset + idx, Count); + template <typename I> IMPLOT_INLINE ImPlotPoint operator()(I idx) const { return Getter(Data, idx); } ImPlotPoint (* const Getter)(void* data, int idx); void* const Data; const int Count; - const int Offset; }; -template <typename T> -struct GetterBarV { - const T* Ys; double XShift; int Count; int Offset; int Stride; - GetterBarV(const T* ys, double xshift, int count, int offset, int stride) { Ys = ys; XShift = xshift; Count = count; Offset = offset; Stride = stride; } - inline ImPlotPoint operator()(int idx) const { return ImPlotPoint((double)idx + (double)XShift, (double)OffsetAndStride(Ys, idx, Count, Offset, Stride)); } +template <typename TGetter> +struct GetterOverrideX { + GetterOverrideX(const TGetter& getter, double x) : Getter(getter), X(x), Count(getter.Count) { } + template <typename I> IMPLOT_INLINE ImPlotPoint operator()(I idx) const { + ImPlotPoint p = Getter(idx); + p.x = X; + return p; + } + const TGetter& Getter; + const double X; + const int Count; }; -template <typename T> -struct GetterBarH { - const T* Xs; double YShift; int Count; int Offset; int Stride; - GetterBarH(const T* xs, double yshift, int count, int offset, int stride) { Xs = xs; YShift = yshift; Count = count; Offset = offset; Stride = stride; } - inline ImPlotPoint operator()(int idx) const { return ImPlotPoint((double)OffsetAndStride(Xs, idx, Count, Offset, Stride), (double)idx + (double)YShift); } +template <typename TGetter> +struct GetterOverrideY { + GetterOverrideY(const TGetter& getter, double y) : Getter(getter), Y(y), Count(getter.Count) { } + template <typename I> IMPLOT_INLINE ImPlotPoint operator()(I idx) const { + ImPlotPoint p = Getter(idx); + p.y = Y; + return p; + } + const TGetter& Getter; + const double Y; + const int Count; }; template <typename T> @@ -391,11 +423,11 @@ struct GetterError { Offset(count ? ImPosMod(offset, count) : 0), Stride(stride) { } - inline ImPlotPointError operator()(int idx) const { - return ImPlotPointError((double)OffsetAndStride(Xs, idx, Count, Offset, Stride), - (double)OffsetAndStride(Ys, idx, Count, Offset, Stride), - (double)OffsetAndStride(Neg, idx, Count, Offset, Stride), - (double)OffsetAndStride(Pos, idx, Count, Offset, Stride)); + template <typename I> IMPLOT_INLINE ImPlotPointError operator()(I idx) const { + return ImPlotPointError((double)IndexData(Xs, idx, Count, Offset, Stride), + (double)IndexData(Ys, idx, Count, Offset, Stride), + (double)IndexData(Neg, idx, Count, Offset, Stride), + (double)IndexData(Pos, idx, Count, Offset, Stride)); } const T* const Xs; const T* const Ys; @@ -412,69 +444,71 @@ struct GetterError { // Transforms convert points in plot space (i.e. ImPlotPoint) to pixel space (i.e. ImVec2) -// Transforms points for linear x and linear y space -struct TransformerLinLin { - TransformerLinLin() : YAxis(GetCurrentYAxis()) {} - // inline ImVec2 operator()(const ImPlotPoint& plt) const { return (*this)(plt.x, plt.y); } - inline ImVec2 operator()(const ImPlotPoint& plt) const { - ImPlotContext& gp = *GImPlot; - return ImVec2( (float)(gp.PixelRange[YAxis].Min.x + gp.Mx * (plt.x - gp.CurrentPlot->XAxis.Range.Min)), - (float)(gp.PixelRange[YAxis].Min.y + gp.My[YAxis] * (plt.y - gp.CurrentPlot->YAxis[YAxis].Range.Min)) ); - } - const int YAxis; +struct TransformerLin { + TransformerLin(double pixMin, double pltMin, double, double m, double ) : PixMin(pixMin), PltMin(pltMin), M(m) { } + template <typename T> IMPLOT_INLINE float operator()(T p) const { return (float)(PixMin + M * (p - PltMin)); } + double PixMin, PltMin, M; }; -// Transforms points for log x and linear y space -struct TransformerLogLin { - TransformerLogLin() : YAxis(GetCurrentYAxis()) {} - inline ImVec2 operator()(const ImPlotPoint& plt) const { - ImPlotContext& gp = *GImPlot; - double t = ImLog10(plt.x / gp.CurrentPlot->XAxis.Range.Min) / gp.LogDenX; - double x = ImLerp(gp.CurrentPlot->XAxis.Range.Min, gp.CurrentPlot->XAxis.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] * (plt.y - gp.CurrentPlot->YAxis[YAxis].Range.Min)) ); +struct TransformerLog { + TransformerLog(double pixMin, double pltMin, double pltMax, double m, double den) : Den(den), PltMin(pltMin), PltMax(pltMax), PixMin(pixMin), M(m) { } + template <typename T> IMPLOT_INLINE float operator()(T p) const { + p = p <= 0.0 ? IMPLOT_LOG_ZERO : p; + double t = ImLog10(p / PltMin) / Den; + p = ImLerp(PltMin, PltMax, (float)t); + return (float)(PixMin + M * (p - PltMin)); } - const int YAxis; + double Den, PltMin, PltMax, PixMin, M; }; -// Transforms points for linear x and log y space -struct TransformerLinLog { - TransformerLinLog() : YAxis(GetCurrentYAxis()) {} - inline ImVec2 operator()(const ImPlotPoint& plt) const { - ImPlotContext& gp = *GImPlot; - double t = ImLog10(plt.y / gp.CurrentPlot->YAxis[YAxis].Range.Min) / gp.LogDenY[YAxis]; - double 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 * (plt.x - gp.CurrentPlot->XAxis.Range.Min)), - (float)(gp.PixelRange[YAxis].Min.y + gp.My[YAxis] * (y - gp.CurrentPlot->YAxis[YAxis].Range.Min)) ); - } - const int YAxis; -}; +template <typename TransformerX, typename TransformerY> +struct TransformerXY { + TransformerXY(const ImPlotAxis& x_axis, const ImPlotAxis& y_axis) : + Tx(x_axis.PixelMin, + x_axis.Range.Min, + x_axis.Range.Max, + x_axis.LinM, + x_axis.LogD), + Ty(y_axis.PixelMin, + y_axis.Range.Min, + y_axis.Range.Max, + y_axis.LinM, + y_axis.LogD) + { } -// Transforms points for log x and log y space -struct TransformerLogLog { - TransformerLogLog() : YAxis(GetCurrentYAxis()) {} - inline ImVec2 operator()(const ImPlotPoint& plt) const { - ImPlotContext& gp = *GImPlot; - double t = ImLog10(plt.x / gp.CurrentPlot->XAxis.Range.Min) / gp.LogDenX; - double x = ImLerp(gp.CurrentPlot->XAxis.Range.Min, gp.CurrentPlot->XAxis.Range.Max, (float)t); - t = ImLog10(plt.y / gp.CurrentPlot->YAxis[YAxis].Range.Min) / gp.LogDenY[YAxis]; - double 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)) ); + TransformerXY(const ImPlotPlot& plot) : + TransformerXY(plot.Axes[plot.CurrentX], plot.Axes[plot.CurrentY]) + { } + + TransformerXY() : + TransformerXY(*GImPlot->CurrentPlot) + { } + + template <typename P> IMPLOT_INLINE ImVec2 operator()(const P& plt) const { + ImVec2 out; + out.x = Tx(plt.x); + out.y = Ty(plt.y); + return out; } - const int YAxis; + TransformerX Tx; + TransformerY Ty; }; +typedef TransformerXY<TransformerLin,TransformerLin> TransformerLinLin; +typedef TransformerXY<TransformerLin,TransformerLog> TransformerLinLog; +typedef TransformerXY<TransformerLog,TransformerLin> TransformerLogLin; +typedef TransformerXY<TransformerLog,TransformerLog> TransformerLogLog; + //----------------------------------------------------------------------------- // PRIMITIVE RENDERERS //----------------------------------------------------------------------------- -inline void AddLine(const ImVec2& P1, const ImVec2& P2, float weight, ImU32 col, ImDrawList& DrawList, ImVec2 uv) { +IMPLOT_INLINE void PrimLine(const ImVec2& P1, const ImVec2& P2, float half_weight, ImU32 col, ImDrawList& DrawList, ImVec2 uv) { float dx = P2.x - P1.x; float dy = P2.y - P1.y; IMPLOT_NORMALIZE2F_OVER_ZERO(dx, dy); - dx *= (weight * 0.5f); - dy *= (weight * 0.5f); + dx *= half_weight; + dy *= half_weight; DrawList._VtxWritePtr[0].pos.x = P1.x + dy; DrawList._VtxWritePtr[0].pos.y = P1.y - dx; DrawList._VtxWritePtr[0].uv = uv; @@ -502,7 +536,7 @@ inline void AddLine(const ImVec2& P1, const ImVec2& P2, float weight, ImU32 col, DrawList._VtxCurrentIdx += 4; } -inline void AddRectFilled(const ImVec2& Pmin, const ImVec2& Pmax, ImU32 col, ImDrawList& DrawList, ImVec2 uv) { +IMPLOT_INLINE void PrimRectFilled(const ImVec2& Pmin, const ImVec2& Pmax, ImU32 col, ImDrawList& DrawList, ImVec2 uv) { DrawList._VtxWritePtr[0].pos = Pmin; DrawList._VtxWritePtr[0].uv = uv; DrawList._VtxWritePtr[0].col = col; @@ -530,22 +564,22 @@ inline void AddRectFilled(const ImVec2& Pmin, const ImVec2& Pmax, ImU32 col, ImD template <typename TGetter, typename TTransformer> struct LineStripRenderer { - inline LineStripRenderer(const TGetter& getter, const TTransformer& transformer, ImU32 col, float weight) : + IMPLOT_INLINE LineStripRenderer(const TGetter& getter, const TTransformer& transformer, ImU32 col, float weight) : Getter(getter), Transformer(transformer), Prims(Getter.Count - 1), Col(col), - Weight(weight) + HalfWeight(weight/2) { P1 = Transformer(Getter(0)); } - inline bool operator()(ImDrawList& DrawList, const ImRect& cull_rect, const ImVec2& uv, int prim) const { + IMPLOT_INLINE bool operator()(ImDrawList& DrawList, const ImRect& cull_rect, const ImVec2& uv, int prim) const { ImVec2 P2 = Transformer(Getter(prim + 1)); if (!cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2)))) { P1 = P2; return false; } - AddLine(P1,P2,Weight,Col,DrawList,uv); + PrimLine(P1,P2,HalfWeight,Col,DrawList,uv); P1 = P2; return true; } @@ -553,15 +587,43 @@ struct LineStripRenderer { const TTransformer& Transformer; const int Prims; const ImU32 Col; - const float Weight; + const float HalfWeight; mutable ImVec2 P1; static const int IdxConsumed = 6; static const int VtxConsumed = 4; }; +template <typename TGetter1, typename TGetter2, typename TTransformer> +struct LineSegmentsRenderer { + IMPLOT_INLINE LineSegmentsRenderer(const TGetter1& getter1, const TGetter2& getter2, const TTransformer& transformer, ImU32 col, float weight) : + Getter1(getter1), + Getter2(getter2), + Transformer(transformer), + Prims(ImMin(Getter1.Count, Getter2.Count)), + Col(col), + HalfWeight(weight/2) + {} + IMPLOT_INLINE bool operator()(ImDrawList& DrawList, const ImRect& cull_rect, const ImVec2& uv, int prim) const { + ImVec2 P1 = Transformer(Getter1(prim)); + ImVec2 P2 = Transformer(Getter2(prim)); + if (!cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2)))) + return false; + PrimLine(P1,P2,HalfWeight,Col,DrawList,uv); + return true; + } + const TGetter1& Getter1; + const TGetter2& Getter2; + const TTransformer& Transformer; + const int Prims; + const ImU32 Col; + const float HalfWeight; + static const int IdxConsumed = 6; + static const int VtxConsumed = 4; +}; + template <typename TGetter, typename TTransformer> struct StairsRenderer { - inline StairsRenderer(const TGetter& getter, const TTransformer& transformer, ImU32 col, float weight) : + IMPLOT_INLINE StairsRenderer(const TGetter& getter, const TTransformer& transformer, ImU32 col, float weight) : Getter(getter), Transformer(transformer), Prims(Getter.Count - 1), @@ -570,17 +632,14 @@ struct StairsRenderer { { P1 = Transformer(Getter(0)); } - inline bool operator()(ImDrawList& DrawList, const ImRect& cull_rect, const ImVec2& uv, int prim) const { + IMPLOT_INLINE bool operator()(ImDrawList& DrawList, const ImRect& cull_rect, const ImVec2& uv, int prim) const { ImVec2 P2 = Transformer(Getter(prim + 1)); if (!cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2)))) { P1 = P2; return false; } - AddRectFilled(ImVec2(P1.x, P1.y + HalfWeight), ImVec2(P2.x, P1.y - HalfWeight), Col, DrawList, uv); - AddRectFilled(ImVec2(P2.x - HalfWeight, P2.y), ImVec2(P2.x + HalfWeight, P1.y), Col, DrawList, uv); - - // AddLine(P1, P12, Weight, Col, DrawList, uv); - // AddLine(P12, P2, Weight, Col, DrawList, uv); + PrimRectFilled(ImVec2(P1.x, P1.y + HalfWeight), ImVec2(P2.x, P1.y - HalfWeight), Col, DrawList, uv); + PrimRectFilled(ImVec2(P2.x - HalfWeight, P2.y), ImVec2(P2.x + HalfWeight, P1.y), Col, DrawList, uv); P1 = P2; return true; } @@ -594,37 +653,11 @@ struct StairsRenderer { static const int VtxConsumed = 8; }; -template <typename TGetter1, typename TGetter2, typename TTransformer> -struct LineSegmentsRenderer { - inline LineSegmentsRenderer(const TGetter1& getter1, const TGetter2& getter2, const TTransformer& transformer, ImU32 col, float weight) : - Getter1(getter1), - Getter2(getter2), - Transformer(transformer), - Prims(ImMin(Getter1.Count, Getter2.Count)), - Col(col), - Weight(weight) - {} - inline bool operator()(ImDrawList& DrawList, const ImRect& cull_rect, const ImVec2& uv, int prim) const { - ImVec2 P1 = Transformer(Getter1(prim)); - ImVec2 P2 = Transformer(Getter2(prim)); - if (!cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2)))) - return false; - AddLine(P1,P2,Weight,Col,DrawList,uv); - return true; - } - const TGetter1& Getter1; - const TGetter2& Getter2; - const TTransformer& Transformer; - const int Prims; - const ImU32 Col; - const float Weight; - static const int IdxConsumed = 6; - static const int VtxConsumed = 4; -}; + template <typename TGetter1, typename TGetter2, typename TTransformer> struct ShadedRenderer { - ShadedRenderer(const TGetter1& getter1, const TGetter2& getter2, const TTransformer& transformer, ImU32 col) : + IMPLOT_INLINE ShadedRenderer(const TGetter1& getter1, const TGetter2& getter2, const TTransformer& transformer, ImU32 col) : Getter1(getter1), Getter2(getter2), Transformer(transformer), @@ -635,7 +668,7 @@ struct ShadedRenderer { P12 = Transformer(Getter2(0)); } - inline bool operator()(ImDrawList& DrawList, const ImRect& cull_rect, const ImVec2& uv, int prim) const { + IMPLOT_INLINE bool operator()(ImDrawList& DrawList, const ImRect& cull_rect, const ImVec2& uv, int prim) const { ImVec2 P21 = Transformer(Getter1(prim+1)); ImVec2 P22 = Transformer(Getter2(prim+1)); ImRect rect(ImMin(ImMin(ImMin(P11,P12),P21),P22), ImMax(ImMax(ImMax(P11,P12),P21),P22)); @@ -666,8 +699,8 @@ struct ShadedRenderer { DrawList._IdxWritePtr[1] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 1 + intersect); DrawList._IdxWritePtr[2] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 3); DrawList._IdxWritePtr[3] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 1); - DrawList._IdxWritePtr[4] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 3 - intersect); - DrawList._IdxWritePtr[5] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 4); + DrawList._IdxWritePtr[4] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 4); + DrawList._IdxWritePtr[5] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 3 - intersect); DrawList._IdxWritePtr += 6; DrawList._VtxCurrentIdx += 5; P11 = P21; @@ -685,15 +718,9 @@ struct ShadedRenderer { static const int VtxConsumed = 5; }; -// Stupid way of calculating maximum index size of ImDrawIdx without integer overflow issues -template <typename T> -struct MaxIdx { static const unsigned int Value; }; -template <> const unsigned int MaxIdx<unsigned short>::Value = 65535; -template <> const unsigned int MaxIdx<unsigned int>::Value = 4294967295; - /// Renders primitive shapes in bulk as efficiently as possible. template <typename Renderer> -inline void RenderPrimitives(const Renderer& renderer, ImDrawList& DrawList, const ImRect& cull_rect) { +IMPLOT_INLINE void RenderPrimitives(const Renderer& renderer, ImDrawList& DrawList, const ImRect& cull_rect) { unsigned int prims = renderer.Prims; unsigned int prims_culled = 0; unsigned int idx = 0; @@ -730,7 +757,7 @@ inline void RenderPrimitives(const Renderer& renderer, ImDrawList& DrawList, con } template <typename Getter, typename Transformer> -inline void RenderLineStrip(const Getter& getter, const Transformer& transformer, ImDrawList& DrawList, float line_weight, ImU32 col) { +IMPLOT_INLINE void RenderLineStrip(const Getter& getter, const Transformer& transformer, ImDrawList& DrawList, float line_weight, ImU32 col) { ImPlotContext& gp = *GImPlot; if (ImHasFlag(gp.CurrentPlot->Flags, ImPlotFlags_AntiAliased) || gp.Style.AntiAliasedLines) { ImVec2 p1 = transformer(getter(0)); @@ -747,7 +774,7 @@ inline void RenderLineStrip(const Getter& getter, const Transformer& transformer } template <typename Getter1, typename Getter2, typename Transformer> -inline void RenderLineSegments(const Getter1& getter1, const Getter2& getter2, const Transformer& transformer, ImDrawList& DrawList, float line_weight, ImU32 col) { +IMPLOT_INLINE void RenderLineSegments(const Getter1& getter1, const Getter2& getter2, const Transformer& transformer, ImDrawList& DrawList, float line_weight, ImU32 col) { ImPlotContext& gp = *GImPlot; if (ImHasFlag(gp.CurrentPlot->Flags, ImPlotFlags_AntiAliased) || gp.Style.AntiAliasedLines) { int I = ImMin(getter1.Count, getter2.Count); @@ -764,7 +791,7 @@ inline void RenderLineSegments(const Getter1& getter1, const Getter2& getter2, c } template <typename Getter, typename Transformer> -inline void RenderStairs(const Getter& getter, const Transformer& transformer, ImDrawList& DrawList, float line_weight, ImU32 col) { +IMPLOT_INLINE void RenderStairs(const Getter& getter, const Transformer& transformer, ImDrawList& DrawList, float line_weight, ImU32 col) { ImPlotContext& gp = *GImPlot; if (ImHasFlag(gp.CurrentPlot->Flags, ImPlotFlags_AntiAliased) || gp.Style.AntiAliasedLines) { ImVec2 p1 = transformer(getter(0)); @@ -787,14 +814,14 @@ inline void RenderStairs(const Getter& getter, const Transformer& transformer, I // MARKER RENDERERS //----------------------------------------------------------------------------- -inline void TransformMarker(ImVec2* points, int n, const ImVec2& c, float s) { +IMPLOT_INLINE void TransformMarker(ImVec2* points, int n, const ImVec2& c, float s) { for (int i = 0; i < n; ++i) { points[i].x = c.x + points[i].x * s; points[i].y = c.y + points[i].y * s; } } -inline void RenderMarkerGeneral(ImDrawList& DrawList, ImVec2* points, int n, const ImVec2& c, float s, bool outline, ImU32 col_outline, bool fill, ImU32 col_fill, float weight) { +IMPLOT_INLINE void RenderMarkerGeneral(ImDrawList& DrawList, ImVec2* points, int n, const ImVec2& c, float s, bool outline, ImU32 col_outline, bool fill, ImU32 col_fill, float weight) { TransformMarker(points, n, c, s); if (fill) DrawList.AddConvexPolyFilled(points, n, col_fill); @@ -804,7 +831,7 @@ inline void RenderMarkerGeneral(ImDrawList& DrawList, ImVec2* points, int n, con } } -inline void RenderMarkerCircle(ImDrawList& DrawList, const ImVec2& c, float s, bool outline, ImU32 col_outline, bool fill, ImU32 col_fill, float weight) { +IMPLOT_INLINE void RenderMarkerCircle(ImDrawList& DrawList, const ImVec2& c, float s, bool outline, ImU32 col_outline, bool fill, ImU32 col_fill, float weight) { ImVec2 marker[10] = {ImVec2(1.0f, 0.0f), ImVec2(0.809017f, 0.58778524f), ImVec2(0.30901697f, 0.95105654f), @@ -818,37 +845,37 @@ inline void RenderMarkerCircle(ImDrawList& DrawList, const ImVec2& c, float s, b RenderMarkerGeneral(DrawList, marker, 10, c, s, outline, col_outline, fill, col_fill, weight); } -inline void RenderMarkerDiamond(ImDrawList& DrawList, const ImVec2& c, float s, bool outline, ImU32 col_outline, bool fill, ImU32 col_fill, float weight) { +IMPLOT_INLINE void RenderMarkerDiamond(ImDrawList& DrawList, const ImVec2& c, float s, bool outline, ImU32 col_outline, bool fill, ImU32 col_fill, float weight) { ImVec2 marker[4] = {ImVec2(1, 0), ImVec2(0, -1), ImVec2(-1, 0), ImVec2(0, 1)}; RenderMarkerGeneral(DrawList, marker, 4, c, s, outline, col_outline, fill, col_fill, weight); } -inline void RenderMarkerSquare(ImDrawList& DrawList, const ImVec2& c, float s, bool outline, ImU32 col_outline, bool fill, ImU32 col_fill, float weight) { +IMPLOT_INLINE void RenderMarkerSquare(ImDrawList& DrawList, const ImVec2& c, float s, bool outline, ImU32 col_outline, bool fill, ImU32 col_fill, float weight) { ImVec2 marker[4] = {ImVec2(SQRT_1_2,SQRT_1_2),ImVec2(SQRT_1_2,-SQRT_1_2),ImVec2(-SQRT_1_2,-SQRT_1_2),ImVec2(-SQRT_1_2,SQRT_1_2)}; RenderMarkerGeneral(DrawList, marker, 4, c, s, outline, col_outline, fill, col_fill, weight); } -inline void RenderMarkerUp(ImDrawList& DrawList, const ImVec2& c, float s, bool outline, ImU32 col_outline, bool fill, ImU32 col_fill, float weight) { +IMPLOT_INLINE void RenderMarkerUp(ImDrawList& DrawList, const ImVec2& c, float s, bool outline, ImU32 col_outline, bool fill, ImU32 col_fill, float weight) { ImVec2 marker[3] = {ImVec2(SQRT_3_2,0.5f),ImVec2(0,-1),ImVec2(-SQRT_3_2,0.5f)}; RenderMarkerGeneral(DrawList, marker, 3, c, s, outline, col_outline, fill, col_fill, weight); } -inline void RenderMarkerDown(ImDrawList& DrawList, const ImVec2& c, float s, bool outline, ImU32 col_outline, bool fill, ImU32 col_fill, float weight) { +IMPLOT_INLINE void RenderMarkerDown(ImDrawList& DrawList, const ImVec2& c, float s, bool outline, ImU32 col_outline, bool fill, ImU32 col_fill, float weight) { ImVec2 marker[3] = {ImVec2(SQRT_3_2,-0.5f),ImVec2(0,1),ImVec2(-SQRT_3_2,-0.5f)}; RenderMarkerGeneral(DrawList, marker, 3, c, s, outline, col_outline, fill, col_fill, weight); } -inline void RenderMarkerLeft(ImDrawList& DrawList, const ImVec2& c, float s, bool outline, ImU32 col_outline, bool fill, ImU32 col_fill, float weight) { +IMPLOT_INLINE void RenderMarkerLeft(ImDrawList& DrawList, const ImVec2& c, float s, bool outline, ImU32 col_outline, bool fill, ImU32 col_fill, float weight) { ImVec2 marker[3] = {ImVec2(-1,0), ImVec2(0.5, SQRT_3_2), ImVec2(0.5, -SQRT_3_2)}; RenderMarkerGeneral(DrawList, marker, 3, c, s, outline, col_outline, fill, col_fill, weight); } -inline void RenderMarkerRight(ImDrawList& DrawList, const ImVec2& c, float s, bool outline, ImU32 col_outline, bool fill, ImU32 col_fill, float weight) { +IMPLOT_INLINE void RenderMarkerRight(ImDrawList& DrawList, const ImVec2& c, float s, bool outline, ImU32 col_outline, bool fill, ImU32 col_fill, float weight) { ImVec2 marker[3] = {ImVec2(1,0), ImVec2(-0.5, SQRT_3_2), ImVec2(-0.5, -SQRT_3_2)}; RenderMarkerGeneral(DrawList, marker, 3, c, s, outline, col_outline, fill, col_fill, weight); } -inline void RenderMarkerAsterisk(ImDrawList& DrawList, const ImVec2& c, float s, bool /*outline*/, ImU32 col_outline, bool /*fill*/, ImU32 /*col_fill*/, float weight) { +IMPLOT_INLINE void RenderMarkerAsterisk(ImDrawList& DrawList, const ImVec2& c, float s, bool /*outline*/, ImU32 col_outline, bool /*fill*/, ImU32 /*col_fill*/, float weight) { ImVec2 marker[6] = {ImVec2(SQRT_3_2, 0.5f), ImVec2(0, -1), ImVec2(-SQRT_3_2, 0.5f), ImVec2(SQRT_3_2, -0.5f), ImVec2(0, 1), ImVec2(-SQRT_3_2, -0.5f)}; TransformMarker(marker, 6, c, s); DrawList.AddLine(marker[0], marker[5], col_outline, weight); @@ -856,14 +883,14 @@ inline void RenderMarkerAsterisk(ImDrawList& DrawList, const ImVec2& c, float s, DrawList.AddLine(marker[2], marker[3], col_outline, weight); } -inline void RenderMarkerPlus(ImDrawList& DrawList, const ImVec2& c, float s, bool /*outline*/, ImU32 col_outline, bool /*fill*/, ImU32 /*col_fill*/, float weight) { +IMPLOT_INLINE void RenderMarkerPlus(ImDrawList& DrawList, const ImVec2& c, float s, bool /*outline*/, ImU32 col_outline, bool /*fill*/, ImU32 /*col_fill*/, float weight) { ImVec2 marker[4] = {ImVec2(1, 0), ImVec2(0, -1), ImVec2(-1, 0), ImVec2(0, 1)}; TransformMarker(marker, 4, c, s); DrawList.AddLine(marker[0], marker[2], col_outline, weight); DrawList.AddLine(marker[1], marker[3], col_outline, weight); } -inline void RenderMarkerCross(ImDrawList& DrawList, const ImVec2& c, float s, bool /*outline*/, ImU32 col_outline, bool /*fill*/, ImU32 /*col_fill*/, float weight) { +IMPLOT_INLINE void RenderMarkerCross(ImDrawList& DrawList, const ImVec2& c, float s, bool /*outline*/, ImU32 col_outline, bool /*fill*/, ImU32 /*col_fill*/, float weight) { ImVec2 marker[4] = {ImVec2(SQRT_1_2,SQRT_1_2),ImVec2(SQRT_1_2,-SQRT_1_2),ImVec2(-SQRT_1_2,-SQRT_1_2),ImVec2(-SQRT_1_2,SQRT_1_2)}; TransformMarker(marker, 4, c, s); DrawList.AddLine(marker[0], marker[2], col_outline, weight); @@ -871,7 +898,7 @@ inline void RenderMarkerCross(ImDrawList& DrawList, const ImVec2& c, float s, bo } template <typename Transformer, typename Getter> -inline void RenderMarkers(Getter getter, Transformer transformer, ImDrawList& DrawList, ImPlotMarker marker, float size, bool rend_mk_line, ImU32 col_mk_line, float weight, bool rend_mk_fill, ImU32 col_mk_fill) { +IMPLOT_INLINE void RenderMarkers(Getter getter, Transformer transformer, ImDrawList& DrawList, ImPlotMarker marker, float size, bool rend_mk_line, ImU32 col_mk_line, float weight, bool rend_mk_fill, ImU32 col_mk_fill) { static void (*marker_table[ImPlotMarker_COUNT])(ImDrawList&, const ImVec2&, float s, bool, ImU32, bool, ImU32, float) = { RenderMarkerCircle, RenderMarkerSquare, @@ -885,9 +912,10 @@ inline void RenderMarkers(Getter getter, Transformer transformer, ImDrawList& Dr RenderMarkerAsterisk }; ImPlotContext& gp = *GImPlot; + const ImRect& rect = gp.CurrentPlot->PlotRect; for (int i = 0; i < getter.Count; ++i) { ImVec2 c = transformer(getter(i)); - if (gp.CurrentPlot->PlotRect.Contains(c)) + if (c.x >= rect.Min.x && c.y >= rect.Min.y && c.x <= rect.Max.x && c.y <= rect.Max.y) marker_table[marker](DrawList, c, size, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, weight); } } @@ -897,7 +925,7 @@ inline void RenderMarkers(Getter getter, Transformer transformer, ImDrawList& Dr //----------------------------------------------------------------------------- template <typename Getter> -inline void PlotLineEx(const char* label_id, const Getter& getter) { +IMPLOT_INLINE void PlotLineEx(const char* label_id, const Getter& getter) { if (BeginItem(label_id, ImPlotCol_Line)) { if (FitThisFrame()) { for (int i = 0; i < getter.Count; ++i) { @@ -918,8 +946,9 @@ inline void PlotLineEx(const char* label_id, const Getter& getter) { } // render markers if (s.Marker != ImPlotMarker_None) { - PopPlotClipRect(); - PushPlotClipRect(s.MarkerSize); + // uncomment lines below to render markers over plot rect border + // PopPlotClipRect(); + // PushPlotClipRect(s.MarkerSize); const ImU32 col_line = ImGui::GetColorU32(s.Colors[ImPlotCol_MarkerOutline]); const ImU32 col_fill = ImGui::GetColorU32(s.Colors[ImPlotCol_MarkerFill]); switch (GetCurrentScale()) { @@ -933,9 +962,10 @@ inline void PlotLineEx(const char* label_id, const Getter& getter) { } } + template <typename T> void PlotLine(const char* label_id, const T* values, int count, double xscale, double x0, int offset, int stride) { - GetterYs<T> getter(values,count,xscale,x0,offset,stride); + GetterXY<GetterLin,GetterIdx<T>> getter(GetterLin(xscale,x0),GetterIdx<T>(values,count,offset,stride),count); PlotLineEx(label_id, getter); } @@ -952,7 +982,7 @@ template IMPLOT_API void PlotLine<double>(const char* label_id, const double* va template <typename T> void PlotLine(const char* label_id, const T* xs, const T* ys, int count, int offset, int stride) { - GetterXsYs<T> getter(xs,ys,count,offset,stride); + GetterXY<GetterIdx<T>,GetterIdx<T>> getter(GetterIdx<T>(xs,count,offset,stride),GetterIdx<T>(ys,count,offset,stride),count); return PlotLineEx(label_id, getter); } @@ -968,8 +998,8 @@ template IMPLOT_API void PlotLine<float>(const char* label_id, const float* xs, template IMPLOT_API void PlotLine<double>(const char* label_id, const double* xs, const double* ys, int count, int offset, int stride); // custom -void PlotLineG(const char* label_id, ImPlotPoint (*getter_func)(void* data, int idx), void* data, int count, int offset) { - GetterFuncPtr getter(getter_func,data, count, offset); +void PlotLineG(const char* label_id, ImPlotGetter getter_func, void* data, int count) { + GetterFuncPtr getter(getter_func,data, count); return PlotLineEx(label_id, getter); } @@ -978,7 +1008,7 @@ void PlotLineG(const char* label_id, ImPlotPoint (*getter_func)(void* data, int //----------------------------------------------------------------------------- template <typename Getter> -inline void PlotScatterEx(const char* label_id, const Getter& getter) { +IMPLOT_INLINE void PlotScatterEx(const char* label_id, const Getter& getter) { if (BeginItem(label_id, ImPlotCol_MarkerOutline)) { if (FitThisFrame()) { for (int i = 0; i < getter.Count; ++i) { @@ -991,8 +1021,9 @@ inline void PlotScatterEx(const char* label_id, const Getter& getter) { // render markers ImPlotMarker marker = s.Marker == ImPlotMarker_None ? ImPlotMarker_Circle : s.Marker; if (marker != ImPlotMarker_None) { - PopPlotClipRect(); - PushPlotClipRect(s.MarkerSize); + // uncomment lines below to render markers over plot rect border + // PopPlotClipRect(); + // PushPlotClipRect(s.MarkerSize); const ImU32 col_line = ImGui::GetColorU32(s.Colors[ImPlotCol_MarkerOutline]); const ImU32 col_fill = ImGui::GetColorU32(s.Colors[ImPlotCol_MarkerFill]); switch (GetCurrentScale()) { @@ -1008,7 +1039,7 @@ inline void PlotScatterEx(const char* label_id, const Getter& getter) { template <typename T> void PlotScatter(const char* label_id, const T* values, int count, double xscale, double x0, int offset, int stride) { - GetterYs<T> getter(values,count,xscale,x0,offset,stride); + GetterXY<GetterLin,GetterIdx<T>> getter(GetterLin(xscale,x0),GetterIdx<T>(values,count,offset,stride),count); PlotScatterEx(label_id, getter); } @@ -1025,7 +1056,7 @@ template IMPLOT_API void PlotScatter<double>(const char* label_id, const double* template <typename T> void PlotScatter(const char* label_id, const T* xs, const T* ys, int count, int offset, int stride) { - GetterXsYs<T> getter(xs,ys,count,offset,stride); + GetterXY<GetterIdx<T>,GetterIdx<T>> getter(GetterIdx<T>(xs,count,offset,stride),GetterIdx<T>(ys,count,offset,stride),count); return PlotScatterEx(label_id, getter); } @@ -1041,8 +1072,8 @@ template IMPLOT_API void PlotScatter<float>(const char* label_id, const float* x template IMPLOT_API void PlotScatter<double>(const char* label_id, const double* xs, const double* ys, int count, int offset, int stride); // custom -void PlotScatterG(const char* label_id, ImPlotPoint (*getter_func)(void* data, int idx), void* data, int count, int offset) { - GetterFuncPtr getter(getter_func,data, count, offset); +void PlotScatterG(const char* label_id, ImPlotGetter getter_func, void* data, int count) { + GetterFuncPtr getter(getter_func,data, count); return PlotScatterEx(label_id, getter); } @@ -1051,7 +1082,7 @@ void PlotScatterG(const char* label_id, ImPlotPoint (*getter_func)(void* data, i //----------------------------------------------------------------------------- template <typename Getter> -inline void PlotStairsEx(const char* label_id, const Getter& getter) { +IMPLOT_INLINE void PlotStairsEx(const char* label_id, const Getter& getter) { if (BeginItem(label_id, ImPlotCol_Line)) { if (FitThisFrame()) { for (int i = 0; i < getter.Count; ++i) { @@ -1089,7 +1120,7 @@ inline void PlotStairsEx(const char* label_id, const Getter& getter) { template <typename T> void PlotStairs(const char* label_id, const T* values, int count, double xscale, double x0, int offset, int stride) { - GetterYs<T> getter(values,count,xscale,x0,offset,stride); + GetterXY<GetterLin,GetterIdx<T>> getter(GetterLin(xscale,x0),GetterIdx<T>(values,count,offset,stride),count); PlotStairsEx(label_id, getter); } @@ -1106,7 +1137,7 @@ template IMPLOT_API void PlotStairs<double>(const char* label_id, const double* template <typename T> void PlotStairs(const char* label_id, const T* xs, const T* ys, int count, int offset, int stride) { - GetterXsYs<T> getter(xs,ys,count,offset,stride); + GetterXY<GetterIdx<T>,GetterIdx<T>> getter(GetterIdx<T>(xs,count,offset,stride),GetterIdx<T>(ys,count,offset,stride),count); return PlotStairsEx(label_id, getter); } @@ -1122,8 +1153,8 @@ template IMPLOT_API void PlotStairs<float>(const char* label_id, const float* xs template IMPLOT_API void PlotStairs<double>(const char* label_id, const double* xs, const double* ys, int count, int offset, int stride); // custom -void PlotStairsG(const char* label_id, ImPlotPoint (*getter_func)(void* data, int idx), void* data, int count, int offset) { - GetterFuncPtr getter(getter_func,data, count, offset); +void PlotStairsG(const char* label_id, ImPlotGetter getter_func, void* data, int count) { + GetterFuncPtr getter(getter_func,data, count); return PlotStairsEx(label_id, getter); } @@ -1132,7 +1163,7 @@ void PlotStairsG(const char* label_id, ImPlotPoint (*getter_func)(void* data, in //----------------------------------------------------------------------------- template <typename Getter1, typename Getter2> -inline void PlotShadedEx(const char* label_id, const Getter1& getter1, const Getter2& getter2, bool fit2) { +IMPLOT_INLINE void PlotShadedEx(const char* label_id, const Getter1& getter1, const Getter2& getter2, bool fit2) { if (BeginItem(label_id, ImPlotCol_Fill)) { if (FitThisFrame()) { for (int i = 0; i < getter1.Count; ++i) @@ -1160,16 +1191,16 @@ inline void PlotShadedEx(const char* label_id, const Getter1& getter1, const Get template <typename T> void PlotShaded(const char* label_id, const T* values, int count, double y_ref, double xscale, double x0, int offset, int stride) { bool fit2 = true; - if (y_ref == -HUGE_VAL) { + if (!(y_ref > -DBL_MAX)) { // filters out nans too fit2 = false; - y_ref = GetPlotLimits().Y.Min; + y_ref = GetPlotLimits(IMPLOT_AUTO,IMPLOT_AUTO).Y.Min; } - if (y_ref == HUGE_VAL) { + if (!(y_ref < DBL_MAX)) { // filters out nans too fit2 = false; - y_ref = GetPlotLimits().Y.Max; + y_ref = GetPlotLimits(IMPLOT_AUTO,IMPLOT_AUTO).Y.Max; } - GetterYs<T> getter1(values,count,xscale,x0,offset,stride); - GetterYRef getter2(y_ref,count,xscale,x0); + GetterXY<GetterLin,GetterIdx<T>> getter1(GetterLin(xscale,x0),GetterIdx<T>(values,count,offset,stride),count); + GetterXY<GetterLin,GetterRef> getter2(GetterLin(xscale,x0),GetterRef(y_ref),count); PlotShadedEx(label_id, getter1, getter2, fit2); } @@ -1187,16 +1218,16 @@ template IMPLOT_API void PlotShaded<double>(const char* label_id, const double* template <typename T> void PlotShaded(const char* label_id, const T* xs, const T* ys, int count, double y_ref, int offset, int stride) { bool fit2 = true; - if (y_ref == -HUGE_VAL) { + if (!(y_ref > -DBL_MAX)) { // filters out nans too fit2 = false; - y_ref = GetPlotLimits().Y.Min; + y_ref = GetPlotLimits(IMPLOT_AUTO,IMPLOT_AUTO).Y.Min; } - if (y_ref == HUGE_VAL) { + if (!(y_ref < DBL_MAX)) { // filters out nans too fit2 = false; - y_ref = GetPlotLimits().Y.Max; + y_ref = GetPlotLimits(IMPLOT_AUTO,IMPLOT_AUTO).Y.Max; } - GetterXsYs<T> getter1(xs, ys, count, offset, stride); - GetterXsYRef<T> getter2(xs, y_ref, count, offset, stride); + GetterXY<GetterIdx<T>,GetterIdx<T>> getter1(GetterIdx<T>(xs,count,offset,stride),GetterIdx<T>(ys,count,offset,stride),count); + GetterXY<GetterIdx<T>,GetterRef> getter2(GetterIdx<T>(xs,count,offset,stride),GetterRef(y_ref),count); PlotShadedEx(label_id, getter1, getter2, fit2); } @@ -1213,8 +1244,8 @@ template IMPLOT_API void PlotShaded<double>(const char* label_id, const double* template <typename T> void PlotShaded(const char* label_id, const T* xs, const T* ys1, const T* ys2, int count, int offset, int stride) { - GetterXsYs<T> getter1(xs, ys1, count, offset, stride); - GetterXsYs<T> getter2(xs, ys2, count, offset, stride); + GetterXY<GetterIdx<T>,GetterIdx<T>> getter1(GetterIdx<T>(xs,count,offset,stride),GetterIdx<T>(ys1,count,offset,stride),count); + GetterXY<GetterIdx<T>,GetterIdx<T>> getter2(GetterIdx<T>(xs,count,offset,stride),GetterIdx<T>(ys2,count,offset,stride),count); PlotShadedEx(label_id, getter1, getter2, true); } @@ -1230,9 +1261,9 @@ template IMPLOT_API void PlotShaded<float>(const char* label_id, const float* xs template IMPLOT_API void PlotShaded<double>(const char* label_id, const double* xs, const double* ys1, const double* ys2, int count, int offset, int stride); // custom -void PlotShadedG(const char* label_id, ImPlotPoint (*g1)(void* data, int idx), void* data1, ImPlotPoint (*g2)(void* data, int idx), void* data2, int count, int offset) { - GetterFuncPtr getter1(g1, data1, count, offset); - GetterFuncPtr getter2(g2, data2, count, offset); +void PlotShadedG(const char* label_id, ImPlotGetter getter_func1, void* data1, ImPlotGetter getter_func2, void* data2, int count) { + GetterFuncPtr getter1(getter_func1, data1, count); + GetterFuncPtr getter2(getter_func2, data2, count); PlotShadedEx(label_id, getter1, getter2, true); } @@ -1242,15 +1273,16 @@ void PlotShadedG(const char* label_id, ImPlotPoint (*g1)(void* data, int idx), v // TODO: Migrate to RenderPrimitives -template <typename Getter> -void PlotBarsEx(const char* label_id, const Getter& getter, double width) { +template <typename Getter1, typename Getter2> +void PlotBarsEx(const char* label_id, const Getter1& getter1, const Getter2 getter2, double width) { if (BeginItem(label_id, ImPlotCol_Fill)) { const double half_width = width / 2; if (FitThisFrame()) { - 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)); + for (int i = 0; i < getter1.Count; ++i) { + ImPlotPoint p1 = getter1(i); + ImPlotPoint p2 = getter2(i); + FitPoint(ImPlotPoint(p1.x - half_width, p1.y)); + FitPoint(ImPlotPoint(p2.x + half_width, p2.y)); } } const ImPlotNextItemData& s = GetItemData(); @@ -1260,12 +1292,20 @@ void PlotBarsEx(const char* label_id, const Getter& getter, double width) { bool rend_line = s.RenderLine; if (s.RenderFill && col_line == col_fill) rend_line = false; - for (int i = 0; i < getter.Count; ++i) { - ImPlotPoint p = getter(i); - if (p.y == 0) + for (int i = 0; i < getter1.Count; ++i) { + ImPlotPoint p1 = getter1(i); + ImPlotPoint p2 = getter2(i); + if (p1.y == p2.y) continue; - ImVec2 a = PlotToPixels(p.x - half_width, p.y); - ImVec2 b = PlotToPixels(p.x + half_width, 0); + ImVec2 a = PlotToPixels(p1.x - half_width, p1.y,IMPLOT_AUTO,IMPLOT_AUTO); + ImVec2 b = PlotToPixels(p2.x + half_width, p2.y,IMPLOT_AUTO,IMPLOT_AUTO); + float width_px = ImAbs(a.x-b.x); + if (width_px < 1.0f) { + a.x += a.x > b.x ? (1-width_px) / 2 : (width_px-1) / 2; + b.x += b.x > a.x ? (1-width_px) / 2 : (width_px-1) / 2; + } + // a.x = IM_ROUND(a.x); + // b.x = IM_ROUND(b.x); if (s.RenderFill) DrawList.AddRectFilled(a, b, col_fill); if (rend_line) @@ -1277,8 +1317,9 @@ void PlotBarsEx(const char* label_id, const Getter& getter, double width) { template <typename T> void PlotBars(const char* label_id, const T* values, int count, double width, double shift, int offset, int stride) { - GetterBarV<T> getter(values,shift,count,offset,stride); - PlotBarsEx(label_id, getter, width); + GetterXY<GetterLin,GetterIdx<T>> getter1(GetterLin(1.0,shift),GetterIdx<T>(values,count,offset,stride),count); + GetterXY<GetterLin,GetterRef> getter2(GetterLin(1.0,shift),GetterRef(0),count); + PlotBarsEx(label_id, getter1, getter2, width); } template IMPLOT_API void PlotBars<ImS8>(const char* label_id, const ImS8* values, int count, double width, double shift, int offset, int stride); @@ -1294,8 +1335,9 @@ template IMPLOT_API void PlotBars<double>(const char* label_id, const double* va template <typename T> void PlotBars(const char* label_id, const T* xs, const T* ys, int count, double width, int offset, int stride) { - GetterXsYs<T> getter(xs,ys,count,offset,stride); - PlotBarsEx(label_id, getter, width); + GetterXY<GetterIdx<T>,GetterIdx<T>> getter1(GetterIdx<T>(xs,count,offset,stride),GetterIdx<T>(ys,count,offset,stride),count); + GetterXY<GetterIdx<T>,GetterRef> getter2(GetterIdx<T>(xs,count,offset,stride),GetterRef(0),count); + PlotBarsEx(label_id, getter1, getter2, width); } template IMPLOT_API void PlotBars<ImS8>(const char* label_id, const ImS8* xs, const ImS8* ys, int count, double width, int offset, int stride); @@ -1310,9 +1352,10 @@ template IMPLOT_API void PlotBars<float>(const char* label_id, const float* xs, template IMPLOT_API void PlotBars<double>(const char* label_id, const double* xs, const double* ys, int count, double width, int offset, int stride); // custom -void PlotBarsG(const char* label_id, ImPlotPoint (*getter_func)(void* data, int idx), void* data, int count, double width, int offset) { - GetterFuncPtr getter(getter_func, data, count, offset); - PlotBarsEx(label_id, getter, width); +void PlotBarsG(const char* label_id, ImPlotGetter getter_func, void* data, int count, double width) { + GetterFuncPtr getter1(getter_func, data, count); + GetterOverrideY<GetterFuncPtr> getter2(getter1,0); + PlotBarsEx(label_id, getter1, getter2, width); } //----------------------------------------------------------------------------- @@ -1321,15 +1364,16 @@ void PlotBarsG(const char* label_id, ImPlotPoint (*getter_func)(void* data, int // TODO: Migrate to RenderPrimitives -template <typename Getter, typename THeight> -void PlotBarsHEx(const char* label_id, const Getter& getter, THeight height) { +template <typename Getter1, typename Getter2> +void PlotBarsHEx(const char* label_id, const Getter1& getter1, const Getter2& getter2, double height) { if (BeginItem(label_id, ImPlotCol_Fill)) { - const THeight half_height = height / 2; + const double half_height = height / 2; if (FitThisFrame()) { - 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)); + for (int i = 0; i < getter1.Count; ++i) { + ImPlotPoint p1 = getter1(i); + ImPlotPoint p2 = getter2(i); + FitPoint(ImPlotPoint(p1.x, p1.y - half_height)); + FitPoint(ImPlotPoint(p2.x, p2.y + half_height)); } } const ImPlotNextItemData& s = GetItemData(); @@ -1339,12 +1383,13 @@ void PlotBarsHEx(const char* label_id, const Getter& getter, THeight height) { bool rend_line = s.RenderLine; if (s.RenderFill && col_line == col_fill) rend_line = false; - for (int i = 0; i < getter.Count; ++i) { - ImPlotPoint p = getter(i); - if (p.x == 0) + for (int i = 0; i < getter1.Count; ++i) { + ImPlotPoint p1 = getter1(i); + ImPlotPoint p2 = getter2(i); + if (p1.x == p2.x) continue; - ImVec2 a = PlotToPixels(0, p.y - half_height); - ImVec2 b = PlotToPixels(p.x, p.y + half_height); + ImVec2 a = PlotToPixels(p1.x, p1.y - half_height,IMPLOT_AUTO,IMPLOT_AUTO); + ImVec2 b = PlotToPixels(p2.x, p2.y + half_height,IMPLOT_AUTO,IMPLOT_AUTO); if (s.RenderFill) DrawList.AddRectFilled(a, b, col_fill); if (rend_line) @@ -1356,8 +1401,9 @@ void PlotBarsHEx(const char* label_id, const Getter& getter, THeight height) { template <typename T> void PlotBarsH(const char* label_id, const T* values, int count, double height, double shift, int offset, int stride) { - GetterBarH<T> getter(values,shift,count,offset,stride); - PlotBarsHEx(label_id, getter, height); + GetterXY<GetterIdx<T>,GetterLin> getter1(GetterIdx<T>(values,count,offset,stride),GetterLin(1.0,shift),count); + GetterXY<GetterRef,GetterLin> getter2(GetterRef(0),GetterLin(1.0,shift),count); + PlotBarsHEx(label_id, getter1, getter2, height); } template IMPLOT_API void PlotBarsH<ImS8>(const char* label_id, const ImS8* values, int count, double height, double shift, int offset, int stride); @@ -1373,8 +1419,9 @@ template IMPLOT_API void PlotBarsH<double>(const char* label_id, const double* v template <typename T> void PlotBarsH(const char* label_id, const T* xs, const T* ys, int count, double height, int offset, int stride) { - GetterXsYs<T> getter(xs,ys,count,offset,stride); - PlotBarsHEx(label_id, getter, height); + GetterXY<GetterIdx<T>,GetterIdx<T>> getter1(GetterIdx<T>(xs,count,offset,stride),GetterIdx<T>(ys,count,offset,stride),count); + GetterXY<GetterRef, GetterIdx<T>> getter2(GetterRef(0),GetterIdx<T>(ys,count,offset,stride),count); + PlotBarsHEx(label_id, getter1, getter2, height); } template IMPLOT_API void PlotBarsH<ImS8>(const char* label_id, const ImS8* xs, const ImS8* ys, int count, double height, int offset, int stride); @@ -1389,11 +1436,122 @@ template IMPLOT_API void PlotBarsH<float>(const char* label_id, const float* xs, template IMPLOT_API void PlotBarsH<double>(const char* label_id, const double* xs, const double* ys, int count, double height, int offset, int stride); // custom -void PlotBarsHG(const char* label_id, ImPlotPoint (*getter_func)(void* data, int idx), void* data, int count, double height, int offset) { - GetterFuncPtr getter(getter_func, data, count, offset); - PlotBarsHEx(label_id, getter, height); +void PlotBarsHG(const char* label_id, ImPlotGetter getter_func, void* data, int count, double height) { + GetterFuncPtr getter1(getter_func, data, count); + GetterOverrideX<GetterFuncPtr> getter2(getter1,0); + PlotBarsHEx(label_id, getter1, getter2, height); +} + +//----------------------------------------------------------------------------- +// PLOT BAR GROUPS +//----------------------------------------------------------------------------- + +template <typename T> +void PlotBarGroups(const char* const label_ids[], const T* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags) { + if (ImHasFlag(flags, ImPlotBarGroupsFlags_Stacked)) { + SetupLock(); + GImPlot->TempDouble1.resize(4*groups); + double* temp = GImPlot->TempDouble1.Data; + double* neg = &temp[0]; + double* pos = &temp[groups]; + double* curr_min = &temp[groups*2]; + double* curr_max = &temp[groups*3]; + for (int g = 0; g < groups*2; ++g) + temp[g] = 0; + for (int i = 0; i < items; ++i) { + if (!IsItemHidden(label_ids[i])) { + for (int g = 0; g < groups; ++g) { + double v = (double)values[i*groups+g]; + if (v > 0) { + curr_min[g] = pos[g]; + curr_max[g] = curr_min[g] + v; + pos[g] += v; + } + else { + curr_max[g] = neg[g]; + curr_min[g] = curr_max[g] + v; + neg[g] += v; + } + } + } + GetterXY<GetterLin,GetterIdx<double>> getter1(GetterLin(1.0,shift),GetterIdx<double>(curr_min,groups),groups); + GetterXY<GetterLin,GetterIdx<double>> getter2(GetterLin(1.0,shift),GetterIdx<double>(curr_max,groups),groups); + PlotBarsEx(label_ids[i],getter1,getter2,width); + } + } + else { + const double subwidth = width / items; + for (int i = 0; i < items; ++i) { + const double subshift = (i+0.5)*subwidth - width/2; + PlotBars(label_ids[i],&values[i*groups],groups,subwidth,subshift+shift); + } + } +} + +template IMPLOT_API void PlotBarGroups<ImS8>(const char* const label_ids[], const ImS8* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); +template IMPLOT_API void PlotBarGroups<ImU8>(const char* const label_ids[], const ImU8* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); +template IMPLOT_API void PlotBarGroups<ImS16>(const char* const label_ids[], const ImS16* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); +template IMPLOT_API void PlotBarGroups<ImU16>(const char* const label_ids[], const ImU16* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); +template IMPLOT_API void PlotBarGroups<ImS32>(const char* const label_ids[], const ImS32* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); +template IMPLOT_API void PlotBarGroups<ImU32>(const char* const label_ids[], const ImU32* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); +template IMPLOT_API void PlotBarGroups<ImS64>(const char* const label_ids[], const ImS64* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); +template IMPLOT_API void PlotBarGroups<ImU64>(const char* const label_ids[], const ImU64* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); +template IMPLOT_API void PlotBarGroups<float>(const char* const label_ids[], const float* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); +template IMPLOT_API void PlotBarGroups<double>(const char* const label_ids[], const double* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); + +template <typename T> +void PlotBarGroupsH(const char* const label_ids[], const T* values, int items, int groups, double height, double shift, ImPlotBarGroupsFlags flags) { + if (ImHasFlag(flags, ImPlotBarGroupsFlags_Stacked)) { + SetupLock(); + GImPlot->TempDouble1.resize(4*groups); + double* temp = GImPlot->TempDouble1.Data; + double* neg = &temp[0]; + double* pos = &temp[groups]; + double* curr_min = &temp[groups*2]; + double* curr_max = &temp[groups*3]; + for (int g = 0; g < groups*2; ++g) + temp[g] = 0; + for (int i = 0; i < items; ++i) { + if (!IsItemHidden(label_ids[i])) { + for (int g = 0; g < groups; ++g) { + double v = (double)values[i*groups+g]; + if (v > 0) { + curr_min[g] = pos[g]; + curr_max[g] = curr_min[g] + v; + pos[g] += v; + } + else { + curr_max[g] = neg[g]; + curr_min[g] = curr_max[g] + v; + neg[g] += v; + } + } + } + GetterXY<GetterIdx<double>,GetterLin> getter1(GetterIdx<double>(curr_min,groups),GetterLin(1.0,shift),groups); + GetterXY<GetterIdx<double>,GetterLin> getter2(GetterIdx<double>(curr_max,groups),GetterLin(1.0,shift),groups); + PlotBarsHEx(label_ids[i],getter1,getter2,height); + } + } + else { + const double subheight = height / items; + for (int i = 0; i < items; ++i) { + const double subshift = (i+0.5)*subheight - height/2; + PlotBarsH(label_ids[i],&values[i*groups],groups,subheight,subshift+shift); + } + } } +template IMPLOT_API void PlotBarGroupsH<ImS8>(const char* const label_ids[], const ImS8* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); +template IMPLOT_API void PlotBarGroupsH<ImU8>(const char* const label_ids[], const ImU8* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); +template IMPLOT_API void PlotBarGroupsH<ImS16>(const char* const label_ids[], const ImS16* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); +template IMPLOT_API void PlotBarGroupsH<ImU16>(const char* const label_ids[], const ImU16* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); +template IMPLOT_API void PlotBarGroupsH<ImS32>(const char* const label_ids[], const ImS32* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); +template IMPLOT_API void PlotBarGroupsH<ImU32>(const char* const label_ids[], const ImU32* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); +template IMPLOT_API void PlotBarGroupsH<ImS64>(const char* const label_ids[], const ImS64* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); +template IMPLOT_API void PlotBarGroupsH<ImU64>(const char* const label_ids[], const ImU64* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); +template IMPLOT_API void PlotBarGroupsH<float>(const char* const label_ids[], const float* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); +template IMPLOT_API void PlotBarGroupsH<double>(const char* const label_ids[], const double* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); + //----------------------------------------------------------------------------- // PLOT ERROR BARS //----------------------------------------------------------------------------- @@ -1415,8 +1573,8 @@ void PlotErrorBarsEx(const char* label_id, const Getter& getter) { const float half_whisker = s.ErrorBarSize * 0.5f; 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); + ImVec2 p1 = PlotToPixels(e.X, e.Y - e.Neg,IMPLOT_AUTO,IMPLOT_AUTO); + ImVec2 p2 = PlotToPixels(e.X, e.Y + e.Pos,IMPLOT_AUTO,IMPLOT_AUTO); DrawList.AddLine(p1,p2,col, s.ErrorBarWeight); if (rend_whisker) { DrawList.AddLine(p1 - ImVec2(half_whisker, 0), p1 + ImVec2(half_whisker, 0), col, s.ErrorBarWeight); @@ -1482,8 +1640,8 @@ void PlotErrorBarsHEx(const char* label_id, const Getter& getter) { const float half_whisker = s.ErrorBarSize * 0.5f; for (int i = 0; i < getter.Count; ++i) { ImPlotPointError e = getter(i); - ImVec2 p1 = PlotToPixels(e.X - e.Neg, e.Y); - ImVec2 p2 = PlotToPixels(e.X + e.Pos, e.Y); + ImVec2 p1 = PlotToPixels(e.X - e.Neg, e.Y,IMPLOT_AUTO,IMPLOT_AUTO); + ImVec2 p2 = PlotToPixels(e.X + e.Pos, e.Y,IMPLOT_AUTO,IMPLOT_AUTO); DrawList.AddLine(p1, p2, col, s.ErrorBarWeight); if (rend_whisker) { DrawList.AddLine(p1 - ImVec2(0, half_whisker), p1 + ImVec2(0, half_whisker), col, s.ErrorBarWeight); @@ -1533,7 +1691,7 @@ template IMPLOT_API void PlotErrorBarsH<double>(const char* label_id, const doub //----------------------------------------------------------------------------- template <typename GetterM, typename GetterB> -inline void PlotStemsEx(const char* label_id, const GetterM& get_mark, const GetterB& get_base) { +IMPLOT_INLINE void PlotStemsEx(const char* label_id, const GetterM& get_mark, const GetterB& get_base) { if (BeginItem(label_id, ImPlotCol_Line)) { if (FitThisFrame()) { for (int i = 0; i < get_base.Count; ++i) { @@ -1573,8 +1731,8 @@ inline void PlotStemsEx(const char* label_id, const GetterM& get_mark, const Get template <typename T> void PlotStems(const char* label_id, const T* values, int count, double y_ref, double xscale, double x0, int offset, int stride) { - GetterYs<T> get_mark(values,count,xscale,x0,offset,stride); - GetterYRef get_base(y_ref,count,xscale,x0); + GetterXY<GetterLin,GetterIdx<T>> get_mark(GetterLin(xscale,x0),GetterIdx<T>(values,count,offset,stride),count); + GetterXY<GetterLin,GetterRef> get_base(GetterLin(xscale,x0),GetterRef(y_ref),count); PlotStemsEx(label_id, get_mark, get_base); } @@ -1591,8 +1749,8 @@ template IMPLOT_API void PlotStems<double>(const char* label_id, const double* v template <typename T> void PlotStems(const char* label_id, const T* xs, const T* ys, int count, double y_ref, int offset, int stride) { - GetterXsYs<T> get_mark(xs,ys,count,offset,stride); - GetterXsYRef<T> get_base(xs,y_ref,count,offset,stride); + GetterXY<GetterIdx<T>,GetterIdx<T>> get_mark(GetterIdx<T>(xs,count,offset,stride),GetterIdx<T>(ys,count,offset,stride),count); + GetterXY<GetterIdx<T>,GetterRef> get_base(GetterIdx<T>(xs,count,offset,stride),GetterRef(y_ref),count); PlotStemsEx(label_id, get_mark, get_base); } @@ -1614,9 +1772,9 @@ template IMPLOT_API void PlotStems<double>(const char* label_id, const double* x template <typename T> void PlotVLines(const char* label_id, const T* xs, int count, int offset, int stride) { if (BeginItem(label_id, ImPlotCol_Line)) { - const ImPlotLimits lims = GetPlotLimits(); - GetterXsYRef<T> get_min(xs,lims.Y.Min,count,offset,stride); - GetterXsYRef<T> get_max(xs,lims.Y.Max,count,offset,stride); + const ImPlotRect lims = GetPlotLimits(IMPLOT_AUTO,IMPLOT_AUTO); + GetterXY<GetterIdx<T>,GetterRef> get_min(GetterIdx<T>(xs,count,offset,stride),GetterRef(lims.Y.Min),count); + GetterXY<GetterIdx<T>,GetterRef> get_max(GetterIdx<T>(xs,count,offset,stride),GetterRef(lims.Y.Max),count); if (FitThisFrame()) { for (int i = 0; i < get_min.Count; ++i) FitPointX(get_min(i).x); @@ -1652,9 +1810,9 @@ template IMPLOT_API void PlotVLines<double>(const char* label_id, const double* template <typename T> void PlotHLines(const char* label_id, const T* ys, int count, int offset, int stride) { if (BeginItem(label_id, ImPlotCol_Line)) { - const ImPlotLimits lims = GetPlotLimits(); - GetterXRefYs<T> get_min(lims.X.Min,ys,count,offset,stride); - GetterXRefYs<T> get_max(lims.X.Max,ys,count,offset,stride); + const ImPlotRect lims = GetPlotLimits(IMPLOT_AUTO,IMPLOT_AUTO); + GetterXY<GetterRef,GetterIdx<T>> get_min(GetterRef(lims.X.Min),GetterIdx<T>(ys,count,offset,stride),count); + GetterXY<GetterRef,GetterIdx<T>> get_max(GetterRef(lims.X.Max),GetterIdx<T>(ys,count,offset,stride),count); if (FitThisFrame()) { for (int i = 0; i < get_min.Count; ++i) FitPointY(get_min(i).y); @@ -1690,15 +1848,15 @@ template IMPLOT_API void PlotHLines<double>(const char* label_id, const double* // PLOT PIE CHART //----------------------------------------------------------------------------- -inline void RenderPieSlice(ImDrawList& DrawList, const ImPlotPoint& center, double radius, double a0, double a1, ImU32 col) { +IMPLOT_INLINE void RenderPieSlice(ImDrawList& DrawList, const ImPlotPoint& center, double radius, double a0, double a1, ImU32 col) { static const float resolution = 50 / (2 * IM_PI); static ImVec2 buffer[50]; - buffer[0] = PlotToPixels(center); + buffer[0] = PlotToPixels(center,IMPLOT_AUTO,IMPLOT_AUTO); int n = ImMax(3, (int)((a1 - a0) * resolution)); double da = (a1 - a0) / (n - 1); for (int i = 0; i < n; ++i) { double a = a0 + i * da; - buffer[i + 1] = PlotToPixels(center.x + radius * cos(a), center.y + radius * sin(a)); + buffer[i + 1] = PlotToPixels(center.x + radius * cos(a), center.y + radius * sin(a),IMPLOT_AUTO,IMPLOT_AUTO); } DrawList.AddConvexPolyFilled(buffer, n + 1, col); } @@ -1719,6 +1877,10 @@ void PlotPieChart(const char* const label_ids[], const T* values, int count, dou double percent = normalize ? (double)values[i] / sum : (double)values[i]; a1 = a0 + 2 * IM_PI * percent; if (BeginItem(label_ids[i])) { + if (FitThisFrame()) { + FitPoint(ImPlotPoint(x-radius,y-radius)); + FitPoint(ImPlotPoint(x+radius,y+radius)); + } ImU32 col = GetCurrentItem()->Color; if (percent < 0.5) { RenderPieSlice(DrawList, center, radius, a0, a1, col); @@ -1740,10 +1902,10 @@ void PlotPieChart(const char* const label_ids[], const T* values, int count, dou double percent = normalize ? (double)values[i] / sum : (double)values[i]; a1 = a0 + 2 * IM_PI * percent; if (item->Show) { - sprintf(buffer, fmt, (double)values[i]); + ImFormatString(buffer, 32, fmt, (double)values[i]); ImVec2 size = ImGui::CalcTextSize(buffer); double angle = a0 + (a1 - a0) * 0.5; - ImVec2 pos = PlotToPixels(center.x + 0.5 * radius * cos(angle), center.y + 0.5 * radius * sin(angle)); + ImVec2 pos = PlotToPixels(center.x + 0.5 * radius * cos(angle), center.y + 0.5 * radius * sin(angle),IMPLOT_AUTO,IMPLOT_AUTO); ImU32 col = CalcTextColor(ImGui::ColorConvertU32ToFloat4(item->Color)); DrawList.AddText(pos - size * 0.5f, col, buffer); } @@ -1775,12 +1937,12 @@ struct RectInfo { template <typename TGetter, typename TTransformer> struct RectRenderer { - inline RectRenderer(const TGetter& getter, const TTransformer& transformer) : + IMPLOT_INLINE RectRenderer(const TGetter& getter, const TTransformer& transformer) : Getter(getter), Transformer(transformer), Prims(Getter.Count) {} - inline bool operator()(ImDrawList& DrawList, const ImRect& cull_rect, const ImVec2& uv, int prim) const { + IMPLOT_INLINE bool operator()(ImDrawList& DrawList, const ImRect& cull_rect, const ImVec2& uv, int prim) const { RectInfo rect = Getter(prim); ImVec2 P1 = Transformer(rect.Min); ImVec2 P2 = Transformer(rect.Max); @@ -1837,7 +1999,7 @@ struct GetterHeatmap { HalfSize(Width*0.5, Height*0.5) { } - inline RectInfo operator()(int idx) const { + template <typename I> IMPLOT_INLINE RectInfo operator()(I idx) const { double val = (double)Values[idx]; const int r = idx / Cols; const int c = idx % Cols; @@ -1894,7 +2056,7 @@ void RenderHeatmap(Transformer transformer, ImDrawList& DrawList, const T* value p.y = yref + ydir * (0.5*h + r*h); ImVec2 px = transformer(p); char buff[32]; - sprintf(buff, fmt, values[i]); + ImFormatString(buff, 32, fmt, values[i]); ImVec2 size = ImGui::CalcTextSize(buff); double t = ImClamp(ImRemap01((double)values[i], scale_min, scale_max),0.0,1.0); ImVec4 color = SampleColormap((float)t); @@ -1958,8 +2120,8 @@ double PlotHistogram(const char* label_id, const T* values, int count, int bins, else width = range.Size() / bins; - ImVector<double>& bin_centers = GImPlot->Temp1; - ImVector<double>& bin_counts = GImPlot->Temp2; + ImVector<double>& bin_centers = GImPlot->TempDouble1; + ImVector<double>& bin_counts = GImPlot->TempDouble2; bin_centers.resize(bins); bin_counts.resize(bins); int below = 0; @@ -2026,7 +2188,7 @@ template IMPLOT_API double PlotHistogram<double>(const char* label_id, const dou //----------------------------------------------------------------------------- template <typename T> -double PlotHistogram2D(const char* label_id, const T* xs, const T* ys, int count, int x_bins, int y_bins, bool density, ImPlotLimits range, bool outliers) { +double PlotHistogram2D(const char* label_id, const T* xs, const T* ys, int count, int x_bins, int y_bins, bool density, ImPlotRect range, bool outliers) { if (count <= 0 || x_bins == 0 || y_bins == 0) return 0; @@ -2056,7 +2218,7 @@ double PlotHistogram2D(const char* label_id, const T* xs, const T* ys, int count const int bins = x_bins * y_bins; - ImVector<double>& bin_counts = GImPlot->Temp1; + ImVector<double>& bin_counts = GImPlot->TempDouble1; bin_counts.resize(bins); for (int b = 0; b < bins; ++b) @@ -2099,16 +2261,16 @@ double PlotHistogram2D(const char* label_id, const T* xs, const T* ys, int count return max_count; } -template IMPLOT_API double PlotHistogram2D<ImS8>(const char* label_id, const ImS8* xs, const ImS8* ys, int count, int x_bins, int y_bins, bool density, ImPlotLimits range, bool outliers); -template IMPLOT_API double PlotHistogram2D<ImU8>(const char* label_id, const ImU8* xs, const ImU8* ys, int count, int x_bins, int y_bins, bool density, ImPlotLimits range, bool outliers); -template IMPLOT_API double PlotHistogram2D<ImS16>(const char* label_id, const ImS16* xs, const ImS16* ys, int count, int x_bins, int y_bins, bool density, ImPlotLimits range, bool outliers); -template IMPLOT_API double PlotHistogram2D<ImU16>(const char* label_id, const ImU16* xs, const ImU16* ys, int count, int x_bins, int y_bins, bool density, ImPlotLimits range, bool outliers); -template IMPLOT_API double PlotHistogram2D<ImS32>(const char* label_id, const ImS32* xs, const ImS32* ys, int count, int x_bins, int y_bins, bool density, ImPlotLimits range, bool outliers); -template IMPLOT_API double PlotHistogram2D<ImU32>(const char* label_id, const ImU32* xs, const ImU32* ys, int count, int x_bins, int y_bins, bool density, ImPlotLimits range, bool outliers); -template IMPLOT_API double PlotHistogram2D<ImS64>(const char* label_id, const ImS64* xs, const ImS64* ys, int count, int x_bins, int y_bins, bool density, ImPlotLimits range, bool outliers); -template IMPLOT_API double PlotHistogram2D<ImU64>(const char* label_id, const ImU64* xs, const ImU64* ys, int count, int x_bins, int y_bins, bool density, ImPlotLimits range, bool outliers); -template IMPLOT_API double PlotHistogram2D<float>(const char* label_id, const float* xs, const float* ys, int count, int x_bins, int y_bins, bool density, ImPlotLimits range, bool outliers); -template IMPLOT_API double PlotHistogram2D<double>(const char* label_id, const double* xs, const double* ys, int count, int x_bins, int y_bins, bool density, ImPlotLimits range, bool outliers); +template IMPLOT_API double PlotHistogram2D<ImS8>(const char* label_id, const ImS8* xs, const ImS8* ys, int count, int x_bins, int y_bins, bool density, ImPlotRect range, bool outliers); +template IMPLOT_API double PlotHistogram2D<ImU8>(const char* label_id, const ImU8* xs, const ImU8* ys, int count, int x_bins, int y_bins, bool density, ImPlotRect range, bool outliers); +template IMPLOT_API double PlotHistogram2D<ImS16>(const char* label_id, const ImS16* xs, const ImS16* ys, int count, int x_bins, int y_bins, bool density, ImPlotRect range, bool outliers); +template IMPLOT_API double PlotHistogram2D<ImU16>(const char* label_id, const ImU16* xs, const ImU16* ys, int count, int x_bins, int y_bins, bool density, ImPlotRect range, bool outliers); +template IMPLOT_API double PlotHistogram2D<ImS32>(const char* label_id, const ImS32* xs, const ImS32* ys, int count, int x_bins, int y_bins, bool density, ImPlotRect range, bool outliers); +template IMPLOT_API double PlotHistogram2D<ImU32>(const char* label_id, const ImU32* xs, const ImU32* ys, int count, int x_bins, int y_bins, bool density, ImPlotRect range, bool outliers); +template IMPLOT_API double PlotHistogram2D<ImS64>(const char* label_id, const ImS64* xs, const ImS64* ys, int count, int x_bins, int y_bins, bool density, ImPlotRect range, bool outliers); +template IMPLOT_API double PlotHistogram2D<ImU64>(const char* label_id, const ImU64* xs, const ImU64* ys, int count, int x_bins, int y_bins, bool density, ImPlotRect range, bool outliers); +template IMPLOT_API double PlotHistogram2D<float>(const char* label_id, const float* xs, const float* ys, int count, int x_bins, int y_bins, bool density, ImPlotRect range, bool outliers); +template IMPLOT_API double PlotHistogram2D<double>(const char* label_id, const double* xs, const double* ys, int count, int x_bins, int y_bins, bool density, ImPlotRect range, bool outliers); //----------------------------------------------------------------------------- // PLOT DIGITAL @@ -2117,13 +2279,16 @@ template IMPLOT_API double PlotHistogram2D<double>(const char* label_id, const d // TODO: Make this behave like all the other plot types (.e. not fixed in y axis) template <typename Getter> -inline void PlotDigitalEx(const char* label_id, Getter getter) { +IMPLOT_INLINE void PlotDigitalEx(const char* label_id, Getter getter) { if (BeginItem(label_id, ImPlotCol_Fill)) { ImPlotContext& gp = *GImPlot; ImDrawList& DrawList = *GetPlotDrawList(); const ImPlotNextItemData& s = GetItemData(); if (getter.Count > 1 && s.RenderFill) { - const int y_axis = GetCurrentYAxis(); + ImPlotPlot& plot = *gp.CurrentPlot; + ImPlotAxis& x_axis = plot.Axes[plot.CurrentX]; + ImPlotAxis& y_axis = plot.Axes[plot.CurrentY]; + int pixYMax = 0; ImPlotPoint itemData1 = getter(0); for (int i = 0; i < getter.Count; ++i) { @@ -2139,24 +2304,24 @@ inline void PlotDigitalEx(const char* label_id, Getter getter) { int pixY_1 = (int)(pixY_1_float); //allow only positive values int pixY_chPosOffset = (int)(ImMax(s.DigitalBitHeight, pixY_1_float) + s.DigitalBitGap); pixYMax = ImMax(pixYMax, pixY_chPosOffset); - ImVec2 pMin = PlotToPixels(itemData1); - ImVec2 pMax = PlotToPixels(itemData2); - int pixY_Offset = 20; //20 pixel from bottom due to mouse cursor label - pMin.y = (gp.PixelRange[y_axis].Min.y) + ((-gp.DigitalPlotOffset) - pixY_Offset); - pMax.y = (gp.PixelRange[y_axis].Min.y) + ((-gp.DigitalPlotOffset) - pixY_0 - pixY_1 - pixY_Offset); + ImVec2 pMin = PlotToPixels(itemData1,IMPLOT_AUTO,IMPLOT_AUTO); + ImVec2 pMax = PlotToPixels(itemData2,IMPLOT_AUTO,IMPLOT_AUTO); + int pixY_Offset = 0; //20 pixel from bottom due to mouse cursor label + pMin.y = (y_axis.PixelMin) + ((-gp.DigitalPlotOffset) - pixY_Offset); + pMax.y = (y_axis.PixelMin) + ((-gp.DigitalPlotOffset) - pixY_0 - pixY_1 - pixY_Offset); //plot only one rectangle for same digital state while (((i+2) < getter.Count) && (itemData1.y == itemData2.y)) { const int in = (i + 1); itemData2 = getter(in); if (ImNanOrInf(itemData2.y)) break; - pMax.x = PlotToPixels(itemData2).x; + pMax.x = PlotToPixels(itemData2,IMPLOT_AUTO,IMPLOT_AUTO).x; i++; } //do not extend plot outside plot range - if (pMin.x < gp.PixelRange[y_axis].Min.x) pMin.x = gp.PixelRange[y_axis].Min.x; - if (pMax.x < gp.PixelRange[y_axis].Min.x) pMax.x = gp.PixelRange[y_axis].Min.x; - if (pMin.x > gp.PixelRange[y_axis].Max.x) pMin.x = gp.PixelRange[y_axis].Max.x; - if (pMax.x > gp.PixelRange[y_axis].Max.x) pMax.x = gp.PixelRange[y_axis].Max.x; + if (pMin.x < x_axis.PixelMin) pMin.x = x_axis.PixelMin; + if (pMax.x < x_axis.PixelMin) pMax.x = x_axis.PixelMin; + if (pMin.x > x_axis.PixelMax) pMin.x = x_axis.PixelMax; + if (pMax.x > x_axis.PixelMax) pMax.x = x_axis.PixelMax; //plot a rectangle that extends up to x2 with y1 height if ((pMax.x > pMin.x) && (gp.CurrentPlot->PlotRect.Contains(pMin) || gp.CurrentPlot->PlotRect.Contains(pMax))) { // ImVec4 colAlpha = item->Color; @@ -2175,7 +2340,7 @@ inline void PlotDigitalEx(const char* label_id, Getter getter) { template <typename T> void PlotDigital(const char* label_id, const T* xs, const T* ys, int count, int offset, int stride) { - GetterXsYs<T> getter(xs,ys,count,offset,stride); + GetterXY<GetterIdx<T>,GetterIdx<T>> getter(GetterIdx<T>(xs,count,offset,stride),GetterIdx<T>(ys,count,offset,stride),count); return PlotDigitalEx(label_id, getter); } @@ -2191,8 +2356,8 @@ template IMPLOT_API void PlotDigital<float>(const char* label_id, const float* x template IMPLOT_API void PlotDigital<double>(const char* label_id, const double* xs, const double* ys, int count, int offset, int stride); // custom -void PlotDigitalG(const char* label_id, ImPlotPoint (*getter_func)(void* data, int idx), void* data, int count, int offset) { - GetterFuncPtr getter(getter_func,data,count,offset); +void PlotDigitalG(const char* label_id, ImPlotGetter getter_func, void* data, int count) { + GetterFuncPtr getter(getter_func,data,count); return PlotDigitalEx(label_id, getter); } @@ -2209,8 +2374,8 @@ void PlotImage(const char* label_id, ImTextureID user_texture_id, const ImPlotPo ImU32 tint_col32 = ImGui::ColorConvertFloat4ToU32(tint_col); GetCurrentItem()->Color = tint_col32; ImDrawList& DrawList = *GetPlotDrawList(); - ImVec2 p1 = PlotToPixels(bmin.x, bmax.y); - ImVec2 p2 = PlotToPixels(bmax.x, bmin.y); + ImVec2 p1 = PlotToPixels(bmin.x, bmax.y,IMPLOT_AUTO,IMPLOT_AUTO); + ImVec2 p2 = PlotToPixels(bmax.x, bmin.y,IMPLOT_AUTO,IMPLOT_AUTO); PushPlotClipRect(); DrawList.AddImage(user_texture_id, p1, p2, uv0, uv1, tint_col32); PopPlotClipRect(); @@ -2225,16 +2390,27 @@ void PlotImage(const char* label_id, ImTextureID user_texture_id, const ImPlotPo // double void PlotText(const char* text, double x, double y, bool vertical, const ImVec2& pixel_offset) { IM_ASSERT_USER_ERROR(GImPlot->CurrentPlot != NULL, "PlotText() needs to be called between BeginPlot() and EndPlot()!"); + SetupLock(); ImDrawList & DrawList = *GetPlotDrawList(); PushPlotClipRect(); ImU32 colTxt = GetStyleColorU32(ImPlotCol_InlayText); if (vertical) { - ImVec2 ctr = CalcTextSizeVertical(text) * 0.5f; - ImVec2 pos = PlotToPixels(ImPlotPoint(x,y)) + ImVec2(-ctr.x, ctr.y) + pixel_offset; + ImVec2 siz = CalcTextSizeVertical(text) * 0.5f; + ImVec2 ctr = siz * 0.5f; + ImVec2 pos = PlotToPixels(ImPlotPoint(x,y),IMPLOT_AUTO,IMPLOT_AUTO) + ImVec2(-ctr.x, ctr.y) + pixel_offset; + if (FitThisFrame()) { + FitPoint(PixelsToPlot(pos)); + FitPoint(PixelsToPlot(pos.x + siz.x, pos.y - siz.y)); + } AddTextVertical(&DrawList, pos, colTxt, text); } else { - ImVec2 pos = PlotToPixels(ImPlotPoint(x,y)) - ImGui::CalcTextSize(text) * 0.5f + pixel_offset; + ImVec2 siz = ImGui::CalcTextSize(text); + ImVec2 pos = PlotToPixels(ImPlotPoint(x,y),IMPLOT_AUTO,IMPLOT_AUTO) - siz * 0.5f + pixel_offset; + if (FitThisFrame()) { + FitPoint(PixelsToPlot(pos)); + FitPoint(PixelsToPlot(pos+siz)); + } DrawList.AddText(pos, colTxt, text); } PopPlotClipRect(); @@ -2249,4 +2425,4 @@ void PlotDummy(const char* label_id) { EndItem(); } -} // namespace ImPlot
\ No newline at end of file +} // namespace ImPlot |