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/process_arguments.cpp

      1 #include <vector>
      2 #include <string>
      3 #include <algorithm>
      4 #include <cstring>
      5 #include <set>
      6 #include <stdio.h>
      7 #include <fstream>
      8 #include <cstdint>
      9 #include <cstdlib>
     10 #include <fstream>
     11 #include <sstream>
     12 
     13 #include "lodepng.h"
     14 #include "mttile.h"
     15 #include "export.h"
     16 #include "map_attributes.h"
     17 #include "palettes.h"
     18 
     19 #include "cmp_int_color.h"
     20 
     21 #include "image_utils.h"
     22 #include "image_data.h"
     23 #include "maps.h"
     24 #include "metasprites.h"
     25 #include "metasprites_functions.h"
     26 #include "process_arguments.h"
     27 #include "png_image.h"
     28 #include "tiles.h"
     29 
     30 #define ARG_SKIP_NONE            0
     31 #define ARG_AT_INPUT_FILENAME    1
     32 #define ARG_AFTER_INPUT_FILENAME 2
     33 
     34 
     35 
     36 using namespace std;
     37 
     38 static string str_remove_path(string str_in);
     39 static void logArguments(int startIndex, int argc, const char* argv[], PNG2AssetArguments* args);
     40 static void initArguments(PNG2AssetArguments* args);
     41 static void showHelp(void);
     42 static int processArguments(int startIndex, int argc, const char* argv[], PNG2AssetArguments* args);
     43 static int handleMetaFileArgs(PNG2AssetArguments* args);
     44 
     45 // Strip any leading path and slashes
     46 static string str_remove_path(string str_in) {
     47     size_t slash_pos = str_in.find_last_of('/');
     48     if (slash_pos != str_in.npos)
     49         str_in = str_in.substr(slash_pos, str_in.length() - slash_pos);
     50 
     51     slash_pos = str_in.find_last_of('\\');
     52     if (slash_pos != str_in.npos)
     53         str_in = str_in.substr(slash_pos, str_in.length() - slash_pos);
     54 
     55     return str_in;
     56 }
     57 
     58 
     59 static void initArguments(PNG2AssetArguments* args) {
     60 
     61     //default values for some params
     62     args->spriteSize.width = 0;
     63     args->spriteSize.height = 0;
     64     args->map_attributes_size.width = 0;
     65     args->map_attributes_size.height = 0;
     66     args->map_attributes_packed_size.width = 0;
     67     args->map_attributes_packed_size.height = 0;
     68 
     69     args->pivot.x = 0xFFFFFF;
     70     args->pivot.y = 0xFFFFFF;
     71     args->pivot.width = 0xFFFFFF;
     72     args->pivot.height = 0xFFFFFF;
     73 
     74 
     75     args->max_palettes = 8;
     76 
     77     args->keep_palette_order = false;
     78     args->repair_indexed_pal = false;
     79     args->output_binary = false;
     80     args->output_transposed = false;
     81     args->export_as_map = false;
     82     args->use_map_attributes = false;
     83     args->use_2x2_map_attributes = false;
     84     args->pack_map_attributes = false;
     85     args->convert_rgb_to_nes = false;
     86     args->includeTileData = true;
     87     args->includedMapOrMetaspriteData = true;
     88     args->keep_duplicate_tiles = false;
     89     args->keep_empty_sprite_tiles = false;
     90     args->include_palettes = true;
     91     args->use_structs = false;
     92     args->flip_tiles = true;
     93 
     94     // args->errorCode;
     95     args->bank = BANK_NUM_UNSET;
     96     args->area_specified = false;
     97     args->sprite_mode = SPR_8x16;
     98     args->bpp = 2;
     99     args->props_default = 0;
    100 
    101     args->tile_origin = 0; // Default to no tile index offset
    102     args->source_total_color_count = 0;
    103     args->source_tileset_size = 0;
    104     args->has_source_tilesets = false;
    105 
    106     args->has_entity_tileset = false;
    107 
    108     args->processing_mode = MODE_MAIN_IMAGE;
    109 
    110     args->pack_mode = Tile::GB;
    111     args->map_entry_size_bytes = 1;
    112 
    113     args->args_for_logging_to_output = "";
    114 
    115     args->relative_paths = false;
    116     args->use_metafile = false;
    117 }
    118 
    119 
    120 void showHelp(void) {
    121         printf("usage: png2asset    <file>.png [options]\n");
    122         printf("-o <filename>       ouput file (if not used then default is <png file>.c)\n");
    123         printf("-c <filename>       deprecated, same as -o\n");
    124         printf("-sw <width>         metasprites width size (default: png width)\n");
    125         printf("-sh <height>        metasprites height size (default: png height)\n");
    126         printf("-sp <props>         change default for sprite OAM property bytes (in hex) (default: 0x00)\n");
    127         printf("-px <x coord>       metasprites pivot x coordinate (default: metasprites width / 2)\n");
    128         printf("-py <y coord>       metasprites pivot y coordinate (default: metasprites height / 2)\n");
    129         printf("-pw <width>         metasprites collision rect width (default: metasprites width)\n");
    130         printf("-ph <height>        metasprites collision rect height (default: metasprites height)\n");
    131         printf("-spr8x8             for 8x8  hardware sprites (use SPRITES_8x8)\n");
    132         printf("-spr8x16            for 8x16 hardware sprites (use SPRITES_8x16) (the default)\n");
    133         printf("-spr16x16msx        MSX only: for 16x16 hardware sprites (use SPRITES_16x16)\n");
    134         printf("-sprite_no_optimize keep empty sprite tiles, do not remove duplicate tiles\n");
    135         printf("-b <banknum>        Bank number (default: fixed bank)\n");
    136         printf("-area <area name>   Area name. Alters \"pragma bank ...\" output to constseg style. (Ex: -area LIT)\n");
    137         printf("-keep_palette_order use png palette\n");
    138         printf("-repair_indexed_pal try to repair indexed tile palettes (implies \"-keep_palette_order\")\n");
    139         printf("-noflip             disable tile flip\n");
    140         printf("-map                Export as map (tileset + bg) instead of default metasprite output\n");
    141         printf("-use_map_attributes Use GBC/SMS/GG BG Map attributes\n");
    142         printf("-use_nes_attributes Use NES BG Map attributes\n");
    143         printf("-use_nes_colors     Convert RGB color values to NES PPU colors\n");
    144         printf("-use_structs        Group the exported info into structs (default: false) (used by ZGB Game Engine)\n");
    145         printf("-bpp                bits per pixel: 1, 2, 4 (default: 2. using 1 auto-enables \"-pack_mode 1bpp\")\n");
    146         printf("-max_palettes       max number of palettes allowed (default: 8)\n");
    147         printf("                    (note: max colors = max_palettes x num colors per palette)\n");
    148         printf("-pack_mode          gb, nes, sgb, sms, 1bpp (default: gb. using 1bpp auto-enables \"-bpp 1\")\n");
    149         printf("-tile_origin        tile index offset for maps (default: 0)\n");
    150 
    151         printf("-tiles_only         export tile data only\n");
    152         printf("-maps_only          export map tilemap only\n");
    153         printf("-metasprites_only   export metasprite descriptors only\n");
    154         printf("-source_tileset     use source tileset (image with common tiles)\n");
    155         printf("-entity_tileset     (maps only) mark matching tiles counting from 255 down, entity patterns not exported\n");
    156         printf("-keep_duplicate_tiles   do not remove duplicate tiles (default: not enabled)\n");
    157         printf("-no_palettes        do not export palette data\n");
    158 
    159         printf("-bin                export to binary format (requires -map)\n");
    160         printf("-transposed         export transposed (column-by-column instead of row-by-row)\n");
    161 
    162         printf("-rel_paths          paths to tilesets are relative to the input file path\n");
    163         printf("-use_metafile       Read extra options from file <inputfile>.meta (file missing not an error)\n");
    164 }
    165 
    166 
    167 static void logArguments(int startIndex, int argc, const char* argv[], PNG2AssetArguments* args) {
    168  
    169     // Save all args for logging into output files
    170     for (int i = startIndex; i < argc; ++i) {
    171         args->args_for_logging_to_output.append(" ").append( str_remove_path((string)argv[i]) );
    172     }
    173 }
    174 
    175 
    176 static int processArguments(int startIndex, int argc, const char* argv[], PNG2AssetArguments* args) {
    177 
    178     //Parse argv
    179     for (int i = startIndex; i < argc; ++i)
    180     {
    181         if(!strcmp(argv[i], "-sw"))
    182         {
    183             args->spriteSize.width = atoi(argv[++i]);
    184         }
    185         else if(!strcmp(argv[i], "-sh"))
    186         {
    187             args->spriteSize.height = atoi(argv[++i]);
    188         }
    189         else if(!strcmp(argv[i], "-sp"))
    190         {
    191             args->props_default = strtol(argv[++i], NULL, 16);
    192         }
    193         else if(!strcmp(argv[i], "-px"))
    194         {
    195             args->pivot.x = atoi(argv[++i]);
    196         }
    197         else if(!strcmp(argv[i], "-py"))
    198         {
    199             args->pivot.y = atoi(argv[++i]);
    200         }
    201         else if(!strcmp(argv[i], "-pw"))
    202         {
    203             args->pivot.width = atoi(argv[++i]);
    204         }
    205         else if(!strcmp(argv[i], "-ph"))
    206         {
    207             args->pivot.height = atoi(argv[++i]);
    208         }
    209         else if(!strcmp(argv[i], "-spr8x8"))
    210         {
    211             args->sprite_mode = SPR_8x8;
    212         }
    213         else if(!strcmp(argv[i], "-spr8x16"))
    214         {
    215             args->sprite_mode = SPR_8x16;
    216         }
    217         else if(!strcmp(argv[i], "-spr16x16msx"))
    218         {
    219             args->sprite_mode = SPR_16x16_MSX;
    220         }
    221         else if(!strcmp(argv[i], "-c") || !strcmp(argv[i], "-o"))
    222         {
    223             if ((i + 1) >= argc) {
    224                 printf("Error: -c or -o requires a filename, none specified\n");
    225                 return EXIT_FAILURE;
    226             } else if (argv[i+1][0] == '-') {
    227                 printf("Error: next argument after -o looks like an option instead of a filename (\"%s\")\n", argv[i + 1]);
    228                 return EXIT_FAILURE;
    229             }
    230 
    231             args->output_filename = argv[++i];
    232         }
    233         else if(!strcmp(argv[i], "-b"))
    234         {
    235             args->bank = atoi(argv[++i]);
    236         }
    237         else if(!strcmp(argv[i], "-area"))
    238         {
    239             args->area_name = argv[++i];
    240             args->area_specified = true;
    241         }
    242         else if(!strcmp(argv[i], "-keep_palette_order"))
    243         {
    244             args->keep_palette_order = true;
    245         }
    246         else if(!strcmp(argv[i], "-repair_indexed_pal"))
    247         {
    248             args->repair_indexed_pal = true;
    249             args->keep_palette_order = true; // -repair_indexed_pal requires -keep_palette_order, so force it on
    250         }
    251         else if(!strcmp(argv[i], "-noflip"))
    252         {
    253             args->flip_tiles = false;
    254         }
    255         else if(!strcmp(argv[i], "-map"))
    256         {
    257             args->export_as_map = true;
    258         }
    259         else if(!strcmp(argv[i], "-use_map_attributes"))
    260         {
    261             args->use_map_attributes = true;
    262         }
    263         else if(!strcmp(argv[i], "-use_nes_attributes"))
    264         {
    265             args->use_map_attributes = true;
    266             args->use_2x2_map_attributes = true;
    267             args->pack_map_attributes = true;
    268         }
    269         else if(!strcmp(argv[i], "-use_nes_colors"))
    270         {
    271             args->convert_rgb_to_nes = true;
    272         }
    273         else if(!strcmp(argv[i], "-use_structs"))
    274         {
    275             args->use_structs = true;
    276         }
    277         else if(!strcmp(argv[i], "-bpp"))
    278         {
    279             args->bpp = atoi(argv[++i]);
    280             // If set to "-bpp 1" auto-enable "-pack_mode 1bpp"
    281             if (atoi(argv[i]) == 1) args->pack_mode = Tile::BPP1;
    282         }
    283         else if(!strcmp(argv[i], "-max_palettes"))
    284         {
    285             args->max_palettes = atoi(argv[++i]);
    286             if(args->max_palettes == 0)
    287             {
    288                 printf("-max_palettes must be larger than zero\n");
    289                 return EXIT_FAILURE;
    290             }
    291         }
    292         else if(!strcmp(argv[i], "-pack_mode"))
    293         {
    294             std::string pack_mode_str = argv[++i];
    295             if(pack_mode_str == "gb")  args->pack_mode = Tile::GB;
    296             else if(pack_mode_str == "nes") args->pack_mode = Tile::NES;
    297             else if(pack_mode_str == "sgb") {
    298                 args->pack_mode = Tile::SGB;
    299                 // SGB attributes are packed in map data, so 2 bytes per map tile
    300                 args->map_entry_size_bytes = 2;
    301             }
    302             else if(pack_mode_str == "sms") {
    303                 args->pack_mode = Tile::SMS;
    304                 // SMS attributes are packed in map data, so 2 bytes per map tile
    305                 args->map_entry_size_bytes = 2;
    306             }
    307             else if(pack_mode_str == "1bpp") {
    308                 args->pack_mode = Tile::BPP1;
    309                 // If set to "-pack_mode 1bpp" auto-enable "-bpp 1"
    310                 args->bpp = 1;
    311             }
    312             else
    313             {
    314                 printf("-pack_mode must be one of gb, nes, sgb, sms, 1bpp\n");
    315                 return EXIT_FAILURE;
    316             }
    317         }
    318         else if(!strcmp(argv[i], "-tile_origin"))
    319         {
    320             args->tile_origin = atoi(argv[++i]);
    321         }
    322         else if(!strcmp(argv[i], "-maps_only") || !strcmp(argv[i], "-metasprites_only"))
    323         {
    324             args->includeTileData = false;
    325         }
    326         else if(!strcmp(argv[i], "-tiles_only"))
    327         {
    328             args->includedMapOrMetaspriteData = false;
    329         }
    330         else if(!strcmp(argv[i], "-keep_duplicate_tiles"))
    331         {
    332             args->keep_duplicate_tiles = true;
    333         }
    334         else if(!strcmp(argv[i], "-sprite_no_optimize"))
    335         {
    336             args->keep_duplicate_tiles = true;
    337             args->keep_empty_sprite_tiles = true;
    338         }
    339         else if(!strcmp(argv[i], "-no_palettes"))
    340         {
    341             args->include_palettes = false;
    342         }
    343         else if(!strcmp(argv[i], "-source_tileset"))
    344         {
    345             // Warning / TODO:FIXME
    346             // includeTileData gets overridden back to TRUE if any tiles not present in the source tileset are found.
    347             // This makes understanding it's full export behavior much harder. Would be better to remove it and try to simplify logic.
    348             args->includeTileData = false;
    349             args->source_tilesets.push_back(argv[++i]);
    350         }
    351         else if(!strcmp(argv[i], "-entity_tileset"))
    352         {
    353             args->entity_tileset_filename = argv[++i];
    354             args->has_entity_tileset = true;
    355         }
    356         else if(!strcmp(argv[i], "-bin"))
    357         {
    358             args->output_binary = true;
    359         }
    360         else if(!strcmp(argv[i], "-transposed"))
    361         {
    362             args->output_transposed = true;
    363         }
    364         else if(!strcmp(argv[i], "-rel_paths")) {
    365             args->relative_paths = true;
    366         }
    367         else if(!strcmp(argv[i], "-use_metafile")) {
    368             args->use_metafile = true;
    369         }
    370         else {
    371             printf("Warning: Argument \"%s\" not recognized\n", argv[i]);
    372         }
    373     }
    374 
    375     return EXIT_SUCCESS;
    376 }
    377 
    378 
    379 // Read in and process a set of arguments from a file named <inputfile>.meta
    380 static int handleMetaFileArgs(PNG2AssetArguments* args) {
    381 
    382     string fname = args->input_filename + ".meta";
    383     ifstream metaFile(fname);
    384     if ( metaFile )
    385     {
    386         static vector<string> argStrings;
    387         static std::vector<char const*> metafile_argv; // Static for program scope, const to ensure c_str() pointers remain valid        
    388 
    389         // Read file contents
    390         stringstream metaFileBuffer;
    391         metaFileBuffer << metaFile.rdbuf();
    392         metaFile.close();
    393 
    394         // Split strings on spaces/newlines
    395         string argEntry;
    396         argStrings.clear();
    397         while (metaFileBuffer >> argEntry) {
    398             argStrings.push_back(argEntry);
    399         }
    400 
    401         // Build argv style array
    402         int metafile_argc = static_cast<int>(argStrings.size());
    403         metafile_argv.clear();
    404         metafile_argv.reserve(metafile_argc + 1); // +1 for null terminator entry (optional with our usage)
    405         for (const auto& s : argStrings) {
    406             metafile_argv.push_back(s.c_str());
    407         }
    408         metafile_argv.push_back(nullptr);
    409 
    410         // Append args to logged ones and then process them
    411         logArguments(ARG_SKIP_NONE, metafile_argc, metafile_argv.data(), args);
    412         if (processArguments(ARG_SKIP_NONE, metafile_argc, metafile_argv.data(), args) == EXIT_FAILURE)
    413             return EXIT_FAILURE;
    414 
    415     } else {
    416         printf("Warning: -use_metafile specified but no meta file found at: %s\n", fname.c_str());
    417     }
    418 
    419     return EXIT_SUCCESS;
    420 }
    421 
    422 
    423 int processPNG2AssetArguments(int argc, char* argv[], PNG2AssetArguments* args) {
    424 
    425     initArguments(args);
    426 
    427     if (argc < 2) {
    428         showHelp();
    429         return EXIT_SUCCESS;
    430     }
    431 
    432     //default params
    433     args->input_filename = argv[ARG_AT_INPUT_FILENAME];
    434     args->output_filename = argv[ARG_AT_INPUT_FILENAME];
    435     args->output_filename = args->output_filename.substr(0, args->output_filename.size() - 4) + ".c";
    436 
    437     logArguments(ARG_AT_INPUT_FILENAME, argc, (const char **)argv, args);
    438     if (processArguments(ARG_AFTER_INPUT_FILENAME, argc, (const char **)argv, args) == EXIT_FAILURE)
    439         return EXIT_FAILURE;
    440 
    441     if (args->use_metafile) {
    442         if (handleMetaFileArgs(args) == EXIT_FAILURE)
    443         return EXIT_FAILURE;
    444     }
    445 
    446     int slash_pos = (int)args->output_filename.find_last_of('/');
    447     if(slash_pos == -1)
    448         slash_pos = (int)args->output_filename.find_last_of('\\');
    449     int dot_pos = (int)args->output_filename.find_first_of('.', slash_pos == -1 ? 0 : slash_pos);
    450 
    451     args->output_filename_h = args->output_filename.substr(0, dot_pos) + ".h";
    452     args->output_filename_bin = args->output_filename.substr(0, dot_pos) + "_map.bin";
    453     args->output_filename_attributes_bin = args->output_filename.substr(0, dot_pos) + "_map_attributes.bin";
    454     args->output_filename_tiles_bin = args->output_filename.substr(0, dot_pos) + "_tiles.bin";
    455     args->output_filename_palettes_bin = args->output_filename.substr(0, dot_pos) + "_palettes.bin";
    456     args->data_name = args->output_filename.substr(slash_pos + 1, dot_pos - 1 - slash_pos);
    457     replace(args->data_name.begin(), args->data_name.end(), '-', '_');
    458 
    459     if ((args->area_specified == true) && (args->bank == BANK_NUM_UNSET)) {
    460         printf("Error: \"-area\" specified but bank number is missing. A bank number is required, use \"-b\"\n");
    461         return EXIT_FAILURE;
    462     }
    463 
    464     if((args->output_binary) && (args->export_as_map == false)) {
    465         printf("Error: \"-bin\" export mode only works when \"-map\" is enabled\n");
    466         return EXIT_FAILURE;
    467     }
    468 
    469     return EXIT_SUCCESS;
    470 }
    471 

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