Implement base palette ID

This commit is contained in:
Rangi42
2025-07-04 02:14:20 -04:00
committed by Eldred Habert
parent d7b1569ee6
commit 185a3b29e6
11 changed files with 36 additions and 12 deletions

View File

@@ -43,6 +43,7 @@ struct Options {
uint32_t right() const { return left + width * 8; } uint32_t right() const { return left + width * 8; }
uint32_t bottom() const { return top + height * 8; } uint32_t bottom() const { return top + height * 8; }
} inputSlice{0, 0, 0, 0}; // -L (margins in clockwise order, like CSS) } inputSlice{0, 0, 0, 0}; // -L (margins in clockwise order, like CSS)
uint8_t basePalID = 0; // -l
std::array<uint16_t, 2> maxNbTiles{UINT16_MAX, 0}; // -N std::array<uint16_t, 2> maxNbTiles{UINT16_MAX, 0}; // -N
uint16_t nbPalettes = 8; // -n uint16_t nbPalettes = 8; // -n
std::string output{}; // -o std::string output{}; // -o

View File

@@ -18,6 +18,7 @@
.Op Fl d Ar depth .Op Fl d Ar depth
.Op Fl i Ar input_tiles .Op Fl i Ar input_tiles
.Op Fl L Ar slice .Op Fl L Ar slice
.Op Fl l Ar base_pal
.Op Fl N Ar nb_tiles .Op Fl N Ar nb_tiles
.Op Fl n Ar nb_pals .Op Fl n Ar nb_pals
.Op Fl o Ar out_file .Op Fl o Ar out_file
@@ -261,6 +262,11 @@ The first number pair specifies the X and Y coordinates of the top-left pixel th
The second number pair specifies how many tiles to process horizontally and vertically, respectively. The second number pair specifies how many tiles to process horizontally and vertically, respectively.
.Pp .Pp
.Fl L Sy is ignored in reverse mode , No no padding is inserted . .Fl L Sy is ignored in reverse mode , No no padding is inserted .
.It Fl l Ar base_pal , Fl \-base-palette Ar base_pal
Set the base ID for attribute map and palette map output.
.Ar base_pal
should be a number between 0 and 255.
It defaults to 0.
.It Fl m , Fl \-mirror-tiles .It Fl m , Fl \-mirror-tiles
Deduplicate tiles that are horizontally and/or vertically symmetrical mirror images of each other. Deduplicate tiles that are horizontally and/or vertically symmetrical mirror images of each other.
Only one of each unique tile will be saved in the tile data file, with mirror images counting as duplicates. Only one of each unique tile will be saved in the tile data file, with mirror images counting as duplicates.

View File

