Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow mirroring only the X or Y axes #1468

Merged
merged 1 commit into from
Aug 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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