fix: Problems with textures in 3d visualizer with bitmap visualizer. (#2167)

The bitmap visualizer has been simplified considerably. The previous version was designed to work with the TIM format which has some peculiarities that are not general enough. The current implementation has the following specifications.

. Whether colors are in a lookup table or part of the image itself they are always 32 bit R8G8B8A8.

. If using a color LUT the image then has indices as its element. Indices can have 16(32000 colors), 8 (256 colors) or 4(16 colors) bits each.

.For the cases 0f 16 and 8 bits, the data should be an array of N*M elements of the given size where N is the number of rows and M is the number of columns of the image.

. For the 4 bit case use an array of N*M/2 bytes so that each column contains two indices.

ToDo: Documentation, sample patterns and unit tests.

The 3-d visualizer can now handle textures from both the command line or the user interface and things should work as expected. A command line entry will be automatically displayed in the user interface, but changes will be applied immediately as you type or use the file picker. If the user interface text is deleted, then the command line texture will be used again.  If a texture is invalid for any reason, then the previous one, if any, will be still in use and an error message will be displayed until the problem is cleared. Valid textures are image files that the stb library can open.
This commit is contained in:
paxcut
2025-05-27 09:25:20 -07:00
committed by GitHub
parent a5eef3f34d
commit 702b5f2888
3 changed files with 40 additions and 46 deletions

View File

@@ -19,6 +19,7 @@
"hex.visualizers.pl_visualizer.3d.error_message_index_count": "Error: Index count must be a multiple of 3",
"hex.visualizers.pl_visualizer.3d.error_message_invalid_indices": "Error: Indices must be between 0 and the number of vertices minus one. Invalid indices: ",
"hex.visualizers.pl_visualizer.3d.error_message_for_vertex_count": " for {} vertices",
"hex.visualizers.pl_visualizer.3d.error_message_invalid_texture_file": "Error: Invalid texture file",
"hex.visualizers.pl_visualizer.3d.specular_brightness": "Specular Brightness",
"hex.visualizers.pl_visualizer.3d.object_reflectiveness": "Object Reflectiveness",
"hex.visualizers.pl_visualizer.3d.light_color": "Light Color",

View File

@@ -97,6 +97,7 @@ namespace hex::plugin::visualizers {
AutoReset<ImGuiExt::Texture> s_texture;
std::fs::path s_texturePath;
std::string s_errorMessage="";
u32 s_vertexCount;
@@ -602,9 +603,16 @@ namespace hex::plugin::visualizers {
// Draw more settings
if (ImGui::CollapsingHeader("hex.visualizers.pl_visualizer.3d.more_settings"_lang)) {
if (ImGuiExt::InputFilePicker("hex.visualizers.pl_visualizer.3d.texture_file"_lang, s_texturePath, {}))
if (ImGuiExt::InputFilePicker("hex.visualizers.pl_visualizer.3d.texture_file"_lang, s_texturePath, {}) || ImGui::IsItemDeactivatedAfterEdit())
s_shouldUpdateTexture = true;
}
if (s_errorMessage != "") {
auto color = ImGui::GetColorU32(ImVec4(1.0F, 0.0F, 0.0F, 1.0F));
ImGui::PushStyleColor(ImGuiCol_Text,color);
ImGui::TextUnformatted(s_errorMessage.c_str());
ImGui::PopStyleColor();
return;
}
}
}
@@ -798,13 +806,22 @@ namespace hex::plugin::visualizers {
shader.setUniform("lightColor", s_lightColor);
vertexArray.bind();
if (s_shouldUpdateTexture) {
if (s_shouldUpdateTexture && !s_texturePath.empty()) {
s_shouldUpdateTexture = false;
s_modelTexture = ImGuiExt::Texture::fromImage(s_texturePath, ImGuiExt::Texture::Filter::Nearest);
if (s_modelTexture.isValid()) {
s_drawTexture = true;
}
}
AutoReset<ImGuiExt::Texture> tempTexture = ImGuiExt::Texture::fromImage(s_texturePath, ImGuiExt::Texture::Filter::Nearest);
if (tempTexture.isValid()) {
const ImGuiExt::Texture &modelTexture = tempTexture.operator*();
if (modelTexture.isValid()) {
s_modelTexture = std::move(tempTexture.operator*());
s_drawTexture = true;
s_errorMessage = "";
} else
s_errorMessage = "hex.visualizers.pl_visualizer.3d.error_message_invalid_texture_file"_lang.get();
} else
s_errorMessage = "hex.visualizers.pl_visualizer.3d.error_message_invalid_texture_file"_lang.get();
} else if (s_texturePath.empty())
s_errorMessage = "";
if (s_drawTexture)
glBindTexture(GL_TEXTURE_2D, *s_modelTexture);
@@ -914,8 +931,11 @@ namespace hex::plugin::visualizers {
}
}
}
s_texturePath = textureFile;
if (!textureFile.empty() && s_texturePath.empty()) {
s_texturePath = textureFile;
s_shouldUpdateTexture = true;
} else if (!s_texturePath.empty())
textureFile = s_texturePath.string();
s_drawTexture = !textureFile.empty();
if (shouldReset)
s_shouldReset = true;

