1
0
mirror of synced 2025-01-11 22:02:17 +01:00
ImHex/lib/third_party/imgui/implot3d/source/implot3d_items.cpp

1339 lines
58 KiB
C++
Raw Normal View History

2024-12-17 23:51:45 +01:00
//--------------------------------------------------
// ImPlot3D v0.1
// implot3d_items.cpp
// Date: 2024-11-26
// Author: Breno Cunha Queiroz (brenocq.com)
//
// Acknowledgments:
// ImPlot3D is heavily inspired by ImPlot
// (https://github.com/epezent/implot) by Evan Pezent,
// and follows a similar code style and structure to
// maintain consistency with ImPlot's API.
//--------------------------------------------------
// Table of Contents:
// [SECTION] Includes
// [SECTION] Macros & Defines
// [SECTION] Template instantiation utility
// [SECTION] Item Utils
// [SECTION] Draw Utils
// [SECTION] Renderers
// [SECTION] Indexers
// [SECTION] Getters
// [SECTION] RenderPrimitives
// [SECTION] Markers
// [SECTION] PlotScatter
// [SECTION] PlotLine
// [SECTION] PlotTriangle
// [SECTION] PlotText
//-----------------------------------------------------------------------------
// [SECTION] Includes
//-----------------------------------------------------------------------------
#ifndef IMGUI_DEFINE_MATH_OPERATORS
#define IMGUI_DEFINE_MATH_OPERATORS
#endif
#include "implot3d.h"
#include "implot3d_internal.h"
#ifndef IMGUI_DISABLE
//-----------------------------------------------------------------------------
// [SECTION] Macros & Defines
//-----------------------------------------------------------------------------
#define SQRT_1_2 0.70710678118f
#define SQRT_3_2 0.86602540378f
// clang-format off
#ifndef IMPLOT3D_NO_FORCE_INLINE
#ifdef _MSC_VER
#define IMPLOT3D_INLINE __forceinline
#elif defined(__GNUC__)
#define IMPLOT3D_INLINE inline __attribute__((__always_inline__))
#elif defined(__CLANG__)
#if __has_attribute(__always_inline__)
#define IMPLOT3D_INLINE inline __attribute__((__always_inline__))
#else
#define IMPLOT3D_INLINE inline
#endif
#else
#define IMPLOT3D_INLINE inline
#endif
#else
#define IMPLOT3D_INLINE inline
#endif
// clang-format on
#define IMPLOT3D_NORMALIZE2F(VX, VY) \
do { \
float d2 = VX * VX + VY * VY; \
if (d2 > 0.0f) { \
float inv_len = ImRsqrt(d2); \
VX *= inv_len; \
VY *= inv_len; \
} \
} while (0)
IMPLOT3D_INLINE void GetLineRenderProps(const ImDrawList3D& draw_list_3d, float& half_weight, ImVec2& tex_uv0, ImVec2& tex_uv1) {
const bool aa = ImPlot3D::ImHasFlag(draw_list_3d._Flags, ImDrawListFlags_AntiAliasedLines) &&
ImPlot3D::ImHasFlag(draw_list_3d._Flags, ImDrawListFlags_AntiAliasedLinesUseTex);
if (aa) {
ImVec4 tex_uvs = draw_list_3d._SharedData->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_3d._SharedData->TexUvWhitePixel;
}
}
//-----------------------------------------------------------------------------
// [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 IMPLOT3D_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.
// -DIMPLOT3D_CUSTOM_NUMERIC_TYPES="(float)(double)"
// In order to support all known C++ types, use:
// -DIMPLOT3D_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 IMPLOT3D_CUSTOM_NUMERIC_TYPES
#define IMPLOT3D_NUMERIC_TYPES IMPLOT3D_CUSTOM_NUMERIC_TYPES
#else
#define IMPLOT3D_NUMERIC_TYPES (ImS8)(ImU8)(ImS16)(ImU16)(ImS32)(ImU32)(ImS64)(ImU64)(float)(double)
#endif
// CALL_INSTANTIATE_FOR_NUMERIC_TYPES will duplicate the template instantiation 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(IMPLOT3D_NUMERIC_TYPES)
//-----------------------------------------------------------------------------
// [SECTION] Item Utils
//-----------------------------------------------------------------------------
namespace ImPlot3D {
static const float ITEM_HIGHLIGHT_LINE_SCALE = 2.0f;
static const float ITEM_HIGHLIGHT_MARK_SCALE = 1.25f;
bool BeginItem(const char* label_id, ImPlot3DItemFlags flags, ImPlot3DCol recolor_from) {
ImPlot3DContext& gp = *GImPlot3D;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr, "PlotX() needs to be called between BeginPlot() and EndPlot()!");
// Lock setup
SetupLock();
ImPlot3DStyle& style = gp.Style;
ImPlot3DNextItemData& n = gp.NextItemData;
// Register item
bool just_created;
ImPlot3DItem* item = RegisterOrGetItem(label_id, flags, &just_created);
// Set/override item color
if (recolor_from != -1) {
if (!IsColorAuto(n.Colors[recolor_from]))
item->Color = ImGui::ColorConvertFloat4ToU32(n.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();
}
// Set next item color
ImVec4 item_color = ImGui::ColorConvertU32ToFloat4(item->Color);
n.IsAutoLine = IsColorAuto(n.Colors[ImPlot3DCol_Line]) && IsColorAuto(ImPlot3DCol_Line);
n.IsAutoFill = IsColorAuto(n.Colors[ImPlot3DCol_Fill]) && IsColorAuto(ImPlot3DCol_Fill);
n.Colors[ImPlot3DCol_Line] = IsColorAuto(n.Colors[ImPlot3DCol_Line]) ? (IsColorAuto(ImPlot3DCol_Line) ? item_color : gp.Style.Colors[ImPlot3DCol_Line]) : n.Colors[ImPlot3DCol_Line];
n.Colors[ImPlot3DCol_Fill] = IsColorAuto(n.Colors[ImPlot3DCol_Fill]) ? (IsColorAuto(ImPlot3DCol_Fill) ? item_color : gp.Style.Colors[ImPlot3DCol_Fill]) : n.Colors[ImPlot3DCol_Fill];
n.Colors[ImPlot3DCol_MarkerOutline] = IsColorAuto(n.Colors[ImPlot3DCol_MarkerOutline]) ? (IsColorAuto(ImPlot3DCol_MarkerOutline) ? n.Colors[ImPlot3DCol_Line] : gp.Style.Colors[ImPlot3DCol_MarkerOutline]) : n.Colors[ImPlot3DCol_MarkerOutline];
n.Colors[ImPlot3DCol_MarkerFill] = IsColorAuto(n.Colors[ImPlot3DCol_MarkerFill]) ? (IsColorAuto(ImPlot3DCol_MarkerFill) ? n.Colors[ImPlot3DCol_Line] : gp.Style.Colors[ImPlot3DCol_MarkerFill]) : n.Colors[ImPlot3DCol_MarkerFill];
// Set size & weight
n.LineWeight = n.LineWeight < 0.0f ? style.LineWeight : n.LineWeight;
n.Marker = n.Marker < 0 ? style.Marker : n.Marker;
n.MarkerSize = n.MarkerSize < 0.0f ? style.MarkerSize : n.MarkerSize;
n.MarkerWeight = n.MarkerWeight < 0.0f ? style.MarkerWeight : n.MarkerWeight;
n.FillAlpha = n.FillAlpha < 0 ? gp.Style.FillAlpha : n.FillAlpha;
// Apply alpha modifiers
n.Colors[ImPlot3DCol_Fill].w *= n.FillAlpha;
n.Colors[ImPlot3DCol_MarkerFill].w *= n.FillAlpha;
// Set render flags
n.RenderLine = n.Colors[ImPlot3DCol_Line].w > 0 && n.LineWeight > 0;
n.RenderFill = n.Colors[ImPlot3DCol_Fill].w > 0;
n.RenderMarkerFill = n.Colors[ImPlot3DCol_MarkerFill].w > 0;
n.RenderMarkerLine = n.Colors[ImPlot3DCol_MarkerOutline].w > 0 && n.MarkerWeight > 0;
// Don't render if item is hidden
if (!item->Show) {
EndItem();
return false;
} else {
// Legend hover highlight
if (item->LegendHovered) {
if (!ImHasFlag(gp.CurrentItems->Legend.Flags, ImPlot3DLegendFlags_NoHighlightItem)) {
n.LineWeight *= ITEM_HIGHLIGHT_LINE_SCALE;
n.MarkerSize *= ITEM_HIGHLIGHT_MARK_SCALE;
n.MarkerWeight *= ITEM_HIGHLIGHT_LINE_SCALE;
}
}
}
return true;
}
template <typename _Getter>
bool BeginItemEx(const char* label_id, const _Getter& getter, ImPlot3DItemFlags flags = 0, ImPlot3DCol recolor_from = IMPLOT3D_AUTO) {
if (BeginItem(label_id, flags, recolor_from)) {
ImPlot3DContext& gp = *GImPlot3D;
ImPlot3DPlot& plot = *gp.CurrentPlot;
if (plot.FitThisFrame && !ImHasFlag(flags, ImPlot3DItemFlags_NoFit)) {
for (int i = 0; i < getter.Count; i++)
plot.ExtendFit(getter(i));
}
return true;
}
return false;
}
void EndItem() {
ImPlot3DContext& gp = *GImPlot3D;
gp.NextItemData.Reset();
}
ImPlot3DItem* RegisterOrGetItem(const char* label_id, ImPlot3DItemFlags flags, bool* just_created) {
ImPlot3DContext& gp = *GImPlot3D;
ImPlot3DItemGroup& Items = *gp.CurrentItems;
ImGuiID id = Items.GetItemID(label_id);
if (just_created != nullptr)
*just_created = Items.GetItem(id) == nullptr;
ImPlot3DItem* item = Items.GetOrAddItem(id);
// Avoid re-adding the same item to the legend (the legend is reset every frame)
if (item->SeenThisFrame)
return item;
item->SeenThisFrame = true;
// Add item to the legend
int idx = Items.GetItemIndex(item);
item->ID = id;
if (!ImHasFlag(flags, ImPlot3DItemFlags_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);
}
return item;
}
void BustItemCache() {
ImPlot3DContext& gp = *GImPlot3D;
for (int p = 0; p < gp.Plots.GetBufSize(); ++p) {
ImPlot3DPlot& plot = *gp.Plots.GetByIndex(p);
plot.Items.Reset();
}
}
void SetNextLineStyle(const ImVec4& col, float weight) {
ImPlot3DContext& gp = *GImPlot3D;
ImPlot3DNextItemData& n = gp.NextItemData;
n.Colors[ImPlot3DCol_Line] = col;
n.LineWeight = weight;
}
void SetNextFillStyle(const ImVec4& col, float alpha) {
ImPlot3DContext& gp = *GImPlot3D;
ImPlot3DNextItemData& n = gp.NextItemData;
gp.NextItemData.Colors[ImPlot3DCol_Fill] = col;
gp.NextItemData.FillAlpha = alpha;
}
void SetNextMarkerStyle(ImPlot3DMarker marker, float size, const ImVec4& fill, float weight, const ImVec4& outline) {
ImPlot3DContext& gp = *GImPlot3D;
ImPlot3DNextItemData& n = gp.NextItemData;
n.Marker = marker;
n.Colors[ImPlot3DCol_MarkerFill] = fill;
n.MarkerSize = size;
n.Colors[ImPlot3DCol_MarkerOutline] = outline;
n.MarkerWeight = weight;
}
//-----------------------------------------------------------------------------
// [SECTION] Draw Utils
//-----------------------------------------------------------------------------
IMPLOT3D_INLINE void PrimLine(ImDrawList3D& draw_list_3d, const ImVec2& P1, const ImVec2& P2, float half_weight, ImU32 col, const ImVec2& tex_uv0, const ImVec2 tex_uv1, float z) {
float dx = P2.x - P1.x;
float dy = P2.y - P1.y;
IMPLOT3D_NORMALIZE2F(dx, dy);
dx *= half_weight;
dy *= half_weight;
draw_list_3d._VtxWritePtr[0].pos.x = P1.x + dy;
draw_list_3d._VtxWritePtr[0].pos.y = P1.y - dx;
draw_list_3d._VtxWritePtr[0].uv = tex_uv0;
draw_list_3d._VtxWritePtr[0].col = col;
draw_list_3d._VtxWritePtr[1].pos.x = P2.x + dy;
draw_list_3d._VtxWritePtr[1].pos.y = P2.y - dx;
draw_list_3d._VtxWritePtr[1].uv = tex_uv0;
draw_list_3d._VtxWritePtr[1].col = col;
draw_list_3d._VtxWritePtr[2].pos.x = P2.x - dy;
draw_list_3d._VtxWritePtr[2].pos.y = P2.y + dx;
draw_list_3d._VtxWritePtr[2].uv = tex_uv1;
draw_list_3d._VtxWritePtr[2].col = col;
draw_list_3d._VtxWritePtr[3].pos.x = P1.x - dy;
draw_list_3d._VtxWritePtr[3].pos.y = P1.y + dx;
draw_list_3d._VtxWritePtr[3].uv = tex_uv1;
draw_list_3d._VtxWritePtr[3].col = col;
draw_list_3d._VtxWritePtr += 4;
draw_list_3d._IdxWritePtr[0] = (ImDrawIdx)(draw_list_3d._VtxCurrentIdx);
draw_list_3d._IdxWritePtr[1] = (ImDrawIdx)(draw_list_3d._VtxCurrentIdx + 1);
draw_list_3d._IdxWritePtr[2] = (ImDrawIdx)(draw_list_3d._VtxCurrentIdx + 2);
draw_list_3d._IdxWritePtr[3] = (ImDrawIdx)(draw_list_3d._VtxCurrentIdx);
draw_list_3d._IdxWritePtr[4] = (ImDrawIdx)(draw_list_3d._VtxCurrentIdx + 2);
draw_list_3d._IdxWritePtr[5] = (ImDrawIdx)(draw_list_3d._VtxCurrentIdx + 3);
draw_list_3d._IdxWritePtr += 6;
draw_list_3d._VtxCurrentIdx += 4;
draw_list_3d._ZWritePtr[0] = z;
draw_list_3d._ZWritePtr[1] = z;
draw_list_3d._ZWritePtr += 2;
}
//-----------------------------------------------------------------------------
// [SECTION] Renderers
//-----------------------------------------------------------------------------
float GetPointDepth(ImPlot3DPoint p) {
ImPlot3DContext& gp = *GImPlot3D;
ImPlot3DPlot& plot = *gp.CurrentPlot;
ImPlot3DPoint p_rot = plot.Rotation * p;
return p_rot.z;
}
struct RendererBase {
RendererBase(int prims, int idx_consumed, int vtx_consumed) : Prims(prims),
IdxConsumed(idx_consumed),
VtxConsumed(vtx_consumed) {}
const unsigned int Prims; // Number of primitives to render
const unsigned int IdxConsumed; // Number of indices consumed per primitive
const unsigned int VtxConsumed; // Number of vertices consumed per primitive
};
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(ImDrawList3D& draw_list_3d) const {
UV = draw_list_3d._SharedData->TexUvWhitePixel;
}
IMPLOT3D_INLINE bool Render(ImDrawList3D& draw_list_3d, const ImPlot3DBox& cull_box, int prim) const {
ImPlot3DPoint p_plot = Getter(prim);
if (!cull_box.Contains(p_plot))
return false;
ImVec2 p = PlotToPixels(p_plot);
// 3 vertices per triangle
for (int i = 0; i < Count; i++) {
draw_list_3d._VtxWritePtr[0].pos.x = p.x + Marker[i].x * Size;
draw_list_3d._VtxWritePtr[0].pos.y = p.y + Marker[i].y * Size;
draw_list_3d._VtxWritePtr[0].uv = UV;
draw_list_3d._VtxWritePtr[0].col = Col;
draw_list_3d._VtxWritePtr++;
}
// 3 indices per triangle
for (int i = 2; i < Count; i++) {
// Indices
draw_list_3d._IdxWritePtr[0] = (ImDrawIdx)(draw_list_3d._VtxCurrentIdx);
draw_list_3d._IdxWritePtr[1] = (ImDrawIdx)(draw_list_3d._VtxCurrentIdx + i - 1);
draw_list_3d._IdxWritePtr[2] = (ImDrawIdx)(draw_list_3d._VtxCurrentIdx + i);
draw_list_3d._IdxWritePtr += 3;
// Z
draw_list_3d._ZWritePtr[0] = GetPointDepth(p_plot);
draw_list_3d._ZWritePtr++;
}
// Update vertex count
draw_list_3d._VtxCurrentIdx += (ImDrawIdx)Count;
return true;
}
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(ImDrawList3D& draw_list_3d) const {
GetLineRenderProps(draw_list_3d, HalfWeight, UV0, UV1);
}
IMPLOT3D_INLINE bool Render(ImDrawList3D& draw_list_3d, const ImPlot3DBox& cull_box, int prim) const {
ImPlot3DPoint p_plot = Getter(prim);
if (!cull_box.Contains(p_plot))
return false;
ImVec2 p = PlotToPixels(p_plot);
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_3d, p1, p2, HalfWeight, Col, UV0, UV1, GetPointDepth(p_plot));
}
return true;
}
const _Getter& Getter;
const ImVec2* Marker;
const int Count;
mutable float HalfWeight;
const float Size;
const ImU32 Col;
mutable ImVec2 UV0;
mutable ImVec2 UV1;
};
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) {
// Initialize the first point in plot coordinates
P1_plot = Getter(0);
}
void Init(ImDrawList3D& draw_list_3d) const {
GetLineRenderProps(draw_list_3d, HalfWeight, UV0, UV1);
}
IMPLOT3D_INLINE bool Render(ImDrawList3D& draw_list_3d, const ImPlot3DBox& cull_box, int prim) const {
ImPlot3DPoint P2_plot = Getter(prim + 1);
// Clip the line segment to the culling box using Liang-Barsky algorithm
ImPlot3DPoint P1_clipped, P2_clipped;
bool visible = cull_box.ClipLineSegment(P1_plot, P2_plot, P1_clipped, P2_clipped);
if (visible) {
// Convert clipped points to pixel coordinates
ImVec2 P1_screen = PlotToPixels(P1_clipped);
ImVec2 P2_screen = PlotToPixels(P2_clipped);
// Render the line segment
PrimLine(draw_list_3d, P1_screen, P2_screen, HalfWeight, Col, UV0, UV1, GetPointDepth((P1_plot + P2_plot) * 0.5f));
}
// Update for next segment
P1_plot = P2_plot;
return visible;
}
const _Getter& Getter;
const ImU32 Col;
mutable float HalfWeight;
mutable ImPlot3DPoint P1_plot;
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) {
// Initialize the first point in plot coordinates
P1_plot = Getter(0);
}
void Init(ImDrawList3D& draw_list_3d) const {
GetLineRenderProps(draw_list_3d, HalfWeight, UV0, UV1);
}
IMPLOT3D_INLINE bool Render(ImDrawList3D& draw_list_3d, const ImPlot3DBox& cull_box, int prim) const {
// Get the next point in plot coordinates
ImPlot3DPoint P2_plot = Getter(prim + 1);
bool visible = false;
// Check for NaNs in P1_plot and P2_plot
if (!ImNan(P1_plot.x) && !ImNan(P1_plot.y) && !ImNan(P1_plot.z) &&
!ImNan(P2_plot.x) && !ImNan(P2_plot.y) && !ImNan(P2_plot.z)) {
// Clip the line segment to the culling box
ImPlot3DPoint P1_clipped, P2_clipped;
visible = cull_box.ClipLineSegment(P1_plot, P2_plot, P1_clipped, P2_clipped);
if (visible) {
// Convert clipped points to pixel coordinates
ImVec2 P1_screen = PlotToPixels(P1_clipped);
ImVec2 P2_screen = PlotToPixels(P2_clipped);
// Render the line segment
PrimLine(draw_list_3d, P1_screen, P2_screen, HalfWeight, Col, UV0, UV1, GetPointDepth((P1_plot + P2_plot) * 0.5f));
}
}
// Update P1_plot if P2_plot is valid
if (!ImNan(P2_plot.x) && !ImNan(P2_plot.y) && !ImNan(P2_plot.z))
P1_plot = P2_plot;
return visible;
}
const _Getter& Getter;
const ImU32 Col;
mutable float HalfWeight;
mutable ImPlot3DPoint P1_plot;
mutable ImVec2 UV0;
mutable ImVec2 UV1;
};
template <class _Getter>
struct RendererLineSegments : RendererBase {
RendererLineSegments(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(ImDrawList3D& draw_list_3d) const {
GetLineRenderProps(draw_list_3d, HalfWeight, UV0, UV1);
}
IMPLOT3D_INLINE bool Render(ImDrawList3D& draw_list_3d, const ImPlot3DBox& cull_box, int prim) const {
// Get the segment's endpoints in plot coordinates
ImPlot3DPoint P1_plot = Getter(prim * 2 + 0);
ImPlot3DPoint P2_plot = Getter(prim * 2 + 1);
// Check for NaNs in P1_plot and P2_plot
if (!ImNan(P1_plot.x) && !ImNan(P1_plot.y) && !ImNan(P1_plot.z) &&
!ImNan(P2_plot.x) && !ImNan(P2_plot.y) && !ImNan(P2_plot.z)) {
// Clip the line segment to the culling box
ImPlot3DPoint P1_clipped, P2_clipped;
bool visible = cull_box.ClipLineSegment(P1_plot, P2_plot, P1_clipped, P2_clipped);
if (visible) {
// Convert clipped points to pixel coordinates
ImVec2 P1_screen = PlotToPixels(P1_clipped);
ImVec2 P2_screen = PlotToPixels(P2_clipped);
// Render the line segment
PrimLine(draw_list_3d, P1_screen, P2_screen, HalfWeight, Col, UV0, UV1, GetPointDepth((P1_plot + P2_plot) * 0.5f));
}
return visible;
}
return false;
}
const _Getter& Getter;
const ImU32 Col;
mutable float HalfWeight;
mutable ImVec2 UV0;
mutable ImVec2 UV1;
};
template <class _Getter>
struct RendererTriangleFill : RendererBase {
RendererTriangleFill(const _Getter& getter, ImU32 col) : RendererBase(getter.Count / 3, 3, 3),
Getter(getter),
Col(col) {}
void Init(ImDrawList3D& draw_list_3d) const {
UV = draw_list_3d._SharedData->TexUvWhitePixel;
}
IMPLOT3D_INLINE bool Render(ImDrawList3D& draw_list_3d, const ImPlot3DBox& cull_box, int prim) const {
ImPlot3DPoint p_plot[3];
p_plot[0] = Getter(3 * prim);
p_plot[1] = Getter(3 * prim + 1);
p_plot[2] = Getter(3 * prim + 2);
// Check if the triangle is outside the culling box
if (!cull_box.Contains(p_plot[0]) && !cull_box.Contains(p_plot[0]) && !cull_box.Contains(p_plot[1]))
return false;
// Project the triangle vertices to screen space
ImVec2 p[3];
p[0] = PlotToPixels(p_plot[0]);
p[1] = PlotToPixels(p_plot[1]);
p[2] = PlotToPixels(p_plot[2]);
// 3 vertices per triangle
draw_list_3d._VtxWritePtr[0].pos.x = p[0].x;
draw_list_3d._VtxWritePtr[0].pos.y = p[0].y;
draw_list_3d._VtxWritePtr[0].uv = UV;
draw_list_3d._VtxWritePtr[0].col = Col;
draw_list_3d._VtxWritePtr[1].pos.x = p[1].x;
draw_list_3d._VtxWritePtr[1].pos.y = p[1].y;
draw_list_3d._VtxWritePtr[1].uv = UV;
draw_list_3d._VtxWritePtr[1].col = Col;
draw_list_3d._VtxWritePtr[2].pos.x = p[2].x;
draw_list_3d._VtxWritePtr[2].pos.y = p[2].y;
draw_list_3d._VtxWritePtr[2].uv = UV;
draw_list_3d._VtxWritePtr[2].col = Col;
draw_list_3d._VtxWritePtr += 3;
// 3 indices per triangle
draw_list_3d._IdxWritePtr[0] = (ImDrawIdx)(draw_list_3d._VtxCurrentIdx);
draw_list_3d._IdxWritePtr[1] = (ImDrawIdx)(draw_list_3d._VtxCurrentIdx + 1);
draw_list_3d._IdxWritePtr[2] = (ImDrawIdx)(draw_list_3d._VtxCurrentIdx + 2);
draw_list_3d._IdxWritePtr += 3;
// 1 Z per vertex
draw_list_3d._ZWritePtr[0] = GetPointDepth((p_plot[0] + p_plot[1] + p_plot[2]) / 3);
draw_list_3d._ZWritePtr++;
// Update vertex count
draw_list_3d._VtxCurrentIdx += 3;
return true;
}
const _Getter& Getter;
mutable ImVec2 UV;
const ImU32 Col;
};
template <class _Getter>
struct RendererQuadFill : RendererBase {
RendererQuadFill(const _Getter& getter, ImU32 col) : RendererBase(getter.Count / 4, 6, 4),
Getter(getter),
Col(col) {}
void Init(ImDrawList3D& draw_list_3d) const {
UV = draw_list_3d._SharedData->TexUvWhitePixel;
}
IMPLOT3D_INLINE bool Render(ImDrawList3D& draw_list_3d, const ImPlot3DBox& cull_box, int prim) const {
ImPlot3DPoint p_plot[4];
p_plot[0] = Getter(4 * prim);
p_plot[1] = Getter(4 * prim + 1);
p_plot[2] = Getter(4 * prim + 2);
p_plot[3] = Getter(4 * prim + 3);
// Check if the quad is outside the culling box
if (!cull_box.Contains(p_plot[0]) && !cull_box.Contains(p_plot[1]) &&
!cull_box.Contains(p_plot[2]) && !cull_box.Contains(p_plot[3]))
return false;
// Project the quad vertices to screen space
ImVec2 p[4];
p[0] = PlotToPixels(p_plot[0]);
p[1] = PlotToPixels(p_plot[1]);
p[2] = PlotToPixels(p_plot[2]);
p[3] = PlotToPixels(p_plot[3]);
// Add vertices for two triangles
draw_list_3d._VtxWritePtr[0].pos.x = p[0].x;
draw_list_3d._VtxWritePtr[0].pos.y = p[0].y;
draw_list_3d._VtxWritePtr[0].uv = UV;
draw_list_3d._VtxWritePtr[0].col = Col;
draw_list_3d._VtxWritePtr[1].pos.x = p[1].x;
draw_list_3d._VtxWritePtr[1].pos.y = p[1].y;
draw_list_3d._VtxWritePtr[1].uv = UV;
draw_list_3d._VtxWritePtr[1].col = Col;
draw_list_3d._VtxWritePtr[2].pos.x = p[2].x;
draw_list_3d._VtxWritePtr[2].pos.y = p[2].y;
draw_list_3d._VtxWritePtr[2].uv = UV;
draw_list_3d._VtxWritePtr[2].col = Col;
draw_list_3d._VtxWritePtr[3].pos.x = p[3].x;
draw_list_3d._VtxWritePtr[3].pos.y = p[3].y;
draw_list_3d._VtxWritePtr[3].uv = UV;
draw_list_3d._VtxWritePtr[3].col = Col;
draw_list_3d._VtxWritePtr += 4;
// Add indices for two triangles
draw_list_3d._IdxWritePtr[0] = (ImDrawIdx)(draw_list_3d._VtxCurrentIdx);
draw_list_3d._IdxWritePtr[1] = (ImDrawIdx)(draw_list_3d._VtxCurrentIdx + 1);
draw_list_3d._IdxWritePtr[2] = (ImDrawIdx)(draw_list_3d._VtxCurrentIdx + 2);
draw_list_3d._IdxWritePtr[3] = (ImDrawIdx)(draw_list_3d._VtxCurrentIdx);
draw_list_3d._IdxWritePtr[4] = (ImDrawIdx)(draw_list_3d._VtxCurrentIdx + 2);
draw_list_3d._IdxWritePtr[5] = (ImDrawIdx)(draw_list_3d._VtxCurrentIdx + 3);
draw_list_3d._IdxWritePtr += 6;
// Add depth values for the two triangles
draw_list_3d._ZWritePtr[0] = GetPointDepth((p_plot[0] + p_plot[1] + p_plot[2]) / 3.0f);
draw_list_3d._ZWritePtr[1] = GetPointDepth((p_plot[0] + p_plot[2] + p_plot[3]) / 3.0f);
draw_list_3d._ZWritePtr += 2;
// Update vertex count
draw_list_3d._VtxCurrentIdx += 4;
return true;
}
const _Getter& Getter;
mutable ImVec2 UV;
const ImU32 Col;
};
template <class _Getter>
struct RendererSurfaceFill : RendererBase {
RendererSurfaceFill(const _Getter& getter, int x_count, int y_count, ImU32 col) : RendererBase((x_count - 1) * (y_count - 1), 6, 4),
Getter(getter),
XCount(x_count),
YCount(y_count),
Col(col) {}
void Init(ImDrawList3D& draw_list_3d) const {
UV = draw_list_3d._SharedData->TexUvWhitePixel;
// Compute min and max values for the colormap (if not solid fill)
const ImPlot3DNextItemData& n = GetItemData();
if (n.IsAutoFill) {
Min = FLT_MAX;
Max = -FLT_MAX;
for (int i = 0; i < Getter.Count; i++) {
float z = Getter(i).z;
Min = ImMin(Min, z);
Max = ImMax(Max, z);
}
}
}
IMPLOT3D_INLINE bool Render(ImDrawList3D& draw_list_3d, const ImPlot3DBox& cull_box, int prim) const {
int x = prim % (XCount - 1);
int y = prim / (XCount - 1);
ImPlot3DPoint p_plot[4];
p_plot[0] = Getter(x + y * XCount);
p_plot[1] = Getter(x + 1 + y * XCount);
p_plot[2] = Getter(x + 1 + (y + 1) * XCount);
p_plot[3] = Getter(x + (y + 1) * XCount);
// Check if the quad is outside the culling box
if (!cull_box.Contains(p_plot[0]) && !cull_box.Contains(p_plot[1]) &&
!cull_box.Contains(p_plot[2]) && !cull_box.Contains(p_plot[3]))
return false;
// Compute colors
ImU32 cols[4] = {Col, Col, Col, Col};
const ImPlot3DNextItemData& n = GetItemData();
if (n.IsAutoFill) {
float alpha = GImPlot3D->NextItemData.FillAlpha;
for (int i = 0; i < 4; i++) {
ImVec4 col = SampleColormap(ImClamp(ImRemap01(p_plot[i].z, Min, Max), 0.0f, 1.0f));
col.w *= alpha;
cols[i] = ImGui::ColorConvertFloat4ToU32(col);
}
}
// Project the quad vertices to screen space
ImVec2 p[4];
p[0] = PlotToPixels(p_plot[0]);
p[1] = PlotToPixels(p_plot[1]);
p[2] = PlotToPixels(p_plot[2]);
p[3] = PlotToPixels(p_plot[3]);
// Add vertices for two triangles
draw_list_3d._VtxWritePtr[0].pos.x = p[0].x;
draw_list_3d._VtxWritePtr[0].pos.y = p[0].y;
draw_list_3d._VtxWritePtr[0].uv = UV;
draw_list_3d._VtxWritePtr[0].col = cols[0];
draw_list_3d._VtxWritePtr[1].pos.x = p[1].x;
draw_list_3d._VtxWritePtr[1].pos.y = p[1].y;
draw_list_3d._VtxWritePtr[1].uv = UV;
draw_list_3d._VtxWritePtr[1].col = cols[1];
draw_list_3d._VtxWritePtr[2].pos.x = p[2].x;
draw_list_3d._VtxWritePtr[2].pos.y = p[2].y;
draw_list_3d._VtxWritePtr[2].uv = UV;
draw_list_3d._VtxWritePtr[2].col = cols[2];
draw_list_3d._VtxWritePtr[3].pos.x = p[3].x;
draw_list_3d._VtxWritePtr[3].pos.y = p[3].y;
draw_list_3d._VtxWritePtr[3].uv = UV;
draw_list_3d._VtxWritePtr[3].col = cols[3];
draw_list_3d._VtxWritePtr += 4;
// Add indices for two triangles
draw_list_3d._IdxWritePtr[0] = (ImDrawIdx)(draw_list_3d._VtxCurrentIdx);
draw_list_3d._IdxWritePtr[1] = (ImDrawIdx)(draw_list_3d._VtxCurrentIdx + 1);
draw_list_3d._IdxWritePtr[2] = (ImDrawIdx)(draw_list_3d._VtxCurrentIdx + 2);
draw_list_3d._IdxWritePtr[3] = (ImDrawIdx)(draw_list_3d._VtxCurrentIdx);
draw_list_3d._IdxWritePtr[4] = (ImDrawIdx)(draw_list_3d._VtxCurrentIdx + 2);
draw_list_3d._IdxWritePtr[5] = (ImDrawIdx)(draw_list_3d._VtxCurrentIdx + 3);
draw_list_3d._IdxWritePtr += 6;
// Add depth values for the two triangles
draw_list_3d._ZWritePtr[0] = GetPointDepth((p_plot[0] + p_plot[1] + p_plot[2]) / 3.0f);
draw_list_3d._ZWritePtr[1] = GetPointDepth((p_plot[0] + p_plot[2] + p_plot[3]) / 3.0f);
draw_list_3d._ZWritePtr += 2;
// Update vertex count
draw_list_3d._VtxCurrentIdx += 4;
return true;
}
const _Getter& Getter;
mutable ImVec2 UV;
mutable float Min; // Minimum value for the colormap
mutable float Max; // Minimum value for the colormap
const int XCount;
const int YCount;
const ImU32 Col;
};
//-----------------------------------------------------------------------------
// [SECTION] Indexers
//-----------------------------------------------------------------------------
template <typename T>
IMPLOT3D_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(offset),
Stride(stride) {}
template <typename I> IMPLOT3D_INLINE double operator()(I idx) const {
return (double)IndexData(Data, idx, Count, Offset, Stride);
}
const T* Data;
int Count;
int Offset;
int Stride;
};
//-----------------------------------------------------------------------------
// [SECTION] Getters
//-----------------------------------------------------------------------------
template <typename _IndexerX, typename _IndexerY, typename _IndexerZ>
struct GetterXYZ {
GetterXYZ(_IndexerX x, _IndexerY y, _IndexerZ z, int count) : IndexerX(x), IndexerY(y), IndexerZ(z), Count(count) {}
template <typename I> IMPLOT3D_INLINE ImPlot3DPoint operator()(I idx) const {
return ImPlot3DPoint(IndexerX(idx), IndexerY(idx), IndexerZ(idx));
}
const _IndexerX IndexerX;
const _IndexerY IndexerY;
const _IndexerZ IndexerZ;
const int Count;
};
template <typename _Getter>
struct GetterLoop {
GetterLoop(_Getter getter) : Getter(getter), Count(getter.Count + 1) {}
template <typename I> IMPLOT3D_INLINE ImPlot3DPoint operator()(I idx) const {
idx = idx % (Count - 1);
return Getter(idx);
}
const _Getter Getter;
const int Count;
};
template <typename _Getter>
struct GetterTriangleLines {
GetterTriangleLines(_Getter getter) : Getter(getter), Count(getter.Count * 2) {}
template <typename I> IMPLOT3D_INLINE ImPlot3DPoint operator()(I idx) const {
idx = ((idx % 6 + 1) / 2) % 3 + idx / 6 * 3;
return Getter(idx);
}
const _Getter Getter;
const int Count;
};
template <typename _Getter>
struct GetterQuadLines {
GetterQuadLines(_Getter getter) : Getter(getter), Count(getter.Count * 2) {}
template <typename I> IMPLOT3D_INLINE ImPlot3DPoint operator()(I idx) const {
idx = ((idx % 8 + 1) / 2) % 4 + idx / 8 * 4;
return Getter(idx);
}
const _Getter Getter;
const int Count;
};
template <typename _Getter>
struct GetterSurfaceLines {
GetterSurfaceLines(_Getter getter, int x_count, int y_count)
: Getter(getter), XCount(x_count), YCount(y_count) {
int horizontal_segments = (XCount - 1) * YCount;
int vertical_segments = (YCount - 1) * XCount;
int segments = horizontal_segments + vertical_segments;
Count = segments * 2; // Each segment has 2 endpoints
}
template <typename I> IMPLOT3D_INLINE ImPlot3DPoint operator()(I idx) const {
// idx is an endpoint index
int endpoint_i = (int)(idx % 2);
int segment_i = (int)(idx / 2);
int horizontal_segments = (XCount - 1) * YCount;
int px, py;
if (segment_i < horizontal_segments) {
// Horizontal segment
int row = segment_i / (XCount - 1);
int col = segment_i % (XCount - 1);
// Endpoint 0 is (col, row), endpoint 1 is (col+1, row)
px = endpoint_i == 0 ? col : col + 1;
py = row;
} else {
// Vertical segment
int seg_v = segment_i - horizontal_segments;
int col = seg_v / (YCount - 1);
int row = seg_v % (YCount - 1);
// Endpoint 0 is (col, row), endpoint 1 is (col, row+1)
px = col;
py = row + endpoint_i;
}
return Getter(py * XCount + px);
}
const _Getter Getter;
int Count;
const int XCount;
const int YCount;
};
struct Getter3DPoints {
Getter3DPoints(const ImPlot3DPoint* points, int count) : Points(points), Count(count) {}
template <typename I> IMPLOT3D_INLINE ImPlot3DPoint operator()(I idx) const {
return Points[idx];
}
const ImPlot3DPoint* Points;
const int Count;
};
struct GetterMeshTriangles {
GetterMeshTriangles(const ImPlot3DPoint* vtx, const unsigned int* idx, int idx_count)
: Vtx(vtx), Idx(idx), IdxCount(idx_count), TriCount(idx_count / 3), Count(idx_count) {}
template <typename I>
IMPLOT3D_INLINE ImPlot3DPoint operator()(I i) const {
unsigned int vi = Idx[i];
return Vtx[vi];
}
const ImPlot3DPoint* Vtx;
const unsigned int* Idx;
int IdxCount;
int TriCount;
int Count;
};
//-----------------------------------------------------------------------------
// [SECTION] RenderPrimitives
//-----------------------------------------------------------------------------
/// Renders primitive shapes
template <template <class> class _Renderer, class _Getter, typename... Args>
void RenderPrimitives(const _Getter& getter, Args... args) {
_Renderer<_Getter> renderer(getter, args...);
ImPlot3DPlot& plot = *GetCurrentPlot();
ImDrawList3D& draw_list_3d = plot.DrawList;
ImPlot3DBox cull_box;
if (ImHasFlag(plot.Flags, ImPlot3DFlags_NoClip)) {
cull_box.Min = ImPlot3DPoint(-HUGE_VAL, -HUGE_VAL, -HUGE_VAL);
cull_box.Max = ImPlot3DPoint(HUGE_VAL, HUGE_VAL, HUGE_VAL);
} else {
cull_box.Min = plot.RangeMin();
cull_box.Max = plot.RangeMax();
}
// Find how many can be reserved up to end of current draw command's limit
unsigned int prims_to_render = ImMin(renderer.Prims, (ImDrawList3D::MaxIdx() - draw_list_3d._VtxCurrentIdx) / renderer.VtxConsumed);
// Reserve vertices and indices to render the primitives
draw_list_3d.PrimReserve(prims_to_render * renderer.IdxConsumed, prims_to_render * renderer.VtxConsumed);
// Initialize renderer
renderer.Init(draw_list_3d);
// Render primitives
int num_culled = 0;
for (unsigned int i = 0; i < prims_to_render; i++)
if (!renderer.Render(draw_list_3d, cull_box, i))
num_culled++;
// Unreserve unused vertices and indices
draw_list_3d.PrimUnreserve(num_culled * renderer.IdxConsumed, num_culled * renderer.VtxConsumed);
}
//-----------------------------------------------------------------------------
// [SECTION] Markers
//-----------------------------------------------------------------------------
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, ImPlot3DMarker marker, float size, bool rend_fill, ImU32 col_fill, bool rend_line, ImU32 col_line, float weight) {
if (rend_fill) {
switch (marker) {
case ImPlot3DMarker_Circle: RenderPrimitives<RendererMarkersFill>(getter, MARKER_FILL_CIRCLE, 10, size, col_fill); break;
case ImPlot3DMarker_Square: RenderPrimitives<RendererMarkersFill>(getter, MARKER_FILL_SQUARE, 4, size, col_fill); break;
case ImPlot3DMarker_Diamond: RenderPrimitives<RendererMarkersFill>(getter, MARKER_FILL_DIAMOND, 4, size, col_fill); break;
case ImPlot3DMarker_Up: RenderPrimitives<RendererMarkersFill>(getter, MARKER_FILL_UP, 3, size, col_fill); break;
case ImPlot3DMarker_Down: RenderPrimitives<RendererMarkersFill>(getter, MARKER_FILL_DOWN, 3, size, col_fill); break;
case ImPlot3DMarker_Left: RenderPrimitives<RendererMarkersFill>(getter, MARKER_FILL_LEFT, 3, size, col_fill); break;
case ImPlot3DMarker_Right: RenderPrimitives<RendererMarkersFill>(getter, MARKER_FILL_RIGHT, 3, size, col_fill); break;
}
}
if (rend_line) {
switch (marker) {
case ImPlot3DMarker_Circle: RenderPrimitives<RendererMarkersLine>(getter, MARKER_LINE_CIRCLE, 20, size, weight, col_line); break;
case ImPlot3DMarker_Square: RenderPrimitives<RendererMarkersLine>(getter, MARKER_LINE_SQUARE, 8, size, weight, col_line); break;
case ImPlot3DMarker_Diamond: RenderPrimitives<RendererMarkersLine>(getter, MARKER_LINE_DIAMOND, 8, size, weight, col_line); break;
case ImPlot3DMarker_Up: RenderPrimitives<RendererMarkersLine>(getter, MARKER_LINE_UP, 6, size, weight, col_line); break;
case ImPlot3DMarker_Down: RenderPrimitives<RendererMarkersLine>(getter, MARKER_LINE_DOWN, 6, size, weight, col_line); break;
case ImPlot3DMarker_Left: RenderPrimitives<RendererMarkersLine>(getter, MARKER_LINE_LEFT, 6, size, weight, col_line); break;
case ImPlot3DMarker_Right: RenderPrimitives<RendererMarkersLine>(getter, MARKER_LINE_RIGHT, 6, size, weight, col_line); break;
case ImPlot3DMarker_Asterisk: RenderPrimitives<RendererMarkersLine>(getter, MARKER_LINE_ASTERISK, 6, size, weight, col_line); break;
case ImPlot3DMarker_Plus: RenderPrimitives<RendererMarkersLine>(getter, MARKER_LINE_PLUS, 4, size, weight, col_line); break;
case ImPlot3DMarker_Cross: RenderPrimitives<RendererMarkersLine>(getter, MARKER_LINE_CROSS, 4, size, weight, col_line); break;
}
}
}
//-----------------------------------------------------------------------------
// [SECTION] PlotScatter
//-----------------------------------------------------------------------------
template <typename Getter>
void PlotScatterEx(const char* label_id, const Getter& getter, ImPlot3DScatterFlags flags) {
if (BeginItemEx(label_id, getter, flags, ImPlot3DCol_MarkerOutline)) {
const ImPlot3DNextItemData& n = GetItemData();
ImPlot3DMarker marker = n.Marker == ImPlot3DMarker_None ? ImPlot3DMarker_Circle : n.Marker;
const ImU32 col_line = ImGui::GetColorU32(n.Colors[ImPlot3DCol_MarkerOutline]);
const ImU32 col_fill = ImGui::GetColorU32(n.Colors[ImPlot3DCol_MarkerFill]);
if (marker != ImPlot3DMarker_None)
RenderMarkers<Getter>(getter, marker, n.MarkerSize, n.RenderMarkerFill, col_fill, n.RenderMarkerLine, col_line, n.MarkerWeight);
EndItem();
}
}
template <typename T>
void PlotScatter(const char* label_id, const T* xs, const T* ys, const T* zs, int count, ImPlot3DScatterFlags flags, int offset, int stride) {
if (count < 1)
return;
GetterXYZ<IndexerIdx<T>, IndexerIdx<T>, IndexerIdx<T>> getter(IndexerIdx<T>(xs, count, offset, stride), IndexerIdx<T>(ys, count, offset, stride), IndexerIdx<T>(zs, count, offset, stride), count);
return PlotScatterEx(label_id, getter, flags);
}
#define INSTANTIATE_MACRO(T) \
template IMPLOT3D_API void PlotScatter<T>(const char* label_id, const T* xs, const T* ys, const T* zs, int count, ImPlot3DScatterFlags flags, int offset, int stride);
CALL_INSTANTIATE_FOR_NUMERIC_TYPES()
#undef INSTANTIATE_MACRO
//-----------------------------------------------------------------------------
// [SECTION] PlotLine
//-----------------------------------------------------------------------------
template <typename _Getter>
void PlotLineEx(const char* label_id, const _Getter& getter, ImPlot3DLineFlags flags) {
if (BeginItemEx(label_id, getter, flags, ImPlot3DCol_Line)) {
const ImPlot3DNextItemData& n = GetItemData();
if (getter.Count >= 2 && n.RenderLine) {
const ImU32 col_line = ImGui::GetColorU32(n.Colors[ImPlot3DCol_Line]);
if (ImHasFlag(flags, ImPlot3DLineFlags_Segments)) {
RenderPrimitives<RendererLineSegments>(getter, col_line, n.LineWeight);
} else if (ImHasFlag(flags, ImPlot3DLineFlags_Loop)) {
if (ImHasFlag(flags, ImPlot3DLineFlags_SkipNaN))
RenderPrimitives<RendererLineStripSkip>(GetterLoop<_Getter>(getter), col_line, n.LineWeight);
else
RenderPrimitives<RendererLineStrip>(GetterLoop<_Getter>(getter), col_line, n.LineWeight);
} else {
if (ImHasFlag(flags, ImPlot3DLineFlags_SkipNaN))
RenderPrimitives<RendererLineStripSkip>(getter, col_line, n.LineWeight);
else
RenderPrimitives<RendererLineStrip>(getter, col_line, n.LineWeight);
}
}
// Render markers
if (n.Marker != ImPlot3DMarker_None) {
const ImU32 col_line = ImGui::GetColorU32(n.Colors[ImPlot3DCol_MarkerOutline]);
const ImU32 col_fill = ImGui::GetColorU32(n.Colors[ImPlot3DCol_MarkerFill]);
RenderMarkers<_Getter>(getter, n.Marker, n.MarkerSize, n.RenderMarkerFill, col_fill, n.RenderMarkerLine, col_line, n.MarkerWeight);
}
EndItem();
}
}
IMPLOT3D_TMP void PlotLine(const char* label_id, const T* xs, const T* ys, const T* zs, int count, ImPlot3DLineFlags flags, int offset, int stride) {
if (count < 2)
return;
GetterXYZ<IndexerIdx<T>, IndexerIdx<T>, IndexerIdx<T>> getter(IndexerIdx<T>(xs, count, offset, stride), IndexerIdx<T>(ys, count, offset, stride), IndexerIdx<T>(zs, count, offset, stride), count);
return PlotLineEx(label_id, getter, flags);
}
#define INSTANTIATE_MACRO(T) \
template IMPLOT3D_API void PlotLine<T>(const char* label_id, const T* xs, const T* ys, const T* zs, int count, ImPlot3DLineFlags flags, int offset, int stride);
CALL_INSTANTIATE_FOR_NUMERIC_TYPES()
#undef INSTANTIATE_MACRO
//-----------------------------------------------------------------------------
// [SECTION] PlotTriangle
//-----------------------------------------------------------------------------
template <typename _Getter>
void PlotTriangleEx(const char* label_id, const _Getter& getter, ImPlot3DTriangleFlags flags) {
if (BeginItemEx(label_id, getter, flags, ImPlot3DCol_Fill)) {
const ImPlot3DNextItemData& n = GetItemData();
// Render fill
if (getter.Count >= 3 && n.RenderFill) {
const ImU32 col_fill = ImGui::GetColorU32(n.Colors[ImPlot3DCol_Fill]);
RenderPrimitives<RendererTriangleFill>(getter, col_fill);
}
// Render lines
if (getter.Count >= 2 && n.RenderLine) {
const ImU32 col_line = ImGui::GetColorU32(n.Colors[ImPlot3DCol_Line]);
RenderPrimitives<RendererLineSegments>(GetterTriangleLines<_Getter>(getter), col_line, n.LineWeight);
}
// Render markers
if (n.Marker != ImPlot3DMarker_None) {
const ImU32 col_line = ImGui::GetColorU32(n.Colors[ImPlot3DCol_MarkerOutline]);
const ImU32 col_fill = ImGui::GetColorU32(n.Colors[ImPlot3DCol_MarkerFill]);
RenderMarkers<_Getter>(getter, n.Marker, n.MarkerSize, n.RenderMarkerFill, col_fill, n.RenderMarkerLine, col_line, n.MarkerWeight);
}
EndItem();
}
}
IMPLOT3D_TMP void PlotTriangle(const char* label_id, const T* xs, const T* ys, const T* zs, int count, ImPlot3DTriangleFlags flags, int offset, int stride) {
if (count < 3)
return;
GetterXYZ<IndexerIdx<T>, IndexerIdx<T>, IndexerIdx<T>> getter(IndexerIdx<T>(xs, count, offset, stride), IndexerIdx<T>(ys, count, offset, stride), IndexerIdx<T>(zs, count, offset, stride), count);
return PlotTriangleEx(label_id, getter, flags);
}
#define INSTANTIATE_MACRO(T) \
template IMPLOT3D_API void PlotTriangle<T>(const char* label_id, const T* xs, const T* ys, const T* zs, int count, ImPlot3DTriangleFlags flags, int offset, int stride);
CALL_INSTANTIATE_FOR_NUMERIC_TYPES()
#undef INSTANTIATE_MACRO
//-----------------------------------------------------------------------------
// [SECTION] PlotQuad
//-----------------------------------------------------------------------------
template <typename _Getter>
void PlotQuadEx(const char* label_id, const _Getter& getter, ImPlot3DQuadFlags flags) {
if (BeginItemEx(label_id, getter, flags, ImPlot3DCol_Fill)) {
const ImPlot3DNextItemData& n = GetItemData();
// Render fill
if (getter.Count >= 4 && n.RenderFill) {
const ImU32 col_fill = ImGui::GetColorU32(n.Colors[ImPlot3DCol_Fill]);
RenderPrimitives<RendererQuadFill>(getter, col_fill);
}
// Render lines
if (getter.Count >= 2 && n.RenderLine) {
const ImU32 col_line = ImGui::GetColorU32(n.Colors[ImPlot3DCol_Line]);
RenderPrimitives<RendererLineSegments>(GetterQuadLines<_Getter>(getter), col_line, n.LineWeight);
}
// Render markers
if (n.Marker != ImPlot3DMarker_None) {
const ImU32 col_line = ImGui::GetColorU32(n.Colors[ImPlot3DCol_MarkerOutline]);
const ImU32 col_fill = ImGui::GetColorU32(n.Colors[ImPlot3DCol_MarkerFill]);
RenderMarkers<_Getter>(getter, n.Marker, n.MarkerSize, n.RenderMarkerFill, col_fill, n.RenderMarkerLine, col_line, n.MarkerWeight);
}
EndItem();
}
}
IMPLOT3D_TMP void PlotQuad(const char* label_id, const T* xs, const T* ys, const T* zs, int count, ImPlot3DQuadFlags flags, int offset, int stride) {
if (count < 3)
return;
GetterXYZ<IndexerIdx<T>, IndexerIdx<T>, IndexerIdx<T>> getter(IndexerIdx<T>(xs, count, offset, stride), IndexerIdx<T>(ys, count, offset, stride), IndexerIdx<T>(zs, count, offset, stride), count);
return PlotQuadEx(label_id, getter, flags);
}
#define INSTANTIATE_MACRO(T) \
template IMPLOT3D_API void PlotQuad<T>(const char* label_id, const T* xs, const T* ys, const T* zs, int count, ImPlot3DQuadFlags flags, int offset, int stride);
CALL_INSTANTIATE_FOR_NUMERIC_TYPES()
#undef INSTANTIATE_MACRO
//-----------------------------------------------------------------------------
// [SECTION] PlotSurface
//-----------------------------------------------------------------------------
template <typename _Getter>
void PlotSurfaceEx(const char* label_id, const _Getter& getter, int x_count, int y_count, ImPlot3DSurfaceFlags flags) {
if (BeginItemEx(label_id, getter, flags, ImPlot3DCol_Fill)) {
const ImPlot3DNextItemData& n = GetItemData();
// Render fill
if (getter.Count >= 4 && n.RenderFill) {
const ImU32 col_fill = ImGui::GetColorU32(n.Colors[ImPlot3DCol_Fill]);
RenderPrimitives<RendererSurfaceFill>(getter, x_count, y_count, col_fill);
}
// Render lines
if (getter.Count >= 2 && n.RenderLine) {
const ImU32 col_line = ImGui::GetColorU32(n.Colors[ImPlot3DCol_Line]);
RenderPrimitives<RendererLineSegments>(GetterSurfaceLines<_Getter>(getter, x_count, y_count), col_line, n.LineWeight);
}
// Render markers
if (n.Marker != ImPlot3DMarker_None) {
const ImU32 col_line = ImGui::GetColorU32(n.Colors[ImPlot3DCol_MarkerOutline]);
const ImU32 col_fill = ImGui::GetColorU32(n.Colors[ImPlot3DCol_MarkerFill]);
RenderMarkers<_Getter>(getter, n.Marker, n.MarkerSize, n.RenderMarkerFill, col_fill, n.RenderMarkerLine, col_line, n.MarkerWeight);
}
EndItem();
}
}
IMPLOT3D_TMP void PlotSurface(const char* label_id, const T* xs, const T* ys, const T* zs, int x_count, int y_count, ImPlot3DSurfaceFlags flags, int offset, int stride) {
int count = x_count * y_count;
if (count < 4)
return;
GetterXYZ<IndexerIdx<T>, IndexerIdx<T>, IndexerIdx<T>> getter(IndexerIdx<T>(xs, count, offset, stride), IndexerIdx<T>(ys, count, offset, stride), IndexerIdx<T>(zs, count, offset, stride), count);
return PlotSurfaceEx(label_id, getter, x_count, y_count, flags);
}
#define INSTANTIATE_MACRO(T) \
template IMPLOT3D_API void PlotSurface<T>(const char* label_id, const T* xs, const T* ys, const T* zs, int x_count, int y_count, ImPlot3DSurfaceFlags flags, int offset, int stride);
CALL_INSTANTIATE_FOR_NUMERIC_TYPES()
#undef INSTANTIATE_MACRO
void PlotMesh(const char* label_id, const ImPlot3DPoint* vtx, const unsigned int* idx, int vtx_count, int idx_count, ImPlot3DMeshFlags flags) {
Getter3DPoints getter(vtx, vtx_count); // Get vertices
GetterMeshTriangles getter_triangles(vtx, idx, idx_count); // Get triangle vertices
if (BeginItemEx(label_id, getter, flags, ImPlot3DCol_Fill)) {
const ImPlot3DNextItemData& n = GetItemData();
// Render fill
if (getter.Count >= 3 && n.RenderFill) {
const ImU32 col_fill = ImGui::GetColorU32(n.Colors[ImPlot3DCol_Fill]);
RenderPrimitives<RendererTriangleFill>(getter_triangles, col_fill);
}
// Render lines
if (getter.Count >= 2 && n.RenderLine && !n.IsAutoLine) {
const ImU32 col_line = ImGui::GetColorU32(n.Colors[ImPlot3DCol_Line]);
RenderPrimitives<RendererLineSegments>(GetterTriangleLines<GetterMeshTriangles>(getter_triangles), col_line, n.LineWeight);
}
// Render markers
if (n.Marker != ImPlot3DMarker_None) {
const ImU32 col_line = ImGui::GetColorU32(n.Colors[ImPlot3DCol_MarkerOutline]);
const ImU32 col_fill = ImGui::GetColorU32(n.Colors[ImPlot3DCol_MarkerFill]);
RenderMarkers(getter, n.Marker, n.MarkerSize, n.RenderMarkerFill, col_fill, n.RenderMarkerLine, col_line, n.MarkerWeight);
}
EndItem();
}
}
//-----------------------------------------------------------------------------
// [SECTION] PlotText
//-----------------------------------------------------------------------------
void PlotText(const char* text, float x, float y, float z, float angle, const ImVec2& pix_offset) {
ImPlot3DContext& gp = *GImPlot3D;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr, "PlotText() needs to be called between BeginPlot() and EndPlot()!");
SetupLock();
ImPlot3DPlot& plot = *gp.CurrentPlot;
ImPlot3DBox cull_box;
if (ImHasFlag(plot.Flags, ImPlot3DFlags_NoClip)) {
cull_box.Min = ImPlot3DPoint(-HUGE_VAL, -HUGE_VAL, -HUGE_VAL);
cull_box.Max = ImPlot3DPoint(HUGE_VAL, HUGE_VAL, HUGE_VAL);
} else {
cull_box.Min = plot.RangeMin();
cull_box.Max = plot.RangeMax();
}
if (!cull_box.Contains(ImPlot3DPoint(x, y, z)))
return;
ImVec2 p = PlotToPixels(ImPlot3DPoint(x, y, z));
p.x += pix_offset.x;
p.y += pix_offset.y;
AddTextRotated(GetPlotDrawList(), p, angle, GetStyleColorU32(ImPlot3DCol_InlayText), text);
}
} // namespace ImPlot3D
#endif // #ifndef IMGUI_DISABLE