@@ -113,7 +113,7 @@ void Options::verbosePrint(uint8_t level, char const *fmt, ...) const {
} }
// Short options // Short options
static char const *optstring = "-Aa:B:b:Cc:d:hi:L:mN:n:Oo:Pp:Qq:r:s:Tt:U:uVvXx:YZ"; static char const *optstring = "-Aa:B:b:Cc:d:hi:L:l:mN:n:Oo:Pp:Qq:r:s:Tt:U:uVvXx:YZ";
// Equivalent long options // Equivalent long options
// Please keep in the same order as short opts. // Please keep in the same order as short opts.
@@ -133,6 +133,7 @@ static option const longopts[] = {
{"help", no_argument, nullptr, 'h'}, {"help", no_argument, nullptr, 'h'},
{"input-tileset", required_argument, nullptr, 'i'}, {"input-tileset", required_argument, nullptr, 'i'},
{"slice", required_argument, nullptr, 'L'}, {"slice", required_argument, nullptr, 'L'},
{"base-palette", required_argument, nullptr, 'l'},
{"mirror-tiles", no_argument, nullptr, 'm'}, {"mirror-tiles", no_argument, nullptr, 'm'},
{"nb-tiles", required_argument, nullptr, 'N'}, {"nb-tiles", required_argument, nullptr, 'N'},
{"nb-palettes", required_argument, nullptr, 'n'}, {"nb-palettes", required_argument, nullptr, 'n'},
@@ -162,9 +163,9 @@ static void printUsage() {
fputs( fputs(
"Usage: rgbgfx [-r stride] [-ChmOuVXYZ] [-v [-v ...]] [-a <attr_map> | -A]\n" "Usage: rgbgfx [-r stride] [-ChmOuVXYZ] [-v [-v ...]] [-a <attr_map> | -A]\n"
" [-b <base_ids>] [-c <colors>] [-d <depth>] [-i <tileset_file>]\n" " [-b <base_ids>] [-c <colors>] [-d <depth>] [-i <tileset_file>]\n"
" [-L <slice>] [-N <nb_tiles>] [-n <nb_pals>] [-o <out_file>]\n" " [-L <slice>] [-l <base_pal>] [-N <nb_tiles>] [-n <nb_pals>]\n"
" [-p <pal_file> | -P] [-q <pal_map> | -Q] [-s <nb_colors>]\n" " [-o <out_file>] [-p <pal_file> | -P] [-q <pal_map> | -Q]\n"
" [-t <tile_map> | -T] [-x <nb_tiles>] <file>\n" " [-s <nb_colors>] [-t <tile_map> | -T] [-x <nb_tiles>] <file>\n"
"Useful options:\n" "Useful options:\n"
" -m, --mirror-tiles optimize out mirrored tiles\n" " -m, --mirror-tiles optimize out mirrored tiles\n"
" -o, --output <path> output the tile data to this path\n" " -o, --output <path> output the tile data to this path\n"
@@ -481,6 +482,16 @@ static char *parseArgv(int argc, char *argv[]) {
error("Unexpected extra characters after slice spec in \"%s\"", musl_optarg); error("Unexpected extra characters after slice spec in \"%s\"", musl_optarg);
} }
break; break;
case 'l':
number = parseNumber(arg, "Base palette ID", 0);
if (*arg != '\0') {
error("Base palette ID must be a valid number, not \"%s\"", musl_optarg);
} else if (number >= 256) {
error("Base palette ID must be below 256");
} else {
options.basePalID = number;
}
break;
case 'm': case 'm':
options.allowMirroringX = true; // Imply `-X` options.allowMirroringX = true; // Imply `-X`
options.allowMirroringY = true; // Imply `-Y` options.allowMirroringY = true; // Imply `-Y`
@@ -876,6 +887,7 @@ int main(int argc, char *argv[]) {
options.baseTileIDs[0], options.baseTileIDs[0],
options.baseTileIDs[1] options.baseTileIDs[1]
); );
fprintf(stderr, "\tBase palette ID: %" PRIu8 "\n", options.basePalID);
fprintf( fprintf(
stderr, stderr,
"\tMaximum %" PRIu16 " tiles in bank 0, %" PRIu16 " in bank 1\n", "\tMaximum %" PRIu16 " tiles in bank 0, %" PRIu16 " in bank 1\n",

View File

@@ -928,9 +928,9 @@ static void outputUnoptimizedMaps(
(*tilemapOutput) (*tilemapOutput)
->sputc((attr.isBackgroundTile() ? 0 : tileID) + options.baseTileIDs[bank]); ->sputc((attr.isBackgroundTile() ? 0 : tileID) + options.baseTileIDs[bank]);
} }
uint8_t palID = attr.getPalID(mappings); uint8_t palID = attr.getPalID(mappings) + options.basePalID;
if (attrmapOutput.has_value()) { if (attrmapOutput.has_value()) {
(*attrmapOutput)->sputc((palID & 7) | bank << 3); // The other flags are all 0 (*attrmapOutput)->sputc((palID & 0b111) | bank << 3); // The other flags are all 0
} }
if (palmapOutput.has_value()) { if (palmapOutput.has_value()) {
(*palmapOutput)->sputc(palID); (*palmapOutput)->sputc(palID);
@@ -1112,7 +1112,7 @@ static void outputAttrmap(
for (AttrmapEntry const &entry : attrmap) { for (AttrmapEntry const &entry : attrmap) {
uint8_t attr = entry.xFlip << 5 | entry.yFlip << 6; uint8_t attr = entry.xFlip << 5 | entry.yFlip << 6;
attr |= entry.bank << 3; attr |= entry.bank << 3;
attr |= entry.getPalID(mappings) & 7; attr |= (entry.getPalID(mappings) + options.basePalID) & 0b111;
output->sputc(attr); output->sputc(attr);
} }
} }
@@ -1128,7 +1128,7 @@ static void outputPalmap(
} }
for (AttrmapEntry const &entry : attrmap) { for (AttrmapEntry const &entry : attrmap) {
output->sputc(entry.getPalID(mappings)); output->sputc(entry.getPalID(mappings) + options.basePalID);
} }
} }

View File

@@ -289,10 +289,10 @@ void reverse() {
uint8_t attr = (*attrmap)[index]; uint8_t attr = (*attrmap)[index];
size_t tx = index % width, ty = index / width; size_t tx = index % width, ty = index / width;
if ((attr & 0b111) > palettes.size()) { if (uint8_t palID = (attr & 0b111) - options.basePalID; palID > palettes.size()) {
error( error(
"Attribute map references palette #%u at (%zu, %zu), but there are only %zu!", "Attribute map references palette #%u at (%zu, %zu), but there are only %zu!",
attr & 0b111, palID,
tx, tx,
ty, ty,
palettes.size() palettes.size()
@@ -356,7 +356,7 @@ void reverse() {
size_t tx = index % width, ty = index / width; size_t tx = index % width, ty = index / width;
uint8_t tileID = (*tilemap)[index]; uint8_t tileID = (*tilemap)[index];
uint8_t attr = (*attrmap)[index]; uint8_t attr = (*attrmap)[index];
bool bank = attr & 0x08; bool bank = attr & 0b1000;
if (uint8_t tileOfs = tileID - options.baseTileIDs[bank]; if (uint8_t tileOfs = tileID - options.baseTileIDs[bank];
tileOfs >= options.maxNbTiles[bank]) { tileOfs >= options.maxNbTiles[bank]) {
@@ -511,7 +511,7 @@ void reverse() {
: index; : index;
// This should have been enforced by the earlier checking. // This should have been enforced by the earlier checking.
assume(tileOfs < nbTiles + options.trim); assume(tileOfs < nbTiles + options.trim);
size_t palID = palmap ? (*palmap)[index] : attribute & 0b111; size_t palID = (palmap ? (*palmap)[index] : attribute & 0b111) - options.basePalID;
assume(palID < palettes.size()); // Should be ensured on data read assume(palID < palettes.size()); // Should be ensured on data read
// We do not have data for tiles trimmed with `-x`, so assume they are "blank" // We do not have data for tiles trimmed with `-x`, so assume they are "blank"

3
test/gfx/base_ids.flags Normal file
View File

@@ -0,0 +1,3 @@
-b 15
-l 3
-m

BIN
test/gfx/base_ids.out.2bpp Normal file

Binary file not shown.

View File

@@ -0,0 +1 @@


BIN
test/gfx/base_ids.out.pal Normal file

Binary file not shown.

View File

@@ -0,0 +1 @@


BIN
test/gfx/base_ids.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 B