Skip to content

Commit 6457ee2

Browse files
Support reading palette arrays as well as palette images (#9)
* SpriteManifest::Format: support palette images as well as palette arrays * Read palette arrays from JSON manifest files Michael Steenbeek <1478678+Gymnasiast@users.noreply.github.com>
1 parent 8d3de9a commit 6457ee2

3 files changed

Lines changed: 93 additions & 8 deletions

File tree

tools/gxc/src/SpriteManifest.cpp

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,17 @@ struct Range
3131
}
3232
};
3333

34-
static SpriteManifest::Format parseFormat(const nlohmann::json& jFormat)
34+
static SpriteManifest::Format parseFormat(const nlohmann::json& jFormat, const bool hasImageFile)
3535
{
3636
auto value = jFormat.get<std::string>();
3737
if (value == "bmp" || value == "raw")
3838
return SpriteManifest::Format::bmp;
3939
else if (value == "rle")
4040
return SpriteManifest::Format::rle;
41+
else if (value == "palette" && hasImageFile)
42+
return SpriteManifest::Format::paletteImage;
4143
else if (value == "palette")
42-
return SpriteManifest::Format::palette;
44+
return SpriteManifest::Format::paletteArray;
4345
else
4446
throw std::runtime_error("Unknown format");
4547
}
@@ -115,6 +117,43 @@ static std::optional<Range> parseRange(std::string_view s)
115117
return std::nullopt;
116118
}
117119

120+
static BGRColour parseJSONPaletteColour(const std::string& s)
121+
{
122+
uint8_t r = 0;
123+
uint8_t g = 0;
124+
uint8_t b = 0;
125+
if (s[0] == '#' && s.size() == 7)
126+
{
127+
// Expect #RRGGBB
128+
r = std::stoul(s.substr(1, 2), nullptr, 16) & 0xFF;
129+
g = std::stoul(s.substr(3, 2), nullptr, 16) & 0xFF;
130+
b = std::stoul(s.substr(5, 2), nullptr, 16) & 0xFF;
131+
}
132+
return { b, g, r };
133+
}
134+
135+
static std::vector<BGRColour> parseColours(const nlohmann::json& jPalette)
136+
{
137+
if (!jPalette.is_object())
138+
throw std::runtime_error("parseColours expects parameter jPalette to be an object");
139+
140+
auto jColours = jPalette["colours"];
141+
std::vector<BGRColour> out;
142+
143+
auto numColours = jColours.size();
144+
out.reserve(numColours * 3);
145+
146+
for (auto& jColour : jColours)
147+
{
148+
if (!jColour.is_string())
149+
throw std::runtime_error("Encountered a value that is not a string!");
150+
151+
out.push_back(parseJSONPaletteColour(jColour.get<std::string>()));
152+
}
153+
154+
return out;
155+
}
156+
118157
static SpriteManifest::Entry parseEntry(const nlohmann::json& jEntry)
119158
{
120159
SpriteManifest::Entry result;
@@ -145,21 +184,33 @@ static SpriteManifest::Entry parseEntry(const nlohmann::json& jEntry)
145184
}
146185
else
147186
{
148-
result.path = jEntry.at("path").get<std::string>();
187+
if (jEntry.contains("path"))
188+
result.path = jEntry.at("path").get<std::string>();
149189
if (jEntry.contains("format"))
150-
result.format = parseFormat(jEntry["format"]);
190+
result.format = parseFormat(jEntry["format"], result.path.empty());
191+
151192
if (jEntry.contains("palette"))
152193
result.palette = parsePalette(jEntry["palette"]);
194+
if (jEntry.contains("colours"))
195+
result.colours = parseColours(jEntry);
196+
197+
if (result.format == SpriteManifest::Format::automatic && !result.colours.empty())
198+
result.format = SpriteManifest::Format::paletteArray;
199+
153200
if (jEntry.contains("x"))
154201
result.offsetX = jEntry["x"];
155202
else if (jEntry.contains("x_offset"))
156203
result.offsetX = jEntry["x_offset"];
204+
else if (jEntry.contains("index")) // palette startIndex
205+
result.offsetX = jEntry["index"]; // palette startIndex
206+
157207
if (jEntry.contains("y"))
158208
result.offsetY = jEntry["y"];
159209
else if (jEntry.contains("y_offset"))
160210
result.offsetY = jEntry["y_offset"];
161211
else if (jEntry.contains("zoom"))
162212
result.zoomOffset = jEntry["zoom"];
213+
163214
if (jEntry.contains("srcX"))
164215
result.srcX = jEntry["srcX"];
165216
if (jEntry.contains("srcY"))

tools/gxc/src/SpriteManifest.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@
77

88
namespace gxc
99
{
10+
struct BGRColour
11+
{
12+
uint8_t blue{};
13+
uint8_t green{};
14+
uint8_t red{};
15+
};
16+
17+
using ColourVector = std::vector<BGRColour>;
18+
1019
class SpriteArchive;
1120

1221
class SpriteManifest
@@ -17,7 +26,8 @@ namespace gxc
1726
automatic,
1827
bmp,
1928
rle,
20-
palette,
29+
paletteImage,
30+
paletteArray,
2131
empty
2232
};
2333

@@ -32,6 +42,7 @@ namespace gxc
3242
fs::path path;
3343
Format format{};
3444
PaletteKind palette{};
45+
ColourVector colours{};
3546
int32_t offsetX{};
3647
int32_t offsetY{};
3748
int32_t zoomOffset{};

tools/gxc/src/gxc.cpp

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ static void convertPaletteToBmp(const GxEntry& entry, void* dst)
3232
}
3333
}
3434

