Downloads containing tileset.cpp

Downloads
Name Author Game Mode Rating
Tileset ExtractorFeatured Download Neobeo Utility 9.9 Download file

File preview

  1. /* tileset.cpp
  2.  *
  3.  * A solitary file, which contains
  4.  * code for extracting JJ2 tilesets
  5.  *
  6.  */
  7.  
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <png.h>
  12. #pragma pack(1)
  13.  
  14. struct TILE_Header { //262 bytes
  15.         char Copyright[180];
  16.         char Magic[4];
  17.         int Signature;
  18.         char LevelName[32];
  19.         short Version;
  20.         int FileSize;
  21.         int CRC32;
  22.         int CData1;
  23.         int UData1;
  24.         int CData2;
  25.         int UData2;
  26.         int CData3;
  27.         int UData3;
  28.         int CData4;
  29.         int UData4;
  30. } tileHeader;
  31.  
  32. struct TilesetInfo123 { //27652 bytes
  33.         int PaletteColor[256];
  34.         int TileCount;
  35.         char FastBlit[1024];
  36.         char Zeros1[1024];
  37.         int ImageAddress[1024];
  38.         int Zeros2[1024];
  39.         int TMaskAddress[1024];
  40.         int Zeros3[1024];
  41.         int MaskAddress[1024];
  42.         int FMaskAddress[1024];
  43. } tile123;
  44.  
  45. struct TilesetInfo124 { //107524 bytes
  46.         int PaletteColor[256];
  47.         int TileCount;
  48.         char FastBlit[4096];
  49.         char Zeros1[4096];
  50.         int ImageAddress[4096];
  51.         int Zeros2[4096];
  52.         int TMaskAddress[4096];
  53.         int Zeros3[4096];
  54.         int MaskAddress[4096];
  55.         int FMaskAddress[4096];
  56. } tile124;
  57.  
  58. char *ErrorMsg[] = {
  59.         "No error",
  60.         "Filename too short"
  61.         "Not a J2T file",
  62.         "Error opening file",
  63.         "Error during decompression",
  64.         "Unknown version of J2T",
  65.         "File has invalid number of tiles",
  66.         "Error during saving process"
  67. };
  68.  
  69. enum {
  70.         NOERROR = 0,
  71.         FILENAMETOOSHORT,
  72.         FILENOTJ2T,
  73.         CANNOTOPENFILE,
  74.         ERRORREADING,
  75.         ERRORUNCOMPRESSING,
  76.         UNKNOWNVERSION,
  77.         BADNUMBEROFTILES,
  78.         CANNOTSAVE,
  79. };
  80.  
  81. char *Data2, *Data4;
  82. char imgBuffer[409 * 32][10][32];
  83. int ROWS;
  84. png_bytep *rowPointers;
  85. png_color palette[256];
  86. png_color monochrome[2] = {87, 0, 203, 0, 0, 0};
  87.  
  88. /****************** End of defines/declares and start of code ******************/
  89.  
  90. //Haha, I stole this snippet from someone, and can't
  91. //remember who or where, so I'll leave it uncredited
  92. //but basically what it does is switch the bit order
  93. unsigned char ReverseBits(unsigned char b) {
  94. return (unsigned char)(((b * 0x0802LU & 0x22110LU) |
  95.         (b * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16);
  96. }
  97.  
  98. //Reads from the file, then uncompresses it into the buffer
  99. bool ReadUncompress(FILE *fileRead, char *buffer, int lenInput, int lenOutput) {
  100.         char *in = (char*)malloc(lenInput);
  101.         fread(in, 1, lenInput, fileRead);
  102.         int ret = uncompress((unsigned char*)buffer,
  103.                 (unsigned long*)&lenOutput,     (unsigned char*)in, lenInput);
  104.         free(in);
  105.         return (ret != 0);
  106. }
  107.  
  108. //Uses rows from rowPointers to save to a picture
  109. bool SavePicture(char *Arg1, char *Arg2, bool UseMonochromePalette) {
  110.         png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  111.         png_infop info_ptr = png_create_info_struct(png_ptr);
  112.         int BPP;
  113.         char strFO[256];
  114.         strcpy(strFO, Arg1);
  115.         strcat(strFO, Arg2);
  116.         FILE *fo = fopen(strFO, "wb");
  117.                 if (!fo) return true;
  118.         png_init_io(png_ptr, fo);
  119.  
  120.         //one-time switch
  121.         if (UseMonochromePalette) {
  122.                 png_set_PLTE(png_ptr, info_ptr, monochrome, 2);
  123.                 BPP = 1;
  124.         } else {
  125.                 png_set_PLTE(png_ptr, info_ptr, palette, 256);
  126.                 BPP = 8;
  127.         }
  128.  
  129.         png_set_IHDR(png_ptr, info_ptr, 320, ROWS * 32, BPP, PNG_COLOR_TYPE_PALETTE,
  130.                 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
  131.         png_set_rows(png_ptr, info_ptr, rowPointers);
  132.         png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, png_voidp_NULL);
  133.         png_write_end(png_ptr, NULL);
  134.         png_destroy_write_struct(&png_ptr, NULL);
  135.  
  136.         return false;
  137. }
  138.  
  139. //The part that extracts tilesets
  140. int ExtractTileset(char *FileName) {
  141.  
  142.         int i, j, k, l; //General-purpose local variables
  143.  
  144.         //Makes sure file is at least 5 chars int
  145.         char Extension[4];
  146.         int lenFileName = strlen(FileName);
  147.         if (lenFileName < 5) return FILENAMETOOSHORT;
  148.  
  149.         //Makes sure that filename ends with .j2t
  150.         for (i = 0; i < 4; ++i)
  151.                 Extension[i] = tolower(FileName[lenFileName - 4 + i]);
  152.         if (memcmp(Extension, ".j2t", 4))
  153.                 return FILENOTJ2T;
  154.         char BaseFileName[256] = {0};
  155.         memcpy(BaseFileName, FileName, strlen(FileName) - 4);
  156.  
  157.         //Reads the 262-byte header
  158.         FILE *fTileset = fopen(FileName, "rb");
  159.         if (!fTileset)
  160.                 return CANNOTOPENFILE;
  161.         if (!fread(&tileHeader, 1, sizeof(TILE_Header), fTileset)) {
  162.                 fclose(fTileset);
  163.                 return ERRORREADING;
  164.         }
  165.  
  166.         //Reads Data1 into info123 or info124, depending on version
  167.         if (tileHeader.Version == 0x200) {
  168.                 if (ReadUncompress(fTileset, (char *)&tile123, tileHeader.CData1, tileHeader.UData1)) {
  169.                         fclose(fTileset);
  170.                         return ERRORUNCOMPRESSING;
  171.                 }
  172.                 //copies data to tile124, to minimize switches between 1.23 and 1.24
  173.                 //there's probably an easier way to do this, by my C++ is not refined
  174.                 memcpy(&tile124.PaletteColor, &tile123.PaletteColor, 1028);
  175.                 memcpy(&tile124.FastBlit,     &tile123.FastBlit,     1024);
  176.                 memcpy(&tile124.Zeros1,       &tile123.Zeros1,       1024);
  177.                 memcpy(&tile124.ImageAddress, &tile123.ImageAddress, 4096);
  178.                 memcpy(&tile124.Zeros2,       &tile123.Zeros2,       4096);
  179.                 memcpy(&tile124.TMaskAddress, &tile123.TMaskAddress, 4096);
  180.                 memcpy(&tile124.Zeros3,       &tile123.Zeros3,       4096);
  181.                 memcpy(&tile124.MaskAddress,  &tile123.MaskAddress,  4096);
  182.                 memcpy(&tile124.FMaskAddress, &tile123.FMaskAddress, 4096);
  183.         } else if (tileHeader.Version == 0x201) {
  184.                 if (ReadUncompress(fTileset, (char *)&tile124, tileHeader.CData1, tileHeader.UData1)) {
  185.                         fclose(fTileset);
  186.                         return ERRORUNCOMPRESSING;
  187.                 }
  188.         } else {
  189.                 fclose(fTileset);
  190.                 return UNKNOWNVERSION;
  191.         }
  192.  
  193.         //If v1.23 tileset has > 1020 tiles, or v1.24 tileset
  194.         //has > 4090 tiles, or if tiles is not multiple of 10
  195.         if ((tileHeader.Version == 0x200 && tile123.TileCount > 1020) ||
  196.                 tile124.TileCount > 4090 || tile124.TileCount % 10) {
  197.                 fclose(fTileset);
  198.                 return BADNUMBEROFTILES;
  199.         }
  200.  
  201.         //Reads uncompressed Data2
  202.         Data2 = (char*)malloc(tileHeader.UData2);
  203.         if (ReadUncompress(fTileset, Data2, tileHeader.CData2, tileHeader.UData2)) {
  204.                 fclose(fTileset);
  205.                 return ERRORUNCOMPRESSING;
  206.         }
  207.  
  208.         //Reads uncompressed Data4
  209.         fseek(fTileset, tileHeader.CData3, SEEK_CUR);
  210.         Data4 = (char*)malloc(tileHeader.UData4);
  211.         if (ReadUncompress(fTileset, Data4, tileHeader.CData4, tileHeader.UData4)) {
  212.                 fclose(fTileset);
  213.                 return ERRORUNCOMPRESSING;
  214.         }
  215.  
  216.         //The fun part -- actually copying the tileset into JCS format
  217.         ROWS = tile124.TileCount / 10;
  218.         for (i = 0; i < ROWS; ++i) { //tilerow 1 to ROWS for the current tileset
  219.                 for (j = 0; j < 10; ++j) { //tile 1 to 10 for the current tilerow
  220.                         for (k = 0; k < 32; ++k) { //pixelrow 1 to 32 for the current tile
  221.                                 memcpy(imgBuffer[i * 32 + k][j],
  222.                                 &Data2[tile124.ImageAddress[i * 10 + j] + k * 32], 32);
  223.                         }
  224.                 }
  225.         }
  226.         //Just initialize rowPointers to point to imgBuffer, only needs to be done once
  227.         rowPointers = (png_bytep*)malloc(ROWS * 32 * sizeof(png_bytep));
  228.         for (i = 0; i < ROWS * 32; ++i) //sets the rowpointer for each
  229.                 rowPointers[i] = (unsigned char*)imgBuffer[i];
  230.         //Copy tileset palette to png palette, and set our own palette[0]
  231.         memcpy(palette, monochrome, 3);
  232.         for (i = 1; i < 256; ++i)
  233.                 memcpy(&palette[i], &tile124.PaletteColor[i], 3);
  234.         //Finally we save the image to a file
  235.         if (SavePicture(BaseFileName, "-image.png", false))
  236.                 return CANNOTSAVE;
  237.  
  238.         //The image png is done, now we do the mask png:
  239.         //You should not recycle imgBuffer like I did, I was just lazy
  240.         ROWS = tile124.TileCount / 10;
  241.         for (i = 0; i < ROWS; ++i) { //tilerow 1 to ROWS for the current tileset
  242.                 for (j = 0; j < 10; ++j) { //tile 1 to 10 for the current tilerow
  243.                         for (k = 0; k < 32; ++k) { //pixelrow 1 to 32 for the current tile
  244.                                 for (l = 0; l < 4; ++l) { //only 4 bytes (32 bits) per pixelrow
  245.                                         imgBuffer[i * 32 + k][0][j * 4 + l] = //we "cheat" the array =(
  246.                                         ReverseBits(Data4[tile124.MaskAddress[i * 10 + j] + k * 4 + l]);
  247.                                 }
  248.                         }
  249.                 }
  250.         }
  251.         //Finally we save the image to a file
  252.         if (SavePicture(BaseFileName, "-mask.png", true))
  253.                 return CANNOTSAVE;
  254.  
  255.         free(Data2);
  256.         free(Data4);
  257.         fclose(fTileset);
  258.         return 0;
  259. }
  260.  
  261. //Program starts here
  262. int main(int argc, char *argv[]) {
  263.  
  264.         bool BreakAtEnd = false;
  265.  
  266.         //Must have at least one argument
  267.         if (argc < 2) {
  268.                 printf("I need files.");
  269.                 getc(stdin);
  270.                 return 0;
  271.         }
  272.  
  273.         //Parses each file individually
  274.         for (int i = 1; i < argc; ++i) {
  275.                 int ret = ExtractTileset(argv[i]);
  276.                 if (ret) {
  277.                         printf("Error parsing %s\nReason: %s\n", argv[i], ErrorMsg[ret]);
  278.                         BreakAtEnd = true;
  279.                 } else {
  280.                         printf("%s succeeded\n", argv[i]);
  281.                 }
  282.         }
  283.  
  284.         if (BreakAtEnd) getc(stdin);
  285.         return 0;
  286. }