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}