/
Yuri
/
Case5
Обзор
Документация
Войти
/
Yuri
/
Case5
Код
Запросы
0
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
implot_items.cpp
2 808 строк
120 KB
LLLida
initial
13 апр 2024, 18:45
13 апр 2024, 18:45
1594dcb
Код
Авторство
О чём код?
// MIT License // Copyright (c) 2023 Evan Pezent // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // ImPlot v0.17 #define IMGUI_DEFINE_MATH_OPERATORS #include "implot.h" #include "implot_internal.h" //----------------------------------------------------------------------------- // [SECTION] Macros and Defines //----------------------------------------------------------------------------- #define SQRT_1_2 0.70710678118f #define SQRT_3_2 0.86602540378f #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 #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 //----------------------------------------------------------------------------- // [SECTION] Template instantiation utility //----------------------------------------------------------------------------- // By default, templates are instantiated for `float`, `double`, and for the following integer types, which are defined in imgui.h: // signed char ImS8; // 8-bit signed integer // unsigned char ImU8; // 8-bit unsigned integer // signed short ImS16; // 16-bit signed integer // unsigned short ImU16; // 16-bit unsigned integer // signed int ImS32; // 32-bit signed integer == int // unsigned int ImU32; // 32-bit unsigned integer // signed long long ImS64; // 64-bit signed integer // unsigned long long ImU64; // 64-bit unsigned integer // (note: this list does *not* include `long`, `unsigned long` and `long double`) // // You can customize the supported types by defining IMPLOT_CUSTOM_NUMERIC_TYPES at compile time to define your own type list. // As an example, you could use the compile time define given by the line below in order to support only float and double. // -DIMPLOT_CUSTOM_NUMERIC_TYPES="(float)(double)" // In order to support all known C++ types, use: // -DIMPLOT_CUSTOM_NUMERIC_TYPES="(signed char)(unsigned char)(signed short)(unsigned short)(signed int)(unsigned int)(signed long)(unsigned long)(signed long long)(unsigned long long)(float)(double)(long double)" #ifdef IMPLOT_CUSTOM_NUMERIC_TYPES #define IMPLOT_NUMERIC_TYPES IMPLOT_CUSTOM_NUMERIC_TYPES #else #define IMPLOT_NUMERIC_TYPES (ImS8)(ImU8)(ImS16)(ImU16)(ImS32)(ImU32)(ImS64)(ImU64)(float)(double) #endif // CALL_INSTANTIATE_FOR_NUMERIC_TYPES will duplicate the template instantion code `INSTANTIATE_MACRO(T)` on supported types. #define _CAT(x, y) _CAT_(x, y) #define _CAT_(x,y) x ## y #define _INSTANTIATE_FOR_NUMERIC_TYPES(chain) _CAT(_INSTANTIATE_FOR_NUMERIC_TYPES_1 chain, _END) #define _INSTANTIATE_FOR_NUMERIC_TYPES_1(T) INSTANTIATE_MACRO(T) _INSTANTIATE_FOR_NUMERIC_TYPES_2 #define _INSTANTIATE_FOR_NUMERIC_TYPES_2(T) INSTANTIATE_MACRO(T) _INSTANTIATE_FOR_NUMERIC_TYPES_1 #define _INSTANTIATE_FOR_NUMERIC_TYPES_1_END #define _INSTANTIATE_FOR_NUMERIC_TYPES_2_END #define CALL_INSTANTIATE_FOR_NUMERIC_TYPES() _INSTANTIATE_FOR_NUMERIC_TYPES(IMPLOT_NUMERIC_TYPES) namespace ImPlot { //----------------------------------------------------------------------------- // [SECTION] 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; IMPLOT_INLINE void GetLineRenderProps(const ImDrawList& draw_list, float& half_weight, ImVec2& tex_uv0, ImVec2& tex_uv1) { const bool aa = ImHasFlag(draw_list.Flags, ImDrawListFlags_AntiAliasedLines) && ImHasFlag(draw_list.Flags, ImDrawListFlags_AntiAliasedLinesUseTex); if (aa) { ImVec4 tex_uvs = draw_list._Data->TexUvLines[(int)(half_weight*2)]; tex_uv0 = ImVec2(tex_uvs.x, tex_uvs.y); tex_uv1 = ImVec2(tex_uvs.z, tex_uvs.w); half_weight += 1; } else { tex_uv0 = tex_uv1 = draw_list._Data->TexUvWhitePixel; } } IMPLOT_INLINE void PrimLine(ImDrawList& draw_list, const ImVec2& P1, const ImVec2& P2, float half_weight, ImU32 col, const ImVec2& tex_uv0, const ImVec2 tex_uv1) { float dx = P2.x - P1.x; float dy = P2.y - P1.y; IMPLOT_NORMALIZE2F_OVER_ZERO(dx, dy); dx *= half_weight; dy *= half_weight; draw_list._VtxWritePtr[0].pos.x = P1.x + dy; draw_list._VtxWritePtr[0].pos.y = P1.y - dx; draw_list._VtxWritePtr[0].uv = tex_uv0; draw_list._VtxWritePtr[0].col = col; draw_list._VtxWritePtr[1].pos.x = P2.x + dy; draw_list._VtxWritePtr[1].pos.y = P2.y - dx; draw_list._VtxWritePtr[1].uv = tex_uv0; draw_list._VtxWritePtr[1].col = col; draw_list._VtxWritePtr[2].pos.x = P2.x - dy; draw_list._VtxWritePtr[2].pos.y = P2.y + dx; draw_list._VtxWritePtr[2].uv = tex_uv1; draw_list._VtxWritePtr[2].col = col; draw_list._VtxWritePtr[3].pos.x = P1.x - dy; draw_list._VtxWritePtr[3].pos.y = P1.y + dx; draw_list._VtxWritePtr[3].uv = tex_uv1; draw_list._VtxWritePtr[3].col = col; draw_list._VtxWritePtr += 4; draw_list._IdxWritePtr[0] = (ImDrawIdx)(draw_list._VtxCurrentIdx); draw_list._IdxWritePtr[1] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 1); draw_list._IdxWritePtr[2] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 2); draw_list._IdxWritePtr[3] = (ImDrawIdx)(draw_list._VtxCurrentIdx); draw_list._IdxWritePtr[4] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 2); draw_list._IdxWritePtr[5] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 3); draw_list._IdxWritePtr += 6; draw_list._VtxCurrentIdx += 4; } IMPLOT_INLINE void PrimRectFill(ImDrawList& draw_list, const ImVec2& Pmin, const ImVec2& Pmax, ImU32 col, const ImVec2& uv) { draw_list._VtxWritePtr[0].pos = Pmin; draw_list._VtxWritePtr[0].uv = uv; draw_list._VtxWritePtr[0].col = col; draw_list._VtxWritePtr[1].pos = Pmax; draw_list._VtxWritePtr[1].uv = uv; draw_list._VtxWritePtr[1].col = col; draw_list._VtxWritePtr[2].pos.x = Pmin.x; draw_list._VtxWritePtr[2].pos.y = Pmax.y; draw_list._VtxWritePtr[2].uv = uv; draw_list._VtxWritePtr[2].col = col; draw_list._VtxWritePtr[3].pos.x = Pmax.x; draw_list._VtxWritePtr[3].pos.y = Pmin.y; draw_list._VtxWritePtr[3].uv = uv; draw_list._VtxWritePtr[3].col = col; draw_list._VtxWritePtr += 4; draw_list._IdxWritePtr[0] = (ImDrawIdx)(draw_list._VtxCurrentIdx); draw_list._IdxWritePtr[1] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 1); draw_list._IdxWritePtr[2] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 2); draw_list._IdxWritePtr[3] = (ImDrawIdx)(draw_list._VtxCurrentIdx); draw_list._IdxWritePtr[4] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 1); draw_list._IdxWritePtr[5] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 3); draw_list._IdxWritePtr += 6; draw_list._VtxCurrentIdx += 4; } IMPLOT_INLINE void PrimRectLine(ImDrawList& draw_list, const ImVec2& Pmin, const ImVec2& Pmax, float weight, ImU32 col, const ImVec2& uv) { draw_list._VtxWritePtr[0].pos.x = Pmin.x; draw_list._VtxWritePtr[0].pos.y = Pmin.y; draw_list._VtxWritePtr[0].uv = uv; draw_list._VtxWritePtr[0].col = col; draw_list._VtxWritePtr[1].pos.x = Pmin.x; draw_list._VtxWritePtr[1].pos.y = Pmax.y; draw_list._VtxWritePtr[1].uv = uv; draw_list._VtxWritePtr[1].col = col; draw_list._VtxWritePtr[2].pos.x = Pmax.x; draw_list._VtxWritePtr[2].pos.y = Pmax.y; draw_list._VtxWritePtr[2].uv = uv; draw_list._VtxWritePtr[2].col = col; draw_list._VtxWritePtr[3].pos.x = Pmax.x; draw_list._VtxWritePtr[3].pos.y = Pmin.y; draw_list._VtxWritePtr[3].uv = uv; draw_list._VtxWritePtr[3].col = col; draw_list._VtxWritePtr[4].pos.x = Pmin.x + weight; draw_list._VtxWritePtr[4].pos.y = Pmin.y + weight; draw_list._VtxWritePtr[4].uv = uv; draw_list._VtxWritePtr[4].col = col; draw_list._VtxWritePtr[5].pos.x = Pmin.x + weight; draw_list._VtxWritePtr[5].pos.y = Pmax.y - weight; draw_list._VtxWritePtr[5].uv = uv; draw_list._VtxWritePtr[5].col = col; draw_list._VtxWritePtr[6].pos.x = Pmax.x - weight; draw_list._VtxWritePtr[6].pos.y = Pmax.y - weight; draw_list._VtxWritePtr[6].uv = uv; draw_list._VtxWritePtr[6].col = col; draw_list._VtxWritePtr[7].pos.x = Pmax.x - weight; draw_list._VtxWritePtr[7].pos.y = Pmin.y + weight; draw_list._VtxWritePtr[7].uv = uv; draw_list._VtxWritePtr[7].col = col; draw_list._VtxWritePtr += 8; draw_list._IdxWritePtr[0] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 0); draw_list._IdxWritePtr[1] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 1); draw_list._IdxWritePtr[2] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 5); draw_list._IdxWritePtr += 3; draw_list._IdxWritePtr[0] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 0); draw_list._IdxWritePtr[1] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 5); draw_list._IdxWritePtr[2] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 4); draw_list._IdxWritePtr += 3; draw_list._IdxWritePtr[0] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 1); draw_list._IdxWritePtr[1] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 2); draw_list._IdxWritePtr[2] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 6); draw_list._IdxWritePtr += 3; draw_list._IdxWritePtr[0] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 1); draw_list._IdxWritePtr[1] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 6); draw_list._IdxWritePtr[2] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 5); draw_list._IdxWritePtr += 3; draw_list._IdxWritePtr[0] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 2); draw_list._IdxWritePtr[1] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 3); draw_list._IdxWritePtr[2] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 7); draw_list._IdxWritePtr += 3; draw_list._IdxWritePtr[0] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 2); draw_list._IdxWritePtr[1] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 7); draw_list._IdxWritePtr[2] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 6); draw_list._IdxWritePtr += 3; draw_list._IdxWritePtr[0] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 3); draw_list._IdxWritePtr[1] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 0); draw_list._IdxWritePtr[2] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 4); draw_list._IdxWritePtr += 3; draw_list._IdxWritePtr[0] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 3); draw_list._IdxWritePtr[1] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 4); draw_list._IdxWritePtr[2] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 7); draw_list._IdxWritePtr += 3; draw_list._VtxCurrentIdx += 8; } //----------------------------------------------------------------------------- // [SECTION] Item Utils //----------------------------------------------------------------------------- ImPlotItem* RegisterOrGetItem(const char* label_id, ImPlotItemFlags flags, bool* just_created) { ImPlotContext& gp = *GImPlot; ImPlotItemGroup& Items = *gp.CurrentItems; ImGuiID id = Items.GetItemID(label_id); if (just_created != nullptr) *just_created = Items.GetItem(id) == nullptr; ImPlotItem* item = Items.GetOrAddItem(id); if (item->SeenThisFrame) return item; item->SeenThisFrame = true; int idx = Items.GetItemIndex(item); item->ID = id; if (!ImHasFlag(flags, ImPlotItemFlags_NoLegend) && ImGui::FindRenderedTextEnd(label_id, nullptr) != label_id) { 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; } return item; } ImPlotItem* GetItem(const char* label_id) { ImPlotContext& gp = *GImPlot; return gp.CurrentItems->GetItem(label_id); } bool IsItemHidden(const char* label_id) { ImPlotItem* item = GetItem(label_id); return item != nullptr && !item->Show; } ImPlotItem* GetCurrentItem() { ImPlotContext& gp = *GImPlot; return gp.CurrentItem; } void SetNextLineStyle(const ImVec4& col, float weight) { ImPlotContext& gp = *GImPlot; gp.NextItemData.Colors[ImPlotCol_Line] = col; gp.NextItemData.LineWeight = weight; } void SetNextFillStyle(const ImVec4& col, float alpha) { ImPlotContext& gp = *GImPlot; gp.NextItemData.Colors[ImPlotCol_Fill] = col; gp.NextItemData.FillAlpha = alpha; } void SetNextMarkerStyle(ImPlotMarker marker, float size, const ImVec4& fill, float weight, const ImVec4& outline) { ImPlotContext& gp = *GImPlot; gp.NextItemData.Marker = marker; gp.NextItemData.Colors[ImPlotCol_MarkerFill] = fill; gp.NextItemData.MarkerSize = size; gp.NextItemData.Colors[ImPlotCol_MarkerOutline] = outline; gp.NextItemData.MarkerWeight = weight; } void SetNextErrorBarStyle(const ImVec4& col, float size, float weight) { ImPlotContext& gp = *GImPlot; gp.NextItemData.Colors[ImPlotCol_ErrorBar] = col; gp.NextItemData.ErrorBarSize = size; gp.NextItemData.ErrorBarWeight = weight; } ImVec4 GetLastItemColor() { ImPlotContext& gp = *GImPlot; if (gp.PreviousItem) return ImGui::ColorConvertU32ToFloat4(gp.PreviousItem->Color); return ImVec4(); } void BustItemCache() { ImPlotContext& gp = *GImPlot; for (int p = 0; p < gp.Plots.GetBufSize(); ++p) { ImPlotPlot& plot = *gp.Plots.GetByIndex(p); plot.Items.Reset(); } for (int p = 0; p < gp.Subplots.GetBufSize(); ++p) { ImPlotSubplot& subplot = *gp.Subplots.GetByIndex(p); subplot.Items.Reset(); } } void BustColorCache(const char* plot_title_id) { ImPlotContext& gp = *GImPlot; if (plot_title_id == nullptr) { BustItemCache(); } else { ImGuiID id = ImGui::GetCurrentWindow()->GetID(plot_title_id); ImPlotPlot* plot = gp.Plots.GetByKey(id); if (plot != nullptr) plot->Items.Reset(); else { ImPlotSubplot* subplot = gp.Subplots.GetByKey(id); if (subplot != nullptr) subplot->Items.Reset(); } } } //----------------------------------------------------------------------------- // [SECTION] BeginItem / 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, ImPlotItemFlags flags, ImPlotCol recolor_from) { ImPlotContext& gp = *GImPlot; IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr, "PlotX() needs to be called between BeginPlot() and EndPlot()!"); SetupLock(); bool just_created; ImPlotItem* item = RegisterOrGetItem(label_id, flags, &just_created); // set current item gp.CurrentItem = item; ImPlotNextItemData& s = gp.NextItemData; // set/override item color if (recolor_from != -1) { if (!IsColorAuto(s.Colors[recolor_from])) item->Color = ImGui::ColorConvertFloat4ToU32(s.Colors[recolor_from]); else if (!IsColorAuto(gp.Style.Colors[recolor_from])) item->Color = ImGui::ColorConvertFloat4ToU32(gp.Style.Colors[recolor_from]); else if (just_created) item->Color = NextColormapColorU32(); } else if (just_created) { item->Color = NextColormapColorU32(); } // hide/show item if (gp.NextItemData.HasHidden) { if (just_created || gp.NextItemData.HiddenCond == ImGuiCond_Always) item->Show = !gp.NextItemData.Hidden; } if (!item->Show) { // reset next item data gp.NextItemData.Reset(); gp.PreviousItem = item; gp.CurrentItem = nullptr; return false; } else { ImVec4 item_color = ImGui::ColorConvertU32ToFloat4(item->Color); // stage next item colors s.Colors[ImPlotCol_Line] = IsColorAuto(s.Colors[ImPlotCol_Line]) ? ( IsColorAuto(ImPlotCol_Line) ? item_color : gp.Style.Colors[ImPlotCol_Line] ) : s.Colors[ImPlotCol_Line]; s.Colors[ImPlotCol_Fill] = IsColorAuto(s.Colors[ImPlotCol_Fill]) ? ( IsColorAuto(ImPlotCol_Fill) ? item_color : gp.Style.Colors[ImPlotCol_Fill] ) : s.Colors[ImPlotCol_Fill]; s.Colors[ImPlotCol_MarkerOutline] = IsColorAuto(s.Colors[ImPlotCol_MarkerOutline]) ? ( IsColorAuto(ImPlotCol_MarkerOutline) ? s.Colors[ImPlotCol_Line] : gp.Style.Colors[ImPlotCol_MarkerOutline] ) : s.Colors[ImPlotCol_MarkerOutline]; s.Colors[ImPlotCol_MarkerFill] = IsColorAuto(s.Colors[ImPlotCol_MarkerFill]) ? ( IsColorAuto(ImPlotCol_MarkerFill) ? s.Colors[ImPlotCol_Line] : gp.Style.Colors[ImPlotCol_MarkerFill] ) : s.Colors[ImPlotCol_MarkerFill]; s.Colors[ImPlotCol_ErrorBar] = IsColorAuto(s.Colors[ImPlotCol_ErrorBar]) ? ( GetStyleColorVec4(ImPlotCol_ErrorBar) ) : s.Colors[ImPlotCol_ErrorBar]; // stage next item style vars s.LineWeight = s.LineWeight < 0 ? gp.Style.LineWeight : s.LineWeight; s.Marker = s.Marker < 0 ? gp.Style.Marker : s.Marker; s.MarkerSize = s.MarkerSize < 0 ? gp.Style.MarkerSize : s.MarkerSize; s.MarkerWeight = s.MarkerWeight < 0 ? gp.Style.MarkerWeight : s.MarkerWeight; s.FillAlpha = s.FillAlpha < 0 ? gp.Style.FillAlpha : s.FillAlpha; s.ErrorBarSize = s.ErrorBarSize < 0 ? gp.Style.ErrorBarSize : s.ErrorBarSize; s.ErrorBarWeight = s.ErrorBarWeight < 0 ? gp.Style.ErrorBarWeight : s.ErrorBarWeight; s.DigitalBitHeight = s.DigitalBitHeight < 0 ? gp.Style.DigitalBitHeight : s.DigitalBitHeight; 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 // apply highlight mods 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; s.RenderFill = s.Colors[ImPlotCol_Fill].w > 0; s.RenderMarkerFill = s.Colors[ImPlotCol_MarkerFill].w > 0; s.RenderMarkerLine = s.Colors[ImPlotCol_MarkerOutline].w > 0 && s.MarkerWeight > 0; // push rendering clip rect PushPlotClipRect(); return true; } } // Ends an item (call only if BeginItem returns true) void EndItem() { ImPlotContext& gp = *GImPlot; // pop rendering clip rect PopPlotClipRect(); // reset next item data gp.NextItemData.Reset(); // set current item gp.PreviousItem = gp.CurrentItem; gp.CurrentItem = nullptr; } //----------------------------------------------------------------------------- // [SECTION] Indexers //----------------------------------------------------------------------------- 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); } } template <typename T> struct IndexerIdx { IndexerIdx(const T* data, int count, int offset = 0, int stride = sizeof(T)) : Data(data), Count(count), Offset(count ? ImPosMod(offset, count) : 0), Stride(stride) { } template <typename I> IMPLOT_INLINE double operator()(I idx) const { return (double)IndexData(Data, idx, Count, Offset, Stride); } const T* Data; int Count; int Offset; int Stride; }; template <typename _Indexer1, typename _Indexer2> struct IndexerAdd { IndexerAdd(const _Indexer1& indexer1, const _Indexer2& indexer2, double scale1 = 1, double scale2 = 1) : Indexer1(indexer1), Indexer2(indexer2), Scale1(scale1), Scale2(scale2), Count(ImMin(Indexer1.Count, Indexer2.Count)) { } template <typename I> IMPLOT_INLINE double operator()(I idx) const { return Scale1 * Indexer1(idx) + Scale2 * Indexer2(idx); } const _Indexer1& Indexer1; const _Indexer2& Indexer2; double Scale1; double Scale2; int Count; }; struct IndexerLin { IndexerLin(double m, double b) : M(m), B(b) { } template <typename I> IMPLOT_INLINE double operator()(I idx) const { return M * idx + B; } const double M; const double B; }; struct IndexerConst { IndexerConst(double ref) : Ref(ref) { } template <typename I> IMPLOT_INLINE double operator()(I) const { return Ref; } const double Ref; }; //----------------------------------------------------------------------------- // [SECTION] Getters //----------------------------------------------------------------------------- template <typename _IndexerX, typename _IndexerY> struct GetterXY { GetterXY(_IndexerX x, _IndexerY y, int count) : IndxerX(x), IndxerY(y), Count(count) { } template <typename I> IMPLOT_INLINE ImPlotPoint operator()(I idx) const { return ImPlotPoint(IndxerX(idx),IndxerY(idx)); } const _IndexerX IndxerX; const _IndexerY IndxerY; const int Count; }; /// Interprets a user's function pointer as ImPlotPoints struct GetterFuncPtr { GetterFuncPtr(ImPlotGetter getter, void* data, int count) : Getter(getter), Data(data), Count(count) { } template <typename I> IMPLOT_INLINE ImPlotPoint operator()(I idx) const { return Getter(idx, Data); } ImPlotGetter Getter; void* const Data; const int Count; }; template <typename _Getter> struct GetterOverrideX { GetterOverrideX(_Getter 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 _Getter Getter; const double X; const int Count; }; template <typename _Getter> struct GetterOverrideY { GetterOverrideY(_Getter 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 _Getter Getter; const double Y; const int Count; }; template <typename _Getter> struct GetterLoop { GetterLoop(_Getter getter) : Getter(getter), Count(getter.Count + 1) { } template <typename I> IMPLOT_INLINE ImPlotPoint operator()(I idx) const { idx = idx % (Count - 1); return Getter(idx); } const _Getter Getter; const int Count; }; template <typename T> struct GetterError { GetterError(const T* xs, const T* ys, const T* neg, const T* pos, int count, int offset, int stride) : Xs(xs), Ys(ys), Neg(neg), Pos(pos), Count(count), Offset(count ? ImPosMod(offset, count) : 0), Stride(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; const T* const Neg; const T* const Pos; const int Count; const int Offset; const int Stride; }; //----------------------------------------------------------------------------- // [SECTION] Fitters //----------------------------------------------------------------------------- template <typename _Getter1> struct Fitter1 { Fitter1(const _Getter1& getter) : Getter(getter) { } void Fit(ImPlotAxis& x_axis, ImPlotAxis& y_axis) const { for (int i = 0; i < Getter.Count; ++i) { ImPlotPoint p = Getter(i); x_axis.ExtendFitWith(y_axis, p.x, p.y); y_axis.ExtendFitWith(x_axis, p.y, p.x); } } const _Getter1& Getter; }; template <typename _Getter1> struct FitterX { FitterX(const _Getter1& getter) : Getter(getter) { } void Fit(ImPlotAxis& x_axis, ImPlotAxis&) const { for (int i = 0; i < Getter.Count; ++i) { ImPlotPoint p = Getter(i); x_axis.ExtendFit(p.x); } } const _Getter1& Getter; }; template <typename _Getter1> struct FitterY { FitterY(const _Getter1& getter) : Getter(getter) { } void Fit(ImPlotAxis&, ImPlotAxis& y_axis) const { for (int i = 0; i < Getter.Count; ++i) { ImPlotPoint p = Getter(i); y_axis.ExtendFit(p.y); } } const _Getter1& Getter; }; template <typename _Getter1, typename _Getter2> struct Fitter2 { Fitter2(const _Getter1& getter1, const _Getter2& getter2) : Getter1(getter1), Getter2(getter2) { } void Fit(ImPlotAxis& x_axis, ImPlotAxis& y_axis) const { for (int i = 0; i < Getter1.Count; ++i) { ImPlotPoint p = Getter1(i); x_axis.ExtendFitWith(y_axis, p.x, p.y); y_axis.ExtendFitWith(x_axis, p.y, p.x); } for (int i = 0; i < Getter2.Count; ++i) { ImPlotPoint p = Getter2(i); x_axis.ExtendFitWith(y_axis, p.x, p.y); y_axis.ExtendFitWith(x_axis, p.y, p.x); } } const _Getter1& Getter1; const _Getter2& Getter2; }; template <typename _Getter1, typename _Getter2> struct FitterBarV { FitterBarV(const _Getter1& getter1, const _Getter2& getter2, double width) : Getter1(getter1), Getter2(getter2), HalfWidth(width*0.5) { } void Fit(ImPlotAxis& x_axis, ImPlotAxis& y_axis) const { int count = ImMin(Getter1.Count, Getter2.Count); for (int i = 0; i < count; ++i) { ImPlotPoint p1 = Getter1(i); p1.x -= HalfWidth; ImPlotPoint p2 = Getter2(i); p2.x += HalfWidth; x_axis.ExtendFitWith(y_axis, p1.x, p1.y); y_axis.ExtendFitWith(x_axis, p1.y, p1.x); x_axis.ExtendFitWith(y_axis, p2.x, p2.y); y_axis.ExtendFitWith(x_axis, p2.y, p2.x); } } const _Getter1& Getter1; const _Getter2& Getter2; const double HalfWidth; }; template <typename _Getter1, typename _Getter2> struct FitterBarH { FitterBarH(const _Getter1& getter1, const _Getter2& getter2, double height) : Getter1(getter1), Getter2(getter2), HalfHeight(height*0.5) { } void Fit(ImPlotAxis& x_axis, ImPlotAxis& y_axis) const { int count = ImMin(Getter1.Count, Getter2.Count); for (int i = 0; i < count; ++i) { ImPlotPoint p1 = Getter1(i); p1.y -= HalfHeight; ImPlotPoint p2 = Getter2(i); p2.y += HalfHeight; x_axis.ExtendFitWith(y_axis, p1.x, p1.y); y_axis.ExtendFitWith(x_axis, p1.y, p1.x); x_axis.ExtendFitWith(y_axis, p2.x, p2.y); y_axis.ExtendFitWith(x_axis, p2.y, p2.x); } } const _Getter1& Getter1; const _Getter2& Getter2; const double HalfHeight; }; struct FitterRect { FitterRect(const ImPlotPoint& pmin, const ImPlotPoint& pmax) : Pmin(pmin), Pmax(pmax) { } FitterRect(const ImPlotRect& rect) : FitterRect(rect.Min(), rect.Max()) { } void Fit(ImPlotAxis& x_axis, ImPlotAxis& y_axis) const { x_axis.ExtendFitWith(y_axis, Pmin.x, Pmin.y); y_axis.ExtendFitWith(x_axis, Pmin.y, Pmin.x); x_axis.ExtendFitWith(y_axis, Pmax.x, Pmax.y); y_axis.ExtendFitWith(x_axis, Pmax.y, Pmax.x); } const ImPlotPoint Pmin; const ImPlotPoint Pmax; }; //----------------------------------------------------------------------------- // [SECTION] Transformers //----------------------------------------------------------------------------- struct Transformer1 { Transformer1(double pixMin, double pltMin, double pltMax, double m, double scaMin, double scaMax, ImPlotTransform fwd, void* data) : ScaMin(scaMin), ScaMax(scaMax), PltMin(pltMin), PltMax(pltMax), PixMin(pixMin), M(m), TransformFwd(fwd), TransformData(data) { } template <typename T> IMPLOT_INLINE float operator()(T p) const { if (TransformFwd != nullptr) { double s = TransformFwd(p, TransformData); double t = (s - ScaMin) / (ScaMax - ScaMin); p = PltMin + (PltMax - PltMin) * t; } return (float)(PixMin + M * (p - PltMin)); } double ScaMin, ScaMax, PltMin, PltMax, PixMin, M; ImPlotTransform TransformFwd; void* TransformData; }; struct Transformer2 { Transformer2(const ImPlotAxis& x_axis, const ImPlotAxis& y_axis) : Tx(x_axis.PixelMin, x_axis.Range.Min, x_axis.Range.Max, x_axis.ScaleToPixel, x_axis.ScaleMin, x_axis.ScaleMax, x_axis.TransformForward, x_axis.TransformData), Ty(y_axis.PixelMin, y_axis.Range.Min, y_axis.Range.Max, y_axis.ScaleToPixel, y_axis.ScaleMin, y_axis.ScaleMax, y_axis.TransformForward, y_axis.TransformData) { } Transformer2(const ImPlotPlot& plot) : Transformer2(plot.Axes[plot.CurrentX], plot.Axes[plot.CurrentY]) { } Transformer2() : Transformer2(*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; } template <typename T> IMPLOT_INLINE ImVec2 operator()(T x, T y) const { ImVec2 out; out.x = Tx(x); out.y = Ty(y); return out; } Transformer1 Tx; Transformer1 Ty; }; //----------------------------------------------------------------------------- // [SECTION] Renderers //----------------------------------------------------------------------------- struct RendererBase { RendererBase(int prims, int idx_consumed, int vtx_consumed) : Prims(prims), IdxConsumed(idx_consumed), VtxConsumed(vtx_consumed) { } const int Prims; Transformer2 Transformer; const int IdxConsumed; const int VtxConsumed; }; template <class _Getter> struct RendererLineStrip : RendererBase { RendererLineStrip(const _Getter& getter, ImU32 col, float weight) : RendererBase(getter.Count - 1, 6, 4), Getter(getter), Col(col), HalfWeight(ImMax(1.0f,weight)*0.5f) { P1 = this->Transformer(Getter(0)); } void Init(ImDrawList& draw_list) const { GetLineRenderProps(draw_list, HalfWeight, UV0, UV1); } IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { ImVec2 P2 = this->Transformer(Getter(prim + 1)); if (!cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2)))) { P1 = P2; return false; } PrimLine(draw_list,P1,P2,HalfWeight,Col,UV0,UV1); P1 = P2; return true; } const _Getter& Getter; const ImU32 Col; mutable float HalfWeight; mutable ImVec2 P1; mutable ImVec2 UV0; mutable ImVec2 UV1; }; template <class _Getter> struct RendererLineStripSkip : RendererBase { RendererLineStripSkip(const _Getter& getter, ImU32 col, float weight) : RendererBase(getter.Count - 1, 6, 4), Getter(getter), Col(col), HalfWeight(ImMax(1.0f,weight)*0.5f) { P1 = this->Transformer(Getter(0)); } void Init(ImDrawList& draw_list) const { GetLineRenderProps(draw_list, HalfWeight, UV0, UV1); } IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { ImVec2 P2 = this->Transformer(Getter(prim + 1)); if (!cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2)))) { if (!ImNan(P2.x) && !ImNan(P2.y)) P1 = P2; return false; } PrimLine(draw_list,P1,P2,HalfWeight,Col,UV0,UV1); if (!ImNan(P2.x) && !ImNan(P2.y)) P1 = P2; return true; } const _Getter& Getter; const ImU32 Col; mutable float HalfWeight; mutable ImVec2 P1; mutable ImVec2 UV0; mutable ImVec2 UV1; }; template <class _Getter> struct RendererLineSegments1 : RendererBase { RendererLineSegments1(const _Getter& getter, ImU32 col, float weight) : RendererBase(getter.Count / 2, 6, 4), Getter(getter), Col(col), HalfWeight(ImMax(1.0f,weight)*0.5f) { } void Init(ImDrawList& draw_list) const { GetLineRenderProps(draw_list, HalfWeight, UV0, UV1); } IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { ImVec2 P1 = this->Transformer(Getter(prim*2+0)); ImVec2 P2 = this->Transformer(Getter(prim*2+1)); if (!cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2)))) return false; PrimLine(draw_list,P1,P2,HalfWeight,Col,UV0,UV1); return true; } const _Getter& Getter; const ImU32 Col; mutable float HalfWeight; mutable ImVec2 UV0; mutable ImVec2 UV1; }; template <class _Getter1, class _Getter2> struct RendererLineSegments2 : RendererBase { RendererLineSegments2(const _Getter1& getter1, const _Getter2& getter2, ImU32 col, float weight) : RendererBase(ImMin(getter1.Count, getter1.Count), 6, 4), Getter1(getter1), Getter2(getter2), Col(col), HalfWeight(ImMax(1.0f,weight)*0.5f) {} void Init(ImDrawList& draw_list) const { GetLineRenderProps(draw_list, HalfWeight, UV0, UV1); } IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { ImVec2 P1 = this->Transformer(Getter1(prim)); ImVec2 P2 = this->Transformer(Getter2(prim)); if (!cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2)))) return false; PrimLine(draw_list,P1,P2,HalfWeight,Col,UV0,UV1); return true; } const _Getter1& Getter1; const _Getter2& Getter2; const ImU32 Col; mutable float HalfWeight; mutable ImVec2 UV0; mutable ImVec2 UV1; }; template <class _Getter1, class _Getter2> struct RendererBarsFillV : RendererBase { RendererBarsFillV(const _Getter1& getter1, const _Getter2& getter2, ImU32 col, double width) : RendererBase(ImMin(getter1.Count, getter1.Count), 6, 4), Getter1(getter1), Getter2(getter2), Col(col), HalfWidth(width/2) {} void Init(ImDrawList& draw_list) const { UV = draw_list._Data->TexUvWhitePixel; } IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { ImPlotPoint p1 = Getter1(prim); ImPlotPoint p2 = Getter2(prim); p1.x += HalfWidth; p2.x -= HalfWidth; ImVec2 P1 = this->Transformer(p1); ImVec2 P2 = this->Transformer(p2); float width_px = ImAbs(P1.x-P2.x); if (width_px < 1.0f) { P1.x += P1.x > P2.x ? (1-width_px) / 2 : (width_px-1) / 2; P2.x += P2.x > P1.x ? (1-width_px) / 2 : (width_px-1) / 2; } ImVec2 PMin = ImMin(P1, P2); ImVec2 PMax = ImMax(P1, P2); if (!cull_rect.Overlaps(ImRect(PMin, PMax))) return false; PrimRectFill(draw_list,PMin,PMax,Col,UV); return true; } const _Getter1& Getter1; const _Getter2& Getter2; const ImU32 Col; const double HalfWidth; mutable ImVec2 UV; }; template <class _Getter1, class _Getter2> struct RendererBarsFillH : RendererBase { RendererBarsFillH(const _Getter1& getter1, const _Getter2& getter2, ImU32 col, double height) : RendererBase(ImMin(getter1.Count, getter1.Count), 6, 4), Getter1(getter1), Getter2(getter2), Col(col), HalfHeight(height/2) {} void Init(ImDrawList& draw_list) const { UV = draw_list._Data->TexUvWhitePixel; } IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { ImPlotPoint p1 = Getter1(prim); ImPlotPoint p2 = Getter2(prim); p1.y += HalfHeight; p2.y -= HalfHeight; ImVec2 P1 = this->Transformer(p1); ImVec2 P2 = this->Transformer(p2); float height_px = ImAbs(P1.y-P2.y); if (height_px < 1.0f) { P1.y += P1.y > P2.y ? (1-height_px) / 2 : (height_px-1) / 2; P2.y += P2.y > P1.y ? (1-height_px) / 2 : (height_px-1) / 2; } ImVec2 PMin = ImMin(P1, P2); ImVec2 PMax = ImMax(P1, P2); if (!cull_rect.Overlaps(ImRect(PMin, PMax))) return false; PrimRectFill(draw_list,PMin,PMax,Col,UV); return true; } const _Getter1& Getter1; const _Getter2& Getter2; const ImU32 Col; const double HalfHeight; mutable ImVec2 UV; }; template <class _Getter1, class _Getter2> struct RendererBarsLineV : RendererBase { RendererBarsLineV(const _Getter1& getter1, const _Getter2& getter2, ImU32 col, double width, float weight) : RendererBase(ImMin(getter1.Count, getter1.Count), 24, 8), Getter1(getter1), Getter2(getter2), Col(col), HalfWidth(width/2), Weight(weight) {} void Init(ImDrawList& draw_list) const { UV = draw_list._Data->TexUvWhitePixel; } IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { ImPlotPoint p1 = Getter1(prim); ImPlotPoint p2 = Getter2(prim); p1.x += HalfWidth; p2.x -= HalfWidth; ImVec2 P1 = this->Transformer(p1); ImVec2 P2 = this->Transformer(p2); float width_px = ImAbs(P1.x-P2.x); if (width_px < 1.0f) { P1.x += P1.x > P2.x ? (1-width_px) / 2 : (width_px-1) / 2; P2.x += P2.x > P1.x ? (1-width_px) / 2 : (width_px-1) / 2; } ImVec2 PMin = ImMin(P1, P2); ImVec2 PMax = ImMax(P1, P2); if (!cull_rect.Overlaps(ImRect(PMin, PMax))) return false; PrimRectLine(draw_list,PMin,PMax,Weight,Col,UV); return true; } const _Getter1& Getter1; const _Getter2& Getter2; const ImU32 Col; const double HalfWidth; const float Weight; mutable ImVec2 UV; }; template <class _Getter1, class _Getter2> struct RendererBarsLineH : RendererBase { RendererBarsLineH(const _Getter1& getter1, const _Getter2& getter2, ImU32 col, double height, float weight) : RendererBase(ImMin(getter1.Count, getter1.Count), 24, 8), Getter1(getter1), Getter2(getter2), Col(col), HalfHeight(height/2), Weight(weight) {} void Init(ImDrawList& draw_list) const { UV = draw_list._Data->TexUvWhitePixel; } IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { ImPlotPoint p1 = Getter1(prim); ImPlotPoint p2 = Getter2(prim); p1.y += HalfHeight; p2.y -= HalfHeight; ImVec2 P1 = this->Transformer(p1); ImVec2 P2 = this->Transformer(p2); float height_px = ImAbs(P1.y-P2.y); if (height_px < 1.0f) { P1.y += P1.y > P2.y ? (1-height_px) / 2 : (height_px-1) / 2; P2.y += P2.y > P1.y ? (1-height_px) / 2 : (height_px-1) / 2; } ImVec2 PMin = ImMin(P1, P2); ImVec2 PMax = ImMax(P1, P2); if (!cull_rect.Overlaps(ImRect(PMin, PMax))) return false; PrimRectLine(draw_list,PMin,PMax,Weight,Col,UV); return true; } const _Getter1& Getter1; const _Getter2& Getter2; const ImU32 Col; const double HalfHeight; const float Weight; mutable ImVec2 UV; }; template <class _Getter> struct RendererStairsPre : RendererBase { RendererStairsPre(const _Getter& getter, ImU32 col, float weight) : RendererBase(getter.Count - 1, 12, 8), Getter(getter), Col(col), HalfWeight(ImMax(1.0f,weight)*0.5f) { P1 = this->Transformer(Getter(0)); } void Init(ImDrawList& draw_list) const { UV = draw_list._Data->TexUvWhitePixel; } IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { ImVec2 P2 = this->Transformer(Getter(prim + 1)); if (!cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2)))) { P1 = P2; return false; } PrimRectFill(draw_list, ImVec2(P1.x - HalfWeight, P1.y), ImVec2(P1.x + HalfWeight, P2.y), Col, UV); PrimRectFill(draw_list, ImVec2(P1.x, P2.y + HalfWeight), ImVec2(P2.x, P2.y - HalfWeight), Col, UV); P1 = P2; return true; } const _Getter& Getter; const ImU32 Col; mutable float HalfWeight; mutable ImVec2 P1; mutable ImVec2 UV; }; template <class _Getter> struct RendererStairsPost : RendererBase { RendererStairsPost(const _Getter& getter, ImU32 col, float weight) : RendererBase(getter.Count - 1, 12, 8), Getter(getter), Col(col), HalfWeight(ImMax(1.0f,weight) * 0.5f) { P1 = this->Transformer(Getter(0)); } void Init(ImDrawList& draw_list) const { UV = draw_list._Data->TexUvWhitePixel; } IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { ImVec2 P2 = this->Transformer(Getter(prim + 1)); if (!cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2)))) { P1 = P2; return false; } PrimRectFill(draw_list, ImVec2(P1.x, P1.y + HalfWeight), ImVec2(P2.x, P1.y - HalfWeight), Col, UV); PrimRectFill(draw_list, ImVec2(P2.x - HalfWeight, P2.y), ImVec2(P2.x + HalfWeight, P1.y), Col, UV); P1 = P2; return true; } const _Getter& Getter; const ImU32 Col; mutable float HalfWeight; mutable ImVec2 P1; mutable ImVec2 UV; }; template <class _Getter> struct RendererStairsPreShaded : RendererBase { RendererStairsPreShaded(const _Getter& getter, ImU32 col) : RendererBase(getter.Count - 1, 6, 4), Getter(getter), Col(col) { P1 = this->Transformer(Getter(0)); Y0 = this->Transformer(ImPlotPoint(0,0)).y; } void Init(ImDrawList& draw_list) const { UV = draw_list._Data->TexUvWhitePixel; } IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { ImVec2 P2 = this->Transformer(Getter(prim + 1)); ImVec2 PMin(ImMin(P1.x, P2.x), ImMin(Y0, P2.y)); ImVec2 PMax(ImMax(P1.x, P2.x), ImMax(Y0, P2.y)); if (!cull_rect.Overlaps(ImRect(PMin, PMax))) { P1 = P2; return false; } PrimRectFill(draw_list, PMin, PMax, Col, UV); P1 = P2; return true; } const _Getter& Getter; const ImU32 Col; float Y0; mutable ImVec2 P1; mutable ImVec2 UV; }; template <class _Getter> struct RendererStairsPostShaded : RendererBase { RendererStairsPostShaded(const _Getter& getter, ImU32 col) : RendererBase(getter.Count - 1, 6, 4), Getter(getter), Col(col) { P1 = this->Transformer(Getter(0)); Y0 = this->Transformer(ImPlotPoint(0,0)).y; } void Init(ImDrawList& draw_list) const { UV = draw_list._Data->TexUvWhitePixel; } IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { ImVec2 P2 = this->Transformer(Getter(prim + 1)); ImVec2 PMin(ImMin(P1.x, P2.x), ImMin(P1.y, Y0)); ImVec2 PMax(ImMax(P1.x, P2.x), ImMax(P1.y, Y0)); if (!cull_rect.Overlaps(ImRect(PMin, PMax))) { P1 = P2; return false; } PrimRectFill(draw_list, PMin, PMax, Col, UV); P1 = P2; return true; } const _Getter& Getter; const ImU32 Col; float Y0; mutable ImVec2 P1; mutable ImVec2 UV; }; template <class _Getter1, class _Getter2> struct RendererShaded : RendererBase { RendererShaded(const _Getter1& getter1, const _Getter2& getter2, ImU32 col) : RendererBase(ImMin(getter1.Count, getter2.Count) - 1, 6, 5), Getter1(getter1), Getter2(getter2), Col(col) { P11 = this->Transformer(Getter1(0)); P12 = this->Transformer(Getter2(0)); } void Init(ImDrawList& draw_list) const { UV = draw_list._Data->TexUvWhitePixel; } IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { ImVec2 P21 = this->Transformer(Getter1(prim+1)); ImVec2 P22 = this->Transformer(Getter2(prim+1)); ImRect rect(ImMin(ImMin(ImMin(P11,P12),P21),P22), ImMax(ImMax(ImMax(P11,P12),P21),P22)); if (!cull_rect.Overlaps(rect)) { P11 = P21; P12 = P22; return false; } const int intersect = (P11.y > P12.y && P22.y > P21.y) || (P12.y > P11.y && P21.y > P22.y); const ImVec2 intersection = intersect == 0 ? ImVec2(0,0) : Intersection(P11,P21,P12,P22); draw_list._VtxWritePtr[0].pos = P11; draw_list._VtxWritePtr[0].uv = UV; draw_list._VtxWritePtr[0].col = Col; draw_list._VtxWritePtr[1].pos = P21; draw_list._VtxWritePtr[1].uv = UV; draw_list._VtxWritePtr[1].col = Col; draw_list._VtxWritePtr[2].pos = intersection; draw_list._VtxWritePtr[2].uv = UV; draw_list._VtxWritePtr[2].col = Col; draw_list._VtxWritePtr[3].pos = P12; draw_list._VtxWritePtr[3].uv = UV; draw_list._VtxWritePtr[3].col = Col; draw_list._VtxWritePtr[4].pos = P22; draw_list._VtxWritePtr[4].uv = UV; draw_list._VtxWritePtr[4].col = Col; draw_list._VtxWritePtr += 5; draw_list._IdxWritePtr[0] = (ImDrawIdx)(draw_list._VtxCurrentIdx); draw_list._IdxWritePtr[1] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 1 + intersect); draw_list._IdxWritePtr[2] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 3); draw_list._IdxWritePtr[3] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 1); draw_list._IdxWritePtr[4] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 4); draw_list._IdxWritePtr[5] = (ImDrawIdx)(draw_list._VtxCurrentIdx + 3 - intersect); draw_list._IdxWritePtr += 6; draw_list._VtxCurrentIdx += 5; P11 = P21; P12 = P22; return true; } const _Getter1& Getter1; const _Getter2& Getter2; const ImU32 Col; mutable ImVec2 P11; mutable ImVec2 P12; mutable ImVec2 UV; }; struct RectC { ImPlotPoint Pos; ImPlotPoint HalfSize; ImU32 Color; }; template <typename _Getter> struct RendererRectC : RendererBase { RendererRectC(const _Getter& getter) : RendererBase(getter.Count, 6, 4), Getter(getter) {} void Init(ImDrawList& draw_list) const { UV = draw_list._Data->TexUvWhitePixel; } IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { RectC rect = Getter(prim); ImVec2 P1 = this->Transformer(rect.Pos.x - rect.HalfSize.x , rect.Pos.y - rect.HalfSize.y); ImVec2 P2 = this->Transformer(rect.Pos.x + rect.HalfSize.x , rect.Pos.y + rect.HalfSize.y); if ((rect.Color & IM_COL32_A_MASK) == 0 || !cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2)))) return false; PrimRectFill(draw_list,P1,P2,rect.Color,UV); return true; } const _Getter& Getter; mutable ImVec2 UV; }; //----------------------------------------------------------------------------- // [SECTION] RenderPrimitives //----------------------------------------------------------------------------- /// Renders primitive shapes in bulk as efficiently as possible. template <class _Renderer> void RenderPrimitivesEx(const _Renderer& renderer, ImDrawList& draw_list, const ImRect& cull_rect) { unsigned int prims = renderer.Prims; unsigned int prims_culled = 0; unsigned int idx = 0; renderer.Init(draw_list); while (prims) { // find how many can be reserved up to end of current draw command's limit unsigned int cnt = ImMin(prims, (MaxIdx<ImDrawIdx>::Value - draw_list._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(64u, prims)) { if (prims_culled >= cnt) prims_culled -= cnt; // reuse previous reservation else { // add more elements to previous reservation draw_list.PrimReserve((cnt - prims_culled) * renderer.IdxConsumed, (cnt - prims_culled) * renderer.VtxConsumed); prims_culled = 0; } } else { if (prims_culled > 0) { draw_list.PrimUnreserve(prims_culled * renderer.IdxConsumed, prims_culled * renderer.VtxConsumed); prims_culled = 0; } cnt = ImMin(prims, (MaxIdx<ImDrawIdx>::Value - 0/*draw_list._VtxCurrentIdx*/) / renderer.VtxConsumed); // reserve new draw command draw_list.PrimReserve(cnt * renderer.IdxConsumed, cnt * renderer.VtxConsumed); } prims -= cnt; for (unsigned int ie = idx + cnt; idx != ie; ++idx) { if (!renderer.Render(draw_list, cull_rect, idx)) prims_culled++; } } if (prims_culled > 0) draw_list.PrimUnreserve(prims_culled * renderer.IdxConsumed, prims_culled * renderer.VtxConsumed); } template <template <class> class _Renderer, class _Getter, typename ...Args> void RenderPrimitives1(const _Getter& getter, Args... args) { ImDrawList& draw_list = *GetPlotDrawList(); const ImRect& cull_rect = GetCurrentPlot()->PlotRect; RenderPrimitivesEx(_Renderer<_Getter>(getter,args...), draw_list, cull_rect); } template <template <class,class> class _Renderer, class _Getter1, class _Getter2, typename ...Args> void RenderPrimitives2(const _Getter1& getter1, const _Getter2& getter2, Args... args) { ImDrawList& draw_list = *GetPlotDrawList(); const ImRect& cull_rect = GetCurrentPlot()->PlotRect; RenderPrimitivesEx(_Renderer<_Getter1,_Getter2>(getter1,getter2,args...), draw_list, cull_rect); } //----------------------------------------------------------------------------- // [SECTION] Markers //----------------------------------------------------------------------------- template <class _Getter> struct RendererMarkersFill : RendererBase { RendererMarkersFill(const _Getter& getter, const ImVec2* marker, int count, float size, ImU32 col) : RendererBase(getter.Count, (count-2)*3, count), Getter(getter), Marker(marker), Count(count), Size(size), Col(col) { } void Init(ImDrawList& draw_list) const { UV = draw_list._Data->TexUvWhitePixel; } IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { ImVec2 p = this->Transformer(Getter(prim)); if (p.x >= cull_rect.Min.x && p.y >= cull_rect.Min.y && p.x <= cull_rect.Max.x && p.y <= cull_rect.Max.y) { for (int i = 0; i < Count; i++) { draw_list._VtxWritePtr[0].pos.x = p.x + Marker[i].x * Size; draw_list._VtxWritePtr[0].pos.y = p.y + Marker[i].y * Size; draw_list._VtxWritePtr[0].uv = UV; draw_list._VtxWritePtr[0].col = Col; draw_list._VtxWritePtr++; } for (int i = 2; i < Count; i++) { draw_list._IdxWritePtr[0] = (ImDrawIdx)(draw_list._VtxCurrentIdx); draw_list._IdxWritePtr[1] = (ImDrawIdx)(draw_list._VtxCurrentIdx + i - 1); draw_list._IdxWritePtr[2] = (ImDrawIdx)(draw_list._VtxCurrentIdx + i); draw_list._IdxWritePtr += 3; } draw_list._VtxCurrentIdx += (ImDrawIdx)Count; return true; } return false; } const _Getter& Getter; const ImVec2* Marker; const int Count; const float Size; const ImU32 Col; mutable ImVec2 UV; }; template <class _Getter> struct RendererMarkersLine : RendererBase { RendererMarkersLine(const _Getter& getter, const ImVec2* marker, int count, float size, float weight, ImU32 col) : RendererBase(getter.Count, count/2*6, count/2*4), Getter(getter), Marker(marker), Count(count), HalfWeight(ImMax(1.0f,weight)*0.5f), Size(size), Col(col) { } void Init(ImDrawList& draw_list) const { GetLineRenderProps(draw_list, HalfWeight, UV0, UV1); } IMPLOT_INLINE bool Render(ImDrawList& draw_list, const ImRect& cull_rect, int prim) const { ImVec2 p = this->Transformer(Getter(prim)); if (p.x >= cull_rect.Min.x && p.y >= cull_rect.Min.y && p.x <= cull_rect.Max.x && p.y <= cull_rect.Max.y) { for (int i = 0; i < Count; i = i + 2) { ImVec2 p1(p.x + Marker[i].x * Size, p.y + Marker[i].y * Size); ImVec2 p2(p.x + Marker[i+1].x * Size, p.y + Marker[i+1].y * Size); PrimLine(draw_list, p1, p2, HalfWeight, Col, UV0, UV1); } return true; } return false; } const _Getter& Getter; const ImVec2* Marker; const int Count; mutable float HalfWeight; const float Size; const ImU32 Col; mutable ImVec2 UV0; mutable ImVec2 UV1; }; static const ImVec2 MARKER_FILL_CIRCLE[10] = {ImVec2(1.0f, 0.0f), ImVec2(0.809017f, 0.58778524f),ImVec2(0.30901697f, 0.95105654f),ImVec2(-0.30901703f, 0.9510565f),ImVec2(-0.80901706f, 0.5877852f),ImVec2(-1.0f, 0.0f),ImVec2(-0.80901694f, -0.58778536f),ImVec2(-0.3090171f, -0.9510565f),ImVec2(0.30901712f, -0.9510565f),ImVec2(0.80901694f, -0.5877853f)}; static const ImVec2 MARKER_FILL_SQUARE[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)}; static const ImVec2 MARKER_FILL_DIAMOND[4] = {ImVec2(1, 0), ImVec2(0, -1), ImVec2(-1, 0), ImVec2(0, 1)}; static const ImVec2 MARKER_FILL_UP[3] = {ImVec2(SQRT_3_2,0.5f),ImVec2(0,-1),ImVec2(-SQRT_3_2,0.5f)}; static const ImVec2 MARKER_FILL_DOWN[3] = {ImVec2(SQRT_3_2,-0.5f),ImVec2(0,1),ImVec2(-SQRT_3_2,-0.5f)}; static const ImVec2 MARKER_FILL_LEFT[3] = {ImVec2(-1,0), ImVec2(0.5, SQRT_3_2), ImVec2(0.5, -SQRT_3_2)}; static const ImVec2 MARKER_FILL_RIGHT[3] = {ImVec2(1,0), ImVec2(-0.5, SQRT_3_2), ImVec2(-0.5, -SQRT_3_2)}; static const ImVec2 MARKER_LINE_CIRCLE[20] = { ImVec2(1.0f, 0.0f), ImVec2(0.809017f, 0.58778524f), ImVec2(0.809017f, 0.58778524f), ImVec2(0.30901697f, 0.95105654f), ImVec2(0.30901697f, 0.95105654f), ImVec2(-0.30901703f, 0.9510565f), ImVec2(-0.30901703f, 0.9510565f), ImVec2(-0.80901706f, 0.5877852f), ImVec2(-0.80901706f, 0.5877852f), ImVec2(-1.0f, 0.0f), ImVec2(-1.0f, 0.0f), ImVec2(-0.80901694f, -0.58778536f), ImVec2(-0.80901694f, -0.58778536f), ImVec2(-0.3090171f, -0.9510565f), ImVec2(-0.3090171f, -0.9510565f), ImVec2(0.30901712f, -0.9510565f), ImVec2(0.30901712f, -0.9510565f), ImVec2(0.80901694f, -0.5877853f), ImVec2(0.80901694f, -0.5877853f), ImVec2(1.0f, 0.0f) }; static const ImVec2 MARKER_LINE_SQUARE[8] = {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), 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)}; static const ImVec2 MARKER_LINE_DIAMOND[8] = {ImVec2(1, 0), ImVec2(0, -1), ImVec2(0, -1), ImVec2(-1, 0), ImVec2(-1, 0), ImVec2(0, 1), ImVec2(0, 1), ImVec2(1, 0)}; static const ImVec2 MARKER_LINE_UP[6] = {ImVec2(SQRT_3_2,0.5f), ImVec2(0,-1),ImVec2(0,-1),ImVec2(-SQRT_3_2,0.5f),ImVec2(-SQRT_3_2,0.5f),ImVec2(SQRT_3_2,0.5f)}; static const ImVec2 MARKER_LINE_DOWN[6] = {ImVec2(SQRT_3_2,-0.5f),ImVec2(0,1),ImVec2(0,1),ImVec2(-SQRT_3_2,-0.5f), ImVec2(-SQRT_3_2,-0.5f), ImVec2(SQRT_3_2,-0.5f)}; static const ImVec2 MARKER_LINE_LEFT[6] = {ImVec2(-1,0), ImVec2(0.5, SQRT_3_2), ImVec2(0.5, SQRT_3_2), ImVec2(0.5, -SQRT_3_2) , ImVec2(0.5, -SQRT_3_2) , ImVec2(-1,0) }; static const ImVec2 MARKER_LINE_RIGHT[6] = {ImVec2(1,0), ImVec2(-0.5, SQRT_3_2), ImVec2(-0.5, SQRT_3_2), ImVec2(-0.5, -SQRT_3_2), ImVec2(-0.5, -SQRT_3_2), ImVec2(1,0) }; static const ImVec2 MARKER_LINE_ASTERISK[6] = {ImVec2(-SQRT_3_2, -0.5f), ImVec2(SQRT_3_2, 0.5f), ImVec2(-SQRT_3_2, 0.5f), ImVec2(SQRT_3_2, -0.5f), ImVec2(0, -1), ImVec2(0, 1)}; static const ImVec2 MARKER_LINE_PLUS[4] = {ImVec2(-1, 0), ImVec2(1, 0), ImVec2(0, -1), ImVec2(0, 1)}; static const ImVec2 MARKER_LINE_CROSS[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)}; template <typename _Getter> void RenderMarkers(const _Getter& getter, ImPlotMarker marker, float size, bool rend_fill, ImU32 col_fill, bool rend_line, ImU32 col_line, float weight) { if (rend_fill) { switch (marker) { case ImPlotMarker_Circle : RenderPrimitives1<RendererMarkersFill>(getter,MARKER_FILL_CIRCLE,10,size,col_fill); break; case ImPlotMarker_Square : RenderPrimitives1<RendererMarkersFill>(getter,MARKER_FILL_SQUARE, 4,size,col_fill); break; case ImPlotMarker_Diamond : RenderPrimitives1<RendererMarkersFill>(getter,MARKER_FILL_DIAMOND,4,size,col_fill); break; case ImPlotMarker_Up : RenderPrimitives1<RendererMarkersFill>(getter,MARKER_FILL_UP, 3,size,col_fill); break; case ImPlotMarker_Down : RenderPrimitives1<RendererMarkersFill>(getter,MARKER_FILL_DOWN, 3,size,col_fill); break; case ImPlotMarker_Left : RenderPrimitives1<RendererMarkersFill>(getter,MARKER_FILL_LEFT, 3,size,col_fill); break; case ImPlotMarker_Right : RenderPrimitives1<RendererMarkersFill>(getter,MARKER_FILL_RIGHT, 3,size,col_fill); break; } } if (rend_line) { switch (marker) { case ImPlotMarker_Circle : RenderPrimitives1<RendererMarkersLine>(getter,MARKER_LINE_CIRCLE, 20,size,weight,col_line); break; case ImPlotMarker_Square : RenderPrimitives1<RendererMarkersLine>(getter,MARKER_LINE_SQUARE, 8,size,weight,col_line); break; case ImPlotMarker_Diamond : RenderPrimitives1<RendererMarkersLine>(getter,MARKER_LINE_DIAMOND, 8,size,weight,col_line); break; case ImPlotMarker_Up : RenderPrimitives1<RendererMarkersLine>(getter,MARKER_LINE_UP, 6,size,weight,col_line); break; case ImPlotMarker_Down : RenderPrimitives1<RendererMarkersLine>(getter,MARKER_LINE_DOWN, 6,size,weight,col_line); break; case ImPlotMarker_Left : RenderPrimitives1<RendererMarkersLine>(getter,MARKER_LINE_LEFT, 6,size,weight,col_line); break; case ImPlotMarker_Right : RenderPrimitives1<RendererMarkersLine>(getter,MARKER_LINE_RIGHT, 6,size,weight,col_line); break; case ImPlotMarker_Asterisk : RenderPrimitives1<RendererMarkersLine>(getter,MARKER_LINE_ASTERISK,6,size,weight,col_line); break; case ImPlotMarker_Plus : RenderPrimitives1<RendererMarkersLine>(getter,MARKER_LINE_PLUS, 4,size,weight,col_line); break; case ImPlotMarker_Cross : RenderPrimitives1<RendererMarkersLine>(getter,MARKER_LINE_CROSS, 4,size,weight,col_line); break; } } } //----------------------------------------------------------------------------- // [SECTION] PlotLine //----------------------------------------------------------------------------- template <typename _Getter> void PlotLineEx(const char* label_id, const _Getter& getter, ImPlotLineFlags flags) { if (BeginItemEx(label_id, Fitter1<_Getter>(getter), flags, ImPlotCol_Line)) { if (getter.Count <= 0) { EndItem(); return; } const ImPlotNextItemData& s = GetItemData(); if (getter.Count > 1) { if (ImHasFlag(flags, ImPlotLineFlags_Shaded) && s.RenderFill) { const ImU32 col_fill = ImGui::GetColorU32(s.Colors[ImPlotCol_Fill]); GetterOverrideY<_Getter> getter2(getter, 0); RenderPrimitives2<RendererShaded>(getter,getter2,col_fill); } if (s.RenderLine) { const ImU32 col_line = ImGui::GetColorU32(s.Colors[ImPlotCol_Line]); if (ImHasFlag(flags,ImPlotLineFlags_Segments)) { RenderPrimitives1<RendererLineSegments1>(getter,col_line,s.LineWeight); } else if (ImHasFlag(flags, ImPlotLineFlags_Loop)) { if (ImHasFlag(flags, ImPlotLineFlags_SkipNaN)) RenderPrimitives1<RendererLineStripSkip>(GetterLoop<_Getter>(getter),col_line,s.LineWeight); else RenderPrimitives1<RendererLineStrip>(GetterLoop<_Getter>(getter),col_line,s.LineWeight); } else { if (ImHasFlag(flags, ImPlotLineFlags_SkipNaN)) RenderPrimitives1<RendererLineStripSkip>(getter,col_line,s.LineWeight); else RenderPrimitives1<RendererLineStrip>(getter,col_line,s.LineWeight); } } } // render markers if (s.Marker != ImPlotMarker_None) { if (ImHasFlag(flags, ImPlotLineFlags_NoClip)) { PopPlotClipRect(); PushPlotClipRect(s.MarkerSize); } const ImU32 col_line = ImGui::GetColorU32(s.Colors[ImPlotCol_MarkerOutline]); const ImU32 col_fill = ImGui::GetColorU32(s.Colors[ImPlotCol_MarkerFill]); RenderMarkers<_Getter>(getter, s.Marker, s.MarkerSize, s.RenderMarkerFill, col_fill, s.RenderMarkerLine, col_line, s.MarkerWeight); } EndItem(); } } template <typename T> void PlotLine(const char* label_id, const T* values, int count, double xscale, double x0, ImPlotLineFlags flags, int offset, int stride) { GetterXY<IndexerLin,IndexerIdx<T>> getter(IndexerLin(xscale,x0),IndexerIdx<T>(values,count,offset,stride),count); PlotLineEx(label_id, getter, flags); } template <typename T> void PlotLine(const char* label_id, const T* xs, const T* ys, int count, ImPlotLineFlags flags, int offset, int stride) { GetterXY<IndexerIdx<T>,IndexerIdx<T>> getter(IndexerIdx<T>(xs,count,offset,stride),IndexerIdx<T>(ys,count,offset,stride),count); PlotLineEx(label_id, getter, flags); } #define INSTANTIATE_MACRO(T) \ template IMPLOT_API void PlotLine<T> (const char* label_id, const T* values, int count, double xscale, double x0, ImPlotLineFlags flags, int offset, int stride); \ template IMPLOT_API void PlotLine<T>(const char* label_id, const T* xs, const T* ys, int count, ImPlotLineFlags flags, int offset, int stride); CALL_INSTANTIATE_FOR_NUMERIC_TYPES() #undef INSTANTIATE_MACRO // custom void PlotLineG(const char* label_id, ImPlotGetter getter_func, void* data, int count, ImPlotLineFlags flags) { GetterFuncPtr getter(getter_func,data, count); PlotLineEx(label_id, getter, flags); } //----------------------------------------------------------------------------- // [SECTION] PlotScatter //----------------------------------------------------------------------------- template <typename Getter> void PlotScatterEx(const char* label_id, const Getter& getter, ImPlotScatterFlags flags) { if (BeginItemEx(label_id, Fitter1<Getter>(getter), flags, ImPlotCol_MarkerOutline)) { if (getter.Count <= 0) { EndItem(); return; } const ImPlotNextItemData& s = GetItemData(); ImPlotMarker marker = s.Marker == ImPlotMarker_None ? ImPlotMarker_Circle: s.Marker; if (marker != ImPlotMarker_None) { if (ImHasFlag(flags,ImPlotScatterFlags_NoClip)) { PopPlotClipRect(); PushPlotClipRect(s.MarkerSize); } const ImU32 col_line = ImGui::GetColorU32(s.Colors[ImPlotCol_MarkerOutline]); const ImU32 col_fill = ImGui::GetColorU32(s.Colors[ImPlotCol_MarkerFill]); RenderMarkers<Getter>(getter, marker, s.MarkerSize, s.RenderMarkerFill, col_fill, s.RenderMarkerLine, col_line, s.MarkerWeight); } EndItem(); } } template <typename T> void PlotScatter(const char* label_id, const T* values, int count, double xscale, double x0, ImPlotScatterFlags flags, int offset, int stride) { GetterXY<IndexerLin,IndexerIdx<T>> getter(IndexerLin(xscale,x0),IndexerIdx<T>(values,count,offset,stride),count); PlotScatterEx(label_id, getter, flags); } template <typename T> void PlotScatter(const char* label_id, const T* xs, const T* ys, int count, ImPlotScatterFlags flags, int offset, int stride) { GetterXY<IndexerIdx<T>,IndexerIdx<T>> getter(IndexerIdx<T>(xs,count,offset,stride),IndexerIdx<T>(ys,count,offset,stride),count); return PlotScatterEx(label_id, getter, flags); } #define INSTANTIATE_MACRO(T) \ template IMPLOT_API void PlotScatter<T>(const char* label_id, const T* values, int count, double xscale, double x0, ImPlotScatterFlags flags, int offset, int stride); \ template IMPLOT_API void PlotScatter<T>(const char* label_id, const T* xs, const T* ys, int count, ImPlotScatterFlags flags, int offset, int stride); CALL_INSTANTIATE_FOR_NUMERIC_TYPES() #undef INSTANTIATE_MACRO // custom void PlotScatterG(const char* label_id, ImPlotGetter getter_func, void* data, int count, ImPlotScatterFlags flags) { GetterFuncPtr getter(getter_func,data, count); return PlotScatterEx(label_id, getter, flags); } //----------------------------------------------------------------------------- // [SECTION] PlotStairs //----------------------------------------------------------------------------- template <typename Getter> void PlotStairsEx(const char* label_id, const Getter& getter, ImPlotStairsFlags flags) { if (BeginItemEx(label_id, Fitter1<Getter>(getter), flags, ImPlotCol_Line)) { if (getter.Count <= 0) { EndItem(); return; } const ImPlotNextItemData& s = GetItemData(); if (getter.Count > 1) { if (s.RenderFill && ImHasFlag(flags,ImPlotStairsFlags_Shaded)) { const ImU32 col_fill = ImGui::GetColorU32(s.Colors[ImPlotCol_Fill]); if (ImHasFlag(flags, ImPlotStairsFlags_PreStep)) RenderPrimitives1<RendererStairsPreShaded>(getter,col_fill); else RenderPrimitives1<RendererStairsPostShaded>(getter,col_fill); } if (s.RenderLine) { const ImU32 col_line = ImGui::GetColorU32(s.Colors[ImPlotCol_Line]); if (ImHasFlag(flags, ImPlotStairsFlags_PreStep)) RenderPrimitives1<RendererStairsPre>(getter,col_line,s.LineWeight); else RenderPrimitives1<RendererStairsPost>(getter,col_line,s.LineWeight); } } // render markers if (s.Marker != ImPlotMarker_None) { PopPlotClipRect(); PushPlotClipRect(s.MarkerSize); const ImU32 col_line = ImGui::GetColorU32(s.Colors[ImPlotCol_MarkerOutline]); const ImU32 col_fill = ImGui::GetColorU32(s.Colors[ImPlotCol_MarkerFill]); RenderMarkers<Getter>(getter, s.Marker, s.MarkerSize, s.RenderMarkerFill, col_fill, s.RenderMarkerLine, col_line, s.MarkerWeight); } EndItem(); } } template <typename T> void PlotStairs(const char* label_id, const T* values, int count, double xscale, double x0, ImPlotStairsFlags flags, int offset, int stride) { GetterXY<IndexerLin,IndexerIdx<T>> getter(IndexerLin(xscale,x0),IndexerIdx<T>(values,count,offset,stride),count); PlotStairsEx(label_id, getter, flags); } template <typename T> void PlotStairs(const char* label_id, const T* xs, const T* ys, int count, ImPlotStairsFlags flags, int offset, int stride) { GetterXY<IndexerIdx<T>,IndexerIdx<T>> getter(IndexerIdx<T>(xs,count,offset,stride),IndexerIdx<T>(ys,count,offset,stride),count); return PlotStairsEx(label_id, getter, flags); } #define INSTANTIATE_MACRO(T) \ template IMPLOT_API void PlotStairs<T> (const char* label_id, const T* values, int count, double xscale, double x0, ImPlotStairsFlags flags, int offset, int stride); \ template IMPLOT_API void PlotStairs<T>(const char* label_id, const T* xs, const T* ys, int count, ImPlotStairsFlags flags, int offset, int stride); CALL_INSTANTIATE_FOR_NUMERIC_TYPES() #undef INSTANTIATE_MACRO // custom void PlotStairsG(const char* label_id, ImPlotGetter getter_func, void* data, int count, ImPlotStairsFlags flags) { GetterFuncPtr getter(getter_func,data, count); return PlotStairsEx(label_id, getter, flags); } //----------------------------------------------------------------------------- // [SECTION] PlotShaded //----------------------------------------------------------------------------- template <typename Getter1, typename Getter2> void PlotShadedEx(const char* label_id, const Getter1& getter1, const Getter2& getter2, ImPlotShadedFlags flags) { if (BeginItemEx(label_id, Fitter2<Getter1,Getter2>(getter1,getter2), flags, ImPlotCol_Fill)) { if (getter1.Count <= 0 || getter2.Count <= 0) { EndItem(); return; } const ImPlotNextItemData& s = GetItemData(); if (s.RenderFill) { const ImU32 col = ImGui::GetColorU32(s.Colors[ImPlotCol_Fill]); RenderPrimitives2<RendererShaded>(getter1,getter2,col); } EndItem(); } } template <typename T> void PlotShaded(const char* label_id, const T* values, int count, double y_ref, double xscale, double x0, ImPlotShadedFlags flags, int offset, int stride) { if (!(y_ref > -DBL_MAX)) y_ref = GetPlotLimits(IMPLOT_AUTO,IMPLOT_AUTO).Y.Min; if (!(y_ref < DBL_MAX)) y_ref = GetPlotLimits(IMPLOT_AUTO,IMPLOT_AUTO).Y.Max; GetterXY<IndexerLin,IndexerIdx<T>> getter1(IndexerLin(xscale,x0),IndexerIdx<T>(values,count,offset,stride),count); GetterXY<IndexerLin,IndexerConst> getter2(IndexerLin(xscale,x0),IndexerConst(y_ref),count); PlotShadedEx(label_id, getter1, getter2, flags); } template <typename T> void PlotShaded(const char* label_id, const T* xs, const T* ys, int count, double y_ref, ImPlotShadedFlags flags, int offset, int stride) { if (y_ref == -HUGE_VAL) y_ref = GetPlotLimits(IMPLOT_AUTO,IMPLOT_AUTO).Y.Min; if (y_ref == HUGE_VAL) y_ref = GetPlotLimits(IMPLOT_AUTO,IMPLOT_AUTO).Y.Max; GetterXY<IndexerIdx<T>,IndexerIdx<T>> getter1(IndexerIdx<T>(xs,count,offset,stride),IndexerIdx<T>(ys,count,offset,stride),count); GetterXY<IndexerIdx<T>,IndexerConst> getter2(IndexerIdx<T>(xs,count,offset,stride),IndexerConst(y_ref),count); PlotShadedEx(label_id, getter1, getter2, flags); } template <typename T> void PlotShaded(const char* label_id, const T* xs, const T* ys1, const T* ys2, int count, ImPlotShadedFlags flags, int offset, int stride) { GetterXY<IndexerIdx<T>,IndexerIdx<T>> getter1(IndexerIdx<T>(xs,count,offset,stride),IndexerIdx<T>(ys1,count,offset,stride),count); GetterXY<IndexerIdx<T>,IndexerIdx<T>> getter2(IndexerIdx<T>(xs,count,offset,stride),IndexerIdx<T>(ys2,count,offset,stride),count); PlotShadedEx(label_id, getter1, getter2, flags); } #define INSTANTIATE_MACRO(T) \ template IMPLOT_API void PlotShaded<T>(const char* label_id, const T* values, int count, double y_ref, double xscale, double x0, ImPlotShadedFlags flags, int offset, int stride); \ template IMPLOT_API void PlotShaded<T>(const char* label_id, const T* xs, const T* ys, int count, double y_ref, ImPlotShadedFlags flags, int offset, int stride); \ template IMPLOT_API void PlotShaded<T>(const char* label_id, const T* xs, const T* ys1, const T* ys2, int count, ImPlotShadedFlags flags, int offset, int stride); CALL_INSTANTIATE_FOR_NUMERIC_TYPES() #undef INSTANTIATE_MACRO // custom void PlotShadedG(const char* label_id, ImPlotGetter getter_func1, void* data1, ImPlotGetter getter_func2, void* data2, int count, ImPlotShadedFlags flags) { GetterFuncPtr getter1(getter_func1, data1, count); GetterFuncPtr getter2(getter_func2, data2, count); PlotShadedEx(label_id, getter1, getter2, flags); } //----------------------------------------------------------------------------- // [SECTION] PlotBars //----------------------------------------------------------------------------- template <typename Getter1, typename Getter2> void PlotBarsVEx(const char* label_id, const Getter1& getter1, const Getter2 getter2, double width, ImPlotBarsFlags flags) { if (BeginItemEx(label_id, FitterBarV<Getter1,Getter2>(getter1,getter2,width), flags, ImPlotCol_Fill)) { if (getter1.Count <= 0 || getter2.Count <= 0) { EndItem(); return; } const ImPlotNextItemData& s = GetItemData(); const ImU32 col_fill = ImGui::GetColorU32(s.Colors[ImPlotCol_Fill]); const ImU32 col_line = ImGui::GetColorU32(s.Colors[ImPlotCol_Line]); bool rend_fill = s.RenderFill; bool rend_line = s.RenderLine; if (rend_fill) { RenderPrimitives2<RendererBarsFillV>(getter1,getter2,col_fill,width); if (rend_line && col_fill == col_line) rend_line = false; } if (rend_line) { RenderPrimitives2<RendererBarsLineV>(getter1,getter2,col_line,width,s.LineWeight); } EndItem(); } } template <typename Getter1, typename Getter2> void PlotBarsHEx(const char* label_id, const Getter1& getter1, const Getter2& getter2, double height, ImPlotBarsFlags flags) { if (BeginItemEx(label_id, FitterBarH<Getter1,Getter2>(getter1,getter2,height), flags, ImPlotCol_Fill)) { if (getter1.Count <= 0 || getter2.Count <= 0) { EndItem(); return; } const ImPlotNextItemData& s = GetItemData(); const ImU32 col_fill = ImGui::GetColorU32(s.Colors[ImPlotCol_Fill]); const ImU32 col_line = ImGui::GetColorU32(s.Colors[ImPlotCol_Line]); bool rend_fill = s.RenderFill; bool rend_line = s.RenderLine; if (rend_fill) { RenderPrimitives2<RendererBarsFillH>(getter1,getter2,col_fill,height); if (rend_line && col_fill == col_line) rend_line = false; } if (rend_line) { RenderPrimitives2<RendererBarsLineH>(getter1,getter2,col_line,height,s.LineWeight); } EndItem(); } } template <typename T> void PlotBars(const char* label_id, const T* values, int count, double bar_size, double shift, ImPlotBarsFlags flags, int offset, int stride) { if (ImHasFlag(flags, ImPlotBarsFlags_Horizontal)) { GetterXY<IndexerIdx<T>,IndexerLin> getter1(IndexerIdx<T>(values,count,offset,stride),IndexerLin(1.0,shift),count); GetterXY<IndexerConst,IndexerLin> getter2(IndexerConst(0),IndexerLin(1.0,shift),count); PlotBarsHEx(label_id, getter1, getter2, bar_size, flags); } else { GetterXY<IndexerLin,IndexerIdx<T>> getter1(IndexerLin(1.0,shift),IndexerIdx<T>(values,count,offset,stride),count); GetterXY<IndexerLin,IndexerConst> getter2(IndexerLin(1.0,shift),IndexerConst(0),count); PlotBarsVEx(label_id, getter1, getter2, bar_size, flags); } } template <typename T> void PlotBars(const char* label_id, const T* xs, const T* ys, int count, double bar_size, ImPlotBarsFlags flags, int offset, int stride) { if (ImHasFlag(flags, ImPlotBarsFlags_Horizontal)) { GetterXY<IndexerIdx<T>,IndexerIdx<T>> getter1(IndexerIdx<T>(xs,count,offset,stride),IndexerIdx<T>(ys,count,offset,stride),count); GetterXY<IndexerConst, IndexerIdx<T>> getter2(IndexerConst(0),IndexerIdx<T>(ys,count,offset,stride),count); PlotBarsHEx(label_id, getter1, getter2, bar_size, flags); } else { GetterXY<IndexerIdx<T>,IndexerIdx<T>> getter1(IndexerIdx<T>(xs,count,offset,stride),IndexerIdx<T>(ys,count,offset,stride),count); GetterXY<IndexerIdx<T>,IndexerConst> getter2(IndexerIdx<T>(xs,count,offset,stride),IndexerConst(0),count); PlotBarsVEx(label_id, getter1, getter2, bar_size, flags); } } #define INSTANTIATE_MACRO(T) \ template IMPLOT_API void PlotBars<T>(const char* label_id, const T* values, int count, double bar_size, double shift, ImPlotBarsFlags flags, int offset, int stride); \ template IMPLOT_API void PlotBars<T>(const char* label_id, const T* xs, const T* ys, int count, double bar_size, ImPlotBarsFlags flags, int offset, int stride); CALL_INSTANTIATE_FOR_NUMERIC_TYPES() #undef INSTANTIATE_MACRO void PlotBarsG(const char* label_id, ImPlotGetter getter_func, void* data, int count, double bar_size, ImPlotBarsFlags flags) { if (ImHasFlag(flags, ImPlotBarsFlags_Horizontal)) { GetterFuncPtr getter1(getter_func, data, count); GetterOverrideX<GetterFuncPtr> getter2(getter1,0); PlotBarsHEx(label_id, getter1, getter2, bar_size, flags); } else { GetterFuncPtr getter1(getter_func, data, count); GetterOverrideY<GetterFuncPtr> getter2(getter1,0); PlotBarsVEx(label_id, getter1, getter2, bar_size, flags); } } //----------------------------------------------------------------------------- // [SECTION] PlotBarGroups //----------------------------------------------------------------------------- template <typename T> void PlotBarGroups(const char* const label_ids[], const T* values, int item_count, int group_count, double group_size, double shift, ImPlotBarGroupsFlags flags) { const bool horz = ImHasFlag(flags, ImPlotBarGroupsFlags_Horizontal); const bool stack = ImHasFlag(flags, ImPlotBarGroupsFlags_Stacked); if (stack) { SetupLock(); ImPlotContext& gp = *GImPlot; gp.TempDouble1.resize(4*group_count); double* temp = gp.TempDouble1.Data; double* neg = &temp[0]; double* pos = &temp[group_count]; double* curr_min = &temp[group_count*2]; double* curr_max = &temp[group_count*3]; for (int g = 0; g < group_count*2; ++g) temp[g] = 0; if (horz) { for (int i = 0; i < item_count; ++i) { if (!IsItemHidden(label_ids[i])) { for (int g = 0; g < group_count; ++g) { double v = (double)values[i*group_count+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<IndexerIdx<double>,IndexerLin> getter1(IndexerIdx<double>(curr_min,group_count),IndexerLin(1.0,shift),group_count); GetterXY<IndexerIdx<double>,IndexerLin> getter2(IndexerIdx<double>(curr_max,group_count),IndexerLin(1.0,shift),group_count); PlotBarsHEx(label_ids[i],getter1,getter2,group_size,0); } } else { for (int i = 0; i < item_count; ++i) { if (!IsItemHidden(label_ids[i])) { for (int g = 0; g < group_count; ++g) { double v = (double)values[i*group_count+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<IndexerLin,IndexerIdx<double>> getter1(IndexerLin(1.0,shift),IndexerIdx<double>(curr_min,group_count),group_count); GetterXY<IndexerLin,IndexerIdx<double>> getter2(IndexerLin(1.0,shift),IndexerIdx<double>(curr_max,group_count),group_count); PlotBarsVEx(label_ids[i],getter1,getter2,group_size,0); } } } else { const double subsize = group_size / item_count; if (horz) { for (int i = 0; i < item_count; ++i) { const double subshift = (i+0.5)*subsize - group_size/2; PlotBars(label_ids[i],&values[i*group_count],group_count,subsize,subshift+shift,ImPlotBarsFlags_Horizontal); } } else { for (int i = 0; i < item_count; ++i) { const double subshift = (i+0.5)*subsize - group_size/2; PlotBars(label_ids[i],&values[i*group_count],group_count,subsize,subshift+shift); } } } } #define INSTANTIATE_MACRO(T) template IMPLOT_API void PlotBarGroups<T>(const char* const label_ids[], const T* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags); CALL_INSTANTIATE_FOR_NUMERIC_TYPES() #undef INSTANTIATE_MACRO //----------------------------------------------------------------------------- // [SECTION] PlotErrorBars //----------------------------------------------------------------------------- template <typename _GetterPos, typename _GetterNeg> void PlotErrorBarsVEx(const char* label_id, const _GetterPos& getter_pos, const _GetterNeg& getter_neg, ImPlotErrorBarsFlags flags) { if (BeginItemEx(label_id, Fitter2<_GetterPos,_GetterNeg>(getter_pos, getter_neg), flags, IMPLOT_AUTO)) { if (getter_pos.Count <= 0 || getter_neg.Count <= 0) { EndItem(); return; } const ImPlotNextItemData& s = GetItemData(); ImDrawList& draw_list = *GetPlotDrawList(); const ImU32 col = ImGui::GetColorU32(s.Colors[ImPlotCol_ErrorBar]); const bool rend_whisker = s.ErrorBarSize > 0; const float half_whisker = s.ErrorBarSize * 0.5f; for (int i = 0; i < getter_pos.Count; ++i) { ImVec2 p1 = PlotToPixels(getter_neg(i),IMPLOT_AUTO,IMPLOT_AUTO); ImVec2 p2 = PlotToPixels(getter_pos(i),IMPLOT_AUTO,IMPLOT_AUTO); draw_list.AddLine(p1,p2,col, s.ErrorBarWeight); if (rend_whisker) { draw_list.AddLine(p1 - ImVec2(half_whisker, 0), p1 + ImVec2(half_whisker, 0), col, s.ErrorBarWeight); draw_list.AddLine(p2 - ImVec2(half_whisker, 0), p2 + ImVec2(half_whisker, 0), col, s.ErrorBarWeight); } } EndItem(); } } template <typename _GetterPos, typename _GetterNeg> void PlotErrorBarsHEx(const char* label_id, const _GetterPos& getter_pos, const _GetterNeg& getter_neg, ImPlotErrorBarsFlags flags) { if (BeginItemEx(label_id, Fitter2<_GetterPos,_GetterNeg>(getter_pos, getter_neg), flags, IMPLOT_AUTO)) { if (getter_pos.Count <= 0 || getter_neg.Count <= 0) { EndItem(); return; } const ImPlotNextItemData& s = GetItemData(); ImDrawList& draw_list = *GetPlotDrawList(); const ImU32 col = ImGui::GetColorU32(s.Colors[ImPlotCol_ErrorBar]); const bool rend_whisker = s.ErrorBarSize > 0; const float half_whisker = s.ErrorBarSize * 0.5f; for (int i = 0; i < getter_pos.Count; ++i) { ImVec2 p1 = PlotToPixels(getter_neg(i),IMPLOT_AUTO,IMPLOT_AUTO); ImVec2 p2 = PlotToPixels(getter_pos(i),IMPLOT_AUTO,IMPLOT_AUTO); draw_list.AddLine(p1, p2, col, s.ErrorBarWeight); if (rend_whisker) { draw_list.AddLine(p1 - ImVec2(0, half_whisker), p1 + ImVec2(0, half_whisker), col, s.ErrorBarWeight); draw_list.AddLine(p2 - ImVec2(0, half_whisker), p2 + ImVec2(0, half_whisker), col, s.ErrorBarWeight); } } EndItem(); } } template <typename T> void PlotErrorBars(const char* label_id, const T* xs, const T* ys, const T* err, int count, ImPlotErrorBarsFlags flags, int offset, int stride) { PlotErrorBars(label_id, xs, ys, err, err, count, flags, offset, stride); } template <typename T> void PlotErrorBars(const char* label_id, const T* xs, const T* ys, const T* neg, const T* pos, int count, ImPlotErrorBarsFlags flags, int offset, int stride) { IndexerIdx<T> indexer_x(xs, count,offset,stride); IndexerIdx<T> indexer_y(ys, count,offset,stride); IndexerIdx<T> indexer_n(neg,count,offset,stride); IndexerIdx<T> indexer_p(pos,count,offset,stride); GetterError<T> getter(xs, ys, neg, pos, count, offset, stride); if (ImHasFlag(flags, ImPlotErrorBarsFlags_Horizontal)) { IndexerAdd<IndexerIdx<T>,IndexerIdx<T>> indexer_xp(indexer_x, indexer_p, 1, 1); IndexerAdd<IndexerIdx<T>,IndexerIdx<T>> indexer_xn(indexer_x, indexer_n, 1, -1); GetterXY<IndexerAdd<IndexerIdx<T>,IndexerIdx<T>>,IndexerIdx<T>> getter_p(indexer_xp, indexer_y, count); GetterXY<IndexerAdd<IndexerIdx<T>,IndexerIdx<T>>,IndexerIdx<T>> getter_n(indexer_xn, indexer_y, count); PlotErrorBarsHEx(label_id, getter_p, getter_n, flags); } else { IndexerAdd<IndexerIdx<T>,IndexerIdx<T>> indexer_yp(indexer_y, indexer_p, 1, 1); IndexerAdd<IndexerIdx<T>,IndexerIdx<T>> indexer_yn(indexer_y, indexer_n, 1, -1); GetterXY<IndexerIdx<T>,IndexerAdd<IndexerIdx<T>,IndexerIdx<T>>> getter_p(indexer_x, indexer_yp, count); GetterXY<IndexerIdx<T>,IndexerAdd<IndexerIdx<T>,IndexerIdx<T>>> getter_n(indexer_x, indexer_yn, count); PlotErrorBarsVEx(label_id, getter_p, getter_n, flags); } } #define INSTANTIATE_MACRO(T) \ template IMPLOT_API void PlotErrorBars<T>(const char* label_id, const T* xs, const T* ys, const T* err, int count, ImPlotErrorBarsFlags flags, int offset, int stride); \ template IMPLOT_API void PlotErrorBars<T>(const char* label_id, const T* xs, const T* ys, const T* neg, const T* pos, int count, ImPlotErrorBarsFlags flags, int offset, int stride); CALL_INSTANTIATE_FOR_NUMERIC_TYPES() #undef INSTANTIATE_MACRO //----------------------------------------------------------------------------- // [SECTION] PlotStems //----------------------------------------------------------------------------- template <typename _GetterM, typename _GetterB> void PlotStemsEx(const char* label_id, const _GetterM& getter_mark, const _GetterB& getter_base, ImPlotStemsFlags flags) { if (BeginItemEx(label_id, Fitter2<_GetterM,_GetterB>(getter_mark,getter_base), flags, ImPlotCol_Line)) { if (getter_mark.Count <= 0 || getter_base.Count <= 0) { EndItem(); return; } const ImPlotNextItemData& s = GetItemData(); // render stems if (s.RenderLine) { const ImU32 col_line = ImGui::GetColorU32(s.Colors[ImPlotCol_Line]); RenderPrimitives2<RendererLineSegments2>(getter_mark, getter_base, col_line, s.LineWeight); } // render markers if (s.Marker != ImPlotMarker_None) { PopPlotClipRect(); PushPlotClipRect(s.MarkerSize); const ImU32 col_line = ImGui::GetColorU32(s.Colors[ImPlotCol_MarkerOutline]); const ImU32 col_fill = ImGui::GetColorU32(s.Colors[ImPlotCol_MarkerFill]); RenderMarkers<_GetterM>(getter_mark, s.Marker, s.MarkerSize, s.RenderMarkerFill, col_fill, s.RenderMarkerLine, col_line, s.MarkerWeight); } EndItem(); } } template <typename T> void PlotStems(const char* label_id, const T* values, int count, double ref, double scale, double start, ImPlotStemsFlags flags, int offset, int stride) { if (ImHasFlag(flags, ImPlotStemsFlags_Horizontal)) { GetterXY<IndexerIdx<T>,IndexerLin> get_mark(IndexerIdx<T>(values,count,offset,stride),IndexerLin(scale,start),count); GetterXY<IndexerConst,IndexerLin> get_base(IndexerConst(ref),IndexerLin(scale,start),count); PlotStemsEx(label_id, get_mark, get_base, flags); } else { GetterXY<IndexerLin,IndexerIdx<T>> get_mark(IndexerLin(scale,start),IndexerIdx<T>(values,count,offset,stride),count); GetterXY<IndexerLin,IndexerConst> get_base(IndexerLin(scale,start),IndexerConst(ref),count); PlotStemsEx(label_id, get_mark, get_base, flags); } } template <typename T> void PlotStems(const char* label_id, const T* xs, const T* ys, int count, double ref, ImPlotStemsFlags flags, int offset, int stride) { if (ImHasFlag(flags, ImPlotStemsFlags_Horizontal)) { GetterXY<IndexerIdx<T>,IndexerIdx<T>> get_mark(IndexerIdx<T>(xs,count,offset,stride),IndexerIdx<T>(ys,count,offset,stride),count); GetterXY<IndexerConst,IndexerIdx<T>> get_base(IndexerConst(ref),IndexerIdx<T>(ys,count,offset,stride),count); PlotStemsEx(label_id, get_mark, get_base, flags); } else { GetterXY<IndexerIdx<T>,IndexerIdx<T>> get_mark(IndexerIdx<T>(xs,count,offset,stride),IndexerIdx<T>(ys,count,offset,stride),count); GetterXY<IndexerIdx<T>,IndexerConst> get_base(IndexerIdx<T>(xs,count,offset,stride),IndexerConst(ref),count); PlotStemsEx(label_id, get_mark, get_base, flags); } } #define INSTANTIATE_MACRO(T) \ template IMPLOT_API void PlotStems<T>(const char* label_id, const T* values, int count, double ref, double scale, double start, ImPlotStemsFlags flags, int offset, int stride); \ template IMPLOT_API void PlotStems<T>(const char* label_id, const T* xs, const T* ys, int count, double ref, ImPlotStemsFlags flags, int offset, int stride); CALL_INSTANTIATE_FOR_NUMERIC_TYPES() #undef INSTANTIATE_MACRO //----------------------------------------------------------------------------- // [SECTION] PlotInfLines //----------------------------------------------------------------------------- template <typename T> void PlotInfLines(const char* label_id, const T* values, int count, ImPlotInfLinesFlags flags, int offset, int stride) { const ImPlotRect lims = GetPlotLimits(IMPLOT_AUTO,IMPLOT_AUTO); if (ImHasFlag(flags, ImPlotInfLinesFlags_Horizontal)) { GetterXY<IndexerConst,IndexerIdx<T>> getter_min(IndexerConst(lims.X.Min),IndexerIdx<T>(values,count,offset,stride),count); GetterXY<IndexerConst,IndexerIdx<T>> getter_max(IndexerConst(lims.X.Max),IndexerIdx<T>(values,count,offset,stride),count); if (BeginItemEx(label_id, FitterY<GetterXY<IndexerConst,IndexerIdx<T>>>(getter_min), flags, ImPlotCol_Line)) { if (count <= 0) { EndItem(); return; } const ImPlotNextItemData& s = GetItemData(); const ImU32 col_line = ImGui::GetColorU32(s.Colors[ImPlotCol_Line]); if (s.RenderLine) RenderPrimitives2<RendererLineSegments2>(getter_min, getter_max, col_line, s.LineWeight); EndItem(); } } else { GetterXY<IndexerIdx<T>,IndexerConst> get_min(IndexerIdx<T>(values,count,offset,stride),IndexerConst(lims.Y.Min),count); GetterXY<IndexerIdx<T>,IndexerConst> get_max(IndexerIdx<T>(values,count,offset,stride),IndexerConst(lims.Y.Max),count); if (BeginItemEx(label_id, FitterX<GetterXY<IndexerIdx<T>,IndexerConst>>(get_min), flags, ImPlotCol_Line)) { if (count <= 0) { EndItem(); return; } const ImPlotNextItemData& s = GetItemData(); const ImU32 col_line = ImGui::GetColorU32(s.Colors[ImPlotCol_Line]); if (s.RenderLine) RenderPrimitives2<RendererLineSegments2>(get_min, get_max, col_line, s.LineWeight); EndItem(); } } } #define INSTANTIATE_MACRO(T) template IMPLOT_API void PlotInfLines<T>(const char* label_id, const T* xs, int count, ImPlotInfLinesFlags flags, int offset, int stride); CALL_INSTANTIATE_FOR_NUMERIC_TYPES() #undef INSTANTIATE_MACRO //----------------------------------------------------------------------------- // [SECTION] PlotPieChart //----------------------------------------------------------------------------- IMPLOT_INLINE void RenderPieSlice(ImDrawList& draw_list, const ImPlotPoint& center, double radius, double a0, double a1, ImU32 col) { const float resolution = 50 / (2 * IM_PI); ImVec2 buffer[52]; buffer[0] = PlotToPixels(center,IMPLOT_AUTO,IMPLOT_AUTO); int n = ImMax(3, (int)((a1 - a0) * resolution)); double da = (a1 - a0) / (n - 1); int i = 0; for (; i < n; ++i) { double a = a0 + i * da; buffer[i + 1] = PlotToPixels(center.x + radius * cos(a), center.y + radius * sin(a),IMPLOT_AUTO,IMPLOT_AUTO); } buffer[i+1] = buffer[0]; // fill draw_list.AddConvexPolyFilled(buffer, n + 1, col); // border (for AA) draw_list.AddPolyline(buffer, n + 2, col, 0, 2.0f); } template <typename T> double PieChartSum(const T* values, int count, bool ignore_hidden) { double sum = 0; if (ignore_hidden) { ImPlotContext& gp = *GImPlot; ImPlotItemGroup& Items = *gp.CurrentItems; for (int i = 0; i < count; ++i) { if (i >= Items.GetItemCount()) break; ImPlotItem* item = Items.GetItemByIndex(i); IM_ASSERT(item != nullptr); if (item->Show) { sum += (double)values[i]; } } } else { for (int i = 0; i < count; ++i) { sum += (double)values[i]; } } return sum; } template <typename T> void PlotPieChartEx(const char* const label_ids[], const T* values, int count, ImPlotPoint center, double radius, double angle0, ImPlotPieChartFlags flags) { ImDrawList& draw_list = *GetPlotDrawList(); const bool ignore_hidden = ImHasFlag(flags, ImPlotPieChartFlags_IgnoreHidden); const double sum = PieChartSum(values, count, ignore_hidden); const bool normalize = ImHasFlag(flags, ImPlotPieChartFlags_Normalize) || sum > 1.0; double a0 = angle0 * 2 * IM_PI / 360.0; double a1 = angle0 * 2 * IM_PI / 360.0; ImPlotPoint Pmin = ImPlotPoint(center.x - radius, center.y - radius); ImPlotPoint Pmax = ImPlotPoint(center.x + radius, center.y + radius); for (int i = 0; i < count; ++i) { ImPlotItem* item = GetItem(label_ids[i]); const double percent = normalize ? (double)values[i] / sum : (double)values[i]; const bool skip = sum <= 0.0 || (ignore_hidden && item != nullptr && !item->Show); if (!skip) a1 = a0 + 2 * IM_PI * percent; if (BeginItemEx(label_ids[i], FitterRect(Pmin, Pmax))) { if (sum > 0.0) { ImU32 col = GetCurrentItem()->Color; if (percent < 0.5) { RenderPieSlice(draw_list, center, radius, a0, a1, col); } else { RenderPieSlice(draw_list, center, radius, a0, a0 + (a1 - a0) * 0.5, col); RenderPieSlice(draw_list, center, radius, a0 + (a1 - a0) * 0.5, a1, col); } } EndItem(); } if (!skip) a0 = a1; } } int PieChartFormatter(double value, char* buff, int size, void* data) { const char* fmt = (const char*)data; return snprintf(buff, size, fmt, value); }; template <typename T> void PlotPieChart(const char* const label_ids[], const T* values, int count, double x, double y, double radius, const char* fmt, double angle0, ImPlotPieChartFlags flags) { PlotPieChart<T>(label_ids, values, count, x, y, radius, PieChartFormatter, (void*)fmt, angle0, flags); } #define INSTANTIATE_MACRO(T) template IMPLOT_API void PlotPieChart<T>(const char* const label_ids[], const T* values, int count, double x, double y, double radius, const char* fmt, double angle0, ImPlotPieChartFlags flags); CALL_INSTANTIATE_FOR_NUMERIC_TYPES() #undef INSTANTIATE_MACRO template <typename T> void PlotPieChart(const char* const label_ids[], const T* values, int count, double x, double y, double radius, ImPlotFormatter fmt, void* fmt_data, double angle0, ImPlotPieChartFlags flags) { IM_ASSERT_USER_ERROR(GImPlot->CurrentPlot != nullptr, "PlotPieChart() needs to be called between BeginPlot() and EndPlot()!"); ImDrawList& draw_list = *GetPlotDrawList(); const bool ignore_hidden = ImHasFlag(flags, ImPlotPieChartFlags_IgnoreHidden); const double sum = PieChartSum(values, count, ignore_hidden); const bool normalize = ImHasFlag(flags, ImPlotPieChartFlags_Normalize) || sum > 1.0; ImPlotPoint center(x, y); PushPlotClipRect(); PlotPieChartEx(label_ids, values, count, center, radius, angle0, flags); if (fmt != nullptr) { double a0 = angle0 * 2 * IM_PI / 360.0; double a1 = angle0 * 2 * IM_PI / 360.0; char buffer[32]; for (int i = 0; i < count; ++i) { ImPlotItem* item = GetItem(label_ids[i]); IM_ASSERT(item != nullptr); const double percent = normalize ? (double)values[i] / sum : (double)values[i]; const bool skip = ignore_hidden && item != nullptr && !item->Show; if (!skip) { a1 = a0 + 2 * IM_PI * percent; if (item->Show) { fmt((double)values[i], buffer, 32, fmt_data); 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), IMPLOT_AUTO, IMPLOT_AUTO); ImU32 col = CalcTextColor(ImGui::ColorConvertU32ToFloat4(item->Color)); draw_list.AddText(pos - size * 0.5f, col, buffer); } a0 = a1; } } } PopPlotClipRect(); } #define INSTANTIATE_MACRO(T) template IMPLOT_API void PlotPieChart(const char* const label_ids[], const T* values, int count, double x, double y, double radius, ImPlotFormatter fmt, void* fmt_data, double angle0, ImPlotPieChartFlags flags); CALL_INSTANTIATE_FOR_NUMERIC_TYPES() #undef INSTANTIATE_MACRO //----------------------------------------------------------------------------- // [SECTION] PlotHeatmap //----------------------------------------------------------------------------- template <typename T> struct GetterHeatmapRowMaj { GetterHeatmapRowMaj(const T* values, int rows, int cols, double scale_min, double scale_max, double width, double height, double xref, double yref, double ydir) : Values(values), Count(rows*cols), Rows(rows), Cols(cols), ScaleMin(scale_min), ScaleMax(scale_max), Width(width), Height(height), XRef(xref), YRef(yref), YDir(ydir), HalfSize(Width*0.5, Height*0.5) { } template <typename I> IMPLOT_INLINE RectC operator()(I idx) const { double val = (double)Values[idx]; const int r = idx / Cols; const int c = idx % Cols; const ImPlotPoint p(XRef + HalfSize.x + c*Width, YRef + YDir * (HalfSize.y + r*Height)); RectC rect; rect.Pos = p; rect.HalfSize = HalfSize; const float t = ImClamp((float)ImRemap01(val, ScaleMin, ScaleMax),0.0f,1.0f); ImPlotContext& gp = *GImPlot; rect.Color = gp.ColormapData.LerpTable(gp.Style.Colormap, t); return rect; } const T* const Values; const int Count, Rows, Cols; const double ScaleMin, ScaleMax, Width, Height, XRef, YRef, YDir; const ImPlotPoint HalfSize; }; template <typename T> struct GetterHeatmapColMaj { GetterHeatmapColMaj(const T* values, int rows, int cols, double scale_min, double scale_max, double width, double height, double xref, double yref, double ydir) : Values(values), Count(rows*cols), Rows(rows), Cols(cols), ScaleMin(scale_min), ScaleMax(scale_max), Width(width), Height(height), XRef(xref), YRef(yref), YDir(ydir), HalfSize(Width*0.5, Height*0.5) { } template <typename I> IMPLOT_INLINE RectC operator()(I idx) const { double val = (double)Values[idx]; const int r = idx % Rows; const int c = idx / Rows; const ImPlotPoint p(XRef + HalfSize.x + c*Width, YRef + YDir * (HalfSize.y + r*Height)); RectC rect; rect.Pos = p; rect.HalfSize = HalfSize; const float t = ImClamp((float)ImRemap01(val, ScaleMin, ScaleMax),0.0f,1.0f); ImPlotContext& gp = *GImPlot; rect.Color = gp.ColormapData.LerpTable(gp.Style.Colormap, t); return rect; } const T* const Values; const int Count, Rows, Cols; const double ScaleMin, ScaleMax, Width, Height, XRef, YRef, YDir; const ImPlotPoint HalfSize; }; template <typename T> void RenderHeatmap(ImDrawList& draw_list, const T* values, int rows, int cols, double scale_min, double scale_max, const char* fmt, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max, bool reverse_y, bool col_maj) { ImPlotContext& gp = *GImPlot; Transformer2 transformer; if (scale_min == 0 && scale_max == 0) { T temp_min, temp_max; ImMinMaxArray(values,rows*cols,&temp_min,&temp_max); scale_min = (double)temp_min; scale_max = (double)temp_max; } if (scale_min == scale_max) { ImVec2 a = transformer(bounds_min); ImVec2 b = transformer(bounds_max); ImU32 col = GetColormapColorU32(0,gp.Style.Colormap); draw_list.AddRectFilled(a, b, col); return; } const double yref = reverse_y ? bounds_max.y : bounds_min.y; const double ydir = reverse_y ? -1 : 1; if (col_maj) { GetterHeatmapColMaj<T> getter(values, rows, cols, scale_min, scale_max, (bounds_max.x - bounds_min.x) / cols, (bounds_max.y - bounds_min.y) / rows, bounds_min.x, yref, ydir); RenderPrimitives1<RendererRectC>(getter); } else { GetterHeatmapRowMaj<T> getter(values, rows, cols, scale_min, scale_max, (bounds_max.x - bounds_min.x) / cols, (bounds_max.y - bounds_min.y) / rows, bounds_min.x, yref, ydir); RenderPrimitives1<RendererRectC>(getter); } // labels if (fmt != nullptr) { const double w = (bounds_max.x - bounds_min.x) / cols; const double h = (bounds_max.y - bounds_min.y) / rows; const ImPlotPoint half_size(w*0.5,h*0.5); int i = 0; if (col_maj) { for (int c = 0; c < cols; ++c) { for (int r = 0; r < rows; ++r) { ImPlotPoint p; p.x = bounds_min.x + 0.5*w + c*w; p.y = yref + ydir * (0.5*h + r*h); ImVec2 px = transformer(p); char buff[32]; 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); ImU32 col = CalcTextColor(color); draw_list.AddText(px - size * 0.5f, col, buff); i++; } } } else { for (int r = 0; r < rows; ++r) { for (int c = 0; c < cols; ++c) { ImPlotPoint p; p.x = bounds_min.x + 0.5*w + c*w; p.y = yref + ydir * (0.5*h + r*h); ImVec2 px = transformer(p); char buff[32]; 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); ImU32 col = CalcTextColor(color); draw_list.AddText(px - size * 0.5f, col, buff); i++; } } } } } template <typename T> void PlotHeatmap(const char* label_id, const T* values, int rows, int cols, double scale_min, double scale_max, const char* fmt, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max, ImPlotHeatmapFlags flags) { if (BeginItemEx(label_id, FitterRect(bounds_min, bounds_max))) { if (rows <= 0 || cols <= 0) { EndItem(); return; } ImDrawList& draw_list = *GetPlotDrawList(); const bool col_maj = ImHasFlag(flags, ImPlotHeatmapFlags_ColMajor); RenderHeatmap(draw_list, values, rows, cols, scale_min, scale_max, fmt, bounds_min, bounds_max, true, col_maj); EndItem(); } } #define INSTANTIATE_MACRO(T) template IMPLOT_API void PlotHeatmap<T>(const char* label_id, const T* values, int rows, int cols, double scale_min, double scale_max, const char* fmt, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max, ImPlotHeatmapFlags flags); CALL_INSTANTIATE_FOR_NUMERIC_TYPES() #undef INSTANTIATE_MACRO //----------------------------------------------------------------------------- // [SECTION] PlotHistogram //----------------------------------------------------------------------------- template <typename T> double PlotHistogram(const char* label_id, const T* values, int count, int bins, double bar_scale, ImPlotRange range, ImPlotHistogramFlags flags) { const bool cumulative = ImHasFlag(flags, ImPlotHistogramFlags_Cumulative); const bool density = ImHasFlag(flags, ImPlotHistogramFlags_Density); const bool outliers = !ImHasFlag(flags, ImPlotHistogramFlags_NoOutliers); if (count <= 0 || bins == 0) return 0; if (range.Min == 0 && range.Max == 0) { T Min, Max; ImMinMaxArray(values, count, &Min, &Max); range.Min = (double)Min; range.Max = (double)Max; } double width; if (bins < 0) CalculateBins(values, count, bins, range, bins, width); else width = range.Size() / bins; ImPlotContext& gp = *GImPlot; ImVector<double>& bin_centers = gp.TempDouble1; ImVector<double>& bin_counts = gp.TempDouble2; bin_centers.resize(bins); bin_counts.resize(bins); int below = 0; for (int b = 0; b < bins; ++b) { bin_centers[b] = range.Min + b * width + width * 0.5; bin_counts[b] = 0; } int counted = 0; double max_count = 0; for (int i = 0; i < count; ++i) { double val = (double)values[i]; if (range.Contains(val)) { const int b = ImClamp((int)((val - range.Min) / width), 0, bins - 1); bin_counts[b] += 1.0; if (bin_counts[b] > max_count) max_count = bin_counts[b]; counted++; } else if (val < range.Min) { below++; } } if (cumulative && density) { if (outliers) bin_counts[0] += below; for (int b = 1; b < bins; ++b) bin_counts[b] += bin_counts[b-1]; double scale = 1.0 / (outliers ? count : counted); for (int b = 0; b < bins; ++b) bin_counts[b] *= scale; max_count = bin_counts[bins-1]; } else if (cumulative) { if (outliers) bin_counts[0] += below; for (int b = 1; b < bins; ++b) bin_counts[b] += bin_counts[b-1]; max_count = bin_counts[bins-1]; } else if (density) { double scale = 1.0 / ((outliers ? count : counted) * width); for (int b = 0; b < bins; ++b) bin_counts[b] *= scale; max_count *= scale; } if (ImHasFlag(flags, ImPlotHistogramFlags_Horizontal)) PlotBars(label_id, &bin_counts.Data[0], &bin_centers.Data[0], bins, bar_scale*width, ImPlotBarsFlags_Horizontal); else PlotBars(label_id, &bin_centers.Data[0], &bin_counts.Data[0], bins, bar_scale*width); return max_count; } #define INSTANTIATE_MACRO(T) template IMPLOT_API double PlotHistogram<T>(const char* label_id, const T* values, int count, int bins, double bar_scale, ImPlotRange range, ImPlotHistogramFlags flags); CALL_INSTANTIATE_FOR_NUMERIC_TYPES() #undef INSTANTIATE_MACRO //----------------------------------------------------------------------------- // [SECTION] PlotHistogram2D //----------------------------------------------------------------------------- template <typename T> double PlotHistogram2D(const char* label_id, const T* xs, const T* ys, int count, int x_bins, int y_bins, ImPlotRect range, ImPlotHistogramFlags flags) { // const bool cumulative = ImHasFlag(flags, ImPlotHistogramFlags_Cumulative); NOT SUPPORTED const bool density = ImHasFlag(flags, ImPlotHistogramFlags_Density); const bool outliers = !ImHasFlag(flags, ImPlotHistogramFlags_NoOutliers); const bool col_maj = ImHasFlag(flags, ImPlotHistogramFlags_ColMajor); if (count <= 0 || x_bins == 0 || y_bins == 0) return 0; if (range.X.Min == 0 && range.X.Max == 0) { T Min, Max; ImMinMaxArray(xs, count, &Min, &Max); range.X.Min = (double)Min; range.X.Max = (double)Max; } if (range.Y.Min == 0 && range.Y.Max == 0) { T Min, Max; ImMinMaxArray(ys, count, &Min, &Max); range.Y.Min = (double)Min; range.Y.Max = (double)Max; } double width, height; if (x_bins < 0) CalculateBins(xs, count, x_bins, range.X, x_bins, width); else width = range.X.Size() / x_bins; if (y_bins < 0) CalculateBins(ys, count, y_bins, range.Y, y_bins, height); else height = range.Y.Size() / y_bins; const int bins = x_bins * y_bins; ImPlotContext& gp = *GImPlot; ImVector<double>& bin_counts = gp.TempDouble1; bin_counts.resize(bins); for (int b = 0; b < bins; ++b) bin_counts[b] = 0; int counted = 0; double max_count = 0; for (int i = 0; i < count; ++i) { if (range.Contains((double)xs[i], (double)ys[i])) { const int xb = ImClamp( (int)((double)(xs[i] - range.X.Min) / width) , 0, x_bins - 1); const int yb = ImClamp( (int)((double)(ys[i] - range.Y.Min) / height) , 0, y_bins - 1); const int b = yb * x_bins + xb; bin_counts[b] += 1.0; if (bin_counts[b] > max_count) max_count = bin_counts[b]; counted++; } } if (density) { double scale = 1.0 / ((outliers ? count : counted) * width * height); for (int b = 0; b < bins; ++b) bin_counts[b] *= scale; max_count *= scale; } if (BeginItemEx(label_id, FitterRect(range))) { if (y_bins <= 0 || x_bins <= 0) { EndItem(); return max_count; } ImDrawList& draw_list = *GetPlotDrawList(); RenderHeatmap(draw_list, &bin_counts.Data[0], y_bins, x_bins, 0, max_count, nullptr, range.Min(), range.Max(), false, col_maj); EndItem(); } return max_count; } #define INSTANTIATE_MACRO(T) template IMPLOT_API double PlotHistogram2D<T>(const char* label_id, const T* xs, const T* ys, int count, int x_bins, int y_bins, ImPlotRect range, ImPlotHistogramFlags flags); CALL_INSTANTIATE_FOR_NUMERIC_TYPES() #undef INSTANTIATE_MACRO //----------------------------------------------------------------------------- // [SECTION] PlotDigital //----------------------------------------------------------------------------- // TODO: Make this behave like all the other plot types (.e. not fixed in y axis) template <typename Getter> void PlotDigitalEx(const char* label_id, Getter getter, ImPlotDigitalFlags flags) { if (BeginItem(label_id, flags, ImPlotCol_Fill)) { ImPlotContext& gp = *GImPlot; ImDrawList& draw_list = *GetPlotDrawList(); const ImPlotNextItemData& s = GetItemData(); if (getter.Count > 1 && s.RenderFill) { 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) { ImPlotPoint itemData2 = getter(i); if (ImNanOrInf(itemData1.y)) { itemData1 = itemData2; continue; } if (ImNanOrInf(itemData2.y)) itemData2.y = ImConstrainNan(ImConstrainInf(itemData2.y)); int pixY_0 = (int)(s.LineWeight); itemData1.y = ImMax(0.0, itemData1.y); float pixY_1_float = s.DigitalBitHeight * (float)itemData1.y; 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,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,IMPLOT_AUTO,IMPLOT_AUTO).x; i++; } //do not extend plot outside plot range 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 - 1; //fix issue related to https://github.com/ocornut/imgui/issues/3976 if (pMax.x > x_axis.PixelMax) pMax.x = x_axis.PixelMax - 1; //fix issue related to https://github.com/ocornut/imgui/issues/3976 //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; // colAlpha.w = item->Highlight ? 1.0f : 0.9f; draw_list.AddRectFilled(pMin, pMax, ImGui::GetColorU32(s.Colors[ImPlotCol_Fill])); } itemData1 = itemData2; } gp.DigitalPlotItemCnt++; gp.DigitalPlotOffset += pixYMax; } EndItem(); } } template <typename T> void PlotDigital(const char* label_id, const T* xs, const T* ys, int count, ImPlotDigitalFlags flags, int offset, int stride) { GetterXY<IndexerIdx<T>,IndexerIdx<T>> getter(IndexerIdx<T>(xs,count,offset,stride),IndexerIdx<T>(ys,count,offset,stride),count); return PlotDigitalEx(label_id, getter, flags); } #define INSTANTIATE_MACRO(T) template IMPLOT_API void PlotDigital<T>(const char* label_id, const T* xs, const T* ys, int count, ImPlotDigitalFlags flags, int offset, int stride); CALL_INSTANTIATE_FOR_NUMERIC_TYPES() #undef INSTANTIATE_MACRO // custom void PlotDigitalG(const char* label_id, ImPlotGetter getter_func, void* data, int count, ImPlotDigitalFlags flags) { GetterFuncPtr getter(getter_func,data,count); return PlotDigitalEx(label_id, getter, flags); } //----------------------------------------------------------------------------- // [SECTION] PlotImage //----------------------------------------------------------------------------- void PlotImage(const char* label_id, ImTextureID user_texture_id, const ImPlotPoint& bmin, const ImPlotPoint& bmax, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, ImPlotImageFlags) { if (BeginItemEx(label_id, FitterRect(bmin,bmax))) { ImU32 tint_col32 = ImGui::ColorConvertFloat4ToU32(tint_col); GetCurrentItem()->Color = tint_col32; ImDrawList& draw_list = *GetPlotDrawList(); ImVec2 p1 = PlotToPixels(bmin.x, bmax.y,IMPLOT_AUTO,IMPLOT_AUTO); ImVec2 p2 = PlotToPixels(bmax.x, bmin.y,IMPLOT_AUTO,IMPLOT_AUTO); PushPlotClipRect(); draw_list.AddImage(user_texture_id, p1, p2, uv0, uv1, tint_col32); PopPlotClipRect(); EndItem(); } } //----------------------------------------------------------------------------- // [SECTION] PlotText //----------------------------------------------------------------------------- void PlotText(const char* text, double x, double y, const ImVec2& pixel_offset, ImPlotTextFlags flags) { IM_ASSERT_USER_ERROR(GImPlot->CurrentPlot != nullptr, "PlotText() needs to be called between BeginPlot() and EndPlot()!"); SetupLock(); ImDrawList & draw_list = *GetPlotDrawList(); PushPlotClipRect(); ImU32 colTxt = GetStyleColorU32(ImPlotCol_InlayText); if (ImHasFlag(flags,ImPlotTextFlags_Vertical)) { 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() && !ImHasFlag(flags, ImPlotItemFlags_NoFit)) { FitPoint(PixelsToPlot(pos)); FitPoint(PixelsToPlot(pos.x + siz.x, pos.y - siz.y)); } AddTextVertical(&draw_list, pos, colTxt, text); } else { ImVec2 siz = ImGui::CalcTextSize(text); ImVec2 pos = PlotToPixels(ImPlotPoint(x,y),IMPLOT_AUTO,IMPLOT_AUTO) - siz * 0.5f + pixel_offset; if (FitThisFrame() && !ImHasFlag(flags, ImPlotItemFlags_NoFit)) { FitPoint(PixelsToPlot(pos)); FitPoint(PixelsToPlot(pos+siz)); } draw_list.AddText(pos, colTxt, text); } PopPlotClipRect(); } //----------------------------------------------------------------------------- // [SECTION] PlotDummy //----------------------------------------------------------------------------- void PlotDummy(const char* label_id, ImPlotDummyFlags flags) { if (BeginItem(label_id, flags, ImPlotCol_Line)) EndItem(); } } // namespace ImPlot