Reimplement basic RGBGFX features in C++

Currently missing from the old version:
- `-f` ("fixing" the input image to be indexed)
- `-m` (the code for detecting mirrored tiles is missing, but all of the
        "plumbing" is otherwise there)
- `-C`
- `-d`
- `-x` (though I need to check the exact functionality the old one has)
- Also the man page is still a draft and needs to be fleshed out

More planned features are not implemented yet either:
- Explicit palette spec
- Better error messages, also error "images"
- Better 8x16 support, as well as other "dedup unit" sizes
- Support for arbitrary number of palettes & colors per palette
- Other output formats (for example, a "full" palette map for "streaming"
  use cases like gb-open-world)
- Quantization?

Some things may also be bugged:
- Transparency support
- Tile offsets (not exposed yet)
- Tile counts per bank (not exposed yet)

...and performance remains to be checked.
We need to set up some tests, honestly.
This commit is contained in:
ISSOtm
2022-02-06 23:30:37 +01:00
committed by Eldred Habert
parent 34bc650341
commit 8c62e80c18
23 changed files with 2022 additions and 1696 deletions

View File

@@ -25,23 +25,7 @@
.Sh DESCRIPTION
The
.Nm
program converts PNG images into the Nintendo Game Boy's planar tile format.
.Pp
The resulting colors and their palette indices are determined differently depending on the input PNG file:
.Bl -dash -width Ds
.It
If the file has an embedded palette, that palette's color and order are used.
.It
If not, and the image only contains shades of gray, rgbgfx maps them to the indices appropriate for each shade.
Any undetermined indices are set to respective default shades of gray.
For example: if the bit depth is 2 and the image contains light gray and black, they become the second and fourth colors, and the first and third colors get set to default white and dark gray.
If the image has multiple shades that map to the same index, the palette is instead determined as if the image had color.
.It
If the image has color (or the grayscale method failed), the colors are sorted from lightest to darkest.
.El
.Pp
The input image may not contain more colors than the selected bit depth allows.
Transparent pixels are set to palette index 0.
program converts PNG images into data suitable
.Sh ARGUMENTS
Note that options can be abbreviated as long as the abbreviation is unambiguous:
.Fl Fl verb
@@ -117,29 +101,59 @@ Print the version of the program and exit.
.It Fl v , Fl Fl verbose
Verbose.
Print errors when the command line parameters and the parameters in the PNG file don't match.
.It Fl x Ar tiles , Fl Fl trim-end Ar tiles
.It Fl x Ar amount , Fl Fl trim-end Ar amount
Trim the end of the output file by this many tiles.
.Pq TODO: tiles, or tilemap?
.El
.Sh PALETTE GENERATION
.Nm
must decide in which order to place colors in the palettes, but the input PNG usually lacks any indications.
A lot of the time, the order does not matter; however, sometimes it does, and
.Nm
attempts to account for those cases.
.Bl -bullet -offset indent
.It
First, if the image contains
.Em any
transparent pixel, color #0 of
.Em all
palettes will be allocated to it.
If palettes were explicitly specified using
.Fl TODO ,
then they will specify color #1 onwards.
.Pq If you do not want this, ask your image editor to remove the alpha channel.
.It
If the PNG file internally contains a palette (often dubbed an
.Dq indexed
PNG), then colors in each output palette will be sorted according to their order in the PNG's palette.
Any unused entries will be ignored, and only the first entry is considered if there any duplicates.
.Pq If you want a given color to appear more than once in a palette, you should specify the palettes explicitly instead using Fl TODO .
.It
Otherwise, if the PNG only contains shades of gray, they will be categorized into 4
.Dq bins
.Pq white, light gray, dark gray, and black in this order ,
and the palette is set to these four bins.
(TODO: how does this interact with 1bpp? With more than 1 palette?)
If more than one grey ends up in the same bin, the RGB method below is used instead.
.It
If none of the above apply, colors are sorted from lightest to darkest.
(This is what the old documentation claimed, but the definition of luminance that was used wasn't quite right.
It is kept for compatibility.)
.El
.Pp
Note that the
.Dq indexed
behavior depends on an internal detail of how the PNG is saved.
Since few image editors (such as GIMP) expose that detail, this behavior is only kept for compatibility and should be considered deprecated; if the order of colors in the palettes is important to you, please use
.Fl TODO
to specify the palette explicitly.
.Sh OUTPUT FILES
.Ss Palette data
Palette data is output like a dump of GBC palette memory: the output is a binary file.
Each color is written as GBC-native little-endian RGB555 (that is, the first byte contains the red and the lower 3 bits of green).
There is no padding between colors, nor between palettes; however, empty colors in the palettes are filled as 0xFF bytes.
.Sh EXAMPLES
The following will take a PNG file with a bit depth of 1, 2, or 8, and output planar 2bpp data:
.Pp
.D1 $ rgbgfx -o out.2bpp in.png
.Pp
The following creates a planar 2bpp file with only unique tiles, and its tilemap
.Pa out.tilemap :
.Pp
.D1 $ rgbgfx -T -u -o out.2bpp in.png
.Pp
The following creates a planar 2bpp file with only unique tiles
.Pa accounting for tile mirroring
and its associated tilemap
.Pa out.tilemap
and attrmap
.Pa out.attrmap :
.Pp
.D1 $ rgbgfx -A -T -m -o out.2bpp in.png
.Pp
The following will do nothing:
The following will only validate the PNG [...] but output nothing:
.Pp
.D1 $ rgbgfx in.png
.Sh BUGS
@@ -153,8 +167,10 @@ Please report bugs on
.Xr gbz80 7
.Sh HISTORY
.Nm
was created by
was originally created by
.An stag019
to be included in RGBDS.
It is now maintained by a number of contributors at
It was later rewritten by
.An ISSOtm ,
and is now maintained by a number of contributors at
.Lk https://github.com/gbdev/rgbds .