Skip to content

Commit 795f73e

Browse files
committed
added encoding with palette support
1 parent 59cd4e5 commit 795f73e

File tree

1 file changed

+92
-67
lines changed

1 file changed

+92
-67
lines changed

src/tools/mcxz/src/main.cpp

Lines changed: 92 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,17 @@ enum
1616
{
1717
ENCODING_RGB565, // 2 bytes
1818
ENCODING_RGB565BGR, // 2 bytes
19-
ENCODING_RGB555, // 2 bytes
20-
ENCODING_RGB332, // 1 byte
19+
ENCODING_RGBX555, // 2 bytes
20+
ENCODING_RGBX888P, // 1 byte
2121
ENCODING_RGB888, // 3 byte
2222
ENCODING_RGBX888, // 4 byte
2323
};
2424

2525
const char *ENCODING_RGB[] = {
2626
"565",
2727
"565BGR",
28-
"555",
29-
"332",
28+
"X555",
29+
"X888P",
3030
"888",
3131
"X888",
3232
};
@@ -56,6 +56,7 @@ typedef struct
5656
bool flipPixels;
5757
bool headerless;
5858
bool outputPNG;
59+
bool diet;
5960
} AppSettings;
6061

6162
typedef std::vector<std::string> StringVector;
@@ -64,6 +65,7 @@ typedef std::vector<std::string> StrVector;
6465
typedef std::map<std::string, StringVector> Config;
6566
typedef std::unordered_map<std::string, uint8_t> StrVal;
6667
typedef std::map<std::string, StrVal> MapStrVal;
68+
typedef std::unordered_map<uint32_t, uint8_t> Palette;
6769

6870
const char *AUTOGENERATED = "//////////////////////////////////////////////////\n"
6971
"// autogenerated\n\n";
@@ -127,40 +129,11 @@ uint16_t rgb888torgb555(const uint8_t *rgb888Pixel)
127129
const uint8_t &blue = rgb888Pixel[2];
128130

129131
const uint16_t b = (blue >> 3) & 0x1f;
130-
const uint16_t g = ((green >> 2) & 0x1f) << 5;
132+
const uint16_t g = ((green >> 3) & 0x1f) << 5;
131133
const uint16_t r = ((red >> 3) & 0x1f) << 10;
132134
return (uint16_t)(r | g | b);
133135
}
134136

