cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

png2asset.cpp (41175B)


      1#include <vector>
      2#include <string>
      3#include <algorithm>
      4#include <cstring>
      5#include <set>
      6#include <stdio.h>
      7#include <fstream>
      8#include "lodepng.h"
      9
     10using namespace std;
     11
     12int decodePNG(vector<unsigned char>& out_image, unsigned long& image_width, unsigned long& image_height, const unsigned char* in_png, size_t in_size, bool convert_to_rgba32 = true);
     13void loadFile(vector<unsigned char>& buffer, const std::string& filename);
     14
     15#define BIT(VALUE, INDEX) (1 & ((VALUE) >> (INDEX)))
     16
     17bool export_as_map = false;
     18bool use_map_attributes = false;
     19size_t pal_size;
     20#define TILE_W 8
     21int tile_h;
     22int bpp = 2;
     23unsigned int tile_origin = 0; // Default to no tile index offset
     24
     25struct Tile
     26{
     27	vector< unsigned char > data;
     28	unsigned char pal;
     29
     30	Tile(size_t size = 0) : data(size), pal(0) {}
     31	bool operator==(const Tile& t) const
     32	{
     33		return data == t.data && pal == t.pal;
     34	}
     35
     36	const Tile& operator=(const Tile& t)
     37	{
     38		data = t.data;
     39		pal = t.pal;
     40		return *this;
     41	}
     42
     43	enum PackMode {
     44		GB,
     45		SGB,
     46		SMS,
     47	};
     48
     49	vector< unsigned char > GetPackedData(PackMode pack_mode) {
     50		vector< unsigned char > ret(tile_h * bpp, 0);
     51		if(pack_mode == GB) {
     52			for(int j = 0; j < tile_h; ++j) {
     53				for(int i = 0; i < 8; ++ i) {
     54					unsigned char col = data[8 * j + i];
     55					ret[j * 2    ] |= BIT(col, 0) << (7 - i);
     56					ret[j * 2 + 1] |= BIT(col, 1) << (7 - i);
     57				}
     58			}
     59		}
     60		else if(pack_mode == SGB)
     61		{
     62			for(int j = 0; j < tile_h; ++j) {
     63				for(int i = 0; i < 8; ++ i) {
     64					unsigned char col = data[8 * j + i];
     65					ret[j * 2    ] |= BIT(col, 0) << (7 - i);
     66					ret[j * 2 + 1] |= BIT(col, 1) << (7 - i);
     67					ret[(tile_h + j) * 2    ] |= BIT(col, 2) << (7 - i);
     68					ret[(tile_h + j) * 2 + 1] |= BIT(col, 3) << (7 - i);
     69				}
     70			}
     71		}
     72		else if(pack_mode == SMS)
     73		{
     74			for(int j = 0; j < tile_h; ++j) {
     75				for(int i = 0; i < 8; ++ i) {
     76					unsigned char col = data[8 * j + i];
     77					ret[j * 4    ] |= BIT(col, 0) << (7 - i);
     78					ret[j * 4 + 1] |= BIT(col, 1) << (7 - i);
     79					ret[j * 4 + 2] |= BIT(col, 2) << (7 - i);
     80					ret[j * 4 + 3] |= BIT(col, 3) << (7 - i);
     81				}
     82			}
     83		}
     84		return ret;
     85	}
     86};
     87
     88struct PNGImage
     89{
     90	vector< unsigned char > data; //data in indexed format
     91	unsigned int w;
     92	unsigned int h;
     93
     94	size_t palettesize; //number of palette colors
     95	unsigned char* palette; //palette colors in RGBA (1 color == 4 bytes)
     96
     97	unsigned char GetGBColor(int x, int y)
     98	{
     99		return data[w * y + x] % pal_size;
    100	}
    101
    102	bool ExtractGBTile(int x, int y, int tile_h, Tile& tile)
    103	{
    104		tile.pal = (export_as_map && !use_map_attributes) ? data[w * y + x] >> 2 : 0; //Set the palette to 0 when pals are not stored in tiles to allow tiles to be equal even when their palettes are different
    105
    106		bool all_zero = true;
    107		for(int j = 0; j < tile_h; ++ j)
    108		{
    109			for(int i = 0; i < 8; ++i)
    110			{
    111				unsigned char color_idx = GetGBColor(x + i, y + j);
    112				tile.data[j * 8 + i] = color_idx;
    113				all_zero = all_zero && (color_idx == 0);
    114			}
    115		}
    116		return !all_zero;
    117	}
    118};
    119
    120struct MTTile
    121{
    122	char offset_x;
    123	char offset_y;
    124	unsigned char offset_idx;
    125	unsigned char props;
    126
    127	MTTile(char offset_x, char offset_y, unsigned char offset_idx, unsigned char props) : offset_x(offset_x), offset_y(offset_y), offset_idx(offset_idx), props(props) {}
    128	MTTile() : offset_x(0), offset_y(0), offset_idx(0), props(0) {}
    129};
    130string source_tileset;
    131unsigned int extra_tile_count = 0;
    132unsigned int source_palette_count = 0;
    133unsigned int source_tileset_size = 0;
    134bool includeTileData = true;
    135bool includedMapOrMetaspriteData = true;
    136PNGImage source_tileset_image;
    137bool use_source_tileset = false;
    138bool keep_duplicate_tiles = false;
    139
    140typedef vector< MTTile > MetaSprite;
    141vector< Tile > tiles;
    142vector<	MetaSprite > sprites;
    143vector< unsigned char > map;
    144vector< unsigned char > map_attributes;
    145PNGImage image;
    146int props_default = 0x00;  // Default Sprite props has no attributes enabled
    147bool use_structs = false;
    148bool flip_tiles = true;
    149Tile::PackMode pack_mode = Tile::GB;
    150
    151Tile FlipH(const Tile& tile)
    152{
    153	Tile ret;
    154	for(int j = (int)tile.data.size() - 8; j >= 0; j -= 8)
    155	{
    156		for(int i = 0; i < 8; ++ i)
    157		{
    158			ret.data.push_back(tile.data[j + i]);
    159		}
    160	}
    161	ret.pal = tile.pal;
    162	return ret;
    163}
    164
    165Tile FlipV(const Tile& tile)
    166{
    167	Tile ret;
    168	for(int j = 0; j < (int)tile.data.size(); j += 8)
    169	{
    170		for(int i = 7; i >= 0; -- i)
    171		{
    172			ret.data.push_back(tile.data[j + i]);
    173		}
    174	}
    175	ret.pal = tile.pal;
    176	return ret;
    177}
    178
    179bool FindTile(const Tile& t, size_t& idx, unsigned char& props)
    180{
    181	vector< Tile >::iterator it;
    182	it = find(tiles.begin(), tiles.end(), t);
    183	if(it != tiles.end())
    184	{
    185		idx = (size_t)(it - tiles.begin());
    186		props = props_default;
    187		return true;
    188	}
    189
    190	if(flip_tiles)
    191	{
    192		Tile tile = FlipV(t);
    193		it = find(tiles.begin(), tiles.end(), tile);
    194		if(it != tiles.end())
    195		{
    196			idx = (size_t)(it - tiles.begin());
    197			props = props_default | (1 << 5);
    198			return true;
    199		}
    200
    201		tile = FlipH(tile);
    202		it = find(tiles.begin(), tiles.end(), tile);
    203		if(it != tiles.end())
    204		{
    205			idx = (size_t)(it - tiles.begin());
    206			props = props_default | (1 << 5) | (1 << 6);
    207			return true;
    208		}
    209
    210		tile = FlipV(tile);
    211		it = find(tiles.begin(), tiles.end(), tile);
    212		if(it != tiles.end())
    213		{
    214			idx = (size_t)(it - tiles.begin());
    215			props = props_default | (1 << 6);
    216			return true;
    217		}
    218	}
    219
    220	return false;
    221}
    222
    223void GetMetaSprite(int _x, int _y, int _w, int _h, int pivot_x, int pivot_y)
    224{
    225	int last_x = _x + pivot_x;
    226	int last_y = _y + pivot_y;
    227
    228	sprites.push_back(MetaSprite());
    229	MetaSprite& mt_sprite = sprites.back();
    230	for(int y = _y; y < _y + _h && y < (int)image.h; y += tile_h)
    231	{
    232		for(int x = _x; x < _x + _w && x < (int)image.w; x += 8)
    233		{
    234			Tile tile(tile_h * 8);
    235			if (image.ExtractGBTile(x, y, tile_h, tile))
    236			{
    237				size_t idx;
    238				unsigned char props;
    239				unsigned char pal_idx = image.data[y * image.w + x] >> 2; //We can pick the palette from the first pixel of this tile
    240
    241				if(keep_duplicate_tiles)
    242				{
    243					tiles.push_back(tile);
    244					idx = tiles.size() - 1;
    245					props = props_default;
    246				}
    247				else
    248				{
    249					if(!FindTile(tile, idx, props))
    250					{
    251						if (use_source_tileset) {
    252							printf("found a tile not in the source tileset at %d,%d. The target tileset has %d extra tiles.\n", x, y,extra_tile_count+1);
    253							extra_tile_count++;
    254							includeTileData = true;
    255						}
    256						tiles.push_back(tile);
    257						idx = tiles.size() - 1;
    258						props = props_default;
    259					}
    260				}
    261
    262				props |= pal_idx;
    263
    264				if(tile_h == 16)
    265					idx *= 2;
    266
    267				mt_sprite.push_back(MTTile(x - last_x, y - last_y, (unsigned char)idx, props));
    268
    269				last_x = x;
    270				last_y = y;
    271			}
    272		}
    273	}
    274}
    275
    276void GetMap()
    277{
    278	for(int y = 0; y < (int)image.h; y += 8)
    279	{
    280		for(int x = 0; x < (int)image.w; x += 8)
    281		{
    282			Tile tile(8 * 8);
    283			image.ExtractGBTile(x, y, 8, tile);
    284
    285			size_t idx;
    286			unsigned char props;
    287
    288			if(keep_duplicate_tiles)
    289			{
    290				tiles.push_back(tile);
    291				idx = tiles.size() - 1;
    292				props = props_default;
    293			}
    294			else
    295			{
    296				if(!FindTile(tile, idx, props))
    297				{
    298					if (use_source_tileset) {
    299						printf("found a tile not in the source tileset at %d,%d. The target tileset has %d extra tiles.\n", x, y, extra_tile_count + 1);
    300						extra_tile_count++;
    301						includeTileData = true;
    302					}
    303					tiles.push_back(tile);
    304					idx = tiles.size() - 1;
    305					props = props_default;
    306
    307					if(tiles.size() > 256 && pack_mode != Tile::SMS)
    308						printf("Warning: found more than 256 tiles on x:%d,y:%d\n", x, y);
    309
    310					if(((tiles.size() + tile_origin) > 256) && (pack_mode != Tile::SMS))
    311						printf("Warning: tile count (%d) + tile origin (%d) exceeds 256 at x:%d,y:%d\n", (unsigned int)tiles.size(), tile_origin, x, y);
    312				}
    313			}
    314
    315			map.push_back((unsigned char)idx + tile_origin);
    316
    317			if(use_map_attributes)
    318			{
    319				unsigned char pal_idx = image.data[y * image.w + x] >> bpp; //We can pick the palette from the first pixel of this tile
    320				if(pack_mode == Tile::SGB)
    321				{
    322					props = props << 1; //Mirror flags in SGB are on bit 7
    323					props |= (pal_idx + 4) << 2; //Pals are in bits 2,3,4 and need to go from 4 to 7
    324					map.push_back(props); //Also they are stored within the map tiles
    325				}
    326				else if(pack_mode == Tile::SMS)
    327				{
    328					props = props >> 4;
    329					if(idx > 255)
    330						props |= 1;
    331					map.push_back(props);
    332				}
    333				else
    334				{
    335					props |= pal_idx;
    336					map_attributes.push_back(props);
    337				}
    338			}
    339
    340		}
    341	}
    342}
    343//Functor to compare entries in SetPal
    344struct CmpIntColor {
    345  bool operator() (unsigned int const& c1, unsigned int const& c2) const
    346  {
    347    unsigned char* c1_ptr = (unsigned char*)&c1;
    348		unsigned char* c2_ptr = (unsigned char*)&c2;
    349
    350		//Compare alpha first, transparent color is considered smaller
    351		if(c1_ptr[0] != c2_ptr[0])
    352		{
    353			return c1_ptr[0] < c2_ptr[0];
    354		}
    355		else
    356		{
    357			unsigned int lum_1 = (unsigned int)(c1_ptr[3] * 0.299f + c1_ptr[2] * 0.587f + c1_ptr[1] * 0.114f);
    358			unsigned int lum_2 = (unsigned int)(c2_ptr[3] * 0.299f + c2_ptr[2] * 0.587f + c2_ptr[1] * 0.114f);
    359			return lum_1 > lum_2;
    360		}
    361  }
    362};
    363
    364//This set will keep colors in the palette ordered based on their grayscale values to ensure they look good on DMG
    365//This assumes the palette used in DMG will be 00 01 10 11
    366typedef set< unsigned int, CmpIntColor > SetPal;
    367
    368SetPal GetPaletteColors(const PNGImage& image, int x, int y, int w, int h)
    369{
    370	SetPal ret;
    371	for(int j = y; j < (y + h); ++ j)
    372	{
    373		for(int i = x; i < (x + w); ++ i)
    374		{
    375			const unsigned char* color = &image.data[(j * image.w + i) * 4];
    376			int color_int = (color[0] << 24) | (color[1] << 16) | (color[2] << 8) | color[3];
    377			ret.insert(color_int);
    378		}
    379	}
    380
    381	for(SetPal::iterator it = ret.begin(); it != ret.end(); ++it)
    382	{
    383		if(it != ret.begin() && ((0xFF & *it) != 0xFF)) //ret.begin() should be the only one transparent
    384			printf("Warning: found more than one transparent color in tile at x:%d, y:%d of size w:%d, h:%d\n", x, y, w, h);
    385	}
    386
    387	return ret;
    388}
    389
    390unsigned int PaletteCountApplyMaxLimit(unsigned int max_palettes, unsigned int cur_palette_size)
    391{
    392	if (cur_palette_size > max_palettes)
    393	{
    394		printf("Warning: %d palettes found, truncating to %d (-max_palettes)\n", (unsigned int)cur_palette_size, (unsigned int)max_palettes);
    395		return max_palettes;
    396	}
    397	else
    398		return cur_palette_size;
    399}
    400
    401bool GetSourceTileset(bool keep_palette_order, unsigned int max_palettes, vector< SetPal >& palettes) {
    402
    403	lodepng::State sourceTilesetState;
    404	vector<unsigned char> buffer2;
    405
    406	lodepng::load_file(buffer2, source_tileset);
    407
    408
    409	if (keep_palette_order) {
    410		//Calling with keep_palette_order means
    411			//-The image is png8
    412			//-Each 4 colors define a gbc palette, the first color is the transparent one
    413			//-Each rectangle with dimension(8, tile_h) in the image has colors from one of those palettes only
    414		sourceTilesetState.info_raw.colortype = LCT_PALETTE;
    415		sourceTilesetState.info_raw.bitdepth = 8;
    416		sourceTilesetState.decoder.color_convert = false;
    417
    418			unsigned error = lodepng::decode(source_tileset_image.data, source_tileset_image.w, source_tileset_image.h, sourceTilesetState, buffer2);
    419			if (error)
    420			{
    421				printf("decoder error %s\n", lodepng_error_text(error));
    422				return false;
    423			}
    424
    425
    426		if (sourceTilesetState.info_raw.colortype != LCT_PALETTE)
    427		{
    428			printf("error: keep_palette_order only works with png8");
    429			return false;
    430		}
    431
    432		unsigned int palette_count = PaletteCountApplyMaxLimit(max_palettes, sourceTilesetState.info_raw.palettesize / pal_size);
    433		source_tileset_image.palettesize = palette_count * pal_size;
    434		source_tileset_image.palette = sourceTilesetState.info_raw.palette;
    435	}
    436	else {
    437
    438		PNGImage image32;
    439		unsigned error = lodepng::decode(image32.data, image32.w, image32.h, sourceTilesetState, buffer2); //decode as 32 bit
    440		if (error)
    441		{
    442			printf("decoder error %s\n", lodepng_error_text(error));
    443			return false;
    444		}
    445
    446
    447		int* palettes_per_tile = new int[(image32.w / 8) * (image32.h / tile_h)];
    448
    449		for (unsigned int y = 0; y < image32.h; y += tile_h)
    450		{
    451			for (unsigned int x = 0; x < image32.w; x += 8)
    452			{
    453				//Get palette colors on (x, y, 8, tile_h)
    454				SetPal pal = GetPaletteColors(image32, x, y, 8, tile_h);
    455				if (pal.size() > pal_size)
    456				{
    457					printf("Error: more than %d colors found in tile at x:%d, y:%d of size w:%d, h:%d\n", (unsigned int)pal_size, x, y, 8, tile_h);
    458					return false;
    459				}
    460
    461				//Check if it matches any palettes or create a new one
    462				size_t i;
    463				for (i = 0; i < palettes.size(); ++i)
    464				{
    465					//Try to merge this palette with any of the palettes (checking if they are equal is not enough since the palettes can have less than 4 colors)
    466					SetPal merged(palettes[i]);
    467					merged.insert(pal.begin(), pal.end());
    468					if (merged.size() <= pal_size)
    469					{
    470						if (palettes[i].size() <= pal_size)
    471							palettes[i] = merged; //Increase colors with this palette (it has less than 4 colors)
    472						break; //Found palette
    473					}
    474				}
    475
    476				if (i == palettes.size())
    477				{
    478					//Palette not found, add a new one
    479					palettes.push_back(pal);
    480				}
    481
    482				palettes_per_tile[(y / tile_h) * (image32.w / 8) + (x / 8)] = i;
    483			}
    484		};
    485
    486		//Create the indexed image
    487		source_tileset_image.data.clear();
    488		source_tileset_image.w = image32.w;
    489		source_tileset_image.h = image32.h;
    490
    491		unsigned int palette_count = PaletteCountApplyMaxLimit(max_palettes, palettes.size());
    492
    493		source_tileset_image.palettesize = palette_count * pal_size;
    494		source_tileset_image.palette = new unsigned char[palette_count * pal_size * 4]; //pal_size colors * 4 bytes each
    495		source_palette_count = source_tileset_image.palettesize;
    496
    497		for (size_t p = 0; p < palette_count; ++p)
    498		{
    499			int* color_ptr = (int*)&source_tileset_image.palette[p * pal_size * 4];
    500
    501			//TODO: if palettes[p].size() != pal_size we should probably try to fill the gaps based on grayscale values
    502
    503			for (SetPal::iterator it = palettes[p].begin(); it != palettes[p].end(); ++it, color_ptr++)
    504			{
    505				unsigned char* c = (unsigned char*)&(*it);
    506				*color_ptr = (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3];
    507			}
    508		}
    509
    510		for (size_t y = 0; y < image32.h; ++y)
    511		{
    512			for (size_t x = 0; x < image32.w; ++x)
    513			{
    514				unsigned char* c32ptr = &image32.data[(image32.w * y + x) * 4];
    515				int color32 = (c32ptr[0] << 24) | (c32ptr[1] << 16) | (c32ptr[2] << 8) | c32ptr[3];
    516				unsigned char palette = palettes_per_tile[(y / tile_h) * (image32.w / 8) + (x / 8)];
    517				unsigned char index = std::distance(palettes[palette].begin(), palettes[palette].find(color32));
    518				source_tileset_image.data.push_back((palette << bpp) + index);
    519			}
    520		}
    521	}
    522
    523	// We'll change the image variable
    524	// So we don't have to change any of the existing code
    525	PNGImage temp = image;
    526	image = source_tileset_image;
    527	use_source_tileset = false;
    528	GetMap();
    529
    530	// Our source tileset shouldn't build the map arrays up
    531	// Clear anything from the previous 'GetMap' call
    532	map.clear();
    533	map_attributes.clear();
    534	use_source_tileset = true;
    535
    536	// Change the image variable back
    537	image = temp;
    538
    539	source_tileset_size = tiles.size();
    540
    541	printf("Got %d tiles from the source tileset.\n", (unsigned int)tiles.size());
    542	printf("Got %d palettes from the source tileset.\n", (unsigned int)source_tileset_image.palettesize/4);
    543
    544	return true;
    545
    546}
    547
    548
    549void Export(const PNGImage& image, const char* path)
    550{
    551	lodepng::State state;
    552	state.info_png.color.colortype = LCT_PALETTE;
    553	state.info_png.color.bitdepth = 8;
    554	state.info_raw.colortype = LCT_PALETTE;
    555	state.info_raw.bitdepth = 8;
    556	state.encoder.auto_convert = 0; //we specify ourselves exactly what output PNG color mode we want
    557
    558#define ADD_PALETTE(R, G, B, A) lodepng_palette_add(&state.info_png.color, R, G, B, A); lodepng_palette_add(&state.info_raw, R, G, B, A)
    559	for(size_t p = 0; p < image.palettesize; ++ p)
    560	{
    561		unsigned char* c = &image.palette[p * 4];
    562		ADD_PALETTE(c[0], c[1], c[2], c[3]);
    563	}
    564
    565	std::vector<unsigned char> buffer;
    566	lodepng::encode(buffer, image.data, image.w, image.h, state);
    567	lodepng::save_file(buffer, path);
    568}
    569
    570int main(int argc, char* argv[])
    571{
    572	if (argc < 2)
    573	{
    574		printf("usage: png2asset    <file>.png [options]\n");
    575		printf("-c                  ouput file (default: <png file>.c)\n");
    576		printf("-sw <width>         metasprites width size (default: png width)\n");
    577		printf("-sh <height>        metasprites height size (default: png height)\n");
    578		printf("-sp <props>         change default for sprite OAM property bytes (in hex) (default: 0x00)\n");
    579		printf("-px <x coord>       metasprites pivot x coordinate (default: metasprites width / 2)\n");
    580		printf("-py <y coord>       metasprites pivot y coordinate (default: metasprites height / 2)\n");
    581		printf("-pw <width>         metasprites collision rect widht (default: metasprites width)\n");
    582		printf("-ph <height>        metasprites collision rect height (default: metasprites height)\n");
    583		printf("-spr8x8             use SPRITES_8x8 (default: SPRITES_8x16)\n");
    584		printf("-spr8x16            use SPRITES_8x16 (default: SPRITES_8x16)\n");
    585		printf("-b <bank>           bank (default 0)\n");
    586		printf("-keep_palette_order use png palette\n");
    587		printf("-noflip             disable tile flip\n");
    588		printf("-map                Export as map (tileset + bg)\n");
    589		printf("-use_map_attributes Use CGB BG Map attributes (default: palettes are stored for each tile in a separate array)\n");
    590		printf("-use_structs        Group the exported info into structs (default: false) (used by ZGB Game Engine)\n");
    591		printf("-bpp                bits per pixel: 2, 4 (default: 2)\n");
    592		printf("-max_palettes       max number of palettes allowed (default: 8)\n");
    593		printf("                    (note: max colors = max_palettes x num colors per palette)\n");
    594		printf("-pack_mode          gb, sgb or sms (default: gb)\n");
    595		printf("-tile_origin        tile index offset for maps (default: 0)\n");
    596
    597		printf("-tiles_only         export tile data only\n");
    598		printf("-maps_only          export map tilemap only\n");
    599		printf("-metasprites_only   export metasprite descriptors only\n");
    600		printf("-source_tileset     use source tileset (image with common tiles)\n");
    601		printf("-keep_duplicate_tiles   do not remove duplicate tiles (default: not enabled)\n");
    602
    603		printf("-bin                export to binary format\n");
    604		printf("-transposed         export transposed (column-by-column instead of row-by-row)\n");
    605		return 0;
    606	}
    607
    608	//default params
    609	int sprite_w = 0;
    610	int sprite_h = 0;
    611	int pivot_x = 0xFFFFFF;
    612	int pivot_y = 0xFFFFFF;
    613	int pivot_w = 0xFFFFFF;
    614	int pivot_h = 0xFFFFFF;
    615	tile_h = 16;
    616	string output_filename = argv[1];
    617	output_filename = output_filename.substr(0, output_filename.size() - 4) + ".c";
    618	int bank = 0;
    619	bool keep_palette_order = false;
    620	bool output_binary = false;
    621	bool output_transposed = false;
    622	size_t max_palettes = 8;
    623
    624	//Parse argv
    625	for(int i = 2; i < argc; ++i)
    626	{
    627		if(!strcmp(argv[i], "-sw"))
    628		{
    629			sprite_w = atoi(argv[++ i]);
    630		}
    631		else if(!strcmp(argv[i], "-sh"))
    632		{
    633			sprite_h = atoi(argv[++ i]);
    634		}
    635		else if(!strcmp(argv[i], "-sp"))
    636		{
    637			props_default = strtol(argv[++i], NULL, 16);
    638		}
    639		if(!strcmp(argv[i], "-px"))
    640		{
    641			pivot_x = atoi(argv[++ i]);
    642		}
    643		else if(!strcmp(argv[i], "-py"))
    644		{
    645			pivot_y = atoi(argv[++ i]);
    646		}
    647		else if(!strcmp(argv[i], "-pw"))
    648		{
    649			pivot_w = atoi(argv[++ i]);
    650		}
    651		else if(!strcmp(argv[i], "-ph"))
    652		{
    653			pivot_h = atoi(argv[++ i]);
    654		}
    655		else if(!strcmp(argv[i], "-spr8x8"))
    656		{
    657			tile_h = 8;
    658		}
    659		else if(!strcmp(argv[i],"-spr8x16"))
    660		{
    661			tile_h = 16;
    662		}
    663		else if(!strcmp(argv[i], "-c"))
    664		{
    665			output_filename = argv[++ i];
    666		}
    667		else if(!strcmp(argv[i], "-b"))
    668		{
    669			bank = atoi(argv[++ i]);
    670		}
    671		else if(!strcmp(argv[i], "-keep_palette_order"))
    672		{
    673			keep_palette_order = true;
    674		}
    675		else if(!strcmp(argv[i], "-noflip"))
    676		{
    677			flip_tiles = false;
    678		}
    679		else if(!strcmp(argv[i], "-map"))
    680		{
    681			export_as_map = true;
    682		}
    683		else if(!strcmp(argv[i], "-use_map_attributes"))
    684		{
    685			use_map_attributes = true;
    686		}
    687		else if(!strcmp(argv[i], "-use_structs"))
    688		{
    689			use_structs = true;
    690		}
    691		else if(!strcmp(argv[i], "-bpp"))
    692		{
    693			bpp = atoi(argv[++ i]);
    694		}
    695		else if(!strcmp(argv[i], "-max_palettes"))
    696		{
    697			max_palettes = atoi(argv[++ i]);
    698			if (max_palettes == 0)
    699			{
    700				printf("-max_palettes must be larger than zero\n");
    701				return 1;
    702			}
    703		}
    704		else if(!strcmp(argv[i], "-pack_mode"))
    705		{
    706			std::string pack_mode_str = argv[++ i];
    707			if     (pack_mode_str == "gb")  pack_mode = Tile::GB;
    708			else if(pack_mode_str == "sgb") pack_mode = Tile::SGB;
    709			else if(pack_mode_str == "sms") pack_mode = Tile::SMS;
    710			else
    711			{
    712				printf("-pack_mode must be one of gb, sgb or sms\n");
    713				return 1;
    714			}
    715		}
    716		else if(!strcmp(argv[i], "-tile_origin"))
    717		{
    718			tile_origin = atoi(argv[++ i]);
    719		}
    720		else if (!strcmp(argv[i], "-maps_only") || !strcmp(argv[i], "-metasprites_only"))
    721		{
    722			includeTileData = false;
    723		}
    724		else if (!strcmp(argv[i], "-tiles_only"))
    725		{
    726			includedMapOrMetaspriteData = false;
    727		}
    728		else if (!strcmp(argv[i], "-keep_duplicate_tiles"))
    729		{
    730			keep_duplicate_tiles = true;
    731		}
    732		else if (!strcmp(argv[i], "-source_tileset"))
    733		{
    734			use_source_tileset = true;
    735			includeTileData = false;
    736			source_tileset = argv[++i];
    737		}
    738		else if (!strcmp(argv[i], "-bin"))
    739		{
    740			output_binary = true;
    741		}
    742		else if (!strcmp(argv[i], "-transposed"))
    743		{
    744			output_transposed = true;
    745		}
    746	}
    747
    748	pal_size = 1 << bpp;
    749
    750	if(export_as_map)
    751		tile_h = 8; //Force tiles_h to 8 on maps
    752
    753	int slash_pos = (int)output_filename.find_last_of('/');
    754	if(slash_pos == -1)
    755		slash_pos = (int)output_filename.find_last_of('\\');
    756	int dot_pos = (int)output_filename.find_first_of('.', slash_pos == -1 ? 0 : slash_pos);
    757
    758	string output_filename_h = output_filename.substr(0, dot_pos) + ".h";
    759	string output_filename_bin = output_filename.substr(0, dot_pos) + "_map.bin";
    760	string output_filename_attributes_bin = output_filename.substr(0, dot_pos) + "_map_attributes.bin";
    761	string output_filename_tiles_bin = output_filename.substr(0, dot_pos) + "_tiles.bin";
    762	string data_name = output_filename.substr(slash_pos + 1, dot_pos - 1 - slash_pos);
    763	replace(data_name.begin(), data_name.end(), '-', '_');
    764
    765	// This was moved from outside the upcoming else statement when not using keep_palette_order
    766	// So the 'GetSourceTileset' function can pre-populate it from the source tileset
    767	vector< SetPal > palettes;
    768
    769	if (use_source_tileset) {
    770
    771		if (!GetSourceTileset(keep_palette_order, max_palettes, palettes)) {
    772			return 1;
    773		}
    774	}
    775
    776
    777	//load and decode png
    778	vector<unsigned char> buffer;
    779	lodepng::load_file(buffer, argv[1]);
    780	lodepng::State state;
    781	if(keep_palette_order)
    782	{
    783		//Calling with keep_palette_order means
    784		//-The image is png8
    785		//-For CGB: Each 4 colors define a gbc palette, the first color is the transparent one
    786		//-Each rectangle with dimension(8, tile_h) in the image has colors from one of those palettes only
    787		state.info_raw.colortype = LCT_PALETTE;
    788		state.info_raw.bitdepth = 8;
    789		state.decoder.color_convert = false;
    790		unsigned error = lodepng::decode(image.data, image.w, image.h, state, buffer);
    791		if(error)
    792		{
    793			printf("decoder error %s\n", lodepng_error_text(error));
    794			return 1;
    795		}
    796
    797		if(state.info_raw.colortype != LCT_PALETTE)
    798		{
    799			printf("error: keep_palette_order only works with png8");
    800			return 1;
    801		}
    802
    803		unsigned int palette_count = PaletteCountApplyMaxLimit(max_palettes, state.info_raw.palettesize / pal_size);
    804		image.palettesize = palette_count * pal_size;
    805		image.palette = state.info_raw.palette;
    806
    807		if (use_source_tileset) {
    808
    809			// Make sure these two values match when keeping palette order
    810			if (image.palettesize != source_tileset_image.palettesize) {
    811
    812				printf("error: The number of color palette's for your source tileset (%d) and target image (%d) do not match.", (unsigned int)source_tileset_image.palettesize, (unsigned int)image.palettesize);
    813				return 1;
    814			}
    815
    816			size_t size = max(image.palettesize, source_tileset_image.palettesize);
    817
    818			// Make sure these two values match when keeping palette order
    819			if (memcmp(image.palette, source_tileset_image.palette, size) != 0) {
    820
    821				printf("error: The palette's for your source tileset and target image do not match.");
    822				return 1;
    823			}
    824		}
    825	}
    826	else
    827	{
    828		PNGImage image32;
    829		unsigned error = lodepng::decode(image32.data, image32.w, image32.h, state, buffer); //decode as 32 bit
    830		if(error)
    831		{
    832			printf("decoder error %s\n", lodepng_error_text(error));
    833			return 1;
    834		}
    835
    836		// Validate image dimensions
    837		if( ((image32.w % TILE_W) != 0) || ((image32.h % tile_h) != 0) )
    838		{
    839			printf("Error: Image size %d x %d isn't an even multiple of tile size %d x %d\n", image32.w, image32.h, TILE_W, tile_h);
    840			return 1;
    841		}
    842
    843		int* palettes_per_tile = new int[(image32.w / 8) * (image32.h /tile_h)];
    844		for(unsigned int y = 0; y < image32.h; y += tile_h)
    845		{
    846			for(unsigned int x = 0; x < image32.w; x += 8)
    847			{
    848				//Get palette colors on (x, y, 8, tile_h)
    849				SetPal pal = GetPaletteColors(image32, x, y, 8, tile_h);
    850				if(pal.size() > pal_size)
    851				{
    852					printf("Error: more than %d colors found in tile at x:%d, y:%d of size w:%d, h:%d\n", (unsigned int)pal_size, x, y, 8, tile_h);
    853					return 1;
    854				}
    855
    856				//Check if it matches any palettes or create a new one
    857				size_t i;
    858				for(i = 0; i < palettes.size(); ++i)
    859				{
    860					//Try to merge this palette wit any of the palettes (checking if they are equal is not enough since the palettes can have less than 4 colors)
    861					SetPal merged(palettes[i]);
    862					merged.insert(pal.begin(), pal.end());
    863					if(merged.size() <= pal_size)
    864					{
    865						if(palettes[i].size() <= pal_size)
    866							palettes[i] = merged; //Increase colors with this palette (it has less than 4 colors)
    867						break; //Found palette
    868					}
    869				}
    870
    871				if(i == palettes.size())
    872				{
    873					//Palette not found, add a new one
    874					palettes.push_back(pal);
    875				}
    876
    877				palettes_per_tile[(y / tile_h) * (image32.w / 8) + (x / 8)] = i;
    878			}
    879		}
    880
    881		//Create the indexed image
    882		image.data.clear();
    883		image.w = image32.w;
    884		image.h = image32.h;
    885
    886		unsigned int palette_count = PaletteCountApplyMaxLimit(max_palettes, palettes.size());
    887
    888		image.palettesize = palette_count * pal_size;
    889		image.palette = new unsigned char[palette_count * pal_size * 4]; //pal_size colors * 4 bytes each
    890
    891		// If we are using a sourcetileset and have more palettes than it defines
    892		if (use_source_tileset && image.palettesize > source_palette_count) {
    893			printf("Found %d extra palette(s) for target tilemap.\n", (unsigned int)(image.palettesize - source_palette_count) / 4);
    894		}
    895		for(size_t p = 0; p < palette_count; ++p)
    896		{
    897			int *color_ptr = (int*)&image.palette[p * pal_size * 4];
    898
    899			//TODO: if palettes[p].size() != pal_size we should probably try to fill the gaps based on grayscale values
    900
    901			for(SetPal::iterator it = palettes[p].begin(); it != palettes[p].end(); ++ it, color_ptr ++)
    902			{
    903				unsigned char* c = (unsigned char*)&(*it);
    904				*color_ptr = (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3];
    905			}
    906		}
    907
    908		for(size_t y = 0; y < image32.h; ++ y)
    909		{
    910			for(size_t x = 0; x < image32.w; ++x)
    911			{
    912				unsigned char* c32ptr = &image32.data[(image32.w * y + x) * 4];
    913				int color32 = (c32ptr[0] << 24) | (c32ptr[1] << 16) | (c32ptr[2] << 8) | c32ptr[3];
    914				unsigned char palette = palettes_per_tile[(y / tile_h) * (image32.w / 8) + (x / 8)];
    915				unsigned char index = std::distance(palettes[palette].begin(), palettes[palette].find(color32));
    916				image.data.push_back((palette << bpp) + index);
    917			}
    918		}
    919
    920		//Test: output png to see how it looks
    921		//Export(image, "temp.png");
    922	}
    923
    924	if(sprite_w == 0) sprite_w = (int)image.w;
    925	if(sprite_h == 0) sprite_h = (int)image.h;
    926	if(pivot_x == 0xFFFFFF) pivot_x = sprite_w / 2;
    927	if(pivot_y == 0xFFFFFF) pivot_y = sprite_h / 2;
    928	if(pivot_w == 0xFFFFFF) pivot_w = sprite_w;
    929	if(pivot_h == 0xFFFFFF) pivot_h = sprite_h;
    930
    931	if(export_as_map)
    932	{
    933		//Extract map
    934		GetMap();
    935	}
    936	else
    937	{
    938		//Extract metasprites
    939		for(int y = 0; y < (int)image.h; y += sprite_h)
    940		{
    941			for(int x = 0; x < (int)image.w; x += sprite_w)
    942			{
    943				GetMetaSprite(x, y, sprite_w, sprite_h, pivot_x, pivot_y);
    944			}
    945		}
    946	}
    947
    948	//Output .h FILE
    949	FILE* file;
    950	if(!output_binary||!export_as_map){
    951		file=fopen(output_filename_h.c_str(), "w");
    952		if (!file) {
    953			printf("Error writing file");
    954			return 1;
    955		}
    956
    957		fprintf(file, "//AUTOGENERATED FILE FROM png2asset\n");
    958		fprintf(file, "#ifndef METASPRITE_%s_H\n", data_name.c_str());
    959		fprintf(file, "#define METASPRITE_%s_H\n", data_name.c_str());
    960		fprintf(file, "\n");
    961		fprintf(file, "#include <stdint.h>\n");
    962		fprintf(file, "#include <gbdk/platform.h>\n");
    963		fprintf(file, "#include <gbdk/metasprites.h>\n");
    964		fprintf(file, "\n");
    965		if(use_structs)
    966		{
    967			if(export_as_map)
    968			{
    969				fprintf(file, "#include \"TilesInfo.h\"\n");
    970				fprintf(file, "#include \"MapInfo.h\"\n");
    971				fprintf(file, "\n");
    972				fprintf(file, "extern const struct TilesInfo %s_tiles_info;\n", data_name.c_str());
    973				fprintf(file, "extern const struct MapInfo %s;\n", data_name.c_str());
    974			}
    975			else
    976			{
    977				fprintf(file, "#include \"MetaSpriteInfo.h\"\n");
    978				fprintf(file, "\n");
    979				fprintf(file, "extern const struct MetaSpriteInfo %s;\n", data_name.c_str());
    980			}
    981		}
    982		else
    983		{
    984			fprintf(file, "#define %s_TILE_ORIGIN %d\n", data_name.c_str(), tile_origin);
    985			fprintf(file, "#define %s_TILE_H %d\n", data_name.c_str(), tile_h);
    986			fprintf(file, "#define %s_WIDTH %d\n",  data_name.c_str(), sprite_w);
    987			fprintf(file, "#define %s_HEIGHT %d\n", data_name.c_str(), sprite_h);
    988			fprintf(file, "#define %s_TILE_COUNT %d\n", data_name.c_str(), ((unsigned int)tiles.size() - source_tileset_size) * (tile_h >> 3));
    989			fprintf(file, "#define %s_PALETTE_COUNT %d\n", data_name.c_str(), (unsigned int)image.palettesize / 4);
    990
    991			if (includedMapOrMetaspriteData) {
    992
    993				if(export_as_map)
    994				{
    995					fprintf(file, "#define %s_MAP_ATTRIBUTES ",  data_name.c_str());
    996					if(use_map_attributes && map_attributes.size())
    997						fprintf(file, "%s_map_attributes\n", data_name.c_str());
    998					else
    999						fprintf(file, "0\n");
   1000
   1001					fprintf(file, "#define %s_TILE_PALS ",  data_name.c_str());
   1002					if(use_map_attributes)
   1003						fprintf(file, "0\n");
   1004					else
   1005						fprintf(file, "%s_tile_pals\n", data_name.c_str());
   1006				}
   1007				else
   1008				{
   1009					fprintf(file, "#define %s_PIVOT_X %d\n", data_name.c_str(), pivot_x);
   1010					fprintf(file, "#define %s_PIVOT_Y %d\n", data_name.c_str(), pivot_y);
   1011					fprintf(file, "#define %s_PIVOT_W %d\n", data_name.c_str(), pivot_w);
   1012					fprintf(file, "#define %s_PIVOT_H %d\n", data_name.c_str(), pivot_h);
   1013				}
   1014			}
   1015			fprintf(file, "\n");
   1016			fprintf(file, "BANKREF_EXTERN(%s)\n", data_name.c_str());
   1017			fprintf(file, "\n");
   1018
   1019			// If we are not using a source tileset, or if we have extra palettes defined
   1020			if (image.palettesize - source_palette_count > 0 || !use_source_tileset) {
   1021				fprintf(file, "extern const palette_color_t %s_palettes[%d];\n", data_name.c_str(), (unsigned int)image.palettesize - source_palette_count);
   1022			}
   1023			if (includeTileData) {
   1024				fprintf(file, "extern const uint8_t %s_tiles[%d];\n", data_name.c_str(), (unsigned int)((tiles.size() - source_tileset_size) * (8 * tile_h * bpp / 8)));
   1025			}
   1026
   1027			fprintf(file, "\n");
   1028			if (includedMapOrMetaspriteData) {
   1029				if(export_as_map)
   1030				{
   1031					fprintf(file, "extern const unsigned char %s_map[%d];\n", data_name.c_str(), (unsigned int)map.size());
   1032
   1033					if(use_map_attributes) {
   1034						if(map_attributes.size()) {
   1035							fprintf(file, "extern const unsigned char %s_map_attributes[%d];\n", data_name.c_str(), (unsigned int)map_attributes.size());
   1036						}
   1037					}
   1038					else if (includeTileData)
   1039						fprintf(file, "extern const unsigned char* %s_tile_pals[%d];\n", data_name.c_str(), (unsigned int)tiles.size());
   1040				}
   1041				else
   1042				{
   1043					fprintf(file, "extern const metasprite_t* const %s_metasprites[%d];\n", data_name.c_str(), (unsigned int)sprites.size());
   1044				}
   1045			}
   1046		}
   1047		fprintf(file, "\n");
   1048		fprintf(file, "#endif");
   1049
   1050
   1051		fclose(file);
   1052
   1053		//Output .c FILE
   1054		file = fopen(output_filename.c_str(), "w");
   1055		if(!file) {
   1056			printf("Error writing file");
   1057			return 1;
   1058		}
   1059
   1060		if (bank) fprintf(file, "#pragma bank %d\n\n", bank);
   1061
   1062		fprintf(file, "//AUTOGENERATED FILE FROM png2asset\n\n");
   1063
   1064		fprintf(file, "#include <stdint.h>\n");
   1065		fprintf(file, "#include <gbdk/platform.h>\n");
   1066		fprintf(file, "#include <gbdk/metasprites.h>\n");
   1067		fprintf(file, "\n");
   1068
   1069		fprintf(file, "BANKREF(%s)\n\n", data_name.c_str());
   1070
   1071		// Are we not using a source tileset, or do we have extra colors
   1072		if (image.palettesize - source_palette_count > 0||!use_source_tileset) {
   1073
   1074				// Subtract however many palettes we had in the source tileset
   1075				fprintf(file, "const palette_color_t %s_palettes[%d] = {\n", data_name.c_str(), (unsigned int)image.palettesize - source_palette_count);
   1076
   1077				// Offset by however many palettes we had in the source ileset
   1078				for (size_t i = source_palette_count/4; i < image.palettesize / 4; ++i)
   1079				{
   1080					if(i != 0)
   1081						fprintf(file, ",\n");
   1082					fprintf(file, "\t");
   1083
   1084					unsigned char* pal_ptr = &image.palette[i * 16];
   1085					for(int c = 0; c < 4; ++ c, pal_ptr += 4)
   1086					{
   1087						fprintf(file, "RGB8(%d, %d, %d)", pal_ptr[0], pal_ptr[1], pal_ptr[2]);
   1088						if(c != 3)
   1089							fprintf(file, ", ");
   1090					}
   1091				}
   1092				fprintf(file, "\n};\n");
   1093		}
   1094
   1095		if (includeTileData) {
   1096			fprintf(file, "\n");
   1097			fprintf(file, "const uint8_t %s_tiles[%d] = {\n", data_name.c_str(), (unsigned int)((tiles.size()-source_tileset_size) * 8 * tile_h * bpp / 8));
   1098			for (vector< Tile >::iterator it = tiles.begin()+ source_tileset_size; it != tiles.end(); ++it)
   1099			{
   1100				fprintf(file, "\t");
   1101
   1102				vector< unsigned char > packed_data = (*it).GetPackedData(pack_mode);
   1103				for(vector< unsigned char >::iterator it2 = packed_data.begin(); it2 != packed_data.end(); ++it2)
   1104				{
   1105					fprintf(file, "0x%02x", (*it2));
   1106					if((it + 1) != tiles.end() || (it2 + 1) != packed_data.end())
   1107						fprintf(file, ",");
   1108				}
   1109
   1110				if(it != tiles.end())
   1111					fprintf(file, "\n");
   1112			}
   1113			fprintf(file, "};\n\n");
   1114		}
   1115
   1116		if(includedMapOrMetaspriteData) {
   1117
   1118			if(!export_as_map)
   1119			{
   1120				for(vector< MetaSprite >::iterator it = sprites.begin(); it != sprites.end(); ++ it)
   1121				{
   1122					fprintf(file, "const metasprite_t %s_metasprite%d[] = {\n", data_name.c_str(), (int)(it - sprites.begin()));
   1123					fprintf(file, "\t");
   1124					for(MetaSprite::iterator it2 = (*it).begin(); it2 != (*it).end(); ++ it2)
   1125					{
   1126						fprintf(file, "METASPR_ITEM(%d, %d, %d, %d), ", (*it2).offset_y, (*it2).offset_x, (*it2).offset_idx, (*it2).props);
   1127					}
   1128					fprintf(file, "METASPR_TERM\n");
   1129					fprintf(file, "};\n\n");
   1130				}
   1131
   1132				fprintf(file, "const metasprite_t* const %s_metasprites[%d] = {\n\t", data_name.c_str(), (unsigned int)sprites.size());
   1133				for(vector< MetaSprite >::iterator it = sprites.begin(); it != sprites.end(); ++ it)
   1134				{
   1135					fprintf(file, "%s_metasprite%d", data_name.c_str(), (int)(it - sprites.begin()));
   1136					if(it + 1 != sprites.end())
   1137						fprintf(file, ", ");
   1138				}
   1139				fprintf(file, "\n};\n");
   1140
   1141				if(use_structs)
   1142				{
   1143					fprintf(file, "\n");
   1144					fprintf(file, "#include \"MetaSpriteInfo.h\"\n");
   1145					fprintf(file, "const struct MetaSpriteInfo %s = {\n", data_name.c_str());
   1146					fprintf(file, "\t%d, //width\n", pivot_w);
   1147					fprintf(file, "\t%d, //height\n", pivot_h);
   1148					fprintf(file, "\t%d, //num tiles\n", (unsigned int)tiles.size() * (tile_h >> 3));
   1149					fprintf(file, "\t%s_tiles, //tiles\n", data_name.c_str());
   1150					fprintf(file, "\t%d, //num palettes\n", (unsigned int)(image.palettesize / pal_size));
   1151					fprintf(file, "\t%s_palettes, //CGB palette\n", data_name.c_str());
   1152					fprintf(file, "\t%d, //num sprites\n", (unsigned int)sprites.size());
   1153					fprintf(file, "\t%s_metasprites, //metasprites\n", data_name.c_str());
   1154					fprintf(file, "};\n");
   1155				}
   1156			}
   1157			else
   1158			{
   1159				if (includeTileData) {
   1160					//Export tiles pals (if any)
   1161					if(!use_map_attributes)
   1162					{
   1163						fprintf(file, "\n");
   1164						fprintf(file, "const uint8_t %s_tile_pals[%d] = {\n\t", data_name.c_str(), (unsigned int)tiles.size()- source_tileset_size);
   1165						for(vector< Tile >::iterator it = tiles.begin()+ source_tileset_size; it != tiles.end(); ++ it)
   1166						{
   1167							if(it != tiles.begin())
   1168								fprintf(file, ", ");
   1169							fprintf(file, "%d", it->pal);
   1170						}
   1171						fprintf(file, "\n};\n");
   1172					}
   1173
   1174					if(use_structs)
   1175					{
   1176						//Export Tiles Info
   1177						fprintf(file, "\n");
   1178						fprintf(file, "#include \"TilesInfo.h\"\n");
   1179						fprintf(file, "BANKREF(%s_tiles_info)\n", data_name.c_str());
   1180						fprintf(file, "const struct TilesInfo %s_tiles_info = {\n", data_name.c_str());
   1181						fprintf(file, "\t%d, //num tiles\n", (unsigned int)tiles.size() * (tile_h >> 3));
   1182						fprintf(file, "\t%s_tiles, //tiles\n", data_name.c_str());
   1183						fprintf(file, "\t%d, //num palettes\n", (unsigned int)(image.palettesize / pal_size));
   1184						fprintf(file, "\t%s_palettes, //palettes\n", data_name.c_str());
   1185						if(!use_map_attributes)
   1186							fprintf(file, "\t%s_tile_pals, //tile palettes\n", data_name.c_str());
   1187						else
   1188							fprintf(file, "\t0 //tile palettes\n");
   1189						fprintf(file, "};\n");
   1190					}
   1191				}
   1192
   1193				//Export map
   1194				fprintf(file, "\n");
   1195				fprintf(file, "const unsigned char %s_map[%d] = {\n", data_name.c_str(), (unsigned int)map.size());
   1196				size_t line_size = map.size() / (image.h / 8);
   1197				if (output_transposed) {
   1198
   1199					for(size_t i = 0; i < line_size; ++i)
   1200					{
   1201						fprintf(file, "\t");
   1202						for (size_t j = 0; j < image.h / 8; ++j)
   1203						{
   1204							fprintf(file, "0x%02x,", map[j * line_size + i]);
   1205						}
   1206						fprintf(file, "\n");
   1207					}
   1208				}
   1209				else {
   1210
   1211					for (size_t j = 0; j < image.h / 8; ++j)
   1212					{
   1213						fprintf(file, "\t");
   1214						for (size_t i = 0; i < line_size; ++i)
   1215						{
   1216							fprintf(file, "0x%02x,", map[j * line_size + i]);
   1217						}
   1218						fprintf(file, "\n");
   1219					}
   1220				}
   1221				fprintf(file, "};\n");
   1222
   1223
   1224				//Export map attributes (if any)
   1225				if(use_map_attributes && map_attributes.size())
   1226				{
   1227					fprintf(file, "\n");
   1228					fprintf(file, "const unsigned char %s_map_attributes[%d] = {\n", data_name.c_str(), (unsigned int)map_attributes.size());
   1229					if (output_transposed) {
   1230						for (size_t i = 0; i < line_size; ++i)
   1231						{
   1232							fprintf(file, "\t");
   1233							for (size_t j = 0; j < image.h / 8; ++j)
   1234							{
   1235								fprintf(file, "0x%02x,", map_attributes[j * line_size + i]);
   1236							}
   1237							fprintf(file, "\n");
   1238						}
   1239					}
   1240					else {
   1241						for (size_t j = 0; j < image.h / 8; ++j)
   1242						{
   1243							fprintf(file, "\t");
   1244							for (size_t i = 0; i < line_size; ++i)
   1245							{
   1246								fprintf(file, "0x%02x,", map_attributes[j * line_size + i]);
   1247							}
   1248							fprintf(file, "\n");
   1249						}
   1250					}
   1251
   1252					fprintf(file, "};\n");
   1253				}
   1254
   1255				if(use_structs)
   1256				{
   1257					//Export Map Info
   1258					fprintf(file, "\n");
   1259					fprintf(file, "#include \"MapInfo.h\"\n");
   1260					fprintf(file, "BANKREF_EXTERN(%s_tiles_info)\n", data_name.c_str());
   1261					fprintf(file, "const struct MapInfo %s = {\n", data_name.c_str());
   1262					fprintf(file, "\t%s_map, //map\n", data_name.c_str());
   1263					fprintf(file, "\t%d, //with\n", image.w >> 3);
   1264					fprintf(file, "\t%d, //height\n", image.h >> 3);
   1265					if (use_map_attributes && map_attributes.size())
   1266						fprintf(file, "\t%s_map_attributes, //map attributes\n", data_name.c_str());
   1267					else
   1268						fprintf(file, "\t%s, //map attributes\n", "0");
   1269					fprintf(file, "\tBANK(%s_tiles_info), //tiles bank\n", data_name.c_str());
   1270					fprintf(file, "\t&%s_tiles_info, //tiles info\n", data_name.c_str());
   1271					fprintf(file, "};\n");
   1272				}
   1273			}
   1274		}
   1275
   1276		fclose(file);
   1277	}
   1278
   1279	// If we are exporting as a map, and binary output is desired
   1280	else if (export_as_map) {
   1281
   1282		std::ofstream mapBinaryFile, mapAttributesBinaryfile,tilesBinaryFile;
   1283		mapBinaryFile.open(output_filename_bin, std::ios_base::binary);
   1284		tilesBinaryFile.open(output_filename_tiles_bin, std::ios_base::binary);
   1285
   1286		for (vector< Tile >::iterator it = tiles.begin() + source_tileset_size; it != tiles.end(); ++it)
   1287		{
   1288
   1289			vector< unsigned char > packed_data = (*it).GetPackedData(pack_mode);
   1290			for (vector< unsigned char >::iterator it2 = packed_data.begin(); it2 != packed_data.end(); ++it2)
   1291			{
   1292
   1293				const char chars[] = { (const char)(*it2) };
   1294				tilesBinaryFile.write(chars, 1);
   1295			}
   1296
   1297		}
   1298
   1299
   1300		// Open our file for writing attributes if speciied
   1301		if (use_map_attributes)mapAttributesBinaryfile.open(output_filename_attributes_bin, std::ios_base::binary);
   1302
   1303		int columns = image.w >> 3;
   1304		int rows = image.h >> 3;
   1305
   1306		// If we want the values to be column-by-column
   1307		if (output_transposed) {
   1308
   1309			// Swap the column/row for loops
   1310			for (int column = 0; column < columns; column++) {
   1311				for (int row = 0; row < rows; ++row) {
   1312
   1313					int tile = column + row * columns;
   1314
   1315					const char mapChars[] = { (const char)map[tile] };
   1316
   1317					// Write map items column-by-column
   1318					mapBinaryFile.write(mapChars, 1);
   1319					if(use_map_attributes) {
   1320						const char mapAttributeChars[] = { (const char)map_attributes[tile] };
   1321						mapAttributesBinaryfile.write(mapAttributeChars, 1);
   1322					}
   1323				}
   1324			}
   1325		}
   1326		else {
   1327
   1328			// Write the arrays as-is, row-by-row
   1329			mapBinaryFile.write((const char*)(&map[0]), rows * columns);
   1330			if (use_map_attributes)mapAttributesBinaryfile.write((const char*)(&map_attributes[0]), rows * columns);
   1331		}
   1332
   1333		// Finalzie the files
   1334		mapBinaryFile.close();
   1335		tilesBinaryFile.close();
   1336		if (use_map_attributes)mapAttributesBinaryfile.close();
   1337
   1338	}
   1339}