mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 18:22:07 +00:00
Implement more features and fix bugs
This commit is contained in:
@@ -23,9 +23,14 @@ struct Rgba {
|
|||||||
Rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a) : red(r), green(g), blue(b), alpha(a) {}
|
Rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a) : red(r), green(g), blue(b), alpha(a) {}
|
||||||
Rgba(uint32_t rgba) : red(rgba), green(rgba >> 8), blue(rgba >> 16), alpha(rgba >> 24) {}
|
Rgba(uint32_t rgba) : red(rgba), green(rgba >> 8), blue(rgba >> 16), alpha(rgba >> 24) {}
|
||||||
|
|
||||||
operator uint32_t() const {
|
operator uint32_t() const { return toCSS(); }
|
||||||
|
/**
|
||||||
|
* Returns this RGBA as a 32-bit number that can be printed in hex (`%08x`) to yield its CSS
|
||||||
|
* representation
|
||||||
|
*/
|
||||||
|
uint32_t toCSS() const {
|
||||||
auto shl = [](uint8_t val, unsigned shift) { return static_cast<uint32_t>(val) << shift; };
|
auto shl = [](uint8_t val, unsigned shift) { return static_cast<uint32_t>(val) << shift; };
|
||||||
return shl(red, 0) | shl(green, 8) | shl(blue, 16) | shl(alpha, 24);
|
return shl(red, 24) | shl(green, 16) | shl(blue, 8) | shl(alpha, 0);
|
||||||
}
|
}
|
||||||
bool operator!=(Rgba const &other) const {
|
bool operator!=(Rgba const &other) const {
|
||||||
return static_cast<uint32_t>(*this) != static_cast<uint32_t>(other);
|
return static_cast<uint32_t>(*this) != static_cast<uint32_t>(other);
|
||||||
@@ -39,12 +44,15 @@ struct Rgba {
|
|||||||
*/
|
*/
|
||||||
static constexpr uint16_t transparent = 0b1'00000'00000'00000;
|
static constexpr uint16_t transparent = 0b1'00000'00000'00000;
|
||||||
|
|
||||||
static constexpr uint8_t transparency_threshold = 5; // TODO: adjust this
|
/**
|
||||||
|
* All alpha values strictly below this will be considered transparent
|
||||||
|
*/
|
||||||
|
static constexpr uint8_t opacity_threshold = 0xF0; // TODO: adjust this
|
||||||
/**
|
/**
|
||||||
* Computes the equivalent CGB color, respects the color curve depending on options
|
* Computes the equivalent CGB color, respects the color curve depending on options
|
||||||
*/
|
*/
|
||||||
uint16_t cgbColor() const {
|
uint16_t cgbColor() const {
|
||||||
if (alpha > 0xFF - transparency_threshold)
|
if (alpha < opacity_threshold)
|
||||||
return transparent;
|
return transparent;
|
||||||
if (options.useColorCurve) {
|
if (options.useColorCurve) {
|
||||||
assert(!"TODO");
|
assert(!"TODO");
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <limits.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
@@ -27,7 +28,7 @@ struct Options {
|
|||||||
uint8_t nbPalettes = 8; // TODO
|
uint8_t nbPalettes = 8; // TODO
|
||||||
uint8_t nbColorsPerPal = 0; // TODO; 0 means "auto" = 1 << bitDepth;
|
uint8_t nbColorsPerPal = 0; // TODO; 0 means "auto" = 1 << bitDepth;
|
||||||
std::array<uint8_t, 2> baseTileIDs{0, 0}; // TODO
|
std::array<uint8_t, 2> baseTileIDs{0, 0}; // TODO
|
||||||
std::array<uint16_t, 2> maxNbTiles{384, 0}; // TODO
|
std::array<uint16_t, 2> maxNbTiles{UINT16_MAX, 0}; // TODO
|
||||||
std::filesystem::path tilemap{}; // -t, -T
|
std::filesystem::path tilemap{}; // -t, -T
|
||||||
std::filesystem::path attrmap{}; // -a, -A
|
std::filesystem::path attrmap{}; // -a, -A
|
||||||
std::filesystem::path palettes{}; // -p, -P
|
std::filesystem::path palettes{}; // -p, -P
|
||||||
@@ -35,6 +36,9 @@ struct Options {
|
|||||||
std::filesystem::path input{}; // positional arg
|
std::filesystem::path input{}; // positional arg
|
||||||
|
|
||||||
format_(printf, 2, 3) void verbosePrint(char const *fmt, ...) const;
|
format_(printf, 2, 3) void verbosePrint(char const *fmt, ...) const;
|
||||||
|
uint8_t maxPalSize() const {
|
||||||
|
return nbColorsPerPal;
|
||||||
|
} // TODO: minus 1 when transparency is active
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Options options;
|
extern Options options;
|
||||||
|
|||||||
@@ -44,7 +44,8 @@ public:
|
|||||||
if (!slot.has_value()) {
|
if (!slot.has_value()) {
|
||||||
slot.emplace(rgba);
|
slot.emplace(rgba);
|
||||||
} else if (*slot != rgba) {
|
} else if (*slot != rgba) {
|
||||||
warning("Different colors melded together"); // TODO: indicate position
|
warning("Different colors melded together (#%08x into #%08x as %04x)", rgba.toCSS(),
|
||||||
|
slot->toCSS(), rgba.cgbColor()); // TODO: indicate position
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -363,7 +364,7 @@ public:
|
|||||||
public:
|
public:
|
||||||
iterator begin() const { return {*this, _width, 0, 0}; }
|
iterator begin() const { return {*this, _width, 0, 0}; }
|
||||||
iterator end() const {
|
iterator end() const {
|
||||||
iterator it{*this, _width, _width - 8, _height - 8}; // Last valid one
|
iterator it{*this, _limit, _width - 8, _height - 8}; // Last valid one
|
||||||
return ++it; // Now one-past-last
|
return ++it; // Now one-past-last
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -443,8 +444,10 @@ static void outputTileData(Png const &png, DefaultInitVec<AttrmapEntry> const &a
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
output.sputc(row & 0xFF);
|
output.sputc(row & 0xFF);
|
||||||
|
if (options.bitDepth == 2) {
|
||||||
output.sputc(row >> 8);
|
output.sputc(row >> 8);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
++iter;
|
++iter;
|
||||||
}
|
}
|
||||||
assert(iter == attrmap.end());
|
assert(iter == attrmap.end());
|
||||||
@@ -505,6 +508,7 @@ public:
|
|||||||
mutable size_t tileID;
|
mutable size_t tileID;
|
||||||
|
|
||||||
TileData(Png::TilesVisitor::Tile const &tile, Palette const &palette) : _hash(0) {
|
TileData(Png::TilesVisitor::Tile const &tile, Palette const &palette) : _hash(0) {
|
||||||
|
size_t writeIndex = 0;
|
||||||
for (uint32_t y = 0; y < 8; ++y) {
|
for (uint32_t y = 0; y < 8; ++y) {
|
||||||
uint16_t bitplanes = 0;
|
uint16_t bitplanes = 0;
|
||||||
for (uint32_t x = 0; x < 8; ++x) {
|
for (uint32_t x = 0; x < 8; ++x) {
|
||||||
@@ -517,8 +521,10 @@ public:
|
|||||||
bitplanes |= 0x100;
|
bitplanes |= 0x100;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_data[y * 2] = bitplanes & 0xFF;
|
_data[writeIndex++] = bitplanes & 0xFF;
|
||||||
_data[y * 2 + 1] = bitplanes >> 8;
|
if (options.bitDepth == 2) {
|
||||||
|
_data[writeIndex++] = bitplanes >> 8;
|
||||||
|
}
|
||||||
|
|
||||||
// Update the hash
|
// Update the hash
|
||||||
_hash ^= bitplanes;
|
_hash ^= bitplanes;
|
||||||
@@ -632,7 +638,7 @@ static void outputTileData(UniqueTiles const &tiles) {
|
|||||||
for (TileData const *tile : tiles) {
|
for (TileData const *tile : tiles) {
|
||||||
assert(tile->tileID == tileID);
|
assert(tile->tileID == tileID);
|
||||||
++tileID;
|
++tileID;
|
||||||
output.sputn(reinterpret_cast<char const *>(tile->data().data()), tile->data().size());
|
output.sputn(reinterpret_cast<char const *>(tile->data().data()), options.bitDepth * 8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -203,10 +203,8 @@ public:
|
|||||||
size_t volume() const { return uniqueColors().size(); }
|
size_t volume() const { return uniqueColors().size(); }
|
||||||
bool canFit(ProtoPalette const &protoPal) const {
|
bool canFit(ProtoPalette const &protoPal) const {
|
||||||
auto &colors = uniqueColors();
|
auto &colors = uniqueColors();
|
||||||
for (uint16_t color : protoPal) {
|
colors.insert(protoPal.begin(), protoPal.end());
|
||||||
colors.insert(color);
|
return colors.size() <= options.maxPalSize();
|
||||||
}
|
|
||||||
return colors.size() <= 4;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -274,9 +272,9 @@ std::tuple<DefaultInitVec<size_t>, size_t>
|
|||||||
bestPal.assign(std::move(attrs));
|
bestPal.assign(std::move(attrs));
|
||||||
|
|
||||||
// If this overloads the palette, get it back to normal (if possible)
|
// If this overloads the palette, get it back to normal (if possible)
|
||||||
while (bestPal.volume() > 4) {
|
while (bestPal.volume() > options.maxPalSize()) {
|
||||||
options.verbosePrint("Palette %zu is overloaded! (%zu > 4)\n", bestPalIndex,
|
options.verbosePrint("Palette %zu is overloaded! (%zu > %" PRIu8 ")\n",
|
||||||
bestPal.volume());
|
bestPalIndex, bestPal.volume(), options.maxPalSize());
|
||||||
|
|
||||||
// Look for a proto-pal minimizing "efficiency" (size / rel_size)
|
// Look for a proto-pal minimizing "efficiency" (size / rel_size)
|
||||||
auto efficiency = [&bestPal](ProtoPalette const &pal) {
|
auto efficiency = [&bestPal](ProtoPalette const &pal) {
|
||||||
@@ -309,7 +307,7 @@ std::tuple<DefaultInitVec<size_t>, size_t>
|
|||||||
|
|
||||||
// Deal with palettes still overloaded, by emptying them
|
// Deal with palettes still overloaded, by emptying them
|
||||||
for (AssignedProtos &pal : assignments) {
|
for (AssignedProtos &pal : assignments) {
|
||||||
if (pal.volume() > 4) {
|
if (pal.volume() > options.maxPalSize()) {
|
||||||
for (ProtoPalAttrs &attrs : pal) {
|
for (ProtoPalAttrs &attrs : pal) {
|
||||||
queue.emplace(std::move(attrs));
|
queue.emplace(std::move(attrs));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user