135-
// RGB 332
136-
uint8_t rgb888torgb332(const uint8_t *rgb888Pixel)
137-
{
138-
const uint8_t &red = rgb888Pixel[0];
139-
const uint8_t &green = rgb888Pixel[1];
140-
const uint8_t &blue = rgb888Pixel[2];
141-
142-
// bit
143-
// 1 low red
144-
// 2 low green
145-
// 3 low blue
146-
// 4 high red
147-
// 5 high green
148-
// 6 high blue
149-
// 7 mid red
150-
// 8 mid green
151-
152-
const uint8_t r = ((red & 0xc0) ? 0x08 : 0) | // high
153-
((red & 0x30) ? 0x01 : 0) | // mid
154-
((red & 0x0c) ? 0x40 : 0); // low
155-
const uint8_t g = ((green & 0xc0) ? 0x10 : 0) | // high
156-
((green & 0x30) ? 0x02 : 0) | // mid
157-
((green & 0x0c) ? 0x80 : 0); // low
158-
const uint8_t b = ((blue & 0xc0) ? 0x20 : 0) | // high
159-
((blue & 0x30) ? 0x04 : 0); // mid
160-
161-
return (uint8_t)(r | g | b);
162-
}
163-
164137
int test()
165138
{
166139
CFileWrap tfileTiny;
@@ -465,7 +438,7 @@ bool generateHeader(const std::string section, const std::string sectionName, st
465438
return true;
466439
}
467440

468-
bool generateData(const std::string section, std::string const sectionBasename, TileVector &tileDefs)
441+
bool generateData(const AppSettings &appSettings, const std::string section, std::string const sectionBasename, TileVector &tileDefs)
469442
{
470443
const std::string fnameData = section + "data.cpp";
471444
CFileWrap tfileData;
@@ -493,14 +466,15 @@ bool generateData(const std::string section, std::string const sectionBasename,
493466
for (int i = 0; i < tileDefs.size(); ++i)
494467
{
495468
Tile &tile = tileDefs[i];
496-
sprintf(tmp, " {0x%.2x, TYPE_%s, %d, %d, %d, %d, %s, \"%s\"}%s",
469+
std::string basename = "\"" + tile.basename + "\"";
470+
sprintf(tmp, " {0x%.2x, TYPE_%s, %d, %d, %d, %d, %s, %s}%s",
497471
tile.flags, tile.typeName.c_str(),
498472
tile.score,
499473
tile.health,
500474
tile.speed,
501475
tile.ai,
502476
tile.hidden ? "true" : "false",
503-
tile.basename.c_str(),
477+
appSettings.diet ? "nullptr" : basename.c_str(),
504478
i != tileDefs.size() - 1 ? ", " : " ");
505479
lines.push_back(tmp);
506480
maxLenght = std::max(maxLenght, strlen(tmp));
@@ -529,23 +503,27 @@ bool generateData(const std::string section, std::string const sectionBasename,
529503
tfileData += tmp;
530504
}
531505

532-
tfileData += "};\n\n"
533-
"const uint8_t chMap[] = {\n";
534-
for (int i = 0; i < sizeof(chMap); ++i)
506+
tfileData += "};\n\n";
507+
508+
if (!appSettings.diet)
535509
{
536-
sprintf(tmp, "%s0x%.2x%s",
537-
i % 8 == 0 ? " " : "",
538-
chMap[i],
539-
// chMap[i], i != sizeof(chMap) - 1 ? ", " : "",
540-
i % 8 == 7 ? ",\n" : ", ");
541-
tfileData += tmp;
510+
tfileData += "const uint8_t chMap[] = {\n";
511+
for (int i = 0; i < sizeof(chMap); ++i)
512+
{
513+
sprintf(tmp, "%s0x%.2x%s",
514+
i % 8 == 0 ? " " : "",
515+
chMap[i],
516+
i % 8 == 7 ? ",\n" : ", ");
517+
tfileData += tmp;
518+
}
519+
tfileData += "};\n\n";
520+
tfileData += "uint8_t getChTile(const uint8_t i)\n"
521+
"{\n"
522+
" return chMap[i % sizeof(chMap)];\n"
523+
"}\n\n";
542524
}
543-
tfileData += "};\n\n"
544-
"uint8_t getChTile(const uint8_t i)\n"
545-
"{\n"
546-
" return chMap[i % sizeof(chMap)];\n"
547-
"}\n\n"
548-
"const TileDef *getTileDefs()\n"
525+
526+
tfileData += "const TileDef *getTileDefs()\n"
549527
"{\n"
550528
" return tileDefs;\n"
551529
"}\n\n"
@@ -698,7 +676,8 @@ bool processSection(
698676
const std::string section,
699677
StringVector &files,
700678
MapStrVal &constConfig,
701-
const AppSettings &appSettings)
679+
const AppSettings &appSettings,
680+
Palette &colors)
702681
{
703682
bool useTileDefs = false;
704683
const std::string sectionName = formatTitleName(section.c_str());
@@ -815,9 +794,19 @@ bool processSection(
815794
switch (appSettings.pixelWidth)
816795
{
817796
case CTileSet::pixel8:
797+
if (colors.size() == 0)
798+
{
799+
colors[0] = 0;
800+
}
801+
818802
for (j = 0; j < pixels; ++j)
819803
{
820-
rgb332[j] = rgb888torgb332(reinterpret_cast<uint8_t *>(&rgbX888[j]));
804+
const uint32_t &color = rgbX888[j] & 0xfff8f8f8;
805+
if (colors.count(color) == 0)
806+
{
807+
colors[color] = colors.size();
808+
}
809+
rgb332[j] = colors[color];
821810
}
822811
tiles.set(i, rgb332);
823812
break;
@@ -834,9 +823,10 @@ bool processSection(
834823
uint8_t bgr[4]{rgb[2], rgb[1], rgb[0], rgb[3]};
835824
rgb565[j] = rgb888torgb565(bgr);
836825
}
837-
else if (appSettings.encoding == ENCODING_RGB555)
826+
else if (appSettings.encoding == ENCODING_RGBX555)
838827
{
839-
rgb565[j] = rgb888torgb555(reinterpret_cast<uint8_t *>(&rgbX888[j]));
828+
uint16_t color = (rgbX888[j] & 0xff000000) ? (0x8000 | rgb888torgb555(reinterpret_cast<uint8_t *>(&rgbX888[j]))) : 0;
829+
rgb565[j] = color;
840830
}
841831
}
842832
tiles.set(i, rgb565);
@@ -865,16 +855,42 @@ bool processSection(
865855
// generate data
866856
if (useTileDefs)
867857
{
868-
generateData(section, sectionBasename, tileDefs);
858+
generateData(appSettings, section, sectionBasename, tileDefs);
859+
}
860+
861+
if (colors.size())
862+
{
863+
printf("palette: %lu\n", colors.size());
869864
}
870865

871866
printf("\n");
872867
return true;
873868
}
874869

870+
bool writePalette(const std::string &lastTileSet, Palette &colors)
871+
{
872+
size_t colorCount = colors.size();
873+
if (colorCount != 0)
874+
{
875+
std::string palettePath = lastTileSet + ".pal";
876+
uint32_t palette[colorCount];
877+
printf("writing palette: %s\n", palettePath.c_str());
878+
for (const auto &[color, idx] : colors)
879+
{
880+
palette[idx] = color;
881+
}
882+
FILE *tfile = fopen(palettePath.c_str(), "wb");
883+
fwrite(palette, sizeof(palette), 1, tfile);
884+
fclose(tfile);
885+
}
886+
return true;
887+
}
888+
875889
bool runJob(const char *src, const AppSettings &appSettings)
876890
{
877891
Config conf;
892+
Palette colors;
893+
std::string lastTileSet;
878894
StrVector sectionList;
879895
bool result;
880896
if (result = parseConfig(conf, sectionList, src))
@@ -902,17 +918,19 @@ bool runJob(const char *src, const AppSettings &appSettings)
902918
}
903919
else
904920
{
921+
lastTileSet = sectionName;
905922
puts(sectionName.c_str());
906923
processSection(
907924
sectionName,
908925
files,
909926
constConfig,
910-
appSettings);
927+
appSettings,
928+
colors);
911929
}
912930
}
913931
writeConstFile(constLists);
914932
}
915-
933+
writePalette(lastTileSet, colors);
916934
return result;
917935
}
918936

@@ -925,15 +943,16 @@ void showUsage(const char *cmd)
925943
"\n"
926944
"filex.ini job configuration \n"
927945
"-e?999 image encoding\n"
928-
" 565 (16bits, default)\n"
929-
" 565BGR (16bits)\n"
930-
" 555 (15bits)\n"
946+
" 565 (16 bits, default)\n"
947+
" 565BGR (16 bits)\n"
948+
" X555 (16 bits)\n"
949+
" X888P (8 bits) + palette\n"
931950
" 888 (24 bits)\n"
932951
" X888 (32 bits)\n"
933-
" 332 (8 bits)\n"
934952
"-r raw headerless generation\n"
935953
"-f flip bytes (only applies to 16bits)\n"
936954
"-p output to png rather than obl\n"
955+
"-d diet\n"
937956
"-h show help\n"
938957
"\n",
939958
cmd);
@@ -946,6 +965,7 @@ int main(int argc, char *argv[], char *envp[])
946965
.encoding = ENCODING_RGB565,
947966
.flipPixels = false,
948967
.headerless = false,
968+
.diet = false,
949969
};
950970
StringVector files;
951971

