mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-21 18:52:07 +00:00
Implement -c #none (#1301)
Also adds a test case for round-tripping `-r` with `-c #none`.
This commit is contained in:
@@ -768,9 +768,16 @@ int main(int argc, char *argv[]) {
|
||||
}());
|
||||
if (options.palSpecType == Options::EXPLICIT) {
|
||||
fputs("\t[\n", stderr);
|
||||
for (std::array<Rgba, 4> const &pal : options.palSpec) {
|
||||
fprintf(stderr, "\t\t#%06x, #%06x, #%06x, #%06x,\n", pal[0].toCSS() >> 8,
|
||||
pal[1].toCSS() >> 8, pal[2].toCSS() >> 8, pal[3].toCSS() >> 8);
|
||||
for (const auto &pal : options.palSpec) {
|
||||
fputs("\t\t", stderr);
|
||||
for (auto &color : pal) {
|
||||
if (color) {
|
||||
fprintf(stderr, "#%06x, ", color->toCSS() >> 8);
|
||||
} else {
|
||||
fputs("#none, ", stderr);
|
||||
}
|
||||
}
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
fputs("\t]\n", stderr);
|
||||
}
|
||||
@@ -847,18 +854,27 @@ auto Palette::begin() -> decltype(colors)::iterator {
|
||||
// Skip the first slot if reserved for transparency
|
||||
return colors.begin() + options.hasTransparentPixels;
|
||||
}
|
||||
|
||||
auto Palette::end() -> decltype(colors)::iterator {
|
||||
return std::find(begin(), colors.end(), UINT16_MAX);
|
||||
// Return an iterator pointing past the last non-empty element.
|
||||
// Since the palette may contain gaps, we must scan from the end.
|
||||
return std::find_if(colors.rbegin(), colors.rend(),
|
||||
[](uint16_t c) { return c != UINT16_MAX; })
|
||||
.base();
|
||||
}
|
||||
|
||||
auto Palette::begin() const -> decltype(colors)::const_iterator {
|
||||
// Skip the first slot if reserved for transparency
|
||||
return colors.begin() + options.hasTransparentPixels;
|
||||
}
|
||||
|
||||
auto Palette::end() const -> decltype(colors)::const_iterator {
|
||||
return std::find(begin(), colors.end(), UINT16_MAX);
|
||||
// Same as the non-const end().
|
||||
return std::find_if(colors.rbegin(), colors.rend(),
|
||||
[](uint16_t c) { return c != UINT16_MAX; })
|
||||
.base();
|
||||
}
|
||||
|
||||
uint8_t Palette::size() const {
|
||||
return indexOf(UINT16_MAX);
|
||||
return end() - colors.begin();
|
||||
}
|
||||
|
||||
@@ -54,7 +54,8 @@ static void skipWhitespace(Str const &str, typename Str::size_type &pos) {
|
||||
}
|
||||
|
||||
void parseInlinePalSpec(char const * const rawArg) {
|
||||
// List of #rrggbb/#rgb colors, comma-separated, palettes are separated by colons
|
||||
// List of #rrggbb/#rgb colors (or #none); comma-separated.
|
||||
// Palettes are separated by colons.
|
||||
|
||||
std::string_view arg(rawArg);
|
||||
using size_type = decltype(arg)::size_type;
|
||||
@@ -87,25 +88,31 @@ void parseInlinePalSpec(char const * const rawArg) {
|
||||
for (;;) {
|
||||
++n; // Ignore the '#' (checked either by caller or previous loop iteration)
|
||||
|
||||
Rgba &color = options.palSpec.back()[nbColors];
|
||||
auto pos = std::min(arg.find_first_not_of("0123456789ABCDEFabcdef"sv, n), arg.length());
|
||||
switch (pos - n) {
|
||||
case 3:
|
||||
color = Rgba(singleToHex(arg[n + 0]), singleToHex(arg[n + 1]), singleToHex(arg[n + 2]),
|
||||
0xFF);
|
||||
break;
|
||||
case 6:
|
||||
color = Rgba(toHex(arg[n + 0], arg[n + 1]), toHex(arg[n + 2], arg[n + 3]),
|
||||
toHex(arg[n + 4], arg[n + 5]), 0xFF);
|
||||
break;
|
||||
case 0:
|
||||
parseError(n - 1, 1, "Missing color after '#'");
|
||||
return;
|
||||
default:
|
||||
parseError(n, pos - n, "Unknown color specification");
|
||||
return;
|
||||
std::optional<Rgba> &color = options.palSpec.back()[nbColors];
|
||||
// Check for #none first.
|
||||
if (arg.compare(n, 4, "none"sv) == 0 || arg.compare(n, 4, "NONE"sv) == 0) {
|
||||
color = {};
|
||||
n += 4;
|
||||
} else {
|
||||
auto pos = std::min(arg.find_first_not_of("0123456789ABCDEFabcdef"sv, n), arg.length());
|
||||
switch (pos - n) {
|
||||
case 3:
|
||||
color = Rgba(singleToHex(arg[n + 0]), singleToHex(arg[n + 1]), singleToHex(arg[n + 2]),
|
||||
0xFF);
|
||||
break;
|
||||
case 6:
|
||||
color = Rgba(toHex(arg[n + 0], arg[n + 1]), toHex(arg[n + 2], arg[n + 3]),
|
||||
toHex(arg[n + 4], arg[n + 5]), 0xFF);
|
||||
break;
|
||||
case 0:
|
||||
parseError(n - 1, 1, "Missing color after '#'");
|
||||
return;
|
||||
default:
|
||||
parseError(n, pos - n, "Unknown color specification");
|
||||
return;
|
||||
}
|
||||
n = pos;
|
||||
}
|
||||
n = pos;
|
||||
|
||||
// Skip whitespace, if any
|
||||
skipWhitespace(arg, n);
|
||||
@@ -442,7 +449,7 @@ static void parseACTFile(std::filebuf &file) {
|
||||
char const *ptr = buf.data();
|
||||
size_t colorIdx = 0;
|
||||
for (uint16_t i = 0; i < nbColors; ++i) {
|
||||
Rgba &color = options.palSpec.back()[colorIdx];
|
||||
std::optional<Rgba> &color = options.palSpec.back()[colorIdx];
|
||||
color = Rgba(ptr[0], ptr[1], ptr[2], 0xFF);
|
||||
|
||||
ptr += 3;
|
||||
@@ -498,7 +505,7 @@ static void parseACOFile(std::filebuf &file) {
|
||||
options.palSpec.emplace_back();
|
||||
}
|
||||
|
||||
Rgba &color = options.palSpec.back()[i % options.nbColorsPerPal];
|
||||
std::optional<Rgba> &color = options.palSpec.back()[i % options.nbColorsPerPal];
|
||||
uint16_t colorType = readBE<uint16_t>(buf);
|
||||
switch (colorType) {
|
||||
case 0: // RGB
|
||||
|
||||
@@ -576,8 +576,11 @@ static std::tuple<DefaultInitVec<size_t>, std::vector<Palette>>
|
||||
// Convert the palette spec to actual palettes
|
||||
std::vector<Palette> palettes(options.palSpec.size());
|
||||
for (auto [spec, pal] : zip(options.palSpec, palettes)) {
|
||||
for (size_t i = 0; i < options.nbColorsPerPal && spec[i].isOpaque(); ++i) {
|
||||
pal[i] = spec[i].cgbColor();
|
||||
for (size_t i = 0; i < options.nbColorsPerPal && (!spec[i] || spec[i]->isOpaque()); ++i) {
|
||||
// If the spec has a gap, there's no need to copy anything.
|
||||
if (spec[i]) {
|
||||
pal[i] = spec[i]->cgbColor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -137,7 +137,7 @@ void reverse() {
|
||||
|
||||
// TODO: `-U` to configure tile size beyond 8x8px ("deduplication units")
|
||||
|
||||
std::vector<std::array<Rgba, 4>> palettes{
|
||||
std::vector<std::array<std::optional<Rgba>, 4>> palettes{
|
||||
{Rgba(0xFFFFFFFF), Rgba(0xAAAAAAFF), Rgba(0x555555FF), Rgba(0x000000FF)}
|
||||
};
|
||||
// If a palette file is used as input, it overrides the default colors.
|
||||
@@ -313,7 +313,7 @@ void reverse() {
|
||||
uint8_t *ptr = &rowPtrs[y][tx * 8 * SIZEOF_PIXEL];
|
||||
for (uint8_t x = 0; x < 8; ++x) {
|
||||
uint8_t bit0 = bitplane0 & 0x80, bit1 = bitplane1 & 0x80;
|
||||
Rgba const &pixel = palette[bit0 >> 7 | bit1 >> 6];
|
||||
Rgba const &pixel = *palette[bit0 >> 7 | bit1 >> 6];
|
||||
*ptr++ = pixel.red;
|
||||
*ptr++ = pixel.green;
|
||||
*ptr++ = pixel.blue;
|
||||
|
||||
Reference in New Issue
Block a user