11#include "imgui/imgui.h"
18 selected_format_(gfx::BppFormat::kBpp8),
19 preview_format_(gfx::BppFormat::kBpp8),
20 show_analysis_(false),
22 show_sheet_analysis_(false),
23 format_changed_(false),
24 last_analysis_sheet_(
"") {}
35 ImGui::Text(tr(
"BPP Format Selection"));
43 tr(
"Current Format: %s"),
47 ImGui::Text(tr(
"Target Format:"));
50 const char* format_names[] = {
"2BPP",
"3BPP",
"4BPP",
"8BPP"};
51 int current_selection =
54 if (ImGui::Combo(
"##BppFormat", ¤t_selection, format_names, 4)) {
60 const auto& format_info =
62 ImGui::Text(tr(
"Max Colors: %d"), format_info.max_colors);
63 ImGui::Text(tr(
"Bytes per Tile: %d"), format_info.bytes_per_tile);
64 ImGui::Text(tr(
"Description: %s"), format_info.description.c_str());
69 ImGui::Text(tr(
"Conversion Efficiency: %d%%"), efficiency);
71 ImVec4 efficiency_color;
72 if (efficiency >= 80) {
74 }
else if (efficiency >= 60) {
79 ImGui::TextColored(efficiency_color, tr(
"Quality: %s"),
80 efficiency >= 80 ?
"Excellent"
81 : efficiency >= 60 ?
"Good"
88 if (ImGui::Button(tr(
"Convert Format"))) {
89 if (on_format_changed) {
96 if (ImGui::Button(tr(
"Show Analysis"))) {
101 if (ImGui::Button(tr(
"Preview Conversion"))) {
130 tr(
"Detected Format: %s"),
134 std::vector<int> color_usage(256, 0);
135 for (uint8_t pixel : bitmap.
vector()) {
136 color_usage[pixel]++;
140 for (
int count : color_usage) {
145 ImGui::Text(tr(
"Colors Used: %d / %d"), used_colors,
146 static_cast<int>(palette.
size()));
147 ImGui::Text(tr(
"Color Efficiency: %.1f%%"),
148 (
static_cast<float>(used_colors) / palette.
size()) * 100.0f);
151 if (ImGui::CollapsingHeader(tr(
"Color Usage Chart"))) {
157 ImGui::Text(tr(
"Format Recommendations:"));
159 if (used_colors <= 4) {
160 ImGui::TextColored(
GetSuccessColor(), tr(
"✓ 2BPP format would be optimal"));
161 }
else if (used_colors <= 8) {
162 ImGui::TextColored(
GetSuccessColor(), tr(
"✓ 3BPP format would be optimal"));
163 }
else if (used_colors <= 16) {
164 ImGui::TextColored(
GetSuccessColor(), tr(
"✓ 4BPP format would be optimal"));
166 ImGui::TextColored(
GetWarningColor(), tr(
"⚠ 8BPP format is necessary"));
170 if (ImGui::CollapsingHeader(tr(
"Memory Usage Comparison"))) {
171 const auto& current_info =
174 (bitmap.
width() * bitmap.
height() * current_info.bits_per_pixel) / 8;
176 ImGui::Text(tr(
"Current Format (%s): %d bytes"), current_info.name.c_str(),
180 if (format == detected_format)
185 (bitmap.
width() * bitmap.
height() * info.bits_per_pixel) / 8;
186 float ratio =
static_cast<float>(format_bytes) / current_bytes;
188 ImGui::Text(tr(
"%s: %d bytes (%.1fx)"), info.name.c_str(), format_bytes,
204 if (current_format == target_format) {
205 ImGui::Text(tr(
"No conversion needed - formats are identical"));
212 bitmap.
vector(), current_format, target_format, bitmap.
width(),
217 converted_data, palette);
221 tr(
"Original (%s) vs Converted (%s)"),
225 ImGui::Columns(2,
"PreviewColumns");
228 ImGui::Text(tr(
"Original"));
231 ImGui::Image((ImTextureID)(intptr_t)bitmap.
texture(),
232 ImVec2(256, 256 * bitmap.
height() / bitmap.
width()));
238 ImGui::Text(tr(
"Converted"));
239 if (preview_bitmap.
texture()) {
242 (ImTextureID)(intptr_t)preview_bitmap.
texture(),
243 ImVec2(256, 256 * preview_bitmap.
height() / preview_bitmap.
width()));
250 ImGui::Text(tr(
"Conversion Statistics:"));
252 const auto& from_info =
254 const auto& to_info =
258 (bitmap.
width() * bitmap.
height() * from_info.bits_per_pixel) / 8;
260 (bitmap.
width() * bitmap.
height() * to_info.bits_per_pixel) / 8;
262 ImGui::Text(tr(
"Size: %d bytes -> %d bytes"), from_bytes, to_bytes);
263 ImGui::Text(tr(
"Compression Ratio: %.2fx"),
264 static_cast<float>(from_bytes) / to_bytes);
272 std::string analysis_key =
"sheet_" + std::to_string(sheet_id);
277 sheet_data, sheet_id, palette);
286 const auto& analysis = it->second;
290 ImGui::Text(tr(
"Sheet ID: %d"), analysis.sheet_id);
291 ImGui::Text(tr(
"Original Format: %s"),
293 .GetFormatInfo(analysis.original_format)
295 ImGui::Text(tr(
"Current Format: %s"),
297 .GetFormatInfo(analysis.current_format)
300 if (analysis.was_converted) {
301 ImGui::TextColored(
GetWarningColor(), tr(
"⚠ This sheet was converted"));
302 ImGui::Text(tr(
"Conversion History: %s"),
303 analysis.conversion_history.c_str());
305 ImGui::TextColored(
GetSuccessColor(), tr(
"✓ Original format preserved"));
309 ImGui::Text(tr(
"Color Usage: %d / %d colors used"),
310 analysis.palette_entries_used,
static_cast<int>(palette.
size()));
311 ImGui::Text(tr(
"Compression Ratio: %.2fx"), analysis.compression_ratio);
312 ImGui::Text(tr(
"Size: %zu -> %zu bytes"), analysis.original_size,
313 analysis.current_size);
316 if (ImGui::CollapsingHeader(tr(
"Tile Usage Pattern"))) {
317 int total_tiles = analysis.tile_usage_pattern.size();
321 for (
int usage : analysis.tile_usage_pattern) {
329 ImGui::Text(tr(
"Total Tiles: %d"), total_tiles);
330 ImGui::Text(tr(
"Used Tiles: %d (%.1f%%)"), used_tiles,
331 (
static_cast<float>(used_tiles) / total_tiles) * 100.0f);
332 ImGui::Text(tr(
"Empty Tiles: %d (%.1f%%)"), empty_tiles,
333 (
static_cast<float>(empty_tiles) / total_tiles) * 100.0f);
338 ImGui::Text(tr(
"Recommendations:"));
340 if (analysis.was_converted && analysis.palette_entries_used <= 16) {
343 tr(
"✓ Consider reverting to %s format for better compression"),
345 .GetFormatInfo(analysis.original_format)
349 if (analysis.palette_entries_used <
static_cast<int>(palette.
size()) / 2) {
352 tr(
"⚠ Palette is underutilized - consider optimization"));
361 return from_format != to_format;
367 if (from_format == to_format)
371 if (
static_cast<int>(from_format) >
static_cast<int>(to_format)) {
372 int bpp_diff =
static_cast<int>(from_format) -
static_cast<int>(to_format);
374 20, 100 - (bpp_diff * 20));
382 ImGui::Text(tr(
"Format: %s"), info.
name.c_str());
384 ImGui::Text(tr(
"Max Colors: %d"), info.
max_colors);
386 ImGui::Text(tr(
"Compressed: %s"), info.
is_compressed ?
"Yes" :
"No");
387 ImGui::Text(tr(
"Description: %s"), info.
description.c_str());
392 int max_usage = *std::max_element(color_usage.begin(), color_usage.end());
397 ImGui::Text(tr(
"Color Usage Distribution:"));
399 for (
size_t i = 0; i < std::min(color_usage.size(),
size_t(16)); ++i) {
400 if (color_usage[i] > 0) {
401 float usage_ratio =
static_cast<float>(color_usage[i]) / max_usage;
402 ImGui::Text(tr(
"Color %zu: %d pixels (%.1f%%)"), i, color_usage[i],
403 (
static_cast<float>(color_usage[i]) / (16 * 16)) * 100.0f);
405 ImGui::ProgressBar(usage_ratio, ImVec2(100, 0));
411 ImGui::Text(tr(
"Conversion History:"));
412 ImGui::TextWrapped(
"%s", history.c_str());
422 return ImVec4(1, 0, 0, 1);
424 return ImVec4(1, 1, 0, 1);
426 return ImVec4(0, 1, 0, 1);
428 return ImVec4(0, 0, 1, 1);
430 return ImVec4(1, 1, 1, 1);
444 target_format_(gfx::BppFormat::kBpp8),
445 preserve_palette_(true),
446 preview_valid_(false),
448 preview_scale_(1.0f) {}
464 ImGui::OpenPopup(
"BPP Format Conversion");
466 if (ImGui::BeginPopupModal(
"BPP Format Conversion", &
is_open_,
467 ImGuiWindowFlags_AlwaysAutoResize)) {
510 ImGui::Text(tr(
"Convert to BPP Format:"));
512 const char* format_names[] = {
"2BPP",
"3BPP",
"4BPP",
"8BPP"};
515 if (ImGui::Combo(
"##TargetFormat", ¤t_selection, format_names, 4)) {
520 const auto& format_info =
522 ImGui::Text(tr(
"Max Colors: %d"), format_info.max_colors);
523 ImGui::Text(tr(
"Description: %s"), format_info.description.c_str());
527 if (ImGui::Button(tr(
"Update Preview"))) {
534 ImGui::Text(tr(
"Preview:"));
552 if (ImGui::Button(tr(
"Convert"))) {
560 if (ImGui::Button(tr(
"Cancel"))) {
571 comparison_scale_(1.0f),
573 selected_comparison_(gfx::BppFormat::kBpp8) {}
587 ImGui::Begin(
"BPP Format Comparison", &
is_open_);
606 if (format == source_format) {
633 ImGui::Columns(2,
"ComparisonColumns");
640 const auto& bitmap = it->second;
641 const auto& format_info =
644 ImGui::Text(
"%s", format_info.name.c_str());
648 ImGui::Image((ImTextureID)(intptr_t)bitmap.
texture(),
659 ImGui::Text(tr(
"Format Metrics:"));
665 const auto& format_info =
669 ImGui::Text(
"%s: %s", format_info.name.c_str(), metrics.c_str());
674 ImGui::Text(tr(
"Selected for Analysis: "));
677 const char* format_names[] = {
"2BPP",
"3BPP",
"4BPP",
"8BPP"};
680 if (ImGui::Combo(
"##SelectedFormat", &selection, format_names, 4)) {
691 format_info.bits_per_pixel) /
694 std::ostringstream metrics;
695 metrics << bytes <<
" bytes, " << format_info.
max_colors <<
" colors";
697 return metrics.str();
Represents a bitmap image optimized for SNES ROM hacking.
TextureHandle texture() const
const std::vector< uint8_t > & vector() const
Represents a palette of colors for the Super Nintendo Entertainment System (SNES).
void RenderFormatSelector()
std::function< void(gfx::BppFormat, bool)> convert_callback_
BppConversionDialog(const std::string &id)
Constructor.
bool Render()
Render the dialog.
gfx::SnesPalette source_palette_
gfx::Bitmap source_bitmap_
void Show(const gfx::Bitmap &bitmap, const gfx::SnesPalette &palette, std::function< void(gfx::BppFormat, bool)> on_convert)
Show the conversion dialog.
gfx::Bitmap preview_bitmap_
gfx::BppFormat target_format_
RAII scope that samples the images drawn inside it with nearest-neighbor filtering.
BppFormat
BPP format enumeration for SNES graphics.
@ kBpp4
4 bits per pixel (16 colors)
@ kBpp3
3 bits per pixel (8 colors)
@ kBpp2
2 bits per pixel (4 colors)
@ kBpp8
8 bits per pixel (256 colors)
Graphics sheet analysis result.