Skip to content

Commit

Permalink
Allow mirroring only the X or Y axes
Browse files Browse the repository at this point in the history
  • Loading branch information
Rangi42 committed Aug 19, 2024
1 parent b729036 commit 24b9306
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 23 deletions.
2 changes: 2 additions & 0 deletions contrib/bash_compl/_rgbgfx.bash
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ _rgbgfx_completions() {
[O]="group-outputs:normal"
[u]="unique-tiles:normal"
[v]="verbose:normal"
[X]="mirror-x:normal"
[Y]="mirror-y:normal"
[Z]="columns:normal"
[a]="attr-map:glob-*.attrmap"
[A]="auto-attr-map:normal"
Expand Down
2 changes: 2 additions & 0 deletions contrib/zsh_compl/_rgbgfx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ local args=(
'(-t --tilemap -T --auto-tilemap)'{-T,--auto-tilemap}'[Shortcut for -t <file>.tilemap]'
'(-u --unique-tiles)'{-u,--unique-tiles}'[Eliminate redundant tiles]'
{-v,--verbose}'[Enable verbose output]'
'(-X --mirror-x)'{-X,--mirror-x}'[Eliminate horizontally mirrored tiles from output]'
'(-Y --mirror-y)'{-Y,--mirror-y}'[Eliminate vertically mirrored tiles from output]'
'(-Z --columns)'{-Z,--columns}'[Read the image in column-major order]'

'(-a --attr-map -A --auto-attr-map)'{-a,--attr-map}'+[Generate a map of tile attributes (mirroring)]:attrmap file:_files'
Expand Down
11 changes: 6 additions & 5 deletions include/gfx/main.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@
#include "gfx/rgba.hpp"

struct Options {
bool useColorCurve = false; // -C
bool allowMirroring = false; // -m
bool allowDedup = false; // -u
bool columnMajor = false; // -Z, previously -h
uint8_t verbosity = 0; // -v
bool useColorCurve = false; // -C
bool allowDedup = false; // -u
bool allowMirroringX = false; // -X, -m
bool allowMirroringY = false; // -Y, -m
bool columnMajor = false; // -Z
uint8_t verbosity = 0; // -v

std::string attrmap{}; // -a, -A
std::array<uint8_t, 2> baseTileIDs{0, 0}; // -b
Expand Down
23 changes: 18 additions & 5 deletions src/gfx/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,14 +144,16 @@ static option const longopts[] = {
{"unique-tiles", no_argument, nullptr, 'u'},
{"version", no_argument, nullptr, 'V'},
{"verbose", no_argument, nullptr, 'v'},
{"mirror-x", no_argument, nullptr, 'X'},
{"trim-end", required_argument, nullptr, 'x'},
{"mirror-y", no_argument, nullptr, 'Y'},
{"columns", no_argument, nullptr, 'Z'},
{nullptr, no_argument, nullptr, 0 }
};

static void printUsage() {
fputs(
"Usage: rgbgfx [-r stride] [-CmOuVZ] [-v [-v ...]] [-a <attr_map> | -A]\n"
"Usage: rgbgfx [-r stride] [-CmOuVXYZ] [-v [-v ...]] [-a <attr_map> | -A]\n"
" [-b <base_ids>] [-c <colors>] [-d <depth>] [-L <slice>] [-N <nb_tiles>]\n"
" [-n <nb_pals>] [-o <out_file>] [-p <pal_file> | -P] [-q <pal_map> | -Q]\n"
" [-s <nb_colors>] [-t <tile_map> | -T] [-x <nb_tiles>] <file>\n"
Expand Down Expand Up @@ -466,8 +468,9 @@ static char *parseArgv(int argc, char *argv[]) {
}
break;
case 'm':
options.allowMirroring = true;
[[fallthrough]]; // Imply `-u`
options.allowMirroringX = true; // Imply `-X`
options.allowMirroringY = true; // Imply `-Y`
[[fallthrough]]; // Imply `-u`
case 'u':
options.allowDedup = true;
break;
Expand Down Expand Up @@ -582,6 +585,14 @@ static char *parseArgv(int argc, char *argv[]) {
error("Tile trim (-x) argument must be a valid number, not \"%s\"", musl_optarg);
}
break;
case 'X':
options.allowMirroringX = true;
options.allowDedup = true; // Imply `-u`
break;
case 'Y':
options.allowMirroringY = true;
options.allowDedup = true; // Imply `-u`
break;
case 'Z':
options.columnMajor = true;
break;
Expand Down Expand Up @@ -757,10 +768,12 @@ int main(int argc, char *argv[]) {
fputs("Options:\n", stderr);
if (options.columnMajor)
fputs("\tVisit image in column-major order\n", stderr);
if (options.allowMirroring)
fputs("\tAllow mirroring tiles\n", stderr);
if (options.allowDedup)
fputs("\tAllow deduplicating tiles\n", stderr);
if (options.allowMirroringX)
fputs("\tAllow deduplicating horizontally mirrored tiles\n", stderr);
if (options.allowMirroringY)
fputs("\tAllow deduplicating vertically mirrored tiles\n", stderr);
if (options.useColorCurve)
fputs("\tUse color curve\n", stderr);
fprintf(stderr, "\tBit depth: %" PRIu8 "bpp\n", options.bitDepth);
Expand Down
36 changes: 23 additions & 13 deletions src/gfx/process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -747,10 +747,10 @@ class TileData {

// Update the hash
_hash ^= bitplanes;
if (options.allowMirroring) {
// Count the line itself as mirrorred; vertical mirroring is
// already taken care of because the symmetric line will be XOR'd
// the same way. (...which is a problem, but probably benign.)
if (options.allowMirroringX) {
// Count the line itself as mirrorred horizontally; vertical mirroring is already
// taken care of because the symmetric line will be XOR'd the same way.
// (...this reduces the hash's efficiency, but seems benign with most real-world data.)
_hash ^= flipTable[bitplanes >> 8] << 8 | flipTable[bitplanes & 0xFF];
}
}
Expand All @@ -773,17 +773,19 @@ class TileData {
return MatchType::EXACT;
}

if (!options.allowMirroring) {
return MatchType::NOPE;
}

// Check if we have horizontal mirroring, which scans the array forward again
if (std::equal(RANGE(_data), other._data.begin(), [](uint8_t lhs, uint8_t rhs) {
return lhs == flipTable[rhs];
})) {
if (options.allowMirroringX
&& std::equal(RANGE(_data), other._data.begin(), [](uint8_t lhs, uint8_t rhs) {
return lhs == flipTable[rhs];
})) {
return MatchType::HFLIP;
}

// The remaining possibilities for matching all require vertical mirroring
if (!options.allowMirroringY) {
return MatchType::NOPE;
}

// Check if we have vertical or vertical+horizontal mirroring, for which we have to read
// bitplane *pairs* backwards
bool hasVFlip = true, hasVHFlip = true;
Expand All @@ -803,8 +805,16 @@ class TileData {
}

// If we have both (i.e. we have symmetry), default to vflip only
assume(hasVFlip || hasVHFlip);
return hasVFlip ? MatchType::VFLIP : MatchType::VHFLIP;
if (hasVFlip) {
return MatchType::VFLIP;
}

// If we allow both and have both, then use both
if (options.allowMirroringX && hasVHFlip) {
return MatchType::VHFLIP;
}

return MatchType::NOPE;
}
friend bool operator==(TileData const &lhs, TileData const &rhs) {
return lhs.tryMatching(rhs) != MatchType::NOPE;
Expand Down

0 comments on commit 24b9306

Please sign in to comment.