feat: Added digital signal pattern visualizer
This commit is contained in:
parent
c5f5973a9d
commit
2e3f523f32
@ -26,6 +26,7 @@ add_imhex_plugin(
|
|||||||
source/content/pl_visualizers/coordinates.cpp
|
source/content/pl_visualizers/coordinates.cpp
|
||||||
source/content/pl_visualizers/timestamp.cpp
|
source/content/pl_visualizers/timestamp.cpp
|
||||||
source/content/pl_visualizers/table.cpp
|
source/content/pl_visualizers/table.cpp
|
||||||
|
source/content/pl_visualizers/digital_signal.cpp
|
||||||
INCLUDES
|
INCLUDES
|
||||||
include
|
include
|
||||||
${MINIAUDIO_INCLUDE_DIRS}
|
${MINIAUDIO_INCLUDE_DIRS}
|
||||||
|
@ -14,6 +14,7 @@ namespace hex::plugin::visualizers {
|
|||||||
void drawCoordinateVisualizer(pl::ptrn::Pattern &, pl::ptrn::IIterable &, bool, std::span<const pl::core::Token::Literal> arguments);
|
void drawCoordinateVisualizer(pl::ptrn::Pattern &, pl::ptrn::IIterable &, bool, std::span<const pl::core::Token::Literal> arguments);
|
||||||
void drawTimestampVisualizer(pl::ptrn::Pattern &, pl::ptrn::IIterable &, bool, std::span<const pl::core::Token::Literal> arguments);
|
void drawTimestampVisualizer(pl::ptrn::Pattern &, pl::ptrn::IIterable &, bool, std::span<const pl::core::Token::Literal> arguments);
|
||||||
void drawTableVisualizer(pl::ptrn::Pattern &, pl::ptrn::IIterable &, bool, std::span<const pl::core::Token::Literal> arguments);
|
void drawTableVisualizer(pl::ptrn::Pattern &, pl::ptrn::IIterable &, bool, std::span<const pl::core::Token::Literal> arguments);
|
||||||
|
void drawDigitalSignalVisualizer(pl::ptrn::Pattern &, pl::ptrn::IIterable &, bool, std::span<const pl::core::Token::Literal> arguments);
|
||||||
|
|
||||||
void registerPatternLanguageVisualizers() {
|
void registerPatternLanguageVisualizers() {
|
||||||
using ParamCount = pl::api::FunctionParameterCount;
|
using ParamCount = pl::api::FunctionParameterCount;
|
||||||
@ -27,6 +28,7 @@ namespace hex::plugin::visualizers {
|
|||||||
ContentRegistry::PatternLanguage::addVisualizer("coordinates", drawCoordinateVisualizer, ParamCount::exactly(2));
|
ContentRegistry::PatternLanguage::addVisualizer("coordinates", drawCoordinateVisualizer, ParamCount::exactly(2));
|
||||||
ContentRegistry::PatternLanguage::addVisualizer("timestamp", drawTimestampVisualizer, ParamCount::exactly(1));
|
ContentRegistry::PatternLanguage::addVisualizer("timestamp", drawTimestampVisualizer, ParamCount::exactly(1));
|
||||||
ContentRegistry::PatternLanguage::addVisualizer("table", drawTableVisualizer, ParamCount::exactly(3));
|
ContentRegistry::PatternLanguage::addVisualizer("table", drawTableVisualizer, ParamCount::exactly(3));
|
||||||
|
ContentRegistry::PatternLanguage::addVisualizer("digital_signal", drawDigitalSignalVisualizer, ParamCount::exactly(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,100 @@
|
|||||||
|
#include <hex/helpers/utils.hpp>
|
||||||
|
|
||||||
|
#include <content/visualizer_helpers.hpp>
|
||||||
|
|
||||||
|
#include <implot.h>
|
||||||
|
#include <imgui.h>
|
||||||
|
#include <hex/helpers/logger.hpp>
|
||||||
|
|
||||||
|
#include <hex/ui/imgui_imhex_extensions.h>
|
||||||
|
#include <pl/patterns/pattern_bitfield.hpp>
|
||||||
|
|
||||||
|
namespace hex::plugin::visualizers {
|
||||||
|
|
||||||
|
void drawDigitalSignalVisualizer(pl::ptrn::Pattern &pattern, pl::ptrn::IIterable &iterable, bool shouldReset, std::span<const pl::core::Token::Literal>) {
|
||||||
|
auto *bitfield = dynamic_cast<pl::ptrn::PatternBitfield*>(&pattern);
|
||||||
|
if (bitfield == nullptr)
|
||||||
|
throw std::logic_error("Digital signal visualizer only works with bitfields.");
|
||||||
|
|
||||||
|
|
||||||
|
struct DataPoint {
|
||||||
|
std::array<ImVec2, 2> points;
|
||||||
|
std::string label;
|
||||||
|
std::string value;
|
||||||
|
ImColor color;
|
||||||
|
};
|
||||||
|
static std::vector<DataPoint> dataPoints;
|
||||||
|
static ImVec2 lastPoint;
|
||||||
|
|
||||||
|
if (shouldReset) {
|
||||||
|
dataPoints.clear();
|
||||||
|
lastPoint = { 0, 0 };
|
||||||
|
|
||||||
|
iterable.forEachEntry(0, iterable.getEntryCount(), [&](u64, pl::ptrn::Pattern *entry) {
|
||||||
|
size_t bitSize = 0;
|
||||||
|
if (auto bitfieldField = dynamic_cast<pl::ptrn::PatternBitfieldField*>(entry); bitfieldField != nullptr)
|
||||||
|
bitSize = bitfieldField->getBitSize();
|
||||||
|
else
|
||||||
|
bitSize = entry->getSize() * 8;
|
||||||
|
|
||||||
|
auto value = entry->getValue();
|
||||||
|
bool high = value.toUnsigned() > 0;
|
||||||
|
dataPoints.emplace_back(
|
||||||
|
std::array<ImVec2, 2> { lastPoint, { lastPoint.x, high ? 1.0F : 0.0F } },
|
||||||
|
entry->getDisplayName(),
|
||||||
|
entry->getFormattedValue(),
|
||||||
|
entry->getColor()
|
||||||
|
);
|
||||||
|
|
||||||
|
lastPoint = dataPoints.back().points[1];
|
||||||
|
lastPoint.x += bitSize;
|
||||||
|
});
|
||||||
|
|
||||||
|
dataPoints.push_back({
|
||||||
|
.points = { lastPoint, { lastPoint.x, 0 } },
|
||||||
|
.label = "",
|
||||||
|
.value = "",
|
||||||
|
.color = ImColor(0x00)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImPlot::BeginPlot("##Signal", ImVec2(600_scaled, 200_scaled), ImPlotFlags_NoLegend | ImPlotFlags_NoFrame | ImPlotFlags_NoMenus | ImPlotFlags_NoMouseText)) {
|
||||||
|
ImPlot::SetupAxisLimitsConstraints(ImAxis_X1, 0, lastPoint.x);
|
||||||
|
|
||||||
|
ImPlot::SetupAxis(ImAxis_Y1, "", ImPlotAxisFlags_LockMin | ImPlotAxisFlags_LockMax);
|
||||||
|
ImPlot::SetupAxisFormat(ImAxis_Y1, "");
|
||||||
|
ImPlot::SetupAxisLimits(ImAxis_Y1, -0.1F, 1.1F);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < dataPoints.size() - 1; i += 1) {
|
||||||
|
const auto &left = dataPoints[i];
|
||||||
|
const auto &right = dataPoints[i + 1];
|
||||||
|
|
||||||
|
{
|
||||||
|
auto x = left.points[1].x + (right.points[0].x - left.points[1].x) / 2;
|
||||||
|
ImPlot::Annotation(x, 0.55F, left.color, {}, false, "%s", left.label.c_str());
|
||||||
|
ImPlot::Annotation(x, 0.40F, left.color, {}, false, "%s", left.value.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ImVec2 min = ImPlot::PlotToPixels(ImPlotPoint(left.points[0].x, 0));
|
||||||
|
ImVec2 max = ImPlot::PlotToPixels(ImPlotPoint(right.points[1].x, 1));
|
||||||
|
|
||||||
|
ImPlot::PushPlotClipRect();
|
||||||
|
auto transparentColor = left.color;
|
||||||
|
transparentColor.Value.w = 0.4F;
|
||||||
|
ImPlot::GetPlotDrawList()->AddRectFilled(min, max, transparentColor);
|
||||||
|
ImPlot::PopPlotClipRect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImPlot::PushStyleVar(ImPlotStyleVar_LineWeight, 2_scaled);
|
||||||
|
ImPlot::PlotLineG("Signal", [](int idx, void*) -> ImPlotPoint {
|
||||||
|
return dataPoints[idx / 2].points[idx % 2];
|
||||||
|
}, nullptr, dataPoints.size() * 2);
|
||||||
|
ImPlot::PopStyleVar();
|
||||||
|
|
||||||
|
ImPlot::EndPlot();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user