| e8555c89 Andy McCall |
1 |
#include "ImGuiPlot.hh" |
| 2 |
|
| 3 |
#include "imgui.h" |
| 4 |
#include "imgui_internal.h" |
| 5 |
|
| 6 |
#include "narrow.hh" |
| 7 |
|
| 8 |
#include <algorithm> |
| 9 |
#include <span> |
| 10 |
|
| 11 |
namespace openmsx { |
| 12 |
|
| 13 |
|
| 14 |
void plotLinesRaw(std::span<const float> values, float scale_min, float scale_max, |
| 15 |
gl::vec2 top_left, gl::vec2 bottom_right, uint32_t color) |
| 16 |
{ |
| 17 |
int num_values = narrow<int>(values.size()); |
| 18 |
if (num_values < 2) return; |
| 19 |
int num_items = num_values - 1; |
| 20 |
|
| 21 |
int inner_width = std::max(1, static_cast<int>(bottom_right.x - top_left.x)); |
| 22 |
int res_w = std::min(inner_width, num_items); |
| 23 |
|
| 24 |
float t_step = 1.0f / (float)res_w; |
| 25 |
float scale_range = scale_max - scale_min; |
| 26 |
float inv_scale = (scale_range != 0.0f) ? (1.0f / scale_range) : 0.0f; |
| 27 |
|
| 28 |
auto valueToY = [&](float v) { |
| 29 |
return 1.0f - std::clamp((v - scale_min) * inv_scale, 0.0f, 1.0f); |
| 30 |
}; |
| 31 |
float t = 0.0f; |
| 32 |
auto tp0 = gl::vec2(t, valueToY(values[0])); |
| 33 |
auto pos0 = ImLerp(top_left, bottom_right, tp0); |
| 34 |
|
| 35 |
auto* drawList = ImGui::GetWindowDrawList(); |
| 36 |
for (int n = 0; n < res_w; n++) { |
| 37 |
auto idx = static_cast<int>(t * float(num_items) + 0.5f); |
| 38 |
assert(0 <= idx && idx < num_values); |
| 39 |
float v = values[(idx + 1) % num_values]; |
| 40 |
|
| 41 |
t += t_step; |
| 42 |
auto tp1 = gl::vec2(t, valueToY(v)); |
| 43 |
auto pos1 = ImLerp(top_left, bottom_right, tp1); |
| 44 |
drawList->AddLine(pos0, pos1, color); |
| 45 |
pos0 = pos1; |
| 46 |
} |
| 47 |
} |
| 48 |
|
| 49 |
void plotLines(std::span<const float> values, float scale_min, float scale_max, gl::vec2 outer_size) |
| 50 |
{ |
| 51 |
const auto& style = ImGui::GetStyle(); |
| 52 |
|
| 53 |
gl::vec2 pos = ImGui::GetCursorScreenPos(); |
| 54 |
auto outer_tl = pos; |
| 55 |
auto outer_br = pos + outer_size; |
| 56 |
auto inner_tl = outer_tl + gl::vec2(style.FramePadding); |
| 57 |
auto inner_br = outer_br - gl::vec2(style.FramePadding); |
| 58 |
|
| 59 |
ImGui::RenderFrame(outer_tl, outer_br, ImGui::GetColorU32(ImGuiCol_FrameBg), |
| 60 |
true, style.FrameRounding); |
| 61 |
|
| 62 |
auto color = ImGui::GetColorU32(ImGuiCol_PlotLines); |
| 63 |
plotLinesRaw(values, scale_min, scale_max, inner_tl, inner_br, color); |
| 64 |
} |
| 65 |
|
| 66 |
|
| 67 |
void plotHistogram(std::span<const float> values, float scale_min, float scale_max, gl::vec2 outer_size) |
| 68 |
{ |
| 69 |
const auto& style = ImGui::GetStyle(); |
| 70 |
|
| 71 |
gl::vec2 pos = ImGui::GetCursorScreenPos(); |
| 72 |
auto outer_tl = pos; |
| 73 |
auto outer_br = pos + outer_size; |
| 74 |
auto inner_tl = outer_tl + gl::vec2(style.FramePadding); |
| 75 |
auto inner_br = outer_br - gl::vec2(style.FramePadding); |
| 76 |
|
| 77 |
ImGui::RenderFrame(outer_tl, outer_br, ImGui::GetColorU32(ImGuiCol_FrameBg), |
| 78 |
true, style.FrameRounding); |
| 79 |
if (values.empty()) return; |
| 80 |
|
| 81 |
int num_values = narrow<int>(values.size()); |
| 82 |
int inner_width = std::max(1, static_cast<int>(inner_br.x - inner_tl.x)); |
| 83 |
int res_w = std::min(inner_width, num_values); |
| 84 |
|
| 85 |
float t_step = 1.0f / static_cast<float>(res_w); |
| 86 |
float scale_range = scale_max - scale_min; |
| 87 |
float inv_scale = (scale_range != 0.0f) ? (1.0f / scale_range) : 0.0f; |
| 88 |
|
| 89 |
auto valueToY = [&](float v) { |
| 90 |
return 1.0f - std::clamp((v - scale_min) * inv_scale, 0.0f, 1.0f); |
| 91 |
}; |
| 92 |
float zero_line = (scale_min * scale_max < 0.0f) |
| 93 |
? (1 + scale_min * inv_scale) |
| 94 |
: (scale_min < 0.0f ? 0.0f : 1.0f); |
| 95 |
|
| 96 |
auto color = ImGui::GetColorU32(ImGuiCol_PlotHistogram); |
| 97 |
|
| 98 |
float t0 = 0.0f; |
| 99 |
auto* drawList = ImGui::GetWindowDrawList(); |
| 100 |
drawList->PrimReserve(6 * res_w, 4 * res_w); |
| 101 |
|
| 102 |
for (int n = 0; n < res_w; n++) { |
| 103 |
auto idx = static_cast<int>(t0 * float(num_values) + 0.5f); |
| 104 |
assert(0 <= idx && idx < num_values); |
| 105 |
float y0 = valueToY(values[idx]); |
| 106 |
float t1 = t0 + t_step; |
| 107 |
|
| 108 |
auto pos0 = ImLerp(inner_tl, inner_br, gl::vec2(t0, y0)); |
| 109 |
auto pos1 = ImLerp(inner_tl, inner_br, gl::vec2(t1, zero_line)); |
| 110 |
drawList->PrimRect(pos0, pos1, color); |
| 111 |
|
| 112 |
t0 = t1; |
| 113 |
} |
| 114 |
} |
| 115 |
|
| 116 |
} |