Skip to content

Commit ed3640d

Browse files
committed
Add a first draft visualiser.
1 parent 87ce3ad commit ed3640d

File tree

5 files changed

+195
-3
lines changed

5 files changed

+195
-3
lines changed

src/gui2/build.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,8 @@ def plugin(name, id, srcs, hdrs, romfsdir, deps):
520520
"./physicalview.h",
521521
"./summaryview.cc",
522522
"./summaryview.h",
523+
"./visualiserview.cc",
524+
"./visualiserview.h",
523525
"./utils.cc",
524526
"./utils.h",
525527
],

src/gui2/fluxengine.cc

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "configview.h"
1111
#include "controlpanelview.h"
1212
#include "logview.h"
13+
#include "visualiserview.h"
1314
#include "diskprovider.h"
1415
#include "datastore.h"
1516

@@ -25,12 +26,13 @@ IMHEX_PLUGIN_SETUP("FluxEngine", "David Given", "FluxEngine integration")
2526

2627
hex::ContentRegistry::Provider::add<DiskProvider>();
2728

28-
hex::ContentRegistry::Views::add<ImageView>();
29-
hex::ContentRegistry::Views::add<PhysicalView>();
30-
hex::ContentRegistry::Views::add<SummaryView>();
3129
hex::ContentRegistry::Views::add<ConfigView>();
3230
hex::ContentRegistry::Views::add<ControlPanelView>();
31+
hex::ContentRegistry::Views::add<ImageView>();
3332
hex::ContentRegistry::Views::add<LogView>();
33+
hex::ContentRegistry::Views::add<PhysicalView>();
34+
hex::ContentRegistry::Views::add<SummaryView>();
35+
hex::ContentRegistry::Views::add<VisualiserView>();
3436

3537
Datastore::init();
3638
}

src/gui2/rsrc/lang/en_US.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@
4444

4545
"fluxengine.view.log.name": "FluxEngine log viewer",
4646

47+
"fluxengine.view.visualiser.name": "FluxEngine disk visualiser",
48+
4749
"fluxengine.view.status.runningSuffix": "...",
4850
"fluxengine.view.status.succeededSuffix": "... done",
4951
"fluxengine.view.status.failedSuffix": "... failed",

