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
+179 -115

No files matched your search

+2
View File
@@ -42,6 +42,8 @@ EmptyLineBeforeAccessModifier: Leave
FixNamespaceComments: false FixNamespaceComments: false
IncludeBlocks: Regroup IncludeBlocks: Regroup
IncludeCategories: IncludeCategories:
- Regex: '^"platform\.hpp"$'
Priority: -1
- Regex: '^<sys/' - Regex: '^<sys/'
Priority: 0 Priority: 0
- Regex: '^<' - Regex: '^<'
+6 -2
View File
@@ -371,8 +371,12 @@ jobs:
python312-imaging python312-imaging
- name: Build using Make - name: Build using Make
if: matrix.arch == 'x86' if: matrix.arch == 'x86'
run: | # Cygwin doesn't support `make develop` sanitizers ASan or UBSan, so we don't use it. run: | # Cygwin doesn't support `make develop` sanitizers ASan or UBSan, so we disable them.
make -k -j "$(getconf _NPROCESSORS_ONLN)" Q= : # 32-bit Cygwin stopped updating since 2022-11-23, and its g++ 11.3.0 gives a false
: # positive "potential null pointer dereference" error on `patch.pcOffset -= pcShift;`
: # in src/asm/output.cpp, so we disable that warning option.
make develop -k -j "$(getconf _NPROCESSORS_ONLN)" Q= \
WARNFLAGS="-fno-sanitize=all -Wno-null-dereference"
- name: Install using Make - name: Install using Make
if: matrix.arch == 'x86' if: matrix.arch == 'x86'
run: | run: |
+4 -3
View File
@@ -222,7 +222,7 @@ install: all
# continous integration infrastructure return failure. # continous integration infrastructure return failure.
# The rationale for some of the flags is documented in the CMakeLists. # The rationale for some of the flags is documented in the CMakeLists.
develop: develop:
$Q${MAKE} WARNFLAGS="${WARNFLAGS} -Werror -Wextra \ $Q${MAKE} WARNFLAGS="-Werror -Wextra \
-Walloc-zero -Wcast-align -Wcast-qual -Wduplicated-branches -Wduplicated-cond \ -Walloc-zero -Wcast-align -Wcast-qual -Wduplicated-branches -Wduplicated-cond \
-Wfloat-equal -Wlogical-op -Wnull-dereference -Wold-style-cast -Wshift-overflow=2 \ -Wfloat-equal -Wlogical-op -Wnull-dereference -Wold-style-cast -Wshift-overflow=2 \
-Wstringop-overflow=4 -Wtrampolines -Wundef -Wuninitialized -Wunused -Wshadow \ -Wstringop-overflow=4 -Wtrampolines -Wundef -Wuninitialized -Wunused -Wshadow \
@@ -232,8 +232,9 @@ develop:
-D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC -D_GLIBCXX_SANITIZE_VECTOR \ -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC -D_GLIBCXX_SANITIZE_VECTOR \
-D_GLIBCXX_VERBOSE_ASSERT -D_GLIBCXX_EXTERN_TEMPLATE=0 \ -D_GLIBCXX_VERBOSE_ASSERT -D_GLIBCXX_EXTERN_TEMPLATE=0 \
-D_LIBCPP_DEBUG -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG \ -D_LIBCPP_DEBUG -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG \
-fsanitize=address -fsanitize=undefined -fsanitize=float-divide-by-zero" \ -fsanitize=address -fsanitize=undefined -fsanitize=float-divide-by-zero \
CXXFLAGS="-ggdb3 -Og -fno-omit-frame-pointer -fno-optimize-sibling-calls" ${WARNFLAGS}" \
CXXFLAGS="-ggdb3 -Og -fno-omit-frame-pointer -fno-optimize-sibling-calls ${CXXFLAGS}"
# Target used in development to debug with gdb. # Target used in development to debug with gdb.
debug: debug:
+19 -5
View File
@@ -57,6 +57,18 @@ just modifying a file, you don't need to do anything (maybe update the copyright
years). If you are adding new files, you need to use the years). If you are adding new files, you need to use the
`SPDX-License-Identifier: MIT` header. `SPDX-License-Identifier: MIT` header.
### AI usage
If you are using AI to assist in writing your contribution, you must follow
[GBDev's AI policy](https://gbdev.io/aipolicy.html). In particular, you are
responsible for reviewing all AI-generated code, ensuring compliance with
licensing requirements, and taking full responsibility for the contribution.
When AI tools have meaningfully assisted in producing a contribution, you must
disclose it with an `Assisted-by` tag in the Git commit message, as detailed
by the policy.
### Contribution steps
1. Fork this repository. 1. Fork this repository.
2. Checkout the `master` branch. 2. Checkout the `master` branch.
3. Create a new branch to work on. You could still work on `master`, but it's 3. Create a new branch to work on. You could still work on `master`, but it's
@@ -66,15 +78,17 @@ years). If you are adding new files, you need to use the
new warning (but it may be possible to remove some warning checks if it makes new warning (but it may be possible to remove some warning checks if it makes
the code much easier). the code much easier).
You can also use `cmake --preset develop` if you prefer. You can also use `cmake --preset develop` if you prefer.
5. Test your changes by running `./run-tests.sh` in the `test` directory. 5. Test your changes by running `./run-tests.sh` in the `test` directory.
`./run-tests.sh --help` will print its available options. (You must run `./run-tests.sh --help` will print its available options. (You must run
`external/fetch-repos.sh` first; if you forget to, the test suite will fail and `external/fetch-repos.sh` first; if you forget to, the test suite will fail and
remind you mid-way.) remind you mid-way.)
You can also use `ctest --test-dir build` if you prefer. You can also use `ctest --test-dir build` if you prefer.
`ctest --test-dir build --print-labels` will print its available `ctest --test-dir build --print-labels` will print its available
[test labels](https://cmake.org/cmake/help/latest/manual/ctest.1.html#label-matching). [test labels](https://cmake.org/cmake/help/latest/manual/ctest.1.html#label-matching).
6. Format your changes according to `clang-format`, which will reformat the 6. Format your changes according to `clang-format`, which will reformat the
coding style according to our standards defined in `.clang-format`. You can coding style according to our standards defined in `.clang-format`. You can
use `make format` to format all the C++ files. use `make format` to format all the C++ files.
@@ -133,7 +147,7 @@ its contents.
### RGBLINK ### RGBLINK
Each `.asm` file corresponds to one test, or one *set* of tests. Each `.asm` file corresponds to one test, or one _set_ of tests.
All tests begin by assembling the `.asm` file into an object file, which will be All tests begin by assembling the `.asm` file into an object file, which will be
linked in various ways depending on the test. linked in various ways depending on the test.
+2 -1
View File
@@ -3,6 +3,8 @@
#ifndef RGBDS_FILE_HPP #ifndef RGBDS_FILE_HPP
#define RGBDS_FILE_HPP #define RGBDS_FILE_HPP
#include "platform.hpp"
#include <fcntl.h> #include <fcntl.h>
#include <fstream> #include <fstream>
#include <ios> #include <ios>
@@ -12,7 +14,6 @@
#include <variant> #include <variant>
#include "helpers.hpp" // assume #include "helpers.hpp" // assume
#include "platform.hpp"
class File { class File {
std::variant<std::streambuf *, std::filebuf> _file; std::variant<std::streambuf *, std::filebuf> _file;
+4
View File
@@ -4,8 +4,12 @@
#define RGBDS_GFX_PAL_SPEC_HPP #define RGBDS_GFX_PAL_SPEC_HPP
#include <stdint.h> #include <stdint.h>
#include <string>
#include "gfx/png.hpp"
void parseInlinePalSpec(char const * const rawArg); void parseInlinePalSpec(char const * const rawArg);
void parseEmbeddedPalSpec(Png const &png);
void parseExternalPalSpec(char const *arg); void parseExternalPalSpec(char const *arg);
void parseDmgPalSpec(char const * const rawArg); void parseDmgPalSpec(char const * const rawArg);
void parseBackgroundPalSpec(char const *arg); void parseBackgroundPalSpec(char const *arg);
+3 -1
View File
@@ -3,7 +3,9 @@
#ifndef RGBDS_GFX_PROCESS_HPP #ifndef RGBDS_GFX_PROCESS_HPP
#define RGBDS_GFX_PROCESS_HPP #define RGBDS_GFX_PROCESS_HPP
#include "gfx/png.hpp"
void processPalettes(); void processPalettes();
void process(); void process(Png &&png);
#endif // RGBDS_GFX_PROCESS_HPP #endif // RGBDS_GFX_PROCESS_HPP
+6 -11
View File
@@ -3,6 +3,12 @@
#ifndef RGBDS_PLATFORM_HPP #ifndef RGBDS_PLATFORM_HPP
#define RGBDS_PLATFORM_HPP #define RGBDS_PLATFORM_HPP
// MingGW and Cygwin may need POSIX functions which are not standard C explicitly enabled
// Make sure to keep this before any system header!
#if (defined(__MINGW32__) || defined(__CYGWIN__)) && !defined(_POSIX_C_SOURCE)
#define _POSIX_C_SOURCE 200809L
#endif
// MSVC doesn't have str(n)casecmp, use a suitable replacement // MSVC doesn't have str(n)casecmp, use a suitable replacement
#ifdef _MSC_VER #ifdef _MSC_VER
#include <string.h> // IWYU pragma: export #include <string.h> // IWYU pragma: export
@@ -55,17 +61,6 @@
#define setmode(fd, mode) (0) #define setmode(fd, mode) (0)
#endif #endif
// Windows has 32-bit `long`, which limits `fseek` and `ftell` to 2 GiB
#if defined(_MSC_VER) || defined(__MINGW32__)
#define fseek _fseeki64
#define ftell _ftelli64
#endif
// MingGW and Cygwin may need POSIX functions which are not standard C explicitly enabled
#if (defined(__MINGW32__) || defined(__CYGWIN__)) && !defined(_POSIX_C_SOURCE)
#define _POSIX_C_SOURCE 200809L
#endif
// Apple has deprecated `sprintf` since Xcode 14 (for macOS 13), but we use it solely in // Apple has deprecated `sprintf` since Xcode 14 (for macOS 13), but we use it solely in
// contexts where both the size of the buffer *and* max size of the printed string are // contexts where both the size of the buffer *and* max size of the printed string are
// known statically, which GCC thus checks for. // known statically, which GCC thus checks for.
+2 -1
View File
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
#include "platform.hpp" // strncasecmp
#include "asm/fstack.hpp" #include "asm/fstack.hpp"
#include <sys/stat.h> #include <sys/stat.h>
@@ -22,7 +24,6 @@
#include "helpers.hpp" #include "helpers.hpp"
#include "itertools.hpp" // reversed #include "itertools.hpp" // reversed
#include "linkdefs.hpp" #include "linkdefs.hpp"
#include "platform.hpp" // strncasecmp
#include "verbosity.hpp" #include "verbosity.hpp"
#include "asm/intern.hpp" #include "asm/intern.hpp"
+2 -1
View File
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
#include "platform.hpp"
#include "asm/lexer.hpp" #include "asm/lexer.hpp"
#include <sys/stat.h> #include <sys/stat.h>
@@ -27,7 +29,6 @@
#include <vector> #include <vector>
#include "helpers.hpp" #include "helpers.hpp"
#include "platform.hpp"
#include "style.hpp" #include "style.hpp"
#include "util.hpp" #include "util.hpp"
#include "verbosity.hpp" #include "verbosity.hpp"
+3 -2
View File
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
#include "platform.hpp"
#include "asm/main.hpp" #include "asm/main.hpp"
#include <algorithm> #include <algorithm>
@@ -23,8 +25,7 @@
#include "diagnostics.hpp" #include "diagnostics.hpp"
#include "helpers.hpp" #include "helpers.hpp"
#include "parser.hpp" // Generated from parser.y #include "parser.hpp" // Generated from parser.y
#include "platform.hpp" #include "style.hpp" // style_Parse
#include "style.hpp" // style_Parse
#include "usage.hpp" #include "usage.hpp"
#include "util.hpp" // UpperMap #include "util.hpp" // UpperMap
#include "verbosity.hpp" #include "verbosity.hpp"
+2 -1
View File
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
#include "platform.hpp"
#include "asm/output.hpp" #include "asm/output.hpp"
#include <algorithm> #include <algorithm>
@@ -16,7 +18,6 @@
#include "helpers.hpp" // assume, Defer #include "helpers.hpp" // assume, Defer
#include "linkdefs.hpp" #include "linkdefs.hpp"
#include "platform.hpp"
#include "util.hpp" // xfclose #include "util.hpp" // xfclose
#include "asm/charmap.hpp" #include "asm/charmap.hpp"
+3 -2
View File
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
#include "platform.hpp" // fseek
#include "asm/section.hpp" #include "asm/section.hpp"
#include <algorithm> #include <algorithm>
@@ -21,8 +23,7 @@
#include "helpers.hpp" #include "helpers.hpp"
#include "itertools.hpp" // InsertionOrderedMap #include "itertools.hpp" // InsertionOrderedMap
#include "linkdefs.hpp" #include "linkdefs.hpp"
#include "platform.hpp" // fseek #include "util.hpp" // xfclose, seekSize
#include "util.hpp" // xfclose, seekSize
#include "asm/fstack.hpp" #include "asm/fstack.hpp"
#include "asm/lexer.hpp" #include "asm/lexer.hpp"
+3 -2
View File
@@ -1,12 +1,13 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
#include "platform.hpp" // strcasecmp
#include "backtrace.hpp" #include "backtrace.hpp"
#include <optional> #include <optional>
#include <stdint.h> #include <stdint.h>
#include "platform.hpp" // strcasecmp #include "util.hpp" // parseWholeNumber
#include "util.hpp" // parseWholeNumber
Tracing tracing; Tracing tracing;
+2 -1
View File
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
#include "platform.hpp"
#include "fix/fix.hpp" #include "fix/fix.hpp"
#include <sys/stat.h> #include <sys/stat.h>
@@ -14,7 +16,6 @@
#include "diagnostics.hpp" #include "diagnostics.hpp"
#include "helpers.hpp" #include "helpers.hpp"
#include "platform.hpp"
#include "util.hpp" // xclose, xfclose #include "util.hpp" // xclose, xfclose
#include "fix/main.hpp" #include "fix/main.hpp"
+2 -1
View File
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
#include "platform.hpp"
#include "fix/main.hpp" #include "fix/main.hpp"
#include <errno.h> #include <errno.h>
@@ -15,7 +17,6 @@
#include "cli.hpp" #include "cli.hpp"
#include "diagnostics.hpp" #include "diagnostics.hpp"
#include "helpers.hpp" #include "helpers.hpp"
#include "platform.hpp"
#include "style.hpp" #include "style.hpp"
#include "usage.hpp" #include "usage.hpp"
#include "util.hpp" #include "util.hpp"
+3 -2
View File
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
#include "platform.hpp" // strcasecmp
#include "fix/mbc.hpp" #include "fix/mbc.hpp"
#include <optional> #include <optional>
@@ -10,8 +12,7 @@
#include <unordered_map> #include <unordered_map>
#include <utility> #include <utility>
#include "helpers.hpp" // unreachable_ #include "helpers.hpp" // unreachable_
#include "platform.hpp" // strcasecmp
#include "util.hpp" #include "util.hpp"
#include "fix/warning.hpp" #include "fix/warning.hpp"
+32 -7
View File
@@ -1,10 +1,13 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
#include "platform.hpp"
#include "gfx/main.hpp" #include "gfx/main.hpp"
#include <inttypes.h> #include <inttypes.h>
#include <ios> #include <ios>
#include <optional> #include <optional>
#include <png.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
@@ -18,7 +21,6 @@
#include "diagnostics.hpp" #include "diagnostics.hpp"
#include "file.hpp" #include "file.hpp"
#include "helpers.hpp" #include "helpers.hpp"
#include "platform.hpp"
#include "style.hpp" // style_Parse #include "style.hpp" // style_Parse
#include "usage.hpp" #include "usage.hpp"
#include "util.hpp" #include "util.hpp"
@@ -479,6 +481,7 @@ static void parseArg(int ch, char *arg) {
// LCOV_EXCL_START // LCOV_EXCL_START
static void verboseOutputConfig() { static void verboseOutputConfig() {
usage.printVersion(true); usage.printVersion(true);
fprintf(stderr, "Using libpng %s\n", png_get_libpng_ver(nullptr));
printVVVVVVerbosity(); printVVVVVVerbosity();
@@ -524,12 +527,18 @@ static void verboseOutputConfig() {
break; break;
case Options::INLINE: case Options::INLINE:
case Options::EXTERNAL: 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) { for (auto const &pal : options.palSpec) {
fputs("\t\t", stderr); fputs("\t\t", stderr);
for (auto const &color : pal) { for (auto const &color : pal) {
if (color.has_value()) { if (color.has_value()) {
fprintf(stderr, "#%06x, ", color->toCSS() >> 8); fprintf(stderr, "#%08x, ", color->toCSS());
} else { } else {
fputs("#none, ", stderr); fputs("#none, ", stderr);
} }
@@ -538,9 +547,6 @@ static void verboseOutputConfig() {
} }
fputs("\t]\n", stderr); fputs("\t]\n", stderr);
break; break;
case Options::EMBEDDED:
fputs("\tEmbedded palette spec from PNG indexed PLTE chunk\n", stderr);
break;
case Options::DMG: case Options::DMG:
fprintf(stderr, "\tDMG palette spec $%02" PRIx8 "\n", options.palSpecDmg); fprintf(stderr, "\tDMG palette spec $%02" PRIx8 "\n", options.palSpecDmg);
break; break;
@@ -671,13 +677,32 @@ int main(int argc, char *argv[]) {
autoOutPath(localOptions.autoPalettes, options.palettes, ".pal"); autoOutPath(localOptions.autoPalettes, options.palettes, ".pal");
autoOutPath(localOptions.autoPalmap, options.palmap, ".palmap"); 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. // Execute deferred pal spec parsing, now that all other params are known.
// Do not parse pal specs if `options.nbColorsPerPal` is invalid. // Do not parse pal specs if `options.nbColorsPerPal` is invalid.
if (options.nbColorsPerPal > 0 && options.nbColorsPerPal <= 4) { if (options.nbColorsPerPal > 0 && options.nbColorsPerPal <= 4) {
switch (options.palSpecType) { switch (options.palSpecType) {
case Options::NO_SPEC: case Options::NO_SPEC:
assume(!localOptions.palSpec);
break;
case Options::EMBEDDED: case Options::EMBEDDED:
assume(!localOptions.palSpec); assume(!localOptions.palSpec);
if (useInputImage) {
parseEmbeddedPalSpec(png);
}
break; break;
case Options::INLINE: case Options::INLINE:
assume(localOptions.palSpec); assume(localOptions.palSpec);
@@ -703,7 +728,7 @@ int main(int argc, char *argv[]) {
if (localOptions.reverse) { if (localOptions.reverse) {
reverse(); reverse();
} else { } else {
process(); process(std::move(png));
} }
} else if (!options.palettes.empty() && options.hasExplicitPalSpec() && !localOptions.reverse) { } else if (!options.palettes.empty() && options.hasExplicitPalSpec() && !localOptions.reverse) {
processPalettes(); processPalettes();
+25 -1
View File
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
#include "platform.hpp"
#include "gfx/pal_spec.hpp" #include "gfx/pal_spec.hpp"
#include <algorithm> #include <algorithm>
@@ -20,8 +22,8 @@
#include <vector> #include <vector>
#include "diagnostics.hpp" #include "diagnostics.hpp"
#include "file.hpp"
#include "helpers.hpp" #include "helpers.hpp"
#include "platform.hpp"
#include "util.hpp" // UpperMap, parseDigit #include "util.hpp" // UpperMap, parseDigit
#include "gfx/main.hpp" #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`. // Appends the first line read from `file` to the end of the provided `buffer`.
// Returns true if a line was read. // Returns true if a line was read.
[[nodiscard]] [[nodiscard]]
+6 -43
View File
@@ -8,7 +8,6 @@
#include <inttypes.h> #include <inttypes.h>
#include <ios> #include <ios>
#include <optional> #include <optional>
#include <png.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@@ -77,8 +76,8 @@ public:
}; };
struct Image { struct Image {
Png png{}; Png png;
ImagePalette colors{}; ImagePalette colors;
Rgba &pixel(uint32_t x, uint32_t y) { return png.pixels[y * png.width + x]; } 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]; } 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}; return {GrayscaleResult::GRAY_OK, std::nullopt};
} }
explicit Image(std::string const &path) { explicit Image(Png &&png_) : png(std::move(png_)), colors() {
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);
// Validate input slice // Validate input slice
if (options.inputSlice.width == 0 && png.width % 8 != 0) { if (options.inputSlice.width == 0 && png.width % 8 != 0) {
fatal("Image width (%" PRIu32 " pixels) is not a multiple of 8", png.width); 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>> static std::pair<std::vector<size_t>, std::vector<Palette>>
generatePalettes(std::vector<ColorSet> const &colorSets, Image const &image) { generatePalettes(std::vector<ColorSet> const &colorSets, Image const &image) {
// Run a "pagination" problem solver // Run a "pagination" problem solver
@@ -450,7 +420,7 @@ static std::pair<std::vector<size_t>, std::vector<Palette>>
if (i + skipFirst >= options.nbColorsPerPal) { if (i + skipFirst >= options.nbColorsPerPal) {
error( error(
"Each palette spec can only contain up to %" PRIu8 "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,
options.nbColorsPerPal - 1 == 1 ? "" : "s" options.nbColorsPerPal - 1 == 1 ? "" : "s"
); );
@@ -992,8 +962,6 @@ static void
} }
void processPalettes() { void processPalettes() {
verbosePrint(VERB_CONFIG, "Using libpng %s\n", png_get_libpng_ver(nullptr));
std::vector<ColorSet> colorSets; std::vector<ColorSet> colorSets;
std::vector<Palette> palettes; std::vector<Palette> palettes;
std::tie(std::ignore, palettes) = makePalsAsSpecified(colorSets); std::tie(std::ignore, palettes) = makePalsAsSpecified(colorSets);
@@ -1001,11 +969,9 @@ void processPalettes() {
outputPalettes(palettes); outputPalettes(palettes);
} }
void process() { void process(Png &&png) {
verbosePrint(VERB_CONFIG, "Using libpng %s\n", png_get_libpng_ver(nullptr));
verbosePrint(VERB_NOTICE, "Reading tiles...\n"); 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 // LCOV_EXCL_START
verboseDo(VERB_INFO, [&]() { verboseDo(VERB_INFO, [&]() {
@@ -1195,9 +1161,6 @@ continue_visiting_tiles:;
fatal("Image does not contain any colors"); fatal("Image does not contain any colors");
} }
if (options.palSpecType == Options::EMBEDDED) {
generatePalSpec(image);
}
auto [mappings, palettes] = auto [mappings, palettes] =
options.palSpecType == Options::NO_SPEC || options.palSpecType == Options::DMG options.palSpecType == Options::NO_SPEC || options.palSpecType == Options::DMG
? generatePalettes(colorSets, image) ? generatePalettes(colorSets, image)
+22 -15
View File
@@ -107,8 +107,6 @@ static void printPalette(std::array<std::optional<Rgba>, 4> const &palette) {
} }
void reverse() { void reverse() {
verbosePrint(VERB_CONFIG, "Using libpng %s\n", png_get_libpng_ver(nullptr));
// Check for weird flag combinations // Check for weird flag combinations
if (options.output.empty()) { if (options.output.empty()) {
@@ -205,6 +203,7 @@ void reverse() {
{grayColors[0], grayColors[1], grayColors[2], grayColors[3]} {grayColors[0], grayColors[1], grayColors[2], grayColors[3]}
}; };
// If a palette file or palette spec is used as input, it overrides the default colors. // If a palette file or palette spec is used as input, it overrides the default colors.
bool grayscale = false;
if (!options.palettes.empty()) { 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)) {
@@ -280,11 +279,15 @@ void reverse() {
for (size_t i = 0; i < palettes[0].size(); ++i) { for (size_t i = 0; i < palettes[0].size(); ++i) {
palettes[0][i] = grayColors[options.dmgValue(i)]; palettes[0][i] = grayColors[options.dmgValue(i)];
} }
grayscale = true;
} else if (options.palSpecType == Options::EMBEDDED) { } else if (options.palSpecType == Options::EMBEDDED) {
warnx("An embedded palette was requested, but no palette file was specified; ignoring " warnx("An embedded palette was requested, but no palette file was specified; ignoring "
"request"); "request");
grayscale = true;
} else if (options.hasExplicitPalSpec()) { } else if (options.hasExplicitPalSpec()) {
palettes = std::move(options.palSpec); // We won't be using it again. palettes = std::move(options.palSpec); // We won't be using it again.
} else {
grayscale = true;
} }
std::optional<std::vector<uint8_t>> attrmap; std::optional<std::vector<uint8_t>> attrmap;
@@ -497,10 +500,10 @@ void reverse() {
} }
png_set_write_fn(png, &pngFile, writePng, flushPng); png_set_write_fn(png, &pngFile, writePng, flushPng);
int pngColorType = options.palettes.empty() ? PNG_COLOR_TYPE_GRAY int pngColorType = grayscale ? PNG_COLOR_TYPE_GRAY
: palettes.size() == 1 ? PNG_COLOR_TYPE_PALETTE : palettes.size() == 1 ? PNG_COLOR_TYPE_PALETTE
: PNG_COLOR_TYPE_RGB_ALPHA; : PNG_COLOR_TYPE_RGB_ALPHA;
int pngDepth = options.palettes.empty() ? options.bitDepth : 8; int pngDepth = grayscale ? options.bitDepth : 8;
png_set_IHDR( png_set_IHDR(
png, png,
@@ -531,17 +534,21 @@ void reverse() {
png_byte pngTrans[4] = {}; png_byte pngTrans[4] = {};
int nbPngColors = 0, nbPngTrans = 0; int nbPngColors = 0, nbPngTrans = 0;
for (auto const &color : palettes[0]) { for (auto const &color : palettes[0]) {
if (!color.has_value()) { if (color.has_value()) {
continue; 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; ++nbPngColors;
if (color->alpha < 255) {
nbPngTrans = nbPngColors;
}
} }
png_set_PLTE(png, pngInfo, pngPalette, nbPngColors); png_set_PLTE(png, pngInfo, pngPalette, nbPngColors);
if (nbPngTrans > 0) { if (nbPngTrans > 0) {
+2 -1
View File
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
#include "platform.hpp"
#include "link/assign.hpp" #include "link/assign.hpp"
#include <algorithm> #include <algorithm>
@@ -16,7 +18,6 @@
#include "helpers.hpp" #include "helpers.hpp"
#include "itertools.hpp" #include "itertools.hpp"
#include "linkdefs.hpp" #include "linkdefs.hpp"
#include "platform.hpp"
#include "verbosity.hpp" #include "verbosity.hpp"
#include "link/main.hpp" #include "link/main.hpp"
+2 -1
View File
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
#include "platform.hpp"
#include "link/object.hpp" #include "link/object.hpp"
#include <deque> #include <deque>
@@ -18,7 +20,6 @@
#include "helpers.hpp" #include "helpers.hpp"
#include "linkdefs.hpp" #include "linkdefs.hpp"
#include "platform.hpp"
#include "util.hpp" // xfclose #include "util.hpp" // xfclose
#include "verbosity.hpp" #include "verbosity.hpp"
#include "version.hpp" #include "version.hpp"
+2 -1
View File
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
#include "platform.hpp"
#include "link/output.hpp" #include "link/output.hpp"
#include <algorithm> #include <algorithm>
@@ -19,7 +21,6 @@
#include "extern/utf8decoder.hpp" #include "extern/utf8decoder.hpp"
#include "helpers.hpp" #include "helpers.hpp"
#include "linkdefs.hpp" #include "linkdefs.hpp"
#include "platform.hpp"
#include "util.hpp" #include "util.hpp"
#include "link/main.hpp" #include "link/main.hpp"
+2 -1
View File
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
#include "platform.hpp"
#include "link/sdas_obj.hpp" #include "link/sdas_obj.hpp"
#include <inttypes.h> #include <inttypes.h>
@@ -14,7 +16,6 @@
#include "helpers.hpp" // assume, literal_strlen #include "helpers.hpp" // assume, literal_strlen
#include "linkdefs.hpp" #include "linkdefs.hpp"
#include "platform.hpp"
#include "util.hpp" // parseWholeNumber #include "util.hpp" // parseWholeNumber
#include "link/fstack.hpp" #include "link/fstack.hpp"
+2 -2
View File
@@ -3,14 +3,14 @@
// This implementation was based on https://github.com/agauniyal/rang/ // This implementation was based on https://github.com/agauniyal/rang/
// and adapted for RGBDS. // and adapted for RGBDS.
#include "platform.hpp" // isatty, strcasecmp
#include "style.hpp" #include "style.hpp"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> // getenv #include <stdlib.h> // getenv
#include <string.h> #include <string.h>
#include "platform.hpp" // isatty, strcasecmp
#if !STYLE_ANSI #if !STYLE_ANSI
// clang-format off: maintain `include` order // clang-format off: maintain `include` order
#define WIN32_LEAN_AND_MEAN // Include less from `windows.h` #define WIN32_LEAN_AND_MEAN // Include less from `windows.h`
+2 -1
View File
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
#include "platform.hpp"
#include "usage.hpp" #include "usage.hpp"
#include <stdarg.h> #include <stdarg.h>
@@ -8,7 +10,6 @@
#include "diagnostics.hpp" // vfatalx #include "diagnostics.hpp" // vfatalx
#include "helpers.hpp" #include "helpers.hpp"
#include "platform.hpp"
#include "style.hpp" #include "style.hpp"
#include "util.hpp" // parseWholeNumber #include "util.hpp" // parseWholeNumber
#include "version.hpp" #include "version.hpp"
+2 -1
View File
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
#include "platform.hpp"
#include "util.hpp" #include "util.hpp"
#include <errno.h> #include <errno.h>
@@ -9,7 +11,6 @@
#include <string.h> // strspn #include <string.h> // strspn
#include "helpers.hpp" // assume #include "helpers.hpp" // assume
#include "platform.hpp"
int xfclose(FILE *file) { int xfclose(FILE *file) {
if (file == stdin || file == stdout || file == stderr) { if (file == stdin || file == stdout || file == stderr) {
-4
View File
@@ -1,4 +0,0 @@
error: Failed to fit tile colors [GB:07,09,05; GB:12,14,05; GB:20,21,06] in specified palettes
note: The following palette was specified:
- [GB:20,21,06; GB:12,14,05]
Conversion aborted after 1 error
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -1,2 +1,2 @@
error: Each palette spec can only contain up to 1 color plus the implict transparent color error: Each palette spec can only contain up to 1 color plus the implicit transparent color
Conversion aborted after 1 error Conversion aborted after 1 error
+2
View File
@@ -0,0 +1,2 @@
error: Each palette spec can only contain up to 3 colors plus the implicit transparent color
Conversion aborted after 1 error
@@ -0,0 +1 @@
-c embedded
Binary file not shown.

After

Width:  |  Height:  |  Size: 135 B

+2
View File
@@ -0,0 +1,2 @@
error: Each palette spec can only contain up to 3 colors plus the implicit transparent color
Conversion aborted after 1 error
@@ -0,0 +1 @@
-c gbc:middle_transparent_gbc_spec.pal
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 135 B

+2
View File
@@ -0,0 +1,2 @@
error: Each palette spec can only contain up to 3 colors plus the implicit transparent color
Conversion aborted after 1 error
@@ -0,0 +1 @@
-c png:middle_transparent_png_spec.pal.png
Binary file not shown.

After

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 B

+1
View File
@@ -0,0 +1 @@
U3U3U3U3U3U3U3U3
+1
View File
@@ -0,0 +1 @@
-c #ff0000,#00ff00,#0000ff,#ffffff