28 "2 bits per pixel - 4 colors, used for simple graphics and UI elements");
32 "3 bits per pixel - 8 colors, common for SNES sprites and tiles");
36 "4 bits per pixel - 16 colors, standard for SNES backgrounds");
40 "8 bits per pixel - 256 colors, high-color graphics and "
47 throw std::invalid_argument(
"Unknown BPP format");
58 const std::vector<uint8_t>& data,
BppFormat from_format,
59 BppFormat to_format,
int width,
int height) {
60 if (from_format == to_format) {
67 std::string cache_key =
72 return cache_iter->second;
75 std::vector<uint8_t> result;
78 std::vector<uint8_t> intermediate_data = data;
80 switch (from_format) {
91 intermediate_data = data;
109 result = intermediate_data;
113 result = intermediate_data;
129 const std::vector<uint8_t>& sheet_data,
int sheet_id,
134 return cache_it->second;
169 std::ostringstream history;
172 history <<
" -> Converted to "
193 int width,
int height) {
204 const std::vector<int>& used_colors) {
211 for (
int color_index : used_colors) {
212 if (color_index <
static_cast<int>(palette.
size()) &&
213 static_cast<int>(optimized_palette.
size()) < format_info.max_colors) {
214 optimized_palette.
AddColor(palette[color_index]);
219 while (
static_cast<int>(optimized_palette.
size()) < format_info.max_colors) {
220 if (
static_cast<int>(optimized_palette.
size()) <
221 static_cast<int>(palette.
size())) {
222 optimized_palette.
AddColor(palette[optimized_palette.
size()]);
229 return optimized_palette;
254 std::ostringstream key;
255 key << static_cast<int>(from_format) <<
"_" <<
static_cast<int>(to_format)
256 <<
"_" << width <<
"x" << height <<
"_" << data.size();
260 for (
size_t i = 0; i < std::min(data.size(),
size_t(1024)); ++i) {
261 hash = hash * 31 + data[i];
275 uint8_t max_color = 0;
276 for (uint8_t pixel : data) {
277 max_color = std::max(max_color, pixel);
287 if (max_color < 16) {
294 const std::vector<uint8_t>& data,
int width,
int height) {
295 std::vector<uint8_t> result(width * height);
297 for (
int row = 0; row < height; ++row) {
298 for (
int col = 0; col < width; col += 4) {
299 if (col / 4 <
static_cast<int>(data.size())) {
300 uint8_t
byte = data[row * (width / 4) + (col / 4)];
303 for (
int i = 0; i < 4 && (col + i) < width; ++i) {
304 uint8_t pixel = (
byte >> (6 - i * 2)) & 0x03;
305 result[row * width + col + i] = pixel;
315 const std::vector<uint8_t>& data,
int width,
int height) {
321 const std::vector<uint8_t>& data,
int width,
int height) {
322 std::vector<uint8_t> result(width * height);
324 for (
int row = 0; row < height; ++row) {
325 for (
int col = 0; col < width; col += 2) {
326 if (col / 2 <
static_cast<int>(data.size())) {
327 uint8_t
byte = data[row * (width / 2) + (col / 2)];
330 uint8_t pixel1 =
byte & 0x0F;
331 uint8_t pixel2 = (
byte >> 4) & 0x0F;
333 result[row * width + col] = pixel1;
334 if (col + 1 < width) {
335 result[row * width + col + 1] = pixel2;
345 const std::vector<uint8_t>& data,
int width,
int height) {
346 std::vector<uint8_t> result((width * height) / 4);
348 for (
int row = 0; row < height; ++row) {
349 for (
int col = 0; col < width; col += 4) {
353 for (
int i = 0; i < 4 && (col + i) < width; ++i) {
354 uint8_t pixel = data[row * width + col + i] & 0x03;
355 byte |= (pixel << (6 - i * 2));
358 result[row * (width / 4) + (col / 4)] = byte;
366 const std::vector<uint8_t>& data,
int width,
int height) {
374 const std::vector<uint8_t>& data,
int width,
int height) {
375 std::vector<uint8_t> result((width * height) / 2);
377 for (
int row = 0; row < height; ++row) {
378 for (
int col = 0; col < width; col += 2) {
379 uint8_t pixel1 = data[row * width + col] & 0x0F;
381 (col + 1 < width) ? (data[row * width + col + 1] & 0x0F) : 0;
383 uint8_t
byte = pixel1 | (pixel2 << 4);
384 result[row * (width / 2) + (col / 2)] = byte;
393 std::vector<bool> used_colors(max_colors,
false);
395 for (uint8_t pixel : data) {
396 if (pixel < max_colors) {
397 used_colors[pixel] =
true;
402 for (
bool used : used_colors) {
411 const std::vector<uint8_t>& original,
412 const std::vector<uint8_t>& compressed) {
413 if (compressed.empty())
415 return static_cast<float>(original.size()) /
416 static_cast<float>(compressed.size());
420 const std::vector<uint8_t>& data,
int width,
int height,
int tile_size) {
421 std::vector<int> usage_pattern;
422 int tiles_x = width / tile_size;
423 int tiles_y = height / tile_size;
425 for (
int tile_row = 0; tile_row < tiles_y; ++tile_row) {
426 for (
int tile_col = 0; tile_col < tiles_x; ++tile_col) {
427 int non_zero_pixels = 0;
430 for (
int row = 0; row < tile_size; ++row) {
431 for (
int col = 0; col < tile_size; ++col) {
432 int pixel_x = tile_col * tile_size + col;
433 int pixel_y = tile_row * tile_size + row;
434 int pixel_index = pixel_y * width + pixel_x;
436 if (pixel_index <
static_cast<int>(data.size()) &&
437 data[pixel_index] != 0) {
443 usage_pattern.push_back(non_zero_pixels);
447 return usage_pattern;
455 : from_format_(from_format),
456 to_format_(to_format),
459 timer_(
"bpp_convert_scope") {
460 std::ostringstream op_name;
461 op_name <<
"bpp_convert_" <<
static_cast<int>(from_format) <<
"_to_"
462 <<
static_cast<int>(to_format);
471 const std::vector<uint8_t>& data) {
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)
Graphics sheet analysis result.
std::string conversion_history
std::vector< int > tile_usage_pattern
BppFormat original_format