src/gui2/visualiserview.cc

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
#include <hex/api/content_registry/user_interface.hpp>
2+
#include <hex/api/theme_manager.hpp>
3+
#include <hex/helpers/logger.hpp>
4+
#include <fonts/vscode_icons.hpp>
5+
#include <fonts/tabler_icons.hpp>
6+
#include <fmt/format.h>
7+
#include "lib/core/globals.h"
8+
#include "lib/config/config.h"
9+
#include "lib/data/disk.h"
10+
#include "lib/data/sector.h"
11+
#include "lib/config/proto.h"
12+
#include "globals.h"
13+
#include "visualiserview.h"
14+
#include "datastore.h"
15+
#include "utils.h"
16+
#include <implot.h>
17+
#include <implot_internal.h>
18+
#include <algorithm>
19+
20+
using namespace hex;
21+
22+
static constexpr float INNER_RADIUS = 50;
23+
static constexpr float SEGMENTS_PER_RADIAN = 24;
24+
25+
VisualiserView::VisualiserView():
26+
View::Window("fluxengine.view.visualiser.name", ICON_VS_PREVIEW)
27+
{
28+
}
29+
30+
void VisualiserView::drawContent()
31+
{
32+
const auto& diskLayout = Datastore::getDiskLayout();
33+
const auto& disk = Datastore::getDisk();
34+
35+
ImDrawList* drawList = ImGui::GetWindowDrawList();
36+
auto pos = ImGui::GetCursorScreenPos();
37+
auto size = ImGui::GetContentRegionAvail();
38+
auto padding = ImGui::GetStyle().WindowPadding;
39+
uint32_t fg = ImGui::GetColorU32(ImGuiCol_Text);
40+
uint32_t bg = ImGui::GetColorU32(ImGuiCol_WindowBg);
41+
uint32_t diskbg = ImGui::GetColorU32(ImGuiCol_FrameBg);
42+
43+
ImVec2 centre(pos.x + size.x / 2, pos.y + size.y / 2);
44+
float outerRadius = (size.x - padding.x * 2) / 2;
45+
ImVec2 side0pos(centre.x, centre.y - outerRadius - padding.y);
46+
ImVec2 side1pos(centre.x, centre.y + outerRadius + padding.y);
47+
48+
auto drawCentered =
49+
[&](const ImVec2& pos, uint32_t colour, const std::string& s)
50+
{
51+
auto size = ImGui::CalcTextSize(s.c_str());
52+
drawList->AddText({pos.x - size.x / 2, pos.y - size.y / 2},
53+
colour,
54+
&*s.begin(),
55+
&*s.end());
56+
};
57+
58+
auto drawSide = [&](int head, ImVec2 pos)
59+
{
60+
drawList->AddCircleFilled(pos, outerRadius, diskbg, 0);
61+
drawList->AddCircleFilled(pos, INNER_RADIUS, bg, 0);
62+
drawList->AddCircle(pos, outerRadius, fg, 0);
63+
drawList->AddCircle(pos, INNER_RADIUS, fg, 0);
64+
drawCentered(pos, fg, fmt::format("h{}", head));
65+
66+
if (!diskLayout || !disk)
67+
return;
68+
69+
int numPhysicalTracks =
70+
diskLayout->maxPhysicalCylinder - diskLayout->minPhysicalCylinder;
71+
float trackSpacing = (float)(outerRadius - INNER_RADIUS) /
72+
(float)(numPhysicalTracks + 2);
73+
74+
for (const auto& [ch, track] : disk->tracksByPhysicalLocation)
75+
{
76+
if (ch.head != head)
77+
continue;
78+
if (!track->fluxmap)
79+
continue;
80+
81+
const auto& indexMarks = track->fluxmap->getIndexMarks();
82+
nanoseconds_t rotationalPeriod;
83+
if (indexMarks.empty())
84+
continue;
85+
if (indexMarks.size() >= 2)
86+
rotationalPeriod = indexMarks[1] - indexMarks[0];
87+
else
88+
{
89+
rotationalPeriod = disk->rotationalPeriod;
90+
if (rotationalPeriod == 0)
91+
continue;
92+
}
93+
float radiansPerNano = IM_PI * 2.0 / rotationalPeriod;
94+
95+
float radius =
96+
(float)outerRadius - ((float)ch.cylinder + 0.5) * trackSpacing;
97+
98+
auto normalisePosition = [&](nanoseconds_t timestamp)
99+
{
100+
if (timestamp < indexMarks[0])
101+
return timestamp - (indexMarks[0] - rotationalPeriod);
102+
103+
auto it = std::upper_bound(
104+
indexMarks.begin(), indexMarks.end(), timestamp);
105+
it--;
106+
return timestamp - *it;
107+
};
108+
109+
auto drawArcRadians =
110+
[&](float startRadians, float endRadians, uint32_t colour)
111+
{
112+
int segments =
113+
ImClamp((endRadians - startRadians) * SEGMENTS_PER_RADIAN,
114+
6.0F,
115+
SEGMENTS_PER_RADIAN * IM_PI * 2);
116+
drawList->PathArcTo(pos,
117+
radius,
118+
startRadians - IM_PI / 2,
119+
endRadians - IM_PI / 2,
120+
segments);
121+
drawList->PathStroke(
122+
colour, ImDrawFlags_None, trackSpacing * 0.75);
123+
};
124+
125+
auto drawArcNs =
126+
[&](nanoseconds_t startNs, nanoseconds_t endNs, uint32_t colour)
127+
{
128+
float startRadians =
129+
normalisePosition(startNs) * radiansPerNano;
130+
float endRadians = normalisePosition(endNs) * radiansPerNano;
131+
drawArcRadians(startRadians, endRadians, colour);
132+
};
133+
134+
for (const auto& sector : track->normalisedSectors)
135+
{
136+
if (sector->headerStartTime && sector->headerEndTime)
137+
drawArcNs(sector->headerStartTime,
138+
sector->headerEndTime,
139+
ImGuiExt::GetCustomColorU32(
140+
ImGuiCustomCol_AdvancedEncodingMultiChar));
141+
if (sector->dataStartTime && sector->dataEndTime)
142+
drawArcNs(sector->dataStartTime,
143+
sector->dataEndTime,
144+
ImGuiExt::GetCustomColorU32(
145+
sector->status == Sector::OK
146+
? ImGuiCustomCol_AdvancedEncodingASCII
147+
: ImGuiCustomCol_DiffRemoved));
148+
}
149+
if (track->normalisedSectors.empty())
150+
drawArcRadians(0,
151+
IM_PI * 2,
152+
ImGuiExt::GetCustomColorU32(ImGuiCustomCol_DiffRemoved));
153+
}
154+
155+
drawList->AddLine({pos.x, pos.y - INNER_RADIUS},
156+
{pos.x, pos.y - outerRadius},
157+
ImGui::GetColorU32(ImGuiCol_PlotHistogram),
158+
1.0);
159+
};
160+
161+
drawSide(0, side0pos);
162+
drawSide(1, side1pos);
163+
}

src/gui2/visualiserview.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#pragma once
2+
3+
#include "lib/core/logger.h"
4+
#include <hex/ui/view.hpp>
5+
6+
class VisualiserView : public hex::View::Window
7+
{
8+
public:
9+
VisualiserView();
10+
~VisualiserView() override = default;
11+
12+
void drawContent() override;
13+
14+
[[nodiscard]] bool shouldDraw() const override
15+
{
16+
return true;
17+
}
18+
[[nodiscard]] bool hasViewMenuItemEntry() const override
19+
{
20+
return true;
21+
}
22+
};
23+

0 commit comments

Comments
 (0)