diff --git a/implot3d.cpp b/implot3d.cpp index cbe883a6..257ff11e 100644 --- a/implot3d.cpp +++ b/implot3d.cpp @@ -48,6 +48,50 @@ Below is a change-log of API breaking changes only. If you are using one of the When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all implot3d files. You can read releases logs https://github.com/brenocq/implot3d/releases for more details. +- 2026/02/03 (0.4) - ImPlotSpec was made the default and _only_ way of styling plot items. The SetNextXXXStyle functions have been removed. + - SetNextLineStyle has been removed, styling should be set via ImPlot3DSpec. + ```cpp + // Before + ImPlot3D::SetNextLineStyle(line_color, line_weight); + ImPlot3D::PlotLine("Line", xs, ys, zs, count); + + // After + ImPlot3DSpec spec; + spec.LineColor = line_color; + spec.LineWeight = line_weight; + ImPlot3D::PlotLine("Line", xs, ys, zs, count, spec); + ``` + - SetNextFillStyle has been removed, styling should be set via ImPlot3DSpec. + ```cpp + // Before + ImPlot3D::SetNextFillStyle(fill_color, fill_alpha); + ImPlot3D::PlotTriangle("Triangle", xs, ys, zs, count); + + // After + ImPlot3DSpec spec; + spec.FillColor = fill_color; + spec.FillAlpha = fill_alpha; + ImPlot3D::PlotTriangle("Triangle", xs, ys, zs, count, spec); + ``` + - SetNextMarkerStyle has been removed, styling should be set via ImPlot3DSpec. + ```cpp + // Before: + ImPlot3D::SetNextMarkerStyle(marker, marker_size, fill_color, line_weight, marker_outline_color); + ImPlot3D::PlotScatter("Scatter", xs, ys, zs, count); + + // After + ImPlot3DSpec spec; + spec.LineWeight = line_weight; + spec.Marker = marker; + spec.MarkerSize = marker_size; + spec.MarkerLineColor = marker_outline_color; + spec.MarkerFillColor = fill_color; + ImPlot3D::PlotScatter("Scatter", xs, ys, zs, count, spec); + ``` + - Flags, Offset and Stride should also be set via ImPlot3DSpec now. +- 2026/02/02 (0.4) - Item colors removed from ImPlot3DCol_, it's no longer possible to push/pop individual item colors. +- 2026/02/02 (0.4) - ImPlot3DStyle::MarkerWeight was removed. The marker line weight is now controlled by ImPlot3DStyle::LineWeight. + - 2025/11/15 (0.3) - Renamed GetPlotPos() -> GetPlotRectPos() and GetPlotSize() -> GetPlotRectSize() for clarity in 3D context. Old functions are marked as deprecated and will be removed in v1.0. - 2025/10/22 (0.3) - **IMPORTANT** All plot coordinate types migrated from float to double precision to fix sorting issues with large values: @@ -2733,11 +2777,10 @@ struct ImPlot3DStyleVarInfo { static const ImPlot3DStyleVarInfo GPlot3DStyleVarInfo[] = { // Item style - {ImGuiDataType_Float, 1, (ImU32)offsetof(ImPlot3DStyle, LineWeight)}, // ImPlot3DStyleVar_LineWeight - {ImGuiDataType_S32, 1, (ImU32)offsetof(ImPlot3DStyle, Marker)}, // ImPlot3DStyleVar_Marker - {ImGuiDataType_Float, 1, (ImU32)offsetof(ImPlot3DStyle, MarkerSize)}, // ImPlot3DStyleVar_MarkerSize - {ImGuiDataType_Float, 1, (ImU32)offsetof(ImPlot3DStyle, MarkerWeight)}, // ImPlot3DStyleVar_MarkerWeight - {ImGuiDataType_Float, 1, (ImU32)offsetof(ImPlot3DStyle, FillAlpha)}, // ImPlot3DStyleVar_FillAlpha + {ImGuiDataType_Float, 1, (ImU32)offsetof(ImPlot3DStyle, LineWeight)}, // ImPlot3DStyleVar_LineWeight + {ImGuiDataType_S32, 1, (ImU32)offsetof(ImPlot3DStyle, Marker)}, // ImPlot3DStyleVar_Marker + {ImGuiDataType_Float, 1, (ImU32)offsetof(ImPlot3DStyle, MarkerSize)}, // ImPlot3DStyleVar_MarkerSize + {ImGuiDataType_Float, 1, (ImU32)offsetof(ImPlot3DStyle, FillAlpha)}, // ImPlot3DStyleVar_FillAlpha // Plot style {ImGuiDataType_Float, 2, (ImU32)offsetof(ImPlot3DStyle, PlotDefaultSize)}, // ImPlot3DStyleVar_Plot3DDefaultSize @@ -2765,10 +2808,6 @@ void StyleColorsAuto(ImPlot3DStyle* dst) { ImPlot3DStyle* style = dst ? dst : &ImPlot3D::GetStyle(); ImVec4* colors = style->Colors; - colors[ImPlot3DCol_Line] = IMPLOT3D_AUTO_COL; - colors[ImPlot3DCol_Fill] = IMPLOT3D_AUTO_COL; - colors[ImPlot3DCol_MarkerOutline] = IMPLOT3D_AUTO_COL; - colors[ImPlot3DCol_MarkerFill] = IMPLOT3D_AUTO_COL; colors[ImPlot3DCol_TitleText] = IMPLOT3D_AUTO_COL; colors[ImPlot3DCol_InlayText] = IMPLOT3D_AUTO_COL; colors[ImPlot3DCol_FrameBg] = IMPLOT3D_AUTO_COL; @@ -2786,10 +2825,6 @@ void StyleColorsDark(ImPlot3DStyle* dst) { ImPlot3DStyle* style = dst ? dst : &ImPlot3D::GetStyle(); ImVec4* colors = style->Colors; - colors[ImPlot3DCol_Line] = IMPLOT3D_AUTO_COL; - colors[ImPlot3DCol_Fill] = IMPLOT3D_AUTO_COL; - colors[ImPlot3DCol_MarkerOutline] = IMPLOT3D_AUTO_COL; - colors[ImPlot3DCol_MarkerFill] = IMPLOT3D_AUTO_COL; colors[ImPlot3DCol_TitleText] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); colors[ImPlot3DCol_InlayText] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); colors[ImPlot3DCol_FrameBg] = ImVec4(1.00f, 1.00f, 1.00f, 0.07f); @@ -2807,10 +2842,6 @@ void StyleColorsLight(ImPlot3DStyle* dst) { ImPlot3DStyle* style = dst ? dst : &ImPlot3D::GetStyle(); ImVec4* colors = style->Colors; - colors[ImPlot3DCol_Line] = IMPLOT3D_AUTO_COL; - colors[ImPlot3DCol_Fill] = IMPLOT3D_AUTO_COL; - colors[ImPlot3DCol_MarkerOutline] = IMPLOT3D_AUTO_COL; - colors[ImPlot3DCol_MarkerFill] = IMPLOT3D_AUTO_COL; colors[ImPlot3DCol_TitleText] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); colors[ImPlot3DCol_InlayText] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); colors[ImPlot3DCol_FrameBg] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); @@ -2828,10 +2859,6 @@ void StyleColorsClassic(ImPlot3DStyle* dst) { ImPlot3DStyle* style = dst ? dst : &ImPlot3D::GetStyle(); ImVec4* colors = style->Colors; - colors[ImPlot3DCol_Line] = IMPLOT3D_AUTO_COL; - colors[ImPlot3DCol_Fill] = IMPLOT3D_AUTO_COL; - colors[ImPlot3DCol_MarkerOutline] = IMPLOT3D_AUTO_COL; - colors[ImPlot3DCol_MarkerFill] = IMPLOT3D_AUTO_COL; colors[ImPlot3DCol_TitleText] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f); colors[ImPlot3DCol_InlayText] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f); colors[ImPlot3DCol_FrameBg] = ImVec4(0.43f, 0.43f, 0.43f, 0.39f); @@ -2970,6 +2997,14 @@ ImVec4 GetStyleColorVec4(ImPlot3DCol idx) { return IsColorAuto(idx) ? GetAutoCol ImU32 GetStyleColorU32(ImPlot3DCol idx) { return ImGui::ColorConvertFloat4ToU32(ImPlot3D::GetStyleColorVec4(idx)); } +ImPlot3DMarker NextMarker() { + ImPlot3DContext& gp = *GImPlot3D; + IM_ASSERT_USER_ERROR(gp.CurrentItems != nullptr, "NextMarker() needs to be called between BeginPlot() and EndPlot()!"); + const int idx = gp.CurrentItems->MarkerIdx % ImPlot3DMarker_COUNT; + ++gp.CurrentItems->MarkerIdx; + return idx; +} + //------------------------------------------------------------------------------ // [SECTION] Colormaps //------------------------------------------------------------------------------ @@ -3218,10 +3253,6 @@ bool IsColorAuto(ImPlot3DCol idx) { return IsColorAuto(GImPlot3D->Style.Colors[i ImVec4 GetAutoColor(ImPlot3DCol idx) { switch (idx) { - case ImPlot3DCol_Line: return IMPLOT3D_AUTO_COL; // Plot dependent - case ImPlot3DCol_Fill: return IMPLOT3D_AUTO_COL; // Plot dependent - case ImPlot3DCol_MarkerOutline: return IMPLOT3D_AUTO_COL; // Plot dependent - case ImPlot3DCol_MarkerFill: return IMPLOT3D_AUTO_COL; // Plot dependent case ImPlot3DCol_TitleText: return ImGui::GetStyleColorVec4(ImGuiCol_Text); case ImPlot3DCol_InlayText: return ImGui::GetStyleColorVec4(ImGuiCol_Text); case ImPlot3DCol_FrameBg: return ImGui::GetStyleColorVec4(ImGuiCol_FrameBg); @@ -3239,8 +3270,7 @@ ImVec4 GetAutoColor(ImPlot3DCol idx) { const char* GetStyleColorName(ImPlot3DCol idx) { static const char* color_names[ImPlot3DCol_COUNT] = { - "Line", "Fill", "MarkerOutline", "MarkerFill", "TitleText", "InlayText", "FrameBg", "PlotBg", - "PlotBorder", "LegendBg", "LegendBorder", "LegendText", "AxisText", "AxisGrid", "AxisTick", + "TitleText", "InlayText", "FrameBg", "PlotBg", "PlotBorder", "LegendBg", "LegendBorder", "LegendText", "AxisText", "AxisGrid", "AxisTick", }; return color_names[idx]; } @@ -3838,7 +3868,6 @@ ImPlot3DStyle::ImPlot3DStyle() { LineWeight = 1.0f; Marker = ImPlot3DMarker_None; MarkerSize = 4.0f; - MarkerWeight = 1.0f; FillAlpha = 1.0f; // Plot style PlotDefaultSize = ImVec2(400, 400); diff --git a/implot3d.h b/implot3d.h index 6e1968ff..a529f8e5 100644 --- a/implot3d.h +++ b/implot3d.h @@ -13,6 +13,7 @@ // [SECTION] Macros and Defines // [SECTION] Forward declarations and basic types // [SECTION] Flags & Enumerations +// [SECTION] Specs API // [SECTION] Callbacks // [SECTION] Context // [SECTION] Begin/End Plot @@ -20,7 +21,7 @@ // [SECTION] Plot Items // [SECTION] Plot Utils // [SECTION] Miscellaneous -// [SECTION] Styles +// [SECTION] Styles API (legacy) // [SECTION] Demo // [SECTION] Debugging // [SECTION] ImPlot3DPoint @@ -45,7 +46,7 @@ #endif #define IMPLOT3D_VERSION "0.4 WIP" // ImPlot3D version -#define IMPLOT3D_VERSION_NUM 400 // Integer encoded version +#define IMPLOT3D_VERSION_NUM 401 // Integer encoded version #define IMPLOT3D_AUTO -1 // Deduce variable automatically #define IMPLOT3D_AUTO_COL ImVec4(0, 0, 0, -1) // Deduce color automatically #define IMPLOT3D_TMP template IMPLOT3D_API @@ -74,6 +75,7 @@ typedef int ImAxis3D; // -> ImAxis3D_ // Enum: Axis ind typedef int ImPlane3D; // -> ImPlane3D_ // Enum: Plane indices typedef int ImPlot3DScale; // -> ImPlot3DScale_ // Enum: Axis scale (linear, log, etc.) typedef int ImPlot3DColormap; // -> ImPlot3DColormap_ // Enum: Colormaps +typedef int ImPlot3DProp; // -> ImPlot3DProp_ // Enum: Plot properties // Flags typedef int ImPlot3DFlags; // -> ImPlot3DFlags_ // Flags: for BeginPlot() @@ -99,6 +101,21 @@ typedef ImTextureID ImTextureRef; // [SECTION] Flags & Enumerations //----------------------------------------------------------------------------- +// Plotting properties. These provide syntactic sugar for creating ImPlot3DSpec from (ImPlot3DProp,value) pairs +enum ImPlot3DProp_ { + ImPlot3DProp_LineColor, // Line color; IMPLOT3D_AUTO_COL will use next Colormap color + ImPlot3DProp_LineWeight, // Line weight in pixels + ImPlot3DProp_FillColor, // Fill color (applies to shaded regions); IMPLOT3D_AUTO_COL will use next Colormap color + ImPlot3DProp_FillAlpha, // Alpha multiplier (applies to FillColor and MarkerFillColor) + ImPlot3DProp_Marker, // Marker type + ImPlot3DProp_MarkerSize, // Size of markers (radius) *in pixels* + ImPlot3DProp_MarkerLineColor, // Marker outline color; IMPLOT3D_AUTO_COL will use next LineColor + ImPlot3DProp_MarkerFillColor, // Marker fill color; IMPLOT3D_AUTO_COL will use LineColor + ImPlot3DProp_Offset, // Data index offset + ImPlot3DProp_Stride, // Data stride in bytes; IMPLOT3D_AUTO will result in sizeof(T) where T is the type passed to PlotX + ImPlot3DProp_Flags // Optional item flags; can be composed from common ImPlot3DItemFlags and/or specialized ImPlot3DXFlags +}; + // Flags for ImPlot3D::BeginPlot() enum ImPlot3DFlags_ { ImPlot3DFlags_None = 0, // Default @@ -123,11 +140,6 @@ enum ImPlot3DCond_ { }; enum ImPlot3DCol_ { - // Item colors - ImPlot3DCol_Line = 0, // Line color - ImPlot3DCol_Fill, // Fill color - ImPlot3DCol_MarkerOutline, // Marker outline color - ImPlot3DCol_MarkerFill, // Marker fill color // Plot colors ImPlot3DCol_TitleText, // Title color ImPlot3DCol_InlayText, // Color for texts appearing inside of plots @@ -148,11 +160,10 @@ enum ImPlot3DCol_ { // Plot styling variables enum ImPlot3DStyleVar_ { // Item style - ImPlot3DStyleVar_LineWeight, // float, plot item line weight in pixels - ImPlot3DStyleVar_Marker, // int, marker specification - ImPlot3DStyleVar_MarkerSize, // float, marker size in pixels (roughly the marker's "radius") - ImPlot3DStyleVar_MarkerWeight, // float, plot outline weight of markers in pixels - ImPlot3DStyleVar_FillAlpha, // float, alpha modifier applied to all plot item fills + ImPlot3DStyleVar_LineWeight, // float, plot item line weight in pixels + ImPlot3DStyleVar_Marker, // int, marker specification + ImPlot3DStyleVar_MarkerSize, // float, marker size in pixels (roughly the marker's "radius") + ImPlot3DStyleVar_FillAlpha, // float, alpha modifier applied to all plot item fills // Plot style ImPlot3DStyleVar_PlotDefaultSize, // ImVec2, default size used when ImVec2(0,0) is passed to BeginPlot ImPlot3DStyleVar_PlotMinSize, // ImVec2, minimum size plot frame can be when shrunk @@ -167,7 +178,8 @@ enum ImPlot3DStyleVar_ { }; enum ImPlot3DMarker_ { - ImPlot3DMarker_None = -1, // No marker + ImPlot3DMarker_None = -2, // No marker + ImPlot3DMarker_Auto = -1, // Automatic marker selection ImPlot3DMarker_Circle, // Circle marker (default) ImPlot3DMarker_Square, // Square maker ImPlot3DMarker_Diamond, // Diamond marker @@ -337,6 +349,93 @@ enum ImPlot3DColormap_ { ImPlot3DColormap_Greys = 15, // White/black }; +//----------------------------------------------------------------------------- +// [SECTION] Specs API +//----------------------------------------------------------------------------- + +// Plot item styling specification. Provide these to PlotX functions to override styling, specify +// offsetting or stride, or set optional flags. This struct can be used in the following ways: +// +// 1. By declaring and defining a struct instance: +// +// ImPlot3DSpec spec; +// spec.LineColor = ImVec4(1,0,0,1); +// spec.LineWeight = 2.0f; +// spec.Marker = ImPlot3DMarker_Circle; +// spec.Flags = ImPlot3DItemFlags_NoLegend | ImPlot3DLineFlags_Segments; +// ImPlot3D::PlotLine("MyLine", xs, ys, zs, 100, spec); +// +// 2. Inline using ImPlot3DProp,value pairs (order does NOT matter): +// +// ImPlot3D::PlotLine("MyLine", xs, ys, zs, 100, { +// ImPlot3DProp_LineColor, ImVec4(1,0,0,1), +// ImPlot3DProp_LineWeight, 2.0f, +// ImPlot3DProp_Marker, ImPlot3DMarker_Circle, +// ImPlot3DProp_Flags, ImPlot3DItemFlags_NoLegend | ImPlot3DLineFlags_Segments +// }); +struct ImPlot3DSpec { + ImVec4 LineColor = IMPLOT3D_AUTO_COL; // Line color; IMPLOT3D_AUTO_COL will use next Colormap color + float LineWeight = 1.0f; // Line weight in pixels + ImVec4 FillColor = IMPLOT3D_AUTO_COL; // Fill color (applies to shaded regions); IMPLOT3D_AUTO_COL will use next Colormap color + float FillAlpha = IMPLOT3D_AUTO; // Alpha multiplier (applies to FillColor and MarkerFillColor) + ImPlot3DMarker Marker = ImPlot3DMarker_Auto; // Marker type + float MarkerSize = IMPLOT3D_AUTO; // Size of markers (radius) *in pixels* + ImVec4 MarkerLineColor = IMPLOT3D_AUTO_COL; // Marker outline color; IMPLOT3D_AUTO_COL will use LineColor + ImVec4 MarkerFillColor = IMPLOT3D_AUTO_COL; // Marker fill color; IMPLOT3D_AUTO_COL will use LineColor + int Offset = 0; // Data index offset + int Stride = IMPLOT3D_AUTO; // Data stride in bytes; IMPLOT3D_AUTO will result in sizeof(T) where T is the type passed to PlotX + ImPlot3DItemFlags Flags = + ImPlot3DItemFlags_None; // Optional item flags; can be composed from common ImPlot3DItemFlags and/or specialized ImPlot3DXFlags + + ImPlot3DSpec() {} + + // Construct a plot item specification from (ImPlot3DProp,value) pairs in any order + // E.g. ImPlot3DSpec(ImPlot3DProp_LineColor, my_color, ImPlot3DProp_Marker, ImPlot3DMarker_Circle) + template ImPlot3DSpec(Args... args) { + static_assert((sizeof...(Args)) % 2 == 0, "Odd number of arguments! You must provide (ImPlot3DProp,value) pairs!"); + SetProp(args...); + } + + // Set properties from (ImPlot3DProp,value) pairs in any order + // E.g. SetProp(ImPlot3DProp_LineColor, my_color, ImPlot3DProp_Marker, ImPlot3DMarker_Circle) + template void SetProp(ImPlot3DProp prop, Arg arg, Args... args) { + static_assert((sizeof...(Args)) % 2 == 0, "Odd number of arguments! You must provide (ImPlot3DProp,value) pairs!"); + SetProp(prop, arg); + SetProp(args...); + } + + // Set a property from a scalar value. + template void SetProp(ImPlot3DProp prop, T v) { + switch (prop) { + case ImPlot3DProp_LineColor: LineColor = ImGui::ColorConvertU32ToFloat4((ImU32)v); return; + case ImPlot3DProp_LineWeight: LineWeight = (float)v; return; + case ImPlot3DProp_FillColor: FillColor = ImGui::ColorConvertU32ToFloat4((ImU32)v); return; + case ImPlot3DProp_FillAlpha: FillAlpha = (float)v; return; + case ImPlot3DProp_Marker: Marker = (ImPlot3DMarker)v; return; + case ImPlot3DProp_MarkerSize: MarkerSize = (float)v; return; + case ImPlot3DProp_MarkerLineColor: MarkerLineColor = ImGui::ColorConvertU32ToFloat4((ImU32)v); return; + case ImPlot3DProp_MarkerFillColor: MarkerFillColor = ImGui::ColorConvertU32ToFloat4((ImU32)v); return; + case ImPlot3DProp_Offset: Offset = (int)v; return; + case ImPlot3DProp_Stride: Stride = (int)v; return; + case ImPlot3DProp_Flags: Flags = (ImPlot3DItemFlags)v; return; + default: break; + } + IM_ASSERT(0 && "User provided an ImPlot3DProp which cannot be set from scalar value!"); + } + + // Set a property from an ImVec4 value. + void SetProp(ImPlot3DProp prop, const ImVec4& v) { + switch (prop) { + case ImPlot3DProp_LineColor: LineColor = v; return; + case ImPlot3DProp_FillColor: FillColor = v; return; + case ImPlot3DProp_MarkerLineColor: MarkerLineColor = v; return; + case ImPlot3DProp_MarkerFillColor: MarkerFillColor = v; return; + default: break; + } + IM_ASSERT(0 && "User provided an ImPlot3DProp which cannot be set from ImVec4 value!"); + } +}; + //----------------------------------------------------------------------------- // [SECTION] Callbacks //----------------------------------------------------------------------------- @@ -492,7 +591,7 @@ IMPLOT3D_API void SetupLegend(ImPlot3DLocation location, ImPlot3DLegendFlags fla // struct Vector3f { float X, Y, Z; }; // ... // Vector3f data[42]; -// ImPlot3D::PlotLine("line", &data[0].X, &data[0].Y, &data[0].Z, 42, 0, 0, sizeof(Vector3f)); +// ImPlot3D::PlotLine("line", &data[0].X, &data[0].Y, &data[0].Z, 42, {ImPlot3DProp_Stride, sizeof(Vector2f)}); // // 2. If your data is in separate arrays or requires computation, you can copy/transform // it into temporary float or double arrays before plotting. @@ -501,30 +600,26 @@ IMPLOT3D_API void SetupLegend(ImPlot3DLocation location, ImPlot3DLegendFlags fla // if you try plotting extremely large 64-bit integral types. Proceed with caution! // Plots a scatter plot in 3D. Points are rendered as markers at the specified coordinates -IMPLOT3D_TMP void PlotScatter(const char* label_id, const T* xs, const T* ys, const T* zs, int count, ImPlot3DScatterFlags flags = 0, int offset = 0, - int stride = sizeof(T)); +IMPLOT3D_TMP void PlotScatter(const char* label_id, const T* xs, const T* ys, const T* zs, int count, const ImPlot3DSpec& spec = ImPlot3DSpec()); // Plots a line in 3D. Consecutive points are connected with line segments -IMPLOT3D_TMP void PlotLine(const char* label_id, const T* xs, const T* ys, const T* zs, int count, ImPlot3DLineFlags flags = 0, int offset = 0, - int stride = sizeof(T)); +IMPLOT3D_TMP void PlotLine(const char* label_id, const T* xs, const T* ys, const T* zs, int count, const ImPlot3DSpec& spec = ImPlot3DSpec()); // Plots triangles in 3D. Every 3 consecutive points define a triangle -IMPLOT3D_TMP void PlotTriangle(const char* label_id, const T* xs, const T* ys, const T* zs, int count, ImPlot3DTriangleFlags flags = 0, - int offset = 0, int stride = sizeof(T)); +IMPLOT3D_TMP void PlotTriangle(const char* label_id, const T* xs, const T* ys, const T* zs, int count, const ImPlot3DSpec& spec = ImPlot3DSpec()); // Plots quads in 3D. Every 4 consecutive points define a quadrilateral -IMPLOT3D_TMP void PlotQuad(const char* label_id, const T* xs, const T* ys, const T* zs, int count, ImPlot3DQuadFlags flags = 0, int offset = 0, - int stride = sizeof(T)); +IMPLOT3D_TMP void PlotQuad(const char* label_id, const T* xs, const T* ys, const T* zs, int count, const ImPlot3DSpec& spec = ImPlot3DSpec()); // Plot the surface defined by a grid of vertices. The grid is defined by the x and y arrays, and the z array contains the height of each vertex. A // total of x_count * y_count vertices are expected for each array. Leave #scale_min and #scale_max both at 0 for automatic color scaling, or set them // to a predefined range IMPLOT3D_TMP void PlotSurface(const char* label_id, const T* xs, const T* ys, const T* zs, int x_count, int y_count, double scale_min = 0.0, - double scale_max = 0.0, ImPlot3DSurfaceFlags flags = 0, int offset = 0, int stride = sizeof(T)); + double scale_max = 0.0, const ImPlot3DSpec& spec = ImPlot3DSpec()); // Plots a 3D mesh given vertex positions and indices. Triangles are defined by the index buffer (every 3 indices form a triangle) IMPLOT3D_API void PlotMesh(const char* label_id, const ImPlot3DPoint* vtx, const unsigned int* idx, int vtx_count, int idx_count, - ImPlot3DMeshFlags flags = 0); + const ImPlot3DSpec& spec = ImPlot3DSpec()); // Plots a rectangular image in 3D defined by its center and two direction vectors (axes). // #center is the center of the rectangle in plot coordinates. @@ -534,7 +629,7 @@ IMPLOT3D_API void PlotMesh(const char* label_id, const ImPlot3DPoint* vtx, const // #tint_col can be used to tint the image. IMPLOT3D_API void PlotImage(const char* label_id, ImTextureRef tex_ref, const ImPlot3DPoint& center, const ImPlot3DPoint& axis_u, const ImPlot3DPoint& axis_v, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), - const ImVec4& tint_col = ImVec4(1, 1, 1, 1), ImPlot3DImageFlags flags = 0); + const ImVec4& tint_col = ImVec4(1, 1, 1, 1), const ImPlot3DSpec& spec = ImPlot3DSpec()); // Plots an image using four arbitrary 3D points that define a quad in space. // Each corner (p0 to p3) corresponds to a corner in the image, and #uv0 to #uv3 are the texture coordinates for each. @@ -544,13 +639,13 @@ IMPLOT3D_API void PlotImage(const char* label_id, ImTextureRef tex_ref, const Im IMPLOT3D_API void PlotImage(const char* label_id, ImTextureRef tex_ref, const ImPlot3DPoint& p0, const ImPlot3DPoint& p1, const ImPlot3DPoint& p2, const ImPlot3DPoint& p3, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 0), const ImVec2& uv2 = ImVec2(1, 1), const ImVec2& uv3 = ImVec2(0, 1), const ImVec4& tint_col = ImVec4(1, 1, 1, 1), - ImPlot3DImageFlags flags = 0); + const ImPlot3DSpec& spec = ImPlot3DSpec()); // Plots a centered text label at point x,y,z with optional rotation angle (in radians) and pixel offset IMPLOT3D_API void PlotText(const char* text, double x, double y, double z, double angle = 0.0, const ImVec2& pix_offset = ImVec2(0, 0)); // Plots a dummy item (can be used to modify legend entry appearance when called after plotting an item, or add a dummy legend entry) -IMPLOT3D_API void PlotDummy(const char* label_id, ImPlot3DDummyFlags flags = 0); +IMPLOT3D_API void PlotDummy(const char* label_id, const ImPlot3DSpec& spec = ImPlot3DSpec()); //----------------------------------------------------------------------------- // [SECTION] Plot Utils @@ -583,7 +678,7 @@ IMPLOT3D_API ImVec2 GetPlotRectSize(); IMPLOT3D_API ImDrawList* GetPlotDrawList(); //----------------------------------------------------------------------------- -// [SECTION] Styles +// [SECTION] Styles API (legacy) //----------------------------------------------------------------------------- // Get current style @@ -611,18 +706,13 @@ IMPLOT3D_API void PushStyleVar(ImPlot3DStyleVar idx, const ImVec2& val); // Undo temporary style variable modification(s). Undo multiple pushes at once by increasing count IMPLOT3D_API void PopStyleVar(int count = 1); -// Set the line color and weight for the next item only -IMPLOT3D_API void SetNextLineStyle(const ImVec4& col = IMPLOT3D_AUTO_COL, float weight = IMPLOT3D_AUTO); -// Set the fill color for the next item only -IMPLOT3D_API void SetNextFillStyle(const ImVec4& col = IMPLOT3D_AUTO_COL, float alpha_mod = IMPLOT3D_AUTO); -// Set the marker style for the next item only -IMPLOT3D_API void SetNextMarkerStyle(ImPlot3DMarker marker = IMPLOT3D_AUTO, float size = IMPLOT3D_AUTO, const ImVec4& fill = IMPLOT3D_AUTO_COL, - float weight = IMPLOT3D_AUTO, const ImVec4& outline = IMPLOT3D_AUTO_COL); - // Get color IMPLOT3D_API ImVec4 GetStyleColorVec4(ImPlot3DCol idx); IMPLOT3D_API ImU32 GetStyleColorU32(ImPlot3DCol idx); +// Returns the next marker and advances the marker for the current plot. You need to call this between Begin/EndPlot! +IMPLOT3D_API ImPlot3DMarker NextMarker(); + //----------------------------------------------------------------------------- // [SECTION] Colormaps //----------------------------------------------------------------------------- @@ -634,7 +724,6 @@ IMPLOT3D_API ImU32 GetStyleColorU32(ImPlot3DCol idx); // Colormap data will be ignored and a custom color will be used if you have done one of the following: // 1) Modified an item style color in your ImPlot3DStyle to anything other than IMPLOT3D_AUTO_COL. -// 3) Set the next item style with a SetNextXXXStyle function. // Add a new colormap. The color data will be copied. The colormap can be used by pushing either the returned index or the // string name with PushColormap. The colormap name must be unique and the size must be greater than 1. You will receive @@ -896,11 +985,10 @@ struct ImPlot3DQuat { struct ImPlot3DStyle { // Item style - float LineWeight; // Line weight in pixels - int Marker; // Default marker type (ImPlot3DMarker_None) - float MarkerSize; // Marker size in pixels (roughly the marker's "radius") - float MarkerWeight; // Marker outline weight in pixels - float FillAlpha; // Alpha modifier applied to plot fills + float LineWeight; // Line weight in pixels + int Marker; // Default marker type (ImPlot3DMarker_None) + float MarkerSize; // Marker size in pixels (roughly the marker's "radius") + float FillAlpha; // Alpha modifier applied to plot fills // Plot style ImVec2 PlotDefaultSize; // Default size used when ImVec2(0,0) is passed to BeginPlot ImVec2 PlotMinSize; // Minimum size plot frame can be when shrunk @@ -977,6 +1065,13 @@ extern unsigned int duck_idx[DUCK_IDX_COUNT]; // Duck indices namespace ImPlot3D { +// OBSOLETED in v0.4 (from February 2026) +// IMPLOT_API void SetNextLineStyle(const ImVec4& col = IMPLOT_AUTO_COL, float weight = IMPLOT_AUTO); // OBSOLETED IN v0.4 // Set ImPlotSpec.LineColor/LineWeight or construct ImPlotSpec with { ImPlotSpec_LineColor, color, ImPlotSpec_LineWeight, weight }. + +// IMPLOT_API void SetNextFillStyle(const ImVec4& col = IMPLOT_AUTO_COL, float alpha_mod = IMPLOT_AUTO);// OBSOLETED IN v0.4 // Set ImPlotSpec.FillColor/FillAlpha or construct ImPlotSpec with { ImPlotSpec_FillColor, color, ImPlotSpec_FillAlpha, alpha }. + +// IMPLOT_API void SetNextMarkerStyle(ImPlotMarker marker = IMPLOT_AUTO, float size = IMPLOT_AUTO, const ImVec4& fill = IMPLOT_AUTO_COL, float weight = IMPLOT_AUTO, const ImVec4& outline = IMPLOT_AUTO_COL); // OBSOLETED IN v0.4 // Set ImPlotSpec.Marker/MarkerSize/MarkerFillColor/LineWeight/MarkerLineColor or construct ImPlotSpec with { ImPlotSpec_Marker, marker, ImPlotSpec_MarkerSize, size, ImPlotSpec_MarkerFillColor, fill_color, ImPlotSpec_LineWeight, weight, ImPlotSpec_MarkerLineColor, outline }. + // OBSOLETED in v0.3 -> PLANNED REMOVAL in v1.0 IMPLOT3D_DEPRECATED(IMPLOT3D_API ImVec2 GetPlotPos()); // Renamed to GetPlotRectPos() IMPLOT3D_DEPRECATED(IMPLOT3D_API ImVec2 GetPlotSize()); // Renamed to GetPlotRectSize() diff --git a/implot3d_demo.cpp b/implot3d_demo.cpp index 3b11099f..3f80c9a0 100644 --- a/implot3d_demo.cpp +++ b/implot3d_demo.cpp @@ -121,8 +121,7 @@ void DemoLinePlots() { if (ImPlot3D::BeginPlot("Line Plots")) { ImPlot3D::SetupAxes("x", "y", "z"); ImPlot3D::PlotLine("f(x)", xs1, ys1, zs1, 1001); - ImPlot3D::SetNextMarkerStyle(ImPlot3DMarker_Circle); - ImPlot3D::PlotLine("g(x)", xs2, ys2, zs2, 20, ImPlot3DLineFlags_Segments); + ImPlot3D::PlotLine("g(x)", xs2, ys2, zs2, 20, {ImPlot3DProp_Marker, ImPlot3DMarker_Circle, ImPlot3DProp_Flags, ImPlot3DLineFlags_Segments}); ImPlot3D::EndPlot(); } } @@ -144,10 +143,13 @@ void DemoScatterPlots() { if (ImPlot3D::BeginPlot("Scatter Plots")) { ImPlot3D::PlotScatter("Data 1", xs1, ys1, zs1, 100); - ImPlot3D::PushStyleVar(ImPlot3DStyleVar_FillAlpha, 0.25f); - ImPlot3D::SetNextMarkerStyle(ImPlot3DMarker_Square, 6, ImPlot3D::GetColormapColor(1), IMPLOT3D_AUTO, ImPlot3D::GetColormapColor(1)); - ImPlot3D::PlotScatter("Data 2", xs2, ys2, zs2, 50); - ImPlot3D::PopStyleVar(); + ImPlot3DSpec spec; + spec.Marker = ImPlot3DMarker_Square; + spec.MarkerSize = 6; + spec.MarkerLineColor = ImPlot3D::GetColormapColor(1); + spec.MarkerFillColor = ImPlot3D::GetColormapColor(1); + spec.FillAlpha = 0.25f; + ImPlot3D::PlotScatter("Data 2", xs2, ys2, zs2, 50, spec); ImPlot3D::EndPlot(); } } @@ -224,12 +226,15 @@ void DemoTrianglePlots() { ImPlot3D::SetupAxesLimits(-1, 1, -1, 1, -0.5, 1.5); // Setup pyramid colors - ImPlot3D::SetNextFillStyle(ImPlot3D::GetColormapColor(0)); - ImPlot3D::SetNextLineStyle(ImPlot3D::GetColormapColor(1), 2); - ImPlot3D::SetNextMarkerStyle(ImPlot3DMarker_Square, 3, ImPlot3D::GetColormapColor(2), IMPLOT3D_AUTO, ImPlot3D::GetColormapColor(2)); + ImPlot3DSpec spec; + spec.FillColor = ImPlot3D::GetColormapColor(0); + spec.LineColor = ImPlot3D::GetColormapColor(1); + spec.Marker = ImPlot3DMarker_Square; + spec.MarkerSize = 3; + spec.Flags = flags; // Plot pyramid - ImPlot3D::PlotTriangle("Pyramid", xs, ys, zs, 6 * 3, flags); // 6 triangles, 3 vertices each = 18 + ImPlot3D::PlotTriangle("Pyramid", xs, ys, zs, 6 * 3, spec); // 6 triangles, 3 vertices each = 18 ImPlot3D::EndPlot(); } } @@ -287,26 +292,28 @@ void DemoQuadPlots() { if (ImPlot3D::BeginPlot("Quad Plots")) { ImPlot3D::SetupAxesLimits(-1.5, 1.5, -1.5, 1.5, -1.5, 1.5); + ImPlot3DSpec spec; + spec.Marker = ImPlot3DMarker_Square; + spec.MarkerSize = 3; + spec.Flags = flags; + // Render +x and -x faces static ImVec4 colorX(0.8f, 0.2f, 0.2f, 0.8f); // Red - ImPlot3D::SetNextFillStyle(colorX); - ImPlot3D::SetNextLineStyle(colorX, 2); - ImPlot3D::SetNextMarkerStyle(ImPlot3DMarker_Square, 3, colorX, IMPLOT3D_AUTO, colorX); - ImPlot3D::PlotQuad("X", &xs[0], &ys[0], &zs[0], 8, flags); + spec.FillColor = colorX; + spec.LineColor = colorX; + ImPlot3D::PlotQuad("X", &xs[0], &ys[0], &zs[0], 8, spec); // Render +y and -y faces static ImVec4 colorY(0.2f, 0.8f, 0.2f, 0.8f); // Green - ImPlot3D::SetNextFillStyle(colorY); - ImPlot3D::SetNextLineStyle(colorY, 2); - ImPlot3D::SetNextMarkerStyle(ImPlot3DMarker_Square, 3, colorY, IMPLOT3D_AUTO, colorY); - ImPlot3D::PlotQuad("Y", &xs[8], &ys[8], &zs[8], 8, flags); + spec.FillColor = colorY; + spec.LineColor = colorY; + ImPlot3D::PlotQuad("Y", &xs[8], &ys[8], &zs[8], 8, spec); // Render +z and -z faces static ImVec4 colorZ(0.2f, 0.2f, 0.8f, 0.8f); // Blue - ImPlot3D::SetNextFillStyle(colorZ); - ImPlot3D::SetNextLineStyle(colorZ, 2); - ImPlot3D::SetNextMarkerStyle(ImPlot3DMarker_Square, 3, colorZ, IMPLOT3D_AUTO, colorZ); - ImPlot3D::PlotQuad("Z", &xs[16], &ys[16], &zs[16], 8, flags); + spec.FillColor = colorZ; + spec.LineColor = colorZ; + ImPlot3D::PlotQuad("Z", &xs[16], &ys[16], &zs[16], 8, spec); ImPlot3D::EndPlot(); } @@ -388,25 +395,21 @@ void DemoSurfacePlots() { if (ImPlot3D::BeginPlot("Surface Plots", ImVec2(-1, 0), ImPlot3DFlags_NoClip)) { ImPlot3D::SetupAxesLimits(-1, 1, -1, 1, -1.5, 1.5); - // Set fill style - ImPlot3D::PushStyleVar(ImPlot3DStyleVar_FillAlpha, 0.8f); + ImPlot3DSpec spec; + spec.FillAlpha = 0.8f; + spec.Flags = flags; + spec.Marker = ImPlot3DMarker_Square; + spec.LineColor = ImPlot3D::GetColormapColor(1); if (selected_fill == 0) - ImPlot3D::SetNextFillStyle(solid_color); - - // Set line style - ImPlot3D::SetNextLineStyle(ImPlot3D::GetColormapColor(1)); - - // Set marker style - ImPlot3D::SetNextMarkerStyle(ImPlot3DMarker_Square, IMPLOT3D_AUTO, ImPlot3D::GetColormapColor(2)); + spec.FillColor = solid_color; // Plot the surface if (custom_range) - ImPlot3D::PlotSurface("Wave Surface", xs, ys, zs, N, N, (double)range_min, (double)range_max, flags); + ImPlot3D::PlotSurface("Wave Surface", xs, ys, zs, N, N, (double)range_min, (double)range_max, spec); else - ImPlot3D::PlotSurface("Wave Surface", xs, ys, zs, N, N, 0.0, 0.0, flags); + ImPlot3D::PlotSurface("Wave Surface", xs, ys, zs, N, N, 0.0, 0.0, spec); // End the plot - ImPlot3D::PopStyleVar(); ImPlot3D::EndPlot(); } if (selected_fill == 1) @@ -438,22 +441,25 @@ void DemoMeshPlots() { if (ImPlot3D::BeginPlot("Mesh Plots")) { ImPlot3D::SetupAxesLimits(-1, 1, -1, 1, -1, 1); + ImPlot3DSpec spec; + spec.Flags = flags; // Set fill style - ImPlot3D::SetNextFillStyle(fill_color); - + spec.FillColor = fill_color; // Set line style - ImPlot3D::SetNextLineStyle(line_color); - + spec.LineColor = line_color; // Set marker style - ImPlot3D::SetNextMarkerStyle(ImPlot3DMarker_Square, 3, marker_color, IMPLOT3D_AUTO, marker_color); + spec.Marker = ImPlot3DMarker_Square; + spec.MarkerSize = 3.0f; + spec.MarkerLineColor = marker_color; + spec.MarkerFillColor = marker_color; // Plot mesh if (mesh_id == 0) - ImPlot3D::PlotMesh("Duck", duck_vtx, duck_idx, DUCK_VTX_COUNT, DUCK_IDX_COUNT, flags); + ImPlot3D::PlotMesh("Duck", duck_vtx, duck_idx, DUCK_VTX_COUNT, DUCK_IDX_COUNT, spec); else if (mesh_id == 1) - ImPlot3D::PlotMesh("Sphere", sphere_vtx, sphere_idx, SPHERE_VTX_COUNT, SPHERE_IDX_COUNT, flags); + ImPlot3D::PlotMesh("Sphere", sphere_vtx, sphere_idx, SPHERE_VTX_COUNT, SPHERE_IDX_COUNT, spec); else if (mesh_id == 2) - ImPlot3D::PlotMesh("Cube", cube_vtx, cube_idx, CUBE_VTX_COUNT, CUBE_IDX_COUNT, flags); + ImPlot3D::PlotMesh("Cube", cube_vtx, cube_idx, CUBE_VTX_COUNT, CUBE_IDX_COUNT, spec); ImPlot3D::EndPlot(); } @@ -576,7 +582,8 @@ void DemoRealtimePlots() { ImPlot3D::SetupAxisLimits(ImAxis3D_X, t - 10.0, t, ImPlot3DCond_Always); ImPlot3D::SetupAxisLimits(ImAxis3D_Y, -400, 400, ImPlot3DCond_Once); ImPlot3D::SetupAxisLimits(ImAxis3D_Z, -400, 400, ImPlot3DCond_Once); - ImPlot3D::PlotLine("Mouse", &sdata1.Data[0], &sdata2.Data[0], &sdata3.Data[0], sdata1.Data.size(), 0, sdata1.Offset, sizeof(float)); + ImPlot3D::PlotLine("Mouse", &sdata1.Data[0], &sdata2.Data[0], &sdata3.Data[0], sdata1.Data.size(), + {ImPlot3DProp_Offset, sdata1.Offset, ImPlot3DProp_Stride, sizeof(float)}); ImPlot3D::EndPlot(); } } @@ -710,8 +717,10 @@ void DemoOffsetAndStride() { char buff[32]; for (int s = 0; s < k_spirals; ++s) { snprintf(buff, sizeof(buff), "Spiral %d", s); - ImPlot3D::PlotLine(buff, &interleaved_data[s * 3 + 0], &interleaved_data[s * 3 + 1], &interleaved_data[s * 3 + 2], k_points_per, 0, - offset, 3 * k_spirals * sizeof(double)); + ImPlot3DSpec spec; + spec.Offset = offset; + spec.Stride = 3 * k_spirals * sizeof(double); + ImPlot3D::PlotLine(buff, &interleaved_data[s * 3 + 0], &interleaved_data[s * 3 + 1], &interleaved_data[s * 3 + 2], k_points_per, spec); } ImPlot3D::EndPlot(); ImPlot3D::PopColormap(); @@ -794,7 +803,7 @@ void DemoLegendOptions() { void DemoMarkersAndText() { static float mk_size = ImPlot3D::GetStyle().MarkerSize; - static float mk_weight = ImPlot3D::GetStyle().MarkerWeight; + static float mk_weight = ImPlot3D::GetStyle().LineWeight; ImGui::DragFloat("Marker Size", &mk_size, 0.1f, 2.0f, 10.0f, "%.2f px"); ImGui::DragFloat("Marker Weight", &mk_weight, 0.05f, 0.5f, 3.0f, "%.2f px"); @@ -814,8 +823,8 @@ void DemoMarkersAndText() { ys[1] = ys[0] + ImSin(zs[0] / float(ImPlot3DMarker_COUNT) * 2 * IM_PI) * 0.5f; ImGui::PushID(m); - ImPlot3D::SetNextMarkerStyle(m, mk_size, IMPLOT3D_AUTO_COL, mk_weight); - ImPlot3D::PlotLine("##Filled", xs, ys, zs, 2); + ImPlot3D::PlotLine("##Filled", xs, ys, zs, 2, + {ImPlot3DProp_Marker, m, ImPlot3DProp_MarkerSize, mk_size, ImPlot3DProp_LineWeight, mk_weight}); ImGui::PopID(); zs[0]--; zs[1]--; @@ -832,8 +841,9 @@ void DemoMarkersAndText() { ys[1] = ys[0] - ImSin(zs[0] / float(ImPlot3DMarker_COUNT) * 2 * IM_PI) * 0.5f; ImGui::PushID(m); - ImPlot3D::SetNextMarkerStyle(m, mk_size, ImVec4(0, 0, 0, 0), mk_weight); - ImPlot3D::PlotLine("##Open", xs, ys, zs, 2); + ImPlot3D::PlotLine("##Open", xs, ys, zs, 2, + {ImPlot3DProp_Marker, m, ImPlot3DProp_MarkerSize, mk_size, ImPlot3DProp_LineWeight, mk_weight, ImPlot3DProp_FillColor, + ImVec4(0, 0, 0, 0)}); ImGui::PopID(); zs[0]--; zs[1]--; @@ -866,8 +876,7 @@ void DemoNaNValues() { ImGui::CheckboxFlags("Skip NaN", (unsigned int*)&flags, ImPlot3DLineFlags_SkipNaN); if (ImPlot3D::BeginPlot("##NaNValues")) { - ImPlot3D::SetNextMarkerStyle(ImPlot3DMarker_Square); - ImPlot3D::PlotLine("Line", data1, data2, data3, 5, flags); + ImPlot3D::PlotLine("Line", data1, data2, data3, 5, {ImPlot3DProp_Flags, flags, ImPlot3DProp_Marker, ImPlot3DMarker_Square}); ImPlot3D::EndPlot(); } } @@ -931,12 +940,9 @@ void DemoBoxRotation() { ImPlot3D::SetupBoxRotation(elevation, azimuth, animate, ImPlot3DCond_Always); // Plot axis lines - ImPlot3D::SetNextLineStyle(ImVec4(0.8f, 0.2f, 0.2f, 1)); - ImPlot3D::PlotLine("X-Axis", axis, origin, origin, 2); - ImPlot3D::SetNextLineStyle(ImVec4(0.2f, 0.8f, 0.2f, 1)); - ImPlot3D::PlotLine("Y-Axis", origin, axis, origin, 2); - ImPlot3D::SetNextLineStyle(ImVec4(0.2f, 0.2f, 0.8f, 1)); - ImPlot3D::PlotLine("Z-Axis", origin, origin, axis, 2); + ImPlot3D::PlotLine("X-Axis", axis, origin, origin, 2, {ImPlot3DProp_LineColor, ImVec4(0.8f, 0.2f, 0.2f, 1)}); + ImPlot3D::PlotLine("Y-Axis", origin, axis, origin, 2, {ImPlot3DProp_LineColor, ImVec4(0.2f, 0.8f, 0.2f, 1)}); + ImPlot3D::PlotLine("Z-Axis", origin, origin, axis, 2, {ImPlot3DProp_LineColor, ImVec4(0.2f, 0.2f, 0.8f, 1)}); ImPlot3D::EndPlot(); } @@ -1144,8 +1150,11 @@ void DemoMousePicking() { // Show intersection point if (ImGui::IsItemHovered() && !point.IsNaN()) { - ImPlot3D::SetNextMarkerStyle(ImPlot3DMarker_Circle, 5, ImVec4(1, 1, 0, 1)); - ImPlot3D::PlotScatter("##Intersection", &point.x, &point.y, &point.z, 1); + ImPlot3DSpec spec; + spec.Marker = ImPlot3DMarker_Circle; + spec.MarkerSize = 5; + spec.FillColor = ImVec4(1, 1, 0, 1); + ImPlot3D::PlotScatter("##Intersection", &point.x, &point.y, &point.z, 1, spec); } // Add point/ray on click @@ -1156,10 +1165,12 @@ void DemoMousePicking() { // Draw all placed points if (!points.empty()) { - ImPlot3D::SetNextMarkerStyle(ImPlot3DMarker_Circle, 3); // Plot points - ImPlot3D::PlotScatter("Placed Points", &points[0].x, &points[0].y, &points[0].z, (int)points.Size, ImPlot3DScatterFlags_None, 0, - sizeof(ImPlot3DPoint)); + ImPlot3DSpec spec; + spec.Marker = ImPlot3DMarker_Circle; + spec.MarkerSize = 3; + spec.Stride = sizeof(ImPlot3DPoint); + ImPlot3D::PlotScatter("Placed Points", &points[0].x, &points[0].y, &points[0].z, (int)points.Size, spec); } // Draw all placed rays @@ -1172,8 +1183,11 @@ void DemoMousePicking() { ray_points.push_back(p1); ray_points.push_back(p2); } - ImPlot3D::PlotLine("Placed Rays", &ray_points[0].x, &ray_points[0].y, &ray_points[0].z, (int)rays.Size * 2, ImPlot3DLineFlags_Segments, 0, - sizeof(ImPlot3DPoint)); + ImPlot3DSpec spec; + spec.Flags = ImPlot3DLineFlags_Segments; + spec.Offset = 0; + spec.Stride = sizeof(ImPlot3DPoint); + ImPlot3D::PlotLine("Placed Rays", &ray_points[0].x, &ray_points[0].y, &ray_points[0].z, (int)rays.Size * 2, spec); } ImPlot3D::EndPlot(); @@ -1351,7 +1365,7 @@ void DemoCustomOverlay() { void DemoCustomPerPointStyle() { ImGui::BulletText("Demonstrates per-point coloring using colormap sampling."); - ImGui::BulletText("Each point calls SetNextMarkerStyle with a sampled color."); + ImGui::BulletText("A different color is sampled for each point."); ImGui::BulletText("All points share the same label for a single legend entry."); static float marker_size = 4.0f; @@ -1432,6 +1446,10 @@ void DemoCustomPerPointStyle() { ImVec4(0.0f, 0.0f, 1.0f, 1.0f) // Blue }; + ImPlot3DSpec spec; + spec.Marker = ImPlot3DMarker_Circle; + spec.MarkerSize = marker_size; + for (int torus = 0; torus < 3; torus++) { const int point_count = 400; for (int i = 0; i < point_count; i++) { @@ -1442,12 +1460,13 @@ void DemoCustomPerPointStyle() { // Sample colormap and set marker style ImVec4 color = ImPlot3D::SampleColormap(t, cmap); - ImPlot3D::SetNextMarkerStyle(ImPlot3DMarker_Circle, marker_size, color, IMPLOT3D_AUTO, color); - ImPlot3D::PlotScatter(labels[torus], &x, &y, &z, 1); + spec.FillColor = color; + spec.LineColor = color; + ImPlot3D::PlotScatter(labels[torus], &x, &y, &z, 1, spec); } // Override legend color with PlotDummy - ImPlot3D::SetNextLineStyle(legend_colors[torus]); - ImPlot3D::PlotDummy(labels[torus]); + spec.LineColor = legend_colors[torus]; + ImPlot3D::PlotDummy(labels[torus], spec); } ImPlot3D::EndPlot(); @@ -1759,7 +1778,6 @@ void ShowStyleEditor(ImPlot3DStyle* ref) { ImGui::Text("Item Styling"); ImGui::SliderFloat("LineWeight", &style.LineWeight, 0.0f, 5.0f, "%.1f"); ImGui::SliderFloat("MarkerSize", &style.MarkerSize, 2.0f, 10.0f, "%.1f"); - ImGui::SliderFloat("MarkerWeight", &style.MarkerWeight, 0.0f, 5.0f, "%.1f"); ImGui::SliderFloat("FillAlpha", &style.FillAlpha, 0.0f, 1.0f, "%.2f"); ImGui::Text("Plot Styling"); ImGui::SliderFloat2("PlotDefaultSize", (float*)&style.PlotDefaultSize, 0.0f, 1000, "%.0f"); @@ -2076,10 +2094,6 @@ void StyleSeaborn() { ImPlot3DStyle& style = ImPlot3D::GetStyle(); ImVec4* colors = style.Colors; - colors[ImPlot3DCol_Line] = IMPLOT3D_AUTO_COL; - colors[ImPlot3DCol_Fill] = IMPLOT3D_AUTO_COL; - colors[ImPlot3DCol_MarkerOutline] = IMPLOT3D_AUTO_COL; - colors[ImPlot3DCol_MarkerFill] = IMPLOT3D_AUTO_COL; colors[ImPlot3DCol_FrameBg] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); colors[ImPlot3DCol_PlotBg] = ImVec4(0.92f, 0.92f, 0.95f, 1.00f); colors[ImPlot3DCol_PlotBorder] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); @@ -2094,7 +2108,6 @@ void StyleSeaborn() { style.LineWeight = 1.5; style.Marker = ImPlot3DMarker_None; style.MarkerSize = 4; - style.MarkerWeight = 1; style.FillAlpha = 1.0f; style.PlotPadding = ImVec2(12, 12); style.LabelPadding = ImVec2(5, 5); diff --git a/implot3d_internal.h b/implot3d_internal.h index d1d22152..42ff7e1c 100644 --- a/implot3d_internal.h +++ b/implot3d_internal.h @@ -12,6 +12,7 @@ // Table of Contents: // [SECTION] Constants // [SECTION] Generic Helpers +// [SECTION] Internal Enumerations // [SECTION] Forward Declarations // [SECTION] Callbacks // [SECTION] Structs @@ -113,6 +114,14 @@ template void FillRange(ImVector& buffer, int n, T vmin, T vmax) } // namespace ImPlot3D +//----------------------------------------------------------------------------- +// [SECTION] Internal Enumerations +//----------------------------------------------------------------------------- + +enum ImPlot3DMarkerInternal_ { + ImPlot3DMarker_Invalid = -3, +}; + //----------------------------------------------------------------------------- // [SECTION] Forward Declarations //----------------------------------------------------------------------------- @@ -177,12 +186,7 @@ struct ImDrawList3D { }; struct ImPlot3DNextItemData { - ImVec4 Colors[4]; // ImPlot3DCol_Line, ImPlot3DCol_Fill, ImPlot3DCol_MarkerOutline, ImPlot3DCol_MarkerFill, - float LineWeight; - ImPlot3DMarker Marker; - float MarkerSize; - float MarkerWeight; - float FillAlpha; + ImPlot3DSpec Spec; bool RenderLine; bool RenderFill; bool RenderMarkerLine; @@ -194,13 +198,7 @@ struct ImPlot3DNextItemData { ImPlot3DNextItemData() { Reset(); } void Reset() { - for (int i = 0; i < 4; i++) - Colors[i] = IMPLOT3D_AUTO_COL; - LineWeight = IMPLOT3D_AUTO; - Marker = IMPLOT3D_AUTO; - MarkerSize = IMPLOT3D_AUTO; - MarkerWeight = IMPLOT3D_AUTO; - FillAlpha = IMPLOT3D_AUTO; + Spec = ImPlot3DSpec(); RenderLine = false; RenderFill = false; RenderMarkerLine = true; @@ -322,6 +320,7 @@ struct ImPlot3DColormapData { struct ImPlot3DItem { ImGuiID ID; ImU32 Color; + ImPlot3DMarker Marker; int NameOffset; bool Show; bool LegendHovered; @@ -330,6 +329,7 @@ struct ImPlot3DItem { ImPlot3DItem() { ID = 0; Color = IM_COL32_WHITE; + Marker = ImPlot3DMarker_None; NameOffset = -1; Show = true; LegendHovered = false; @@ -367,8 +367,12 @@ struct ImPlot3DItemGroup { ImPool ItemPool; ImPlot3DLegend Legend; int ColormapIdx; + ImPlot3DMarker MarkerIdx; - ImPlot3DItemGroup() { ColormapIdx = 0; } + ImPlot3DItemGroup() { + ColormapIdx = 0; + MarkerIdx = 0; + } int GetItemCount() const { return ItemPool.GetBufSize(); } ImGuiID GetItemID(const char* label_id) { return ImGui::GetID(label_id); } @@ -384,6 +388,7 @@ struct ImPlot3DItemGroup { ItemPool.Clear(); Legend.Reset(); ColormapIdx = 0; + MarkerIdx = 0; } }; @@ -848,7 +853,9 @@ IMPLOT3D_API void RenderColorBar(const ImU32* colors, int size, ImDrawList& Draw // [SECTION] Item Utils //----------------------------------------------------------------------------- -IMPLOT3D_API bool BeginItem(const char* label_id, ImPlot3DItemFlags flags = 0, ImPlot3DCol recolor_from = IMPLOT3D_AUTO); +// Begins a new item. Returns false if the item should not be plotted +IMPLOT3D_API bool BeginItem(const char* label_id, const ImPlot3DSpec& spec = ImPlot3DSpec(), const ImVec4& item_col = IMPLOT3D_AUTO_COL, + ImPlot3DMarker item_mkr = ImPlot3DMarker_Invalid); IMPLOT3D_API void EndItem(); // Register or get an existing item from the current plot diff --git a/implot3d_items.cpp b/implot3d_items.cpp index 87a80b74..7367822e 100644 --- a/implot3d_items.cpp +++ b/implot3d_items.cpp @@ -138,69 +138,69 @@ 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) { +template int Stride(const ImPlot3DSpec& spec) { return spec.Stride == IMPLOT3D_AUTO ? sizeof(T) : spec.Stride; } + +bool BeginItem(const char* label_id, const ImPlot3DSpec& spec, const ImVec4& item_col, ImPlot3DMarker item_mkr) { ImPlot3DContext& gp = *GImPlot3D; IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr, "PlotX() needs to be called between BeginPlot() and EndPlot()!"); // Lock setup SetupLock(); + // Override next data with spec ImPlot3DStyle& style = gp.Style; ImPlot3DNextItemData& n = gp.NextItemData; + ImPlot3DSpec& s = n.Spec; + s = spec; // Register item bool just_created; - ImPlot3DItem* item = RegisterOrGetItem(label_id, flags, &just_created); + ImPlot3DItem* item = RegisterOrGetItem(label_id, spec.Flags, &just_created); // Set current item gp.CurrentItem = item; // 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(); + if (!IsColorAuto(item_col)) { + item->Color = ImGui::ColorConvertFloat4ToU32(item_col); } else if (just_created) { item->Color = NextColormapColorU32(); } + // Set/override item marker + if (item_mkr != ImPlot3DMarker_Invalid) { + if (item_mkr != ImPlot3DMarker_Auto) { + item->Marker = item_mkr; + } else if (just_created && item_mkr == ImPlot3DMarker_Auto) { + item->Marker = NextMarker(); + } else if (item_mkr == ImPlot3DMarker_Auto && item->Marker == ImPlot3DMarker_None) { + item->Marker = NextMarker(); + } + } + // 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]; + n.IsAutoLine = IsColorAuto(s.LineColor); + n.IsAutoFill = IsColorAuto(s.FillColor); + s.LineColor = IsColorAuto(s.LineColor) ? item_color : s.LineColor; + s.FillColor = IsColorAuto(s.FillColor) ? item_color : s.FillColor; + s.MarkerLineColor = IsColorAuto(s.MarkerLineColor) ? s.LineColor : s.MarkerLineColor; + s.MarkerFillColor = IsColorAuto(s.MarkerFillColor) ? s.LineColor : s.MarkerFillColor; // 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; + s.LineWeight = s.LineWeight < 0.0f ? style.LineWeight : s.LineWeight; + s.Marker = s.Marker < 0 ? style.Marker : s.Marker; + s.MarkerSize = s.MarkerSize < 0.0f ? style.MarkerSize : s.MarkerSize; + s.FillAlpha = s.FillAlpha < 0 ? gp.Style.FillAlpha : s.FillAlpha; // Apply alpha modifiers - n.Colors[ImPlot3DCol_Fill].w *= n.FillAlpha; - n.Colors[ImPlot3DCol_MarkerFill].w *= n.FillAlpha; + s.FillColor.w *= s.FillAlpha; + s.MarkerFillColor.w *= s.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; + n.RenderLine = s.LineColor.w > 0 && s.LineWeight > 0; + n.RenderFill = s.FillColor.w > 0; + n.RenderMarkerLine = s.LineColor.w > 0 && s.LineWeight > 0; + n.RenderMarkerFill = s.FillColor.w > 0; // Don't render if item is hidden if (!item->Show) { @@ -210,9 +210,8 @@ bool BeginItem(const char* label_id, ImPlot3DItemFlags flags, ImPlot3DCol recolo // 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; + s.LineWeight *= ITEM_HIGHLIGHT_LINE_SCALE; + s.MarkerSize *= ITEM_HIGHLIGHT_MARK_SCALE; } } } @@ -220,12 +219,12 @@ bool BeginItem(const char* label_id, ImPlot3DItemFlags flags, ImPlot3DCol recolo return true; } -template -bool BeginItemEx(const char* label_id, const _Getter& getter, ImPlot3DItemFlags flags = 0, ImPlot3DCol recolor_from = IMPLOT3D_AUTO) { - if (BeginItem(label_id, flags, recolor_from)) { +template bool BeginItemEx(const char* label_id, const _Getter& getter, const ImPlot3DSpec& spec, + const ImVec4& item_col = IMPLOT3D_AUTO_COL, ImPlot3DMarker item_mkr = ImPlot3DMarker_Invalid) { + if (BeginItem(label_id, spec, item_col, item_mkr)) { ImPlot3DContext& gp = *GImPlot3D; ImPlot3DPlot& plot = *gp.CurrentPlot; - if (plot.FitThisFrame && !ImHasFlag(flags, ImPlot3DItemFlags_NoFit)) { + if (plot.FitThisFrame && !ImHasFlag(spec.Flags, ImPlot3DItemFlags_NoFit)) { for (int i = 0; i < getter.Count; i++) plot.ExtendFit(getter(i)); } @@ -277,30 +276,6 @@ void BustItemCache() { } } -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; - n.Colors[ImPlot3DCol_Fill] = col; - n.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 //----------------------------------------------------------------------------- @@ -814,7 +789,7 @@ template struct RendererSurfaceFill : RendererBase { ImU32 cols[4] = {Col, Col, Col, Col}; const ImPlot3DNextItemData& n = GetItemData(); if (n.IsAutoFill) { - float alpha = GImPlot3D->NextItemData.FillAlpha; + float alpha = GImPlot3D->NextItemData.Spec.FillAlpha; double min = Min; double max = Max; if (ScaleMin != 0.0 || ScaleMax != 0.0) { @@ -1153,30 +1128,31 @@ template void RenderMarkers(const _Getter& getter, ImPlot3DMa // [SECTION] PlotScatter //----------------------------------------------------------------------------- -template void PlotScatterEx(const char* label_id, const Getter& getter, ImPlot3DScatterFlags flags) { - if (BeginItemEx(label_id, getter, flags, ImPlot3DCol_MarkerOutline)) { +template void PlotScatterEx(const char* label_id, const Getter& getter, const ImPlot3DSpec& spec) { + if (BeginItemEx(label_id, getter, spec, spec.MarkerLineColor, spec.Marker)) { 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]); + const ImPlot3DSpec& s = n.Spec; + ImPlot3DMarker marker = s.Marker == ImPlot3DMarker_None ? ImPlot3DMarker_Circle : s.Marker; + const ImU32 col_line = ImGui::GetColorU32(s.MarkerLineColor); + const ImU32 col_fill = ImGui::GetColorU32(s.MarkerFillColor); if (marker != ImPlot3DMarker_None) - RenderMarkers(getter, marker, n.MarkerSize, n.RenderMarkerFill, col_fill, n.RenderMarkerLine, col_line, n.MarkerWeight); + RenderMarkers(getter, marker, s.MarkerSize, n.RenderMarkerFill, col_fill, n.RenderMarkerLine, col_line, s.LineWeight); EndItem(); } } -template -void PlotScatter(const char* label_id, const T* xs, const T* ys, const T* zs, int count, ImPlot3DScatterFlags flags, int offset, int stride) { +template void PlotScatter(const char* label_id, const T* xs, const T* ys, const T* zs, int count, const ImPlot3DSpec& spec) { if (count < 1) return; - GetterXYZ, IndexerIdx, IndexerIdx> getter(IndexerIdx(xs, count, offset, stride), IndexerIdx(ys, count, offset, stride), - IndexerIdx(zs, count, offset, stride), count); - return PlotScatterEx(label_id, getter, flags); + int stride = Stride(spec); + GetterXYZ, IndexerIdx, IndexerIdx> getter(IndexerIdx(xs, count, spec.Offset, stride), + IndexerIdx(ys, count, spec.Offset, stride), + IndexerIdx(zs, count, spec.Offset, stride), count); + return PlotScatterEx(label_id, getter, spec); } #define INSTANTIATE_MACRO(T) \ - template IMPLOT3D_API void PlotScatter(const char* label_id, const T* xs, const T* ys, const T* zs, int count, ImPlot3DScatterFlags flags, \ - int offset, int stride); + template IMPLOT3D_API void PlotScatter(const char* label_id, const T* xs, const T* ys, const T* zs, int count, const ImPlot3DSpec& spec); CALL_INSTANTIATE_FOR_NUMERIC_TYPES() #undef INSTANTIATE_MACRO @@ -1184,47 +1160,50 @@ CALL_INSTANTIATE_FOR_NUMERIC_TYPES() // [SECTION] PlotLine //----------------------------------------------------------------------------- -template void PlotLineEx(const char* label_id, const _Getter& getter, ImPlot3DLineFlags flags) { - if (BeginItemEx(label_id, getter, flags, ImPlot3DCol_Line)) { +template void PlotLineEx(const char* label_id, const _Getter& getter, const ImPlot3DSpec& spec) { + if (BeginItemEx(label_id, getter, spec, spec.LineColor, spec.Marker)) { const ImPlot3DNextItemData& n = GetItemData(); + const ImPlot3DSpec& s = n.Spec; + if (getter.Count >= 2 && n.RenderLine) { - const ImU32 col_line = ImGui::GetColorU32(n.Colors[ImPlot3DCol_Line]); - if (ImHasFlag(flags, ImPlot3DLineFlags_Segments)) { - RenderPrimitives(getter, col_line, n.LineWeight); - } else if (ImHasFlag(flags, ImPlot3DLineFlags_Loop)) { - if (ImHasFlag(flags, ImPlot3DLineFlags_SkipNaN)) - RenderPrimitives(GetterLoop<_Getter>(getter), col_line, n.LineWeight); + const ImU32 col_line = ImGui::GetColorU32(s.LineColor); + if (ImHasFlag(spec.Flags, ImPlot3DLineFlags_Segments)) { + RenderPrimitives(getter, col_line, s.LineWeight); + } else if (ImHasFlag(spec.Flags, ImPlot3DLineFlags_Loop)) { + if (ImHasFlag(spec.Flags, ImPlot3DLineFlags_SkipNaN)) + RenderPrimitives(GetterLoop<_Getter>(getter), col_line, s.LineWeight); else - RenderPrimitives(GetterLoop<_Getter>(getter), col_line, n.LineWeight); + RenderPrimitives(GetterLoop<_Getter>(getter), col_line, s.LineWeight); } else { - if (ImHasFlag(flags, ImPlot3DLineFlags_SkipNaN)) - RenderPrimitives(getter, col_line, n.LineWeight); + if (ImHasFlag(spec.Flags, ImPlot3DLineFlags_SkipNaN)) + RenderPrimitives(getter, col_line, s.LineWeight); else - RenderPrimitives(getter, col_line, n.LineWeight); + RenderPrimitives(getter, col_line, s.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); + if (s.Marker != ImPlot3DMarker_None) { + const ImU32 col_line = ImGui::GetColorU32(s.MarkerLineColor); + const ImU32 col_fill = ImGui::GetColorU32(s.MarkerFillColor); + RenderMarkers<_Getter>(getter, s.Marker, s.MarkerSize, n.RenderMarkerFill, col_fill, n.RenderMarkerLine, col_line, s.LineWeight); } 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) { +IMPLOT3D_TMP void PlotLine(const char* label_id, const T* xs, const T* ys, const T* zs, int count, const ImPlot3DSpec& spec) { if (count < 2) return; - GetterXYZ, IndexerIdx, IndexerIdx> getter(IndexerIdx(xs, count, offset, stride), IndexerIdx(ys, count, offset, stride), - IndexerIdx(zs, count, offset, stride), count); - return PlotLineEx(label_id, getter, flags); + int stride = Stride(spec); + GetterXYZ, IndexerIdx, IndexerIdx> getter(IndexerIdx(xs, count, spec.Offset, stride), + IndexerIdx(ys, count, spec.Offset, stride), + IndexerIdx(zs, count, spec.Offset, stride), count); + return PlotLineEx(label_id, getter, spec); } #define INSTANTIATE_MACRO(T) \ - template IMPLOT3D_API void PlotLine(const char* label_id, const T* xs, const T* ys, const T* zs, int count, ImPlot3DLineFlags flags, \ - int offset, int stride); + template IMPLOT3D_API void PlotLine(const char* label_id, const T* xs, const T* ys, const T* zs, int count, const ImPlot3DSpec& spec); CALL_INSTANTIATE_FOR_NUMERIC_TYPES() #undef INSTANTIATE_MACRO @@ -1232,45 +1211,46 @@ CALL_INSTANTIATE_FOR_NUMERIC_TYPES() // [SECTION] PlotTriangle //----------------------------------------------------------------------------- -template void PlotTriangleEx(const char* label_id, const _Getter& getter, ImPlot3DTriangleFlags flags) { - if (BeginItemEx(label_id, getter, flags, ImPlot3DCol_Fill)) { +template void PlotTriangleEx(const char* label_id, const _Getter& getter, const ImPlot3DSpec& spec) { + if (BeginItemEx(label_id, getter, spec, spec.FillColor, spec.Marker)) { const ImPlot3DNextItemData& n = GetItemData(); + const ImPlot3DSpec& s = n.Spec; // Render fill - if (getter.Count >= 3 && n.RenderFill && !ImHasFlag(flags, ImPlot3DTriangleFlags_NoFill)) { - const ImU32 col_fill = ImGui::GetColorU32(n.Colors[ImPlot3DCol_Fill]); + if (getter.Count >= 3 && n.RenderFill && !ImHasFlag(spec.Flags, ImPlot3DTriangleFlags_NoFill)) { + const ImU32 col_fill = ImGui::GetColorU32(s.FillColor); RenderPrimitives(getter, col_fill); } // Render lines - if (getter.Count >= 2 && n.RenderLine && !ImHasFlag(flags, ImPlot3DTriangleFlags_NoLines)) { - const ImU32 col_line = ImGui::GetColorU32(n.Colors[ImPlot3DCol_Line]); - RenderPrimitives(GetterTriangleLines<_Getter>(getter), col_line, n.LineWeight); + if (getter.Count >= 2 && n.RenderLine && !ImHasFlag(spec.Flags, ImPlot3DTriangleFlags_NoLines)) { + const ImU32 col_line = ImGui::GetColorU32(s.LineColor); + RenderPrimitives(GetterTriangleLines<_Getter>(getter), col_line, s.LineWeight); } // Render markers - if (n.Marker != ImPlot3DMarker_None && !ImHasFlag(flags, ImPlot3DTriangleFlags_NoMarkers)) { - 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); + if (s.Marker != ImPlot3DMarker_None && !ImHasFlag(spec.Flags, ImPlot3DTriangleFlags_NoMarkers)) { + const ImU32 col_line = ImGui::GetColorU32(s.MarkerLineColor); + const ImU32 col_fill = ImGui::GetColorU32(s.MarkerFillColor); + RenderMarkers<_Getter>(getter, s.Marker, s.MarkerSize, n.RenderMarkerFill, col_fill, n.RenderMarkerLine, col_line, s.LineWeight); } 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) { +IMPLOT3D_TMP void PlotTriangle(const char* label_id, const T* xs, const T* ys, const T* zs, int count, const ImPlot3DSpec& spec) { if (count < 3) return; - GetterXYZ, IndexerIdx, IndexerIdx> getter(IndexerIdx(xs, count, offset, stride), IndexerIdx(ys, count, offset, stride), - IndexerIdx(zs, count, offset, stride), count); - return PlotTriangleEx(label_id, getter, flags); + int stride = Stride(spec); + GetterXYZ, IndexerIdx, IndexerIdx> getter(IndexerIdx(xs, count, spec.Offset, stride), + IndexerIdx(ys, count, spec.Offset, stride), + IndexerIdx(zs, count, spec.Offset, stride), count); + return PlotTriangleEx(label_id, getter, spec); } #define INSTANTIATE_MACRO(T) \ - template IMPLOT3D_API void PlotTriangle(const char* label_id, const T* xs, const T* ys, const T* zs, int count, ImPlot3DTriangleFlags flags, \ - int offset, int stride); + template IMPLOT3D_API void PlotTriangle(const char* label_id, const T* xs, const T* ys, const T* zs, int count, const ImPlot3DSpec& spec); CALL_INSTANTIATE_FOR_NUMERIC_TYPES() #undef INSTANTIATE_MACRO @@ -1278,44 +1258,46 @@ CALL_INSTANTIATE_FOR_NUMERIC_TYPES() // [SECTION] PlotQuad //----------------------------------------------------------------------------- -template void PlotQuadEx(const char* label_id, const _Getter& getter, ImPlot3DQuadFlags flags) { - if (BeginItemEx(label_id, getter, flags, ImPlot3DCol_Fill)) { +template void PlotQuadEx(const char* label_id, const _Getter& getter, const ImPlot3DSpec& spec) { + if (BeginItemEx(label_id, getter, spec, spec.FillColor, spec.Marker)) { const ImPlot3DNextItemData& n = GetItemData(); + const ImPlot3DSpec& s = n.Spec; // Render fill - if (getter.Count >= 4 && n.RenderFill && !ImHasFlag(flags, ImPlot3DQuadFlags_NoFill)) { - const ImU32 col_fill = ImGui::GetColorU32(n.Colors[ImPlot3DCol_Fill]); + if (getter.Count >= 4 && n.RenderFill && !ImHasFlag(spec.Flags, ImPlot3DQuadFlags_NoFill)) { + const ImU32 col_fill = ImGui::GetColorU32(s.FillColor); RenderPrimitives(getter, col_fill); } // Render lines - if (getter.Count >= 2 && n.RenderLine && !ImHasFlag(flags, ImPlot3DQuadFlags_NoLines)) { - const ImU32 col_line = ImGui::GetColorU32(n.Colors[ImPlot3DCol_Line]); - RenderPrimitives(GetterQuadLines<_Getter>(getter), col_line, n.LineWeight); + if (getter.Count >= 2 && n.RenderLine && !ImHasFlag(spec.Flags, ImPlot3DQuadFlags_NoLines)) { + const ImU32 col_line = ImGui::GetColorU32(s.LineColor); + RenderPrimitives(GetterQuadLines<_Getter>(getter), col_line, s.LineWeight); } // Render markers - if (n.Marker != ImPlot3DMarker_None && !ImHasFlag(flags, ImPlot3DQuadFlags_NoMarkers)) { - 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); + if (s.Marker != ImPlot3DMarker_None && !ImHasFlag(spec.Flags, ImPlot3DQuadFlags_NoMarkers)) { + const ImU32 col_line = ImGui::GetColorU32(s.MarkerLineColor); + const ImU32 col_fill = ImGui::GetColorU32(s.MarkerFillColor); + RenderMarkers<_Getter>(getter, s.Marker, s.MarkerSize, n.RenderMarkerFill, col_fill, n.RenderMarkerLine, col_line, s.LineWeight); } 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) { +IMPLOT3D_TMP void PlotQuad(const char* label_id, const T* xs, const T* ys, const T* zs, int count, const ImPlot3DSpec& spec) { if (count < 3) return; - GetterXYZ, IndexerIdx, IndexerIdx> getter(IndexerIdx(xs, count, offset, stride), IndexerIdx(ys, count, offset, stride), - IndexerIdx(zs, count, offset, stride), count); - return PlotQuadEx(label_id, getter, flags); + int stride = Stride(spec); + GetterXYZ, IndexerIdx, IndexerIdx> getter(IndexerIdx(xs, count, spec.Offset, stride), + IndexerIdx(ys, count, spec.Offset, stride), + IndexerIdx(zs, count, spec.Offset, stride), count); + return PlotQuadEx(label_id, getter, spec); } #define INSTANTIATE_MACRO(T) \ - template IMPLOT3D_API void PlotQuad(const char* label_id, const T* xs, const T* ys, const T* zs, int count, ImPlot3DQuadFlags flags, \ - int offset, int stride); + template IMPLOT3D_API void PlotQuad(const char* label_id, const T* xs, const T* ys, const T* zs, int count, const ImPlot3DSpec& spec); CALL_INSTANTIATE_FOR_NUMERIC_TYPES() #undef INSTANTIATE_MACRO @@ -1324,27 +1306,28 @@ CALL_INSTANTIATE_FOR_NUMERIC_TYPES() //----------------------------------------------------------------------------- template void PlotSurfaceEx(const char* label_id, const _Getter& getter, int x_count, int y_count, double scale_min, - double scale_max, ImPlot3DSurfaceFlags flags) { - if (BeginItemEx(label_id, getter, flags, ImPlot3DCol_Fill)) { + double scale_max, const ImPlot3DSpec& spec) { + if (BeginItemEx(label_id, getter, spec, spec.FillColor, spec.Marker)) { const ImPlot3DNextItemData& n = GetItemData(); + const ImPlot3DSpec& s = n.Spec; // Render fill - if (getter.Count >= 4 && n.RenderFill && !ImHasFlag(flags, ImPlot3DSurfaceFlags_NoFill)) { - const ImU32 col_fill = ImGui::GetColorU32(n.Colors[ImPlot3DCol_Fill]); + if (getter.Count >= 4 && n.RenderFill && !ImHasFlag(spec.Flags, ImPlot3DSurfaceFlags_NoFill)) { + const ImU32 col_fill = ImGui::GetColorU32(s.FillColor); RenderPrimitives(getter, x_count, y_count, col_fill, scale_min, scale_max); } // Render lines - if (getter.Count >= 2 && n.RenderLine && !ImHasFlag(flags, ImPlot3DSurfaceFlags_NoLines)) { - const ImU32 col_line = ImGui::GetColorU32(n.Colors[ImPlot3DCol_Line]); - RenderPrimitives(GetterSurfaceLines<_Getter>(getter, x_count, y_count), col_line, n.LineWeight); + if (getter.Count >= 2 && n.RenderLine && !ImHasFlag(spec.Flags, ImPlot3DSurfaceFlags_NoLines)) { + const ImU32 col_line = ImGui::GetColorU32(s.LineColor); + RenderPrimitives(GetterSurfaceLines<_Getter>(getter, x_count, y_count), col_line, s.LineWeight); } // Render markers - if (n.Marker != ImPlot3DMarker_None && !ImHasFlag(flags, ImPlot3DSurfaceFlags_NoMarkers)) { - 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); + if (s.Marker != ImPlot3DMarker_None && !ImHasFlag(spec.Flags, ImPlot3DSurfaceFlags_NoMarkers)) { + const ImU32 col_line = ImGui::GetColorU32(s.MarkerLineColor); + const ImU32 col_fill = ImGui::GetColorU32(s.MarkerFillColor); + RenderMarkers<_Getter>(getter, s.Marker, s.MarkerSize, n.RenderMarkerFill, col_fill, n.RenderMarkerLine, col_line, s.LineWeight); } EndItem(); @@ -1352,18 +1335,20 @@ template void PlotSurfaceEx(const char* label_id, const _Gett } IMPLOT3D_TMP void PlotSurface(const char* label_id, const T* xs, const T* ys, const T* zs, int x_count, int y_count, double scale_min, - double scale_max, ImPlot3DSurfaceFlags flags, int offset, int stride) { + double scale_max, const ImPlot3DSpec& spec) { int count = x_count * y_count; if (count < 4) return; - GetterXYZ, IndexerIdx, IndexerIdx> getter(IndexerIdx(xs, count, offset, stride), IndexerIdx(ys, count, offset, stride), - IndexerIdx(zs, count, offset, stride), count); - return PlotSurfaceEx(label_id, getter, x_count, y_count, scale_min, scale_max, flags); + int stride = Stride(spec); + GetterXYZ, IndexerIdx, IndexerIdx> getter(IndexerIdx(xs, count, spec.Offset, stride), + IndexerIdx(ys, count, spec.Offset, stride), + IndexerIdx(zs, count, spec.Offset, stride), count); + return PlotSurfaceEx(label_id, getter, x_count, y_count, scale_min, scale_max, spec); } #define INSTANTIATE_MACRO(T) \ template IMPLOT3D_API void PlotSurface(const char* label_id, const T* xs, const T* ys, const T* zs, int x_count, int y_count, \ - double scale_min, double scale_max, ImPlot3DSurfaceFlags flags, int offset, int stride); + double scale_min, double scale_max, const ImPlot3DSpec& spec); CALL_INSTANTIATE_FOR_NUMERIC_TYPES() #undef INSTANTIATE_MACRO @@ -1371,29 +1356,31 @@ CALL_INSTANTIATE_FOR_NUMERIC_TYPES() // [SECTION] PlotMesh //----------------------------------------------------------------------------- -void PlotMesh(const char* label_id, const ImPlot3DPoint* vtx, const unsigned int* idx, int vtx_count, int idx_count, ImPlot3DMeshFlags flags) { +void PlotMesh(const char* label_id, const ImPlot3DPoint* vtx, const unsigned int* idx, int vtx_count, int idx_count, const ImPlot3DSpec& spec) { 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)) { + + if (BeginItemEx(label_id, getter, spec, spec.FillColor, spec.Marker)) { const ImPlot3DNextItemData& n = GetItemData(); + const ImPlot3DSpec& s = n.Spec; // Render fill - if (getter.Count >= 3 && n.RenderFill && !ImHasFlag(flags, ImPlot3DMeshFlags_NoFill)) { - const ImU32 col_fill = ImGui::GetColorU32(n.Colors[ImPlot3DCol_Fill]); + if (getter.Count >= 3 && n.RenderFill && !ImHasFlag(spec.Flags, ImPlot3DMeshFlags_NoFill)) { + const ImU32 col_fill = ImGui::GetColorU32(s.FillColor); RenderPrimitives(getter_triangles, col_fill); } // Render lines - if (getter.Count >= 2 && n.RenderLine && !n.IsAutoLine && !ImHasFlag(flags, ImPlot3DMeshFlags_NoLines)) { - const ImU32 col_line = ImGui::GetColorU32(n.Colors[ImPlot3DCol_Line]); - RenderPrimitives(GetterTriangleLines(getter_triangles), col_line, n.LineWeight); + if (getter.Count >= 2 && n.RenderLine && !n.IsAutoLine && !ImHasFlag(spec.Flags, ImPlot3DMeshFlags_NoLines)) { + const ImU32 col_line = ImGui::GetColorU32(s.LineColor); + RenderPrimitives(GetterTriangleLines(getter_triangles), col_line, s.LineWeight); } // Render markers - if (n.Marker != ImPlot3DMarker_None && !ImHasFlag(flags, ImPlot3DMeshFlags_NoMarkers)) { - 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); + if (s.Marker != ImPlot3DMarker_None && !ImHasFlag(spec.Flags, ImPlot3DMeshFlags_NoMarkers)) { + const ImU32 col_line = ImGui::GetColorU32(s.MarkerLineColor); + const ImU32 col_fill = ImGui::GetColorU32(s.MarkerFillColor); + RenderMarkers(getter, s.Marker, s.MarkerSize, n.RenderMarkerFill, col_fill, n.RenderMarkerLine, col_line, s.LineWeight); } EndItem(); @@ -1405,7 +1392,7 @@ void PlotMesh(const char* label_id, const ImPlot3DPoint* vtx, const unsigned int //----------------------------------------------------------------------------- IMPLOT3D_API void PlotImage(const char* label_id, ImTextureRef tex_ref, const ImPlot3DPoint& center, const ImPlot3DPoint& axis_u, - const ImPlot3DPoint& axis_v, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, ImPlot3DImageFlags flags) { + const ImPlot3DPoint& axis_v, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImPlot3DSpec& spec) { // Compute corners from center and axes ImPlot3DPoint p0 = center - axis_u - axis_v; // Bottom-left ImPlot3DPoint p1 = center + axis_u - axis_v; // Bottom-right @@ -1419,12 +1406,12 @@ IMPLOT3D_API void PlotImage(const char* label_id, ImTextureRef tex_ref, const Im ImVec2 uv_3 = ImVec2(uv0.x, uv1.y); // Delegate to full quad version - PlotImage(label_id, tex_ref, p0, p1, p2, p3, uv_0, uv_1, uv_2, uv_3, tint_col, flags); + PlotImage(label_id, tex_ref, p0, p1, p2, p3, uv_0, uv_1, uv_2, uv_3, tint_col, spec); } IMPLOT3D_API void PlotImage(const char* label_id, ImTextureRef tex_ref, const ImPlot3DPoint& p0, const ImPlot3DPoint& p1, const ImPlot3DPoint& p2, const ImPlot3DPoint& p3, const ImVec2& uv0, const ImVec2& uv1, const ImVec2& uv2, const ImVec2& uv3, - const ImVec4& tint_col, ImPlot3DImageFlags flags) { + const ImVec4& tint_col, const ImPlot3DSpec& spec) { ImPlot3DContext& gp = *GImPlot3D; IM_ASSERT_USER_ERROR(gp.CurrentPlot != nullptr, "PlotImage() needs to be called between BeginPlot() and EndPlot()!"); SetupLock(); @@ -1438,7 +1425,7 @@ IMPLOT3D_API void PlotImage(const char* label_id, ImTextureRef tex_ref, const Im ImVec2 uv_2 = ImVec2(uv2.x, 1 - uv2.y); ImVec2 uv_3 = ImVec2(uv3.x, 1 - uv3.y); - if (BeginItemEx(label_id, getter, flags)) { + if (BeginItemEx(label_id, getter, spec, tint_col, spec.Marker)) { ImU32 tint_col32 = ImGui::ColorConvertFloat4ToU32(tint_col); GetCurrentItem()->Color = tint_col32; @@ -1478,8 +1465,8 @@ void PlotText(const char* text, double x, double y, double z, double angle, cons AddTextRotated(GetPlotDrawList(), p, (float)angle, GetStyleColorU32(ImPlot3DCol_InlayText), text); } -void PlotDummy(const char* label_id, ImPlot3DDummyFlags flags) { - if (BeginItem(label_id, flags, ImPlot3DCol_Line)) +void PlotDummy(const char* label_id, const ImPlot3DSpec& spec) { + if (BeginItem(label_id, spec, spec.LineColor, spec.Marker)) EndItem(); }