ImHex/plugins/visualizers/source/content/pl_visualizers/image.cpp

132 lines
5.0 KiB
C++

#include <content/visualizer_helpers.hpp>
#include <hex/helpers/scaling.hpp>
#include <hex/helpers/auto_reset.hpp>
#include <imgui.h>
#include <hex/ui/imgui_imhex_extensions.h>
namespace hex::plugin::visualizers {
std::vector<u32> getIndices(pl::ptrn::Pattern *colorTablePattern, u64 width, u64 height);
ImGuiExt::Texture getTexture(pl::ptrn::Pattern *colorTablePattern, const std::vector<u32> &indices, u64 width, u64 height);
void drawImageVisualizer(pl::ptrn::Pattern &, bool shouldReset, std::span<const pl::core::Token::Literal> arguments) {
static AutoReset<ImGuiExt::Texture> texture;
static float scale = 1.0F;
if (shouldReset) {
auto pattern = arguments[0].toPattern();
auto data = pattern->getBytes();
texture = ImGuiExt::Texture::fromImage(data.data(), data.size(), ImGuiExt::Texture::Filter::Nearest);
scale = 200_scaled / texture->getSize().x;
}
if (texture.isValid())
ImGui::Image(*texture, texture->getSize() * scale);
if (ImGui::IsWindowHovered()) {
auto scrollDelta = ImGui::GetIO().MouseWheel;
if (scrollDelta != 0.0F) {
scale += scrollDelta * 0.1F;
scale = std::clamp(scale, 0.1F, 10.0F);
}
}
}
void drawBitmapVisualizer(pl::ptrn::Pattern &, bool shouldReset, std::span<const pl::core::Token::Literal> arguments) {
static AutoReset<ImGuiExt::Texture> texture;
static float scale = 1.0F;
if (shouldReset) {
auto pattern = arguments[0].toPattern();
auto width = u64(arguments[1].toUnsigned());
auto height = u64(arguments[2].toUnsigned());
bool hasColorTable = false;
if (arguments.size() == 4) {
auto colorTablePattern = arguments[3].toPattern();
if (colorTablePattern->getSize() > 0) {
auto indices = getIndices(pattern.get(), width, height);
texture = getTexture(colorTablePattern.get(), indices, width, height);
hasColorTable = true;
}
}
if (!hasColorTable) {
auto data = pattern->getBytes();
texture = ImGuiExt::Texture::fromBitmap(data.data(), data.size(), width, height, ImGuiExt::Texture::Filter::Nearest);
}
}
if (texture.isValid())
ImGui::Image(*texture, texture->getSize() * scale);
if (ImGui::IsWindowHovered()) {
auto scrollDelta = ImGui::GetIO().MouseWheel;
if (scrollDelta != 0.0F) {
scale += scrollDelta * 0.1F;
scale = std::clamp(scale, 0.1F, 10.0F);
}
}
}
ImGuiExt::Texture getTexture(pl::ptrn::Pattern *colorTablePattern, const std::vector<u32> &indices, u64 width, u64 height) {
std::vector<u32> colorTable = patternToArray<u32>(colorTablePattern);
auto colorCount = colorTable.size();
auto indexCount = indices.size();
std::vector<u32> image(indexCount);
for (u32 i = 0; i < indexCount; i++) {
auto index = indices[i];
if (index >= colorCount)
index = 0;
image[i] = colorTable[index];
}
void *tmp = image.data();
auto *data = static_cast<const ImU8 *>(tmp);
ImGuiExt::Texture texture = ImGuiExt::Texture::fromBitmap(data, indexCount*4, width, height, ImGuiExt::Texture::Filter::Nearest);
return texture;
}
std::vector<u32> getIndices(pl::ptrn::Pattern *pattern, u64 width, u64 height) {
auto indexCount = width * height / pattern->getSize();
std::vector<u32> indices;
const auto *iterable = dynamic_cast<pl::ptrn::IIterable *>(pattern);
if (iterable == nullptr || iterable->getEntryCount() == 0)
return indices;
auto content = iterable->getEntry(0);
auto byteCount = content->getSize();
if (byteCount >= indexCount && indexCount != 0) {
auto bytePerIndex = byteCount / indexCount;
if (bytePerIndex == 1) {
auto temp = patternToArray<u8>(pattern);
indices = std::vector<u32>(temp.begin(), temp.end());
} else if (bytePerIndex == 2) {
auto temp = patternToArray<u16>(pattern);
indices = std::vector<u32>(temp.begin(), temp.end());
} else // 32 bits indices make no sense.
return indices;
} else if (byteCount != 0) {
auto indicesPerByte = indexCount / byteCount;
auto temp = patternToArray<u8>(pattern);
if (indicesPerByte == 2) {
for (u32 i = 0; i < temp.size(); i++) {
indices.push_back(temp[i] & 0xF);
indices.push_back((temp[i] >> 4) & 0xF);
}
} else // 2 bits indices are too little
return indices;
}
return indices;
}
}