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
2525const 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
6162typedef std::vector<std::string> StringVector;
@@ -64,6 +65,7 @@ typedef std::vector<std::string> StrVector;
6465typedef std::map<std::string, StringVector> Config;
6566typedef std::unordered_map<std::string, uint8_t > StrVal;
6667typedef std::map<std::string, StrVal> MapStrVal;
68+ typedef std::unordered_map<uint32_t , uint8_t > Palette;
6769
6870const 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-
164137int 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+
875889bool 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