35-
static void encodePalette(Stream& stream, const Image& image)
35+
static void encodePaletteFromImage(Stream& stream, const Image& image)
3636
{
3737
const auto* src = image.pixels.data();
3838
for (uint32_t x = 0; x < image.width; x++)
@@ -60,6 +60,14 @@ static void encodePalette(Stream& stream, const Image& image)
6060
}
6161
}
6262

63+
static void encodePaletteFromArray(Stream& stream, const std::vector<BGRColour>& colours)
64+
{
65+
for (auto& colour : colours)
66+
{
67+
stream.write(&colour, 3);
68+
}
69+
}
70+
6371
static std::string stringifyFlags(uint16_t flags)
6472
{
6573
std::string result;
@@ -136,6 +144,21 @@ int runBuild(const CommandLineOptions& options)
136144
}
137145
try
138146
{
147+
// Palette arrays don't have an image to load, so start with those
148+
if (manifestEntry.format == SpriteManifest::Format::paletteArray)
149+
{
150+
MemoryStream ms;
151+
encodePaletteFromArray(ms, manifestEntry.colours);
152+
153+
SpriteArchive::Entry entry;
154+
entry.width = manifestEntry.colours.size();
155+
entry.height = 1;
156+
entry.offsetX = manifestEntry.offsetX;
157+
entry.flags = GxFlags::isPalette;
158+
archive.addEntry(entry, ms.asSpan<const std::byte>());
159+
continue;
160+
}
161+
139162
auto imageCacheIterator = imageCache.find(manifestEntry.path);
140163
if (imageCacheIterator == imageCache.end())
141164
{
@@ -151,10 +174,10 @@ int runBuild(const CommandLineOptions& options)
151174
img = img.crop(manifestEntry.srcX, manifestEntry.srcY, manifestEntry.srcWidth, manifestEntry.srcHeight);
152175
}
153176

154-
if (manifestEntry.format == SpriteManifest::Format::palette)
177+
if (manifestEntry.format == SpriteManifest::Format::paletteImage)
155178
{
156179
MemoryStream ms;
157-
encodePalette(ms, img);
180+
encodePaletteFromImage(ms, img);
158181

159182
SpriteArchive::Entry entry;
160183
entry.width = img.width;

0 commit comments

Comments
 (0)