mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-29 06:17:48 +00:00
Extend RGBASM and RGBLINK verbosity flags to have multiple levels like RGBGFX (#1772)
This commit is contained in:
196
src/gfx/main.cpp
196
src/gfx/main.cpp
@@ -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();
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user