28 "2 bits per pixel - 4 colors, used for simple graphics and UI elements"
33 "3 bits per pixel - 8 colors, common for SNES sprites and tiles"
38 "4 bits per pixel - 16 colors, standard for SNES backgrounds"
43 "8 bits per pixel - 256 colors, high-color graphics and converted formats"
50 throw std::invalid_argument(
"Unknown BPP format");
61 int width,
int height) {
62 if (from_format == to_format) {
69 std::string cache_key =
GenerateCacheKey(data, from_format, to_format, width, height);
73 return cache_iter->second;
76 std::vector<uint8_t> result;
79 std::vector<uint8_t> intermediate_data = data;
81 switch (from_format) {
92 intermediate_data = data;
110 result = intermediate_data;
114 result = intermediate_data;
135 return cache_it->second;
168 std::ostringstream history;
200 const std::vector<int>& used_colors) {
207 for (
int color_index : used_colors) {
208 if (color_index <
static_cast<int>(palette.
size()) &&
209 static_cast<int>(optimized_palette.
size()) < format_info.max_colors) {
210 optimized_palette.
AddColor(palette[color_index]);
215 while (
static_cast<int>(optimized_palette.
size()) < format_info.max_colors) {
216 if (
static_cast<int>(optimized_palette.
size()) <
static_cast<int>(palette.
size())) {
217 optimized_palette.
AddColor(palette[optimized_palette.
size()]);
224 return optimized_palette;
246 int width,
int height) {
247 std::ostringstream key;
248 key << static_cast<int>(from_format) <<
"_" <<
static_cast<int>(to_format)
249 <<
"_" << width <<
"x" << height <<
"_" << data.size();
253 for (
size_t i = 0; i < std::min(data.size(),
size_t(1024)); ++i) {
254 hash = hash * 31 + data[i];
267 uint8_t max_color = 0;
268 for (uint8_t pixel : data) {
269 max_color = std::max(max_color, pixel);
279 if (max_color < 16) {
286 std::vector<uint8_t> result(width * height);
288 for (
int row = 0; row < height; ++row) {
289 for (
int col = 0; col < width; col += 4) {
290 if (col / 4 <
static_cast<int>(data.size())) {
291 uint8_t
byte = data[row * (width / 4) + (col / 4)];
294 for (
int i = 0; i < 4 && (col + i) < width; ++i) {
295 uint8_t pixel = (
byte >> (6 - i * 2)) & 0x03;
296 result[row * width + col + i] = pixel;
311 std::vector<uint8_t> result(width * height);
313 for (
int row = 0; row < height; ++row) {
314 for (
int col = 0; col < width; col += 2) {
315 if (col / 2 <
static_cast<int>(data.size())) {
316 uint8_t
byte = data[row * (width / 2) + (col / 2)];
319 uint8_t pixel1 =
byte & 0x0F;
320 uint8_t pixel2 = (
byte >> 4) & 0x0F;
322 result[row * width + col] = pixel1;
323 if (col + 1 < width) {
324 result[row * width + col + 1] = pixel2;
334 std::vector<uint8_t> result((width * height) / 4);
336 for (
int row = 0; row < height; ++row) {
337 for (
int col = 0; col < width; col += 4) {
341 for (
int i = 0; i < 4 && (col + i) < width; ++i) {
342 uint8_t pixel = data[row * width + col + i] & 0x03;
343 byte |= (pixel << (6 - i * 2));
346 result[row * (width / 4) + (col / 4)] = byte;
361 std::vector<uint8_t> result((width * height) / 2);
363 for (
int row = 0; row < height; ++row) {
364 for (
int col = 0; col < width; col += 2) {
365 uint8_t pixel1 = data[row * width + col] & 0x0F;
366 uint8_t pixel2 = (col + 1 < width) ? (data[row * width + col + 1] & 0x0F) : 0;
368 uint8_t
byte = pixel1 | (pixel2 << 4);
369 result[row * (width / 2) + (col / 2)] = byte;
377 std::vector<bool> used_colors(max_colors,
false);
379 for (uint8_t pixel : data) {
380 if (pixel < max_colors) {
381 used_colors[pixel] =
true;
386 for (
bool used : used_colors) {
394 const std::vector<uint8_t>& compressed) {
395 if (compressed.empty())
return 1.0f;
396 return static_cast<float>(original.size()) /
static_cast<float>(compressed.size());
400 int width,
int height,
int tile_size) {
401 std::vector<int> usage_pattern;
402 int tiles_x = width / tile_size;
403 int tiles_y = height / tile_size;
405 for (
int tile_row = 0; tile_row < tiles_y; ++tile_row) {
406 for (
int tile_col = 0; tile_col < tiles_x; ++tile_col) {
407 int non_zero_pixels = 0;
410 for (
int row = 0; row < tile_size; ++row) {
411 for (
int col = 0; col < tile_size; ++col) {
412 int pixel_x = tile_col * tile_size + col;
413 int pixel_y = tile_row * tile_size + row;
414 int pixel_index = pixel_y * width + pixel_x;
416 if (pixel_index <
static_cast<int>(data.size()) && data[pixel_index] != 0) {
422 usage_pattern.push_back(non_zero_pixels);
426 return usage_pattern;
432 int width,
int height)
433 : from_format_(from_format), to_format_(to_format), width_(width), height_(height),
434 timer_(
"bpp_convert_scope") {
435 std::ostringstream op_name;
436 op_name <<
"bpp_convert_" <<
static_cast<int>(from_format)
437 <<
"_to_" <<
static_cast<int>(to_format);
BppConversionScope(BppFormat from_format, BppFormat to_format, int width, int height)
std::vector< uint8_t > Convert(const std::vector< uint8_t > &data)
std::string operation_name_
RAII timer for automatic timing management.
Represents a palette of colors for the Super Nintendo Entertainment System (SNES).
void AddColor(const SnesColor &color)
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)
Main namespace for the application.
Graphics sheet analysis result.
std::string conversion_history
std::vector< int > tile_usage_pattern
BppFormat original_format