@@ -972,14 +992,14 @@ int main(int argc, char *argv[], char *envp[])
972992
appSettings.encoding = ENCODING_RGB565BGR;
973993
appSettings.pixelWidth = 2;
974994
}
975-
else if (strcmp(&src[2], ENCODING_RGB[ENCODING_RGB555]) == 0)
995+
else if (strcmp(&src[2], ENCODING_RGB[ENCODING_RGBX555]) == 0)
976996
{
977-
appSettings.encoding = ENCODING_RGB555;
997+
appSettings.encoding = ENCODING_RGBX555;
978998
appSettings.pixelWidth = 2;
979999
}
980-
else if (strcmp(&src[2], ENCODING_RGB[ENCODING_RGB332]) == 0)
1000+
else if (strcmp(&src[2], ENCODING_RGB[ENCODING_RGBX888P]) == 0)
9811001
{
982-
appSettings.encoding = ENCODING_RGB332;
1002+
appSettings.encoding = ENCODING_RGBX888P;
9831003
appSettings.pixelWidth = 1;
9841004
}
9851005
else if (strcmp(&src[2], ENCODING_RGB[ENCODING_RGB888]) == 0)
@@ -1024,6 +1044,11 @@ int main(int argc, char *argv[], char *envp[])
10241044
appSettings.flipPixels = true;
10251045
continue;
10261046
}
1047+
else if (src[1] == 'd')
1048+
{
1049+
appSettings.diet = true;
1050+
continue;
1051+
}
10271052
else if (src[1] == 'r')
10281053
{
10291054
appSettings.headerless = true;

0 commit comments

Comments
 (0)