diff --git a/src/grfcodec.cpp b/src/grfcodec.cpp index 026f4e8d..22f82bcc 100644 --- a/src/grfcodec.cpp +++ b/src/grfcodec.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #ifdef __MINGW32__ #include @@ -651,6 +652,31 @@ static int encode(const char *file, const char *dir, int compress, int *colourma return 0; } +std::map _sprite_offsets{}; + +static void read_grf_sprite_offsets(FILE *grf) +{ + _sprite_offsets.clear(); + + const char action[] = "Reading sprite offsets"; + uint32_t offset = readdword(action, grf); + off_t pos = ftell(grf); + fseek(grf, offset, SEEK_CUR); + + uint id = 0, count = 0; + while ((id = readdword(action, grf)) != 0) { + if (_sprite_offsets.count(id) == 0) + _sprite_offsets[id] = ftell(grf) - 4; + + fseek(grf, readdword(action, grf), SEEK_CUR); + count++; + } + + printf("Found %zu / %u container chunks\n", _sprite_offsets.size(), count); + + fseek(grf, pos, SEEK_SET); +} + static int decode(const char *file, const char *dir, const U8 *palette, int box, int width, int height, int *colourmap, int useplaintext) { int count, result, lastpct = -1; @@ -694,14 +720,13 @@ static int decode(const char *file, const char *dir, const U8 *palette, int box, cfread(action, buffer, 1, sizeof(buffer), grf); int grfcontversion = memcmp(buffer, header, sizeof(header)) == 0 ? 2 : 1; - U32 dataoffset = 0; + printf("Found grf container version %d\n", grfcontversion); if (grfcontversion == 1) { fseek(grf, 0, SEEK_SET); } else { - dataoffset = sizeof(header) + 4 + readdword(action, grf); // GRF data offset + read_grf_sprite_offsets(grf); fgetc(grf); // Compression } - printf("Found grf container version %d\n", grfcontversion); // We do the 'file' and 'writer' seperate to make // this a little bit less messy @@ -764,7 +789,7 @@ static int decode(const char *file, const char *dir, const U8 *palette, int box, pcx->newsprite(); if (pcx32 != NULL) pcx32->newsprite(); - result = decodesprite(grf, pcx, pcx32, &writer, count, &dataoffset, grfcontversion); + result = decodesprite(grf, pcx, pcx32, &writer, count, grfcontversion); writer.flush(); count++; } while (result); diff --git a/src/sprites.cpp b/src/sprites.cpp index 575debb7..bc5d189f 100644 --- a/src/sprites.cpp +++ b/src/sprites.cpp @@ -17,6 +17,7 @@ \*****************************************/ #include +#include #include "sprites.h" #include "grfcomm.h" @@ -241,7 +242,9 @@ static void writesprite(bool first, spritestorage *image_writer, spriteinfowrite image_writer->spritedone(info.xdim, info.ydim); } -int decodesprite(FILE *grf, spritestorage *imgpal, spritestorage *imgrgba, spriteinfowriter *writer, int spriteno, U32 *dataoffset, int grfcontversion) +extern std::map _sprite_offsets; + +int decodesprite(FILE *grf, spritestorage *imgpal, spritestorage *imgrgba, spriteinfowriter *writer, int spriteno, int grfcontversion) { static const char *action = "decoding sprite"; unsigned long size, datasize, inbufsize, outbufsize, startpos, returnpos = 0; @@ -268,7 +271,8 @@ int decodesprite(FILE *grf, spritestorage *imgpal, spritestorage *imgrgba, sprit id = readdword(action, grf); returnpos = ftell(grf); - fseek(grf, *dataoffset, SEEK_SET); + uint32_t dataoffset = _sprite_offsets[id]; + fseek(grf, dataoffset, SEEK_SET); } long result; @@ -302,7 +306,6 @@ int decodesprite(FILE *grf, spritestorage *imgpal, spritestorage *imgrgba, sprit result = 1; if (returnpos == 0) return result; - *dataoffset = startpos + size + 1; break; } @@ -394,14 +397,14 @@ int decodesprite(FILE *grf, spritestorage *imgpal, spritestorage *imgrgba, sprit printf("\nError: cannot decode 32bpp sprites to pcx\n"); exit(2); } - writesprite(false, imgrgba, writer, imgbuffer, info); + writesprite(i == 0, imgrgba, writer, imgbuffer, info); } else if (info.depth==DEPTH_MASK) { if (imgrgba == NULL) { printf("\nError: cannot decode 32bpp sprites to pcx\n"); exit(2); } info.depth=DEPTH_32BPP; - writesprite(false, imgrgba, writer, imgbuffer, info); + writesprite(i == 0, imgrgba, writer, imgbuffer, info); info.depth=DEPTH_MASK; writesprite(false, imgpal, writer, imgbuffer, info); } else if (info.depth==DEPTH_8BPP) { @@ -422,10 +425,7 @@ int decodesprite(FILE *grf, spritestorage *imgpal, spritestorage *imgrgba, sprit free(outbuffer); free(imgbuffer); - if (returnpos != 0) { - *dataoffset = startpos + inbufsize; - if (grfcontversion == 2 && HASTRANSPARENCY(info.info)) *dataoffset += 4; - } else { + if (returnpos == 0) { returnpos = startpos + inbufsize; break; } diff --git a/src/sprites.h b/src/sprites.h index a183304a..9cc33d43 100644 --- a/src/sprites.h +++ b/src/sprites.h @@ -91,7 +91,7 @@ class spritestorage { extern int maxx, maxy, maxs; -int decodesprite(FILE *grf, spritestorage *imgpal, spritestorage *imgrgba, spriteinfowriter *writer, int spriteno, U32 *dataoffset, int grfcontversion); +int decodesprite(FILE *grf, spritestorage *imgpal, spritestorage *imgrgba, spriteinfowriter *writer, int spriteno, int grfcontversion); long getlasttilesize(); long encodetile(U8 **compressed_data, long *uncompressed_size, const CommonPixel *image, long imgsize, int sx, int sy, SpriteInfo inf, int docompress, int spriteno, bool has_mask, bool rgba, int grfcontversion);