View File

@@ -75,11 +75,11 @@ namespace hex::plugin::visualizers {
}
}
template <typename T> ImGuiExt::Texture unmapColors(pl::ptrn::Pattern *colorTablePattern, std::vector<u32>& indices, u64 width, u64 height) {
std::vector<T> colorTable = patternToArray<T>(colorTablePattern);
ImGuiExt::Texture getTexture(pl::ptrn::Pattern *colorTablePattern, 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<T> image(indexCount);
std::vector<u32> image(indexCount);
for (u32 i = 0; i < indexCount; i++) {
auto index = indices[i];
@@ -90,12 +90,12 @@ namespace hex::plugin::visualizers {
}
void *tmp = image.data();
ImU8 *data = static_cast<ImU8 *>(tmp);
ImGuiExt::Texture texture = ImGuiExt::Texture::fromBitmap(data, indexCount*sizeof(T), width, height, ImGuiExt::Texture::Filter::Nearest);
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 = 2 * width * height / pattern->getSize();
auto indexCount = width * height / pattern->getSize();
std::vector<u32> indices;
auto *iterable = dynamic_cast<pl::ptrn::IIterable *>(pattern);
@@ -113,11 +113,9 @@ namespace hex::plugin::visualizers {
} else if (bytePerIndex == 2) {
auto temp = patternToArray<u16>(pattern);
indices = std::vector<u32>(temp.begin(), temp.end());
} else if (bytePerIndex == 4) {
auto temp = patternToArray<u32>(pattern);
indices = std::vector<u32>(temp.begin(), temp.end());
}
} else if (indexCount != 0) {
} else // 32 bits indices make no sense.
return indices;
} else if (byteCount != 0) {
auto indicesPerByte = indexCount / byteCount;
auto temp = patternToArray<u8>(pattern);
@@ -126,34 +124,9 @@ namespace hex::plugin::visualizers {
indices.push_back(temp[i] & 0xF);
indices.push_back((temp[i] >> 4) & 0xF);
}
} else if (indicesPerByte == 4) {
for (u32 i = 0; i < temp.size(); i++) {
indices.push_back(temp[i] & 0x3);
indices.push_back((temp[i] >> 2) & 0x3);
indices.push_back((temp[i] >> 4) & 0x3);
indices.push_back((temp[i] >> 6) & 0x3);
}
}
} else // 2 bits indices are too little
return indices;
}
return indices;
}
ImGuiExt::Texture getTexture(pl::ptrn::Pattern *colorTablePattern, std::vector<u32>& indices, u64 width, u64 height) {
ImGuiExt::Texture texture;
auto iterable = dynamic_cast<pl::ptrn::IIterable *>(colorTablePattern);
if (iterable == nullptr || iterable->getEntryCount() <= 0)
return texture;
auto content = iterable->getEntry(0);
auto colorTypeSize = content->getSize()*2;
if (colorTypeSize == 1) {
texture = unmapColors<u8>(colorTablePattern, indices, width, height);
} else if (colorTypeSize == 2) {
texture = unmapColors<u16>(colorTablePattern, indices, width, height);
} else if (colorTypeSize == 4) {
texture = unmapColors<u32>(colorTablePattern, indices, width, height);
}
return texture;
}
}