mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 10:12:06 +00:00
Switch to using std::filesystem (#1235)
Allows better platform-agnostic path manipulation. Also, using `std::optional` rather than empty strings allows correctly handling empty arguments (treating them as such, instead of acting as they were never passed).
This commit is contained in:
@@ -7,11 +7,11 @@
|
|||||||
#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>
|
||||||
#include <streambuf>
|
#include <streambuf>
|
||||||
#include <string>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
@@ -41,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::string const &path, std::ios_base::openmode mode) {
|
File *open(std::filesystem::path 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) {
|
||||||
@@ -85,8 +85,15 @@ public:
|
|||||||
: nullptr;
|
: nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
char const *c_str(std::string const &path) const {
|
char const *c_str(std::filesystem::path const &path) const {
|
||||||
return std::visit(Visitor{[&path](std::filebuf const &) { return path.c_str(); },
|
// FIXME: This is a hack to prevent the path string from being destroyed until
|
||||||
|
// `.c_str(path)` is called again. It's necessary because just `return path.c_str()`
|
||||||
|
// fails on Windows, where paths use `wchar_t`.
|
||||||
|
static std::string path_string;
|
||||||
|
return std::visit(Visitor{[&path](std::filebuf const &) {
|
||||||
|
path_string = path.string();
|
||||||
|
return path_string.c_str();
|
||||||
|
},
|
||||||
[](std::streambuf const *buf) {
|
[](std::streambuf const *buf) {
|
||||||
return buf == std::cin.rdbuf() ? "<stdin>" : "<stdout>";
|
return buf == std::cin.rdbuf() ? "<stdin>" : "<stdout>";
|
||||||
}},
|
}},
|
||||||
|
|||||||
@@ -4,7 +4,9 @@
|
|||||||
#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>
|
||||||
@@ -24,7 +26,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::string attrmap{}; // -a, -A
|
std::optional<std::filesystem::path> 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,
|
||||||
@@ -41,14 +43,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::string output{}; // -o
|
std::optional<std::filesystem::path> output{}; // -o
|
||||||
std::string palettes{}; // -p, -P
|
std::optional<std::filesystem::path> palettes{}; // -p, -P
|
||||||
std::string palmap{}; // -q, -Q
|
std::optional<std::filesystem::path> palmap{}; // -q, -Q
|
||||||
uint8_t nbColorsPerPal = 0; // -s; 0 means "auto" = 1 << bitDepth;
|
uint8_t nbColorsPerPal = 0; // -s; 0 means "auto" = 1 << bitDepth;
|
||||||
std::string tilemap{}; // -t, -T
|
std::optional<std::filesystem::path> tilemap{}; // -t, -T
|
||||||
uint64_t trim = 0; // -x
|
uint64_t trim = 0; // -x
|
||||||
|
|
||||||
std::string input{}; // positional arg
|
std::optional<std::filesystem::path> 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
|
||||||
|
|||||||
@@ -7,10 +7,12 @@
|
|||||||
#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>
|
||||||
@@ -228,11 +230,11 @@ static void skipWhitespace(char *&arg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void registerInput(char const *arg) {
|
static void registerInput(char const *arg) {
|
||||||
if (!options.input.empty()) {
|
if (options.input.has_value()) {
|
||||||
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
|
||||||
@@ -240,7 +242,7 @@ static void registerInput(char const *arg) {
|
|||||||
printUsage();
|
printUsage();
|
||||||
exit(1);
|
exit(1);
|
||||||
} else {
|
} else {
|
||||||
options.input = arg;
|
options.input.emplace(arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,7 +250,8 @@ 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::string const &path, std::vector<char> &argPool) {
|
static std::vector<size_t> readAtFile(std::filesystem::path const &path,
|
||||||
|
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.c_str(path), strerror(errno));
|
fatal("Error reading @%s: %s", file.c_str(path), strerror(errno));
|
||||||
@@ -316,6 +319,7 @@ static std::vector<size_t> readAtFile(std::string const &path, std::vector<char>
|
|||||||
} while (c != '\n' && c != EOF); // End if we reached EOL
|
} while (c != '\n' && c != EOF); // End if we reached EOL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parses an arg vector, modifying `options` as options are read.
|
* Parses an arg vector, modifying `options` as options are read.
|
||||||
* The three booleans are for the "auto path" flags, since their processing must be deferred to the
|
* The three booleans are for the "auto path" flags, since their processing must be deferred to the
|
||||||
@@ -334,8 +338,8 @@ static char *parseArgv(int argc, char **argv, bool &autoAttrmap, bool &autoTilem
|
|||||||
break;
|
break;
|
||||||
case 'a':
|
case 'a':
|
||||||
autoAttrmap = false;
|
autoAttrmap = false;
|
||||||
if (!options.attrmap.empty())
|
if (options.attrmap.has_value())
|
||||||
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':
|
||||||
@@ -478,8 +482,8 @@ static char *parseArgv(int argc, char **argv, bool &autoAttrmap, bool &autoTilem
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'o':
|
case 'o':
|
||||||
if (!options.output.empty())
|
if (options.output.has_value())
|
||||||
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':
|
||||||
@@ -487,8 +491,8 @@ static char *parseArgv(int argc, char **argv, bool &autoAttrmap, bool &autoTilem
|
|||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
autoPalettes = false;
|
autoPalettes = false;
|
||||||
if (!options.palettes.empty())
|
if (options.palettes.has_value())
|
||||||
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':
|
||||||
@@ -496,8 +500,8 @@ static char *parseArgv(int argc, char **argv, bool &autoAttrmap, bool &autoTilem
|
|||||||
break;
|
break;
|
||||||
case 'q':
|
case 'q':
|
||||||
autoPalmap = false;
|
autoPalmap = false;
|
||||||
if (!options.palmap.empty())
|
if (options.palmap.has_value())
|
||||||
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':
|
||||||
@@ -525,8 +529,8 @@ static char *parseArgv(int argc, char **argv, bool &autoAttrmap, bool &autoTilem
|
|||||||
break;
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
autoTilemap = false;
|
autoTilemap = false;
|
||||||
if (!options.tilemap.empty())
|
if (options.tilemap.has_value())
|
||||||
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':
|
||||||
@@ -642,27 +646,15 @@ int main(int argc, char *argv[]) {
|
|||||||
1u << options.bitDepth, options.nbColorsPerPal);
|
1u << options.bitDepth, options.nbColorsPerPal);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto autoOutPath = [](bool autoOptEnabled, std::string &path, char const *extension) {
|
auto autoOutPath = [](bool autoOptEnabled, std::optional<std::filesystem::path> &path,
|
||||||
|
char const *extension) {
|
||||||
if (autoOptEnabled) {
|
if (autoOptEnabled) {
|
||||||
constexpr std::string_view chars =
|
if (!options.input.has_value()) {
|
||||||
// Both must start with a dot!
|
fputs("FATAL: No input image specified\n", stderr);
|
||||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
printUsage();
|
||||||
"./\\"sv;
|
exit(1);
|
||||||
#else
|
|
||||||
"./"sv;
|
|
||||||
#endif
|
|
||||||
size_t len = options.input.npos;
|
|
||||||
size_t i = options.input.find_last_of(chars);
|
|
||||||
if (i != options.input.npos && options.input[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(options.input[i - 1], 1) == chars.npos) {
|
|
||||||
// We can replace the extension
|
|
||||||
len = i;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
path.assign(options.input, 0, len);
|
path.emplace(*options.input).replace_extension(extension);
|
||||||
path.append(extension);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
autoOutPath(autoAttrmap, options.attrmap, ".attrmap");
|
autoOutPath(autoAttrmap, options.attrmap, ".attrmap");
|
||||||
@@ -747,9 +739,10 @@ 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, std::string const &path) {
|
auto printPath = [](char const *name,
|
||||||
if (!path.empty()) {
|
std::optional<std::filesystem::path> const &path) {
|
||||||
fprintf(stderr, "\t%s: %s\n", name, path.c_str());
|
if (path.has_value()) {
|
||||||
|
fprintf(stderr, "\t%s: %s\n", name, path->c_str());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
printPath("Input image", options.input);
|
printPath("Input image", options.input);
|
||||||
@@ -765,13 +758,13 @@ int main(int argc, char *argv[]) {
|
|||||||
giveUp();
|
giveUp();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!options.input.empty()) {
|
if (options.input.has_value()) {
|
||||||
if (options.reverse()) {
|
if (options.reverse()) {
|
||||||
reverse();
|
reverse();
|
||||||
} else {
|
} else {
|
||||||
process();
|
process();
|
||||||
}
|
}
|
||||||
} else if (!options.palettes.empty() && options.palSpecType == Options::EXPLICIT
|
} else if (options.palettes.has_value() && options.palSpecType == Options::EXPLICIT
|
||||||
&& !options.reverse()) {
|
&& !options.reverse()) {
|
||||||
processPalettes();
|
processPalettes();
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#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>
|
||||||
@@ -71,7 +72,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
class Png {
|
class Png {
|
||||||
std::string const &path;
|
std::filesystem::path const &path;
|
||||||
File file{};
|
File file{};
|
||||||
png_structp png = nullptr;
|
png_structp png = nullptr;
|
||||||
png_infop info = nullptr;
|
png_infop info = nullptr;
|
||||||
@@ -169,7 +170,7 @@ 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::string const &filePath) : path(filePath), colors() {
|
explicit Png(std::filesystem::path 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.c_str(path), strerror(errno));
|
fatal("Failed to open input image (\"%s\"): %s", file.c_str(path), strerror(errno));
|
||||||
}
|
}
|
||||||
@@ -637,10 +638,10 @@ static void outputPalettes(std::vector<Palette> const &palettes) {
|
|||||||
options.nbPalettes);
|
options.nbPalettes);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!options.palettes.empty()) {
|
if (options.palettes.has_value()) {
|
||||||
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.c_str(options.palettes),
|
fatal("Failed to open \"%s\": %s", output.c_str(*options.palettes),
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -770,8 +771,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.c_str(options.output), strerror(errno));
|
fatal("Failed to open \"%s\": %s", output.c_str(*options.output), 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;
|
||||||
@@ -804,27 +805,18 @@ 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;
|
||||||
if (!options.tilemap.empty()) {
|
auto autoOpenPath = [](std::optional<std::filesystem::path> &path, std::optional<File> &file) {
|
||||||
tilemapOutput.emplace();
|
if (path.has_value()) {
|
||||||
if (!tilemapOutput->open(options.tilemap, std::ios_base::out | std::ios_base::binary)) {
|
file.emplace();
|
||||||
fatal("Failed to open \"%s\": %s", tilemapOutput->c_str(options.tilemap),
|
if (!file->open(*path, std::ios_base::out | std::ios_base::binary)) {
|
||||||
strerror(errno));
|
fatal("Failed to open \"%s\": %s", file->c_str(*path),
|
||||||
|
strerror(errno));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
if (!options.attrmap.empty()) {
|
autoOpenPath(options.tilemap, tilemapOutput);
|
||||||
attrmapOutput.emplace();
|
autoOpenPath(options.attrmap, attrmapOutput);
|
||||||
if (!attrmapOutput->open(options.attrmap, std::ios_base::out | std::ios_base::binary)) {
|
autoOpenPath(options.palmap, palmapOutput);
|
||||||
fatal("Failed to open \"%s\": %s", attrmapOutput->c_str(options.attrmap),
|
|
||||||
strerror(errno));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!options.palmap.empty()) {
|
|
||||||
palmapOutput.emplace();
|
|
||||||
if (!palmapOutput->open(options.palmap, std::ios_base::out | std::ios_base::binary)) {
|
|
||||||
fatal("Failed to open \"%s\": %s", palmapOutput->c_str(options.palmap),
|
|
||||||
strerror(errno));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t tileID = 0;
|
uint8_t tileID = 0;
|
||||||
uint8_t bank = 0;
|
uint8_t bank = 0;
|
||||||
@@ -919,8 +911,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.c_str(options.output), strerror(errno));
|
fatal("Failed to create \"%s\": %s", output.c_str(*options.output), strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t tileID = 0;
|
uint16_t tileID = 0;
|
||||||
@@ -934,8 +926,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.c_str(options.tilemap), strerror(errno));
|
fatal("Failed to create \"%s\": %s", output.c_str(*options.tilemap), strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (AttrmapEntry const &entry : attrmap) {
|
for (AttrmapEntry const &entry : attrmap) {
|
||||||
@@ -946,8 +938,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.c_str(options.attrmap), strerror(errno));
|
fatal("Failed to create \"%s\": %s", output.c_str(*options.attrmap), strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (AttrmapEntry const &entry : attrmap) {
|
for (AttrmapEntry const &entry : attrmap) {
|
||||||
@@ -961,8 +953,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.c_str(options.palmap), strerror(errno));
|
fatal("Failed to create \"%s\": %s", output.c_str(*options.palmap), strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (AttrmapEntry const &entry : attrmap) {
|
for (AttrmapEntry const &entry : attrmap) {
|
||||||
@@ -986,7 +978,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,12 +1100,13 @@ contained:;
|
|||||||
nbTilesW * nbTilesH, options.maxNbTiles[0], options.maxNbTiles[1]);
|
nbTilesW * nbTilesH, options.maxNbTiles[0], options.maxNbTiles[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!options.output.empty()) {
|
if (options.output.has_value()) {
|
||||||
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.empty() || !options.attrmap.empty() || !options.palmap.empty()) {
|
if (options.tilemap.has_value() || options.attrmap.has_value()
|
||||||
|
|| 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");
|
||||||
@@ -1129,22 +1122,22 @@ contained:;
|
|||||||
tiles.size(), options.maxNbTiles[0], options.maxNbTiles[1]);
|
tiles.size(), options.maxNbTiles[0], options.maxNbTiles[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!options.output.empty()) {
|
if (options.output.has_value()) {
|
||||||
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.empty()) {
|
if (options.tilemap.has_value()) {
|
||||||
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.empty()) {
|
if (options.attrmap.has_value()) {
|
||||||
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.empty()) {
|
if (options.palmap.has_value()) {
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#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>
|
||||||
@@ -21,7 +22,7 @@
|
|||||||
|
|
||||||
#include "gfx/main.hpp"
|
#include "gfx/main.hpp"
|
||||||
|
|
||||||
static DefaultInitVec<uint8_t> readInto(std::string path) {
|
static DefaultInitVec<uint8_t> readInto(std::filesystem::path 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.c_str(path), strerror(errno));
|
fatal("Failed to open \"%s\": %s", file.c_str(path), strerror(errno));
|
||||||
@@ -77,11 +78,11 @@ void reverse() {
|
|||||||
|
|
||||||
// Check for weird flag combinations
|
// Check for weird flag combinations
|
||||||
|
|
||||||
if (options.output.empty()) {
|
if (!options.output.has_value()) {
|
||||||
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.empty()) {
|
if (options.allowDedup && !options.tilemap.has_value()) {
|
||||||
warning("Tile deduplication is enabled, but no tilemap is provided?");
|
warning("Tile deduplication is enabled, but no tilemap is provided?");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +101,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",
|
||||||
@@ -111,8 +112,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.empty()) {
|
if (options.tilemap.has_value()) {
|
||||||
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);
|
||||||
}
|
}
|
||||||
@@ -140,10 +141,10 @@ void reverse() {
|
|||||||
std::vector<std::array<Rgba, 4>> palettes{
|
std::vector<std::array<Rgba, 4>> palettes{
|
||||||
{Rgba(0xFFFFFFFF), Rgba(0xAAAAAAFF), Rgba(0x555555FF), Rgba(0x000000FF)}
|
{Rgba(0xFFFFFFFF), Rgba(0xAAAAAAFF), Rgba(0x555555FF), Rgba(0x000000FF)}
|
||||||
};
|
};
|
||||||
if (!options.palettes.empty()) {
|
if (options.palettes.has_value()) {
|
||||||
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.c_str(options.palettes), strerror(errno));
|
fatal("Failed to open \"%s\": %s", file.c_str(*options.palettes), strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
palettes.clear();
|
palettes.clear();
|
||||||
@@ -172,8 +173,8 @@ void reverse() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::optional<DefaultInitVec<uint8_t>> attrmap;
|
std::optional<DefaultInitVec<uint8_t>> attrmap;
|
||||||
if (!options.attrmap.empty()) {
|
if (options.attrmap.has_value()) {
|
||||||
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);
|
||||||
@@ -219,8 +220,8 @@ void reverse() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::optional<DefaultInitVec<uint8_t>> palmap;
|
std::optional<DefaultInitVec<uint8_t>> palmap;
|
||||||
if (!options.palmap.empty()) {
|
if (options.palmap.has_value()) {
|
||||||
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);
|
||||||
@@ -229,12 +230,12 @@ 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.c_str(options.input), strerror(errno));
|
fatal("Failed to create \"%s\": %s", pngFile.c_str(*options.input), 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.c_str(options.input))), pngError,
|
const_cast<png_voidp>(static_cast<void const *>(pngFile.c_str(*options.input))), 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));
|
||||||
|
|||||||
Reference in New Issue
Block a user