OXYGENHUB
◆ main openmsx / src / imgui / ImGuiPlot.cc
3.7 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
e8555c89 Andy McCall 1
#include "ImGuiPlot.hh"
2
3
#include "imgui.h"
4
#include "imgui_internal.h" // for ImLerp
5
6
#include "narrow.hh"
7
8
#include <algorithm>
9
#include <span>
10
11
namespace openmsx {
12
13
// Simplified/optimized version of ImGui::PlotLines()
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;              // top-left
55
	auto outer_br = pos + outer_size; // bottom-right
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
// Simplified/optimized version of ImGui::PlotHistogram()
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;              // top-left
73
	auto outer_br = pos + outer_size; // bottom-right
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
} // namespace openmsx