Revert "Switch to using std::filesystem (#1235)"

This reverts commit cf62ff772f.
Some functions used by this break on macOS before 10.15,
which we want to keep supporting.
This commit is contained in:
ISSOtm
2023-12-30 20:31:13 +01:00
committed by Rangi
parent 93d1d85f94
commit 6b559e99b2
5 changed files with 105 additions and 103 deletions

View File

@@ -7,7 +7,6 @@
#include <assert.h> #include <assert.h>
#include <cassert> #include <cassert>
#include <fcntl.h> #include <fcntl.h>
#include <filesystem>
#include <fstream> #include <fstream>
#include <ios> #include <ios>
#include <iostream> #include <iostream>
@@ -42,7 +41,7 @@ public:
* This should only be called once, and before doing any `->` operations. * This should only be called once, and before doing any `->` operations.
* Returns `nullptr` on error, and a non-null pointer otherwise. * Returns `nullptr` on error, and a non-null pointer otherwise.
*/ */
File *open(std::filesystem::path const &path, std::ios_base::openmode mode) { File *open(std::string const &path, std::ios_base::openmode mode) {
if (path != "-") { if (path != "-") {
return _file.emplace<std::filebuf>().open(path, mode) ? this : nullptr; return _file.emplace<std::filebuf>().open(path, mode) ? this : nullptr;
} else if (mode & std::ios_base::in) { } else if (mode & std::ios_base::in) {
@@ -86,11 +85,11 @@ public:
: nullptr; : nullptr;
} }
std::string string(std::filesystem::path const &path) const { char const *c_str(std::string const &path) const {
return std::visit(Visitor{[&path](std::filebuf const &) { return path.string(); }, return std::visit(Visitor{[&path](std::filebuf const &) { return path.c_str(); },
[](std::streambuf const *buf) { [](std::streambuf const *buf) {
return std::string{buf == std::cin.rdbuf() return buf == std::cin.rdbuf()
? "<stdin>" : "<stdout>"}; ? "<stdin>" : "<stdout>";
}}, }},
_file); _file);
} }

View File

@@ -4,9 +4,7 @@
#define RGBDS_GFX_MAIN_HPP #define RGBDS_GFX_MAIN_HPP
#include <array> #include <array>
#include <filesystem>
#include <limits.h> #include <limits.h>
#include <optional>
#include <stdint.h> #include <stdint.h>
#include <string> #include <string>
#include <utility> #include <utility>
@@ -26,7 +24,7 @@ struct Options {
bool columnMajor = false; // -Z, previously -h bool columnMajor = false; // -Z, previously -h
uint8_t verbosity = 0; // -v uint8_t verbosity = 0; // -v
std::optional<std::filesystem::path> attrmap{}; // -a, -A std::string attrmap{}; // -a, -A
std::array<uint8_t, 2> baseTileIDs{0, 0}; // -b std::array<uint8_t, 2> baseTileIDs{0, 0}; // -b
enum { enum {
NO_SPEC, NO_SPEC,
@@ -43,14 +41,14 @@ struct Options {
} inputSlice{0, 0, 0, 0}; // -L (margins in clockwise order, like CSS) } inputSlice{0, 0, 0, 0}; // -L (margins in clockwise order, like CSS)
std::array<uint16_t, 2> maxNbTiles{UINT16_MAX, 0}; // -N std::array<uint16_t, 2> maxNbTiles{UINT16_MAX, 0}; // -N
uint8_t nbPalettes = 8; // -n uint8_t nbPalettes = 8; // -n
std::optional<std::filesystem::path> output{}; // -o std::string output{}; // -o
std::optional<std::filesystem::path> palettes{}; // -p, -P std::string palettes{}; // -p, -P
std::optional<std::filesystem::path> palmap{}; // -q, -Q std::string palmap{}; // -q, -Q
uint8_t nbColorsPerPal = 0; // -s; 0 means "auto" = 1 << bitDepth; uint8_t nbColorsPerPal = 0; // -s; 0 means "auto" = 1 << bitDepth;
std::optional<std::filesystem::path> tilemap{}; // -t, -T std::string tilemap{}; // -t, -T
uint64_t trim = 0; // -x uint64_t trim = 0; // -x
std::optional<std::filesystem::path> input{}; // positional arg std::string input{}; // positional arg
static constexpr uint8_t VERB_NONE = 0; // Normal, no extra output static constexpr uint8_t VERB_NONE = 0; // Normal, no extra output
static constexpr uint8_t VERB_CFG = 1; // Print configuration after parsing options static constexpr uint8_t VERB_CFG = 1; // Print configuration after parsing options

View File

@@ -7,12 +7,10 @@
#include <cinttypes> #include <cinttypes>
#include <cstdint> #include <cstdint>
#include <ctype.h> #include <ctype.h>
#include <filesystem>
#include <fstream> #include <fstream>
#include <ios> #include <ios>
#include <limits> #include <limits>
#include <numeric> #include <numeric>
#include <optional>
#include <stdarg.h> #include <stdarg.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
@@ -240,11 +238,11 @@ static void skipWhitespace(char *&arg) {
} }
static void registerInput(char const *arg) { static void registerInput(char const *arg) {
if (options.input.has_value()) { if (!options.input.empty()) {
fprintf(stderr, fprintf(stderr,
"FATAL: input image specified more than once! (first \"%s\", then " "FATAL: input image specified more than once! (first \"%s\", then "
"\"%s\")\n", "\"%s\")\n",
options.input->c_str(), arg); options.input.c_str(), arg);
printUsage(); printUsage();
exit(1); exit(1);
} else if (arg[0] == '\0') { // Empty input path } else if (arg[0] == '\0') { // Empty input path
@@ -252,7 +250,7 @@ static void registerInput(char const *arg) {
printUsage(); printUsage();
exit(1); exit(1);
} else { } else {
options.input.emplace(arg); options.input = arg;
} }
} }
@@ -260,11 +258,10 @@ static void registerInput(char const *arg) {
* Turn an "at-file"'s contents into an argv that `getopt` can handle * Turn an "at-file"'s contents into an argv that `getopt` can handle
* @param argPool Argument characters will be appended to this vector, for storage purposes. * @param argPool Argument characters will be appended to this vector, for storage purposes.
*/ */
static std::vector<size_t> readAtFile(std::filesystem::path const &path, static std::vector<size_t> readAtFile(std::string const &path, std::vector<char> &argPool) {
std::vector<char> &argPool) {
File file; File file;
if (!file.open(path, std::ios_base::in)) { if (!file.open(path, std::ios_base::in)) {
fatal("Error reading @%s: %s", file.string(path).c_str(), strerror(errno)); fatal("Error reading @%s: %s", file.c_str(path), strerror(errno));
} }
// We only filter out `EOF`, but calling `isblank()` on anything else is UB! // We only filter out `EOF`, but calling `isblank()` on anything else is UB!
@@ -349,8 +346,8 @@ static char *parseArgv(int argc, char **argv) {
break; break;
case 'a': case 'a':
localOptions.autoAttrmap = false; localOptions.autoAttrmap = false;
if (options.attrmap.has_value()) if (!options.attrmap.empty())
warning("Overriding attrmap file %s", options.attrmap->c_str()); warning("Overriding attrmap file %s", options.attrmap.c_str());
options.attrmap = musl_optarg; options.attrmap = musl_optarg;
break; break;
case 'b': case 'b':
@@ -496,8 +493,8 @@ static char *parseArgv(int argc, char **argv) {
localOptions.groupOutputs = true; localOptions.groupOutputs = true;
break; break;
case 'o': case 'o':
if (options.output.has_value()) if (!options.output.empty())
warning("Overriding tile data file %s", options.output->c_str()); warning("Overriding tile data file %s", options.output.c_str());
options.output = musl_optarg; options.output = musl_optarg;
break; break;
case -'P': case -'P':
@@ -508,8 +505,8 @@ static char *parseArgv(int argc, char **argv) {
break; break;
case 'p': case 'p':
localOptions.autoPalettes = false; localOptions.autoPalettes = false;
if (options.palettes.has_value()) if (!options.palettes.empty())
warning("Overriding palettes file %s", options.palettes->c_str()); warning("Overriding palettes file %s", options.palettes.c_str());
options.palettes = musl_optarg; options.palettes = musl_optarg;
break; break;
case -'Q': case -'Q':
@@ -520,8 +517,8 @@ static char *parseArgv(int argc, char **argv) {
break; break;
case 'q': case 'q':
localOptions.autoPalmap = false; localOptions.autoPalmap = false;
if (options.palmap.has_value()) if (!options.palmap.empty())
warning("Overriding palette map file %s", options.palmap->c_str()); warning("Overriding palette map file %s", options.palmap.c_str());
options.palmap = musl_optarg; options.palmap = musl_optarg;
break; break;
case 'r': case 'r':
@@ -552,8 +549,8 @@ static char *parseArgv(int argc, char **argv) {
break; break;
case 't': case 't':
localOptions.autoTilemap = false; localOptions.autoTilemap = false;
if (options.tilemap.has_value()) if (!options.tilemap.empty())
warning("Overriding tilemap file %s", options.tilemap->c_str()); warning("Overriding tilemap file %s", options.tilemap.c_str());
options.tilemap = musl_optarg; options.tilemap = musl_optarg;
break; break;
case 'V': case 'V':
@@ -658,17 +655,36 @@ int main(int argc, char *argv[]) {
1u << options.bitDepth, options.nbColorsPerPal); 1u << options.bitDepth, options.nbColorsPerPal);
} }
auto autoOutPath = [](bool autoOptEnabled, std::optional<std::filesystem::path> &path, auto autoOutPath = [](bool autoOptEnabled, std::string &path, char const *extension) {
char const *extension) {
if (autoOptEnabled) { if (autoOptEnabled) {
auto image = localOptions.groupOutputs ? options.output : options.input; auto &image = localOptions.groupOutputs ? options.output : options.input;
if (!image.has_value()) { if (image.empty()) {
fprintf(stderr, "FATAL: No %s specified\n", localOptions.groupOutputs fprintf(stderr, "FATAL: No %s specified\n", localOptions.groupOutputs
? "output tile data file" : "input image"); ? "output tile data file" : "input image");
printUsage(); printUsage();
exit(1); exit(1);
} }
path.emplace(*image).replace_extension(extension);
// Manual implementation of std::filesystem::path.replace_extension().
constexpr std::string_view chars =
// Both must start with a dot!
#if defined(_MSC_VER) || defined(__MINGW32__)
"./\\"sv;
#else
"./"sv;
#endif
size_t len = image.npos;
size_t i = image.find_last_of(chars);
if (i != image.npos && image[i] == '.') {
// We found the last dot, but check if it's part of a stem
// (There must be a non-path separator character before it)
if (i != 0 && chars.find(image[i - 1], 1) == chars.npos) {
// We can replace the extension
len = i;
}
}
path.assign(image, 0, len);
path.append(extension);
} }
}; };
autoOutPath(localOptions.autoAttrmap, options.attrmap, ".attrmap"); autoOutPath(localOptions.autoAttrmap, options.attrmap, ".attrmap");
@@ -753,10 +769,9 @@ int main(int argc, char *argv[]) {
options.baseTileIDs[1]); options.baseTileIDs[1]);
fprintf(stderr, "\tMaximum %" PRIu16 " tiles in bank 0, %" PRIu16 " in bank 1\n", fprintf(stderr, "\tMaximum %" PRIu16 " tiles in bank 0, %" PRIu16 " in bank 1\n",
options.maxNbTiles[0], options.maxNbTiles[1]); options.maxNbTiles[0], options.maxNbTiles[1]);
auto printPath = [](char const *name, auto printPath = [](char const *name, std::string const &path) {
std::optional<std::filesystem::path> const &path) { if (!path.empty()) {
if (path.has_value()) { fprintf(stderr, "\t%s: %s\n", name, path.c_str());
fprintf(stderr, "\t%s: %s\n", name, path->c_str());
} }
}; };
printPath("Input image", options.input); printPath("Input image", options.input);
@@ -772,13 +787,13 @@ int main(int argc, char *argv[]) {
giveUp(); giveUp();
} }
if (options.input.has_value()) { if (!options.input.empty()) {
if (options.reverse()) { if (options.reverse()) {
reverse(); reverse();
} else { } else {
process(); process();
} }
} else if (options.palettes.has_value() && options.palSpecType == Options::EXPLICIT } else if (!options.palettes.empty() && options.palSpecType == Options::EXPLICIT
&& !options.reverse()) { && !options.reverse()) {
processPalettes(); processPalettes();
} else { } else {

View File

@@ -8,7 +8,6 @@
#include <climits> #include <climits>
#include <cstdio> #include <cstdio>
#include <errno.h> #include <errno.h>
#include <filesystem>
#include <fstream> #include <fstream>
#include <memory> #include <memory>
#include <optional> #include <optional>
@@ -72,7 +71,7 @@ public:
}; };
class Png { class Png {
std::filesystem::path const &path; std::string const &path;
File file{}; File file{};
png_structp png = nullptr; png_structp png = nullptr;
png_infop info = nullptr; png_infop info = nullptr;
@@ -89,13 +88,13 @@ class Png {
[[noreturn]] static void handleError(png_structp png, char const *msg) { [[noreturn]] static void handleError(png_structp png, char const *msg) {
Png *self = reinterpret_cast<Png *>(png_get_error_ptr(png)); Png *self = reinterpret_cast<Png *>(png_get_error_ptr(png));
fatal("Error reading input image (\"%s\"): %s", self->string().c_str(), msg); fatal("Error reading input image (\"%s\"): %s", self->c_str(), msg);
} }
static void handleWarning(png_structp png, char const *msg) { static void handleWarning(png_structp png, char const *msg) {
Png *self = reinterpret_cast<Png *>(png_get_error_ptr(png)); Png *self = reinterpret_cast<Png *>(png_get_error_ptr(png));
warning("In input image (\"%s\"): %s", self->string().c_str(), msg); warning("In input image (\"%s\"): %s", self->c_str(), msg);
} }
static void readData(png_structp png, png_bytep data, size_t length) { static void readData(png_structp png, png_bytep data, size_t length) {
@@ -107,7 +106,7 @@ class Png {
if (nbBytesRead != expectedLen) { if (nbBytesRead != expectedLen) {
fatal("Error reading input image (\"%s\"): file too short (expected at least %zd more " fatal("Error reading input image (\"%s\"): file too short (expected at least %zd more "
"bytes after reading %lld)", "bytes after reading %lld)",
self->string().c_str(), length - nbBytesRead, self->c_str(), length - nbBytesRead,
self->file->pubseekoff(0, std::ios_base::cur)); self->file->pubseekoff(0, std::ios_base::cur));
} }
} }
@@ -129,7 +128,7 @@ public:
Rgba const &pixel(uint32_t x, uint32_t y) const { return pixels[y * width + x]; } Rgba const &pixel(uint32_t x, uint32_t y) const { return pixels[y * width + x]; }
std::string string() const { return file.string(path); } char const *c_str() const { return file.c_str(path); }
bool isSuitableForGrayscale() const { bool isSuitableForGrayscale() const {
// Check that all of the grays don't fall into the same "bin" // Check that all of the grays don't fall into the same "bin"
@@ -172,9 +171,9 @@ public:
* We also use that occasion to only read the PNG one line at a time, since we store all of * We also use that occasion to only read the PNG one line at a time, since we store all of
* the pixel data in `pixels`, which saves on memory allocations. * the pixel data in `pixels`, which saves on memory allocations.
*/ */
explicit Png(std::filesystem::path const &filePath) : path(filePath), colors() { explicit Png(std::string const &filePath) : path(filePath), colors() {
if (file.open(path, std::ios_base::in | std::ios_base::binary) == nullptr) { if (file.open(path, std::ios_base::in | std::ios_base::binary) == nullptr) {
fatal("Failed to open input image (\"%s\"): %s", file.string(path).c_str(), fatal("Failed to open input image (\"%s\"): %s", file.c_str(path),
strerror(errno)); strerror(errno));
} }
@@ -185,7 +184,7 @@ public:
if (file->sgetn(reinterpret_cast<char *>(pngHeader.data()), pngHeader.size()) if (file->sgetn(reinterpret_cast<char *>(pngHeader.data()), pngHeader.size())
!= static_cast<std::streamsize>(pngHeader.size()) // Not enough bytes? != static_cast<std::streamsize>(pngHeader.size()) // Not enough bytes?
|| png_sig_cmp(pngHeader.data(), 0, pngHeader.size()) != 0) { || png_sig_cmp(pngHeader.data(), 0, pngHeader.size()) != 0) {
fatal("Input file (\"%s\") is not a PNG image!", file.string(path).c_str()); fatal("Input file (\"%s\") is not a PNG image!", file.c_str(path));
} }
options.verbosePrint(Options::VERB_INTERM, "PNG header signature is OK\n"); options.verbosePrint(Options::VERB_INTERM, "PNG header signature is OK\n");
@@ -641,10 +640,10 @@ static void outputPalettes(std::vector<Palette> const &palettes) {
options.nbPalettes); options.nbPalettes);
} }
if (options.palettes.has_value()) { if (!options.palettes.empty()) {
File output; File output;
if (!output.open(*options.palettes, std::ios_base::out | std::ios_base::binary)) { if (!output.open(options.palettes, std::ios_base::out | std::ios_base::binary)) {
fatal("Failed to open \"%s\": %s", output.string(*options.palettes).c_str(), fatal("Failed to open \"%s\": %s", output.c_str(options.palettes),
strerror(errno)); strerror(errno));
} }
@@ -774,9 +773,8 @@ static void outputTileData(Png const &png, DefaultInitVec<AttrmapEntry> const &a
std::vector<Palette> const &palettes, std::vector<Palette> const &palettes,
DefaultInitVec<size_t> const &mappings) { DefaultInitVec<size_t> const &mappings) {
File output; File output;
if (!output.open(*options.output, std::ios_base::out | std::ios_base::binary)) { if (!output.open(options.output, std::ios_base::out | std::ios_base::binary)) {
fatal("Failed to open \"%s\": %s", output.string(*options.output).c_str(), fatal("Failed to open \"%s\": %s", output.c_str(options.output), strerror(errno));
strerror(errno));
} }
uint16_t widthTiles = options.inputSlice.width ? options.inputSlice.width : png.getWidth() / 8; uint16_t widthTiles = options.inputSlice.width ? options.inputSlice.width : png.getWidth() / 8;
@@ -809,11 +807,11 @@ static void outputTileData(Png const &png, DefaultInitVec<AttrmapEntry> const &a
static void outputMaps(DefaultInitVec<AttrmapEntry> const &attrmap, static void outputMaps(DefaultInitVec<AttrmapEntry> const &attrmap,
DefaultInitVec<size_t> const &mappings) { DefaultInitVec<size_t> const &mappings) {
std::optional<File> tilemapOutput, attrmapOutput, palmapOutput; std::optional<File> tilemapOutput, attrmapOutput, palmapOutput;
auto autoOpenPath = [](std::optional<std::filesystem::path> &path, std::optional<File> &file) { auto autoOpenPath = [](std::string const &path, std::optional<File> &file) {
if (path.has_value()) { if (!path.empty()) {
file.emplace(); file.emplace();
if (!file->open(*path, std::ios_base::out | std::ios_base::binary)) { if (!file->open(path, std::ios_base::out | std::ios_base::binary)) {
fatal("Failed to open \"%s\": %s", file->string(*path).c_str(), fatal("Failed to open \"%s\": %s", file->c_str(options.tilemap),
strerror(errno)); strerror(errno));
} }
} }
@@ -915,9 +913,8 @@ static UniqueTiles dedupTiles(Png const &png, DefaultInitVec<AttrmapEntry> &attr
static void outputTileData(UniqueTiles const &tiles) { static void outputTileData(UniqueTiles const &tiles) {
File output; File output;
if (!output.open(*options.output, std::ios_base::out | std::ios_base::binary)) { if (!output.open(options.output, std::ios_base::out | std::ios_base::binary)) {
fatal("Failed to create \"%s\": %s", output.string(*options.output).c_str(), fatal("Failed to create \"%s\": %s", output.c_str(options.output), strerror(errno));
strerror(errno));
} }
uint16_t tileID = 0; uint16_t tileID = 0;
@@ -931,9 +928,8 @@ static void outputTileData(UniqueTiles const &tiles) {
static void outputTilemap(DefaultInitVec<AttrmapEntry> const &attrmap) { static void outputTilemap(DefaultInitVec<AttrmapEntry> const &attrmap) {
File output; File output;
if (!output.open(*options.tilemap, std::ios_base::out | std::ios_base::binary)) { if (!output.open(options.tilemap, std::ios_base::out | std::ios_base::binary)) {
fatal("Failed to create \"%s\": %s", output.string(*options.tilemap).c_str(), fatal("Failed to create \"%s\": %s", output.c_str(options.tilemap), strerror(errno));
strerror(errno));
} }
for (AttrmapEntry const &entry : attrmap) { for (AttrmapEntry const &entry : attrmap) {
@@ -944,9 +940,8 @@ static void outputTilemap(DefaultInitVec<AttrmapEntry> const &attrmap) {
static void outputAttrmap(DefaultInitVec<AttrmapEntry> const &attrmap, static void outputAttrmap(DefaultInitVec<AttrmapEntry> const &attrmap,
DefaultInitVec<size_t> const &mappings) { DefaultInitVec<size_t> const &mappings) {
File output; File output;
if (!output.open(*options.attrmap, std::ios_base::out | std::ios_base::binary)) { if (!output.open(options.attrmap, std::ios_base::out | std::ios_base::binary)) {
fatal("Failed to create \"%s\": %s", output.string(*options.attrmap).c_str(), fatal("Failed to create \"%s\": %s", output.c_str(options.attrmap), strerror(errno));
strerror(errno));
} }
for (AttrmapEntry const &entry : attrmap) { for (AttrmapEntry const &entry : attrmap) {
@@ -960,9 +955,8 @@ static void outputAttrmap(DefaultInitVec<AttrmapEntry> const &attrmap,
static void outputPalmap(DefaultInitVec<AttrmapEntry> const &attrmap, static void outputPalmap(DefaultInitVec<AttrmapEntry> const &attrmap,
DefaultInitVec<size_t> const &mappings) { DefaultInitVec<size_t> const &mappings) {
File output; File output;
if (!output.open(*options.palmap, std::ios_base::out | std::ios_base::binary)) { if (!output.open(options.palmap, std::ios_base::out | std::ios_base::binary)) {
fatal("Failed to create \"%s\": %s", output.string(*options.palmap).c_str(), fatal("Failed to create \"%s\": %s", output.c_str(options.palmap), strerror(errno));
strerror(errno));
} }
for (AttrmapEntry const &entry : attrmap) { for (AttrmapEntry const &entry : attrmap) {
@@ -986,7 +980,7 @@ void process() {
options.verbosePrint(Options::VERB_CFG, "Using libpng %s\n", png_get_libpng_ver(nullptr)); options.verbosePrint(Options::VERB_CFG, "Using libpng %s\n", png_get_libpng_ver(nullptr));
options.verbosePrint(Options::VERB_LOG_ACT, "Reading tiles...\n"); options.verbosePrint(Options::VERB_LOG_ACT, "Reading tiles...\n");
Png png(*options.input); // This also sets `hasTransparentPixels` as a side effect Png png(options.input); // This also sets `hasTransparentPixels` as a side effect
ImagePalette const &colors = png.getColors(); ImagePalette const &colors = png.getColors();
// Now, we have all the image's colors in `colors` // Now, we have all the image's colors in `colors`
@@ -1108,13 +1102,12 @@ contained:;
nbTilesW * nbTilesH, options.maxNbTiles[0], options.maxNbTiles[1]); nbTilesW * nbTilesH, options.maxNbTiles[0], options.maxNbTiles[1]);
} }
if (options.output.has_value()) { if (!options.output.empty()) {
options.verbosePrint(Options::VERB_LOG_ACT, "Generating unoptimized tile data...\n"); options.verbosePrint(Options::VERB_LOG_ACT, "Generating unoptimized tile data...\n");
unoptimized::outputTileData(png, attrmap, palettes, mappings); unoptimized::outputTileData(png, attrmap, palettes, mappings);
} }
if (options.tilemap.has_value() || options.attrmap.has_value() if (!options.tilemap.empty() || !options.attrmap.empty() || !options.palmap.empty()) {
|| options.palmap.has_value()) {
options.verbosePrint( options.verbosePrint(
Options::VERB_LOG_ACT, Options::VERB_LOG_ACT,
"Generating unoptimized tilemap and/or attrmap and/or palmap...\n"); "Generating unoptimized tilemap and/or attrmap and/or palmap...\n");
@@ -1130,22 +1123,22 @@ contained:;
tiles.size(), options.maxNbTiles[0], options.maxNbTiles[1]); tiles.size(), options.maxNbTiles[0], options.maxNbTiles[1]);
} }
if (options.output.has_value()) { if (!options.output.empty()) {
options.verbosePrint(Options::VERB_LOG_ACT, "Generating optimized tile data...\n"); options.verbosePrint(Options::VERB_LOG_ACT, "Generating optimized tile data...\n");
optimized::outputTileData(tiles); optimized::outputTileData(tiles);
} }
if (options.tilemap.has_value()) { if (!options.tilemap.empty()) {
options.verbosePrint(Options::VERB_LOG_ACT, "Generating optimized tilemap...\n"); options.verbosePrint(Options::VERB_LOG_ACT, "Generating optimized tilemap...\n");
optimized::outputTilemap(attrmap); optimized::outputTilemap(attrmap);
} }
if (options.attrmap.has_value()) { if (!options.attrmap.empty()) {
options.verbosePrint(Options::VERB_LOG_ACT, "Generating optimized attrmap...\n"); options.verbosePrint(Options::VERB_LOG_ACT, "Generating optimized attrmap...\n");
optimized::outputAttrmap(attrmap, mappings); optimized::outputAttrmap(attrmap, mappings);
} }
if (options.palmap.has_value()) { if (!options.palmap.empty()) {
options.verbosePrint(Options::VERB_LOG_ACT, "Generating optimized palmap...\n"); options.verbosePrint(Options::VERB_LOG_ACT, "Generating optimized palmap...\n");
optimized::outputPalmap(attrmap, mappings); optimized::outputPalmap(attrmap, mappings);
} }

View File

@@ -7,7 +7,6 @@
#include <assert.h> #include <assert.h>
#include <cinttypes> #include <cinttypes>
#include <errno.h> #include <errno.h>
#include <filesystem>
#include <fstream> #include <fstream>
#include <optional> #include <optional>
#include <png.h> #include <png.h>
@@ -22,10 +21,10 @@
#include "gfx/main.hpp" #include "gfx/main.hpp"
static DefaultInitVec<uint8_t> readInto(std::filesystem::path path) { static DefaultInitVec<uint8_t> readInto(std::string path) {
File file; File file;
if (!file.open(path, std::ios::in | std::ios::binary)) { if (!file.open(path, std::ios::in | std::ios::binary)) {
fatal("Failed to open \"%s\": %s", file.string(path).c_str(), strerror(errno)); fatal("Failed to open \"%s\": %s", file.c_str(path), strerror(errno));
} }
DefaultInitVec<uint8_t> data(128 * 16); // Begin with some room pre-allocated DefaultInitVec<uint8_t> data(128 * 16); // Begin with some room pre-allocated
@@ -78,11 +77,11 @@ void reverse() {
// Check for weird flag combinations // Check for weird flag combinations
if (!options.output.has_value()) { if (options.output.empty()) {
fatal("Tile data must be provided when reversing an image!"); fatal("Tile data must be provided when reversing an image!");
} }
if (options.allowDedup && !options.tilemap.has_value()) { if (options.allowDedup && options.tilemap.empty()) {
warning("Tile deduplication is enabled, but no tilemap is provided?"); warning("Tile deduplication is enabled, but no tilemap is provided?");
} }
@@ -101,7 +100,7 @@ void reverse() {
} }
options.verbosePrint(Options::VERB_LOG_ACT, "Reading tiles...\n"); options.verbosePrint(Options::VERB_LOG_ACT, "Reading tiles...\n");
auto const tiles = readInto(*options.output); auto const tiles = readInto(options.output);
uint8_t tileSize = 8 * options.bitDepth; uint8_t tileSize = 8 * options.bitDepth;
if (tiles.size() % tileSize != 0) { if (tiles.size() % tileSize != 0) {
fatal("Tile data size (%zu bytes) is not a multiple of %" PRIu8 " bytes", fatal("Tile data size (%zu bytes) is not a multiple of %" PRIu8 " bytes",
@@ -112,8 +111,8 @@ void reverse() {
size_t nbTileInstances = tiles.size() / tileSize + options.trim; // Image size in tiles size_t nbTileInstances = tiles.size() / tileSize + options.trim; // Image size in tiles
options.verbosePrint(Options::VERB_INTERM, "Read %zu tiles.\n", nbTileInstances); options.verbosePrint(Options::VERB_INTERM, "Read %zu tiles.\n", nbTileInstances);
std::optional<DefaultInitVec<uint8_t>> tilemap; std::optional<DefaultInitVec<uint8_t>> tilemap;
if (options.tilemap.has_value()) { if (!options.tilemap.empty()) {
tilemap = readInto(*options.tilemap); tilemap = readInto(options.tilemap);
nbTileInstances = tilemap->size(); nbTileInstances = tilemap->size();
options.verbosePrint(Options::VERB_INTERM, "Read %zu tilemap entries.\n", nbTileInstances); options.verbosePrint(Options::VERB_INTERM, "Read %zu tilemap entries.\n", nbTileInstances);
} }
@@ -142,11 +141,10 @@ void reverse() {
{Rgba(0xFFFFFFFF), Rgba(0xAAAAAAFF), Rgba(0x555555FF), Rgba(0x000000FF)} {Rgba(0xFFFFFFFF), Rgba(0xAAAAAAFF), Rgba(0x555555FF), Rgba(0x000000FF)}
}; };
// If a palette file is used as input, it overrides the default colors. // If a palette file is used as input, it overrides the default colors.
if (options.palettes.has_value()) { if (!options.palettes.empty()) {
File file; File file;
if (!file.open(*options.palettes, std::ios::in | std::ios::binary)) { if (!file.open(options.palettes, std::ios::in | std::ios::binary)) {
fatal("Failed to open \"%s\": %s", file.string(*options.palettes).c_str(), fatal("Failed to open \"%s\": %s", file.c_str(options.palettes), strerror(errno));
strerror(errno));
} }
palettes.clear(); palettes.clear();
@@ -183,8 +181,8 @@ void reverse() {
} }
std::optional<DefaultInitVec<uint8_t>> attrmap; std::optional<DefaultInitVec<uint8_t>> attrmap;
if (options.attrmap.has_value()) { if (!options.attrmap.empty()) {
attrmap = readInto(*options.attrmap); attrmap = readInto(options.attrmap);
if (attrmap->size() != nbTileInstances) { if (attrmap->size() != nbTileInstances) {
fatal("Attribute map size (%zu tiles) doesn't match image's (%zu)", attrmap->size(), fatal("Attribute map size (%zu tiles) doesn't match image's (%zu)", attrmap->size(),
nbTileInstances); nbTileInstances);
@@ -230,8 +228,8 @@ void reverse() {
} }
std::optional<DefaultInitVec<uint8_t>> palmap; std::optional<DefaultInitVec<uint8_t>> palmap;
if (options.palmap.has_value()) { if (!options.palmap.empty()) {
palmap = readInto(*options.palmap); palmap = readInto(options.palmap);
if (palmap->size() != nbTileInstances) { if (palmap->size() != nbTileInstances) {
fatal("Palette map size (%zu tiles) doesn't match image's (%zu)", palmap->size(), fatal("Palette map size (%zu tiles) doesn't match image's (%zu)", palmap->size(),
nbTileInstances); nbTileInstances);
@@ -240,14 +238,13 @@ void reverse() {
options.verbosePrint(Options::VERB_LOG_ACT, "Writing image...\n"); options.verbosePrint(Options::VERB_LOG_ACT, "Writing image...\n");
File pngFile; File pngFile;
if (!pngFile.open(*options.input, std::ios::out | std::ios::binary)) { if (!pngFile.open(options.input, std::ios::out | std::ios::binary)) {
fatal("Failed to create \"%s\": %s", pngFile.string(*options.input).c_str(), fatal("Failed to create \"%s\": %s", pngFile.c_str(options.input), strerror(errno));
strerror(errno));
} }
png_structp png = png_create_write_struct( png_structp png = png_create_write_struct(
PNG_LIBPNG_VER_STRING, PNG_LIBPNG_VER_STRING,
const_cast<png_voidp>(static_cast<void const *>(pngFile.string(*options.input).c_str())), const_cast<png_voidp>(static_cast<void const *>(pngFile.c_str(options.input))), pngError,
pngError, pngWarning); pngWarning);
if (!png) { if (!png) {
fatal("Couldn't create PNG write struct: %s", strerror(errno)); fatal("Couldn't create PNG write struct: %s", strerror(errno));
} }