Merge branch 'master' into features-1.1.0

This commit is contained in:
Rangi committed 2026-09-26 16:47:44 -04:00
commit ff6f1699e9
45 files changed
+181 -117

No files matched your search

+2 -1
View File
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: MIT
#include "platform.hpp" // strncasecmp
#include "asm/fstack.hpp"
#include <sys/stat.h>
@@ -22,7 +24,6 @@
#include "helpers.hpp"
#include "itertools.hpp" // reversed
#include "linkdefs.hpp"
#include "platform.hpp" // strncasecmp
#include "verbosity.hpp"
#include "asm/intern.hpp"
+2 -1
View File
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: MIT
#include "platform.hpp"
#include "asm/lexer.hpp"
#include <sys/stat.h>
@@ -27,7 +29,6 @@
#include <vector>
#include "helpers.hpp"
#include "platform.hpp"
#include "style.hpp"
#include "util.hpp"
#include "verbosity.hpp"
+3 -2
View File
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: MIT
#include "platform.hpp"
#include "asm/main.hpp"
#include <algorithm>
@@ -23,8 +25,7 @@
#include "diagnostics.hpp"
#include "helpers.hpp"
#include "parser.hpp" // Generated from parser.y
#include "platform.hpp"
#include "style.hpp" // style_Parse
#include "style.hpp" // style_Parse
#include "usage.hpp"
#include "util.hpp" // UpperMap
#include "verbosity.hpp"
+2 -1
View File
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: MIT
#include "platform.hpp"
#include "asm/output.hpp"
#include <algorithm>
@@ -16,7 +18,6 @@
#include "helpers.hpp" // assume, Defer
#include "linkdefs.hpp"
#include "platform.hpp"
#include "util.hpp" // xfclose
#include "asm/charmap.hpp"
+3 -2
View File
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: MIT
#include "platform.hpp" // fseek
#include "asm/section.hpp"
#include <algorithm>
@@ -21,8 +23,7 @@
#include "helpers.hpp"
#include "itertools.hpp" // InsertionOrderedMap
#include "linkdefs.hpp"
#include "platform.hpp" // fseek
#include "util.hpp" // xfclose, seekSize
#include "util.hpp" // xfclose, seekSize
#include "asm/fstack.hpp"
#include "asm/lexer.hpp"
+3 -2
View File
@@ -1,12 +1,13 @@
// SPDX-License-Identifier: MIT
#include "platform.hpp" // strcasecmp
#include "backtrace.hpp"
#include <optional>
#include <stdint.h>
#include "platform.hpp" // strcasecmp
#include "util.hpp" // parseWholeNumber
#include "util.hpp" // parseWholeNumber
Tracing tracing;
+2 -1
View File
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: MIT
#include "platform.hpp"
#include "fix/fix.hpp"
#include <sys/stat.h>
@@ -14,7 +16,6 @@
#include "diagnostics.hpp"
#include "helpers.hpp"
#include "platform.hpp"
#include "util.hpp" // xclose, xfclose
#include "fix/main.hpp"
+2 -1
View File
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: MIT
#include "platform.hpp"
#include "fix/main.hpp"
#include <errno.h>
@@ -15,7 +17,6 @@
#include "cli.hpp"
#include "diagnostics.hpp"
#include "helpers.hpp"
#include "platform.hpp"
#include "style.hpp"
#include "usage.hpp"
#include "util.hpp"
+3 -2
View File
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: MIT
#include "platform.hpp" // strcasecmp
#include "fix/mbc.hpp"
#include <optional>
@@ -10,8 +12,7 @@
#include <unordered_map>
#include <utility>
#include "helpers.hpp" // unreachable_
#include "platform.hpp" // strcasecmp
#include "helpers.hpp" // unreachable_
#include "util.hpp"
#include "fix/warning.hpp"
+32 -7
View File
@@ -1,10 +1,13 @@
// SPDX-License-Identifier: MIT
#include "platform.hpp"
#include "gfx/main.hpp"
#include <inttypes.h>
#include <ios>
#include <optional>
#include <png.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
@@ -18,7 +21,6 @@
#include "diagnostics.hpp"
#include "file.hpp"
#include "helpers.hpp"
#include "platform.hpp"
#include "style.hpp" // style_Parse
#include "usage.hpp"
#include "util.hpp"
@@ -479,6 +481,7 @@ static void parseArg(int ch, char *arg) {
// LCOV_EXCL_START
static void verboseOutputConfig() {
usage.printVersion(true);
fprintf(stderr, "Using libpng %s\n", png_get_libpng_ver(nullptr));
printVVVVVVerbosity();
@@ -524,12 +527,18 @@ static void verboseOutputConfig() {
break;
case Options::INLINE:
case Options::EXTERNAL:
fputs("\tExplicit palette spec\n\t[\n", stderr);
case Options::EMBEDDED:
if (options.palSpecType == Options::EMBEDDED) {
fputs("\tEmbedded palette spec from PNG indexed PLTE chunk\n", stderr);
} else {
fputs("\tExplicit palette spec\n", stderr);
}
fputs("\t[\n", stderr);
for (auto const &pal : options.palSpec) {
fputs("\t\t", stderr);
for (auto const &color : pal) {
if (color.has_value()) {
fprintf(stderr, "#%06x, ", color->toCSS() >> 8);
fprintf(stderr, "#%08x, ", color->toCSS());
} else {
fputs("#none, ", stderr);
}
@@ -538,9 +547,6 @@ static void verboseOutputConfig() {
}
fputs("\t]\n", stderr);
break;
case Options::EMBEDDED:
fputs("\tEmbedded palette spec from PNG indexed PLTE chunk\n", stderr);
break;
case Options::DMG:
fprintf(stderr, "\tDMG palette spec $%02" PRIx8 "\n", options.palSpecDmg);
break;
@@ -671,13 +677,32 @@ int main(int argc, char *argv[]) {
autoOutPath(localOptions.autoPalettes, options.palettes, ".pal");
autoOutPath(localOptions.autoPalmap, options.palmap, ".palmap");
// Read the input image now since it may be needed for parsing an embedded palette spec
bool useInputImage = !options.input.empty() && !localOptions.reverse;
Png png;
if (useInputImage) {
if (File image;
image.open(options.input, std::ios_base::in | std::ios_base::binary) == nullptr) {
fatal(
"Failed to open PNG image (\"%s\"): %s", image.c_str(options.input), strerror(errno)
);
} else {
png = Png(image.c_str(options.input), *image);
}
}
// Execute deferred pal spec parsing, now that all other params are known.
// Do not parse pal specs if `options.nbColorsPerPal` is invalid.
if (options.nbColorsPerPal > 0 && options.nbColorsPerPal <= 4) {
switch (options.palSpecType) {
case Options::NO_SPEC:
assume(!localOptions.palSpec);
break;
case Options::EMBEDDED:
assume(!localOptions.palSpec);
if (useInputImage) {
parseEmbeddedPalSpec(png);
}
break;
case Options::INLINE:
assume(localOptions.palSpec);
@@ -703,7 +728,7 @@ int main(int argc, char *argv[]) {
if (localOptions.reverse) {
reverse();
} else {
process();
process(std::move(png));
}
} else if (!options.palettes.empty() && options.hasExplicitPalSpec() && !localOptions.reverse) {
processPalettes();
+25 -1
View File
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: MIT
#include "platform.hpp"
#include "gfx/pal_spec.hpp"
#include <algorithm>
@@ -20,8 +22,8 @@
#include <vector>
#include "diagnostics.hpp"
#include "file.hpp"
#include "helpers.hpp"
#include "platform.hpp"
#include "util.hpp" // UpperMap, parseDigit
#include "gfx/main.hpp"
@@ -174,6 +176,28 @@ void parseInlinePalSpec(char const * const rawArg) {
}
}
void parseEmbeddedPalSpec(Png const &png) {
// Generate a palette spec from one palette's length of colors in the embedded palette
if (png.palette.empty()) {
error("\"-c embedded\" was given, but the PNG does not have an embedded palette");
return;
}
// Ignore extraneous colors if they are unused
size_t nbColors = png.palette.size();
if (nbColors > options.maxOpaqueColors()) {
nbColors = options.maxOpaqueColors();
}
// Fill in the palette spec
options.palSpec.clear();
auto &palette = options.palSpec.emplace_back();
assume(nbColors <= palette.size());
for (size_t i = 0; i < nbColors; ++i) {
palette[i] = png.palette[i];
}
}
// Appends the first line read from `file` to the end of the provided `buffer`.
// Returns true if a line was read.
[[nodiscard]]
+6 -43
View File
@@ -8,7 +8,6 @@
#include <inttypes.h>
#include <ios>
#include <optional>
#include <png.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
@@ -77,8 +76,8 @@ public:
};
struct Image {
Png png{};
ImagePalette colors{};
Png png;
ImagePalette colors;
Rgba &pixel(uint32_t x, uint32_t y) { return png.pixels[y * png.width + x]; }
Rgba const &pixel(uint32_t x, uint32_t y) const { return png.pixels[y * png.width + x]; }
@@ -127,14 +126,7 @@ struct Image {
return {GrayscaleResult::GRAY_OK, std::nullopt};
}
explicit Image(std::string const &path) {
File input;
if (input.open(path, std::ios_base::in | std::ios_base::binary) == nullptr) {
fatal("Failed to open input image (\"%s\"): %s", input.c_str(path), strerror(errno));
}
png = Png(input.c_str(path), *input);
explicit Image(Png &&png_) : png(std::move(png_)), colors() {
// Validate input slice
if (options.inputSlice.width == 0 && png.width % 8 != 0) {
fatal("Image width (%" PRIu32 " pixels) is not a multiple of 8", png.width);
@@ -332,28 +324,6 @@ struct AttrmapEntry {
}
};
static void generatePalSpec(Image const &image) {
// Generate a palette spec from the first few colors in the embedded palette
std::vector<Rgba> const &embPal = image.png.palette;
if (embPal.empty()) {
fatal("\"-c embedded\" was given, but the PNG does not have an embedded palette");
}
// Ignore extraneous colors if they are unused
size_t nbColors = embPal.size();
if (nbColors > options.maxOpaqueColors()) {
nbColors = options.maxOpaqueColors();
}
// Fill in the palette spec
options.palSpec.clear();
auto &palette = options.palSpec.emplace_back();
assume(nbColors <= palette.size());
for (size_t i = 0; i < nbColors; ++i) {
palette[i] = embPal[i];
}
}
static std::pair<std::vector<size_t>, std::vector<Palette>>
generatePalettes(std::vector<ColorSet> const &colorSets, Image const &image) {
// Run a "pagination" problem solver
@@ -450,7 +420,7 @@ static std::pair<std::vector<size_t>, std::vector<Palette>>
if (i + skipFirst >= options.nbColorsPerPal) {
error(
"Each palette spec can only contain up to %" PRIu8
" color%s plus the implict transparent color",
" color%s plus the implicit transparent color",
options.nbColorsPerPal - 1,
options.nbColorsPerPal - 1 == 1 ? "" : "s"
);
@@ -992,8 +962,6 @@ static void
}
void processPalettes() {
verbosePrint(VERB_CONFIG, "Using libpng %s\n", png_get_libpng_ver(nullptr));
std::vector<ColorSet> colorSets;
std::vector<Palette> palettes;
std::tie(std::ignore, palettes) = makePalsAsSpecified(colorSets);
@@ -1001,11 +969,9 @@ void processPalettes() {
outputPalettes(palettes);
}
void process() {
verbosePrint(VERB_CONFIG, "Using libpng %s\n", png_get_libpng_ver(nullptr));
void process(Png &&png) {
verbosePrint(VERB_NOTICE, "Reading tiles...\n");
Image image(options.input); // This also sets `hasTransparentPixels` as a side effect
Image image(std::move(png)); // This also sets `hasTransparentPixels` as a side effect
// LCOV_EXCL_START
verboseDo(VERB_INFO, [&]() {
@@ -1195,9 +1161,6 @@ continue_visiting_tiles:;
fatal("Image does not contain any colors");
}
if (options.palSpecType == Options::EMBEDDED) {
generatePalSpec(image);
}
auto [mappings, palettes] =
options.palSpecType == Options::NO_SPEC || options.palSpecType == Options::DMG
? generatePalettes(colorSets, image)
+22 -15
View File
@@ -107,8 +107,6 @@ static void printPalette(std::array<std::optional<Rgba>, 4> const &palette) {
}
void reverse() {
verbosePrint(VERB_CONFIG, "Using libpng %s\n", png_get_libpng_ver(nullptr));
// Check for weird flag combinations
if (options.output.empty()) {
@@ -205,6 +203,7 @@ void reverse() {
{grayColors[0], grayColors[1], grayColors[2], grayColors[3]}
};
// If a palette file or palette spec is used as input, it overrides the default colors.
bool grayscale = false;
if (!options.palettes.empty()) {
File file;
if (!file.open(options.palettes, std::ios::in | std::ios::binary)) {
@@ -280,11 +279,15 @@ void reverse() {
for (size_t i = 0; i < palettes[0].size(); ++i) {
palettes[0][i] = grayColors[options.dmgValue(i)];
}
grayscale = true;
} else if (options.palSpecType == Options::EMBEDDED) {
warnx("An embedded palette was requested, but no palette file was specified; ignoring "
"request");
grayscale = true;
} else if (options.hasExplicitPalSpec()) {
palettes = std::move(options.palSpec); // We won't be using it again.
} else {
grayscale = true;
}
std::optional<std::vector<uint8_t>> attrmap;
@@ -497,10 +500,10 @@ void reverse() {
}
png_set_write_fn(png, &pngFile, writePng, flushPng);
int pngColorType = options.palettes.empty() ? PNG_COLOR_TYPE_GRAY
: palettes.size() == 1 ? PNG_COLOR_TYPE_PALETTE
: PNG_COLOR_TYPE_RGB_ALPHA;
int pngDepth = options.palettes.empty() ? options.bitDepth : 8;
int pngColorType = grayscale ? PNG_COLOR_TYPE_GRAY
: palettes.size() == 1 ? PNG_COLOR_TYPE_PALETTE
: PNG_COLOR_TYPE_RGB_ALPHA;
int pngDepth = grayscale ? options.bitDepth : 8;
png_set_IHDR(
png,
@@ -531,17 +534,21 @@ void reverse() {
png_byte pngTrans[4] = {};
int nbPngColors = 0, nbPngTrans = 0;
for (auto const &color : palettes[0]) {
if (!color.has_value()) {
continue;
if (color.has_value()) {
pngPalette[nbPngColors].red = color->red;
pngPalette[nbPngColors].green = color->green;
pngPalette[nbPngColors].blue = color->blue;
pngTrans[nbPngColors] = color->alpha;
if (color->alpha < 255) {
nbPngTrans = nbPngColors;
}
} else {
pngPalette[nbPngColors].red = 255;
pngPalette[nbPngColors].green = 255;
pngPalette[nbPngColors].blue = 255;
pngTrans[nbPngColors] = 255;
}
pngPalette[nbPngColors].red = color->red;
pngPalette[nbPngColors].green = color->green;
pngPalette[nbPngColors].blue = color->blue;
pngTrans[nbPngColors] = color->alpha;
++nbPngColors;
if (color->alpha < 255) {
nbPngTrans = nbPngColors;
}
}
png_set_PLTE(png, pngInfo, pngPalette, nbPngColors);
if (nbPngTrans > 0) {
+2 -1
View File
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: MIT
#include "platform.hpp"
#include "link/assign.hpp"
#include <algorithm>
@@ -16,7 +18,6 @@
#include "helpers.hpp"
#include "itertools.hpp"
#include "linkdefs.hpp"
#include "platform.hpp"
#include "verbosity.hpp"
#include "link/main.hpp"
+2 -1
View File
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: MIT
#include "platform.hpp"
#include "link/object.hpp"
#include <deque>
@@ -18,7 +20,6 @@
#include "helpers.hpp"
#include "linkdefs.hpp"
#include "platform.hpp"
#include "util.hpp" // xfclose
#include "verbosity.hpp"
#include "version.hpp"
+2 -1
View File
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: MIT
#include "platform.hpp"
#include "link/output.hpp"
#include <algorithm>
@@ -19,7 +21,6 @@
#include "extern/utf8decoder.hpp"
#include "helpers.hpp"
#include "linkdefs.hpp"
#include "platform.hpp"
#include "util.hpp"
#include "link/main.hpp"
+2 -1
View File
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: MIT
#include "platform.hpp"
#include "link/sdas_obj.hpp"
#include <inttypes.h>
@@ -14,7 +16,6 @@
#include "helpers.hpp" // assume, literal_strlen
#include "linkdefs.hpp"
#include "platform.hpp"
#include "util.hpp" // parseWholeNumber
#include "link/fstack.hpp"
+2 -2
View File
@@ -3,14 +3,14 @@
// This implementation was based on https://github.com/agauniyal/rang/
// and adapted for RGBDS.
#include "platform.hpp" // isatty, strcasecmp
#include "style.hpp"
#include <stdio.h>
#include <stdlib.h> // getenv
#include <string.h>
#include "platform.hpp" // isatty, strcasecmp
#if !STYLE_ANSI
// clang-format off: maintain `include` order
#define WIN32_LEAN_AND_MEAN // Include less from `windows.h`
+2 -1
View File
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: MIT
#include "platform.hpp"
#include "usage.hpp"
#include <stdarg.h>
@@ -8,7 +10,6 @@
#include "diagnostics.hpp" // vfatalx
#include "helpers.hpp"
#include "platform.hpp"
#include "style.hpp"
#include "util.hpp" // parseWholeNumber
#include "version.hpp"
+2 -1
View File
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: MIT
#include "platform.hpp"
#include "util.hpp"
#include <errno.h>
@@ -9,7 +11,6 @@
#include <string.h> // strspn
#include "helpers.hpp" // assume
#include "platform.hpp"
int xfclose(FILE *file) {
if (file == stdin || file == stdout || file == stderr) {