Skip to content
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
59 changes: 55 additions & 4 deletions tools/gxc/src/SpriteManifest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,17 @@ struct Range
}
};

static SpriteManifest::Format parseFormat(const nlohmann::json& jFormat)
static SpriteManifest::Format parseFormat(const nlohmann::json& jFormat, const bool hasImageFile)
{
auto value = jFormat.get<std::string>();
if (value == "bmp" || value == "raw")
return SpriteManifest::Format::bmp;
else if (value == "rle")
return SpriteManifest::Format::rle;
else if (value == "palette" && hasImageFile)
return SpriteManifest::Format::paletteImage;
else if (value == "palette")
return SpriteManifest::Format::palette;
return SpriteManifest::Format::paletteArray;
else
throw std::runtime_error("Unknown format");
}
Expand Down Expand Up @@ -115,6 +117,43 @@ static std::optional<Range> parseRange(std::string_view s)
return std::nullopt;
}

static BGRColour parseJSONPaletteColour(const std::string& s)
{
uint8_t r = 0;
uint8_t g = 0;
uint8_t b = 0;
if (s[0] == '#' && s.size() == 7)
{
// Expect #RRGGBB
r = std::stoul(s.substr(1, 2), nullptr, 16) & 0xFF;
g = std::stoul(s.substr(3, 2), nullptr, 16) & 0xFF;
b = std::stoul(s.substr(5, 2), nullptr, 16) & 0xFF;
}
return { b, g, r };
}

static std::vector<BGRColour> parseColours(const nlohmann::json& jPalette)
{
if (!jPalette.is_object())
throw std::runtime_error("parseColours expects parameter jPalette to be an object");

auto jColours = jPalette["colours"];
std::vector<BGRColour> out;

auto numColours = jColours.size();
out.reserve(numColours * 3);

for (auto& jColour : jColours)
{
if (!jColour.is_string())
throw std::runtime_error("Encountered a value that is not a string!");

out.push_back(parseJSONPaletteColour(jColour.get<std::string>()));
}

return out;
}

static SpriteManifest::Entry parseEntry(const nlohmann::json& jEntry)
{
SpriteManifest::Entry result;
Expand Down Expand Up @@ -145,21 +184,33 @@ static SpriteManifest::Entry parseEntry(const nlohmann::json& jEntry)
}
else
{
result.path = jEntry.at("path").get<std::string>();
if (jEntry.contains("path"))
result.path = jEntry.at("path").get<std::string>();
if (jEntry.contains("format"))
result.format = parseFormat(jEntry["format"]);
result.format = parseFormat(jEntry["format"], result.path.empty());

if (jEntry.contains("palette"))
result.palette = parsePalette(jEntry["palette"]);
if (jEntry.contains("colours"))
result.colours = parseColours(jEntry);

if (result.format == SpriteManifest::Format::automatic && !result.colours.empty())
result.format = SpriteManifest::Format::paletteArray;

if (jEntry.contains("x"))
result.offsetX = jEntry["x"];
else if (jEntry.contains("x_offset"))
result.offsetX = jEntry["x_offset"];
else if (jEntry.contains("index")) // palette startIndex
result.offsetX = jEntry["index"]; // palette startIndex

if (jEntry.contains("y"))
result.offsetY = jEntry["y"];
else if (jEntry.contains("y_offset"))
result.offsetY = jEntry["y_offset"];
else if (jEntry.contains("zoom"))
result.zoomOffset = jEntry["zoom"];

if (jEntry.contains("srcX"))
result.srcX = jEntry["srcX"];
if (jEntry.contains("srcY"))
Expand Down
13 changes: 12 additions & 1 deletion tools/gxc/src/SpriteManifest.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@

namespace gxc
{
struct BGRColour
{
uint8_t blue{};
uint8_t green{};
uint8_t red{};
};

using ColourVector = std::vector<BGRColour>;

class SpriteArchive;

class SpriteManifest
Expand All @@ -17,7 +26,8 @@ namespace gxc
automatic,
bmp,
rle,
palette,
paletteImage,
paletteArray,
empty
};

Expand All @@ -32,6 +42,7 @@ namespace gxc
fs::path path;
Format format{};
PaletteKind palette{};
ColourVector colours{};
int32_t offsetX{};
int32_t offsetY{};
int32_t zoomOffset{};
Expand Down
29 changes: 26 additions & 3 deletions tools/gxc/src/gxc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ static void convertPaletteToBmp(const GxEntry& entry, void* dst)
}
}

static void encodePalette(Stream& stream, const Image& image)
static void encodePaletteFromImage(Stream& stream, const Image& image)
{
const auto* src = image.pixels.data();
for (uint32_t x = 0; x < image.width; x++)
Expand Down Expand Up @@ -60,6 +60,14 @@ static void encodePalette(Stream& stream, const Image& image)
}
}

static void encodePaletteFromArray(Stream& stream, const std::vector<BGRColour>& colours)
{
for (auto& colour : colours)
{
stream.write(&colour, 3);
}
}

static std::string stringifyFlags(uint16_t flags)
{
std::string result;
Expand Down Expand Up @@ -136,6 +144,21 @@ int runBuild(const CommandLineOptions& options)
}
try
{
// Palette arrays don't have an image to load, so start with those
if (manifestEntry.format == SpriteManifest::Format::paletteArray)
{
MemoryStream ms;
encodePaletteFromArray(ms, manifestEntry.colours);

SpriteArchive::Entry entry;
entry.width = manifestEntry.colours.size();
entry.height = 1;
entry.offsetX = manifestEntry.offsetX;
entry.flags = GxFlags::isPalette;
archive.addEntry(entry, ms.asSpan<const std::byte>());
continue;
}

auto imageCacheIterator = imageCache.find(manifestEntry.path);
if (imageCacheIterator == imageCache.end())
{
Expand All @@ -151,10 +174,10 @@ int runBuild(const CommandLineOptions& options)
img = img.crop(manifestEntry.srcX, manifestEntry.srcY, manifestEntry.srcWidth, manifestEntry.srcHeight);
}

if (manifestEntry.format == SpriteManifest::Format::palette)
if (manifestEntry.format == SpriteManifest::Format::paletteImage)
{
MemoryStream ms;
encodePalette(ms, img);
encodePaletteFromImage(ms, img);

SpriteArchive::Entry entry;
entry.width = img.width;
Expand Down