Extend RGBASM and RGBLINK verbosity flags to have multiple levels like RGBGFX (#1772)

This commit is contained in:
Rangi
2025-08-02 17:10:10 -04:00
committed by GitHub
parent b51056f743
commit 752b273aec
28 changed files with 688 additions and 347 deletions

View File

@@ -19,6 +19,7 @@
#include "file.hpp"
#include "platform.hpp"
#include "usage.hpp"
#include "verbosity.hpp"
#include "version.hpp"
#include "gfx/pal_spec.hpp"
@@ -40,18 +41,6 @@ static struct LocalOptions {
bool reverse;
} localOptions;
void Options::verbosePrint(uint8_t level, char const *fmt, ...) const {
// LCOV_EXCL_START
if (verbosity >= level) {
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
}
// LCOV_EXCL_STOP
}
// Short options
static char const *optstring = "-Aa:B:b:Cc:d:hi:L:l:mN:n:Oo:Pp:Qq:r:s:Tt:U:uVvW:wXx:YZ";
@@ -107,11 +96,12 @@ static Usage usage(
" [-o <out_file>] [-p <pal_file> | -P] [-q <pal_map> | -Q]\n"
" [-s <nb_colors>] [-t <tile_map> | -T] [-x <nb_tiles>] <file>\n"
"Useful options:\n"
" -m, --mirror-tiles optimize out mirrored tiles\n"
" -o, --output <path> output the tile data to this path\n"
" -t, --tilemap <path> output the tile map to this path\n"
" -u, --unique-tiles optimize out identical tiles\n"
" -V, --version print RGBGFX version and exit\n"
" -m, --mirror-tiles optimize out mirrored tiles\n"
" -o, --output <path> output the tile data to this path\n"
" -t, --tilemap <path> output the tile map to this path\n"
" -u, --unique-tiles optimize out identical tiles\n"
" -V, --version print RGBGFX version and exit\n"
" -W, --warning <warning> enable or disable warnings\n"
"\n"
"For help, use `man rgbgfx' or go to https://rgbds.gbdev.io/docs/\n"
);
@@ -536,9 +526,7 @@ static char *parseArgv(int argc, char *argv[]) {
// LCOV_EXCL_STOP
case 'v':
// LCOV_EXCL_START
if (options.verbosity < Options::VERB_VVVVVV) {
++options.verbosity;
}
incrementVerbosity();
break;
// LCOV_EXCL_STOP
case 'W':
@@ -580,93 +568,66 @@ static char *parseArgv(int argc, char *argv[]) {
return nullptr; // Done processing this argv
}
// LCOV_EXCL_START
static void verboseOutputConfig() {
fprintf(stderr, "rgbgfx %s\n", get_package_version_string());
if (options.verbosity >= Options::VERB_VVVVVV) {
putc('\n', stderr);
// clang-format off: vertically align values
static std::array<uint16_t, 21> gfx{
0b0111111110,
0b1111111111,
0b1110011001,
0b1110011001,
0b1111111111,
0b1111111111,
0b1110000001,
0b1111000011,
0b0111111110,
0b0001111000,
0b0111111110,
0b1111111111,
0b1111111111,
0b1111111111,
0b1101111011,
0b1101111011,
0b0011111100,
0b0011001100,
0b0111001110,
0b0111001110,
0b0111001110,
};
// clang-format on
static std::array<char const *, 3> textbox{
" ,----------------------------------------.",
" | Augh, dimensional interference again?! |",
" `----------------------------------------'",
};
for (size_t i = 0; i < gfx.size(); ++i) {
uint16_t row = gfx[i];
for (uint8_t _ = 0; _ < 10; ++_) {
unsigned char c = row & 1 ? '0' : ' ';
putc(c, stderr);
// Double the pixel horizontally, otherwise the aspect ratio looks wrong
putc(c, stderr);
row >>= 1;
}
if (i < textbox.size()) {
fputs(textbox[i], stderr);
}
putc('\n', stderr);
}
putc('\n', stderr);
if (!checkVerbosity(VERB_CONFIG)) {
return;
}
fprintf(stderr, "rgbgfx %s\n", get_package_version_string());
printVVVVVVerbosity();
fputs("Options:\n", stderr);
// -Z/--columns
if (options.columnMajor) {
fputs("\tVisit image in column-major order\n", stderr);
}
// -u/--unique-tiles
if (options.allowDedup) {
fputs("\tAllow deduplicating tiles\n", stderr);
fputs("\tAllow deduplicating identical tiles\n", stderr);
}
if (options.allowMirroringX) {
// -m/--mirror-tiles
if (options.allowMirroringX && options.allowMirroringY) {
fputs("\tAllow deduplicating mirrored tiles\n", stderr);
}
// -X/--mirror-x
else if (options.allowMirroringX) {
fputs("\tAllow deduplicating horizontally mirrored tiles\n", stderr);
}
if (options.allowMirroringY) {
// -Y/--mirror-y
else if (options.allowMirroringY) {
fputs("\tAllow deduplicating vertically mirrored tiles\n", stderr);
}
// -C/--color-curve
if (options.useColorCurve) {
fputs("\tUse color curve\n", stderr);
}
// -d/--depth
fprintf(stderr, "\tBit depth: %" PRIu8 "bpp\n", options.bitDepth);
// -x/--trim-end
if (options.trim != 0) {
fprintf(stderr, "\tTrim the last %" PRIu64 " tiles\n", options.trim);
}
// -n/--nb-palettes
fprintf(stderr, "\tMaximum %" PRIu16 " palettes\n", options.nbPalettes);
// -s/--palette-size
fprintf(stderr, "\tPalettes contain %" PRIu8 " colors\n", options.nbColorsPerPal);
fprintf(stderr, "\t%s palette spec\n", [] {
switch (options.palSpecType) {
case Options::NO_SPEC:
return "No";
case Options::EXPLICIT:
return "Explicit";
case Options::EMBEDDED:
return "Embedded";
case Options::DMG:
return "DMG";
}
return "???";
}());
// -c/--colors
if (options.palSpecType != Options::NO_SPEC) {
fprintf(stderr, "\t%s palette spec\n", [] {
switch (options.palSpecType) {
case Options::EXPLICIT:
return "Explicit";
case Options::EMBEDDED:
return "Embedded";
case Options::DMG:
return "DMG";
default:
return "???";
}
}());
}
if (options.palSpecType == Options::EXPLICIT) {
fputs("\t[\n", stderr);
for (auto const &pal : options.palSpec) {
@@ -682,40 +643,65 @@ static void verboseOutputConfig() {
}
fputs("\t]\n", stderr);
}
// -L/--slice
if (options.inputSlice.specified()) {
fprintf(
stderr,
"\tInput image slice: %" PRIu16 "x%" PRIu16 " pixels starting at (%" PRIu16 ", %" PRIu16
")\n",
options.inputSlice.width,
options.inputSlice.height,
options.inputSlice.left,
options.inputSlice.top
);
}
// -b/--base-tiles
if (options.baseTileIDs[0] || options.baseTileIDs[1]) {
fprintf(
stderr,
"\tBase tile IDs: bank 0 = 0x%02" PRIx8 ", bank 1 = 0x%02" PRIx8 "\n",
options.baseTileIDs[0],
options.baseTileIDs[1]
);
}
// -l/--base-palette
if (options.basePalID) {
fprintf(stderr, "\tBase palette ID: %" PRIu8 "\n", options.basePalID);
}
// -N/--nb-tiles
fprintf(
stderr,
"\tInput image slice: %" PRIu16 "x%" PRIu16 " pixels starting at (%" PRIu16 ", %" PRIu16
")\n",
options.inputSlice.width,
options.inputSlice.height,
options.inputSlice.left,
options.inputSlice.top
);
fprintf(
stderr,
"\tBase tile IDs: [%" PRIu8 ", %" PRIu8 "]\n",
options.baseTileIDs[0],
options.baseTileIDs[1]
);
fprintf(stderr, "\tBase palette ID: %" PRIu8 "\n", options.basePalID);
fprintf(
stderr,
"\tMaximum %" PRIu16 " tiles in bank 0, %" PRIu16 " in bank 1\n",
"\tMaximum %" PRIu16 " tiles in bank 0, and %" PRIu16 " in bank 1\n",
options.maxNbTiles[0],
options.maxNbTiles[1]
);
// -O/--group-outputs (influences other options)
auto printPath = [](char const *name, std::string const &path) {
if (!path.empty()) {
fprintf(stderr, "\t%s: %s\n", name, path.c_str());
}
};
// file
printPath("Input image", options.input);
// -i/--input-tileset
printPath("Input tileset", options.inputTileset);
// -o/--output
printPath("Output tile data", options.output);
// -t/--tilemap or -T/--auto-tilemap
printPath("Output tilemap", options.tilemap);
// -a/--attrmap or -A/--auto-attrmap
printPath("Output attrmap", options.attrmap);
// -p/--palette or -P/--auto-palette
printPath("Output palettes", options.palettes);
// -q/--palette-map or -Q/--auto-palette-map
printPath("Output palette map", options.palmap);
// -r/--reverse
if (localOptions.reverse) {
fprintf(stderr, "\tReverse image width: %" PRIu16 " tiles\n", options.reversedWidth);
}
fputs("Ready.\n", stderr);
}
// LCOV_EXCL_STOP
// Manual implementation of std::filesystem::path.replace_extension().
// macOS <10.15 did not support std::filesystem::path.
@@ -839,11 +825,7 @@ int main(int argc, char *argv[]) {
parseExternalPalSpec(localOptions.externalPalSpec);
}
// LCOV_EXCL_START
if (options.verbosity >= Options::VERB_CFG) {
verboseOutputConfig();
}
// LCOV_EXCL_STOP
verboseOutputConfig(); // LCOV_EXCL_LINE
// Do not do anything if option parsing went wrong.
requireZeroErrors();

View File

@@ -14,6 +14,7 @@
#include <utility>
#include "helpers.hpp"
#include "verbosity.hpp"
#include "gfx/color_set.hpp"
#include "gfx/main.hpp"
@@ -247,6 +248,10 @@ public:
static void verboseOutputAssignments(
std::vector<AssignedSets> const &assignments, std::vector<ColorSet> const &colorSets
) {
if (!checkVerbosity(VERB_INFO)) {
return;
}
for (AssignedSets const &assignment : assignments) {
fputs("{ ", stderr);
for (ColorSetAttrs const &attrs : assignment) {
@@ -284,9 +289,7 @@ static void decant(std::vector<AssignedSets> &assignments, std::vector<ColorSet>
}
};
options.verbosePrint(
Options::VERB_DEBUG, "%zu palettes before decanting\n", assignments.size()
);
verbosePrint(VERB_DEBUG, "%zu palettes before decanting\n", assignments.size());
// Decant on palettes
decantOn([&colorSets](AssignedSets &to, AssignedSets &from) {
@@ -298,9 +301,7 @@ static void decant(std::vector<AssignedSets> &assignments, std::vector<ColorSet>
from.clear();
}
});
options.verbosePrint(
Options::VERB_DEBUG, "%zu palettes after decanting on palettes\n", assignments.size()
);
verbosePrint(VERB_DEBUG, "%zu palettes after decanting on palettes\n", assignments.size());
// Decant on "components" (color sets sharing colors)
decantOn([&colorSets](AssignedSets &to, AssignedSets &from) {
@@ -344,8 +345,8 @@ static void decant(std::vector<AssignedSets> &assignments, std::vector<ColorSet>
}
}
});
options.verbosePrint(
Options::VERB_DEBUG, "%zu palettes after decanting on \"components\"\n", assignments.size()
verbosePrint(
VERB_DEBUG, "%zu palettes after decanting on \"components\"\n", assignments.size()
);
// Decant on individual color sets
@@ -357,15 +358,11 @@ static void decant(std::vector<AssignedSets> &assignments, std::vector<ColorSet>
}
}
});
options.verbosePrint(
Options::VERB_DEBUG, "%zu palettes after decanting on color sets\n", assignments.size()
);
verbosePrint(VERB_DEBUG, "%zu palettes after decanting on color sets\n", assignments.size());
}
std::tuple<std::vector<size_t>, size_t> overloadAndRemove(std::vector<ColorSet> const &colorSets) {
options.verbosePrint(
Options::VERB_LOG_ACT, "Paginating palettes using \"overload-and-remove\" strategy...\n"
);
verbosePrint(VERB_NOTICE, "Paginating palettes using \"overload-and-remove\" strategy...\n");
// Sort the color sets by size, which improves the packing algorithm's efficiency
auto const indexOfLargestColorSetFirst = [&colorSets](size_t left, size_t right) {
@@ -389,7 +386,7 @@ std::tuple<std::vector<size_t>, size_t> overloadAndRemove(std::vector<ColorSet>
!queue.empty();
queue.pop()) {
ColorSetAttrs const &attrs = queue.front(); // Valid until the `queue.pop()`
options.verbosePrint(Options::VERB_TRACE, "Handling color set %zu\n", attrs.colorSetIndex);
verbosePrint(VERB_TRACE, "Handling color set %zu\n", attrs.colorSetIndex);
ColorSet const &colorSet = colorSets[attrs.colorSetIndex];
size_t bestPalIndex = assignments.size();
@@ -404,8 +401,8 @@ std::tuple<std::vector<size_t>, size_t> overloadAndRemove(std::vector<ColorSet>
}
uint32_t relSize = assignments[i].relSizeOf(colorSet);
options.verbosePrint(
Options::VERB_TRACE,
verbosePrint(
VERB_TRACE,
" Relative size to palette %zu (of %zu): %" PRIu32 " (size = %zu)\n",
i,
assignments.size(),
@@ -420,8 +417,8 @@ std::tuple<std::vector<size_t>, size_t> overloadAndRemove(std::vector<ColorSet>
if (bestPalIndex == assignments.size()) {
// Found nowhere to put it, create a new page containing just that one
options.verbosePrint(
Options::VERB_TRACE,
verbosePrint(
VERB_TRACE,
"Assigning color set %zu to new palette %zu\n",
attrs.colorSetIndex,
bestPalIndex
@@ -430,8 +427,8 @@ std::tuple<std::vector<size_t>, size_t> overloadAndRemove(std::vector<ColorSet>
continue;
}
options.verbosePrint(
Options::VERB_TRACE,
verbosePrint(
VERB_TRACE,
"Assigning color set %zu to palette %zu\n",
attrs.colorSetIndex,
bestPalIndex
@@ -448,8 +445,8 @@ std::tuple<std::vector<size_t>, size_t> overloadAndRemove(std::vector<ColorSet>
uint32_t relSize1 = bestPal.relSizeOf(colorSet1);
uint32_t relSize2 = bestPal.relSizeOf(colorSet2);
options.verbosePrint(
Options::VERB_TRACE,
verbosePrint(
VERB_TRACE,
" Color sets %zu <=> %zu: Efficiency: %zu / %" PRIu32 " <=> %zu / "
"%" PRIu32 "\n",
attrs1.colorSetIndex,
@@ -470,8 +467,8 @@ std::tuple<std::vector<size_t>, size_t> overloadAndRemove(std::vector<ColorSet>
// If this overloads the palette, get it back to normal (if possible)
while (bestPal.volume() > options.maxOpaqueColors()) {
options.verbosePrint(
Options::VERB_TRACE,
verbosePrint(
VERB_TRACE,
"Palette %zu is overloaded! (%zu > %" PRIu8 ")\n",
bestPalIndex,
bestPal.volume(),
@@ -488,13 +485,13 @@ std::tuple<std::vector<size_t>, size_t> overloadAndRemove(std::vector<ColorSet>
// All efficiencies are identical iff min equals max
if (compareEfficiency(*minEfficiencyIter, *maxEfficiencyIter) == 0) {
options.verbosePrint(Options::VERB_TRACE, " All efficiencies are identical\n");
verbosePrint(VERB_TRACE, " All efficiencies are identical\n");
break;
}
// Remove the color set with minimal efficiency
options.verbosePrint(
Options::VERB_TRACE, " Removing color set %zu\n", minEfficiencyIter->colorSetIndex
verbosePrint(
VERB_TRACE, " Removing color set %zu\n", minEfficiencyIter->colorSetIndex
);
queue.emplace(std::move(*minEfficiencyIter));
queue.back().banFrom(bestPalIndex); // Ban it from this palette
@@ -526,16 +523,16 @@ std::tuple<std::vector<size_t>, size_t> overloadAndRemove(std::vector<ColorSet>
return pal.canFit(colorSet);
});
if (iter == assignments.end()) { // No such page, create a new one
options.verbosePrint(
Options::VERB_DEBUG,
verbosePrint(
VERB_DEBUG,
"Adding new palette (%zu) for overflowing color set %zu\n",
assignments.size(),
attrs.colorSetIndex
);
assignments.emplace_back(colorSets, std::move(attrs));
} else {
options.verbosePrint(
Options::VERB_DEBUG,
verbosePrint(
VERB_DEBUG,
"Assigning overflowing color set %zu to palette %zu\n",
attrs.colorSetIndex,
iter - assignments.begin()
@@ -544,21 +541,13 @@ std::tuple<std::vector<size_t>, size_t> overloadAndRemove(std::vector<ColorSet>
}
}
// LCOV_EXCL_START
if (options.verbosity >= Options::VERB_INTERM) {
verboseOutputAssignments(assignments, colorSets);
}
// LCOV_EXCL_STOP
verboseOutputAssignments(assignments, colorSets); // LCOV_EXCL_LINE
// "Decant" the result
decant(assignments, colorSets);
// Note that the result does not contain any empty palettes
// LCOV_EXCL_START
if (options.verbosity >= Options::VERB_INTERM) {
verboseOutputAssignments(assignments, colorSets);
}
// LCOV_EXCL_STOP
verboseOutputAssignments(assignments, colorSets); // LCOV_EXCL_LINE
std::vector<size_t> mappings(colorSets.size());
for (size_t i = 0; i < assignments.size(); ++i) {

View File

@@ -5,11 +5,12 @@
#include <algorithm>
#include "helpers.hpp"
#include "verbosity.hpp"
#include "gfx/main.hpp"
void sortIndexed(std::vector<Palette> &palettes, std::vector<Rgba> const &embPal) {
options.verbosePrint(Options::VERB_LOG_ACT, "Sorting palettes using embedded palette...\n");
verbosePrint(VERB_NOTICE, "Sorting palettes using embedded palette...\n");
for (Palette &pal : palettes) {
std::sort(RANGE(pal), [&](uint16_t lhs, uint16_t rhs) {
@@ -35,7 +36,7 @@ void sortIndexed(std::vector<Palette> &palettes, std::vector<Rgba> const &embPal
void sortGrayscale(
std::vector<Palette> &palettes, std::array<std::optional<Rgba>, NB_COLOR_SLOTS> const &colors
) {
options.verbosePrint(Options::VERB_LOG_ACT, "Sorting palette by grayscale bins...\n");
verbosePrint(VERB_NOTICE, "Sorting palette by grayscale bins...\n");
// This method is only applicable if there are at most as many colors as colors per palette, so
// we should only have a single palette.
@@ -59,7 +60,7 @@ static unsigned int luminance(uint16_t color) {
}
void sortRgb(std::vector<Palette> &palettes) {
options.verbosePrint(Options::VERB_LOG_ACT, "Sorting palettes by luminance...\n");
verbosePrint(VERB_NOTICE, "Sorting palettes by luminance...\n");
for (Palette &pal : palettes) {
// Sort from lightest to darkest

View File

@@ -4,6 +4,8 @@
#include <png.h>
#include "verbosity.hpp"
#include "gfx/main.hpp"
#include "gfx/rgba.hpp"
#include "gfx/warning.hpp"
@@ -47,7 +49,7 @@ static void readData(png_structp png, png_bytep data, size_t length) {
Png::Png(char const *filename, std::streambuf &file) {
Input input(filename, file);
options.verbosePrint(Options::VERB_LOG_ACT, "Reading PNG file \"%s\"\n", input.filename);
verbosePrint(VERB_NOTICE, "Reading PNG file \"%s\"\n", input.filename);
std::array<unsigned char, 8> pngHeader;
if (input.file.sgetn(reinterpret_cast<char *>(pngHeader.data()), pngHeader.size())
@@ -56,7 +58,7 @@ Png::Png(char const *filename, std::streambuf &file) {
fatal("File \"%s\" is not a valid PNG image", input.filename); // LCOV_EXCL_LINE
}
options.verbosePrint(Options::VERB_INTERM, "PNG header signature is OK\n");
verbosePrint(VERB_INFO, "PNG header signature is OK\n");
png_structp png = png_create_read_struct(
PNG_LIBPNG_VER_STRING, static_cast<png_voidp>(&input), handleError, handleWarning
@@ -110,8 +112,8 @@ Png::Png(char const *filename, std::streambuf &file) {
return "unknown interlace type";
}
};
options.verbosePrint(
Options::VERB_INTERM,
verbosePrint(
VERB_INFO,
"PNG image: %" PRIu32 "x%" PRIu32 " pixels, %dbpp %s, %s\n",
width,
height,
@@ -139,18 +141,15 @@ Png::Png(char const *filename, std::streambuf &file) {
);
}
options.verbosePrint(
Options::VERB_INTERM, "Embedded PNG palette has %d colors: [", nbColors
);
for (int i = 0; i < nbColors; ++i) {
if (i > 0) {
options.verbosePrint(Options::VERB_INTERM, ", ");
if (checkVerbosity(VERB_INFO)) {
fprintf(stderr, "Embedded PNG palette has %d colors: [", nbColors);
for (int i = 0; i < nbColors; ++i) {
fprintf(stderr, "%s#%08x", i > 0 ? ", " : "", palette[i].toCSS());
}
options.verbosePrint(Options::VERB_INTERM, "#%08x", palette[i].toCSS());
fprintf(stderr, "]\n");
}
options.verbosePrint(Options::VERB_INTERM, "]\n");
} else {
options.verbosePrint(Options::VERB_INTERM, "No embedded PNG palette\n");
verbosePrint(VERB_INFO, "No embedded PNG palette\n");
}
// Set up transformations to turn everything into RGBA8888 for simplicity of handling

View File

@@ -19,6 +19,7 @@
#include "file.hpp"
#include "helpers.hpp"
#include "itertools.hpp"
#include "verbosity.hpp"
#include "gfx/color_set.hpp"
#include "gfx/main.hpp"
@@ -79,8 +80,8 @@ struct Image {
bool isSuitableForGrayscale() const {
// Check that all of the grays don't fall into the same "bin"
if (colors.size() > options.maxOpaqueColors()) { // Apply the Pigeonhole Principle
options.verbosePrint(
Options::VERB_DEBUG,
verbosePrint(
VERB_DEBUG,
"Too many colors for grayscale sorting (%zu > %" PRIu8 ")\n",
colors.size(),
options.maxOpaqueColors()
@@ -93,8 +94,8 @@ struct Image {
continue;
}
if (!color->isGray()) {
options.verbosePrint(
Options::VERB_DEBUG,
verbosePrint(
VERB_DEBUG,
"Found non-gray color #%08x, not using grayscale sorting\n",
color->toCSS()
);
@@ -102,8 +103,8 @@ struct Image {
}
uint8_t mask = 1 << color->grayIndex();
if (bins & mask) { // Two in the same bin!
options.verbosePrint(
Options::VERB_DEBUG,
verbosePrint(
VERB_DEBUG,
"Color #%08x conflicts with another one, not using grayscale sorting\n",
color->toCSS()
);
@@ -336,7 +337,7 @@ static std::tuple<std::vector<size_t>, std::vector<Palette>>
assume(mappings.size() == colorSets.size());
// LCOV_EXCL_START
if (options.verbosity >= Options::VERB_INTERM) {
if (checkVerbosity(VERB_INFO)) {
fprintf(
stderr, "Color set mappings: (%zu palette%s)\n", nbPalettes, nbPalettes != 1 ? "s" : ""
);
@@ -438,7 +439,7 @@ static std::tuple<std::vector<size_t>, std::vector<Palette>>
static void outputPalettes(std::vector<Palette> const &palettes) {
// LCOV_EXCL_START
if (options.verbosity >= Options::VERB_INTERM) {
if (checkVerbosity(VERB_INFO)) {
for (Palette const &palette : palettes) {
fputs("{ ", stderr);
for (uint16_t colorIndex : palette) {
@@ -897,7 +898,7 @@ static void
}
void processPalettes() {
options.verbosePrint(Options::VERB_CFG, "Using libpng %s\n", png_get_libpng_ver(nullptr));
verbosePrint(VERB_CONFIG, "Using libpng %s\n", png_get_libpng_ver(nullptr));
std::vector<ColorSet> colorSets;
std::vector<Palette> palettes;
@@ -907,13 +908,13 @@ void processPalettes() {
}
void process() {
options.verbosePrint(Options::VERB_CFG, "Using libpng %s\n", png_get_libpng_ver(nullptr));
verbosePrint(VERB_CONFIG, "Using libpng %s\n", png_get_libpng_ver(nullptr));
options.verbosePrint(Options::VERB_LOG_ACT, "Reading tiles...\n");
verbosePrint(VERB_NOTICE, "Reading tiles...\n");
Image image(options.input); // This also sets `hasTransparentPixels` as a side effect
// LCOV_EXCL_START
if (options.verbosity >= Options::VERB_INTERM) {
if (checkVerbosity(VERB_INFO)) {
fputs("Image colors: [ ", stderr);
for (std::optional<Rgba> const &slot : image.colors) {
if (!slot.has_value()) {
@@ -1025,14 +1026,14 @@ void process() {
continue_visiting_tiles:;
}
options.verbosePrint(
Options::VERB_INTERM,
verbosePrint(
VERB_INFO,
"Image contains %zu color set%s\n",
colorSets.size(),
colorSets.size() != 1 ? "s" : ""
);
// LCOV_EXCL_START
if (options.verbosity >= Options::VERB_INTERM) {
if (checkVerbosity(VERB_INFO)) {
for (ColorSet const &colorSet : colorSets) {
fputs("[ ", stderr);
for (uint16_t color : colorSet) {
@@ -1074,20 +1075,19 @@ continue_visiting_tiles:;
}
if (!options.output.empty()) {
options.verbosePrint(Options::VERB_LOG_ACT, "Generating unoptimized tile data...\n");
verbosePrint(VERB_NOTICE, "Generating unoptimized tile data...\n");
outputUnoptimizedTileData(image, attrmap, palettes, mappings);
}
if (!options.tilemap.empty() || !options.attrmap.empty() || !options.palmap.empty()) {
options.verbosePrint(
Options::VERB_LOG_ACT,
"Generating unoptimized tilemap and/or attrmap and/or palmap...\n"
verbosePrint(
VERB_NOTICE, "Generating unoptimized tilemap and/or attrmap and/or palmap...\n"
);
outputUnoptimizedMaps(attrmap, mappings);
}
} else {
// All of these require the deduplication process to be performed to be output
options.verbosePrint(Options::VERB_LOG_ACT, "Deduplicating tiles...\n");
verbosePrint(VERB_NOTICE, "Deduplicating tiles...\n");
UniqueTiles tiles = dedupTiles(image, attrmap, palettes, mappings);
if (size_t nbTiles = tiles.size();
@@ -1101,22 +1101,22 @@ continue_visiting_tiles:;
}
if (!options.output.empty()) {
options.verbosePrint(Options::VERB_LOG_ACT, "Generating optimized tile data...\n");
verbosePrint(VERB_NOTICE, "Generating optimized tile data...\n");
outputTileData(tiles);
}
if (!options.tilemap.empty()) {
options.verbosePrint(Options::VERB_LOG_ACT, "Generating optimized tilemap...\n");
verbosePrint(VERB_NOTICE, "Generating optimized tilemap...\n");
outputTilemap(attrmap);
}
if (!options.attrmap.empty()) {
options.verbosePrint(Options::VERB_LOG_ACT, "Generating optimized attrmap...\n");
verbosePrint(VERB_NOTICE, "Generating optimized attrmap...\n");
outputAttrmap(attrmap, mappings);
}
if (!options.palmap.empty()) {
options.verbosePrint(Options::VERB_LOG_ACT, "Generating optimized palmap...\n");
verbosePrint(VERB_NOTICE, "Generating optimized palmap...\n");
outputPalmap(attrmap, mappings);
}
}

View File

@@ -15,6 +15,7 @@
#include "diagnostics.hpp"
#include "file.hpp"
#include "helpers.hpp" // assume
#include "verbosity.hpp"
#include "gfx/main.hpp"
#include "gfx/warning.hpp"
@@ -98,7 +99,7 @@ static void printPalette(std::array<std::optional<Rgba>, 4> const &palette) {
}
void reverse() {
options.verbosePrint(Options::VERB_CFG, "Using libpng %s\n", png_get_libpng_ver(nullptr));
verbosePrint(VERB_CONFIG, "Using libpng %s\n", png_get_libpng_ver(nullptr));
// Check for weird flag combinations
@@ -127,7 +128,7 @@ void reverse() {
);
}
options.verbosePrint(Options::VERB_LOG_ACT, "Reading tiles...\n");
verbosePrint(VERB_NOTICE, "Reading tiles...\n");
std::vector<uint8_t> const tiles = readInto(options.output);
uint8_t tileSize = 8 * options.bitDepth;
if (tiles.size() % tileSize != 0) {
@@ -140,13 +141,13 @@ void reverse() {
// By default, assume tiles are not deduplicated, and add the (allegedly) trimmed tiles
size_t const nbTiles = tiles.size() / tileSize;
options.verbosePrint(Options::VERB_INTERM, "Read %zu tiles.\n", nbTiles);
verbosePrint(VERB_INFO, "Read %zu tiles.\n", nbTiles);
size_t mapSize = nbTiles + options.trim; // Image size in tiles
std::optional<std::vector<uint8_t>> tilemap;
if (!options.tilemap.empty()) {
tilemap = readInto(options.tilemap);
mapSize = tilemap->size();
options.verbosePrint(Options::VERB_INTERM, "Read %zu tilemap entries.\n", mapSize);
verbosePrint(VERB_INFO, "Read %zu tilemap entries.\n", mapSize);
}
if (mapSize == 0) {
@@ -172,7 +173,7 @@ void reverse() {
break;
}
}
options.verbosePrint(Options::VERB_INTERM, "Picked reversing width of %zu tiles\n", width);
verbosePrint(VERB_INFO, "Picked reversing width of %zu tiles\n", width);
}
if (mapSize % width != 0) {
if (options.trim == 0 && !tilemap) {
@@ -192,9 +193,7 @@ void reverse() {
}
height = mapSize / width;
options.verbosePrint(
Options::VERB_INTERM, "Reversed image dimensions: %zux%zu tiles\n", width, height
);
verbosePrint(VERB_INFO, "Reversed image dimensions: %zux%zu tiles\n", width, height);
Rgba const grayColors[4] = {
Rgba(0xFFFFFFFF), Rgba(0xAAAAAAFF), Rgba(0x555555FF), Rgba(0x000000FF)
@@ -320,8 +319,8 @@ void reverse() {
}
}
options.verbosePrint(
Options::VERB_INTERM,
verbosePrint(
VERB_INFO,
"Number of tiles in bank {0: %" PRIu16 ", 1: %" PRIu16 "}\n",
nbTilesInBank[0],
nbTilesInBank[1]
@@ -404,7 +403,7 @@ void reverse() {
}
}
options.verbosePrint(Options::VERB_LOG_ACT, "Writing image...\n");
verbosePrint(VERB_NOTICE, "Writing image...\n");
File pngFile;
if (!pngFile.open(options.input, std::ios::out | std::ios::binary)) {
// LCOV_EXCL_START