git.y1.nz

gbdk-2020

GameBoy Development Kit
download: https://git.y1.nz/archives/gbdk.tar.gz
README | Files | Log | Refs | LICENSE

gbdk-support/png2asset/export_c_file.cpp

      1 // This prevents windows build errors regarding the 'fopen' function
      2 // Example: 'fopen': This function or variable may be unsafe.Consider using fopen_s instead.To disable deprecation, use _CRT_SECURE_NO_WARNINGS.See online help for details.
      3 // More info: https://stackoverflow.com/questions/14386/fopen-deprecated-warning
      4 // From bbbbbr: `Looks like some of the benefits are concurrency protection, but that probably isn't an issue for png2asset`
      5 #ifdef _WIN32
      6 #define _CRT_SECURE_NO_DEPRECATE
      7 #endif
      8 
      9 #include <vector>
     10 #include <string>
     11 #include <algorithm>
     12 #include <cstring>
     13 #include <set>
     14 #include <stdio.h>
     15 #include <fstream>
     16 #include <cstdint>
     17 
     18 #include "lodepng.h"
     19 #include "mttile.h"
     20 
     21 #include "cmp_int_color.h"
     22 #include "metasprites.h"
     23 
     24 #include "png2asset.h"
     25 #include "png_image.h"
     26 #include "export.h"
     27 #include "image_utils.h"
     28 #include "process_arguments.h"
     29 #include "rgb_to_nes_lut.h"
     30 
     31 using namespace std;
     32 
     33 enum {
     34     ZGB_TILES_MODE_NORMAL,
     35     ZGB_TILES_MODE_TILESONLY
     36 };
     37 
     38 static exportOptions_t exportOpt;
     39 
     40 static void export_c_palette_data(PNG2AssetData* assetData, FILE* file);
     41 static void export_c_tile_data(PNG2AssetData* assetData, FILE* file);
     42 static void export_c_metasprite_mode(PNG2AssetData* assetData, FILE* file);
     43 static void export_c_map_mode(PNG2AssetData* assetData, FILE* file);
     44 
     45 static void export_c_zgb_metasprite_struct(PNG2AssetData* assetData, FILE* file);
     46 static void export_c_zgb_per_tile_palette_ids(PNG2AssetData* assetData, FILE* file);
     47 static void export_c_zgb_tiles_struct(PNG2AssetData* assetData, FILE* file, int output_mode);
     48 static void export_c_zgb_map_struct(PNG2AssetData* assetData, FILE* file);
     49 
     50 
     51 bool export_c_file( PNG2AssetData* assetData) {
     52 
     53     FILE* file;
     54     calc_palette_and_tileset_export_size(assetData, &exportOpt);
     55 
     56     file = fopen(assetData->args->output_filename.c_str(), "w");
     57     if(!file) {
     58         printf("Error writing file: %s", assetData->args->output_filename.c_str());
     59         return false;
     60     }
     61 
     62     if (assetData->args->bank != BANK_NUM_UNSET) {
     63         if (assetData->args->area_specified)
     64             fprintf(file, "#pragma constseg %s_%d\n\n", assetData->args->area_name.c_str(), assetData->args->bank);
     65         else
     66             fprintf(file, "#pragma bank %d\n\n", assetData->args->bank);
     67     }
     68 
     69     fprintf(file, "//AUTOGENERATED FILE FROM png2asset\n");
     70     fprintf(file, "// Conversion args:%s\n\n", assetData->args->args_for_logging_to_output.c_str());
     71 
     72     fprintf(file, "#include <stdint.h>\n");
     73     fprintf(file, "#include <gbdk/platform.h>\n");
     74     fprintf(file, "#include <gbdk/metasprites.h>\n");
     75 
     76     if (assetData->args->use_structs) {
     77         fprintf(file, "#include \"TilesInfo.h\"\n");
     78         if (assetData->args->includedMapOrMetaspriteData) {
     79             if (assetData->args->export_as_map)
     80                 fprintf(file, "#include \"MapInfo.h\"\n");
     81             else
     82                 fprintf(file, "#include \"MetaSpriteInfo.h\"\n");
     83         }
     84     }
     85 
     86     fprintf(file, "\n");
     87 
     88     fprintf(file, "BANKREF(%s)\n\n", assetData->args->data_name.c_str());
     89 
     90     if (exportOpt.has_palette_data_to_export)
     91         export_c_palette_data(assetData, file);
     92 
     93     if (assetData->args->includeTileData)
     94         export_c_tile_data(assetData, file);
     95 
     96     if (assetData->args->includedMapOrMetaspriteData) {
     97 
     98         if (assetData->args->export_as_map) {
     99             export_c_map_mode(assetData, file);
    100         }
    101         else {
    102             export_c_metasprite_mode(assetData, file);
    103         }
    104     }
    105     else {
    106         // "-use_structs -tiles_only" case
    107         if ((assetData->args->includeTileData) && (assetData->args->use_structs)) {
    108             export_c_zgb_per_tile_palette_ids(assetData, file);
    109             export_c_zgb_tiles_struct(assetData, file, ZGB_TILES_MODE_TILESONLY);
    110         }
    111     }
    112 
    113     fclose(file);
    114     return true; // success
    115 }
    116 
    117 
    118 static void export_c_palette_data(PNG2AssetData* assetData, FILE* file) {
    119 
    120     if (!(assetData->args->use_structs) || (assetData->args->includeTileData)) {
    121         fprintf(file, "const palette_color_t %s_palettes[%d] = {\n", assetData->args->data_name.c_str(), (unsigned int)exportOpt.color_count);
    122         const size_t palette_start = exportOpt.color_start / assetData->image.colors_per_pal;
    123         const size_t total_palette_count = assetData->image.total_color_count / assetData->image.colors_per_pal;
    124         int cur_color = exportOpt.color_start;
    125 
    126         fprintf(file, "\t");
    127         for (size_t i = palette_start; i < total_palette_count; ++i)
    128         {
    129             unsigned char* pal_ptr = &assetData->image.palette[i * (assetData->image.colors_per_pal * RGBA32_SZ)];
    130             for (int c = 0; c < (int)assetData->image.colors_per_pal; ++c, pal_ptr += RGBA32_SZ)
    131             {
    132                 size_t rgb222 = (((pal_ptr[2] >> 6) & 0x3) << 4) |
    133                     (((pal_ptr[1] >> 6) & 0x3) << 2) |
    134                     (((pal_ptr[0] >> 6) & 0x3) << 0);
    135 
    136                 if (assetData->args->convert_rgb_to_nes)
    137                     fprintf(file, "0x%0X", rgb_to_nes[rgb222]);
    138                 else
    139                     fprintf(file, "RGB8(%3d,%3d,%3d)", pal_ptr[0], pal_ptr[1], pal_ptr[2]);
    140 
    141                 // Trailing comma except for the last entry
    142                 if (cur_color < ((int)assetData->image.total_color_count - 1))
    143                     fprintf(file, ",");
    144 
    145                 // Line break every 4 colors to keep line width down,
    146                 // otherwise a trailing space (except on the last color/array item)
    147                 if (((cur_color + 1) % 4) == 0)
    148                     fprintf(file, "\n\t");
    149                 else if (cur_color < ((int)assetData->image.total_color_count - 1))
    150                     fprintf(file, " ");
    151 
    152                 cur_color++;
    153             }
    154         }
    155         fprintf(file, "};\n");
    156     }
    157 }
    158 
    159 
    160 static void export_c_tile_data(PNG2AssetData* assetData, FILE* file) {
    161 
    162     fprintf(file, "\n");
    163     fprintf(file, "const uint8_t %s_tiles[%d] = {\n", assetData->args->data_name.c_str(), (unsigned int)(exportOpt.tiles_count * assetData->image.tile_w * assetData->image.tile_h * assetData->args->bpp / 8));
    164     fprintf(file, "\t");
    165     for(vector< Tile >::iterator it = assetData->tiles.begin() + exportOpt.tiles_start; it != assetData->tiles.end(); ++it)
    166     {
    167 
    168         int line_break = 1; // Start with 1 to prevent line break on first iteration
    169         vector< unsigned char > packed_data = (*it).GetPackedData(assetData->args->pack_mode, assetData->image.tile_w, assetData->image.tile_h, assetData->args->bpp);
    170         for(vector< unsigned char >::iterator it2 = packed_data.begin(); it2 != packed_data.end(); ++it2)
    171         {
    172             fprintf(file, "0x%02x", (*it2));
    173             if((it + 1) != assetData->tiles.end() || (it2 + 1) != packed_data.end())
    174                 fprintf(file, ",");
    175             // Add a line break after each 8x8 tile
    176             if (((line_break++) % (8 * assetData->args->bpp)) == 0)
    177                 fprintf(file, "\n\t");
    178         }
    179     }
    180     fprintf(file, "};\n\n");
    181 
    182 }
    183 
    184 
    185 static void export_c_metasprite_mode(PNG2AssetData* assetData, FILE* file) {
    186 
    187     for(vector< MetaSprite >::iterator it = assetData->sprites.begin(); it != assetData->sprites.end(); ++it)
    188     {
    189         fprintf(file, "const metasprite_t %s_metasprite%d[] = {\n", assetData->args->data_name.c_str(), (int)(it - assetData->sprites.begin()));
    190         for(MetaSprite::iterator it2 = (*it).begin(); it2 != (*it).end(); ++it2)
    191         {
    192             int pal_idx  = (*it2).props & 0xF;
    193             int dmg_pal  = ((*it2).props >> 4) & 1;
    194             int flip_x   = ((*it2).props >> 5) & 1;
    195             int flip_y   = ((*it2).props >> 6) & 1;
    196             int priority = ((*it2).props >> 7) & 1;
    197             fprintf(file,
    198                 "\tMETASPR_ITEM(%d, %d, %d, S_PAL(%d)%s%s%s%s),\n",
    199                 (*it2).offset_y,
    200                 (*it2).offset_x,
    201                 (*it2).offset_idx,
    202                 pal_idx,
    203                 (dmg_pal)  ? " | S_PALETTE"  : "",
    204                 (flip_x)   ? " | S_FLIPX"    : "",
    205                 (flip_y)   ? " | S_FLIPY"    : "",
    206                 (priority) ? " | S_PRIORITY" : "");
    207         }
    208         fprintf(file, "\tMETASPR_TERM\n");
    209         fprintf(file, "};\n\n");
    210     }
    211 
    212     fprintf(file, "const metasprite_t* const %s_metasprites[%d] = {\n\t", assetData->args->data_name.c_str(), (unsigned int)(assetData->sprites.size()));
    213     for(vector< MetaSprite >::iterator it = assetData->sprites.begin(); it != assetData->sprites.end(); ++it)
    214     {
    215         fprintf(file, "%s_metasprite%d", assetData->args->data_name.c_str(), (int)(it - assetData->sprites.begin()));
    216         if(it + 1 != assetData->sprites.end())
    217             fprintf(file, ", ");
    218     }
    219     fprintf(file, "\n};\n");
    220 
    221     if(assetData->args->use_structs)
    222         export_c_zgb_metasprite_struct(assetData, file);
    223 
    224 }
    225 
    226 static void export_c_zgb_metasprite_struct(PNG2AssetData* assetData, FILE* file) {
    227     // Export ZGB Metasprite Struct
    228     fprintf(file, "\n");
    229     fprintf(file, "const struct MetaSpriteInfo %s = {\n",   assetData->args->data_name.c_str());
    230     fprintf(file, "\t.width=%d,"                   " // width\n",        (unsigned int)assetData->args->pivot.width);
    231     fprintf(file, "\t.height=%d,"                  " // height\n",       (unsigned int)assetData->args->pivot.height);
    232     fprintf(file, "\t.num_tiles=%d,"               " // num tiles\n",    (unsigned int)assetData->tiles.size() * (assetData->image.tile_h >> 3));
    233     fprintf(file, "\t.data=%s_tiles,"              " // tiles\n",        assetData->args->data_name.c_str());
    234     fprintf(file, "\t.num_palettes=%d,"            " // num palettes\n", (unsigned int)(assetData->image.total_color_count / assetData->image.colors_per_pal));
    235     fprintf(file, "\t.palettes=%s_palettes,"       " // CGB palette\n",  assetData->args->data_name.c_str());
    236     fprintf(file, "\t.num_sprites=%d,"             " // num sprites\n",  (unsigned int)assetData->sprites.size());
    237     fprintf(file, "\t.metasprites=%s_metasprites," " // metasprites\n",  assetData->args->data_name.c_str());
    238     fprintf(file, "};\n");
    239 }
    240 
    241 
    242 static void export_c_map_mode(PNG2AssetData* assetData, FILE* file) {
    243 
    244     // ZGB export mode
    245     if(assetData->args->use_structs)
    246     {
    247         // For ZGB Structs with source_tileset enabled, the primary tile data points to the EXTERNAL source tileset
    248         // so add the required externs used to reference them in the struct
    249         if( (assetData->args->has_source_tilesets)) {
    250             fprintf(file, "\n");
    251             fprintf(file, "BANKREF_EXTERN(%s)\n", extract_name(assetData->args->source_tilesets[0]).c_str());
    252             fprintf(file, "extern const struct TilesInfo %s;\n", extract_name(assetData->args->source_tilesets[0]).c_str());
    253         }
    254 
    255         // Map's own tile data, if any present
    256         if(assetData->args->includeTileData) {
    257             export_c_zgb_per_tile_palette_ids(assetData, file);
    258             export_c_zgb_tiles_struct(assetData, file, ZGB_TILES_MODE_NORMAL);
    259         }
    260     }
    261 
    262     //Export map
    263     fprintf(file, "\n");
    264     fprintf(file, "const unsigned char %s_map[%d] = {\n", assetData->args->data_name.c_str(), (unsigned int)(assetData->map.size()));
    265     // TODO: These hardwired "/ 8" should be using " / assetData->image.tile_w" and "_h"
    266     // TODO: Should also be converted to using args.map_entry_size_bytes
    267     size_t line_size = assetData->map.size() / (assetData->image.h / 8);
    268     if(assetData->args->output_transposed) {
    269 
    270         for(size_t i = 0; i < line_size; ++i)
    271         {
    272             fprintf(file, "\t");
    273             for(size_t j = 0; j < assetData->image.h / 8; ++j)
    274             {
    275                 fprintf(file, "0x%02x,", assetData->map[j * line_size + i]);
    276             }
    277             fprintf(file, "\n");
    278         }
    279     }
    280     else {
    281 
    282         for(size_t j = 0; j < assetData->image.h / 8; ++j)
    283         {
    284             fprintf(file, "\t");
    285             for(size_t i = 0; i < line_size; ++i)
    286             {
    287                 fprintf(file, "0x%02x,", assetData->map[j * line_size + i]);
    288             }
    289             fprintf(file, "\n");
    290         }
    291     }
    292     fprintf(file, "};\n");
    293 
    294 
    295     //Export map attributes (if any)
    296     if(assetData->args->use_map_attributes && assetData->map_attributes.size())
    297     {
    298         fprintf(file, "\n");
    299         fprintf(file, "const unsigned char %s_map_attributes[%d] = {\n", assetData->args->data_name.c_str(), (unsigned int)(assetData->map_attributes.size()));
    300         if(assetData->args->output_transposed) {
    301             for(size_t i = 0; i < assetData->args->map_attributes_packed_size.width; ++i)
    302             {
    303                 fprintf(file, "\t");
    304                 for(size_t j = 0; j < assetData->args->map_attributes_packed_size.height; ++j)
    305                 {
    306                     fprintf(file, "0x%02x,", assetData->map_attributes[j * assetData->args->map_attributes_packed_size.width + i]);
    307                 }
    308                 fprintf(file, "\n");
    309             }
    310         }
    311         else {
    312             for(size_t j = 0; j < assetData->args->map_attributes_packed_size.height; ++j)
    313             {
    314                 fprintf(file, "\t");
    315                 for(size_t i = 0; i < assetData->args->map_attributes_packed_size.width; ++i)
    316                 {
    317                     fprintf(file, "0x%02x,", assetData->map_attributes[j * assetData->args->map_attributes_packed_size.width + i]);
    318                 }
    319                 fprintf(file, "\n");
    320             }
    321         }
    322 
    323         fprintf(file, "};\n");
    324     }
    325 
    326     if(assetData->args->use_structs)
    327         export_c_zgb_map_struct(assetData, file);
    328 }
    329 
    330 
    331 static void export_c_zgb_per_tile_palette_ids(PNG2AssetData* assetData, FILE* file) {
    332     //Export tiles pals (if any)
    333     if(!assetData->args->use_map_attributes)
    334     {
    335         fprintf(file, "\n");
    336         fprintf(file, "const uint8_t %s_tile_pals[%d] = {\n\t", assetData->args->data_name.c_str(), (unsigned int)exportOpt.tiles_count);
    337         for(vector< Tile >::iterator it = assetData->tiles.begin() + exportOpt.tiles_start; it != assetData->tiles.end(); ++it)
    338         {
    339             fprintf(file, "%d", it->pal);
    340             if (it + 1 != assetData->tiles.end())
    341                 fprintf(file, ", ");
    342         }
    343         fprintf(file, "\n};\n");
    344     }
    345 }
    346 
    347 
    348 static void export_c_zgb_tiles_struct(PNG2AssetData* assetData, FILE* file, int output_mode) {
    349     // Export Tiles Info
    350     fprintf(file, "\n");
    351     // ZGB Tiles-only mode doesn't append "_tiles_info" to the struct name and lacks a BANKREF output.
    352     if (output_mode == ZGB_TILES_MODE_TILESONLY) {
    353         fprintf(file, "const struct TilesInfo %s = {\n",                   assetData->args->data_name.c_str());
    354     }
    355     else { // implied (output_mode == ZGB_TILES_MODE_NORMAL)
    356         fprintf(file, "BANKREF(%s_tiles_info)\n", assetData->args->data_name.c_str());
    357         fprintf(file, "const struct TilesInfo %s_tiles_info = {\n",        assetData->args->data_name.c_str());
    358     }
    359 
    360     fprintf(file, "\t.num_frames=%d,"            " // num tiles\n",    (unsigned int)exportOpt.tiles_count);
    361     fprintf(file, "\t.data=%s_tiles,"            " // tiles\n",        assetData->args->data_name.c_str());
    362     fprintf(file, "\t.num_pals=%d,"              " // num palettes\n", (unsigned int)(exportOpt.color_count / assetData->image.colors_per_pal));
    363     fprintf(file, "\t.pals=%s_palettes,"         " // palettes\n",     assetData->args->data_name.c_str());
    364 
    365     // This var references the output of export_c_zgb_per_tile_palette_ids()
    366     if(!assetData->args->use_map_attributes)
    367         fprintf(file, "\t.color_data=%s_tile_pals, // tile palettes\n", assetData->args->data_name.c_str());
    368     else
    369         fprintf(file, "\t.color_data=0 "         " // tile palettes\n");
    370     fprintf(file, "};\n");
    371 }
    372 
    373 
    374 // "-use_structs" map output behavior
    375 //
    376 //   "-source_tileset" NOT enabled:
    377 //     - tile data -> TileInfo struct, point .tiles to it
    378 //     - .tiles points to TileInfo struct, .extra_tiles is NULL
    379 //     - only map tile palettes *not* found in the source tileset will be emitted for .num_pals/.pals
    380 //
    381 //   "-source_tileset" IS enabled
    382 //     - .tiles -> the external source tileset
    383 //     - .extra_tiles -> map TileInfo
    384 //       - contains unique tiles not found in source tileset (not in entity tiles)
    385 //         - if none of those tiles were found then
    386 //           - map TileInfo will not be emitted
    387 //           - .extra_tiles == NULL then
    388 //     - *all* map tile palettes will be emitted for .num_pals/.pals (those from map and source tileset)
    389 //
    390 static void export_c_zgb_map_struct(PNG2AssetData* assetData, FILE* file) {
    391     //Export Map Info
    392     fprintf(file, "\n");
    393 
    394     if(assetData->args->includeTileData) {
    395         fprintf(file, "BANKREF_EXTERN(%s_tiles_info)\n", assetData->args->data_name.c_str());
    396     }
    397 
    398     fprintf(file, "const struct MapInfo %s = {\n",                       assetData->args->data_name.c_str());
    399     fprintf(file, "\t.data=%s_map,"                      " // map\n",    assetData->args->data_name.c_str());
    400     fprintf(file, "\t.width=%d,"                         " // width\n",  assetData->image.w >> 3);
    401     fprintf(file, "\t.height=%d,"                        " // height\n", assetData->image.h >> 3);
    402 
    403     if(assetData->args->use_map_attributes && assetData->map_attributes.size())
    404         fprintf(file, "\t.attributes=%s_map_attributes," " // map attributes\n", assetData->args->data_name.c_str());
    405     else
    406         fprintf(file, "\t.attributes=0,"                 " // map attributes\n");
    407 
    408     // For ZGB Structs with source_tileset enabled, the tile data points to the EXTERNAL source tileset
    409     if (assetData->args->has_source_tilesets == true) {
    410         fprintf(file, "\t.tiles_bank=BANK(%s),"     " // source tiles bank\n", extract_name(assetData->args->source_tilesets[0]).c_str());
    411         fprintf(file, "\t.tiles=&%s,"               " // source tiles info\n", extract_name(assetData->args->source_tilesets[0]).c_str());
    412 
    413         // If map tiles were found that were not in the source tileset (or entity tileset)
    414         // then point ".extra_tiles" to them. Otherwise set it to null to indicate none found.
    415         if (exportOpt.tiles_count > 0) {
    416             fprintf(file, "\t.extra_tiles=&%s_tiles_info,"        " // pointer to Tilesinfo struct with map tiles not found in the source tileset\n", assetData->args->data_name.c_str());
    417             fprintf(file, "\t.extra_tiles_bank=BANK(%s_tiles_info), // bank for above Tilesinfo struct\n", assetData->args->data_name.c_str());
    418         }
    419         else {
    420             fprintf(file, "\t.extra_tiles=NULL,"                  " // pointer to Tilesinfo struct with map tiles not found in the source tileset (no extra tiles found)\n");
    421             fprintf(file, "\t.extra_tiles_bank=0,"                " // bank for above Tilesinfo struct\n");
    422         }
    423 
    424     }
    425     else if(assetData->args->includeTileData) {
    426         fprintf(file, "\t.tiles_bank=BANK(%s_tiles_info), // tiles bank\n", assetData->args->data_name.c_str());
    427         fprintf(file, "\t.tiles=&%s_tiles_info,"        " // tiles info\n", assetData->args->data_name.c_str());
    428     }
    429     fprintf(file, "};\n");
    430 }

This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.