#ifndef IMPLOT_DISABLE_OBSOLETE_FUNCTIONS
#define IMPLOT_DISABLE_OBSOLETE_FUNCTIONS
#endif
#include "implot3d.h"
#include "implot3d_internal.h"
#if IMGUI_VERSION_NUM >= 19263
namespace ImGui {
extern IMGUI_API void DemoMarker(const char* file, int line, const char* section);
};
#define IMGUI_DEMO_MARKER(section) \
do { \
ImGui::DemoMarker("implot3d_demo.cpp", __LINE__, section); \
} while (0)
#else
#define IMGUI_DEMO_MARKER(section)
#endif
namespace MyImPlot3D {
void StyleSeaborn();
}
namespace ImPlot3D {
#define CHECKBOX_FLAG(flags, flag) ImGui::CheckboxFlags(#flag, (unsigned int*)&flags, flag)
static void HelpMarker(const char* desc) {
ImGui::TextDisabled("(?)");
if (ImGui::BeginItemTooltip()) {
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
ImGui::TextUnformatted(desc);
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
}
}
struct ScrollingBuffer {
int MaxSize;
int Offset;
ImVector<float> Data;
ScrollingBuffer(int max_size = 2000) {
MaxSize = max_size;
Offset = 0;
Data.reserve(MaxSize);
}
void AddPoint(float x) {
if (Data.size() < MaxSize)
Data.push_back(x);
else {
Data[Offset] = x;
Offset = (Offset + 1) % MaxSize;
}
}
void Erase() {
if (Data.size() > 0) {
Data.shrink(0);
Offset = 0;
}
}
};
int MetricFormatter(double value, char* buff, int size, void* data) {
const char* unit = (const char*)data;
static double v[] = {1000000000, 1000000, 1000, 1, 0.001, 0.000001, 0.000000001};
static const char* p[] = {"G", "M", "k", "", "m", "u", "n"};
if (value == 0) {
return snprintf(buff, size, "0 %s", unit);
}
for (int i = 0; i < 7; ++i) {
if (fabs(value) >= v[i]) {
return snprintf(buff, size, "%g %s%s", value / v[i], p[i], unit);
}
}
return snprintf(buff, size, "%g %s%s", value / v[6], p[6], unit);
}
void DemoLinePlots() {
IMGUI_DEMO_MARKER("Plots/Line Plots");
static float xs1[1001], ys1[1001], zs1[1001];
for (int i = 0; i < 1001; i++) {
xs1[i] = i * 0.001f;
ys1[i] = 0.5f + 0.5f * cosf(50 * (xs1[i] + (float)ImGui::GetTime() / 10));
zs1[i] = 0.5f + 0.5f * sinf(50 * (xs1[i] + (float)ImGui::GetTime() / 10));
}
static double xs2[20], ys2[20], zs2[20];
for (int i = 0; i < 20; i++) {
xs2[i] = i * 1 / 19.0f;
ys2[i] = xs2[i] * xs2[i];
zs2[i] = xs2[i] * ys2[i];
}
if (ImPlot3D::BeginPlot("Line Plots")) {
ImPlot3D::SetupAxes("x", "y", "z");
ImPlot3D::PlotLine("f(x)", xs1, ys1, zs1, 1001);
ImPlot3D::PlotLine("g(x)", xs2, ys2, zs2, 20, {ImPlot3DProp_Marker, ImPlot3DMarker_Circle, ImPlot3DProp_Flags, ImPlot3DLineFlags_Segments});
ImPlot3D::EndPlot();
}
}
void DemoScatterPlots() {
IMGUI_DEMO_MARKER("Plots/Scatter Plots");
srand(0);
static float xs1[100], ys1[100], zs1[100];
for (int i = 0; i < 100; i++) {
xs1[i] = i * 0.01f;
ys1[i] = xs1[i] + 0.1f * ((float)rand() / (float)RAND_MAX);
zs1[i] = xs1[i] + 0.1f * ((float)rand() / (float)RAND_MAX);
}
static float xs2[50], ys2[50], zs2[50];
for (int i = 0; i < 50; i++) {
xs2[i] = 0.25f + 0.2f * ((float)rand() / (float)RAND_MAX);
ys2[i] = 0.50f + 0.2f * ((float)rand() / (float)RAND_MAX);
zs2[i] = 0.75f + 0.2f * ((float)rand() / (float)RAND_MAX);
}
if (ImPlot3D::BeginPlot("Scatter Plots")) {
ImPlot3D::PlotScatter("Data 1", xs1, ys1, zs1, 100);
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();
}
}
void DemoTrianglePlots() {
IMGUI_DEMO_MARKER("Plots/Triangle Plots");
float ax = 0.0f, ay = 0.0f, az = 1.0f;
float cx[4] = {-0.5f, 0.5f, 0.5f, -0.5f};
float cy[4] = {-0.5f, -0.5f, 0.5f, 0.5f};
float cz[4] = {0.0f, 0.0f, 0.0f, 0.0f};
static float xs[18], ys[18], zs[18];
int i = 0;
auto AddVertex = [&](float X, float Y, float Z) {
xs[i] = X;
ys[i] = Y;
zs[i] = Z;
i++;
};
AddVertex(ax, ay, az);
AddVertex(cx[0], cy[0], cz[0]);
AddVertex(cx[1], cy[1], cz[1]);
AddVertex(ax, ay, az);
AddVertex(cx[1], cy[1], cz[1]);
AddVertex(cx[2], cy[2], cz[2]);
AddVertex(ax, ay, az);
AddVertex(cx[2], cy[2], cz[2]);
AddVertex(cx[3], cy[3], cz[3]);
AddVertex(ax, ay, az);
AddVertex(cx[3], cy[3], cz[3]);
AddVertex(cx[0], cy[0], cz[0]);
AddVertex(cx[0], cy[0], cz[0]);
AddVertex(cx[1], cy[1], cz[1]);
AddVertex(cx[2], cy[2], cz[2]);
AddVertex(cx[0], cy[0], cz[0]);
AddVertex(cx[2], cy[2], cz[2]);
AddVertex(cx[3], cy[3], cz[3]);
static ImPlot3DTriangleFlags flags = ImPlot3DTriangleFlags_None;
CHECKBOX_FLAG(flags, ImPlot3DTriangleFlags_NoLines);
CHECKBOX_FLAG(flags, ImPlot3DTriangleFlags_NoFill);
CHECKBOX_FLAG(flags, ImPlot3DTriangleFlags_NoMarkers);
if (ImPlot3D::BeginPlot("Triangle Plots")) {
ImPlot3D::SetupAxesLimits(-1, 1, -1, 1, -0.5, 1.5);
ImPlot3DSpec spec;
spec.FillColor = ImPlot3D::GetColormapColor(0);
spec.LineColor = ImPlot3D::GetColormapColor(1);
spec.Marker = ImPlot3DMarker_Square;
spec.MarkerSize = 3;
spec.Flags = flags;
ImPlot3D::PlotTriangle("Pyramid", xs, ys, zs, 6 * 3, spec); ImPlot3D::EndPlot();
}
}
void DemoQuadPlots() {
IMGUI_DEMO_MARKER("Plots/Quad Plots");
static float xs[6 * 4], ys[6 * 4], zs[6 * 4];
xs[0] = 1; ys[0] = -1; zs[0] = -1;
xs[1] = 1; ys[1] = 1; zs[1] = -1;
xs[2] = 1; ys[2] = 1; zs[2] = 1;
xs[3] = 1; ys[3] = -1; zs[3] = 1;
xs[4] = -1; ys[4] = -1; zs[4] = -1;
xs[5] = -1; ys[5] = 1; zs[5] = -1;
xs[6] = -1; ys[6] = 1; zs[6] = 1;
xs[7] = -1; ys[7] = -1; zs[7] = 1;
xs[8] = -1; ys[8] = 1; zs[8] = -1;
xs[9] = 1; ys[9] = 1; zs[9] = -1;
xs[10] = 1; ys[10] = 1; zs[10] = 1;
xs[11] = -1; ys[11] = 1; zs[11] = 1;
xs[12] = -1; ys[12] = -1; zs[12] = -1;
xs[13] = 1; ys[13] = -1; zs[13] = -1;
xs[14] = 1; ys[14] = -1; zs[14] = 1;
xs[15] = -1; ys[15] = -1; zs[15] = 1;
xs[16] = -1; ys[16] = -1; zs[16] = 1;
xs[17] = 1; ys[17] = -1; zs[17] = 1;
xs[18] = 1; ys[18] = 1; zs[18] = 1;
xs[19] = -1; ys[19] = 1; zs[19] = 1;
xs[20] = -1; ys[20] = -1; zs[20] = -1;
xs[21] = 1; ys[21] = -1; zs[21] = -1;
xs[22] = 1; ys[22] = 1; zs[22] = -1;
xs[23] = -1; ys[23] = 1; zs[23] = -1;
static ImPlot3DQuadFlags flags = ImPlot3DQuadFlags_None;
CHECKBOX_FLAG(flags, ImPlot3DQuadFlags_NoLines);
CHECKBOX_FLAG(flags, ImPlot3DQuadFlags_NoFill);
CHECKBOX_FLAG(flags, ImPlot3DQuadFlags_NoMarkers);
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;
static ImVec4 colorX(0.8f, 0.2f, 0.2f, 0.8f); spec.FillColor = colorX;
spec.LineColor = colorX;
ImPlot3D::PlotQuad("X", &xs[0], &ys[0], &zs[0], 8, spec);
static ImVec4 colorY(0.2f, 0.8f, 0.2f, 0.8f); spec.FillColor = colorY;
spec.LineColor = colorY;
ImPlot3D::PlotQuad("Y", &xs[8], &ys[8], &zs[8], 8, spec);
static ImVec4 colorZ(0.2f, 0.2f, 0.8f, 0.8f); spec.FillColor = colorZ;
spec.LineColor = colorZ;
ImPlot3D::PlotQuad("Z", &xs[16], &ys[16], &zs[16], 8, spec);
ImPlot3D::EndPlot();
}
}
void DemoSurfacePlots() {
IMGUI_DEMO_MARKER("Plots/Surface Plots");
constexpr int N = 20;
static float xs[N * N], ys[N * N], zs[N * N];
static ImU32 custom_colors[N * N];
static float t = 0.0f;
t += ImGui::GetIO().DeltaTime;
constexpr float min_val = -1.0f;
constexpr float max_val = 1.0f;
constexpr float step = (max_val - min_val) / (N - 1);
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
int idx = i * N + j;
xs[idx] = min_val + j * step; ys[idx] = min_val + i * step; zs[idx] = ImSin(2 * t + ImSqrt((xs[idx] * xs[idx] + ys[idx] * ys[idx]))); custom_colors[idx] =
IM_COL32((ImU8)((xs[idx] + 1) * 0.5f * 255), (ImU8)((ys[idx] + 1) * 0.5f * 255), (ImU8)((zs[idx] + 1) * 0.5f * 255), 255);
}
}
ImGui::Text("Fill color");
static int selected_fill = 1; static ImVec4 solid_color = ImVec4(0.8f, 0.8f, 0.2f, 0.6f);
const char* colormaps[] = {"Viridis", "Plasma", "Hot", "Cool", "Pink", "Jet", "Twilight", "RdBu", "BrBG", "PiYG", "Spectral", "Greys"};
static int sel_colormap = 5; {
ImGui::Indent();
ImGui::RadioButton("Solid", &selected_fill, 0);
if (selected_fill == 0) {
ImGui::SameLine();
ImGui::ColorEdit4("##SurfaceSolidColor", (float*)&solid_color);
}
ImGui::RadioButton("Colormap", &selected_fill, 1);
if (selected_fill == 1) {
ImGui::SameLine();
ImGui::Combo("##SurfaceColormap", &sel_colormap, colormaps, IM_ARRAYSIZE(colormaps));
}
ImGui::RadioButton("Custom Per-Point", &selected_fill, 2);
if (selected_fill == 2)
ImGui::SameLine(), ImGui::TextDisabled("R=x, G=y, B=z");
ImGui::Unindent();
}
static bool custom_range = false;
static float range_min = -1.0f;
static float range_max = 1.0f;
if (selected_fill != 1)
ImGui::BeginDisabled();
ImGui::Checkbox("Custom range", &custom_range);
{
ImGui::Indent();
if (!custom_range)
ImGui::BeginDisabled();
ImGui::SliderFloat("Range min", &range_min, -1.0f, range_max - 0.01f);
ImGui::SliderFloat("Range max", &range_max, range_min + 0.01f, 1.0f);
if (!custom_range)
ImGui::EndDisabled();
ImGui::Unindent();
}
if (selected_fill != 1)
ImGui::EndDisabled();
static ImPlot3DSurfaceFlags flags = ImPlot3DSurfaceFlags_NoMarkers;
CHECKBOX_FLAG(flags, ImPlot3DSurfaceFlags_NoLines);
CHECKBOX_FLAG(flags, ImPlot3DSurfaceFlags_NoFill);
CHECKBOX_FLAG(flags, ImPlot3DSurfaceFlags_NoMarkers);
if (selected_fill == 1)
ImPlot3D::PushColormap(colormaps[sel_colormap]);
if (ImPlot3D::BeginPlot("Surface Plots", ImVec2(-1, 0), ImPlot3DFlags_NoClip)) {
ImPlot3D::SetupAxesLimits(-1, 1, -1, 1, -1.5, 1.5);
ImPlot3DSpec spec;
spec.FillAlpha = 0.8f;
spec.Flags = flags;
spec.Marker = ImPlot3DMarker_Square;
spec.LineColor = ImPlot3D::GetColormapColor(1);
if (selected_fill == 0)
spec.FillColor = solid_color;
else if (selected_fill == 2)
spec.FillColors = custom_colors;
if (custom_range)
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, spec);
ImPlot3D::EndPlot();
}
if (selected_fill == 1)
ImPlot3D::PopColormap();
}
void DemoMeshPlots() {
IMGUI_DEMO_MARKER("Plots/Mesh Plots");
static int mesh_id = 0;
ImGui::Combo("Mesh", &mesh_id, "Duck\0Sphere\0Cube\0\0");
static ImVec4 line_color = ImVec4(0.5f, 0.5f, 0.2f, 0.6f);
ImGui::ColorEdit4("Line Color##Mesh", (float*)&line_color);
static ImVec4 fill_color = ImVec4(0.8f, 0.8f, 0.2f, 0.6f);
ImGui::ColorEdit4("Fill Color##Mesh", (float*)&fill_color);
static ImVec4 marker_color = ImVec4(0.5f, 0.5f, 0.2f, 0.6f);
ImGui::ColorEdit4("Marker Color##Mesh", (float*)&marker_color);
static ImPlot3DMeshFlags flags = ImPlot3DMeshFlags_NoMarkers;
CHECKBOX_FLAG(flags, ImPlot3DMeshFlags_NoLines);
CHECKBOX_FLAG(flags, ImPlot3DMeshFlags_NoFill);
CHECKBOX_FLAG(flags, ImPlot3DMeshFlags_NoMarkers);
if (ImPlot3D::BeginPlot("Mesh Plots")) {
ImPlot3D::SetupAxesLimits(-1, 1, -1, 1, -1, 1);
ImPlot3DSpec spec;
spec.Flags = flags;
spec.Stride = (int)sizeof(ImPlot3DPoint);
spec.FillColor = fill_color;
spec.LineColor = line_color;
spec.Marker = ImPlot3DMarker_Square;
spec.MarkerSize = 3.0f;
spec.MarkerLineColor = marker_color;
spec.MarkerFillColor = marker_color;
if (mesh_id == 0)
ImPlot3D::PlotMesh("Duck", &duck_vtx[0].x, &duck_vtx[0].y, &duck_vtx[0].z, duck_idx, DUCK_VTX_COUNT, DUCK_IDX_COUNT, spec);
else if (mesh_id == 1)
ImPlot3D::PlotMesh("Sphere", &sphere_vtx[0].x, &sphere_vtx[0].y, &sphere_vtx[0].z, sphere_idx, SPHERE_VTX_COUNT, SPHERE_IDX_COUNT, spec);
else if (mesh_id == 2)
ImPlot3D::PlotMesh("Cube", &cube_vtx[0].x, &cube_vtx[0].y, &cube_vtx[0].z, cube_idx, CUBE_VTX_COUNT, CUBE_IDX_COUNT, spec);
ImPlot3D::EndPlot();
}
}
void DemoImagePlots() {
IMGUI_DEMO_MARKER("Plots/Image Plots");
ImGui::BulletText("Below we are displaying the font texture, which is the only texture we have\naccess to in this demo.");
ImGui::BulletText("Use the 'ImTextureID' type as storage to pass pointers or identifiers to your\nown texture data.");
ImGui::BulletText("See ImGui Wiki page 'Image Loading and Displaying Examples'.");
static ImVec4 tint1(1, 1, 1, 1);
static ImVec4 tint2(1, 1, 1, 1);
static ImPlot3DPoint center1(0, 0, 1);
static ImPlot3DPoint axis_u1(1, 0, 0);
static ImPlot3DPoint axis_v1(0, 1, 0);
static ImVec2 uv0_1(0, 0), uv1_1(1, 1);
static ImPlot3DPoint p0(-1, -1, 0);
static ImPlot3DPoint p1(1, -1, 0);
static ImPlot3DPoint p2(1, 1, 0);
static ImPlot3DPoint p3(-1, 1, 0);
static ImVec2 uv0(0, 0), uv1(1, 0), uv2(1, 1), uv3(0, 1);
ImGui::Dummy(ImVec2(0, 10));
if (ImGui::TreeNodeEx("Image 1 Controls: Center + Axes")) {
float center1_f[3] = {(float)center1.x, (float)center1.y, (float)center1.z};
if (ImGui::SliderFloat3("Center", center1_f, -2, 2, "%.1f")) {
center1 = ImPlot3DPoint(center1_f[0], center1_f[1], center1_f[2]);
}
float axis_u1_f[3] = {(float)axis_u1.x, (float)axis_u1.y, (float)axis_u1.z};
if (ImGui::SliderFloat3("Axis U", axis_u1_f, -2, 2, "%.1f")) {
axis_u1 = ImPlot3DPoint(axis_u1_f[0], axis_u1_f[1], axis_u1_f[2]);
}
float axis_v1_f[3] = {(float)axis_v1.x, (float)axis_v1.y, (float)axis_v1.z};
if (ImGui::SliderFloat3("Axis V", axis_v1_f, -2, 2, "%.1f")) {
axis_v1 = ImPlot3DPoint(axis_v1_f[0], axis_v1_f[1], axis_v1_f[2]);
}
ImGui::SliderFloat2("UV0", &uv0_1.x, 0, 1, "%.2f");
ImGui::SliderFloat2("UV1", &uv1_1.x, 0, 1, "%.2f");
ImGui::ColorEdit4("Tint", &tint1.x);
ImGui::TreePop();
}
if (ImGui::TreeNodeEx("Image 2 Controls: Full Quad")) {
float p0_f[3] = {(float)p0.x, (float)p0.y, (float)p0.z};
if (ImGui::SliderFloat3("P0", p0_f, -2, 2, "%.1f")) {
p0 = ImPlot3DPoint(p0_f[0], p0_f[1], p0_f[2]);
}
float p1_f[3] = {(float)p1.x, (float)p1.y, (float)p1.z};
if (ImGui::SliderFloat3("P1", p1_f, -2, 2, "%.1f")) {
p1 = ImPlot3DPoint(p1_f[0], p1_f[1], p1_f[2]);
}
float p2_f[3] = {(float)p2.x, (float)p2.y, (float)p2.z};
if (ImGui::SliderFloat3("P2", p2_f, -2, 2, "%.1f")) {
p2 = ImPlot3DPoint(p2_f[0], p2_f[1], p2_f[2]);
}
float p3_f[3] = {(float)p3.x, (float)p3.y, (float)p3.z};
if (ImGui::SliderFloat3("P3", p3_f, -2, 2, "%.1f")) {
p3 = ImPlot3DPoint(p3_f[0], p3_f[1], p3_f[2]);
}
ImGui::SliderFloat2("UV0", &uv0.x, 0, 1, "%.2f");
ImGui::SliderFloat2("UV1", &uv1.x, 0, 1, "%.2f");
ImGui::SliderFloat2("UV2", &uv2.x, 0, 1, "%.2f");
ImGui::SliderFloat2("UV3", &uv3.x, 0, 1, "%.2f");
ImGui::ColorEdit4("Tint##2", &tint2.x);
ImGui::TreePop();
}
if (ImPlot3D::BeginPlot("Image Plot", ImVec2(-1, 0), ImPlot3DFlags_NoClip)) {
#ifdef IMGUI_HAS_TEXTURES
ImTextureRef tex = ImGui::GetIO().Fonts->TexRef;
#else
ImTextureID tex = ImGui::GetIO().Fonts->TexID;
#endif
ImPlot3D::PlotImage("Image 1", tex, center1, axis_u1, axis_v1, uv0_1, uv1_1, tint1);
ImPlot3D::PlotImage("Image 2", tex, p0, p1, p2, p3, uv0, uv1, uv2, uv3, tint2);
ImPlot3D::EndPlot();
}
}
void DemoRealtimePlots() {
IMGUI_DEMO_MARKER("Plots/Realtime Plots");
ImGui::BulletText("Move your mouse to change the data!");
static ScrollingBuffer sdata1, sdata2, sdata3;
static ImPlot3DAxisFlags flags = ImPlot3DAxisFlags_NoTickLabels;
static float t = 0.0f;
static float last_t = -1.0f;
if (ImPlot3D::BeginPlot("Scrolling Plot")) {
t += ImGui::GetIO().DeltaTime;
if (t - last_t > 0.01f) {
last_t = t;
ImVec2 mouse = ImGui::GetMousePos();
if (ImAbs(mouse.x) < 1e4f && ImAbs(mouse.y) < 1e4f) {
ImVec2 plot_center = ImPlot3D::GetFramePos();
plot_center.x += ImPlot3D::GetFrameSize().x / 2;
plot_center.y += ImPlot3D::GetFrameSize().y / 2;
sdata1.AddPoint(t);
sdata2.AddPoint(mouse.x - plot_center.x);
sdata3.AddPoint(mouse.y - plot_center.y);
}
}
ImPlot3D::SetupAxes("Time", "Mouse X", "Mouse Y", flags, flags, flags);
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(),
{ImPlot3DProp_Offset, sdata1.Offset, ImPlot3DProp_Stride, sizeof(float)});
ImPlot3D::EndPlot();
}
}
void DemoPlotFlags() {
IMGUI_DEMO_MARKER("Plots/Plot Flags");
static ImPlot3DFlags flags = ImPlot3DFlags_None;
CHECKBOX_FLAG(flags, ImPlot3DFlags_NoTitle);
ImGui::SameLine();
ImGui::TextDisabled("(?)");
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Hide plot title");
}
CHECKBOX_FLAG(flags, ImPlot3DFlags_NoLegend);
ImGui::SameLine();
ImGui::TextDisabled("(?)");
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Hide plot legend");
}
CHECKBOX_FLAG(flags, ImPlot3DFlags_NoMouseText);
ImGui::SameLine();
ImGui::TextDisabled("(?)");
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Hide mouse position in plot coordinates");
}
CHECKBOX_FLAG(flags, ImPlot3DFlags_NoClip);
ImGui::SameLine();
ImGui::TextDisabled("(?)");
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Disable 3D box clipping");
}
CHECKBOX_FLAG(flags, ImPlot3DFlags_NoMenus);
ImGui::SameLine();
ImGui::TextDisabled("(?)");
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("The user will not be able to open context menus");
}
CHECKBOX_FLAG(flags, ImPlot3DFlags_Equal);
ImGui::SameLine();
ImGui::TextDisabled("(?)");
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("X, Y, and Z axes will be constrained to have the same units/pixel");
}
CHECKBOX_FLAG(flags, ImPlot3DFlags_NoRotate);
ImGui::SameLine();
ImGui::TextDisabled("(?)");
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Lock rotation interaction");
}
CHECKBOX_FLAG(flags, ImPlot3DFlags_NoPan);
ImGui::SameLine();
ImGui::TextDisabled("(?)");
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Lock panning/translation interaction");
}
CHECKBOX_FLAG(flags, ImPlot3DFlags_NoZoom);
ImGui::SameLine();
ImGui::TextDisabled("(?)");
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Lock zooming interaction");
}
CHECKBOX_FLAG(flags, ImPlot3DFlags_NoInputs);
ImGui::SameLine();
ImGui::TextDisabled("(?)");
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Disable all user inputs");
}
if (ImPlot3D::BeginPlot("Plot Flags Demo", ImVec2(-1, 0), flags)) {
ImPlot3D::SetupAxes("X-axis", "Y-axis", "Z-axis");
ImPlot3D::SetupAxesLimits(-10, 10, -10, 10, -5, 5);
static float x[100], y[100], z[100];
static bool first = true;
if (first) {
for (int i = 0; i < 100; i++) {
float t = i * 0.1f;
x[i] = 3.0f * cosf(t);
y[i] = 3.0f * sinf(t);
z[i] = t - 5.0f;
}
first = false;
}
ImPlot3D::PlotLine("Helix", x, y, z, 100);
float scatter_x[8] = {-10, 10, -10, 10, -10, 10, -10, 10};
float scatter_y[8] = {-10, -10, 10, 10, -10, -10, 10, 10};
float scatter_z[8] = {-5, -5, -5, -5, 5, 5, 5, 5};
ImPlot3D::PlotScatter("Cube corners", scatter_x, scatter_y, scatter_z, 8);
ImPlot3D::EndPlot();
}
}
void DemoOffsetAndStride() {
IMGUI_DEMO_MARKER("Plots/Offset and Stride");
static const int k_spirals = 11;
static const int k_points_per = 50;
static const int k_size = 3 * k_points_per * k_spirals;
static double interleaved_data[k_size];
for (int p = 0; p < k_points_per; ++p) {
for (int s = 0; s < k_spirals; ++s) {
double r = (double)s / (k_spirals - 1) * 0.2 + 0.2;
double theta = (double)p / k_points_per * 6.28;
interleaved_data[p * 3 * k_spirals + 3 * s + 0] = 0.5 + r * cos(theta);
interleaved_data[p * 3 * k_spirals + 3 * s + 1] = 0.5 + r * sin(theta);
interleaved_data[p * 3 * k_spirals + 3 * s + 2] = 0.5 + 0.5 * sin(2.0 * theta);
}
}
static int offset = 0;
ImGui::BulletText("Offsetting is useful for realtime plots (see above) and circular buffers.");
ImGui::BulletText("Striding is useful for interleaved data (e.g. audio) or plotting structs.");
ImGui::BulletText("Here, all spiral data is stored in a single interleaved buffer:");
ImGui::BulletText("[s0.x0 s0.y0 s0.z0 ... sn.x0 sn.y0 sn.z0 s0.x1 s0.y1 s0.z1 ... sn.x1 sn.y1 sn.z1 ... sn.xm sn.ym sn.zm]");
ImGui::BulletText("The offset value indicates which spiral point index is considered the first.");
ImGui::BulletText("Offsets can be negative and/or larger than the actual data count.");
ImGui::SliderInt("Offset", &offset, -2 * k_points_per, 2 * k_points_per);
if (ImPlot3D::BeginPlot("##strideoffset", ImVec2(-1, 0))) {
ImPlot3D::PushColormap(ImPlot3DColormap_Jet);
char buff[32];
for (int s = 0; s < k_spirals; ++s) {
snprintf(buff, sizeof(buff), "Spiral %d", s);
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();
}
}
void DemoLegendOptions() {
IMGUI_DEMO_MARKER("Plots/Legend Options");
static ImPlot3DLocation loc = ImPlot3DLocation_East;
ImGui::CheckboxFlags("North", (unsigned int*)&loc, ImPlot3DLocation_North);
ImGui::SameLine();
ImGui::CheckboxFlags("South", (unsigned int*)&loc, ImPlot3DLocation_South);
ImGui::SameLine();
ImGui::CheckboxFlags("West", (unsigned int*)&loc, ImPlot3DLocation_West);
ImGui::SameLine();
ImGui::CheckboxFlags("East", (unsigned int*)&loc, ImPlot3DLocation_East);
static ImPlot3DLegendFlags flags = 0;
CHECKBOX_FLAG(flags, ImPlot3DLegendFlags_Horizontal);
ImGui::SameLine();
ImGui::TextDisabled("(?)");
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Legend entries will be displayed horizontally");
}
CHECKBOX_FLAG(flags, ImPlot3DLegendFlags_NoButtons);
ImGui::SameLine();
ImGui::TextDisabled("(?)");
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Legend icons will not function as hide/show buttons");
}
CHECKBOX_FLAG(flags, ImPlot3DLegendFlags_NoHighlightItem);
ImGui::SameLine();
ImGui::TextDisabled("(?)");
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Plot items will not be highlighted when their legend entry is hovered");
}
ImGui::SliderFloat2("LegendPadding", (float*)&ImPlot3D::GetStyle().LegendPadding, 0.0f, 20.0f, "%.0f");
ImGui::SliderFloat2("LegendInnerPadding", (float*)&ImPlot3D::GetStyle().LegendInnerPadding, 0.0f, 10.0f, "%.0f");
ImGui::SliderFloat2("LegendSpacing", (float*)&ImPlot3D::GetStyle().LegendSpacing, 0.0f, 5.0f, "%.0f");
if (ImPlot3D::BeginPlot("Legend Options Demo", ImVec2(-1, 0))) {
ImPlot3D::SetupAxes("X-Axis", "Y-Axis", "Z-Axis");
ImPlot3D::SetupAxesLimits(-1, 1, -1, 1, -1, 1);
ImPlot3D::SetupLegend(loc, flags);
static float t = 0;
t += ImGui::GetIO().DeltaTime * 0.5f;
constexpr int count = 50;
static float xs1[count], ys1[count], zs1[count];
static float xs2[count], ys2[count], zs2[count];
static float xs3[count], ys3[count], zs3[count];
for (int i = 0; i < count; i++) {
float phase = i * 0.1f + t;
xs1[i] = 0.8f * cosf(phase);
ys1[i] = 0.8f * sinf(phase);
zs1[i] = 0.5f * sinf(phase * 2);
xs2[i] = 0.6f * cosf(phase + 1.0f);
ys2[i] = 0.6f * sinf(phase + 1.0f);
zs2[i] = -0.3f * cosf(phase * 1.5f);
xs3[i] = 0.4f * sinf(phase);
ys3[i] = 0.4f * cosf(phase);
zs3[i] = 0.7f * cosf(phase * 0.8f);
}
ImPlot3D::PlotLine("Helix A", xs1, ys1, zs1, count);
ImPlot3D::PlotLine("Helix B##IDText", xs2, ys2, zs2, count); ImPlot3D::PlotLine("##NotListed", xs3, ys3, zs3, count);
ImPlot3D::EndPlot();
}
}
void DemoMarkersAndText() {
IMGUI_DEMO_MARKER("Plots/Markers and Text");
static float mk_size = ImPlot3D::GetStyle().MarkerSize;
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");
if (ImPlot3D::BeginPlot("##MarkerStyles", ImVec2(-1, 0), ImPlot3DFlags_CanvasOnly)) {
ImPlot3D::SetupAxes(nullptr, nullptr, nullptr, ImPlot3DAxisFlags_NoDecorations, ImPlot3DAxisFlags_NoDecorations,
ImPlot3DAxisFlags_NoDecorations);
ImPlot3D::SetupAxesLimits(-0.5, 1.5, -0.5, 1.5, 0, ImPlot3DMarker_COUNT + 1);
float xs[2] = {0, 0};
float ys[2] = {0, 0};
float zs[2] = {ImPlot3DMarker_COUNT, ImPlot3DMarker_COUNT + 1};
for (int m = 0; m < ImPlot3DMarker_COUNT; ++m) {
xs[1] = xs[0] + ImCos(zs[0] / float(ImPlot3DMarker_COUNT) * 2 * IM_PI) * 0.5f;
ys[1] = ys[0] + ImSin(zs[0] / float(ImPlot3DMarker_COUNT) * 2 * IM_PI) * 0.5f;
ImGui::PushID(m);
ImPlot3D::PlotLine("##Filled", xs, ys, zs, 2,
{ImPlot3DProp_Marker, m, ImPlot3DProp_MarkerSize, mk_size, ImPlot3DProp_LineWeight, mk_weight});
ImGui::PopID();
zs[0]--;
zs[1]--;
}
xs[0] = 1;
ys[0] = 1;
zs[0] = ImPlot3DMarker_COUNT;
zs[1] = zs[0] + 1;
for (int m = 0; m < ImPlot3DMarker_COUNT; ++m) {
xs[1] = xs[0] + ImCos(zs[0] / float(ImPlot3DMarker_COUNT) * 2 * IM_PI) * 0.5f;
ys[1] = ys[0] - ImSin(zs[0] / float(ImPlot3DMarker_COUNT) * 2 * IM_PI) * 0.5f;
ImGui::PushID(m);
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]--;
}
ImPlot3D::PlotText("Filled Markers", 0.0, 0.0, 6.0);
ImPlot3D::PlotText("Open Markers", 1.0, 1.0, 6.0);
ImPlot3D::PushStyleColor(ImPlot3DCol_InlayText, ImVec4(1, 0, 1, 1));
ImPlot3D::PlotText("Rotated Text", 0.5, 0.5, 6.0, IM_PI / 4, ImVec2(0, 0));
ImPlot3D::PopStyleColor();
ImPlot3D::EndPlot();
}
}
void DemoNaNValues() {
IMGUI_DEMO_MARKER("Plots/NaN Values");
static bool include_nan = true;
static ImPlot3DLineFlags flags = 0;
float data1[5] = {0.0f, 0.25f, 0.5f, 0.75f, 1.0f};
float data2[5] = {0.0f, 0.25f, 0.5f, 0.75f, 1.0f};
float data3[5] = {0.0f, 0.25f, 0.5f, 0.75f, 1.0f};
if (include_nan)
data1[2] = NAN;
ImGui::Checkbox("Include NaN", &include_nan);
ImGui::SameLine();
ImGui::CheckboxFlags("Skip NaN", (unsigned int*)&flags, ImPlot3DLineFlags_SkipNaN);
if (ImPlot3D::BeginPlot("##NaNValues")) {
ImPlot3D::PlotLine("Line", data1, data2, data3, 5, {ImPlot3DProp_Flags, flags, ImPlot3DProp_Marker, ImPlot3DMarker_Square});
ImPlot3D::EndPlot();
}
}
void Demo_PerIndexColors() {
IMGUI_DEMO_MARKER("Plots/Per-Index Colors");
static float xs1[1001], ys1[1001], zs1[1001];
static ImU32 colors1[1001];
for (int i = 0; i < 1001; ++i) {
xs1[i] = i * 0.001f;
ys1[i] = 0.5f + 0.5f * sinf(50 * (xs1[i] + (float)ImGui::GetTime() / 10));
zs1[i] = 0.5f + 0.5f * cosf(50 * (xs1[i] + (float)ImGui::GetTime() / 10));
float hue = (float)i / 1000.0f;
colors1[i] = ImColor::HSV(hue, 0.8f, 0.9f);
}
static float xs2[20], ys2[20], zs2[20];
static ImU32 colors2[20];
for (int i = 0; i < 20; ++i) {
xs2[i] = i * 1 / 19.0f;
ys2[i] = xs2[i] * xs2[i];
zs2[i] = xs2[i] * ys2[i];
float t = i / 19.0f;
ImVec4 color = ImPlot3D::SampleColormap(t, ImPlot3DColormap_Viridis);
colors2[i] = ImGui::GetColorU32(color);
}
if (ImPlot3D::BeginPlot("Colorful Lines")) {
ImPlot3D::PlotLine("f(x)", xs1, ys1, zs1, 1001, {ImPlot3DProp_LineColors, colors1});
ImPlot3D::PlotLine("g(x)", xs2, ys2, zs2, 20,
{ImPlot3DProp_Marker, ImPlot3DMarker_Circle, ImPlot3DProp_Flags, (int)ImPlot3DLineFlags_Segments, ImPlot3DProp_LineColors,
colors2, ImPlot3DProp_MarkerFillColors, colors2, ImPlot3DProp_MarkerLineColors, colors2});
ImPlot3D::EndPlot();
}
srand(0);
static float xs_scatter1[100], ys_scatter1[100], zs_scatter1[100];
static ImU32 colors_scatter1_fill[100], colors_scatter1_line[100];
static float sizes_scatter1[100];
for (int i = 0; i < 100; ++i) {
xs_scatter1[i] = i * 0.01f;
ys_scatter1[i] = xs_scatter1[i] + 0.1f * ((float)rand() / (float)RAND_MAX);
zs_scatter1[i] = xs_scatter1[i] + 0.1f * ((float)rand() / (float)RAND_MAX);
float hue = i / 99.0f;
colors_scatter1_fill[i] = ImColor::HSV(hue, 0.8f, 0.9f);
colors_scatter1_line[i] = ImColor::HSV(hue, 0.9f, 0.7f);
sizes_scatter1[i] = 2.0f + 4.0f * ((float)rand() / (float)RAND_MAX);
}
static float xs_scatter2[50], ys_scatter2[50], zs_scatter2[50];
static ImU32 colors_scatter2[50];
static float sizes_scatter2[50];
for (int i = 0; i < 50; ++i) {
xs_scatter2[i] = 0.25f + 0.2f * ((float)rand() / (float)RAND_MAX);
ys_scatter2[i] = 0.50f + 0.2f * ((float)rand() / (float)RAND_MAX);
zs_scatter2[i] = 0.75f + 0.2f * ((float)rand() / (float)RAND_MAX);
float t = i / 49.0f;
ImVec4 color = ImPlot3D::SampleColormap(t, ImPlot3DColormap_Viridis);
colors_scatter2[i] = ImGui::GetColorU32(color);
sizes_scatter2[i] = 2.0f + 4.0f * ((float)rand() / (float)RAND_MAX);
}
if (ImPlot3D::BeginPlot("Colorful Scatter")) {
ImPlot3D::PlotScatter("Data 1", xs_scatter1, ys_scatter1, zs_scatter1, 100,
{ImPlot3DProp_MarkerFillColors, colors_scatter1_fill, ImPlot3DProp_MarkerLineColors, colors_scatter1_line,
ImPlot3DProp_MarkerSizes, sizes_scatter1});
ImPlot3D::PlotScatter("Data 2", xs_scatter2, ys_scatter2, zs_scatter2, 50,
{ImPlot3DProp_Marker, ImPlot3DMarker_Square, ImPlot3DProp_MarkerFillColors, colors_scatter2,
ImPlot3DProp_MarkerLineColors, colors_scatter2, ImPlot3DProp_MarkerSizes, sizes_scatter2, ImPlot3DProp_FillAlpha,
0.5f});
ImPlot3D::EndPlot();
}
static float xs_tri[18], ys_tri[18], zs_tri[18];
static ImU32 colors_tri[18];
{
float ax = 0.0f, ay = 0.0f, az = 1.0f;
float cx[4] = {-0.5f, 0.5f, 0.5f, -0.5f};
float cy[4] = {-0.5f, -0.5f, 0.5f, 0.5f};
float cz[4] = {0.0f, 0.0f, 0.0f, 0.0f};
int v = 0;
auto AddVertex = [&](float x, float y, float z) {
xs_tri[v] = x;
ys_tri[v] = y;
zs_tri[v] = z;
v++;
};
AddVertex(ax, ay, az);
AddVertex(cx[0], cy[0], cz[0]);
AddVertex(cx[1], cy[1], cz[1]);
AddVertex(ax, ay, az);
AddVertex(cx[1], cy[1], cz[1]);
AddVertex(cx[2], cy[2], cz[2]);
AddVertex(ax, ay, az);
AddVertex(cx[2], cy[2], cz[2]);
AddVertex(cx[3], cy[3], cz[3]);
AddVertex(ax, ay, az);
AddVertex(cx[3], cy[3], cz[3]);
AddVertex(cx[0], cy[0], cz[0]);
AddVertex(cx[0], cy[0], cz[0]);
AddVertex(cx[1], cy[1], cz[1]);
AddVertex(cx[2], cy[2], cz[2]);
AddVertex(cx[0], cy[0], cz[0]);
AddVertex(cx[2], cy[2], cz[2]);
AddVertex(cx[3], cy[3], cz[3]);
for (int i = 0; i < 18; ++i) {
ImVec4 color = ImPlot3D::SampleColormap(0.5f * zs_tri[i], ImPlot3DColormap_Hot);
colors_tri[i] = ImGui::GetColorU32(color);
}
}
if (ImPlot3D::BeginPlot("Colorful Triangles")) {
ImPlot3D::SetupAxesLimits(-1, 1, -1, 1, -0.5, 1.5);
ImPlot3D::PlotTriangle("Pyramid", xs_tri, ys_tri, zs_tri, 18, {ImPlot3DProp_FillColors, colors_tri, ImPlot3DProp_FillAlpha, 0.8f});
ImPlot3D::EndPlot();
}
static float xs_quad[24], ys_quad[24], zs_quad[24];
static ImU32 colors_quad[24];
{
xs_quad[0]=1; ys_quad[0]=0; zs_quad[0]=0; xs_quad[1]=1; ys_quad[1]=1; zs_quad[1]=0; xs_quad[2]=1; ys_quad[2]=1; zs_quad[2]=1; xs_quad[3]=1; ys_quad[3]=0; zs_quad[3]=1;
xs_quad[4]=0; ys_quad[4]=0; zs_quad[4]=0; xs_quad[5]=0; ys_quad[5]=1; zs_quad[5]=0; xs_quad[6]=0; ys_quad[6]=1; zs_quad[6]=1; xs_quad[7]=0; ys_quad[7]=0; zs_quad[7]=1;
xs_quad[8]=0; ys_quad[8]=1; zs_quad[8]=0; xs_quad[9]=1; ys_quad[9]=1; zs_quad[9]=0; xs_quad[10]=1; ys_quad[10]=1; zs_quad[10]=1; xs_quad[11]=0; ys_quad[11]=1; zs_quad[11]=1;
xs_quad[12]=0; ys_quad[12]=0; zs_quad[12]=0; xs_quad[13]=1; ys_quad[13]=0; zs_quad[13]=0; xs_quad[14]=1; ys_quad[14]=0; zs_quad[14]=1; xs_quad[15]=0; ys_quad[15]=0; zs_quad[15]=1;
xs_quad[16]=0; ys_quad[16]=0; zs_quad[16]=1; xs_quad[17]=1; ys_quad[17]=0; zs_quad[17]=1; xs_quad[18]=1; ys_quad[18]=1; zs_quad[18]=1; xs_quad[19]=0; ys_quad[19]=1; zs_quad[19]=1;
xs_quad[20]=0; ys_quad[20]=0; zs_quad[20]=0; xs_quad[21]=1; ys_quad[21]=0; zs_quad[21]=0; xs_quad[22]=1; ys_quad[22]=1; zs_quad[22]=0; xs_quad[23]=0; ys_quad[23]=1; zs_quad[23]=0;
for (int i = 0; i < 24; ++i)
colors_quad[i] = IM_COL32((ImU8)(xs_quad[i] * 255), (ImU8)(ys_quad[i] * 255), (ImU8)(zs_quad[i] * 255), 255);
}
if (ImPlot3D::BeginPlot("Colorful Quads")) {
ImPlot3D::SetupAxesLimits(-0.5, 1.5, -0.5, 1.5, -0.5, 1.5);
ImPlot3D::PlotQuad("Cube", xs_quad, ys_quad, zs_quad, 24, {ImPlot3DProp_FillColors, colors_quad, ImPlot3DProp_FillAlpha, 0.8f});
ImPlot3D::EndPlot();
}
static ImU32 duck_fill_colors[DUCK_IDX_COUNT];
static bool duck_colors_built = false;
if (!duck_colors_built) {
struct Vec3 {
float x, y, z;
};
auto sub3 = [](Vec3 a, Vec3 b) -> Vec3 { return {a.x - b.x, a.y - b.y, a.z - b.z}; };
auto add3 = [](Vec3 a, Vec3 b) -> Vec3 { return {a.x + b.x, a.y + b.y, a.z + b.z}; };
auto cross3 = [](Vec3 a, Vec3 b) -> Vec3 { return {a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x}; };
auto dot3 = [](Vec3 a, Vec3 b) { return a.x * b.x + a.y * b.y + a.z * b.z; };
auto norm3 = [&dot3](Vec3 a) -> Vec3 {
float len = sqrtf(dot3(a, a));
return len > 1e-8f ? Vec3{a.x / len, a.y / len, a.z / len} : Vec3{0, 0, 1};
};
Vec3 vtx_normals[DUCK_VTX_COUNT] = {};
for (int i = 0; i < DUCK_IDX_COUNT; i += 3) {
unsigned int i0 = duck_idx[i], i1 = duck_idx[i + 1], i2 = duck_idx[i + 2];
Vec3 p0 = {(float)duck_vtx[i0].x, (float)duck_vtx[i0].y, (float)duck_vtx[i0].z};
Vec3 p1 = {(float)duck_vtx[i1].x, (float)duck_vtx[i1].y, (float)duck_vtx[i1].z};
Vec3 p2 = {(float)duck_vtx[i2].x, (float)duck_vtx[i2].y, (float)duck_vtx[i2].z};
Vec3 fn = cross3(sub3(p1, p0), sub3(p2, p0)); vtx_normals[i0] = add3(vtx_normals[i0], fn);
vtx_normals[i1] = add3(vtx_normals[i1], fn);
vtx_normals[i2] = add3(vtx_normals[i2], fn);
}
for (int v = 0; v < DUCK_VTX_COUNT; v++)
vtx_normals[v] = norm3(vtx_normals[v]);
Vec3 light_pos = {2.0f, 2.0f, 3.0f};
Vec3 duck_col = {1.0f, 0.85f, 0.1f}; Vec3 light_col = {1.0f, 0.95f, 0.8f}; Vec3 ambient = {0.15f, 0.12f, 0.03f};
ImU32 vtx_colors[DUCK_VTX_COUNT];
for (int v = 0; v < DUCK_VTX_COUNT; v++) {
Vec3 pos = {(float)duck_vtx[v].x, (float)duck_vtx[v].y, (float)duck_vtx[v].z};
Vec3 to_light = norm3(sub3(light_pos, pos));
float diff = ImMax(0.0f, dot3(vtx_normals[v], to_light));
float r = ImMin(1.0f, ambient.x + duck_col.x * light_col.x * diff);
float g = ImMin(1.0f, ambient.y + duck_col.y * light_col.y * diff);
float b = ImMin(1.0f, ambient.z + duck_col.z * light_col.z * diff);
vtx_colors[v] = IM_COL32((ImU8)(r * 255), (ImU8)(g * 255), (ImU8)(b * 255), 255);
}
for (int i = 0; i < DUCK_IDX_COUNT; i++)
duck_fill_colors[i] = vtx_colors[duck_idx[i]];
duck_colors_built = true;
}
if (ImPlot3D::BeginPlot("Gouraud Duck")) {
ImPlot3D::SetupAxesLimits(-1, 1, -1, 1, -1, 1);
ImPlot3D::PlotMesh("Duck", &duck_vtx[0].x, &duck_vtx[0].y, &duck_vtx[0].z, duck_idx, DUCK_VTX_COUNT, DUCK_IDX_COUNT,
{ImPlot3DProp_Stride, (int)sizeof(ImPlot3DPoint), ImPlot3DProp_FillColors, duck_fill_colors, ImPlot3DProp_Flags,
(int)ImPlot3DMeshFlags_NoLines});
ImPlot3D::EndPlot();
}
}
void DemoBoxScale() {
IMGUI_DEMO_MARKER("Axes/Box Scale");
constexpr int N = 100;
float xs[N], ys[N], zs[N];
for (int i = 0; i < N; i++) {
float t = i / (float)(N - 1);
xs[i] = sinf(t * 2.0f * IM_PI);
ys[i] = cosf(t * 4.0f * IM_PI);
zs[i] = t * 2.0f - 1.0f;
}
static float scale[3] = {1.0f, 1.0f, 1.0f};
ImGui::SliderFloat3("Box Scale", scale, 0.1f, 2.0f, "%.2f");
if (ImPlot3D::BeginPlot("##BoxScale")) {
ImPlot3D::SetupBoxScale(scale[0], scale[1], scale[2]);
ImPlot3D::PlotLine("3D Curve", xs, ys, zs, N);
ImPlot3D::EndPlot();
}
}
void DemoBoxRotation() {
IMGUI_DEMO_MARKER("Axes/Box Rotation");
double origin[2] = {0.0, 0.0};
double axis[2] = {0.0, 1.0};
static float elevation = 45.0f;
static float azimuth = -135.0f;
static bool animate = false;
ImGui::Text("Rotation");
bool changed = false;
if (ImGui::SliderFloat("Elevation", &elevation, -90.0f, 90.0f, "%.1f degrees"))
changed = true;
if (ImGui::SliderFloat("Azimuth", &azimuth, -180.0f, 180.0f, "%.1f degrees"))
changed = true;
ImGui::Checkbox("Animate", &animate);
ImGui::Text("Initial Rotation");
ImGui::SameLine();
HelpMarker("The rotation will be reset to the initial rotation when you double right-click");
static float init_elevation = 45.0f;
static float init_azimuth = -135.0f;
ImGui::SliderFloat("Initial Elevation", &init_elevation, -90.0f, 90.0f, "%.1f degrees");
ImGui::SliderFloat("Initial Azimuth", &init_azimuth, -180.0f, 180.0f, "%.1f degrees");
if (ImPlot3D::BeginPlot("##BoxRotation")) {
ImPlot3D::SetupAxesLimits(-1, 1, -1, 1, -1, 1, ImPlot3DCond_Always);
ImPlot3D::SetupBoxInitialRotation(init_elevation, init_azimuth);
if (changed)
ImPlot3D::SetupBoxRotation(elevation, azimuth, animate, ImPlot3DCond_Always);
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();
}
}
void Demo_LogScale() {
IMGUI_DEMO_MARKER("Axes/Log Scale");
static double xs[1001], ys1[1001], ys2[1001], ys3[1001], zs[1001];
for (int i = 0; i < 1001; i++) {
xs[i] = i * 0.1;
ys1[i] = sin(xs[i]) + 1;
ys2[i] = log(xs[i]);
ys3[i] = pow(10.0, xs[i]);
zs[i] = 0.0;
}
if (ImPlot3D::BeginPlot("Log Plot 3D", ImVec2(-1, 0))) {
ImPlot3D::SetupAxisScale(ImAxis3D_X, ImPlot3DScale_Log10);
ImPlot3D::SetupAxesLimits(0.1, 100, 0, 10, -1, 1);
ImPlot3D::PlotLine("f(x) = x", xs, xs, zs, 1001);
ImPlot3D::PlotLine("f(x) = sin(x)+1", xs, ys1, zs, 1001);
ImPlot3D::PlotLine("f(x) = log(x)", xs, ys2, zs, 1001);
ImPlot3D::PlotLine("f(x) = 10^x", xs, ys3, zs, 21);
ImPlot3D::EndPlot();
}
}
void Demo_SymmetricLogScale() {
IMGUI_DEMO_MARKER("Axes/Symmetric Log Scale");
static double xs[1001], ys1[1001], ys2[1001], zs[1001];
for (int i = 0; i < 1001; i++) {
xs[i] = i * 0.1f - 50;
ys1[i] = sin(xs[i]);
ys2[i] = i * 0.002 - 1;
zs[i] = 0.0;
}
if (ImPlot3D::BeginPlot("SymLog Plot", ImVec2(-1, 0))) {
ImPlot3D::SetupAxisScale(ImAxis3D_X, ImPlot3DScale_SymLog);
ImPlot3D::PlotLine("f(x) = a*x+b", xs, ys2, zs, 1001);
ImPlot3D::PlotLine("f(x) = sin(x)", xs, ys1, zs, 1001);
ImPlot3D::EndPlot();
}
}
void DemoTickLabels() {
IMGUI_DEMO_MARKER("Axes/Tick Labels");
static bool custom_fmt = true;
static bool custom_ticks = false;
static bool custom_labels = true;
ImGui::Checkbox("Show Custom Format", &custom_fmt);
ImGui::SameLine();
ImGui::Checkbox("Show Custom Ticks", &custom_ticks);
if (custom_ticks) {
ImGui::SameLine();
ImGui::Checkbox("Show Custom Labels", &custom_labels);
}
const double pi = 3.14;
const char* pi_str[] = {"PI"};
static double letters_ticks[] = {0.0, 0.2, 0.4, 0.6, 0.8, 1.0};
static const char* letters_labels[] = {"A", "B", "C", "D", "E", "F"};
if (ImPlot3D::BeginPlot("##Ticks")) {
ImPlot3D::SetupAxesLimits(2, 5, 0, 1, 0, 1000);
if (custom_fmt) {
ImPlot3D::SetupAxisFormat(ImAxis3D_Y, MetricFormatter, (void*)"Hz");
ImPlot3D::SetupAxisFormat(ImAxis3D_Z, MetricFormatter, (void*)"m");
}
if (custom_ticks) {
ImPlot3D::SetupAxisTicks(ImAxis3D_X, &pi, 1, custom_labels ? pi_str : nullptr, true);
ImPlot3D::SetupAxisTicks(ImAxis3D_Y, letters_ticks, 6, custom_labels ? letters_labels : nullptr, false);
ImPlot3D::SetupAxisTicks(ImAxis3D_Z, 0, 1000, 6, custom_labels ? letters_labels : nullptr, false);
}
ImPlot3D::EndPlot();
}
}
void DemoAxisConstraints() {
IMGUI_DEMO_MARKER("Axes/Axis Constraints");
static float limit_constraints[2] = {-10, 10};
static float zoom_constraints[2] = {1, 20};
static ImPlot3DAxisFlags flags;
ImGui::DragFloat2("Limits Constraints", limit_constraints, 0.01f);
ImGui::DragFloat2("Zoom Constraints", zoom_constraints, 0.01f);
CHECKBOX_FLAG(flags, ImPlot3DAxisFlags_PanStretch);
if (ImPlot3D::BeginPlot("##AxisConstraints", ImVec2(-1, 0))) {
ImPlot3D::SetupAxes("X", "Y", "Z", flags, flags, flags);
ImPlot3D::SetupAxesLimits(-1, 1, -1, 1, -1, 1);
ImPlot3D::SetupAxisLimitsConstraints(ImAxis3D_X, (double)limit_constraints[0], (double)limit_constraints[1]);
ImPlot3D::SetupAxisLimitsConstraints(ImAxis3D_Y, (double)limit_constraints[0], (double)limit_constraints[1]);
ImPlot3D::SetupAxisLimitsConstraints(ImAxis3D_Z, (double)limit_constraints[0], (double)limit_constraints[1]);
ImPlot3D::SetupAxisZoomConstraints(ImAxis3D_X, (double)zoom_constraints[0], (double)zoom_constraints[1]);
ImPlot3D::SetupAxisZoomConstraints(ImAxis3D_Y, (double)zoom_constraints[0], (double)zoom_constraints[1]);
ImPlot3D::SetupAxisZoomConstraints(ImAxis3D_Z, (double)zoom_constraints[0], (double)zoom_constraints[1]);
ImPlot3D::EndPlot();
}
}
void DemoEqualAxes() {
IMGUI_DEMO_MARKER("Axes/Equal Axes");
ImGui::BulletText("Equal constraint applies to all three axes (X, Y, Z)");
ImGui::BulletText("When enabled, the axes maintain the same units/pixel ratio");
static double circle_xs[360], circle_ys[360], circle_zs[360];
static double helix_xs[360], helix_ys[360], helix_zs[360];
float square_xs[] = {-0.5f, 0.5f, 0.5f, -0.5f, -0.5f};
float square_ys[] = {-0.5f, -0.5f, 0.5f, 0.5f, -0.5f};
float square_zs[] = {-0.5f, -0.5f, -0.5f, -0.5f, -0.5f};
static bool initialized = false;
if (!initialized) {
for (int i = 0; i < 360; ++i) {
double angle = i * 2 * IM_PI / 359.0;
circle_xs[i] = cos(angle);
circle_ys[i] = sin(angle);
circle_zs[i] = 0;
helix_xs[i] = 0.5 * cos(angle);
helix_ys[i] = 0.5 * sin(angle);
helix_zs[i] = (double)i / 359.0 * 2.0 - 1.0;
}
initialized = true;
}
static ImPlot3DFlags flags = ImPlot3DFlags_Equal;
CHECKBOX_FLAG(flags, ImPlot3DFlags_Equal);
if (ImPlot3D::BeginPlot("##EqualAxes", ImVec2(-1, 0), flags)) {
ImPlot3D::SetupAxes("X-Axis", "Y-Axis", "Z-Axis");
ImPlot3D::PlotLine("Circle", circle_xs, circle_ys, circle_zs, 360);
ImPlot3D::PlotLine("Helix", helix_xs, helix_ys, helix_zs, 360);
ImPlot3D::PlotLine("Square", square_xs, square_ys, square_zs, 5);
ImPlot3D::EndPlot();
}
}
void DemoAutoFittingData() {
IMGUI_DEMO_MARKER("Axes/Auto-Fitting Data");
ImGui::BulletText("Axes can be configured to auto-fit to data extents.");
ImGui::BulletText("Try panning and zooming to see the axes adjust.");
ImGui::BulletText("Disable AutoFit on an axis to fix its range.");
static ImPlot3DAxisFlags xflags = ImPlot3DAxisFlags_None;
static ImPlot3DAxisFlags yflags = ImPlot3DAxisFlags_None;
static ImPlot3DAxisFlags zflags = ImPlot3DAxisFlags_AutoFit;
ImGui::TextUnformatted("X: ");
ImGui::SameLine();
ImGui::CheckboxFlags("ImPlot3DAxisFlags_AutoFit##X", (unsigned int*)&xflags, ImPlot3DAxisFlags_AutoFit);
ImGui::TextUnformatted("Y: ");
ImGui::SameLine();
ImGui::CheckboxFlags("ImPlot3DAxisFlags_AutoFit##Y", (unsigned int*)&yflags, ImPlot3DAxisFlags_AutoFit);
ImGui::TextUnformatted("Z: ");
ImGui::SameLine();
ImGui::CheckboxFlags("ImPlot3DAxisFlags_AutoFit##Z", (unsigned int*)&zflags, ImPlot3DAxisFlags_AutoFit);
static double data_x[101], data_y[101], data_z[101];
static bool initialized = false;
if (!initialized) {
srand(0);
for (int i = 0; i < 101; ++i) {
data_x[i] = i * 0.1;
data_y[i] = i * 0.1;
data_z[i] = 1 + sin(i / 10.0);
}
initialized = true;
}
if (ImPlot3D::BeginPlot("##AutoFitting")) {
ImPlot3D::SetupAxes("X-Axis", "Y-Axis", "Z-Axis", xflags, yflags, zflags);
ImPlot3D::PlotLine("Wave", data_x, data_y, data_z, 101);
ImPlot3D::EndPlot();
}
}
void DemoMousePicking() {
IMGUI_DEMO_MARKER("Tools/Mouse Picking");
static ImVector<ImPlot3DPoint> points;
static ImVector<ImPlot3DRay> rays;
ImGui::BulletText("Click anywhere in the plot to place points/rays.");
static int selected_plane = ImPlane3D_XY;
ImGui::RadioButton("XY-Plane", &selected_plane, ImPlane3D_XY);
ImGui::SameLine();
ImGui::RadioButton("XZ-Plane", &selected_plane, ImPlane3D_XZ);
ImGui::SameLine();
ImGui::RadioButton("YZ-Plane", &selected_plane, ImPlane3D_YZ);
static bool mask_plane = true;
ImGui::Checkbox("Mask Plane", &mask_plane);
if (ImGui::Button("Clear")) {
points.clear();
rays.clear();
}
if (ImPlot3D::BeginPlot("Mouse Picking", ImVec2(-1, 0), ImPlot3DFlags_NoClip)) {
ImPlot3D::SetupAxes("X-Axis", "Y-Axis", "Z-Axis");
ImPlot3D::SetupAxesLimits(-1, 1, -1, 1, -1, 1);
ImVec2 mouse_pos = ImGui::GetMousePos();
ImPlot3DRay ray = ImPlot3D::PixelsToPlotRay(mouse_pos);
ImPlane3D plane = (ImPlane3D)selected_plane;
ImPlot3DPoint point = ImPlot3D::PixelsToPlotPlane(mouse_pos, plane, mask_plane);
if (ImGui::IsItemHovered() && !point.IsNaN()) {
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);
}
if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(0) && !point.IsNaN()) {
points.push_back(point);
rays.push_back(ray);
}
if (!points.empty()) {
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);
}
if (!rays.empty()) {
ImVector<ImPlot3DPoint> ray_points;
ray_points.reserve(rays.Size * 2);
for (int i = 0; i < rays.Size; i++) {
ImPlot3DPoint p1 = points[i];
ImPlot3DPoint p2 = points[i] - rays[i].Direction; ray_points.push_back(p1);
ray_points.push_back(p2);
}
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();
}
}
void DemoCustomStyles() {
IMGUI_DEMO_MARKER("Custom/Custom Styles");
ImPlot3D::PushColormap(ImPlot3DColormap_Deep);
ImPlot3DStyle backup = ImPlot3D::GetStyle();
MyImPlot3D::StyleSeaborn();
if (ImPlot3D::BeginPlot("Seaborn Style")) {
ImPlot3D::SetupAxes("X-axis", "Y-axis", "Z-axis");
ImPlot3D::SetupAxesLimits(-0.5, 9.5, -0.5, 0.5, 0, 10);
unsigned int xs[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
unsigned int ys[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
unsigned int lin[10] = {8, 8, 9, 7, 8, 8, 8, 9, 7, 8};
unsigned int dot[10] = {7, 6, 6, 7, 8, 5, 6, 5, 8, 7};
ImPlot3D::NextColormapColor(); ImPlot3D::PlotLine("Line", xs, ys, lin, 10);
ImPlot3D::NextColormapColor(); ImPlot3D::PlotScatter("Scatter", xs, ys, dot, 10);
ImPlot3D::EndPlot();
}
ImPlot3D::GetStyle() = backup;
ImPlot3D::PopColormap();
}
void DemoCustomRendering() {
IMGUI_DEMO_MARKER("Custom/Custom Rendering");
if (ImPlot3D::BeginPlot("##CustomRend")) {
ImPlot3D::SetupAxesLimits(-0.1, 1.1, -0.1, 1.1, -0.1, 1.1);
ImVec2 cntr = ImPlot3D::PlotToPixels(ImPlot3DPoint(0.5, 0.5, 0.5));
ImPlot3D::GetPlotDrawList()->AddCircleFilled(cntr, 20, IM_COL32(255, 255, 0, 255), 20);
ImPlot3DPoint corners[8] = {
ImPlot3DPoint(0, 0, 0), ImPlot3DPoint(1, 0, 0), ImPlot3DPoint(1, 1, 0), ImPlot3DPoint(0, 1, 0),
ImPlot3DPoint(0, 0, 1), ImPlot3DPoint(1, 0, 1), ImPlot3DPoint(1, 1, 1), ImPlot3DPoint(0, 1, 1),
};
ImVec2 corners_px[8];
for (int i = 0; i < 8; i++)
corners_px[i] = ImPlot3D::PlotToPixels(corners[i]);
ImU32 col = IM_COL32(128, 0, 255, 255);
for (int i = 0; i < 4; i++) {
ImPlot3D::GetPlotDrawList()->AddLine(corners_px[i], corners_px[(i + 1) % 4], col);
ImPlot3D::GetPlotDrawList()->AddLine(corners_px[i + 4], corners_px[(i + 1) % 4 + 4], col);
ImPlot3D::GetPlotDrawList()->AddLine(corners_px[i], corners_px[i + 4], col);
}
ImPlot3D::EndPlot();
}
}
void DemoCustomOverlay() {
IMGUI_DEMO_MARKER("Custom/Custom Overlay");
ImGui::BulletText("Demonstrates custom 2D overlays using GetPlotRectPos/GetPlotRectSize.");
ImGui::BulletText("Shows mouse tooltip, line to closest point, and orientation gizmo.");
static float xs[50], ys[50], zs[50];
static bool initialized = false;
if (!initialized) {
srand(0);
for (int i = 0; i < 50; i++) {
xs[i] = (float)rand() / (float)RAND_MAX;
ys[i] = (float)rand() / (float)RAND_MAX;
zs[i] = (float)rand() / (float)RAND_MAX;
}
initialized = true;
}
if (ImPlot3D::BeginPlot("##CustomOverlay", ImVec2(-1, 0))) {
ImPlot3D::SetupAxes("X-Axis", "Y-Axis", "Z-Axis");
ImPlot3D::SetupAxesLimits(0, 1, 0, 1, 0, 1);
ImPlot3D::PlotScatter("Data", xs, ys, zs, 50);
ImDrawList* draw_list = ImPlot3D::GetPlotDrawList();
ImVec2 mouse_pos = ImGui::GetMousePos();
ImVec2 plot_pos = ImPlot3D::GetPlotRectPos();
ImVec2 plot_size = ImPlot3D::GetPlotRectSize();
bool is_hovered = ImGui::IsItemHovered();
if (is_hovered) {
int closest_idx = -1;
float min_dist_sq = 1e10f; ImVec2 closest_px;
for (int i = 0; i < 50; i++) {
ImVec2 point_px = ImPlot3D::PlotToPixels(xs[i], ys[i], zs[i]);
float dx = point_px.x - mouse_pos.x;
float dy = point_px.y - mouse_pos.y;
float dist_sq = dx * dx + dy * dy;
if (dist_sq < min_dist_sq) {
min_dist_sq = dist_sq;
closest_idx = i;
closest_px = point_px;
}
}
if (closest_idx >= 0) {
draw_list->AddLine(mouse_pos, closest_px, IM_COL32(255, 255, 0, 255), 2.0f);
ImGui::BeginTooltip();
ImGui::Text("Mouse: (%.1f, %.1f)", mouse_pos.x, mouse_pos.y);
ImGui::Text("Closest Point #%d", closest_idx);
ImGui::Text("Position: (%.3f, %.3f, %.3f)", xs[closest_idx], ys[closest_idx], zs[closest_idx]);
ImGui::Text("Distance: %.1f px", ImSqrt(min_dist_sq));
ImGui::EndTooltip();
}
}
ImPlot3DContext& gp = *GImPlot3D;
ImPlot3DPlot* plot = gp.CurrentPlot;
if (plot) {
ImVec2 gizmo_center = ImVec2(plot_pos.x + plot_size.x - 50, plot_pos.y + plot_size.y - 50);
float gizmo_size = 30.0f;
ImPlot3DQuat rot = plot->Rotation;
ImPlot3DPoint axes[3] = {
ImPlot3DPoint(1, 0, 0), ImPlot3DPoint(0, 1, 0), ImPlot3DPoint(0, 0, 1) };
ImU32 colors[3] = {
IM_COL32(200, 50, 50, 255), IM_COL32(50, 200, 50, 255), IM_COL32(50, 50, 200, 255) };
const char* labels[3] = {"X", "Y", "Z"};
draw_list->AddCircleFilled(gizmo_center, gizmo_size + 5, IM_COL32(0, 0, 0, 100));
for (int i = 0; i < 3; i++) {
ImPlot3DPoint rotated = rot * axes[i];
ImVec2 axis_end = ImVec2(gizmo_center.x + float(rotated.x) * gizmo_size,
gizmo_center.y - float(rotated.y) * gizmo_size );
draw_list->AddLine(gizmo_center, axis_end, colors[i], 2.0f);
draw_list->AddCircleFilled(axis_end, 4.0f, colors[i]);
ImVec2 label_pos = ImVec2(axis_end.x + 8, axis_end.y - 8);
draw_list->AddText(label_pos, colors[i], labels[i]);
}
}
ImPlot3D::EndPlot();
}
}
void DemoCustomPerPointStyle() {
IMGUI_DEMO_MARKER("Custom/Custom Per-Point Style");
ImGui::BulletText("Demonstrates per-point coloring using colormap sampling.");
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;
static ImPlot3DColormap cmap = ImPlot3DColormap_Viridis;
ImGui::SliderFloat("Marker Size", &marker_size, 2.0f, 10.0f);
if (ImGui::BeginCombo("Colormap", ImPlot3D::GetColormapName(cmap))) {
ImPlot3DContext& gp = *GImPlot3D;
for (int i = 0; i < ImPlot3D::GetColormapCount(); i++) {
if (!gp.ColormapData.IsQual(i)) {
if (ImGui::Selectable(ImPlot3D::GetColormapName(i), cmap == i))
cmap = i;
}
}
ImGui::EndCombo();
}
static float torus_data[3][400][4]; static bool initialized = false;
if (!initialized) {
const float R = 0.6f; const float r = 0.2f; const int u_samples = 20;
const int v_samples = 20;
for (int torus = 0; torus < 3; torus++) {
float z_offset = (2 - torus) * 0.6f;
int idx = 0;
for (int i = 0; i < u_samples; i++) {
float u = (float)i / u_samples * 2.0f * IM_PI;
for (int j = 0; j < v_samples; j++) {
float v = (float)j / v_samples * 2.0f * IM_PI;
float x = (R + r * ImCos(v)) * ImCos(u);
float y = (R + r * ImCos(v)) * ImSin(u);
float z = r * ImSin(v) + z_offset;
float t;
if (torus == 0) {
t = (z - (z_offset - r)) / (2.0f * r);
} else if (torus == 1) {
t = (ImCos(v) + 1.0f) / 2.0f;
} else {
t = (ImCos(u) + 1.0f) / 2.0f; }
torus_data[torus][idx][0] = x;
torus_data[torus][idx][1] = y;
torus_data[torus][idx][2] = z;
torus_data[torus][idx][3] = t;
idx++;
}
}
}
initialized = true;
}
static float xs[3][400], ys[3][400], zs[3][400];
ImU32 point_colors[3][400];
for (int torus = 0; torus < 3; torus++) {
for (int i = 0; i < 400; i++) {
xs[torus][i] = torus_data[torus][i][0];
ys[torus][i] = torus_data[torus][i][1];
zs[torus][i] = torus_data[torus][i][2];
point_colors[torus][i] = ImGui::ColorConvertFloat4ToU32(ImPlot3D::SampleColormap(torus_data[torus][i][3], cmap));
}
}
if (ImPlot3D::BeginPlot("##PerPointStyle", ImVec2(-1, 0))) {
ImPlot3D::SetupAxes("X", "Y", "Z");
ImPlot3D::SetupAxesLimits(-1, 1, -1, 1, -0.5, 1.5);
const char* labels[3] = {"Height-colored", "Radial-colored", "Angular-colored"};
const ImVec4 legend_colors[3] = {
ImVec4(1.0f, 0.0f, 0.0f, 1.0f), ImVec4(0.0f, 1.0f, 0.0f, 1.0f), ImVec4(0.0f, 0.0f, 1.0f, 1.0f) };
ImPlot3DSpec spec;
spec.Marker = ImPlot3DMarker_Circle;
spec.MarkerSize = marker_size;
for (int torus = 0; torus < 3; torus++) {
spec.MarkerFillColors = point_colors[torus];
spec.MarkerLineColors = point_colors[torus];
ImPlot3D::PlotScatter(labels[torus], xs[torus], ys[torus], zs[torus], 400, spec);
spec.MarkerFillColors = nullptr;
spec.MarkerLineColors = nullptr;
spec.MarkerFillColor = legend_colors[torus];
spec.MarkerLineColor = legend_colors[torus];
ImPlot3D::PlotDummy(labels[torus], spec);
}
ImPlot3D::EndPlot();
}
}
void DemoConfig() {
IMGUI_DEMO_MARKER("Config");
ImGui::ShowFontSelector("Font");
ImGui::ShowStyleSelector("ImGui Style");
ImPlot3D::ShowStyleSelector("ImPlot3D Style");
ImPlot3D::ShowColormapSelector("ImPlot3D Colormap");
ImGui::Separator();
if (ImPlot3D::BeginPlot("Preview", ImVec2(-1, 0))) {
static float xs[10][50], ys[10][50], zs[10][50];
static bool initialized = false;
if (!initialized) {
for (int i = 0; i < 10; ++i) {
for (int j = 0; j < 50; ++j) {
float t = j / 49.0f;
float angle = t * 4.0f * IM_PI;
float radius = 0.3f + i * 0.05f;
xs[i][j] = radius * ImCos(angle);
ys[i][j] = radius * ImSin(angle);
zs[i][j] = i / 9.0f;
}
}
initialized = true;
}
for (int i = 0; i < 10; ++i) {
ImGui::PushID(i);
ImPlot3D::PlotLine("##Spiral", xs[i], ys[i], zs[i], 50);
ImGui::PopID();
}
ImPlot3D::EndPlot();
}
}
void DemoHelp() {
IMGUI_DEMO_MARKER("Help");
ImGui::SeparatorText("ABOUT THIS DEMO:");
ImGui::BulletText("The other tabs are demonstrating many aspects of the library.");
ImGui::SeparatorText("PROGRAMMER GUIDE:");
ImGui::BulletText("See the ShowDemoWindow() code in implot3d_demo.cpp. <- you are here!");
ImGui::BulletText("See comments in implot3d_demo.cpp.");
ImGui::BulletText("See example application in example/ folder.");
ImGui::SeparatorText("USER GUIDE:");
ImGui::BulletText("Translation");
{
ImGui::Indent();
ImGui::BulletText("Left-click drag to translate.");
ImGui::BulletText("If over axis, only that axis will translate.");
ImGui::BulletText("If over plane, only that plane will translate.");
ImGui::BulletText("If outside plot area, translate in the view plane.");
ImGui::Unindent();
}
ImGui::BulletText("Zoom");
{
ImGui::Indent();
ImGui::BulletText("Scroll or middle-click drag to zoom.");
ImGui::BulletText("If over axis, only that axis will zoom.");
ImGui::BulletText("If over plane, only that plane will zoom.");
ImGui::BulletText("If outside plot area, zoom the entire plot.");
ImGui::Unindent();
}
ImGui::BulletText("Rotation");
{
ImGui::Indent();
ImGui::BulletText("Right-click drag to rotate.");
ImGui::BulletText("To reset rotation, double right-click outside plot area.");
ImGui::BulletText("To rotate to plane, double right-click when over the plane.");
ImGui::Unindent();
}
ImGui::BulletText("Fit data");
{
ImGui::Indent();
ImGui::BulletText("Double left-click to fit.");
ImGui::BulletText("If over axis, fit data to axis.");
ImGui::BulletText("If over plane, fit data to plane.");
ImGui::BulletText("If outside plot area, fit data to plot.");
ImGui::Unindent();
}
ImGui::BulletText("Context Menus");
{
ImGui::Indent();
ImGui::BulletText("Right-click outside plot area to show full context menu.");
ImGui::BulletText("Right-click over legend to show legend context menu.");
ImGui::BulletText("Right-click over axis to show axis context menu.");
ImGui::BulletText("Right-click over plane to show plane context menu.");
ImGui::Unindent();
}
ImGui::BulletText("Click legend label icons to show/hide plot items.");
}
void DemoHeader(const char* label, void (*demo)()) {
if (ImGui::TreeNodeEx(label)) {
demo();
ImGui::TreePop();
}
}
void ShowAllDemos() {
ImGui::Text("ImPlot3D says olá! (%s) (%d)", IMPLOT3D_VERSION, IMPLOT3D_VERSION_NUM);
ImGui::Spacing();
if (ImGui::BeginTabBar("ImPlot3DDemoTabs")) {
if (ImGui::BeginTabItem("Plots")) {
ImGui::SeparatorText("Plot Types");
DemoHeader("Line Plots", DemoLinePlots);
DemoHeader("Scatter Plots", DemoScatterPlots);
DemoHeader("Triangle Plots", DemoTrianglePlots);
DemoHeader("Quad Plots", DemoQuadPlots);
DemoHeader("Surface Plots", DemoSurfacePlots);
DemoHeader("Mesh Plots", DemoMeshPlots);
DemoHeader("Realtime Plots", DemoRealtimePlots);
DemoHeader("Image Plots", DemoImagePlots);
ImGui::SeparatorText("Plot Options");
DemoHeader("Plot Flags", DemoPlotFlags);
DemoHeader("Offset and Stride", DemoOffsetAndStride);
DemoHeader("Legend Options", DemoLegendOptions);
DemoHeader("Markers and Text", DemoMarkersAndText);
DemoHeader("NaN Values", DemoNaNValues);
DemoHeader("Per-Index Colors", Demo_PerIndexColors);
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Axes")) {
DemoHeader("Box Scale", DemoBoxScale);
DemoHeader("Box Rotation", DemoBoxRotation);
DemoHeader("Log Scale", Demo_LogScale);
DemoHeader("Symmetric Log Scale", Demo_SymmetricLogScale);
DemoHeader("Tick Labels", DemoTickLabels);
DemoHeader("Axis Constraints", DemoAxisConstraints);
DemoHeader("Equal Axes", DemoEqualAxes);
DemoHeader("Auto-Fitting Data", DemoAutoFittingData);
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Tools")) {
DemoHeader("Mouse Picking", DemoMousePicking);
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Custom")) {
DemoHeader("Custom Styles", DemoCustomStyles);
DemoHeader("Custom Rendering", DemoCustomRendering);
DemoHeader("Custom Overlay", DemoCustomOverlay);
DemoHeader("Custom Per-Point Style", DemoCustomPerPointStyle);
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Config")) {
DemoConfig();
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Help")) {
DemoHelp();
ImGui::EndTabItem();
}
ImGui::EndTabBar();
}
}
void ShowDemoWindow(bool* p_open) {
static bool show_implot3d_metrics = false;
static bool show_implot3d_style_editor = false;
static bool show_implot3d_about = false;
static bool show_imgui_metrics = false;
static bool show_imgui_style_editor = false;
static bool show_imgui_demo = false;
if (show_implot3d_metrics)
ImPlot3D::ShowMetricsWindow(&show_implot3d_metrics);
if (show_implot3d_style_editor) {
ImGui::Begin("Style Editor (ImPlot3D)", &show_implot3d_style_editor);
ImPlot3D::ShowStyleEditor();
ImGui::End();
}
if (show_implot3d_about)
ImPlot3D::ShowAboutWindow(&show_implot3d_about);
if (show_imgui_style_editor) {
ImGui::Begin("Style Editor (ImGui)", &show_imgui_style_editor);
ImGui::ShowStyleEditor();
ImGui::End();
}
if (show_imgui_metrics)
ImGui::ShowMetricsWindow(&show_imgui_metrics);
if (show_imgui_demo)
ImGui::ShowDemoWindow(&show_imgui_demo);
ImGui::SetNextWindowPos(ImVec2(100, 100), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(ImVec2(600, 750), ImGuiCond_FirstUseEver);
ImGui::Begin("ImPlot3D Demo", p_open, ImGuiWindowFlags_MenuBar);
if (ImGui::BeginMenuBar()) {
if (ImGui::BeginMenu("Tools")) {
ImGui::MenuItem("Metrics", nullptr, &show_implot3d_metrics);
ImGui::MenuItem("Style Editor", nullptr, &show_implot3d_style_editor);
ImGui::MenuItem("About ImPlot3D", nullptr, &show_implot3d_about);
ImGui::Separator();
ImGui::MenuItem("ImGui Metrics", nullptr, &show_imgui_metrics);
ImGui::MenuItem("ImGui Style Editor", nullptr, &show_imgui_style_editor);
ImGui::MenuItem("ImGui Demo", nullptr, &show_imgui_demo);
ImGui::EndMenu();
}
ImGui::EndMenuBar();
}
ShowAllDemos();
ImGui::End();
}
bool ColormapButton(const char* label, const ImVec2& size_arg, ImPlot3DColormap cmap) {
ImGuiContext& G = *GImGui;
const ImGuiStyle& style = G.Style;
ImGuiWindow* Window = G.CurrentWindow;
if (Window->SkipItems)
return false;
ImPlot3DContext& gp = *GImPlot3D;
cmap = cmap == IMPLOT3D_AUTO ? gp.Style.Colormap : cmap;
IM_ASSERT_USER_ERROR(cmap >= 0 && cmap < gp.ColormapData.Count, "Invalid colormap index!");
const ImU32* keys = gp.ColormapData.GetKeys(cmap);
const int count = gp.ColormapData.GetKeyCount(cmap);
const bool qual = gp.ColormapData.IsQual(cmap);
const ImVec2 pos = ImGui::GetCurrentWindow()->DC.CursorPos;
const ImVec2 label_size = ImGui::CalcTextSize(label, nullptr, true);
ImVec2 size = ImGui::CalcItemSize(size_arg, label_size.x + style.FramePadding.x * 2.0f, label_size.y + style.FramePadding.y * 2.0f);
const ImRect rect = ImRect(pos.x, pos.y, pos.x + size.x, pos.y + size.y);
RenderColorBar(keys, count, *ImGui::GetWindowDrawList(), rect, false, false, !qual);
const ImU32 text = CalcTextColor(gp.ColormapData.LerpTable(cmap, G.Style.ButtonTextAlign.x));
ImGui::PushStyleColor(ImGuiCol_Button, IM_COL32_BLACK_TRANS);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(1, 1, 1, 0.1f));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(1, 1, 1, 0.2f));
ImGui::PushStyleColor(ImGuiCol_Text, text);
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 0);
const bool pressed = ImGui::Button(label, size);
ImGui::PopStyleColor(4);
ImGui::PopStyleVar(1);
return pressed;
}
void ShowStyleEditor(ImPlot3DStyle* ref) {
ImPlot3DContext& gp = *GImPlot3D;
ImPlot3DStyle& style = GetStyle();
static ImPlot3DStyle ref_saved_style;
static bool init = true;
if (init && ref == nullptr)
ref_saved_style = style;
init = false;
if (ref == nullptr)
ref = &ref_saved_style;
static float flash_color_time = 0.5f;
static ImPlot3DCol flash_color_idx = ImPlot3DCol_COUNT;
static ImVec4 flash_color_backup = ImVec4(0, 0, 0, 0);
if (flash_color_idx != ImPlot3DCol_COUNT) {
ImVec4& color = style.Colors[flash_color_idx];
ImGui::ColorConvertHSVtoRGB(ImCos(flash_color_time * 6.0f) * 0.5f + 0.5f, 0.5f, 0.5f, color.x, color.y, color.z);
color.w = 1.0f;
if ((flash_color_time -= ImGui::GetIO().DeltaTime) <= 0.0f) {
style.Colors[flash_color_idx] = flash_color_backup;
flash_color_idx = ImPlot3DCol_COUNT;
flash_color_time = 0.5f;
}
}
if (ImPlot3D::ShowStyleSelector("Colors##Selector"))
ref_saved_style = style;
if (ImGui::Button("Save Ref"))
*ref = ref_saved_style = style;
ImGui::SameLine();
if (ImGui::Button("Revert Ref"))
style = *ref;
ImGui::SameLine();
HelpMarker("Save/Revert in local non-persistent storage. Default Colors definition are not affected. "
"Use \"Export\" below to save them somewhere.");
ImGui::Separator();
if (ImGui::BeginTabBar("##Tabs", ImGuiTabBarFlags_None)) {
if (ImGui::BeginTabItem("Variables")) {
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("FillAlpha", &style.FillAlpha, 0.0f, 1.0f, "%.2f");
ImGui::Text("Plot Styling");
ImGui::SliderFloat2("PlotDefaultSize", (float*)&style.PlotDefaultSize, 0.0f, 1000, "%.0f");
ImGui::SliderFloat2("PlotMinSize", (float*)&style.PlotMinSize, 0.0f, 300, "%.0f");
ImGui::SliderFloat2("PlotPadding", (float*)&style.PlotPadding, 0.0f, 20.0f, "%.0f");
ImGui::SliderFloat2("LabelPadding", (float*)&style.LabelPadding, 0.0f, 20.0f, "%.0f");
ImGui::SliderFloat("ViewScaleFactor", (float*)&style.ViewScaleFactor, 0.1f, 2.0f, "%.2f");
ImGui::Text("Legend Styling");
ImGui::SliderFloat2("LegendPadding", (float*)&style.LegendPadding, 0.0f, 20.0f, "%.0f");
ImGui::SliderFloat2("LegendInnerPadding", (float*)&style.LegendInnerPadding, 0.0f, 10.0f, "%.0f");
ImGui::SliderFloat2("LegendSpacing", (float*)&style.LegendSpacing, 0.0f, 5.0f, "%.0f");
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Colors")) {
static int output_dest = 0;
static bool output_only_modified = true;
if (ImGui::Button("Export")) {
if (output_dest == 0)
ImGui::LogToClipboard();
else
ImGui::LogToTTY();
ImGui::LogText("ImVec4* colors = ImPlot3D::GetStyle().Colors;\n");
for (int i = 0; i < ImPlot3DCol_COUNT; i++) {
const ImVec4& col = style.Colors[i];
const char* name = ImPlot3D::GetStyleColorName(i);
if (!output_only_modified || memcmp(&col, &ref->Colors[i], sizeof(ImVec4)) != 0)
ImGui::LogText("colors[ImPlot3DCol_%s]%*s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);\n", name, 15 - (int)strlen(name), "", col.x,
col.y, col.z, col.w);
}
ImGui::LogFinish();
}
ImGui::SameLine();
ImGui::SetNextItemWidth(120);
ImGui::Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0");
ImGui::SameLine();
ImGui::Checkbox("Only Modified Colors", &output_only_modified);
static ImGuiTextFilter filter;
filter.Draw("Filter colors", ImGui::GetFontSize() * 16);
static ImGuiColorEditFlags alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf;
#if IMGUI_VERSION_NUM < 19173
if (ImGui::RadioButton("Opaque", alpha_flags == ImGuiColorEditFlags_None))
alpha_flags = ImGuiColorEditFlags_None;
ImGui::SameLine();
if (ImGui::RadioButton("Alpha", alpha_flags == ImGuiColorEditFlags_AlphaPreview))
alpha_flags = ImGuiColorEditFlags_AlphaPreview;
ImGui::SameLine();
if (ImGui::RadioButton("Both", alpha_flags == ImGuiColorEditFlags_AlphaPreviewHalf))
alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf;
ImGui::SameLine();
#else
if (ImGui::RadioButton("Opaque", alpha_flags == ImGuiColorEditFlags_AlphaOpaque))
alpha_flags = ImGuiColorEditFlags_AlphaOpaque;
ImGui::SameLine();
if (ImGui::RadioButton("Alpha", alpha_flags == ImGuiColorEditFlags_None))
alpha_flags = ImGuiColorEditFlags_None;
ImGui::SameLine();
if (ImGui::RadioButton("Both", alpha_flags == ImGuiColorEditFlags_AlphaPreviewHalf))
alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf;
ImGui::SameLine();
#endif
HelpMarker("In the color list:\n"
"Left-click on color square to open color picker,\n"
"Right-click to open edit options menu.");
ImGui::Separator();
for (int i = 0; i < ImPlot3DCol_COUNT; i++) {
const char* name = ImPlot3D::GetStyleColorName(i);
if (!filter.PassFilter(name))
continue;
ImGui::PushID(i);
if (ImGui::Button("?")) {
if (flash_color_idx != ImPlot3DCol_COUNT)
style.Colors[flash_color_idx] = flash_color_backup;
flash_color_time = 0.5f;
flash_color_idx = (ImPlot3DCol)i;
flash_color_backup = style.Colors[i];
}
ImGui::SetItemTooltip("Flash given color to identify places where it is used.");
ImGui::SameLine();
const bool is_auto = IsColorAuto(style.Colors[i]);
if (is_auto)
ImGui::BeginDisabled();
if (ImGui::Button("Auto"))
style.Colors[i] = IMPLOT3D_AUTO_COL;
if (is_auto)
ImGui::EndDisabled();
ImGui::SameLine();
if (ImGui::ColorEdit4("##Color", (float*)&style.Colors[i], ImGuiColorEditFlags_NoInputs | alpha_flags)) {
if (style.Colors[i].w == -1)
style.Colors[i].w = 1;
}
if (memcmp(&style.Colors[i], &ref->Colors[i], sizeof(ImVec4)) != 0) {
ImGui::SameLine();
if (ImGui::Button("Save"))
ref->Colors[i] = style.Colors[i];
ImGui::SameLine();
if (ImGui::Button("Revert"))
style.Colors[i] = ref->Colors[i];
}
ImGui::SameLine();
ImGui::TextUnformatted(name);
ImGui::PopID();
}
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Colormaps")) {
static int output_dest = 0;
if (ImGui::Button("Export", ImVec2(75, 0))) {
if (output_dest == 0)
ImGui::LogToClipboard();
else
ImGui::LogToTTY();
int size = GetColormapSize();
const char* name = GetColormapName(gp.Style.Colormap);
ImGui::LogText("static const ImU32 %s_Data[%d] = {\n", name, size);
for (int i = 0; i < size; i++) {
ImU32 col = GetColormapColorU32(i, gp.Style.Colormap);
ImGui::LogText(" %u%s\n", col, i == size - 1 ? "" : ",");
}
ImGui::LogText("};\nImPlotColormap %s = ImPlot::AddColormap(\"%s\", %s_Data, %d);", name, name, name, size);
ImGui::LogFinish();
}
ImGui::SameLine();
ImGui::SetNextItemWidth(120);
ImGui::Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0");
ImGui::SameLine();
static bool edit = false;
ImGui::Checkbox("Edit Mode", &edit);
ImGui::Separator();
for (int i = 0; i < gp.ColormapData.Count; i++) {
ImGui::PushID(i);
int size = gp.ColormapData.GetKeyCount(i);
bool selected = i == gp.Style.Colormap;
const char* name = GetColormapName(i);
if (!selected)
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.25f);
if (ImGui::Button(name, ImVec2(100, 0))) {
gp.Style.Colormap = i;
BustItemCache();
}
if (!selected)
ImGui::PopStyleVar();
ImGui::SameLine();
ImGui::BeginGroup();
if (edit) {
for (int c = 0; c < size; ++c) {
ImGui::PushID(c);
ImVec4 col4 = ImGui::ColorConvertU32ToFloat4(gp.ColormapData.GetKeyColor(i, c));
if (ImGui::ColorEdit4("", &col4.x, ImGuiColorEditFlags_NoInputs)) {
ImU32 col32 = ImGui::ColorConvertFloat4ToU32(col4);
gp.ColormapData.SetKeyColor(i, c, col32);
BustItemCache();
}
if ((c + 1) % 12 != 0 && c != size - 1)
ImGui::SameLine();
ImGui::PopID();
}
} else {
if (ColormapButton("##", ImVec2(-1, 0), i))
edit = true;
}
ImGui::EndGroup();
ImGui::PopID();
}
static ImVector<ImVec4> custom;
if (custom.Size == 0) {
custom.push_back(ImVec4(1, 0, 0, 1));
custom.push_back(ImVec4(0, 1, 0, 1));
custom.push_back(ImVec4(0, 0, 1, 1));
}
ImGui::Separator();
ImGui::BeginGroup();
static char name[16] = "MyColormap";
if (ImGui::Button("+", ImVec2((100 - ImGui::GetStyle().ItemSpacing.x) / 2, 0)))
custom.push_back(ImVec4(0, 0, 0, 1));
ImGui::SameLine();
if (ImGui::Button("-", ImVec2((100 - ImGui::GetStyle().ItemSpacing.x) / 2, 0)) && custom.Size > 2)
custom.pop_back();
ImGui::SetNextItemWidth(100);
ImGui::InputText("##Name", name, 16, ImGuiInputTextFlags_CharsNoBlank);
static bool qual = true;
ImGui::Checkbox("Qualitative", &qual);
if (ImGui::Button("Add", ImVec2(100, 0)) && gp.ColormapData.GetIndex(name) == -1)
AddColormap(name, custom.Data, custom.Size, qual);
ImGui::EndGroup();
ImGui::SameLine();
ImGui::BeginGroup();
for (int c = 0; c < custom.Size; ++c) {
ImGui::PushID(c);
if (ImGui::ColorEdit4("##Col1", &custom[c].x, ImGuiColorEditFlags_NoInputs)) {
}
if ((c + 1) % 12 != 0)
ImGui::SameLine();
ImGui::PopID();
}
ImGui::EndGroup();
ImGui::EndTabItem();
}
ImGui::EndTabBar();
}
}
void ShowAboutWindow(bool* p_open) {
if (!ImGui::Begin("About ImPlot3D", p_open, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::End();
return;
}
ImGui::Text("ImPlot3D %s (%d)", IMPLOT3D_VERSION, IMPLOT3D_VERSION_NUM);
ImGui::TextLinkOpenURL("Homepage", "https://github.com/brenocq/implot3d");
ImGui::SameLine();
ImGui::TextLinkOpenURL("Q&A", "https://github.com/brenocq/implot3d/discussions/categories/q-a");
ImGui::SameLine();
ImGui::TextLinkOpenURL("Releases", "https://github.com/brenocq/implot3d/releases");
ImGui::SameLine();
ImGui::TextLinkOpenURL("Sponsors", "https://github.com/sponsors/brenocq");
ImGui::Separator();
ImGui::Text("(c) 2024-2025 Breno Cunha Queiroz");
ImGui::Text("Developed by Breno Cunha Queiroz and all ImPlot3D contributors.");
ImGui::Text("ImPlot3D is licensed under the MIT License.");
ImGui::Text("If your company uses ImPlot3D, please consider sponsoring the project.");
static bool show_config_info = false;
ImGui::Checkbox("Config/Build Information", &show_config_info);
if (show_config_info) {
bool copy_to_clipboard = ImGui::Button("Copy to clipboard");
ImVec2 child_size = ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 18);
ImGui::BeginChild(ImGui::GetID("cfg_infos"), child_size, ImGuiChildFlags_FrameStyle);
if (copy_to_clipboard) {
ImGui::LogToClipboard();
ImGui::LogText("```cpp\n");
}
ImGui::Text("ImPlot3D %s (%d)", IMPLOT3D_VERSION, IMPLOT3D_VERSION_NUM);
ImGui::Separator();
ImGui::Text("sizeof(size_t): %d, sizeof(ImPlot3DPoint): %d", (int)sizeof(size_t), (int)sizeof(ImPlot3DPoint));
#ifdef IMPLOT3D_DISABLE_OBSOLETE_FUNCTIONS
ImGui::Text("define: IMPLOT3D_DISABLE_OBSOLETE_FUNCTIONS");
#endif
ImGui::Text("define: __cplusplus=%d", (int)__cplusplus);
#ifdef _WIN32
ImGui::Text("define: _WIN32");
#endif
#ifdef _WIN64
ImGui::Text("define: _WIN64");
#endif
#ifdef __linux__
ImGui::Text("define: __linux__");
#endif
#ifdef __APPLE__
ImGui::Text("define: __APPLE__");
#endif
#ifdef _MSC_VER
ImGui::Text("define: _MSC_VER=%d", _MSC_VER);
#endif
#ifdef __MINGW32__
ImGui::Text("define: __MINGW32__");
#endif
#ifdef __MINGW64__
ImGui::Text("define: __MINGW64__");
#endif
#ifdef __GNUC__
ImGui::Text("define: __GNUC__=%d", (int)__GNUC__);
#endif
#ifdef __clang_version__
ImGui::Text("define: __clang_version__=%s", __clang_version__);
#endif
if (copy_to_clipboard) {
ImGui::LogText("```\n");
ImGui::LogFinish();
}
ImGui::EndChild();
}
ImGui::End();
}
}
namespace MyImPlot3D {
void StyleSeaborn() {
ImPlot3DStyle& style = ImPlot3D::GetStyle();
ImVec4* colors = style.Colors;
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);
colors[ImPlot3DCol_LegendBg] = ImVec4(0.92f, 0.92f, 0.95f, 1.00f);
colors[ImPlot3DCol_LegendBorder] = ImVec4(0.80f, 0.81f, 0.85f, 1.00f);
colors[ImPlot3DCol_LegendText] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f);
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_AxisText] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f);
colors[ImPlot3DCol_AxisGrid] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
style.LineWeight = 1.5;
style.Marker = ImPlot3DMarker_None;
style.MarkerSize = 4;
style.FillAlpha = 1.0f;
style.PlotPadding = ImVec2(12, 12);
style.LabelPadding = ImVec2(5, 5);
style.LegendPadding = ImVec2(5, 5);
style.PlotMinSize = ImVec2(300, 225);
}
}